Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New thing process #444

Merged
merged 4 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/ArduinoIoTCloud.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ ArduinoIoTCloudClass::ArduinoIoTCloudClass()
: _connection{nullptr}
, _time_service(TimeService)
, _thing_id{""}
, _thing_id_property{nullptr}
, _lib_version{AIOT_CONFIG_LIB_VERSION}
, _device_id{""}
, _cloud_event_callback{nullptr}
Expand Down
1 change: 0 additions & 1 deletion src/ArduinoIoTCloud.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ class ArduinoIoTCloudClass
ConnectionHandler * _connection;
TimeServiceClass & _time_service;
String _thing_id;
Property * _thing_id_property;
String _lib_version;

void execCloudEventCallback(ArduinoIoTCloudEvent const event);
Expand Down
135 changes: 51 additions & 84 deletions src/ArduinoIoTCloudTCP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,10 @@ unsigned long getTime()
ArduinoIoTCloudTCP::ArduinoIoTCloudTCP()
: _state{State::ConnectPhy}
, _connection_attempt(0,0)
, _message_stream(std::bind(&ArduinoIoTCloudTCP::sendMessage, this, std::placeholders::_1))
, _thing(&_message_stream)
, _thing_id_property{nullptr}
, _device_property_container{0}
, _thing_property_container{0}
, _last_checked_property_index{0}
, _tz_offset{0}
, _tz_offset_property{nullptr}
, _tz_dst_until{0}
, _tz_dst_until_property{nullptr}
, _mqtt_data_buf{0}
, _mqtt_data_len{0}
, _mqtt_data_request_retransmit{false}
Expand Down Expand Up @@ -214,10 +211,8 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress,
#endif /* OTA_ENABLED */
p = new CloudWrapperString(_thing_id);
_thing_id_property = &addPropertyToContainer(_device_property_container, *p, "thing_id", Permission::ReadWrite, -1).writeOnDemand();
p = new CloudWrapperInt(_tz_offset);
_tz_offset_property = &addPropertyToContainer(_thing_property_container, *p, "tz_offset", Permission::ReadWrite, -1).writeOnDemand();
p = new CloudWrapperUnsignedInt(_tz_dst_until);
_tz_dst_until_property = &addPropertyToContainer(_thing_property_container, *p, "tz_dst_until", Permission::ReadWrite, -1).writeOnDemand();

_thing.begin();

#if OTA_ENABLED
_ota_cap = OTA::isCapable();
Expand Down Expand Up @@ -274,7 +269,6 @@ void ArduinoIoTCloudTCP::update()
case State::SubscribeDeviceTopic: next_state = handle_SubscribeDeviceTopic(); break;
case State::CheckDeviceConfig: next_state = handle_CheckDeviceConfig(); break;
case State::SubscribeThingTopics: next_state = handle_SubscribeThingTopics(); break;
case State::RequestLastValues: next_state = handle_RequestLastValues(); break;
case State::Connected: next_state = handle_Connected(); break;
case State::Disconnect: next_state = handle_Disconnect(); break;
}
Expand Down Expand Up @@ -328,12 +322,13 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectPhy()

ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SyncTime()
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
unsigned long const internal_posix_time = _time_service.getTime();
#pragma GCC diagnostic pop
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s internal clock configured to posix timestamp %d", __FUNCTION__, internal_posix_time);
return State::ConnectMqttBroker;
if (TimeServiceClass::isTimeValid(getTime()))
{
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s internal clock configured to posix timestamp %d", __FUNCTION__, getTime());
return State::ConnectMqttBroker;
}

return State::ConnectPhy;
}

ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_ConnectMqttBroker()
Expand Down Expand Up @@ -477,38 +472,12 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeThingTopics()

