From c56b9a81ae5277d217df0215f0810b1582d2941b Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Fri, 16 Feb 2018 17:37:28 +0100 Subject: [PATCH 01/24] Integrate ArduinoCloudThing I really dislike that I had to expose the Thing object but otherwise the addProperty() call would become terrible. I added a line on Cloud_blink example to show the composition of functions on properties. It can be safely removed in the next iteration. --- .../MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino | 9 +++++++++ src/ArduinoCloud.cpp | 16 ++++++++++++++++ src/ArduinoCloudV2.h | 5 +++++ 3 files changed, 30 insertions(+) diff --git a/examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino b/examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino index 5724c4d30..3700f52c4 100644 --- a/examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino +++ b/examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino @@ -15,6 +15,13 @@ unsigned long getTime() { return WiFi.getTime(); } +int position; + +void onPositionUpdate() { + Serial.print("New position value: "); + Serial.println(position); +} + void setup() { //Initialize serial and wait for port to open: Serial.begin(9600); @@ -59,6 +66,8 @@ void setup() { Serial.println("Successfully connected to Arduino Cloud :)"); + ArduinoCloud.Thing.addProperty(position, READ).publishEvery(10*SECONDS).onUpdate(onPositionUpdate); + CloudSerial.begin(9600); } diff --git a/src/ArduinoCloud.cpp b/src/ArduinoCloud.cpp index fd3bbbaf5..86125fcfc 100644 --- a/src/ArduinoCloud.cpp +++ b/src/ArduinoCloud.cpp @@ -55,8 +55,11 @@ int ArduinoCloudClass::begin(Client& net, const String& id) _id = id; + Thing.begin(); + _stdoutTopic = "$aws/things/" + _id + "/stdout"; _stdinTopic = "$aws/things/" + _id + "/stdin"; + _dataTopic = "$aws/things/" + _id + "/data"; return 1; } @@ -75,6 +78,11 @@ int ArduinoCloudClass::connect() void ArduinoCloudClass::poll() { _mqttClient.loop(); + uint8_t data[1024]; + int length = Thing.poll(data); + if (length) { + writeProperties(data, length); + } } void ArduinoCloudClass::onGetTime(unsigned long(*callback)(void)) @@ -87,6 +95,11 @@ int ArduinoCloudClass::connected() return _mqttClient.connected(); } +int ArduinoCloudClass::writeProperties(const byte data[], int length) +{ + return _mqttClient.publish(_dataTopic.c_str(), (const char*)data, length); +} + int ArduinoCloudClass::writeStdout(const byte data[], int length) { return _mqttClient.publish(_stdoutTopic.c_str(), (const char*)data, length); @@ -102,6 +115,9 @@ void ArduinoCloudClass::handleMessage(char topic[], char bytes[], int length) if (_stdinTopic == topic) { CloudSerial.appendStdin((uint8_t*)bytes, length); } + if (_dataTopic == topic) { + Thing.decode((uint8_t*)bytes, length); + } } ArduinoCloudClass ArduinoCloud; diff --git a/src/ArduinoCloudV2.h b/src/ArduinoCloudV2.h index 4c8f59157..a7d8808d8 100644 --- a/src/ArduinoCloudV2.h +++ b/src/ArduinoCloudV2.h @@ -3,6 +3,7 @@ #include #include +#include #include "CloudSerial.h" @@ -22,9 +23,12 @@ class ArduinoCloudClass { int connected(); + ArduinoCloudThing Thing; + protected: friend class CloudSerialClass; int writeStdout(const byte data[], int length); + int writeProperties(const byte data[], int length); private: static void onMessage(MQTTClient *client, char topic[], char bytes[], int length); @@ -38,6 +42,7 @@ class ArduinoCloudClass { String _stdinTopic; String _stdoutTopic; + String _dataTopic; }; From 9aae39a4334b67c348d697fd52835445ff960c23 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 22 Feb 2018 16:03:55 +0100 Subject: [PATCH 02/24] Fix .readOnly/.writeOnly compisition --- examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino | 2 +- src/ArduinoCloud.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino b/examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino index 3700f52c4..731c14866 100644 --- a/examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino +++ b/examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino @@ -66,7 +66,7 @@ void setup() { Serial.println("Successfully connected to Arduino Cloud :)"); - ArduinoCloud.Thing.addProperty(position, READ).publishEvery(10*SECONDS).onUpdate(onPositionUpdate); + ArduinoCloud.Thing.addProperty(position).publishEvery(10*SECONDS).onUpdate(onPositionUpdate).readOnly(); CloudSerial.begin(9600); } diff --git a/src/ArduinoCloud.cpp b/src/ArduinoCloud.cpp index 86125fcfc..4da16ae59 100644 --- a/src/ArduinoCloud.cpp +++ b/src/ArduinoCloud.cpp @@ -71,6 +71,7 @@ int ArduinoCloudClass::connect() } _mqttClient.subscribe(_stdinTopic); + _mqttClient.subscribe(_dataTopic); return 1; } From 6391cc6daaefe7f62931a0c1adfcf51b0c1dbe0d Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 30 May 2018 15:51:40 +0200 Subject: [PATCH 03/24] Add addProperty API with complete signature --- examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino | 2 +- src/ArduinoCloudV2.h | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino b/examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino index 731c14866..f57e64862 100644 --- a/examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino +++ b/examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino @@ -66,7 +66,7 @@ void setup() { Serial.println("Successfully connected to Arduino Cloud :)"); - ArduinoCloud.Thing.addProperty(position).publishEvery(10*SECONDS).onUpdate(onPositionUpdate).readOnly(); + ArduinoCloud.addProperty(position, READ, 10*SECONDS, onPositionUpdate); CloudSerial.begin(9600); } diff --git a/src/ArduinoCloudV2.h b/src/ArduinoCloudV2.h index a7d8808d8..75ae03d2c 100644 --- a/src/ArduinoCloudV2.h +++ b/src/ArduinoCloudV2.h @@ -23,7 +23,12 @@ class ArduinoCloudClass { int connected(); - ArduinoCloudThing Thing; + #define addPropertyMacro(prop) addPropertyReal(prop, #prop) + #undef addProperty + + template void addProperty(T property, permissionType _permission = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL) { + Thing.addPropertyMacro(property).publishEvery(seconds).setPermission(_permission).onUpdate(fn); + } protected: friend class CloudSerialClass; @@ -37,6 +42,7 @@ class ArduinoCloudClass { private: String _id; + ArduinoCloudThing Thing; BearSSLClient* _bearSslClient; MQTTClient _mqttClient; From 2406990bbd4bf87e3555a6f2f04cf72abb66471c Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 30 May 2018 15:51:53 +0200 Subject: [PATCH 04/24] Initial testing on OTA --- src/ArduinoCloud.cpp | 26 ++++++++++++++++++++++++++ src/ArduinoCloudV2.h | 3 +++ 2 files changed, 29 insertions(+) diff --git a/src/ArduinoCloud.cpp b/src/ArduinoCloud.cpp index 4da16ae59..07f4adb1d 100644 --- a/src/ArduinoCloud.cpp +++ b/src/ArduinoCloud.cpp @@ -4,6 +4,8 @@ #include #include "CloudSerial.h" +#include "SerialFlashStorage.h" +//#include "SFU.h" const static char server[] = "a19g5nbe27wn47.iot.eu-west-1.amazonaws.com"; //"xxxxxxxxxxxxxx.iot.xx-xxxx-x.amazonaws.com"; @@ -13,6 +15,7 @@ const static int serialNumberSlot = 11; ArduinoCloudClass::ArduinoCloudClass() : _bearSslClient(NULL), + _otaClient(NULL), _mqttClient(256) { } @@ -22,6 +25,9 @@ ArduinoCloudClass::~ArduinoCloudClass() if (_bearSslClient) { delete _bearSslClient; } + if (_otaClient) { + delete _otaClient; + } } int ArduinoCloudClass::begin(Client& net, const String& id) @@ -57,9 +63,12 @@ int ArduinoCloudClass::begin(Client& net, const String& id) Thing.begin(); + _otaClient = new HttpClient(net, server, 80); + _stdoutTopic = "$aws/things/" + _id + "/stdout"; _stdinTopic = "$aws/things/" + _id + "/stdin"; _dataTopic = "$aws/things/" + _id + "/data"; + _otaTopic = "$aws/things/" + _id + "/upload"; return 1; } @@ -72,6 +81,7 @@ int ArduinoCloudClass::connect() _mqttClient.subscribe(_stdinTopic); _mqttClient.subscribe(_dataTopic); + _mqttClient.subscribe(_otaTopic); return 1; } @@ -119,6 +129,22 @@ void ArduinoCloudClass::handleMessage(char topic[], char bytes[], int length) if (_dataTopic == topic) { Thing.decode((uint8_t*)bytes, length); } + if (_otaTopic == topic) { + + String url = String(bytes); + + _otaClient->get(url); + + SerialFlashStorage.open(_otaClient->contentLength()); + uint8_t buf[1024]; + while (_otaClient->available()) { + int size = _otaClient->available() >= 1024 ? 1024 : _otaClient->available(); + _otaClient->read(buf, size); + SerialFlashStorage.write((uint8_t*)buf, size); + } + SerialFlashStorage.close(); + SerialFlashStorage.apply(); + } } ArduinoCloudClass ArduinoCloud; diff --git a/src/ArduinoCloudV2.h b/src/ArduinoCloudV2.h index 75ae03d2c..b29114bbc 100644 --- a/src/ArduinoCloudV2.h +++ b/src/ArduinoCloudV2.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "CloudSerial.h" @@ -45,10 +46,12 @@ class ArduinoCloudClass { ArduinoCloudThing Thing; BearSSLClient* _bearSslClient; MQTTClient _mqttClient; + HttpClient* _otaClient; String _stdinTopic; String _stdoutTopic; String _dataTopic; + String _otaTopic; }; From 543c75b5c15a69c2cbdba8336dd81bf65a06fb61 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 30 May 2018 18:36:54 +0200 Subject: [PATCH 05/24] Port to fixed ArduinoCloudThing --- src/ArduinoCloud.cpp | 2 -- src/ArduinoCloudV2.h | 7 ++----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/ArduinoCloud.cpp b/src/ArduinoCloud.cpp index 2e90323aa..b379b0bb1 100644 --- a/src/ArduinoCloud.cpp +++ b/src/ArduinoCloud.cpp @@ -67,8 +67,6 @@ int ArduinoCloudClass::begin(Client& net) _mqttClient.onMessageAdvanced(ArduinoCloudClass::onMessage); _mqttClient.begin(server, 8883, *_bearSslClient); - _id = id; - Thing.begin(); _otaClient = new HttpClient(net, server, 80); diff --git a/src/ArduinoCloudV2.h b/src/ArduinoCloudV2.h index 6f7517a49..65f166df4 100644 --- a/src/ArduinoCloudV2.h +++ b/src/ArduinoCloudV2.h @@ -24,11 +24,8 @@ class ArduinoCloudClass { int connected(); - #define addPropertyMacro(prop) addPropertyReal(prop, #prop) - #undef addProperty - template void addProperty(T property, permissionType _permission = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL) { - Thing.addPropertyMacro(property).publishEvery(seconds).setPermission(_permission).onUpdate(fn); + Thing.addProperty(property).publishEvery(seconds).setPermission(_permission).onUpdate(fn); } protected: @@ -45,8 +42,8 @@ class ArduinoCloudClass { String _id; ArduinoCloudThing Thing; BearSSLClient* _bearSslClient; - MQTTClient _mqttClient; HttpClient* _otaClient; + MQTTClient _mqttClient; String _stdinTopic; String _stdoutTopic; From ba5faf40ad8c66aa9c58fef8f8d2f0d48afe19aa Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 7 Jun 2018 18:37:22 +0200 Subject: [PATCH 06/24] Add missing libraries --- src/ArduinoCloud.cpp | 2 +- src/OTAStorage.h | 35 +++++++++++++++++++ src/SerialFlashStorage.cpp | 69 ++++++++++++++++++++++++++++++++++++++ src/SerialFlashStorage.h | 43 ++++++++++++++++++++++++ 4 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 src/OTAStorage.h create mode 100644 src/SerialFlashStorage.cpp create mode 100644 src/SerialFlashStorage.h diff --git a/src/ArduinoCloud.cpp b/src/ArduinoCloud.cpp index b379b0bb1..c01f9344b 100644 --- a/src/ArduinoCloud.cpp +++ b/src/ArduinoCloud.cpp @@ -5,7 +5,7 @@ #include "CloudSerial.h" #include "SerialFlashStorage.h" -//#include "SFU.h" +#include "SFU.h" const static char server[] = "a19g5nbe27wn47.iot.us-east-1.amazonaws.com"; //"xxxxxxxxxxxxxx.iot.xx-xxxx-x.amazonaws.com"; diff --git a/src/OTAStorage.h b/src/OTAStorage.h new file mode 100644 index 000000000..0f96e2b3f --- /dev/null +++ b/src/OTAStorage.h @@ -0,0 +1,35 @@ +/* + Copyright (c) 2017 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _OTA_STORAGE_H_INCLUDED +#define _OTA_STORAGE_H_INCLUDED + +class OTAStorage { +public: + virtual int open(int length) = 0; + virtual size_t write(uint8_t* data, size_t size) = 0; + virtual void close() = 0; + virtual void clear() = 0; + virtual void apply() = 0; + + virtual long maxSize() { + return ((256 * 1024) - 0x2000); + } +}; + +#endif diff --git a/src/SerialFlashStorage.cpp b/src/SerialFlashStorage.cpp new file mode 100644 index 000000000..432b7c7b6 --- /dev/null +++ b/src/SerialFlashStorage.cpp @@ -0,0 +1,69 @@ +/* + Copyright (c) 2017 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "SerialFlashStorage.h" + +#define UPDATE_FILE "UPDATE.BIN" + +int SerialFlashStorageClass::open(int contentLength) +{ + if (!SerialFlash.begin(SERIAL_FLASH_CS)) { + return 0; + } + + while (!SerialFlash.ready()) {} + + if (SerialFlash.exists(UPDATE_FILE)) { + SerialFlash.remove(UPDATE_FILE); + } + + if (SerialFlash.create(UPDATE_FILE, contentLength)) { + _file = SerialFlash.open(UPDATE_FILE); + } + + if (!_file) { + return 0; + } + + return 1; +} + +size_t SerialFlashStorageClass::write(uint8_t *data, size_t size) +{ + while (!SerialFlash.ready()) {} + int ret = _file.write(data, size); + return ret; +} + +void SerialFlashStorageClass::close() +{ + _file.close(); +} + +void SerialFlashStorageClass::clear() +{ + SerialFlash.remove(UPDATE_FILE); +} + +void SerialFlashStorageClass::apply() +{ + // just reset, SDU copies the data to flash + NVIC_SystemReset(); +} + +SerialFlashStorageClass SerialFlashStorage; diff --git a/src/SerialFlashStorage.h b/src/SerialFlashStorage.h new file mode 100644 index 000000000..4409969f5 --- /dev/null +++ b/src/SerialFlashStorage.h @@ -0,0 +1,43 @@ +/* + Copyright (c) 2017 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _SERIALFLASH_STORAGE_H_INCLUDED +#define _SERIALFLASH_STORAGE_H_INCLUDED + +#include + +#include "OTAStorage.h" + +#define SERIAL_FLASH_BUFFER_SIZE 64 +#define SERIAL_FLASH_CS 5 + +class SerialFlashStorageClass : public OTAStorage { +public: + virtual int open(int length); + virtual size_t write(uint8_t* data, size_t size); + virtual void close(); + virtual void clear(); + virtual void apply(); + +private: + SerialFlashFile _file; +}; + +extern SerialFlashStorageClass SerialFlashStorage; + +#endif From 659608d897d25547605ec17075e12d275134f5f9 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 27 Jun 2018 23:56:39 +0200 Subject: [PATCH 07/24] Fix addProperty macro, again --- src/ArduinoCloudV2.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ArduinoCloudV2.h b/src/ArduinoCloudV2.h index 65f166df4..03c8d99be 100644 --- a/src/ArduinoCloudV2.h +++ b/src/ArduinoCloudV2.h @@ -24,8 +24,10 @@ class ArduinoCloudClass { int connected(); - template void addProperty(T property, permissionType _permission = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL) { - Thing.addProperty(property).publishEvery(seconds).setPermission(_permission).onUpdate(fn); + #define addProperty( v, ...) addPropertyReal(v, #v, __VA_ARGS__) + + template void addPropertyReal(T property, String name, permissionType _permission = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL) { + Thing.addPropertyReal(property, name).publishEvery(seconds).setPermission(_permission).onUpdate(fn); } protected: From 52e179d2b4dfbf1bfac0c83f1cdfa76a62e49e46 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 28 Jun 2018 00:46:15 +0200 Subject: [PATCH 08/24] Fix reference as value in addProperty signature --- src/ArduinoCloud.cpp | 4 ++-- src/ArduinoCloudV2.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ArduinoCloud.cpp b/src/ArduinoCloud.cpp index c01f9344b..f45cf9ade 100644 --- a/src/ArduinoCloud.cpp +++ b/src/ArduinoCloud.cpp @@ -97,8 +97,8 @@ void ArduinoCloudClass::poll() _mqttClient.loop(); uint8_t data[1024]; int length = Thing.poll(data); - if (length) { - writeProperties(data, length); + if (length > 0) { + writeProperties(data, length); } } diff --git a/src/ArduinoCloudV2.h b/src/ArduinoCloudV2.h index 03c8d99be..4f08a6cec 100644 --- a/src/ArduinoCloudV2.h +++ b/src/ArduinoCloudV2.h @@ -26,7 +26,7 @@ class ArduinoCloudClass { #define addProperty( v, ...) addPropertyReal(v, #v, __VA_ARGS__) - template void addPropertyReal(T property, String name, permissionType _permission = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL) { + template void addPropertyReal(T& property, String name, permissionType _permission = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL) { Thing.addPropertyReal(property, name).publishEvery(seconds).setPermission(_permission).onUpdate(fn); } From 31d9eea5e6290a611f4c6d2de112f6a48f5838c6 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 28 Jun 2018 00:59:01 +0200 Subject: [PATCH 09/24] Call THing.poll with the new API --- src/ArduinoCloud.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ArduinoCloud.cpp b/src/ArduinoCloud.cpp index f45cf9ade..2076d44db 100644 --- a/src/ArduinoCloud.cpp +++ b/src/ArduinoCloud.cpp @@ -96,7 +96,7 @@ void ArduinoCloudClass::poll() { _mqttClient.loop(); uint8_t data[1024]; - int length = Thing.poll(data); + int length = Thing.poll(data, sizeof(data)); if (length > 0) { writeProperties(data, length); } From 7a75314a6b0731681b18440121cd8d27ed05b306 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 3 Jul 2018 11:55:58 +0200 Subject: [PATCH 10/24] TEMP: remove OTA stuff --- src/ArduinoCloud.cpp | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/ArduinoCloud.cpp b/src/ArduinoCloud.cpp index 2076d44db..9a0b598d2 100644 --- a/src/ArduinoCloud.cpp +++ b/src/ArduinoCloud.cpp @@ -4,8 +4,6 @@ #include #include "CloudSerial.h" -#include "SerialFlashStorage.h" -#include "SFU.h" const static char server[] = "a19g5nbe27wn47.iot.us-east-1.amazonaws.com"; //"xxxxxxxxxxxxxx.iot.xx-xxxx-x.amazonaws.com"; @@ -16,7 +14,6 @@ const static int thingIdSlot = 12; ArduinoCloudClass::ArduinoCloudClass() : _bearSslClient(NULL), - _otaClient(NULL), _mqttClient(256) { } @@ -26,9 +23,6 @@ ArduinoCloudClass::~ArduinoCloudClass() if (_bearSslClient) { delete _bearSslClient; } - if (_otaClient) { - delete _otaClient; - } } int ArduinoCloudClass::begin(Client& net) @@ -69,12 +63,9 @@ int ArduinoCloudClass::begin(Client& net) Thing.begin(); - _otaClient = new HttpClient(net, server, 80); - _stdoutTopic = "$aws/things/" + _id + "/stdout"; _stdinTopic = "$aws/things/" + _id + "/stdin"; _dataTopic = "$aws/things/" + _id + "/data"; - _otaTopic = "$aws/things/" + _id + "/upload"; return 1; } @@ -87,7 +78,6 @@ int ArduinoCloudClass::connect() _mqttClient.subscribe(_stdinTopic); _mqttClient.subscribe(_dataTopic); - _mqttClient.subscribe(_otaTopic); return 1; } @@ -135,22 +125,6 @@ void ArduinoCloudClass::handleMessage(char topic[], char bytes[], int length) if (_dataTopic == topic) { Thing.decode((uint8_t*)bytes, length); } - if (_otaTopic == topic) { - - String url = String(bytes); - - _otaClient->get(url); - - SerialFlashStorage.open(_otaClient->contentLength()); - uint8_t buf[1024]; - while (_otaClient->available()) { - int size = _otaClient->available() >= 1024 ? 1024 : _otaClient->available(); - _otaClient->read(buf, size); - SerialFlashStorage.write((uint8_t*)buf, size); - } - SerialFlashStorage.close(); - SerialFlashStorage.apply(); - } } ArduinoCloudClass ArduinoCloud; From 11fe6138400df991c9b9dfd43aee09b09fc316d2 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 3 Jul 2018 11:56:29 +0200 Subject: [PATCH 11/24] Add minDelta API and a bunch of overloaded not clashing calls --- src/ArduinoCloudV2.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ArduinoCloudV2.h b/src/ArduinoCloudV2.h index 4f08a6cec..5f1f71479 100644 --- a/src/ArduinoCloudV2.h +++ b/src/ArduinoCloudV2.h @@ -26,8 +26,16 @@ class ArduinoCloudClass { #define addProperty( v, ...) addPropertyReal(v, #v, __VA_ARGS__) - template void addPropertyReal(T& property, String name, permissionType _permission = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL) { - Thing.addPropertyReal(property, name).publishEvery(seconds).setPermission(_permission).onUpdate(fn); + template void addPropertyReal(T& property, String name, permissionType _permission = READWRITE, long seconds = ON_CHANGE, T minDelta = 0, void(*fn)(void) = NULL) { + Thing.addPropertyReal(property, name).publishEvery(seconds).setPermission(_permission).onUpdate(fn).minimumDelta(&minDelta); + } + + template void addPropertyReal(T& property, String name, permissionType _permission = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, T minDelta = 0) { + Thing.addPropertyReal(property, name).publishEvery(seconds).setPermission(_permission).onUpdate(fn).minimumDelta(&minDelta); + } + + template void addPropertyReal(T& property, String name, permissionType _permission = READWRITE, void(*fn)(void) = NULL, long seconds = ON_CHANGE, T minDelta = 0) { + Thing.addPropertyReal(property, name).publishEvery(seconds).setPermission(_permission).onUpdate(fn).minimumDelta(&minDelta); } protected: From 2c4971fd6fb01ce13f57b6dbb4d9d978506b53d8 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 21 Aug 2018 19:12:58 +0200 Subject: [PATCH 12/24] TEMP: fully remove OTA support --- src/OTAStorage.h | 35 ------------------- src/SerialFlashStorage.cpp | 69 -------------------------------------- src/SerialFlashStorage.h | 43 ------------------------ 3 files changed, 147 deletions(-) delete mode 100644 src/OTAStorage.h delete mode 100644 src/SerialFlashStorage.cpp delete mode 100644 src/SerialFlashStorage.h diff --git a/src/OTAStorage.h b/src/OTAStorage.h deleted file mode 100644 index 0f96e2b3f..000000000 --- a/src/OTAStorage.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - Copyright (c) 2017 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _OTA_STORAGE_H_INCLUDED -#define _OTA_STORAGE_H_INCLUDED - -class OTAStorage { -public: - virtual int open(int length) = 0; - virtual size_t write(uint8_t* data, size_t size) = 0; - virtual void close() = 0; - virtual void clear() = 0; - virtual void apply() = 0; - - virtual long maxSize() { - return ((256 * 1024) - 0x2000); - } -}; - -#endif diff --git a/src/SerialFlashStorage.cpp b/src/SerialFlashStorage.cpp deleted file mode 100644 index 432b7c7b6..000000000 --- a/src/SerialFlashStorage.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - Copyright (c) 2017 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "SerialFlashStorage.h" - -#define UPDATE_FILE "UPDATE.BIN" - -int SerialFlashStorageClass::open(int contentLength) -{ - if (!SerialFlash.begin(SERIAL_FLASH_CS)) { - return 0; - } - - while (!SerialFlash.ready()) {} - - if (SerialFlash.exists(UPDATE_FILE)) { - SerialFlash.remove(UPDATE_FILE); - } - - if (SerialFlash.create(UPDATE_FILE, contentLength)) { - _file = SerialFlash.open(UPDATE_FILE); - } - - if (!_file) { - return 0; - } - - return 1; -} - -size_t SerialFlashStorageClass::write(uint8_t *data, size_t size) -{ - while (!SerialFlash.ready()) {} - int ret = _file.write(data, size); - return ret; -} - -void SerialFlashStorageClass::close() -{ - _file.close(); -} - -void SerialFlashStorageClass::clear() -{ - SerialFlash.remove(UPDATE_FILE); -} - -void SerialFlashStorageClass::apply() -{ - // just reset, SDU copies the data to flash - NVIC_SystemReset(); -} - -SerialFlashStorageClass SerialFlashStorage; diff --git a/src/SerialFlashStorage.h b/src/SerialFlashStorage.h deleted file mode 100644 index 4409969f5..000000000 --- a/src/SerialFlashStorage.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - Copyright (c) 2017 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _SERIALFLASH_STORAGE_H_INCLUDED -#define _SERIALFLASH_STORAGE_H_INCLUDED - -#include - -#include "OTAStorage.h" - -#define SERIAL_FLASH_BUFFER_SIZE 64 -#define SERIAL_FLASH_CS 5 - -class SerialFlashStorageClass : public OTAStorage { -public: - virtual int open(int length); - virtual size_t write(uint8_t* data, size_t size); - virtual void close(); - virtual void clear(); - virtual void apply(); - -private: - SerialFlashFile _file; -}; - -extern SerialFlashStorageClass SerialFlashStorage; - -#endif From 0b5fc7f24059309c97f8c2b9229880a040302596 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 21 Aug 2018 19:13:23 +0200 Subject: [PATCH 13/24] Remove useless dependency on HTTPClient --- src/ArduinoCloudV2.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ArduinoCloudV2.h b/src/ArduinoCloudV2.h index 5f1f71479..815736880 100644 --- a/src/ArduinoCloudV2.h +++ b/src/ArduinoCloudV2.h @@ -4,7 +4,6 @@ #include #include #include -#include #include "CloudSerial.h" @@ -52,7 +51,6 @@ class ArduinoCloudClass { String _id; ArduinoCloudThing Thing; BearSSLClient* _bearSslClient; - HttpClient* _otaClient; MQTTClient _mqttClient; String _stdinTopic; From 02a1994b19386cd94bd24406757a8e8eb970d489 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 21 Aug 2018 19:13:46 +0200 Subject: [PATCH 14/24] Adapt to String property type --- src/ArduinoCloudV2.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ArduinoCloudV2.h b/src/ArduinoCloudV2.h index 815736880..c4cd8f5d3 100644 --- a/src/ArduinoCloudV2.h +++ b/src/ArduinoCloudV2.h @@ -25,15 +25,15 @@ class ArduinoCloudClass { #define addProperty( v, ...) addPropertyReal(v, #v, __VA_ARGS__) - template void addPropertyReal(T& property, String name, permissionType _permission = READWRITE, long seconds = ON_CHANGE, T minDelta = 0, void(*fn)(void) = NULL) { + template void addPropertyReal(T& property, String name, permissionType _permission = READWRITE, long seconds = ON_CHANGE, T minDelta = T(0), void(*fn)(void) = NULL) { Thing.addPropertyReal(property, name).publishEvery(seconds).setPermission(_permission).onUpdate(fn).minimumDelta(&minDelta); } - template void addPropertyReal(T& property, String name, permissionType _permission = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, T minDelta = 0) { + template void addPropertyReal(T& property, String name, permissionType _permission = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, T minDelta = T(0)) { Thing.addPropertyReal(property, name).publishEvery(seconds).setPermission(_permission).onUpdate(fn).minimumDelta(&minDelta); } - template void addPropertyReal(T& property, String name, permissionType _permission = READWRITE, void(*fn)(void) = NULL, long seconds = ON_CHANGE, T minDelta = 0) { + template void addPropertyReal(T& property, String name, permissionType _permission = READWRITE, void(*fn)(void) = NULL, long seconds = ON_CHANGE, T minDelta = T(0)) { Thing.addPropertyReal(property, name).publishEvery(seconds).setPermission(_permission).onUpdate(fn).minimumDelta(&minDelta); } From 2989ad0de97578be3c1fa1b1088545f229a5921c Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Tue, 24 Jul 2018 16:22:38 -0400 Subject: [PATCH 15/24] Add ability to add Authority Key Identifier to reconstructed SSL public cert --- src/utility/ECCX08Cert.cpp | 72 ++++++++++++++++++++++++++++++++++---- src/utility/ECCX08Cert.h | 8 +++++ 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/src/utility/ECCX08Cert.cpp b/src/utility/ECCX08Cert.cpp index 1311c3092..7369b1024 100644 --- a/src/utility/ECCX08Cert.cpp +++ b/src/utility/ECCX08Cert.cpp @@ -73,6 +73,7 @@ ECCX08CertClass::ECCX08CertClass() : _keySlot(-1), _compressedCertSlot(-1), _serialNumberSlot(-1), + _authorityKeyIdentifier(NULL), _bytes(NULL), _length(0) { @@ -334,10 +335,19 @@ int ECCX08CertClass::endReconstruction() int publicKeyLen = publicKeyLength(); + int authorityKeyIdentifierLen = authorityKeyIdentifierLength(_authorityKeyIdentifier); + int signatureLen = signatureLength(compressedCert.signature); int certInfoLen = 5 + serialNumberLen + 12 + issuerHeaderLen + issuerLen + 32 + - subjectHeaderLen + subjectLen + publicKeyLen + 4; + subjectHeaderLen + subjectLen + publicKeyLen; + + if (authorityKeyIdentifierLen) { + certInfoLen += authorityKeyIdentifierLen; + } else { + certInfoLen += 4; + } + int certInfoHeaderLen = sequenceHeaderLength(certInfoLen); int certDataLen = certInfoLen + certInfoHeaderLen + signatureLen; @@ -411,11 +421,16 @@ int ECCX08CertClass::endReconstruction() appendPublicKey(publicKey, out); out += publicKeyLen; - // null sequence - *out++ = 0xA3; - *out++ = 0x02; - *out++ = 0x30; - *out++ = 0x00; + if (authorityKeyIdentifierLen) { + appendAuthorityKeyIdentifier(_authorityKeyIdentifier, out); + out += authorityKeyIdentifierLen; + } else { + // null sequence + *out++ = 0xA3; + *out++ = 0x02; + *out++ = 0x30; + *out++ = 0x00; + } // signature appendSignature(compressedCert.signature, out); @@ -494,6 +509,11 @@ void ECCX08CertClass::setSubjectCommonName(const String& commonName) _subjectCommonName = commonName; } +void ECCX08CertClass::setAuthorityKeyIdentifier(const byte authorityKeyIdentifier[]) +{ + _authorityKeyIdentifier = authorityKeyIdentifier; +} + int ECCX08CertClass::versionLength() { return 3; @@ -546,6 +566,11 @@ int ECCX08CertClass::publicKeyLength() return (2 + 2 + 9 + 10 + 4 + 64); } +int ECCX08CertClass::authorityKeyIdentifierLength(const byte authorityKeyIdentifier[]) +{ + return (authorityKeyIdentifier == NULL) ? 0 : 37; +} + int ECCX08CertClass::signatureLength(const byte signature[]) { const byte* r = &signature[0]; @@ -684,6 +709,41 @@ void ECCX08CertClass::appendPublicKey(const byte publicKey[], byte out[]) memcpy(out, publicKey, 64); } +void ECCX08CertClass::appendAuthorityKeyIdentifier(const byte authorityKeyIdentifier[], byte out[]) +{ + // [3] + *out++ = 0xa3; + *out++ = 0x23; + + // sequence + *out++ = ASN1_SEQUENCE; + *out++ = 0x21; + + // sequence + *out++ = ASN1_SEQUENCE; + *out++ = 0x1f; + + // 2.5.29.35 authorityKeyIdentifier(X.509 extension) + *out++ = 0x06; + *out++ = 0x03; + *out++ = 0x55; + *out++ = 0x1d; + *out++ = 0x23; + + // octet string + *out++ = 0x04; + *out++ = 0x18; + + // sequence + *out++ = ASN1_SEQUENCE; + *out++ = 0x16; + + *out++ = 0x80; + *out++ = 0x14; + + memcpy(out, authorityKeyIdentifier, 20); +} + void ECCX08CertClass::appendSignature(const byte signature[], byte out[]) { // signature algorithm diff --git a/src/utility/ECCX08Cert.h b/src/utility/ECCX08Cert.h index 882ba76d1..84197021e 100644 --- a/src/utility/ECCX08Cert.h +++ b/src/utility/ECCX08Cert.h @@ -42,6 +42,8 @@ class ECCX08CertClass { void setSubjectOrganizationalUnitName(const String& organizationalUnitName); void setSubjectCommonName(const String& commonName); + void setAuthorityKeyIdentifier(const byte authorityKeyIdentifier[]); + private: int versionLength(); @@ -54,6 +56,8 @@ class ECCX08CertClass { int publicKeyLength(); + int authorityKeyIdentifierLength(const byte authorityKeyIdentifier[]); + int signatureLength(const byte signature[]); int serialNumberLength(const byte serialNumber[]); @@ -72,6 +76,8 @@ class ECCX08CertClass { void appendPublicKey(const byte publicKey[], byte out[]); + void appendAuthorityKeyIdentifier(const byte authorityKeyIdentifier[], byte out[]); + void appendSignature(const byte signature[], byte out[]); void appendSerialNumber(const byte serialNumber[], byte out[]); @@ -103,6 +109,8 @@ class ECCX08CertClass { String _subjectOrganizationalUnitName; String _subjectCommonName; + const byte* _authorityKeyIdentifier; + byte _temp[88]; byte* _bytes; int _length; From 9966adb0194cf9e0b22f7485cef35ce6ffca3a91 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Tue, 24 Jul 2018 16:23:03 -0400 Subject: [PATCH 16/24] Set Authority Key Identifier when re-constructing cert --- src/ArduinoCloud.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ArduinoCloud.cpp b/src/ArduinoCloud.cpp index 05159a144..4a6515a28 100644 --- a/src/ArduinoCloud.cpp +++ b/src/ArduinoCloud.cpp @@ -48,6 +48,12 @@ int ArduinoCloudClass::begin(Client& net) ECCX08Cert.setIssuerOrganizationalUnitName("IT"); ECCX08Cert.setIssuerCommonName("Arduino"); + const byte authorityKeyIdentifier[20] = { + 0xb2, 0xed, 0xef, 0xed, 0x3b, 0xbf, 0xc7, 0x71, 0x75, 0x24, 0x33, 0xd1, 0xae, 0x8b, 0x54, 0xed, 0x97, 0x14, 0x7a, 0x1d + }; + + ECCX08Cert.setAuthorityKeyIdentifier(authorityKeyIdentifier); + if (!ECCX08Cert.endReconstruction()) { return 0; } From 1e3b0234c5c701eaee22cb7674b9f0e6de848305 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Wed, 25 Jul 2018 18:17:45 -0400 Subject: [PATCH 17/24] Use ECCX08 slot to store Authority Key Identifier, and request in provisioning sketch --- .../utility/Provisioning/Provisioning.ino | 38 +++++++------ src/ArduinoCloud.cpp | 17 ++---- src/utility/ECCX08Cert.cpp | 57 ++++++++++++++----- src/utility/ECCX08Cert.h | 16 +++--- 4 files changed, 77 insertions(+), 51 deletions(-) diff --git a/examples/utility/Provisioning/Provisioning.ino b/examples/utility/Provisioning/Provisioning.ino index 29cb46793..0777dcb1f 100644 --- a/examples/utility/Provisioning/Provisioning.ino +++ b/examples/utility/Provisioning/Provisioning.ino @@ -3,12 +3,13 @@ #include #include -#include +#include -const int keySlot = 0; -const int compressedCertSlot = 10; -const int serialNumberSlot = 11; -const int thingIdSlot = 12; +const int keySlot = 0; +const int compressedCertSlot = 10; +const int serialNumberSlot = 11; +const int authorityKeyIdentifierSlot = 12; +const int thingIdSlot = 13; void setup() { Serial.begin(9600); @@ -68,37 +69,41 @@ void setup() { Serial.println(); Serial.println(csr); - String thingId = promptAndReadLine("Please enter the thing id: "); - String issueYear = promptAndReadLine("Please enter the issue year of the certificate (2000 - 2031): "); - String issueMonth = promptAndReadLine("Please enter the issue month of the certificate (1 - 12): "); - String issueDay = promptAndReadLine("Please enter the issue day of the certificate (1 - 31): "); - String issueHour = promptAndReadLine("Please enter the issue hour of the certificate (0 - 23): "); - String expireYears = promptAndReadLine("Please enter how many years the certificate is valid for (0 - 31): "); - String serialNumber = promptAndReadLine("Please enter the certificates serial number: "); - String signature = promptAndReadLine("Please enter the certificates signature: "); + String thingId = promptAndReadLine("Please enter the thing id: "); + String issueYear = promptAndReadLine("Please enter the issue year of the certificate (2000 - 2031): "); + String issueMonth = promptAndReadLine("Please enter the issue month of the certificate (1 - 12): "); + String issueDay = promptAndReadLine("Please enter the issue day of the certificate (1 - 31): "); + String issueHour = promptAndReadLine("Please enter the issue hour of the certificate (0 - 23): "); + String expireYears = promptAndReadLine("Please enter how many years the certificate is valid for (0 - 31): "); + String serialNumber = promptAndReadLine("Please enter the certificates serial number: "); + String authorityKeyIdentifier = promptAndReadLine("Please enter the certificates authority key identifier: "); + String signature = promptAndReadLine("Please enter the certificates signature: "); serialNumber.toUpperCase(); signature.toUpperCase(); byte thingIdBytes[72]; byte serialNumberBytes[16]; + byte authorityKeyIdentifierBytes[20]; byte signatureBytes[64]; thingId.getBytes(thingIdBytes, sizeof(thingIdBytes)); hexStringToBytes(serialNumber, serialNumberBytes, sizeof(serialNumberBytes)); - hexStringToBytes(signature, signatureBytes, 64); + hexStringToBytes(authorityKeyIdentifier, authorityKeyIdentifierBytes, sizeof(authorityKeyIdentifierBytes)); + hexStringToBytes(signature, signatureBytes, sizeof(signatureBytes)); if (!ECCX08.writeSlot(thingIdSlot, thingIdBytes, sizeof(thingIdBytes))) { Serial.println("Error storing thing id!"); while (1); } - if (!ECCX08Cert.beginStorage(compressedCertSlot, serialNumberSlot)) { + if (!ECCX08Cert.beginStorage(compressedCertSlot, serialNumberSlot, authorityKeyIdentifierSlot)) { Serial.println("Error starting ECCX08 storage!"); while (1); } ECCX08Cert.setSignature(signatureBytes); + ECCX08Cert.setAuthorityKeyIdentifier(authorityKeyIdentifierBytes); ECCX08Cert.setSerialNumber(serialNumberBytes); ECCX08Cert.setIssueYear(issueYear.toInt()); ECCX08Cert.setIssueMonth(issueMonth.toInt()); @@ -111,7 +116,7 @@ void setup() { while (1); } - if (!ECCX08Cert.beginReconstruction(keySlot, compressedCertSlot, serialNumberSlot)) { + if (!ECCX08Cert.beginReconstruction(keySlot, compressedCertSlot, serialNumberSlot, authorityKeyIdentifierSlot)) { Serial.println("Error starting ECCX08 cert reconstruction!"); while (1); } @@ -189,4 +194,3 @@ void hexStringToBytes(const String& in, byte out[], int length) { out[outLength++] = (highByte << 4) | lowByte; } } - diff --git a/src/ArduinoCloud.cpp b/src/ArduinoCloud.cpp index 4a6515a28..64cb7dca5 100644 --- a/src/ArduinoCloud.cpp +++ b/src/ArduinoCloud.cpp @@ -7,10 +7,11 @@ const static char server[] = "a19g5nbe27wn47.iot.us-east-1.amazonaws.com"; //"xxxxxxxxxxxxxx.iot.xx-xxxx-x.amazonaws.com"; -const static int keySlot = 0; -const static int compressedCertSlot = 10; -const static int serialNumberSlot = 11; -const static int thingIdSlot = 12; +const static int keySlot = 0; +const static int compressedCertSlot = 10; +const static int serialNumberSlot = 11; +const static int authorityKeyIdentifierSlot = 12; +const static int thingIdSlot = 13; ArduinoCloudClass::ArduinoCloudClass() : _bearSslClient(NULL), @@ -38,7 +39,7 @@ int ArduinoCloudClass::begin(Client& net) } _id = (char*)thingIdBytes; - if (!ECCX08Cert.beginReconstruction(keySlot, compressedCertSlot, serialNumberSlot)) { + if (!ECCX08Cert.beginReconstruction(keySlot, compressedCertSlot, serialNumberSlot, authorityKeyIdentifierSlot)) { return 0; } @@ -48,12 +49,6 @@ int ArduinoCloudClass::begin(Client& net) ECCX08Cert.setIssuerOrganizationalUnitName("IT"); ECCX08Cert.setIssuerCommonName("Arduino"); - const byte authorityKeyIdentifier[20] = { - 0xb2, 0xed, 0xef, 0xed, 0x3b, 0xbf, 0xc7, 0x71, 0x75, 0x24, 0x33, 0xd1, 0xae, 0x8b, 0x54, 0xed, 0x97, 0x14, 0x7a, 0x1d - }; - - ECCX08Cert.setAuthorityKeyIdentifier(authorityKeyIdentifier); - if (!ECCX08Cert.endReconstruction()) { return 0; } diff --git a/src/utility/ECCX08Cert.cpp b/src/utility/ECCX08Cert.cpp index 7369b1024..bfcd0dfc4 100644 --- a/src/utility/ECCX08Cert.cpp +++ b/src/utility/ECCX08Cert.cpp @@ -18,7 +18,8 @@ struct __attribute__((__packed__)) CompressedCert { byte unused[5]; }; -#define SERIAL_NUMBER_LENGTH 16 +#define SERIAL_NUMBER_LENGTH 16 +#define AUTHORITY_KEY_IDENTIFIER_LENGTH 20 static String base64Encode(const byte in[], unsigned int length, const char* prefix, const char* suffix) { @@ -73,7 +74,7 @@ ECCX08CertClass::ECCX08CertClass() : _keySlot(-1), _compressedCertSlot(-1), _serialNumberSlot(-1), - _authorityKeyIdentifier(NULL), + _authorityKeyIdentifierSlot(-1), _bytes(NULL), _length(0) { @@ -185,7 +186,7 @@ String ECCX08CertClass::endCSR() return base64Encode(csr, csrLen + csrHeaderLen, "-----BEGIN CERTIFICATE REQUEST-----\n", "\n-----END CERTIFICATE REQUEST-----\n"); } -int ECCX08CertClass::beginStorage(int compressedCertSlot, int serialNumberSlot) +int ECCX08CertClass::beginStorage(int compressedCertSlot, int serialNumberSlot, int authorityKeyIdentifierSlot) { if (compressedCertSlot < 8 || compressedCertSlot > 15) { return 0; @@ -195,8 +196,15 @@ int ECCX08CertClass::beginStorage(int compressedCertSlot, int serialNumberSlot) return 0; } + if (authorityKeyIdentifierSlot > -1) { + if (authorityKeyIdentifierSlot < 8 || authorityKeyIdentifierSlot > 15) { + return 0; + } + } + _compressedCertSlot = compressedCertSlot; _serialNumberSlot = serialNumberSlot; + _authorityKeyIdentifierSlot = authorityKeyIdentifierSlot; memset(_temp, 0x00, sizeof(_temp)); @@ -256,11 +264,16 @@ void ECCX08CertClass::setExpireYears(int expireYears) compressedCert->dates[2] |= expireYears; } -void ECCX08CertClass::setSerialNumber(byte serialNumber[]) +void ECCX08CertClass::setSerialNumber(const byte serialNumber[]) { memcpy(&_temp[72], serialNumber, SERIAL_NUMBER_LENGTH); } +void ECCX08CertClass::setAuthorityKeyIdentifier(const byte authorityKeyIdentifier[]) +{ + memcpy(&_temp[88], authorityKeyIdentifier, AUTHORITY_KEY_IDENTIFIER_LENGTH); +} + int ECCX08CertClass::endStorage() { if (!ECCX08.writeSlot(_compressedCertSlot, &_temp[0], 72)) { @@ -271,10 +284,14 @@ int ECCX08CertClass::endStorage() return 0; } + if (!ECCX08.writeSlot(_authorityKeyIdentifierSlot, &_temp[88], AUTHORITY_KEY_IDENTIFIER_LENGTH)) { + return 0; + } + return 1; } -int ECCX08CertClass::beginReconstruction(int keySlot, int compressedCertSlot, int serialNumberSlot) +int ECCX08CertClass::beginReconstruction(int keySlot, int compressedCertSlot, int serialNumberSlot, int authorityKeyIdentifierSlot) { if (keySlot < 0 || keySlot > 8) { return 0; @@ -288,9 +305,16 @@ int ECCX08CertClass::beginReconstruction(int keySlot, int compressedCertSlot, in return 0; } + if (authorityKeyIdentifierSlot > -1) { + if (authorityKeyIdentifierSlot < 8 || authorityKeyIdentifierSlot > 15) { + return 0; + } + } + _keySlot = keySlot; _compressedCertSlot = compressedCertSlot; _serialNumberSlot = serialNumberSlot; + _authorityKeyIdentifierSlot = authorityKeyIdentifierSlot; return 1; } @@ -300,6 +324,7 @@ int ECCX08CertClass::endReconstruction() byte publicKey[64]; struct CompressedCert compressedCert; byte serialNumber[SERIAL_NUMBER_LENGTH]; + byte authorityKeyIdentifier[AUTHORITY_KEY_IDENTIFIER_LENGTH]; if (!ECCX08.generatePublicKey(_keySlot, publicKey)) { return 0; @@ -313,6 +338,11 @@ int ECCX08CertClass::endReconstruction() return 0; } + if (_authorityKeyIdentifierSlot > -1 && + !ECCX08.readSlot(_authorityKeyIdentifierSlot, authorityKeyIdentifier, sizeof(authorityKeyIdentifier))) { + return 0; + } + int serialNumberLen = serialNumberLength(serialNumber); int issuerLen = issuerOrSubjectLength(_issuerCountryName, @@ -335,7 +365,11 @@ int ECCX08CertClass::endReconstruction() int publicKeyLen = publicKeyLength(); - int authorityKeyIdentifierLen = authorityKeyIdentifierLength(_authorityKeyIdentifier); + int authorityKeyIdentifierLen = 0; + + if (_authorityKeyIdentifierSlot > -1) { + authorityKeyIdentifierLen = authorityKeyIdentifierLength(); + } int signatureLen = signatureLength(compressedCert.signature); @@ -422,7 +456,7 @@ int ECCX08CertClass::endReconstruction() out += publicKeyLen; if (authorityKeyIdentifierLen) { - appendAuthorityKeyIdentifier(_authorityKeyIdentifier, out); + appendAuthorityKeyIdentifier(authorityKeyIdentifier, out); out += authorityKeyIdentifierLen; } else { // null sequence @@ -509,11 +543,6 @@ void ECCX08CertClass::setSubjectCommonName(const String& commonName) _subjectCommonName = commonName; } -void ECCX08CertClass::setAuthorityKeyIdentifier(const byte authorityKeyIdentifier[]) -{ - _authorityKeyIdentifier = authorityKeyIdentifier; -} - int ECCX08CertClass::versionLength() { return 3; @@ -566,9 +595,9 @@ int ECCX08CertClass::publicKeyLength() return (2 + 2 + 9 + 10 + 4 + 64); } -int ECCX08CertClass::authorityKeyIdentifierLength(const byte authorityKeyIdentifier[]) +int ECCX08CertClass::authorityKeyIdentifierLength() { - return (authorityKeyIdentifier == NULL) ? 0 : 37; + return 37; } int ECCX08CertClass::signatureLength(const byte signature[]) diff --git a/src/utility/ECCX08Cert.h b/src/utility/ECCX08Cert.h index 84197021e..f0f4df380 100644 --- a/src/utility/ECCX08Cert.h +++ b/src/utility/ECCX08Cert.h @@ -12,17 +12,18 @@ class ECCX08CertClass { int beginCSR(int keySlot, bool newPrivateKey = true); String endCSR(); - int beginStorage(int compressedCertSlot, int serialNumberSlot); + int beginStorage(int compressedCertSlot, int serialNumberSlot, int authorityKeyIdentifierSlot); void setSignature(byte signature[]); void setIssueYear(int issueYear); void setIssueMonth(int issueMonth); void setIssueDay(int issueDay); void setIssueHour(int issueHour); void setExpireYears(int expireYears); - void setSerialNumber(byte serialNumber[]); + void setSerialNumber(const byte serialNumber[]); + void setAuthorityKeyIdentifier(const byte authorityKeyIdentifier[]); int endStorage(); - int beginReconstruction(int keySlot, int compressedCertSlot, int serialNumberSlot); + int beginReconstruction(int keySlot, int compressedCertSlot, int serialNumberSlot, int authorityKeyIdentifierSlot); int endReconstruction(); byte* bytes(); @@ -42,8 +43,6 @@ class ECCX08CertClass { void setSubjectOrganizationalUnitName(const String& organizationalUnitName); void setSubjectCommonName(const String& commonName); - void setAuthorityKeyIdentifier(const byte authorityKeyIdentifier[]); - private: int versionLength(); @@ -56,7 +55,7 @@ class ECCX08CertClass { int publicKeyLength(); - int authorityKeyIdentifierLength(const byte authorityKeyIdentifier[]); + int authorityKeyIdentifierLength(); int signatureLength(const byte signature[]); @@ -94,6 +93,7 @@ class ECCX08CertClass { int _keySlot; int _compressedCertSlot; int _serialNumberSlot; + int _authorityKeyIdentifierSlot; String _issuerCountryName; String _issuerStateProvinceName; @@ -109,9 +109,7 @@ class ECCX08CertClass { String _subjectOrganizationalUnitName; String _subjectCommonName; - const byte* _authorityKeyIdentifier; - - byte _temp[88]; + byte _temp[108]; byte* _bytes; int _length; }; From 50181e713b8a358e20ac6a7946904f16db7009d8 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Thu, 26 Jul 2018 10:08:42 -0400 Subject: [PATCH 18/24] Combine certificate serial number and authority key identifier data into one slot --- .../utility/Provisioning/Provisioning.ino | 13 ++-- src/ArduinoCloud.cpp | 11 ++- src/utility/ECCX08Cert.cpp | 78 ++++++++----------- src/utility/ECCX08Cert.h | 9 +-- 4 files changed, 47 insertions(+), 64 deletions(-) diff --git a/examples/utility/Provisioning/Provisioning.ino b/examples/utility/Provisioning/Provisioning.ino index 0777dcb1f..a58b486b3 100644 --- a/examples/utility/Provisioning/Provisioning.ino +++ b/examples/utility/Provisioning/Provisioning.ino @@ -5,11 +5,10 @@ #include #include -const int keySlot = 0; -const int compressedCertSlot = 10; -const int serialNumberSlot = 11; -const int authorityKeyIdentifierSlot = 12; -const int thingIdSlot = 13; +const int keySlot = 0; +const int compressedCertSlot = 10; +const int serialNumberAndAuthorityKeyIdentifierSlot = 11; +const int thingIdSlot = 12; void setup() { Serial.begin(9600); @@ -97,7 +96,7 @@ void setup() { while (1); } - if (!ECCX08Cert.beginStorage(compressedCertSlot, serialNumberSlot, authorityKeyIdentifierSlot)) { + if (!ECCX08Cert.beginStorage(compressedCertSlot, serialNumberAndAuthorityKeyIdentifierSlot)) { Serial.println("Error starting ECCX08 storage!"); while (1); } @@ -116,7 +115,7 @@ void setup() { while (1); } - if (!ECCX08Cert.beginReconstruction(keySlot, compressedCertSlot, serialNumberSlot, authorityKeyIdentifierSlot)) { + if (!ECCX08Cert.beginReconstruction(keySlot, compressedCertSlot, serialNumberAndAuthorityKeyIdentifierSlot)) { Serial.println("Error starting ECCX08 cert reconstruction!"); while (1); } diff --git a/src/ArduinoCloud.cpp b/src/ArduinoCloud.cpp index 64cb7dca5..dddf3683d 100644 --- a/src/ArduinoCloud.cpp +++ b/src/ArduinoCloud.cpp @@ -7,11 +7,10 @@ const static char server[] = "a19g5nbe27wn47.iot.us-east-1.amazonaws.com"; //"xxxxxxxxxxxxxx.iot.xx-xxxx-x.amazonaws.com"; -const static int keySlot = 0; -const static int compressedCertSlot = 10; -const static int serialNumberSlot = 11; -const static int authorityKeyIdentifierSlot = 12; -const static int thingIdSlot = 13; +const static int keySlot = 0; +const static int compressedCertSlot = 10; +const static int serialNumberAndAuthorityKeyIdentifierSlot = 11; +const static int thingIdSlot = 12; ArduinoCloudClass::ArduinoCloudClass() : _bearSslClient(NULL), @@ -39,7 +38,7 @@ int ArduinoCloudClass::begin(Client& net) } _id = (char*)thingIdBytes; - if (!ECCX08Cert.beginReconstruction(keySlot, compressedCertSlot, serialNumberSlot, authorityKeyIdentifierSlot)) { + if (!ECCX08Cert.beginReconstruction(keySlot, compressedCertSlot, serialNumberAndAuthorityKeyIdentifierSlot)) { return 0; } diff --git a/src/utility/ECCX08Cert.cpp b/src/utility/ECCX08Cert.cpp index bfcd0dfc4..7d38969bc 100644 --- a/src/utility/ECCX08Cert.cpp +++ b/src/utility/ECCX08Cert.cpp @@ -21,6 +21,11 @@ struct __attribute__((__packed__)) CompressedCert { #define SERIAL_NUMBER_LENGTH 16 #define AUTHORITY_KEY_IDENTIFIER_LENGTH 20 +struct __attribute__((__packed__)) SerialNumberAndAuthorityKeyIdentifier { + byte serialNumber[SERIAL_NUMBER_LENGTH]; + byte authorityKeyIdentifier[AUTHORITY_KEY_IDENTIFIER_LENGTH]; +}; + static String base64Encode(const byte in[], unsigned int length, const char* prefix, const char* suffix) { static const char* CODES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; @@ -73,8 +78,7 @@ static String base64Encode(const byte in[], unsigned int length, const char* pre ECCX08CertClass::ECCX08CertClass() : _keySlot(-1), _compressedCertSlot(-1), - _serialNumberSlot(-1), - _authorityKeyIdentifierSlot(-1), + _serialNumberAndAuthorityKeyIdentifierSlot(-1), _bytes(NULL), _length(0) { @@ -186,25 +190,18 @@ String ECCX08CertClass::endCSR() return base64Encode(csr, csrLen + csrHeaderLen, "-----BEGIN CERTIFICATE REQUEST-----\n", "\n-----END CERTIFICATE REQUEST-----\n"); } -int ECCX08CertClass::beginStorage(int compressedCertSlot, int serialNumberSlot, int authorityKeyIdentifierSlot) +int ECCX08CertClass::beginStorage(int compressedCertSlot, int serialNumberAndAuthorityKeyIdentifierSlot) { if (compressedCertSlot < 8 || compressedCertSlot > 15) { return 0; } - if (serialNumberSlot < 8 || serialNumberSlot > 15) { + if (serialNumberAndAuthorityKeyIdentifierSlot < 8 || serialNumberAndAuthorityKeyIdentifierSlot > 15) { return 0; } - if (authorityKeyIdentifierSlot > -1) { - if (authorityKeyIdentifierSlot < 8 || authorityKeyIdentifierSlot > 15) { - return 0; - } - } - _compressedCertSlot = compressedCertSlot; - _serialNumberSlot = serialNumberSlot; - _authorityKeyIdentifierSlot = authorityKeyIdentifierSlot; + _serialNumberAndAuthorityKeyIdentifierSlot = serialNumberAndAuthorityKeyIdentifierSlot; memset(_temp, 0x00, sizeof(_temp)); @@ -280,18 +277,14 @@ int ECCX08CertClass::endStorage() return 0; } - if (!ECCX08.writeSlot(_serialNumberSlot, &_temp[72], SERIAL_NUMBER_LENGTH)) { - return 0; - } - - if (!ECCX08.writeSlot(_authorityKeyIdentifierSlot, &_temp[88], AUTHORITY_KEY_IDENTIFIER_LENGTH)) { + if (!ECCX08.writeSlot(_serialNumberAndAuthorityKeyIdentifierSlot, &_temp[72], SERIAL_NUMBER_LENGTH + AUTHORITY_KEY_IDENTIFIER_LENGTH)) { return 0; } return 1; } -int ECCX08CertClass::beginReconstruction(int keySlot, int compressedCertSlot, int serialNumberSlot, int authorityKeyIdentifierSlot) +int ECCX08CertClass::beginReconstruction(int keySlot, int compressedCertSlot, int serialNumberAndAuthorityKeyIdentifierSlot) { if (keySlot < 0 || keySlot > 8) { return 0; @@ -301,20 +294,13 @@ int ECCX08CertClass::beginReconstruction(int keySlot, int compressedCertSlot, in return 0; } - if (serialNumberSlot < 8 || serialNumberSlot > 15) { + if (serialNumberAndAuthorityKeyIdentifierSlot < 8 || serialNumberAndAuthorityKeyIdentifierSlot > 15) { return 0; } - if (authorityKeyIdentifierSlot > -1) { - if (authorityKeyIdentifierSlot < 8 || authorityKeyIdentifierSlot > 15) { - return 0; - } - } - _keySlot = keySlot; _compressedCertSlot = compressedCertSlot; - _serialNumberSlot = serialNumberSlot; - _authorityKeyIdentifierSlot = authorityKeyIdentifierSlot; + _serialNumberAndAuthorityKeyIdentifierSlot = serialNumberAndAuthorityKeyIdentifierSlot; return 1; } @@ -323,8 +309,7 @@ int ECCX08CertClass::endReconstruction() { byte publicKey[64]; struct CompressedCert compressedCert; - byte serialNumber[SERIAL_NUMBER_LENGTH]; - byte authorityKeyIdentifier[AUTHORITY_KEY_IDENTIFIER_LENGTH]; + struct SerialNumberAndAuthorityKeyIdentifier serialNumberAndAuthorityKeyIdentifier; if (!ECCX08.generatePublicKey(_keySlot, publicKey)) { return 0; @@ -334,16 +319,11 @@ int ECCX08CertClass::endReconstruction() return 0; } - if (!ECCX08.readSlot(_serialNumberSlot, serialNumber, sizeof(serialNumber))) { + if (!ECCX08.readSlot(_serialNumberAndAuthorityKeyIdentifierSlot, (byte*)&serialNumberAndAuthorityKeyIdentifier, sizeof(serialNumberAndAuthorityKeyIdentifier))) { return 0; } - if (_authorityKeyIdentifierSlot > -1 && - !ECCX08.readSlot(_authorityKeyIdentifierSlot, authorityKeyIdentifier, sizeof(authorityKeyIdentifier))) { - return 0; - } - - int serialNumberLen = serialNumberLength(serialNumber); + int serialNumberLen = serialNumberLength(serialNumberAndAuthorityKeyIdentifier.serialNumber); int issuerLen = issuerOrSubjectLength(_issuerCountryName, _issuerStateProvinceName, @@ -365,12 +345,8 @@ int ECCX08CertClass::endReconstruction() int publicKeyLen = publicKeyLength(); - int authorityKeyIdentifierLen = 0; - - if (_authorityKeyIdentifierSlot > -1) { - authorityKeyIdentifierLen = authorityKeyIdentifierLength(); - } - + int authorityKeyIdentifierLen = authorityKeyIdentifierLength(serialNumberAndAuthorityKeyIdentifier.authorityKeyIdentifier); + int signatureLen = signatureLength(compressedCert.signature); int certInfoLen = 5 + serialNumberLen + 12 + issuerHeaderLen + issuerLen + 32 + @@ -411,7 +387,7 @@ int ECCX08CertClass::endReconstruction() *out++ = 0x02; // serial number - appendSerialNumber(serialNumber, out); + appendSerialNumber(serialNumberAndAuthorityKeyIdentifier.serialNumber, out); out += serialNumberLen; // ecdsaWithSHA256 @@ -456,7 +432,7 @@ int ECCX08CertClass::endReconstruction() out += publicKeyLen; if (authorityKeyIdentifierLen) { - appendAuthorityKeyIdentifier(authorityKeyIdentifier, out); + appendAuthorityKeyIdentifier(serialNumberAndAuthorityKeyIdentifier.authorityKeyIdentifier, out); out += authorityKeyIdentifierLen; } else { // null sequence @@ -595,9 +571,19 @@ int ECCX08CertClass::publicKeyLength() return (2 + 2 + 9 + 10 + 4 + 64); } -int ECCX08CertClass::authorityKeyIdentifierLength() +int ECCX08CertClass::authorityKeyIdentifierLength(const byte authorityKeyIdentifier[]) { - return 37; + bool set = false; + + // check if the authority key identifier is non-zero + for (int i = 0; i < AUTHORITY_KEY_IDENTIFIER_LENGTH; i++) { + if (authorityKeyIdentifier[i] != 0) { + set = true; + break; + } + } + + return (set ? 37 : 0); } int ECCX08CertClass::signatureLength(const byte signature[]) diff --git a/src/utility/ECCX08Cert.h b/src/utility/ECCX08Cert.h index f0f4df380..2b35f7777 100644 --- a/src/utility/ECCX08Cert.h +++ b/src/utility/ECCX08Cert.h @@ -12,7 +12,7 @@ class ECCX08CertClass { int beginCSR(int keySlot, bool newPrivateKey = true); String endCSR(); - int beginStorage(int compressedCertSlot, int serialNumberSlot, int authorityKeyIdentifierSlot); + int beginStorage(int compressedCertSlot, int serialNumberAndAuthorityKeyIdentifierSlot); void setSignature(byte signature[]); void setIssueYear(int issueYear); void setIssueMonth(int issueMonth); @@ -23,7 +23,7 @@ class ECCX08CertClass { void setAuthorityKeyIdentifier(const byte authorityKeyIdentifier[]); int endStorage(); - int beginReconstruction(int keySlot, int compressedCertSlot, int serialNumberSlot, int authorityKeyIdentifierSlot); + int beginReconstruction(int keySlot, int compressedCertSlot, int serialNumberAndAuthorityKeyIdentifierSlot); int endReconstruction(); byte* bytes(); @@ -55,7 +55,7 @@ class ECCX08CertClass { int publicKeyLength(); - int authorityKeyIdentifierLength(); + int authorityKeyIdentifierLength(const byte authorityKeyIdentifier[]); int signatureLength(const byte signature[]); @@ -92,8 +92,7 @@ class ECCX08CertClass { private: int _keySlot; int _compressedCertSlot; - int _serialNumberSlot; - int _authorityKeyIdentifierSlot; + int _serialNumberAndAuthorityKeyIdentifierSlot; String _issuerCountryName; String _issuerStateProvinceName; From b935975d0f9ed5272a4fd6ccea4c7e06d24e5917 Mon Sep 17 00:00:00 2001 From: Simone Marchisio Date: Fri, 31 Aug 2018 16:41:26 +0200 Subject: [PATCH 19/24] Handle reconnection inside library --- src/ArduinoCloud.cpp | 78 ++++++++++++++++++++++++++++++++++++++++---- src/ArduinoCloudV2.h | 29 +++++++++++++--- 2 files changed, 97 insertions(+), 10 deletions(-) diff --git a/src/ArduinoCloud.cpp b/src/ArduinoCloud.cpp index dddf3683d..ba791bd43 100644 --- a/src/ArduinoCloud.cpp +++ b/src/ArduinoCloud.cpp @@ -14,7 +14,8 @@ const static int thingIdSlot = 12; ArduinoCloudClass::ArduinoCloudClass() : _bearSslClient(NULL), - _mqttClient(256) + // Size of the receive buffer + _mqttClient(MQTT_BUFFER_SIZE) { } @@ -58,17 +59,31 @@ int ArduinoCloudClass::begin(Client& net) _bearSslClient = new BearSSLClient(net); _bearSslClient->setEccSlot(keySlot, ECCX08Cert.bytes(), ECCX08Cert.length()); - _mqttClient.onMessageAdvanced(ArduinoCloudClass::onMessage); - _mqttClient.begin(server, 8883, *_bearSslClient); - - _stdoutTopic = "$aws/things/" + _id + "/stdout"; - _stdinTopic = "$aws/things/" + _id + "/stdin"; + // Begin function for the MQTTClient + mqttClientBegin(*_bearSslClient); return 1; } +// private class method used to initialize mqttClient class member. (called in the begin class method) +void ArduinoCloudClass::mqttClientBegin(Client& net) +{ + // MQTT topics definition + _stdoutTopic = "/a/d/" + _id + "/s/o"; + _stdinTopic = "/a/d/" + _id + "/s/i"; + + // use onMessage as callback for received mqtt messages + _mqttClient.onMessageAdvanced(ArduinoCloudClass::onMessage); + _mqttClient.begin(server, 8883, net); + + // Set MQTT connection options + _mqttClient.setOptions(mqttOpt.keepAlive, mqttOpt.cleanSession, mqttOpt.timeout); +} + int ArduinoCloudClass::connect() { + // Username: device id + // Password: empty if (!_mqttClient.connect(_id.c_str())) { return 0; } @@ -78,11 +93,62 @@ int ArduinoCloudClass::connect() return 1; } +bool ArduinoCloudClass::disconnect() +{ + return _mqttClient.disconnect(); +} + void ArduinoCloudClass::poll() { + // If user call poll() without parameters use the default ones + poll(MAX_RETRIES, RECONNECTION_TIMEOUT); +} + +bool ArduinoCloudClass::mqttReconnect(int maxRetries, int timeout) +{ + // Counter for reconnection retries + int retries = 0; + unsigned long start = millis(); + + // Check for MQTT broker connection, of if maxReties limit is reached + // if MQTTClient is connected , simply do nothing and retun true + while(!_mqttClient.connected() && (retries++ < maxRetries) && (millis() - start < timeout)) { + + // Get last MTTQClient error, (a common error may be a buffer overflow) + lwmqtt_err_t err = _mqttClient.lastError(); + + // try establish the MQTT broker connection + connect(); + } + + // It was impossible to establish a connection, return + if ((retries == maxRetries) || (millis() - start >= timeout)) + return false; + + return true; +} + +void ArduinoCloudClass::poll(int reconnectionMaxRetries, int reconnectionTimeoutMs) +{ + // Method's argument controls + int maxRetries = (reconnectionMaxRetries > 0) ? reconnectionMaxRetries : MAX_RETRIES; + int timeout = (reconnectionTimeoutMs > 0) ? reconnectionTimeoutMs : RECONNECTION_TIMEOUT; + + // If the reconnect() culd not establish the connection, return the control to the user sketch + if (!mqttReconnect(maxRetries, timeout)) + return; + + // MTTQClient connected!, poll() used to retrieve data from MQTT broker _mqttClient.loop(); } +void ArduinoCloudClass::reconnect(Client& net) +{ + // Initialize again the MQTTClient, otherwise it would not be able to receive messages through its callback + mqttClientBegin(net); + connect(); +} + void ArduinoCloudClass::onGetTime(unsigned long(*callback)(void)) { ArduinoBearSSL.onGetTime(callback); diff --git a/src/ArduinoCloudV2.h b/src/ArduinoCloudV2.h index 6a592565f..6b6b8ff6e 100644 --- a/src/ArduinoCloudV2.h +++ b/src/ArduinoCloudV2.h @@ -6,6 +6,13 @@ #include "CloudSerial.h" +// Declaration of the struct for the mqtt connection options +typedef struct mqtt_opt{ + int keepAlive; + bool cleanSession; + int timeout; +} mqttConnectionOptions; + class ArduinoCloudClass { public: @@ -14,33 +21,47 @@ class ArduinoCloudClass { int begin(Client& net); - int connect(); + // Class constant declaration + static const int MQTT_BUFFER_SIZE = 256; + static const int MAX_RETRIES = 5; + static const int RECONNECTION_TIMEOUT = 2000; + const mqttConnectionOptions mqttOpt = {120, false, 1000}; + int connect(); + bool disconnect(); void poll(); + // defined for users who want to specify max reconnections reties and timeout between them + void poll(int reconnectionMaxRetries, int reconnectionTimeoutMs); + // It must be a user defined function, in order to avoid ArduinoCloud include specific WiFi file + // in this case this library is independent from the WiFi one void onGetTime(unsigned long(*)(void)); int connected(); + // Clean up existing Mqtt connection, create a new one and initialize it + void reconnect(Client& net); protected: friend class CloudSerialClass; int writeStdout(const byte data[], int length); + // Used to initialize MQTTClient + void mqttClientBegin(Client& net); + // Function in charge of perform MQTT reconnection, basing on class parameters(retries,and timeout) + bool mqttReconnect(int maxRetries, int timeout); private: static void onMessage(MQTTClient *client, char topic[], char bytes[], int length); - void handleMessage(char topic[], char bytes[], int length); -private: String _id; BearSSLClient* _bearSslClient; MQTTClient _mqttClient; + // 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; }; - extern ArduinoCloudClass ArduinoCloud; #endif From 3669b2cebbf30978f5928f34a3ab2fe70b86df6a Mon Sep 17 00:00:00 2001 From: Alberto Iannaccone Date: Fri, 31 Aug 2018 16:41:48 +0200 Subject: [PATCH 20/24] use vernemq instance --- src/ArduinoCloud.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ArduinoCloud.cpp b/src/ArduinoCloud.cpp index ba791bd43..bed2a727f 100644 --- a/src/ArduinoCloud.cpp +++ b/src/ArduinoCloud.cpp @@ -5,7 +5,7 @@ #include "ArduinoCloudV2.h" -const static char server[] = "a19g5nbe27wn47.iot.us-east-1.amazonaws.com"; //"xxxxxxxxxxxxxx.iot.xx-xxxx-x.amazonaws.com"; +const static char server[] = "mqtts-sa.iot.oniudra.cc"; const static int keySlot = 0; const static int compressedCertSlot = 10; @@ -43,7 +43,7 @@ int ArduinoCloudClass::begin(Client& net) return 0; } - ECCX08Cert.setSubjectCommonName(ECCX08.serialNumber()); + ECCX08Cert.setSubjectCommonName(_id); ECCX08Cert.setIssuerCountryName("US"); ECCX08Cert.setIssuerOrganizationName("Arduino LLC US"); ECCX08Cert.setIssuerOrganizationalUnitName("IT"); @@ -87,7 +87,6 @@ int ArduinoCloudClass::connect() if (!_mqttClient.connect(_id.c_str())) { return 0; } - _mqttClient.subscribe(_stdinTopic); return 1; From cb8b5494f247144961238110f0b4b115828e1e83 Mon Sep 17 00:00:00 2001 From: Alberto Iannaccone Date: Fri, 31 Aug 2018 16:42:19 +0200 Subject: [PATCH 21/24] Adapt provisioning to new backend infractructure --- examples/utility/Provisioning/Provisioning.ino | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/examples/utility/Provisioning/Provisioning.ino b/examples/utility/Provisioning/Provisioning.ino index a58b486b3..cf18f0664 100644 --- a/examples/utility/Provisioning/Provisioning.ino +++ b/examples/utility/Provisioning/Provisioning.ino @@ -5,6 +5,7 @@ #include #include +const bool DEBUG = true; const int keySlot = 0; const int compressedCertSlot = 10; const int serialNumberAndAuthorityKeyIdentifierSlot = 11; @@ -55,7 +56,8 @@ void setup() { while (1); } - ECCX08Cert.setSubjectCommonName(ECCX08.serialNumber()); + String thingId = promptAndReadLine("Please enter the thing id: "); + ECCX08Cert.setSubjectCommonName(thingId); String csr = ECCX08Cert.endCSR(); @@ -68,7 +70,6 @@ void setup() { Serial.println(); Serial.println(csr); - String thingId = promptAndReadLine("Please enter the thing id: "); String issueYear = promptAndReadLine("Please enter the issue year of the certificate (2000 - 2031): "); String issueMonth = promptAndReadLine("Please enter the issue month of the certificate (1 - 12): "); String issueDay = promptAndReadLine("Please enter the issue day of the certificate (1 - 31): "); @@ -78,9 +79,6 @@ void setup() { String authorityKeyIdentifier = promptAndReadLine("Please enter the certificates authority key identifier: "); String signature = promptAndReadLine("Please enter the certificates signature: "); - serialNumber.toUpperCase(); - signature.toUpperCase(); - byte thingIdBytes[72]; byte serialNumberBytes[16]; byte authorityKeyIdentifierBytes[20]; @@ -130,6 +128,10 @@ void setup() { while (1); } + if (!DEBUG) { + return; + } + Serial.println("Compressed cert = "); const byte* certData = ECCX08Cert.bytes(); @@ -179,8 +181,9 @@ String readLine() { return line; } -void hexStringToBytes(const String& in, byte out[], int length) { +void hexStringToBytes(String& in, byte out[], int length) { int inLength = in.length(); + in.toUpperCase(); int outLength = 0; for (int i = 0; i < inLength && outLength < length; i += 2) { @@ -190,6 +193,6 @@ void hexStringToBytes(const String& in, byte out[], int length) { byte highByte = (highChar <= '9') ? (highChar - '0') : (highChar + 10 - 'A'); byte lowByte = (lowChar <= '9') ? (lowChar - '0') : (lowChar + 10 - 'A'); - out[outLength++] = (highByte << 4) | lowByte; + out[outLength++] = (highByte << 4) | (lowByte & 0xF); } } From 88e9cdec740dc033ade78e1dd3daa0796d0919e4 Mon Sep 17 00:00:00 2001 From: Alberto Iannaccone Date: Fri, 31 Aug 2018 16:42:47 +0200 Subject: [PATCH 22/24] Fix getting started CloudSerial sketch --- .../MKR1000_Cloud_Blink.ino | 84 +++++++++++++++++-- 1 file changed, 75 insertions(+), 9 deletions(-) diff --git a/examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino b/examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino index 07a7deed3..a8fda62f6 100644 --- a/examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino +++ b/examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino @@ -1,11 +1,14 @@ -#include +#include // change to WiFiNINA.h if you are using the MKR WiFi 1010 or MKR Vidor 4000 #include - #include "arduino_secrets.h" + +#define TIMEOUT 7000 + ///////please enter your sensitive data in the Secret tab/arduino_secrets.h char ssid[] = SECRET_SSID; // your network SSID (name) char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) int status = WL_IDLE_STATUS; // the WiFi radio's status +String cloudSerialBuffer = ""; // the string used to compose network messages from the received characters WiFiClient wifiClient; @@ -16,9 +19,8 @@ unsigned long getTime() { void setup() { //Initialize serial and wait for port to open: Serial.begin(9600); - while (!Serial) { - ; // wait for serial port to connect. Needed for native USB port only - } + int timeout = millis() + TIMEOUT; + while (!Serial && (millis() < timeout)) {} // check for the presence of the shield: if (WiFi.status() == WL_NO_SHIELD) { @@ -33,7 +35,8 @@ void setup() { } // attempt to connect to WiFi network: - while (status != WL_CONNECTED) { + int attempts = 0; + while (status != WL_CONNECTED && attempts < 6) { Serial.print("Attempting to connect to WPA SSID: "); Serial.println(ssid); // Connect to WPA/WPA2 network: @@ -41,16 +44,29 @@ void setup() { // wait 10 seconds for connection: delay(10000); + attempts++; + } + + if (status != WL_CONNECTED) { + Serial.println("Failed to connect to Wifi!"); + while (true); } // you're connected now, so print out the data: Serial.print("You're connected to the network"); Serial.println(); - Serial.println("Attempting to connect to Arduino Cloud ..."); + Serial.println("Attempting to connect to Arduino Cloud"); ArduinoCloud.onGetTime(getTime); - if (!ArduinoCloud.connect()) { + + attempts = 0; + while (!ArduinoCloud.connect() && attempts < 10) { + Serial.print("."); + attempts++; + } + + if (attempts >= 10) { Serial.println("Failed to connect to Arduino Cloud!"); while (1); } @@ -58,17 +74,67 @@ void setup() { Serial.println("Successfully connected to Arduino Cloud :)"); CloudSerial.begin(9600); + CloudSerial.print("I'm ready for blinking!\n"); } void loop() { ArduinoCloud.poll(); + // check if there is something waiting to be read if (CloudSerial.available()) { - Serial.write(CloudSerial.read()); + char character = CloudSerial.read(); + cloudSerialBuffer += character; + + // if a \n character has been received, there should be a complete command inside cloudSerialBuffer + if (character == '\n') { + manageString(); + } + } + else // if there is nothing to read, it could be that the last command didn't end with a '\n'. Check. + { + manageString(); } + // Just to be able to simulate the board responses through the serial monitor if (Serial.available()) { CloudSerial.write(Serial.read()); } } +void manageString() { + // Don't proceed if the string is empty + if (cloudSerialBuffer.equals("")) return; + + // Remove whitespaces + cloudSerialBuffer.trim(); + + // Make it uppercase; + cloudSerialBuffer.toUpperCase(); + + if (cloudSerialBuffer.equals("ON")) { + digitalWrite(6, HIGH); + } + if (cloudSerialBuffer.equals("OFF")) { + digitalWrite(6, LOW); + } + + sendString(cloudSerialBuffer); + + // Reset cloudSerialBuffer + cloudSerialBuffer = ""; +} + +// sendString sends a string to the Arduino Cloud. +void sendString(String stringToSend) { + // send the characters one at a time + char lastSentChar = 0; + for (int i = 0; i < stringToSend.length(); i++) { + lastSentChar = stringToSend.charAt(i); + CloudSerial.write(lastSentChar); + } + + // if the last sent character wasn't a '\n' add it + if (lastSentChar != '\n') { + CloudSerial.write('\n'); + } +} From 82fb1684128656e551b0996b5e0437552b6de4cb Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Fri, 31 Aug 2018 17:17:20 +0200 Subject: [PATCH 23/24] Split _dataTopic into In and Out --- src/ArduinoCloud.cpp | 11 +++++++---- src/ArduinoCloudV2.h | 3 ++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ArduinoCloud.cpp b/src/ArduinoCloud.cpp index 1f33c4ae6..4a7f9e37f 100644 --- a/src/ArduinoCloud.cpp +++ b/src/ArduinoCloud.cpp @@ -73,6 +73,8 @@ void ArduinoCloudClass::mqttClientBegin(Client& net) // MQTT topics definition _stdoutTopic = "/a/d/" + _id + "/s/o"; _stdinTopic = "/a/d/" + _id + "/s/i"; + _dataTopicIn = "/a/d/" + _id + "/e/i"; + _dataTopicOut = "/a/d/" + _id + "/e/o"; // use onMessage as callback for received mqtt messages _mqttClient.onMessageAdvanced(ArduinoCloudClass::onMessage); @@ -90,7 +92,7 @@ int ArduinoCloudClass::connect() return 0; } _mqttClient.subscribe(_stdinTopic); - _mqttClient.subscribe(_dataTopic); + _mqttClient.subscribe(_dataTopicIn); return 1; } @@ -142,7 +144,8 @@ void ArduinoCloudClass::poll(int reconnectionMaxRetries, int reconnectionTimeout // MTTQClient connected!, poll() used to retrieve data from MQTT broker _mqttClient.loop(); - uint8_t data[1024]; + + uint8_t data[MQTT_BUFFER_SIZE]; int length = Thing.poll(data, sizeof(data)); if (length > 0) { writeProperties(data, length); @@ -168,7 +171,7 @@ int ArduinoCloudClass::connected() int ArduinoCloudClass::writeProperties(const byte data[], int length) { - return _mqttClient.publish(_dataTopic.c_str(), (const char*)data, length); + return _mqttClient.publish(_dataTopicOut.c_str(), (const char*)data, length); } int ArduinoCloudClass::writeStdout(const byte data[], int length) @@ -186,7 +189,7 @@ void ArduinoCloudClass::handleMessage(char topic[], char bytes[], int length) if (_stdinTopic == topic) { CloudSerial.appendStdin((uint8_t*)bytes, length); } - if (_dataTopic == topic) { + if (_dataTopicIn == topic) { Thing.decode((uint8_t*)bytes, length); } } diff --git a/src/ArduinoCloudV2.h b/src/ArduinoCloudV2.h index 8c4832e23..6c3d5e767 100644 --- a/src/ArduinoCloudV2.h +++ b/src/ArduinoCloudV2.h @@ -77,7 +77,8 @@ class ArduinoCloudClass { // 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 _dataTopic; + String _dataTopicOut; + String _dataTopicIn; String _otaTopic; }; From 646c92ae62765b1fe5ece61df7c82e87600eefd0 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Mon, 3 Sep 2018 17:30:25 +0200 Subject: [PATCH 24/24] Thing: use non-composition APIs --- src/ArduinoCloudV2.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ArduinoCloudV2.h b/src/ArduinoCloudV2.h index 6c3d5e767..dc2a89714 100644 --- a/src/ArduinoCloudV2.h +++ b/src/ArduinoCloudV2.h @@ -45,15 +45,15 @@ class ArduinoCloudClass { #define addProperty( v, ...) addPropertyReal(v, #v, __VA_ARGS__) template void addPropertyReal(T& property, String name, permissionType _permission = READWRITE, long seconds = ON_CHANGE, T minDelta = T(0), void(*fn)(void) = NULL) { - Thing.addPropertyReal(property, name).publishEvery(seconds).setPermission(_permission).onUpdate(fn).minimumDelta(&minDelta); + Thing.addPropertyReal(property, name, _permission, seconds, fn, minDelta); } template void addPropertyReal(T& property, String name, permissionType _permission = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, T minDelta = T(0)) { - Thing.addPropertyReal(property, name).publishEvery(seconds).setPermission(_permission).onUpdate(fn).minimumDelta(&minDelta); + Thing.addPropertyReal(property, name, _permission, seconds, fn, minDelta); } template void addPropertyReal(T& property, String name, permissionType _permission = READWRITE, void(*fn)(void) = NULL, long seconds = ON_CHANGE, T minDelta = T(0)) { - Thing.addPropertyReal(property, name).publishEvery(seconds).setPermission(_permission).onUpdate(fn).minimumDelta(&minDelta); + Thing.addPropertyReal(property, name, _permission, seconds, fn, minDelta); } protected: