Skip to content

Commit 767f131

Browse files
authored
Merge pull request #8 from bcmi-labs/vernemq_rebased
Vernemq rebased
2 parents 6cf3249 + 88e9cde commit 767f131

File tree

4 files changed

+181
-24
lines changed

4 files changed

+181
-24
lines changed

Diff for: examples/MKR1000_Cloud_Blink/MKR1000_Cloud_Blink.ino

+75-9
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
#include <WiFi101.h>
1+
#include <WiFi101.h> // change to WiFiNINA.h if you are using the MKR WiFi 1010 or MKR Vidor 4000
22
#include <ArduinoCloudV2.h>
3-
43
#include "arduino_secrets.h"
4+
5+
#define TIMEOUT 7000
6+
57
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
68
char ssid[] = SECRET_SSID; // your network SSID (name)
79
char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP)
810
int status = WL_IDLE_STATUS; // the WiFi radio's status
11+
String cloudSerialBuffer = ""; // the string used to compose network messages from the received characters
912

1013
WiFiClient wifiClient;
1114

@@ -16,9 +19,8 @@ unsigned long getTime() {
1619
void setup() {
1720
//Initialize serial and wait for port to open:
1821
Serial.begin(9600);
19-
while (!Serial) {
20-
; // wait for serial port to connect. Needed for native USB port only
21-
}
22+
int timeout = millis() + TIMEOUT;
23+
while (!Serial && (millis() < timeout)) {}
2224

2325
// check for the presence of the shield:
2426
if (WiFi.status() == WL_NO_SHIELD) {
@@ -33,42 +35,106 @@ void setup() {
3335
}
3436

3537
// attempt to connect to WiFi network:
36-
while (status != WL_CONNECTED) {
38+
int attempts = 0;
39+
while (status != WL_CONNECTED && attempts < 6) {
3740
Serial.print("Attempting to connect to WPA SSID: ");
3841
Serial.println(ssid);
3942
// Connect to WPA/WPA2 network:
4043
status = WiFi.begin(ssid, pass);
4144

4245
// wait 10 seconds for connection:
4346
delay(10000);
47+
attempts++;
48+
}
49+
50+
if (status != WL_CONNECTED) {
51+
Serial.println("Failed to connect to Wifi!");
52+
while (true);
4453
}
4554

4655
// you're connected now, so print out the data:
4756
Serial.print("You're connected to the network");
4857

4958
Serial.println();
50-
Serial.println("Attempting to connect to Arduino Cloud ...");
59+
Serial.println("Attempting to connect to Arduino Cloud");
5160

5261
ArduinoCloud.onGetTime(getTime);
53-
if (!ArduinoCloud.connect()) {
62+
63+
attempts = 0;
64+
while (!ArduinoCloud.connect() && attempts < 10) {
65+
Serial.print(".");
66+
attempts++;
67+
}
68+
69+
if (attempts >= 10) {
5470
Serial.println("Failed to connect to Arduino Cloud!");
5571
while (1);
5672
}
5773

5874
Serial.println("Successfully connected to Arduino Cloud :)");
5975

6076
CloudSerial.begin(9600);
77+
CloudSerial.print("I'm ready for blinking!\n");
6178
}
6279

6380
void loop() {
6481
ArduinoCloud.poll();
6582

83+
// check if there is something waiting to be read
6684
if (CloudSerial.available()) {
67-
Serial.write(CloudSerial.read());
85+
char character = CloudSerial.read();
86+
cloudSerialBuffer += character;
87+
88+
// if a \n character has been received, there should be a complete command inside cloudSerialBuffer
89+
if (character == '\n') {
90+
manageString();
91+
}
92+
}
93+
else // if there is nothing to read, it could be that the last command didn't end with a '\n'. Check.
94+
{
95+
manageString();
6896
}
6997

98+
// Just to be able to simulate the board responses through the serial monitor
7099
if (Serial.available()) {
71100
CloudSerial.write(Serial.read());
72101
}
73102
}
74103

104+
void manageString() {
105+
// Don't proceed if the string is empty
106+
if (cloudSerialBuffer.equals("")) return;
107+
108+
// Remove whitespaces
109+
cloudSerialBuffer.trim();
110+
111+
// Make it uppercase;
112+
cloudSerialBuffer.toUpperCase();
113+
114+
if (cloudSerialBuffer.equals("ON")) {
115+
digitalWrite(6, HIGH);
116+
}
117+
if (cloudSerialBuffer.equals("OFF")) {
118+
digitalWrite(6, LOW);
119+
}
120+
121+
sendString(cloudSerialBuffer);
122+
123+
// Reset cloudSerialBuffer
124+
cloudSerialBuffer = "";
125+
}
126+
127+
// sendString sends a string to the Arduino Cloud.
128+
void sendString(String stringToSend) {
129+
// send the characters one at a time
130+
char lastSentChar = 0;
131+
for (int i = 0; i < stringToSend.length(); i++) {
132+
lastSentChar = stringToSend.charAt(i);
133+
CloudSerial.write(lastSentChar);
134+
}
135+
136+
// if the last sent character wasn't a '\n' add it
137+
if (lastSentChar != '\n') {
138+
CloudSerial.write('\n');
139+
}
140+
}

Diff for: examples/utility/Provisioning/Provisioning.ino

+7-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <ArduinoBearSSL.h>
66
#include <ArduinoECCX08.h>
77

8+
const bool DEBUG = true;
89
const int keySlot = 0;
910
const int compressedCertSlot = 10;
1011
const int serialNumberAndAuthorityKeyIdentifierSlot = 11;
@@ -55,7 +56,8 @@ void setup() {
5556
while (1);
5657
}
5758

58-
ECCX08Cert.setSubjectCommonName(ECCX08.serialNumber());
59+
String thingId = promptAndReadLine("Please enter the thing id: ");
60+
ECCX08Cert.setSubjectCommonName(thingId);
5961

6062
String csr = ECCX08Cert.endCSR();
6163

@@ -68,7 +70,6 @@ void setup() {
6870
Serial.println();
6971
Serial.println(csr);
7072

71-
String thingId = promptAndReadLine("Please enter the thing id: ");
7273
String issueYear = promptAndReadLine("Please enter the issue year of the certificate (2000 - 2031): ");
7374
String issueMonth = promptAndReadLine("Please enter the issue month of the certificate (1 - 12): ");
7475
String issueDay = promptAndReadLine("Please enter the issue day of the certificate (1 - 31): ");
@@ -127,6 +128,10 @@ void setup() {
127128
while (1);
128129
}
129130

131+
if (!DEBUG) {
132+
return;
133+
}
134+
130135
Serial.println("Compressed cert = ");
131136

132137
const byte* certData = ECCX08Cert.bytes();

Diff for: src/ArduinoCloud.cpp

+74-9
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
#include "ArduinoCloudV2.h"
77

8-
const static char server[] = "a19g5nbe27wn47.iot.us-east-1.amazonaws.com"; //"xxxxxxxxxxxxxx.iot.xx-xxxx-x.amazonaws.com";
8+
const static char server[] = "mqtts-sa.iot.oniudra.cc";
99

1010
const static int keySlot = 0;
1111
const static int compressedCertSlot = 10;
@@ -14,7 +14,8 @@ const static int thingIdSlot = 12;
1414

1515
ArduinoCloudClass::ArduinoCloudClass() :
1616
_bearSslClient(NULL),
17-
_mqttClient(256)
17+
// Size of the receive buffer
18+
_mqttClient(MQTT_BUFFER_SIZE)
1819
{
1920
}
2021

@@ -42,7 +43,7 @@ int ArduinoCloudClass::begin(Client& net)
4243
return 0;
4344
}
4445

45-
ECCX08Cert.setSubjectCommonName(ECCX08.serialNumber());
46+
ECCX08Cert.setSubjectCommonName(_id);
4647
ECCX08Cert.setIssuerCountryName("US");
4748
ECCX08Cert.setIssuerOrganizationName("Arduino LLC US");
4849
ECCX08Cert.setIssuerOrganizationalUnitName("IT");
@@ -58,31 +59,95 @@ int ArduinoCloudClass::begin(Client& net)
5859
_bearSslClient = new BearSSLClient(net);
5960
_bearSslClient->setEccSlot(keySlot, ECCX08Cert.bytes(), ECCX08Cert.length());
6061

61-
_mqttClient.onMessageAdvanced(ArduinoCloudClass::onMessage);
62-
_mqttClient.begin(server, 8883, *_bearSslClient);
63-
64-
_stdoutTopic = "$aws/things/" + _id + "/stdout";
65-
_stdinTopic = "$aws/things/" + _id + "/stdin";
62+
// Begin function for the MQTTClient
63+
mqttClientBegin(*_bearSslClient);
6664

6765
return 1;
6866
}
6967

68+
// private class method used to initialize mqttClient class member. (called in the begin class method)
69+
void ArduinoCloudClass::mqttClientBegin(Client& net)
70+
{
71+
// MQTT topics definition
72+
_stdoutTopic = "/a/d/" + _id + "/s/o";
73+
_stdinTopic = "/a/d/" + _id + "/s/i";
74+
75+
// use onMessage as callback for received mqtt messages
76+
_mqttClient.onMessageAdvanced(ArduinoCloudClass::onMessage);
77+
_mqttClient.begin(server, 8883, net);
78+
79+
// Set MQTT connection options
80+
_mqttClient.setOptions(mqttOpt.keepAlive, mqttOpt.cleanSession, mqttOpt.timeout);
81+
}
82+
7083
int ArduinoCloudClass::connect()
7184
{
85+
// Username: device id
86+
// Password: empty
7287
if (!_mqttClient.connect(_id.c_str())) {
7388
return 0;
7489
}
75-
7690
_mqttClient.subscribe(_stdinTopic);
7791

7892
return 1;
7993
}
8094

95+
bool ArduinoCloudClass::disconnect()
96+
{
97+
return _mqttClient.disconnect();
98+
}
99+
81100
void ArduinoCloudClass::poll()
82101
{
102+
// If user call poll() without parameters use the default ones
103+
poll(MAX_RETRIES, RECONNECTION_TIMEOUT);
104+
}
105+
106+
bool ArduinoCloudClass::mqttReconnect(int maxRetries, int timeout)
107+
{
108+
// Counter for reconnection retries
109+
int retries = 0;
110+
unsigned long start = millis();
111+
112+
// Check for MQTT broker connection, of if maxReties limit is reached
113+
// if MQTTClient is connected , simply do nothing and retun true
114+
while(!_mqttClient.connected() && (retries++ < maxRetries) && (millis() - start < timeout)) {
115+
116+
// Get last MTTQClient error, (a common error may be a buffer overflow)
117+
lwmqtt_err_t err = _mqttClient.lastError();
118+
119+
// try establish the MQTT broker connection
120+
connect();
121+
}
122+
123+
// It was impossible to establish a connection, return
124+
if ((retries == maxRetries) || (millis() - start >= timeout))
125+
return false;
126+
127+
return true;
128+
}
129+
130+
void ArduinoCloudClass::poll(int reconnectionMaxRetries, int reconnectionTimeoutMs)
131+
{
132+
// Method's argument controls
133+
int maxRetries = (reconnectionMaxRetries > 0) ? reconnectionMaxRetries : MAX_RETRIES;
134+
int timeout = (reconnectionTimeoutMs > 0) ? reconnectionTimeoutMs : RECONNECTION_TIMEOUT;
135+
136+
// If the reconnect() culd not establish the connection, return the control to the user sketch
137+
if (!mqttReconnect(maxRetries, timeout))
138+
return;
139+
140+
// MTTQClient connected!, poll() used to retrieve data from MQTT broker
83141
_mqttClient.loop();
84142
}
85143

144+
void ArduinoCloudClass::reconnect(Client& net)
145+
{
146+
// Initialize again the MQTTClient, otherwise it would not be able to receive messages through its callback
147+
mqttClientBegin(net);
148+
connect();
149+
}
150+
86151
void ArduinoCloudClass::onGetTime(unsigned long(*callback)(void))
87152
{
88153
ArduinoBearSSL.onGetTime(callback);

Diff for: src/ArduinoCloudV2.h

+25-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66

77
#include "CloudSerial.h"
88

9+
// Declaration of the struct for the mqtt connection options
10+
typedef struct mqtt_opt{
11+
int keepAlive;
12+
bool cleanSession;
13+
int timeout;
14+
} mqttConnectionOptions;
15+
916
class ArduinoCloudClass {
1017

1118
public:
@@ -14,33 +21,47 @@ class ArduinoCloudClass {
1421

1522
int begin(Client& net);
1623

17-
int connect();
24+
// Class constant declaration
25+
static const int MQTT_BUFFER_SIZE = 256;
26+
static const int MAX_RETRIES = 5;
27+
static const int RECONNECTION_TIMEOUT = 2000;
28+
const mqttConnectionOptions mqttOpt = {120, false, 1000};
1829

30+
int connect();
31+
bool disconnect();
1932
void poll();
2033

34+
// defined for users who want to specify max reconnections reties and timeout between them
35+
void poll(int reconnectionMaxRetries, int reconnectionTimeoutMs);
36+
// It must be a user defined function, in order to avoid ArduinoCloud include specific WiFi file
37+
// in this case this library is independent from the WiFi one
2138
void onGetTime(unsigned long(*)(void));
2239

2340
int connected();
41+
// Clean up existing Mqtt connection, create a new one and initialize it
42+
void reconnect(Client& net);
2443

2544
protected:
2645
friend class CloudSerialClass;
2746
int writeStdout(const byte data[], int length);
47+
// Used to initialize MQTTClient
48+
void mqttClientBegin(Client& net);
49+
// Function in charge of perform MQTT reconnection, basing on class parameters(retries,and timeout)
50+
bool mqttReconnect(int maxRetries, int timeout);
2851

2952
private:
3053
static void onMessage(MQTTClient *client, char topic[], char bytes[], int length);
31-
3254
void handleMessage(char topic[], char bytes[], int length);
3355

34-
private:
3556
String _id;
3657
BearSSLClient* _bearSslClient;
3758
MQTTClient _mqttClient;
3859

60+
// Class attribute to define MTTQ topics 2 for stdIn/out and 2 for data, in order to avoid getting previous pupblished payload
3961
String _stdinTopic;
4062
String _stdoutTopic;
4163
};
4264

43-
4465
extern ArduinoCloudClass ArduinoCloud;
4566

4667
#endif

0 commit comments

Comments
 (0)