/* Successfully subscribed to thing topics, reconfigure timers for next state and go on */
_connection_attempt.begin(AIOT_CONFIG_TIMEOUT_FOR_LASTVALUES_SYNC_ms);
return State::RequestLastValues;
}

ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_RequestLastValues()
{
if (!_mqttClient.connected() || _thing_id_property->isDifferentFromCloud())
{
return State::Disconnect;
}

/* Check whether or not we need to send a new request. */
if (_connection_attempt.isRetry() && !_connection_attempt.isExpired())
return State::RequestLastValues;

/* Track the number of times a get-last-values request was sent to the cloud.
* If no data is received within a certain number of retry-requests it's a better
* strategy to disconnect and re-establish connection from the ground up.
*/
if (_connection_attempt.getRetryCount() > AIOT_CONFIG_LASTVALUES_SYNC_MAX_RETRY_CNT)
{
return State::Disconnect;
}

_connection_attempt.retry();
requestLastValue();
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] last values requested", __FUNCTION__, _time_service.getTime());
return State::RequestLastValues;
return State::Connected;
}

ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected()
{
if (!_mqttClient.connected())
if (!_mqttClient.connected() || _thing_id_property->isDifferentFromCloud() || !_thing.connected())
{
/* The last message was definitely lost, trigger a retransmit. */
_mqtt_data_request_retransmit = true;
Expand All @@ -517,20 +486,6 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected()
/* We are connected so let's to our stuff here. */
else
{
if (_thing_id_property->isDifferentFromCloud())
{
return State::Disconnect;
}

/* Check if a primitive property wrapper is locally changed.
* This function requires an existing time service which in
* turn requires an established connection. Not having that
* leads to a wrong time set in the time service which inhibits
* the connection from being established due to a wrong data
* in the reconstructed certificate.
*/
updateTimestampOnLocallyChangedProperties(_thing_property_container);

/* Retransmit data in case there was a lost transaction due
* to phy layer or MQTT connectivity loss.
*/
Expand All @@ -539,27 +494,11 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected()
_mqtt_data_request_retransmit = false;
}

/* Configure Time service with timezone data:
* _tz_offset [offset + dst]
* _tz_dst_until [posix timestamp until _tz_offset is valid]
*/
if (_tz_offset_property->isDifferentFromCloud() || _tz_dst_until_property->isDifferentFromCloud()) {
_tz_offset_property->fromCloudToLocal();
_tz_dst_until_property->fromCloudToLocal();
_time_service.setTimeZoneData(_tz_offset, _tz_dst_until);
}
/* Call CloudThing process to synchronize properties */
_thing.update();

/* Check if any properties need encoding and send them to
* the cloud if necessary.
*/
sendThingPropertiesToCloud();
return State::Connected;

unsigned long const internal_posix_time = _time_service.getTime();
if (internal_posix_time < _tz_dst_until) {
return State::Connected;
} else {
return State::RequestLastValues;
}
}
}

Expand Down Expand Up @@ -604,9 +543,15 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Disconnect()
/* TODO add device topic */
_mqttClient.stop();
}

Message message = { ResetCmdId };
_thing.handleMessage(&message);

DEBUG_INFO("Disconnected from Arduino IoT Cloud");
execCloudEventCallback(ArduinoIoTCloudEvent::DISCONNECT);

updateThingTopics();

/* Setup timer for broker connection and restart */
_connection_attempt.begin(AIOT_CONFIG_RECONNECTION_RETRY_DELAY_ms, AIOT_CONFIG_MAX_RECONNECTION_RETRY_DELAY_ms);
return State::ConnectPhy;
Expand All @@ -630,25 +575,47 @@ void ArduinoIoTCloudTCP::handleMessage(int length)
/* Topic for OTA properties and device configuration */
if (_deviceTopicIn == topic) {
CBORDecoder::decode(_device_property_container, (uint8_t*)bytes, length);
_state = State::CheckDeviceConfig;
if (_thing_id_property->isDifferentFromCloud() && (_thing_id.length() != 0)) {
_state = State::Disconnect;
} else {
_state = State::CheckDeviceConfig;
}
}

/* Topic for user input data */
if (_dataTopicIn == topic) {
CBORDecoder::decode(_thing_property_container, (uint8_t*)bytes, length);
CBORDecoder::decode(_thing.getPropertyContainer(), (uint8_t*)bytes, length);
}

