From 5352b804ad91efd10be45e4b0e870febd7fa229c Mon Sep 17 00:00:00 2001 From: ilcato Date: Fri, 8 Feb 2019 15:11:26 +0100 Subject: [PATCH 01/22] Implementation of the shadow Thing feature on the device --- src/ArduinoIoTCloud.cpp | 97 +++++++++++++++++++++++++++++++++++++---- src/ArduinoIoTCloud.h | 22 +++++++++- 2 files changed, 109 insertions(+), 10 deletions(-) diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index fb0ca3758bf..f8bbe9f45f9 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -20,6 +20,11 @@ #include "CloudSerial.h" #include "ArduinoIoTCloud.h" +#ifdef ARDUINO_ARCH_SAMD + #include + RTCZero rtc; +#endif + const static int keySlot = 0; const static int compressedCertSlot = 10; const static int serialNumberAndAuthorityKeyIdentifierSlot = 11; @@ -37,11 +42,20 @@ static unsigned long getTime() { return time; } +static unsigned long getTimestamp() { + #ifdef ARDUINO_ARCH_SAMD + return rtc.getEpoch(); + #else + return 0; + #endif +} + ArduinoIoTCloudClass::ArduinoIoTCloudClass() : _thing_id (""), _bearSslClient(NULL), _mqttClient (NULL), - connection (NULL) + connection (NULL), + _lastSyncRequestTickTime(0) { } @@ -64,6 +78,9 @@ int ArduinoIoTCloudClass::begin(ConnectionManager *c, String brokerAddress, uint Client &connectionClient = c->getClient(); _brokerAddress = brokerAddress; _brokerPort = brokerPort; + #ifdef ARDUINO_ARCH_SAMD + rtc.begin(); + #endif return begin(connectionClient, _brokerAddress, _brokerPort); } @@ -148,6 +165,8 @@ void ArduinoIoTCloudClass::mqttClientBegin() else { _dataTopicIn = "/a/t/" + _thing_id + "/e/i"; _dataTopicOut = "/a/t/" + _thing_id + "/e/o"; + _shadowTopicIn = "/a/t/" + _thing_id + "/shadow/i"; + _shadowTopicOut = "/a/t/" + _thing_id + "/shadow/o"; } // use onMessage as callback for received mqtt messages @@ -166,6 +185,10 @@ int ArduinoIoTCloudClass::connect() } _mqttClient->subscribe(_stdinTopic); _mqttClient->subscribe(_dataTopicIn); + _mqttClient->subscribe(_shadowTopicIn); + + syncStatus = SYNC_STATUS_WAIT_FOR_CLOUD_VALUES; + _lastSyncRequestTickTime = 0; return 1; } @@ -182,14 +205,18 @@ void ArduinoIoTCloudClass::poll() update(); } -void ArduinoIoTCloudClass::update() +void ArduinoIoTCloudClass::update(void (*callback)(void)) { // If user call update() without parameters use the default ones - update(MAX_RETRIES, RECONNECTION_TIMEOUT); + update(MAX_RETRIES, RECONNECTION_TIMEOUT, callback); } void ArduinoIoTCloudClass::update(int const reconnectionMaxRetries, int const reconnectionTimeoutMs) { + unsigned long timestamp = getTimestamp(); + //check if a property is changed + if(timestamp) Thing.updateTimestampOnChangedProperties(timestamp); + connectionCheck(); if(iotStatus != IOT_STATUS_CLOUD_CONNECTED){ return; @@ -198,11 +225,30 @@ void ArduinoIoTCloudClass::update(int const reconnectionMaxRetries, int const re // MTTQClient connected!, poll() used to retrieve data from MQTT broker _mqttClient->poll(); - uint8_t data[MQTT_TRANSMIT_BUFFER_SIZE]; - int const length = Thing.encode(data, sizeof(data)); - if (length > 0) { - writeProperties(data, length); - } + switch (syncStatus) { + case SYNC_STATUS_SYNCHRONIZED: + sendPropertiesToCloud(); + break; + case SYNC_STATUS_WAIT_FOR_CLOUD_VALUES: + if (millis() - _lastSyncRequestTickTime > TIMEOUT_FOR_LASTVALUES_SYNC) { + requestLastValue(); + _lastSyncRequestTickTime = millis(); + } + break; + case SYNC_STATUS_VALUES_PROCESSED: + if(callback != NULL) + (*callback)(); + syncStatus = SYNC_STATUS_SYNCHRONIZED; + break; + } +} + +void ArduinoIoTCloudClass::sendPropertiesToCloud() { + uint8_t data[MQTT_TRANSMIT_BUFFER_SIZE]; + int const length = Thing.encode(data, sizeof(data)); + if (length > 0) { + writeProperties(data, length); + } } int ArduinoIoTCloudClass::reconnect(Client& /* net */) @@ -254,6 +300,23 @@ int ArduinoIoTCloudClass::writeStdout(const byte data[], int length) return 1; } +int ArduinoIoTCloudClass::writeShadowOut(const byte data[], int length) +{ + if (!_mqttClient->beginMessage(_shadowTopicOut, length, false, 0)) { + return 0; + } + + if (!_mqttClient->write(data, length)) { + return 0; + } + + if (!_mqttClient->endMessage()) { + return 0; + } + + return 1; +} + void ArduinoIoTCloudClass::onMessage(int length) { ArduinoCloud.handleMessage(length); @@ -276,6 +339,19 @@ void ArduinoIoTCloudClass::handleMessage(int length) if (_dataTopicIn == topic) { Thing.decode((uint8_t*)bytes, length); } + if ((_shadowTopicIn == topic) && syncStatus == SYNC_STATUS_WAIT_FOR_CLOUD_VALUES) { + Thing.decode((uint8_t*)bytes, length, true); + sendPropertiesToCloud(); + syncStatus = SYNC_STATUS_VALUES_PROCESSED; + } +} + +void ArduinoIoTCloudClass::requestLastValue() +{ + // Send the getLastValues CBOR message to the cloud + // [{0: "r:m", 3: "getLastValues"}] = 81 A2 00 63 72 3A 6D 03 6D 67 65 74 4C 61 73 74 56 61 6C 75 65 73 + const uint8_t data[] = { 0x81, 0xA2, 0x00, 0x63, 0x72, 0x3A, 0x6D, 0x03, 0x6D, 0x67, 0x65, 0x74, 0x4C, 0x61, 0x73, 0x74, 0x56, 0x61, 0x6C, 0x75, 0x65, 0x73 }; + writeShadowOut(data, sizeof data); } void ArduinoIoTCloudClass::connectionCheck() @@ -332,6 +408,11 @@ void ArduinoIoTCloudClass::connectionCheck() CloudSerial.begin(9600); CloudSerial.println("Hello from Cloud Serial!"); } + #ifdef ARDUINO_ARCH_SAMD + unsigned long epoch = getTime(); + if (epoch!=0) + rtc.setEpoch(epoch); + #endif break; } } diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index 41fa94d6588..fe15f31342f 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -63,6 +63,7 @@ class ArduinoIoTCloudClass { static const int MQTT_TRANSMIT_BUFFER_SIZE = 256; static const int MAX_RETRIES = 5; static const int RECONNECTION_TIMEOUT = 2000; + static const int MAX_CHECK_LASTVALUES_SYNC = 20; void onGetTime(unsigned long(*callback)(void)); @@ -71,10 +72,12 @@ class ArduinoIoTCloudClass { bool disconnect(); void poll() __attribute__((deprecated)); /* Attention: Function is deprecated - use 'update' instead */ - void update(); + void update(int mode = PROPERTIES_SYNC_FORCE_DEVICE, void (*callback)(void) = NULL); // defined for users who want to specify max reconnections reties and timeout between them - void update(int const reconnectionMaxRetries, int const reconnectionTimeoutMs); + void update(int const reconnectionMaxRetries, int const reconnectionTimeoutMs, int mode = PROPERTIES_SYNC_FORCE_DEVICE, void (*callback)(void) = NULL); + // get the status of synchronization after getLastValues request + bool getLastValuesSyncStatus(); int connected(); // Clean up existing Mqtt connection, create a new one and initialize it @@ -120,10 +123,14 @@ class ArduinoIoTCloudClass { friend class CloudSerialClass; int writeStdout(const byte data[], int length); int writeProperties(const byte data[], int length); + int writeShadowOut(const byte data[], int length); + // Used to initialize MQTTClient void mqttClientBegin(); // Function in charge of perform MQTT reconnection, basing on class parameters(retries,and timeout) bool mqttReconnect(int const maxRetries, int const timeout); + // Used to retrieve ast values from _shadowTopicIn + void getLastValues(); ArduinoIoTConnectionStatus getIoTStatus() { return iotStatus; } void setIoTConnectionState(ArduinoIoTConnectionStatus _newState); @@ -140,14 +147,25 @@ class ArduinoIoTCloudClass { ArduinoCloudThing Thing; BearSSLClient* _bearSslClient; MqttClient* _mqttClient; + int _mode, + _check_lastValues_sync; + bool _callGetLastValueCallback; + // Class attribute to define MTTQ topics 2 for stdIn/out and 2 for data, in order to avoid getting previous pupblished payload String _stdinTopic; String _stdoutTopic; + String _shadowTopicOut; + String _shadowTopicIn; String _dataTopicOut; String _dataTopicIn; String _otaTopic; Client *_net; + + // Used to synchronize properties + bool _firstReconnectionUpdate; + bool _propertiesSynchronized; + void (*_syncCallback)(void); }; extern ArduinoIoTCloudClass ArduinoCloud; From 9417c0659e1ea40a085913e4d757c5f211b0e5f9 Mon Sep 17 00:00:00 2001 From: ilcato Date: Fri, 8 Feb 2019 18:19:33 +0100 Subject: [PATCH 02/22] put rtc sync only in CONNECTING + avoid multiple sending of getLastValue --- src/ArduinoIoTCloud.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index fe15f31342f..21e008c143f 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -63,7 +63,7 @@ class ArduinoIoTCloudClass { static const int MQTT_TRANSMIT_BUFFER_SIZE = 256; static const int MAX_RETRIES = 5; static const int RECONNECTION_TIMEOUT = 2000; - static const int MAX_CHECK_LASTVALUES_SYNC = 20; + static const int TIMEOUT_FOR_LASTVALUES_SYNC = 10000; void onGetTime(unsigned long(*callback)(void)); @@ -148,7 +148,7 @@ class ArduinoIoTCloudClass { BearSSLClient* _bearSslClient; MqttClient* _mqttClient; int _mode, - _check_lastValues_sync; + _lastSyncRequestTickTime; bool _callGetLastValueCallback; From fb8f194751b90a42fc9dccf7a393931850545189 Mon Sep 17 00:00:00 2001 From: ilcato Date: Wed, 13 Feb 2019 15:17:40 +0100 Subject: [PATCH 03/22] first draft of properties synchronization using individual callback --- src/ArduinoIoTCloud.h | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index 21e008c143f..a72a557ebae 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -72,10 +72,10 @@ class ArduinoIoTCloudClass { bool disconnect(); void poll() __attribute__((deprecated)); /* Attention: Function is deprecated - use 'update' instead */ - void update(int mode = PROPERTIES_SYNC_FORCE_DEVICE, void (*callback)(void) = NULL); + void update(void (*callback)(void) = NULL); // defined for users who want to specify max reconnections reties and timeout between them - void update(int const reconnectionMaxRetries, int const reconnectionTimeoutMs, int mode = PROPERTIES_SYNC_FORCE_DEVICE, void (*callback)(void) = NULL); + void update(int const reconnectionMaxRetries, int const reconnectionTimeoutMs, void (*callback)(void) = NULL); // get the status of synchronization after getLastValues request bool getLastValuesSyncStatus(); @@ -95,17 +95,17 @@ class ArduinoIoTCloudClass { template - void addPropertyReal(T & property, String name, permissionType permission_type = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, N minDelta = N(0)) { + void addPropertyReal(T & property, String name, permissionType permission_type = READWRITE, int syncMode = PROPERTIES_SYNC_FORCE_DEVICE, void(*synFn)(ArduinoCloudProperty property) = NULL, long seconds = ON_CHANGE, void(*fn)(void) = NULL, N minDelta = N(0)) { Permission permission = Permission::ReadWrite; if (permission_type == READ ) permission = Permission::Read; else if(permission_type == WRITE) permission = Permission::Write; else permission = Permission::ReadWrite; if(seconds == ON_CHANGE) { - Thing.addPropertyReal(property, name, permission).publishOnChange((T)minDelta, DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn); + Thing.addPropertyReal(property, name, permission, syncMode).publishOnChange((T)minDelta, DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(synFn); } else { - Thing.addPropertyReal(property, name, permission).publishEvery(seconds).onUpdate(fn); + Thing.addPropertyReal(property, name, permission, syncMode).publishEvery(seconds).onUpdate(fn).onSync(synFn); } } @@ -129,8 +129,8 @@ class ArduinoIoTCloudClass { void mqttClientBegin(); // Function in charge of perform MQTT reconnection, basing on class parameters(retries,and timeout) bool mqttReconnect(int const maxRetries, int const timeout); - // Used to retrieve ast values from _shadowTopicIn - void getLastValues(); + // Used to retrieve last values from _shadowTopicIn + void requestLastValue(); ArduinoIoTConnectionStatus getIoTStatus() { return iotStatus; } void setIoTConnectionState(ArduinoIoTConnectionStatus _newState); @@ -147,8 +147,7 @@ class ArduinoIoTCloudClass { ArduinoCloudThing Thing; BearSSLClient* _bearSslClient; MqttClient* _mqttClient; - int _mode, - _lastSyncRequestTickTime; + int _lastSyncRequestTickTime; bool _callGetLastValueCallback; From 18418b3e066f1c4ec11729a938cb542c2066d16c Mon Sep 17 00:00:00 2001 From: ilcato Date: Wed, 13 Feb 2019 21:02:45 +0100 Subject: [PATCH 04/22] Refactoring --- src/ArduinoIoTCloud.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index a72a557ebae..cdcc0ba5904 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -95,7 +95,7 @@ class ArduinoIoTCloudClass { template - void addPropertyReal(T & property, String name, permissionType permission_type = READWRITE, int syncMode = PROPERTIES_SYNC_FORCE_DEVICE, void(*synFn)(ArduinoCloudProperty property) = NULL, long seconds = ON_CHANGE, void(*fn)(void) = NULL, N minDelta = N(0)) { + void addPropertyReal(T & property, String name, permissionType permission_type = READWRITE, SyncMode syncMode = PROPERTIES_SYNC_FORCE_DEVICE, void(*synFn)(ArduinoCloudProperty property) = NULL, long seconds = ON_CHANGE, void(*fn)(void) = NULL, N minDelta = N(0)) { Permission permission = Permission::ReadWrite; if (permission_type == READ ) permission = Permission::Read; else if(permission_type == WRITE) permission = Permission::Write; From b7292cc6a542d9eccd72fd0caf5f132a2e7ce25e Mon Sep 17 00:00:00 2001 From: ilcato Date: Thu, 14 Feb 2019 17:56:33 +0100 Subject: [PATCH 05/22] pre-defined sync callbacks are declared in the header, the callback passed to the property is based on syncMode parameter --- src/ArduinoIoTCloud.h | 71 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index cdcc0ba5904..1125317df29 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -51,6 +51,31 @@ enum ArduinoIoTConnectionStatus { IOT_STATUS_CLOUD_ERROR, }; +template +void onAutoSync(ArduinoCloudProperty property) { + Serial.println("Executing the AUTO sync"); + if( property.getLastCloudChangeTimestamp() > property.getLastLocalChangeTimestamp()){ + property.setPropertyValue(property.getCloudShadowValue()); + if( property.getLastCloudChangeTimestamp() > property.getLastCloudSyncTimestamp()){ + property.forceCallbackOnChange(); + } + } +} + +template +void onForceCloudSync(ArduinoCloudProperty property) { + Serial.println("Executing the FORCE_CLOUD sync"); + property.setPropertyValue(property.getCloudShadowValue()); + if( property.getLastCloudChangeTimestamp() > property.getLastCloudSyncTimestamp()){ + property.forceCallbackOnChange(); + } +} + +template +void onForceDeviceSync(ArduinoCloudProperty property) { + Serial.println("Executing the FORCE_DEVICE sync"); +} + class ArduinoIoTCloudClass { public: @@ -65,11 +90,11 @@ class ArduinoIoTCloudClass { static const int RECONNECTION_TIMEOUT = 2000; static const int TIMEOUT_FOR_LASTVALUES_SYNC = 10000; - void onGetTime(unsigned long(*callback)(void)); int connect (); bool disconnect(); + void prova(); void poll() __attribute__((deprecated)); /* Attention: Function is deprecated - use 'update' instead */ void update(void (*callback)(void) = NULL); @@ -95,17 +120,47 @@ class ArduinoIoTCloudClass { template - void addPropertyReal(T & property, String name, permissionType permission_type = READWRITE, SyncMode syncMode = PROPERTIES_SYNC_FORCE_DEVICE, void(*synFn)(ArduinoCloudProperty property) = NULL, long seconds = ON_CHANGE, void(*fn)(void) = NULL, N minDelta = N(0)) { + void addPropertyReal(T & property, String name, permissionType permission_type = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, SyncMode syncMode = PROPERTIES_SYNC_FORCE_DEVICE, void(*synFn)(ArduinoCloudProperty property) = NULL, N minDelta = N(0)) { Permission permission = Permission::ReadWrite; if (permission_type == READ ) permission = Permission::Read; else if(permission_type == WRITE) permission = Permission::Write; else permission = Permission::ReadWrite; - - if(seconds == ON_CHANGE) { - Thing.addPropertyReal(property, name, permission, syncMode).publishOnChange((T)minDelta, DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(synFn); - } - else { - Thing.addPropertyReal(property, name, permission, syncMode).publishEvery(seconds).onUpdate(fn).onSync(synFn); + + switch (syncMode){ + case PROPERTIES_SYNC_AUTO: + if(seconds == ON_CHANGE) { + Thing.addPropertyReal(property, name, permission).publishOnChange((T)minDelta, DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(onAutoSync); + } else { + Thing.addPropertyReal(property, name, permission).publishEvery(seconds).onUpdate(fn).onSync(onAutoSync); + } + break; + case PROPERTIES_SYNC_FORCE_CLOUD: + if(seconds == ON_CHANGE) { + Thing.addPropertyReal(property, name, permission).publishOnChange((T)minDelta, DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(onForceCloudSync); + } else { + Thing.addPropertyReal(property, name, permission).publishEvery(seconds).onUpdate(fn).onSync(onForceCloudSync); + } + break; + case PROPERTIES_SYNC_FORCE_DEVICE: + if(seconds == ON_CHANGE) { + Thing.addPropertyReal(property, name, permission).publishOnChange((T)minDelta, DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(onForceDeviceSync); + } else { + Thing.addPropertyReal(property, name, permission).publishEvery(seconds).onUpdate(fn).onSync(onForceDeviceSync); + } + break; + case PROPERTIES_SYNC_CUSTOM: + if(seconds == ON_CHANGE) { + Thing.addPropertyReal(property, name, permission).publishOnChange((T)minDelta, DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(synFn); + } else { + Thing.addPropertyReal(property, name, permission).publishEvery(seconds).onUpdate(fn).onSync(synFn); + } + break; + default: + if(seconds == ON_CHANGE) { + Thing.addPropertyReal(property, name, permission).publishOnChange((T)minDelta, DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(onForceCloudSync); + } else { + Thing.addPropertyReal(property, name, permission).publishEvery(seconds).onUpdate(fn).onSync(onForceCloudSync); + } } } From 9bf4fcad8ecec54985eb7bf27e1684dc1d69d087 Mon Sep 17 00:00:00 2001 From: ilcato Date: Thu, 14 Feb 2019 20:25:30 +0100 Subject: [PATCH 06/22] Changed the API of syncmode --- src/ArduinoIoTCloud.h | 69 +++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index 1125317df29..d0d240f817c 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -51,9 +51,11 @@ enum ArduinoIoTConnectionStatus { IOT_STATUS_CLOUD_ERROR, }; -template +#define AUTO_SYNC onAutoSync +template void onAutoSync(ArduinoCloudProperty property) { - Serial.println("Executing the AUTO sync"); + Serial.print("Executing the AUTO sync on: "); + Serial.println(property.getPropertyName()); if( property.getLastCloudChangeTimestamp() > property.getLastLocalChangeTimestamp()){ property.setPropertyValue(property.getCloudShadowValue()); if( property.getLastCloudChangeTimestamp() > property.getLastCloudSyncTimestamp()){ @@ -62,18 +64,22 @@ void onAutoSync(ArduinoCloudProperty property) { } } -template +#define FORCE_CLOUD_SYNC onForceCloudSync +template void onForceCloudSync(ArduinoCloudProperty property) { - Serial.println("Executing the FORCE_CLOUD sync"); + Serial.print("Executing the FORCE_CLOUD sync on: "); + Serial.println(property.getPropertyName()); property.setPropertyValue(property.getCloudShadowValue()); if( property.getLastCloudChangeTimestamp() > property.getLastCloudSyncTimestamp()){ property.forceCallbackOnChange(); } } -template +#define FORCE_DEVICE_SYNC onForceDeviceSync +template void onForceDeviceSync(ArduinoCloudProperty property) { - Serial.println("Executing the FORCE_DEVICE sync"); + Serial.print("Executing the FORCE_DEVICE sync on: "); + Serial.println(property.getPropertyName()); } class ArduinoIoTCloudClass { @@ -120,47 +126,26 @@ class ArduinoIoTCloudClass { template - void addPropertyReal(T & property, String name, permissionType permission_type = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, SyncMode syncMode = PROPERTIES_SYNC_FORCE_DEVICE, void(*synFn)(ArduinoCloudProperty property) = NULL, N minDelta = N(0)) { + void addPropertyReal(T & property, String name, permissionType permission_type = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, N minDelta = N(0), void(*synFn)(ArduinoCloudProperty property) = FORCE_CLOUD_SYNC) { Permission permission = Permission::ReadWrite; if (permission_type == READ ) permission = Permission::Read; else if(permission_type == WRITE) permission = Permission::Write; else permission = Permission::ReadWrite; - switch (syncMode){ - case PROPERTIES_SYNC_AUTO: - if(seconds == ON_CHANGE) { - Thing.addPropertyReal(property, name, permission).publishOnChange((T)minDelta, DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(onAutoSync); - } else { - Thing.addPropertyReal(property, name, permission).publishEvery(seconds).onUpdate(fn).onSync(onAutoSync); - } - break; - case PROPERTIES_SYNC_FORCE_CLOUD: - if(seconds == ON_CHANGE) { - Thing.addPropertyReal(property, name, permission).publishOnChange((T)minDelta, DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(onForceCloudSync); - } else { - Thing.addPropertyReal(property, name, permission).publishEvery(seconds).onUpdate(fn).onSync(onForceCloudSync); - } - break; - case PROPERTIES_SYNC_FORCE_DEVICE: - if(seconds == ON_CHANGE) { - Thing.addPropertyReal(property, name, permission).publishOnChange((T)minDelta, DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(onForceDeviceSync); - } else { - Thing.addPropertyReal(property, name, permission).publishEvery(seconds).onUpdate(fn).onSync(onForceDeviceSync); - } - break; - case PROPERTIES_SYNC_CUSTOM: - if(seconds == ON_CHANGE) { - Thing.addPropertyReal(property, name, permission).publishOnChange((T)minDelta, DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(synFn); - } else { - Thing.addPropertyReal(property, name, permission).publishEvery(seconds).onUpdate(fn).onSync(synFn); - } - break; - default: - if(seconds == ON_CHANGE) { - Thing.addPropertyReal(property, name, permission).publishOnChange((T)minDelta, DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(onForceCloudSync); - } else { - Thing.addPropertyReal(property, name, permission).publishEvery(seconds).onUpdate(fn).onSync(onForceCloudSync); - } + SyncMode syncMode = PROPERTIES_SYNC_FORCE_CLOUD; + if (synFn == (void(*)(ArduinoCloudProperty property))AUTO_SYNC) + syncMode = PROPERTIES_SYNC_AUTO; + else if (synFn == (void(*)(ArduinoCloudProperty property))FORCE_CLOUD_SYNC) + syncMode = PROPERTIES_SYNC_FORCE_CLOUD; + else if (synFn == (void(*)(ArduinoCloudProperty property))FORCE_DEVICE_SYNC) + syncMode = PROPERTIES_SYNC_FORCE_DEVICE; + else + syncMode = PROPERTIES_SYNC_CUSTOM; + + if(seconds == ON_CHANGE) { + Thing.addPropertyReal(property, name, permission).publishOnChange((T)minDelta, DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(synFn); + } else { + Thing.addPropertyReal(property, name, permission).publishEvery(seconds).onUpdate(fn).onSync(synFn); } } From e9297c3c75fbe2b7942be38e57f01fda6937e797 Mon Sep 17 00:00:00 2001 From: ilcato Date: Tue, 19 Feb 2019 12:49:14 +0100 Subject: [PATCH 07/22] Refactoring sync status --- src/ArduinoIoTCloud.h | 59 ++++++++----------------------------------- 1 file changed, 10 insertions(+), 49 deletions(-) diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index d0d240f817c..195dce9f6c5 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -51,36 +51,11 @@ enum ArduinoIoTConnectionStatus { IOT_STATUS_CLOUD_ERROR, }; -#define AUTO_SYNC onAutoSync -template -void onAutoSync(ArduinoCloudProperty property) { - Serial.print("Executing the AUTO sync on: "); - Serial.println(property.getPropertyName()); - if( property.getLastCloudChangeTimestamp() > property.getLastLocalChangeTimestamp()){ - property.setPropertyValue(property.getCloudShadowValue()); - if( property.getLastCloudChangeTimestamp() > property.getLastCloudSyncTimestamp()){ - property.forceCallbackOnChange(); - } - } -} - -#define FORCE_CLOUD_SYNC onForceCloudSync -template -void onForceCloudSync(ArduinoCloudProperty property) { - Serial.print("Executing the FORCE_CLOUD sync on: "); - Serial.println(property.getPropertyName()); - property.setPropertyValue(property.getCloudShadowValue()); - if( property.getLastCloudChangeTimestamp() > property.getLastCloudSyncTimestamp()){ - property.forceCallbackOnChange(); - } -} - -#define FORCE_DEVICE_SYNC onForceDeviceSync -template -void onForceDeviceSync(ArduinoCloudProperty property) { - Serial.print("Executing the FORCE_DEVICE sync on: "); - Serial.println(property.getPropertyName()); -} +enum ArduinoIoTSynchronizationStatus { + SYNC_STATUS_SYNCHRONIZED, + SYNC_STATUS_WAIT_FOR_CLOUD_VALUES, + SYNC_STATUS_VALUES_PROCESSED +}; class ArduinoIoTCloudClass { @@ -100,15 +75,12 @@ class ArduinoIoTCloudClass { int connect (); bool disconnect(); - void prova(); void poll() __attribute__((deprecated)); /* Attention: Function is deprecated - use 'update' instead */ void update(void (*callback)(void) = NULL); // defined for users who want to specify max reconnections reties and timeout between them void update(int const reconnectionMaxRetries, int const reconnectionTimeoutMs, void (*callback)(void) = NULL); - // get the status of synchronization after getLastValues request - bool getLastValuesSyncStatus(); int connected(); // Clean up existing Mqtt connection, create a new one and initialize it @@ -126,21 +98,11 @@ class ArduinoIoTCloudClass { template - void addPropertyReal(T & property, String name, permissionType permission_type = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, N minDelta = N(0), void(*synFn)(ArduinoCloudProperty property) = FORCE_CLOUD_SYNC) { + void addPropertyReal(T & property, String name, permissionType permission_type = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, void(*synFn)(ArduinoCloudProperty property) = FORCE_CLOUD_SYNC, N minDelta = N(0)) { Permission permission = Permission::ReadWrite; if (permission_type == READ ) permission = Permission::Read; else if(permission_type == WRITE) permission = Permission::Write; else permission = Permission::ReadWrite; - - SyncMode syncMode = PROPERTIES_SYNC_FORCE_CLOUD; - if (synFn == (void(*)(ArduinoCloudProperty property))AUTO_SYNC) - syncMode = PROPERTIES_SYNC_AUTO; - else if (synFn == (void(*)(ArduinoCloudProperty property))FORCE_CLOUD_SYNC) - syncMode = PROPERTIES_SYNC_FORCE_CLOUD; - else if (synFn == (void(*)(ArduinoCloudProperty property))FORCE_DEVICE_SYNC) - syncMode = PROPERTIES_SYNC_FORCE_DEVICE; - else - syncMode = PROPERTIES_SYNC_CUSTOM; if(seconds == ON_CHANGE) { Thing.addPropertyReal(property, name, permission).publishOnChange((T)minDelta, DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS).onUpdate(fn).onSync(synFn); @@ -179,6 +141,10 @@ class ArduinoIoTCloudClass { ConnectionManager *connection; static void onMessage(int length); void handleMessage(int length); + ArduinoIoTSynchronizationStatus syncStatus = SYNC_STATUS_SYNCHRONIZED; + + void sendPropertiesToCloud(); + String _id, _thing_id, @@ -200,11 +166,6 @@ class ArduinoIoTCloudClass { String _dataTopicIn; String _otaTopic; Client *_net; - - // Used to synchronize properties - bool _firstReconnectionUpdate; - bool _propertiesSynchronized; - void (*_syncCallback)(void); }; extern ArduinoIoTCloudClass ArduinoCloud; From 3addcf46535a5b4ece01f12a493fd46cd0ae385f Mon Sep 17 00:00:00 2001 From: per1234 Date: Wed, 20 Feb 2019 06:47:19 +0100 Subject: [PATCH 08/22] Apply suggestions from code review Co-Authored-By: ilcato --- src/ArduinoIoTCloud.cpp | 23 ++++++++++++----------- src/ArduinoIoTCloud.h | 4 ++-- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index f8bbe9f45f9..f8301362386 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -240,15 +240,16 @@ void ArduinoIoTCloudClass::update(int const reconnectionMaxRetries, int const re (*callback)(); syncStatus = SYNC_STATUS_SYNCHRONIZED; break; - } + } } -void ArduinoIoTCloudClass::sendPropertiesToCloud() { - uint8_t data[MQTT_TRANSMIT_BUFFER_SIZE]; - int const length = Thing.encode(data, sizeof(data)); - if (length > 0) { - writeProperties(data, length); - } +void ArduinoIoTCloudClass::sendPropertiesToCloud() +{ + uint8_t data[MQTT_TRANSMIT_BUFFER_SIZE]; + int const length = Thing.encode(data, sizeof(data)); + if (length > 0) { + writeProperties(data, length); + } } int ArduinoIoTCloudClass::reconnect(Client& /* net */) @@ -348,10 +349,10 @@ void ArduinoIoTCloudClass::handleMessage(int length) void ArduinoIoTCloudClass::requestLastValue() { - // Send the getLastValues CBOR message to the cloud - // [{0: "r:m", 3: "getLastValues"}] = 81 A2 00 63 72 3A 6D 03 6D 67 65 74 4C 61 73 74 56 61 6C 75 65 73 - const uint8_t data[] = { 0x81, 0xA2, 0x00, 0x63, 0x72, 0x3A, 0x6D, 0x03, 0x6D, 0x67, 0x65, 0x74, 0x4C, 0x61, 0x73, 0x74, 0x56, 0x61, 0x6C, 0x75, 0x65, 0x73 }; - writeShadowOut(data, sizeof data); + // Send the getLastValues CBOR message to the cloud + // [{0: "r:m", 3: "getLastValues"}] = 81 A2 00 63 72 3A 6D 03 6D 67 65 74 4C 61 73 74 56 61 6C 75 65 73 + const uint8_t data[] = { 0x81, 0xA2, 0x00, 0x63, 0x72, 0x3A, 0x6D, 0x03, 0x6D, 0x67, 0x65, 0x74, 0x4C, 0x61, 0x73, 0x74, 0x56, 0x61, 0x6C, 0x75, 0x65, 0x73 }; + writeShadowOut(data, sizeof data); } void ArduinoIoTCloudClass::connectionCheck() diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index 195dce9f6c5..b34c0725b9b 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -153,8 +153,8 @@ class ArduinoIoTCloudClass { ArduinoCloudThing Thing; BearSSLClient* _bearSslClient; MqttClient* _mqttClient; - int _lastSyncRequestTickTime; - bool _callGetLastValueCallback; + int _lastSyncRequestTickTime; + bool _callGetLastValueCallback; // Class attribute to define MTTQ topics 2 for stdIn/out and 2 for data, in order to avoid getting previous pupblished payload From 860dbb3e4c9225c11980441e6f0ee2a5209249d9 Mon Sep 17 00:00:00 2001 From: ilcato Date: Thu, 21 Feb 2019 17:11:58 +0100 Subject: [PATCH 09/22] Added compilation warning in cased of absence of RTC. --- src/ArduinoIoTCloud.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index f8301362386..f3fc08ce01e 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -46,6 +46,7 @@ static unsigned long getTimestamp() { #ifdef ARDUINO_ARCH_SAMD return rtc.getEpoch(); #else + #warning "No RTC available on this architecture - ArduinoIoTCloud will not keep track of local changes timestamps ." return 0; #endif } From 7e5fe28a49c613d44485ece14e0085dd2636fe47 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Thu, 21 Feb 2019 17:15:26 +0100 Subject: [PATCH 10/22] Update src/ArduinoIoTCloud.cpp Co-Authored-By: ilcato --- src/ArduinoIoTCloud.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index f3fc08ce01e..21f7328c674 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -214,7 +214,7 @@ void ArduinoIoTCloudClass::update(void (*callback)(void)) void ArduinoIoTCloudClass::update(int const reconnectionMaxRetries, int const reconnectionTimeoutMs) { - unsigned long timestamp = getTimestamp(); + unsigned long const timestamp = getTimestamp(); //check if a property is changed if(timestamp) Thing.updateTimestampOnChangedProperties(timestamp); From 1eddd1b86f19bf049a3abf48dd3c482982fb6231 Mon Sep 17 00:00:00 2001 From: ilcato Date: Thu, 21 Feb 2019 17:23:26 +0100 Subject: [PATCH 11/22] Cleanup callback definition --- src/ArduinoIoTCloud.cpp | 8 ++++---- src/ArduinoIoTCloud.h | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index 21f7328c674..62134eb96e8 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -206,10 +206,10 @@ void ArduinoIoTCloudClass::poll() update(); } -void ArduinoIoTCloudClass::update(void (*callback)(void)) +void ArduinoIoTCloudClass::update(CallbackFunc onSyncCompleteCallback) { // If user call update() without parameters use the default ones - update(MAX_RETRIES, RECONNECTION_TIMEOUT, callback); + update(MAX_RETRIES, RECONNECTION_TIMEOUT, onSyncCompleteCallback); } void ArduinoIoTCloudClass::update(int const reconnectionMaxRetries, int const reconnectionTimeoutMs) @@ -237,8 +237,8 @@ void ArduinoIoTCloudClass::update(int const reconnectionMaxRetries, int const re } break; case SYNC_STATUS_VALUES_PROCESSED: - if(callback != NULL) - (*callback)(); + if(onSyncCompleteCallback != NULL) + (*onSyncCompleteCallback)(); syncStatus = SYNC_STATUS_SYNCHRONIZED; break; } diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index b34c0725b9b..48dc2029388 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -40,6 +40,8 @@ typedef struct { int timeout; } mqttConnectionOptions; +typedef void (*CallbackFunc)(void); + extern ConnectionManager *ArduinoIoTPreferredConnection; enum ArduinoIoTConnectionStatus { @@ -77,10 +79,10 @@ class ArduinoIoTCloudClass { bool disconnect(); void poll() __attribute__((deprecated)); /* Attention: Function is deprecated - use 'update' instead */ - void update(void (*callback)(void) = NULL); + void update(CallbackFunc onSyncCompleteCallback = NULL); // defined for users who want to specify max reconnections reties and timeout between them - void update(int const reconnectionMaxRetries, int const reconnectionTimeoutMs, void (*callback)(void) = NULL); + void update(int const reconnectionMaxRetries, int const reconnectionTimeoutMs, CallbackFunc onSyncCompleteCallback = NULL); int connected(); // Clean up existing Mqtt connection, create a new one and initialize it From e8028be04762f840805169f6515be6ecc17c5833 Mon Sep 17 00:00:00 2001 From: ilcato Date: Thu, 21 Feb 2019 17:28:39 +0100 Subject: [PATCH 12/22] Enum cleanup --- src/ArduinoIoTCloud.cpp | 14 +++++++------- src/ArduinoIoTCloud.h | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index 62134eb96e8..f7105babee6 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -188,7 +188,7 @@ int ArduinoIoTCloudClass::connect() _mqttClient->subscribe(_dataTopicIn); _mqttClient->subscribe(_shadowTopicIn); - syncStatus = SYNC_STATUS_WAIT_FOR_CLOUD_VALUES; + syncStatus = ArduinoIoTSynchronizationStatus::SYNC_STATUS_WAIT_FOR_CLOUD_VALUES; _lastSyncRequestTickTime = 0; return 1; @@ -227,19 +227,19 @@ void ArduinoIoTCloudClass::update(int const reconnectionMaxRetries, int const re _mqttClient->poll(); switch (syncStatus) { - case SYNC_STATUS_SYNCHRONIZED: + case ArduinoIoTSynchronizationStatus::SYNC_STATUS_SYNCHRONIZED: sendPropertiesToCloud(); break; - case SYNC_STATUS_WAIT_FOR_CLOUD_VALUES: + case ArduinoIoTSynchronizationStatus::SYNC_STATUS_WAIT_FOR_CLOUD_VALUES: if (millis() - _lastSyncRequestTickTime > TIMEOUT_FOR_LASTVALUES_SYNC) { requestLastValue(); _lastSyncRequestTickTime = millis(); } break; - case SYNC_STATUS_VALUES_PROCESSED: + case ArduinoIoTSynchronizationStatus::SYNC_STATUS_VALUES_PROCESSED: if(onSyncCompleteCallback != NULL) (*onSyncCompleteCallback)(); - syncStatus = SYNC_STATUS_SYNCHRONIZED; + syncStatus = ArduinoIoTSynchronizationStatus::SYNC_STATUS_SYNCHRONIZED; break; } } @@ -341,10 +341,10 @@ void ArduinoIoTCloudClass::handleMessage(int length) if (_dataTopicIn == topic) { Thing.decode((uint8_t*)bytes, length); } - if ((_shadowTopicIn == topic) && syncStatus == SYNC_STATUS_WAIT_FOR_CLOUD_VALUES) { + if ((_shadowTopicIn == topic) && syncStatus == ArduinoIoTSynchronizationStatus::SYNC_STATUS_WAIT_FOR_CLOUD_VALUES) { Thing.decode((uint8_t*)bytes, length, true); sendPropertiesToCloud(); - syncStatus = SYNC_STATUS_VALUES_PROCESSED; + syncStatus = ArduinoIoTSynchronizationStatus::SYNC_STATUS_VALUES_PROCESSED; } } diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index 48dc2029388..ac4dc926593 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -53,7 +53,7 @@ enum ArduinoIoTConnectionStatus { IOT_STATUS_CLOUD_ERROR, }; -enum ArduinoIoTSynchronizationStatus { +enum class ArduinoIoTSynchronizationStatus { SYNC_STATUS_SYNCHRONIZED, SYNC_STATUS_WAIT_FOR_CLOUD_VALUES, SYNC_STATUS_VALUES_PROCESSED @@ -143,7 +143,7 @@ class ArduinoIoTCloudClass { ConnectionManager *connection; static void onMessage(int length); void handleMessage(int length); - ArduinoIoTSynchronizationStatus syncStatus = SYNC_STATUS_SYNCHRONIZED; + ArduinoIoTSynchronizationStatus syncStatus = ArduinoIoTSynchronizationStatus::SYNC_STATUS_SYNCHRONIZED; void sendPropertiesToCloud(); From c399baff7121c6da08e7a057b22d654910c8b1ab Mon Sep 17 00:00:00 2001 From: ilcato Date: Thu, 21 Feb 2019 17:31:07 +0100 Subject: [PATCH 13/22] Class memeber cleanup --- src/ArduinoIoTCloud.cpp | 10 +++++----- src/ArduinoIoTCloud.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index f7105babee6..19ad2ce881d 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -188,7 +188,7 @@ int ArduinoIoTCloudClass::connect() _mqttClient->subscribe(_dataTopicIn); _mqttClient->subscribe(_shadowTopicIn); - syncStatus = ArduinoIoTSynchronizationStatus::SYNC_STATUS_WAIT_FOR_CLOUD_VALUES; + _syncStatus = ArduinoIoTSynchronizationStatus::SYNC_STATUS_WAIT_FOR_CLOUD_VALUES; _lastSyncRequestTickTime = 0; return 1; @@ -226,7 +226,7 @@ void ArduinoIoTCloudClass::update(int const reconnectionMaxRetries, int const re // MTTQClient connected!, poll() used to retrieve data from MQTT broker _mqttClient->poll(); - switch (syncStatus) { + switch (_syncStatus) { case ArduinoIoTSynchronizationStatus::SYNC_STATUS_SYNCHRONIZED: sendPropertiesToCloud(); break; @@ -239,7 +239,7 @@ void ArduinoIoTCloudClass::update(int const reconnectionMaxRetries, int const re case ArduinoIoTSynchronizationStatus::SYNC_STATUS_VALUES_PROCESSED: if(onSyncCompleteCallback != NULL) (*onSyncCompleteCallback)(); - syncStatus = ArduinoIoTSynchronizationStatus::SYNC_STATUS_SYNCHRONIZED; + _syncStatus = ArduinoIoTSynchronizationStatus::SYNC_STATUS_SYNCHRONIZED; break; } } @@ -341,10 +341,10 @@ void ArduinoIoTCloudClass::handleMessage(int length) if (_dataTopicIn == topic) { Thing.decode((uint8_t*)bytes, length); } - if ((_shadowTopicIn == topic) && syncStatus == ArduinoIoTSynchronizationStatus::SYNC_STATUS_WAIT_FOR_CLOUD_VALUES) { + if ((_shadowTopicIn == topic) && _syncStatus == ArduinoIoTSynchronizationStatus::SYNC_STATUS_WAIT_FOR_CLOUD_VALUES) { Thing.decode((uint8_t*)bytes, length, true); sendPropertiesToCloud(); - syncStatus = ArduinoIoTSynchronizationStatus::SYNC_STATUS_VALUES_PROCESSED; + _syncStatus = ArduinoIoTSynchronizationStatus::SYNC_STATUS_VALUES_PROCESSED; } } diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index ac4dc926593..1ced6560e0a 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -143,7 +143,7 @@ class ArduinoIoTCloudClass { ConnectionManager *connection; static void onMessage(int length); void handleMessage(int length); - ArduinoIoTSynchronizationStatus syncStatus = ArduinoIoTSynchronizationStatus::SYNC_STATUS_SYNCHRONIZED; + ArduinoIoTSynchronizationStatus _syncStatus = ArduinoIoTSynchronizationStatus::SYNC_STATUS_SYNCHRONIZED; void sendPropertiesToCloud(); From e101b79ef4b26027e817285b29090cd5004cbc08 Mon Sep 17 00:00:00 2001 From: ilcato Date: Thu, 21 Feb 2019 18:01:48 +0100 Subject: [PATCH 14/22] Reanme of the standard sync callbacks. --- src/ArduinoIoTCloud.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index 1ced6560e0a..3109ede0cc9 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -100,7 +100,7 @@ class ArduinoIoTCloudClass { template - void addPropertyReal(T & property, String name, permissionType permission_type = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, void(*synFn)(ArduinoCloudProperty property) = FORCE_CLOUD_SYNC, N minDelta = N(0)) { + void addPropertyReal(T & property, String name, permissionType permission_type = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, void(*synFn)(ArduinoCloudProperty property) = CLOUD_WINS, N minDelta = N(0)) { Permission permission = Permission::ReadWrite; if (permission_type == READ ) permission = Permission::Read; else if(permission_type == WRITE) permission = Permission::Write; From ddd80f7ca67973ceb209b0f2063567d9a1497dc0 Mon Sep 17 00:00:00 2001 From: ilcato Date: Tue, 26 Feb 2019 15:00:43 +0100 Subject: [PATCH 15/22] Fixed update signature --- src/ArduinoIoTCloud.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index 19ad2ce881d..76a36108668 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -212,7 +212,7 @@ void ArduinoIoTCloudClass::update(CallbackFunc onSyncCompleteCallback) update(MAX_RETRIES, RECONNECTION_TIMEOUT, onSyncCompleteCallback); } -void ArduinoIoTCloudClass::update(int const reconnectionMaxRetries, int const reconnectionTimeoutMs) +void ArduinoIoTCloudClass::update(int const reconnectionMaxRetries, int const reconnectionTimeoutMs, CallbackFunc onSyncCompleteCallback) { unsigned long const timestamp = getTimestamp(); //check if a property is changed From 0b83429f20e9753ec00202345ff94611c0aa52b2 Mon Sep 17 00:00:00 2001 From: ilcato Date: Tue, 26 Feb 2019 15:32:13 +0100 Subject: [PATCH 16/22] Fix getTime management --- src/ArduinoIoTCloud.cpp | 8 +------- src/ConnectionManager.h | 8 ++++++-- src/GSMConnectionManager.h | 9 +++++++-- src/WiFiConnectionManager.h | 7 ++++++- src/utility/NTPUtils.cpp | 1 - 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index 76a36108668..7731e135fa0 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -33,13 +33,7 @@ const static int thingIdSlot = 12; static ConnectionManager *getTimeConnection = NULL; static unsigned long getTime() { - if (!getTimeConnection) return 0; - unsigned long time = getTimeConnection->getTime(); - if (!NTPUtils::isTimeValid(time)) { - debugMessage("Bogus NTP time from API, fallback to UDP method", 0); - time = NTPUtils(getTimeConnection->getUDP()).getTime(); - } - return time; + return getTimeConnection->getTime(); } static unsigned long getTimestamp() { diff --git a/src/ConnectionManager.h b/src/ConnectionManager.h index f8dc92339d9..8c1a489728f 100644 --- a/src/ConnectionManager.h +++ b/src/ConnectionManager.h @@ -38,9 +38,9 @@ class ConnectionManager { public: virtual void init() = 0; virtual void check() = 0; - virtual unsigned long getTime() = 0; + virtual unsigned long getTime(); virtual Client &getClient(); - virtual UDP &getUDP(); + virtual UDP &getUDP() = 0; virtual NetworkConnectionState getStatus() { return netConnectionState; } @@ -96,6 +96,10 @@ inline void debugMessage(char *_msg, int _debugLevel, bool _timestamp = true, bo } } +inline unsigned long ConnectionManager::getTime() { + return NTPUtils(this->getUDP()).getTime(); +} + inline void setDebugMessageLevel(int _debugLevel){ debugMessageLevel = _debugLevel; } diff --git a/src/GSMConnectionManager.h b/src/GSMConnectionManager.h index 676f924cdb0..7703505e1c1 100644 --- a/src/GSMConnectionManager.h +++ b/src/GSMConnectionManager.h @@ -39,7 +39,7 @@ class GSMConnectionManager : public ConnectionManager { const int CHECK_INTERVAL_IDLE = 100; const int CHECK_INTERVAL_INIT = 100; const int CHECK_INTERVAL_CONNECTING = 500; - const int CHECK_INTERVAL_GETTIME = 666; + const int CHECK_INTERVAL_GETTIME = 10; const int CHECK_INTERVAL_CONNECTED = 10000; const int CHECK_INTERVAL_RETRYING = 5000; const int CHECK_INTERVAL_DISCONNECTED = 1000; @@ -67,7 +67,12 @@ GSMConnectionManager::GSMConnectionManager(const char *pin, const char *apn, con } unsigned long GSMConnectionManager::getTime() { - return gsmAccess.getTime(); + unsigned long time = ConnectionManager::getTime() { + if (!NTPUtils::isTimeValid(time)) { + debugMessage("Bogus NTP time from API, fallback to UDP method", 0); + time = gsmAccess.getTime(); + } + return time; } void GSMConnectionManager::init() { diff --git a/src/WiFiConnectionManager.h b/src/WiFiConnectionManager.h index c9915e3343c..cede0739f80 100644 --- a/src/WiFiConnectionManager.h +++ b/src/WiFiConnectionManager.h @@ -63,7 +63,12 @@ WiFiConnectionManager::WiFiConnectionManager(const char *ssid, const char *pass) } unsigned long WiFiConnectionManager::getTime() { - return WiFi.getTime(); + unsigned long time = ConnectionManager::getTime(); + if (!NTPUtils::isTimeValid(time)) { + debugMessage("Bogus NTP time from API, fallback to UDP method", 0); + time = WiFi.getTime(); + } + return time; } void WiFiConnectionManager::init() { diff --git a/src/utility/NTPUtils.cpp b/src/utility/NTPUtils.cpp index 5d1129117bb..0a61cc7b209 100644 --- a/src/utility/NTPUtils.cpp +++ b/src/utility/NTPUtils.cpp @@ -29,7 +29,6 @@ static time_t cvt_TIME(char const *time) { NTPUtils::NTPUtils(UDP& Udp) : Udp(Udp) {} bool NTPUtils::isTimeValid(unsigned long time) { - Serial.println("Compile time: " + String(cvt_TIME(__DATE__))); return (time > cvt_TIME(__DATE__)); } From 8b5ac80e4fc748409cc95d3b55072c4fb25d0e32 Mon Sep 17 00:00:00 2001 From: ilcato Date: Tue, 26 Feb 2019 15:36:21 +0100 Subject: [PATCH 17/22] Changed debug message --- src/GSMConnectionManager.h | 2 +- src/WiFiConnectionManager.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GSMConnectionManager.h b/src/GSMConnectionManager.h index 7703505e1c1..f7acff3ffdc 100644 --- a/src/GSMConnectionManager.h +++ b/src/GSMConnectionManager.h @@ -69,7 +69,7 @@ GSMConnectionManager::GSMConnectionManager(const char *pin, const char *apn, con unsigned long GSMConnectionManager::getTime() { unsigned long time = ConnectionManager::getTime() { if (!NTPUtils::isTimeValid(time)) { - debugMessage("Bogus NTP time from API, fallback to UDP method", 0); + debugMessage("Bogus UDP time from, fallback to Network method", 0); time = gsmAccess.getTime(); } return time; diff --git a/src/WiFiConnectionManager.h b/src/WiFiConnectionManager.h index cede0739f80..d492484fd56 100644 --- a/src/WiFiConnectionManager.h +++ b/src/WiFiConnectionManager.h @@ -65,7 +65,7 @@ WiFiConnectionManager::WiFiConnectionManager(const char *ssid, const char *pass) unsigned long WiFiConnectionManager::getTime() { unsigned long time = ConnectionManager::getTime(); if (!NTPUtils::isTimeValid(time)) { - debugMessage("Bogus NTP time from API, fallback to UDP method", 0); + debugMessage("Bogus UDP time from, fallback to Network method", 0); time = WiFi.getTime(); } return time; From aa128549005c1ff563d0b41e298af0df2018c432 Mon Sep 17 00:00:00 2001 From: Alexander Entinger Date: Wed, 27 Feb 2019 08:17:41 +0100 Subject: [PATCH 18/22] Apply suggestions from @lxrobotics code review Co-Authored-By: ilcato --- src/ArduinoIoTCloud.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index 7731e135fa0..335e44880da 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -40,7 +40,7 @@ static unsigned long getTimestamp() { #ifdef ARDUINO_ARCH_SAMD return rtc.getEpoch(); #else - #warning "No RTC available on this architecture - ArduinoIoTCloud will not keep track of local changes timestamps ." + #warning "No RTC available on this architecture - ArduinoIoTCloud will not keep track of local change timestamps ." return 0; #endif } @@ -210,7 +210,7 @@ void ArduinoIoTCloudClass::update(int const reconnectionMaxRetries, int const re { unsigned long const timestamp = getTimestamp(); //check if a property is changed - if(timestamp) Thing.updateTimestampOnChangedProperties(timestamp); + if(timestamp != 0) Thing.updateTimestampOnChangedProperties(timestamp); connectionCheck(); if(iotStatus != IOT_STATUS_CLOUD_CONNECTED){ @@ -347,7 +347,7 @@ void ArduinoIoTCloudClass::requestLastValue() // Send the getLastValues CBOR message to the cloud // [{0: "r:m", 3: "getLastValues"}] = 81 A2 00 63 72 3A 6D 03 6D 67 65 74 4C 61 73 74 56 61 6C 75 65 73 const uint8_t data[] = { 0x81, 0xA2, 0x00, 0x63, 0x72, 0x3A, 0x6D, 0x03, 0x6D, 0x67, 0x65, 0x74, 0x4C, 0x61, 0x73, 0x74, 0x56, 0x61, 0x6C, 0x75, 0x65, 0x73 }; - writeShadowOut(data, sizeof data); + writeShadowOut(data, sizeof(data)); } void ArduinoIoTCloudClass::connectionCheck() @@ -405,7 +405,7 @@ void ArduinoIoTCloudClass::connectionCheck() CloudSerial.println("Hello from Cloud Serial!"); } #ifdef ARDUINO_ARCH_SAMD - unsigned long epoch = getTime(); + unsigned long const epoch = getTime(); if (epoch!=0) rtc.setEpoch(epoch); #endif From 85e760eb9ce77e38481fba20f2bb91d41f368744 Mon Sep 17 00:00:00 2001 From: ilcato Date: Wed, 27 Feb 2019 08:20:47 +0100 Subject: [PATCH 19/22] Cleanup code --- src/ArduinoIoTCloud.cpp | 4 ++-- src/ArduinoIoTCloud.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index 335e44880da..656821c4e13 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -346,8 +346,8 @@ void ArduinoIoTCloudClass::requestLastValue() { // Send the getLastValues CBOR message to the cloud // [{0: "r:m", 3: "getLastValues"}] = 81 A2 00 63 72 3A 6D 03 6D 67 65 74 4C 61 73 74 56 61 6C 75 65 73 - const uint8_t data[] = { 0x81, 0xA2, 0x00, 0x63, 0x72, 0x3A, 0x6D, 0x03, 0x6D, 0x67, 0x65, 0x74, 0x4C, 0x61, 0x73, 0x74, 0x56, 0x61, 0x6C, 0x75, 0x65, 0x73 }; - writeShadowOut(data, sizeof(data)); + const uint8_t CBOR_REQUEST_LAST_VALUE_MSG[] = { 0x81, 0xA2, 0x00, 0x63, 0x72, 0x3A, 0x6D, 0x03, 0x6D, 0x67, 0x65, 0x74, 0x4C, 0x61, 0x73, 0x74, 0x56, 0x61, 0x6C, 0x75, 0x65, 0x73 }; + writeShadowOut(CBOR_REQUEST_LAST_VALUE_MSG, sizeof(CBOR_REQUEST_LAST_VALUE_MSG)); } void ArduinoIoTCloudClass::connectionCheck() diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index 3109ede0cc9..2d10a203ccc 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -156,7 +156,6 @@ class ArduinoIoTCloudClass { BearSSLClient* _bearSslClient; MqttClient* _mqttClient; int _lastSyncRequestTickTime; - bool _callGetLastValueCallback; // Class attribute to define MTTQ topics 2 for stdIn/out and 2 for data, in order to avoid getting previous pupblished payload From 410a1b41be4f36b30171be9d907f72738e5bcee6 Mon Sep 17 00:00:00 2001 From: ilcato Date: Wed, 27 Feb 2019 18:02:31 +0100 Subject: [PATCH 20/22] Call API getTime first and use NTP UDP as a fallback --- src/GSMConnectionManager.h | 6 +++--- src/WiFiConnectionManager.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/GSMConnectionManager.h b/src/GSMConnectionManager.h index f7acff3ffdc..dc118d3fe13 100644 --- a/src/GSMConnectionManager.h +++ b/src/GSMConnectionManager.h @@ -67,10 +67,10 @@ GSMConnectionManager::GSMConnectionManager(const char *pin, const char *apn, con } unsigned long GSMConnectionManager::getTime() { - unsigned long time = ConnectionManager::getTime() { + unsigned long time = gsmAccess.getTime() { if (!NTPUtils::isTimeValid(time)) { - debugMessage("Bogus UDP time from, fallback to Network method", 0); - time = gsmAccess.getTime(); + debugMessage("Bogus NTP time from API, fallback to UDP method", 0); + time = ConnectionManager::getTime(); } return time; } diff --git a/src/WiFiConnectionManager.h b/src/WiFiConnectionManager.h index d492484fd56..211b87998af 100644 --- a/src/WiFiConnectionManager.h +++ b/src/WiFiConnectionManager.h @@ -63,10 +63,10 @@ WiFiConnectionManager::WiFiConnectionManager(const char *ssid, const char *pass) } unsigned long WiFiConnectionManager::getTime() { - unsigned long time = ConnectionManager::getTime(); + unsigned long time = WiFi.getTime(); if (!NTPUtils::isTimeValid(time)) { - debugMessage("Bogus UDP time from, fallback to Network method", 0); - time = WiFi.getTime(); + debugMessage("Bogus NTP time from API, fallback to UDP method", 0); + time = ConnectionManager::getTime(); } return time; } From 24a632dab349cec9d33cfa352ef06ce4e5e114bb Mon Sep 17 00:00:00 2001 From: ilcato Date: Tue, 12 Mar 2019 14:47:56 +0100 Subject: [PATCH 21/22] Document the way to generate the CBOR encoding --- src/ArduinoIoTCloud.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index 656821c4e13..75ad82ced29 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -346,6 +346,7 @@ void ArduinoIoTCloudClass::requestLastValue() { // Send the getLastValues CBOR message to the cloud // [{0: "r:m", 3: "getLastValues"}] = 81 A2 00 63 72 3A 6D 03 6D 67 65 74 4C 61 73 74 56 61 6C 75 65 73 + // Use http://cbor.me to easily generate CBOR encoding const uint8_t CBOR_REQUEST_LAST_VALUE_MSG[] = { 0x81, 0xA2, 0x00, 0x63, 0x72, 0x3A, 0x6D, 0x03, 0x6D, 0x67, 0x65, 0x74, 0x4C, 0x61, 0x73, 0x74, 0x56, 0x61, 0x6C, 0x75, 0x65, 0x73 }; writeShadowOut(CBOR_REQUEST_LAST_VALUE_MSG, sizeof(CBOR_REQUEST_LAST_VALUE_MSG)); } From 5a2cf5c3fcf4639831ebe7083345ef27d4585de3 Mon Sep 17 00:00:00 2001 From: ilcato Date: Wed, 13 Mar 2019 11:17:42 +0100 Subject: [PATCH 22/22] Revert fix getTime management --- src/ArduinoIoTCloud.cpp | 8 +++++++- src/ConnectionManager.h | 8 ++------ src/GSMConnectionManager.h | 9 ++------- src/WiFiConnectionManager.h | 7 +------ src/utility/NTPUtils.cpp | 1 + 5 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index 75ad82ced29..2b04377f64a 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -33,7 +33,13 @@ const static int thingIdSlot = 12; static ConnectionManager *getTimeConnection = NULL; static unsigned long getTime() { - return getTimeConnection->getTime(); + if (!getTimeConnection) return 0; + unsigned long time = getTimeConnection->getTime(); + if (!NTPUtils::isTimeValid(time)) { + debugMessage("Bogus NTP time from API, fallback to UDP method", 0); + time = NTPUtils(getTimeConnection->getUDP()).getTime(); + } + return time; } static unsigned long getTimestamp() { diff --git a/src/ConnectionManager.h b/src/ConnectionManager.h index 8c1a489728f..f8dc92339d9 100644 --- a/src/ConnectionManager.h +++ b/src/ConnectionManager.h @@ -38,9 +38,9 @@ class ConnectionManager { public: virtual void init() = 0; virtual void check() = 0; - virtual unsigned long getTime(); + virtual unsigned long getTime() = 0; virtual Client &getClient(); - virtual UDP &getUDP() = 0; + virtual UDP &getUDP(); virtual NetworkConnectionState getStatus() { return netConnectionState; } @@ -96,10 +96,6 @@ inline void debugMessage(char *_msg, int _debugLevel, bool _timestamp = true, bo } } -inline unsigned long ConnectionManager::getTime() { - return NTPUtils(this->getUDP()).getTime(); -} - inline void setDebugMessageLevel(int _debugLevel){ debugMessageLevel = _debugLevel; } diff --git a/src/GSMConnectionManager.h b/src/GSMConnectionManager.h index dc118d3fe13..676f924cdb0 100644 --- a/src/GSMConnectionManager.h +++ b/src/GSMConnectionManager.h @@ -39,7 +39,7 @@ class GSMConnectionManager : public ConnectionManager { const int CHECK_INTERVAL_IDLE = 100; const int CHECK_INTERVAL_INIT = 100; const int CHECK_INTERVAL_CONNECTING = 500; - const int CHECK_INTERVAL_GETTIME = 10; + const int CHECK_INTERVAL_GETTIME = 666; const int CHECK_INTERVAL_CONNECTED = 10000; const int CHECK_INTERVAL_RETRYING = 5000; const int CHECK_INTERVAL_DISCONNECTED = 1000; @@ -67,12 +67,7 @@ GSMConnectionManager::GSMConnectionManager(const char *pin, const char *apn, con } unsigned long GSMConnectionManager::getTime() { - unsigned long time = gsmAccess.getTime() { - if (!NTPUtils::isTimeValid(time)) { - debugMessage("Bogus NTP time from API, fallback to UDP method", 0); - time = ConnectionManager::getTime(); - } - return time; + return gsmAccess.getTime(); } void GSMConnectionManager::init() { diff --git a/src/WiFiConnectionManager.h b/src/WiFiConnectionManager.h index 211b87998af..c9915e3343c 100644 --- a/src/WiFiConnectionManager.h +++ b/src/WiFiConnectionManager.h @@ -63,12 +63,7 @@ WiFiConnectionManager::WiFiConnectionManager(const char *ssid, const char *pass) } unsigned long WiFiConnectionManager::getTime() { - unsigned long time = WiFi.getTime(); - if (!NTPUtils::isTimeValid(time)) { - debugMessage("Bogus NTP time from API, fallback to UDP method", 0); - time = ConnectionManager::getTime(); - } - return time; + return WiFi.getTime(); } void WiFiConnectionManager::init() { diff --git a/src/utility/NTPUtils.cpp b/src/utility/NTPUtils.cpp index 0a61cc7b209..5d1129117bb 100644 --- a/src/utility/NTPUtils.cpp +++ b/src/utility/NTPUtils.cpp @@ -29,6 +29,7 @@ static time_t cvt_TIME(char const *time) { NTPUtils::NTPUtils(UDP& Udp) : Udp(Udp) {} bool NTPUtils::isTimeValid(unsigned long time) { + Serial.println("Compile time: " + String(cvt_TIME(__DATE__))); return (time > cvt_TIME(__DATE__)); }