/* Topic for sync Thing last values on connect */
if ((_shadowTopicIn == topic) && (_state == State::RequestLastValues))
if (_shadowTopicIn == topic)
{
DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] last values received", __FUNCTION__, millis());
CBORDecoder::decode(_thing_property_container, (uint8_t*)bytes, length, true);
_time_service.setTimeZoneData(_tz_offset, _tz_dst_until);
CBORDecoder::decode(_thing.getPropertyContainer(), (uint8_t*)bytes, length, true);
Message message = { LastValuesUpdateCmdId };
_thing.handleMessage(&message);
execCloudEventCallback(ArduinoIoTCloudEvent::SYNC);
_state = State::Connected;
}
}

void ArduinoIoTCloudTCP::sendMessage(Message * msg)
{
switch (msg->id)
{
case PropertiesUpdateCmdId:
sendThingPropertiesToCloud();
break;

case LastValuesBeginCmdId:
requestLastValue();
break;

default:
break;
}
}

void ArduinoIoTCloudTCP::sendPropertyContainerToCloud(String const topic, PropertyContainer & property_container, unsigned int & current_property_index)
{
int bytes_encoded = 0;
Expand All @@ -669,7 +636,7 @@ void ArduinoIoTCloudTCP::sendPropertyContainerToCloud(String const topic, Proper

void ArduinoIoTCloudTCP::sendThingPropertiesToCloud()
{
sendPropertyContainerToCloud(_dataTopicOut, _thing_property_container, _last_checked_property_index);
sendPropertyContainerToCloud(_dataTopicOut, _thing.getPropertyContainer(), _thing.getPropertyContainerIndex());
}

void ArduinoIoTCloudTCP::sendDevicePropertiesToCloud()
Expand Down
18 changes: 6 additions & 12 deletions src/ArduinoIoTCloudTCP.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#include <AIoTC_Config.h>
#include <ArduinoIoTCloud.h>
#include <ArduinoMqttClient.h>
#include <utility/time/TimedAttempt.h>
#include <ArduinoIoTCloudThing.h>

#if defined(BOARD_HAS_SECURE_ELEMENT)
#include <Arduino_SecureElement.h>
Expand Down Expand Up @@ -75,7 +75,6 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
ArduinoIoTCloudTCP();
virtual ~ArduinoIoTCloudTCP() { }


virtual void update () override;
virtual int connected () override;
virtual void printDebugInfo() override;
Expand All @@ -91,7 +90,7 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
inline String getBrokerAddress() const { return _brokerAddress; }
inline uint16_t getBrokerPort () const { return _brokerPort; }

inline PropertyContainer &getThingPropertyContainer() { return _thing_property_container; }
inline PropertyContainer &getThingPropertyContainer() { return _thing.getPropertyContainer(); }

#if OTA_ENABLED
/* The callback is triggered when the OTA is initiated and it gets executed until _ota_req flag is cleared.
Expand All @@ -118,21 +117,16 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
SubscribeDeviceTopic,
CheckDeviceConfig,
SubscribeThingTopics,
RequestLastValues,
Connected,
Disconnect,
};

State _state;
TimedAttempt _connection_attempt;
MessageStream _message_stream;
ArduinoCloudThing _thing;
Property * _thing_id_property;
PropertyContainer _device_property_container;
PropertyContainer _thing_property_container;
unsigned int _last_checked_property_index;

int _tz_offset;
Property * _tz_offset_property;
unsigned int _tz_dst_until;
Property * _tz_dst_until_property;

String _brokerAddress;
uint16_t _brokerPort;
Expand Down Expand Up @@ -200,12 +194,12 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
State handle_CheckDeviceConfig();
State handle_SubscribeDeviceTopic();
State handle_SubscribeThingTopics();
State handle_RequestLastValues();
State handle_Connected();
State handle_Disconnect();

static void onMessage(int length);
void handleMessage(int length);
void sendMessage(Message * msg);
void sendPropertyContainerToCloud(String const topic, PropertyContainer & property_container, unsigned int & current_property_index);
void sendThingPropertiesToCloud();
void sendDevicePropertiesToCloud();
Expand Down
Loading
Loading