Skip to content

Commit bff994e

Browse files
authored
Merge branch 'master' into gsm_proper_connmanager
2 parents 7fc775b + 73f30cc commit bff994e

File tree

6 files changed

+119
-21
lines changed

6 files changed

+119
-21
lines changed

README.md

+76-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,80 @@
11
# ArduinoIoTCloud
22

3-
This library allows to connect to the Arduino IoT Cloud service. It provides a ConnectionManager to handle connection/disconnection, property-change updates and events callbacks.
4-
The supported boards are MKRGSM, MKR1000 (Wifi101) and MKR 1010 (WifiNINA).
3+
This library facilitates interactions between boards featuring a cryptography co-processor and the Arduino IoT Cloud service. It includes a ConnectionManager to handle connection/disconnection/reconnection flows and provides means to interface local sketch variables with cloud based Thing properties, enabling synchronization and on-change callbacks.
4+
Currently supported boards: MKR1000 (WiFi101) and MKR 1010 (WiFiNINA). Support for MKRGSM is nearing completion and more cryptography enabled boards are following.
55

6+
## Arduino IoT Cloud
67

8+
[Arduino IoT Cloud](https://create.arduino.cc/iot) is a service which facilitates connections between cloud-based applications and the world around you. More information [is available here](https://www.arduino.cc/en/IoT/HomePage) and a detailed tutorial can be found on [Arduino Project Hub](https://create.arduino.cc/projecthub/133030/iot-cloud-getting-started-c93255).
9+
The platform is currently in public beta, we appreciate any feedback provided.
10+
11+
12+
### Arduino IoT Cloud Components
13+
14+
- **Devices**: Physical objects built around a board (e.g. MKR WiFi 1010). This is the hardware which runs the sketch, reads sensors, controls actuators and communicates with the Arduino IoT Cloud.
15+
16+
- **Things**: Logical representation of a connected object. They embody inherent properties of the object, with as little reference to the actual hardware or code used to implement them. Each Thing is represented by a collection of _Properties_ (e.g., temperature, light, pressure...).
17+
18+
- **Properties**: Qualities defining the characteristics of a system. A _Property_ can be defined as *read-only* (RO) to indicate that Arduino IoT Cloud can read the data, but cannot change the value of such _Property_. On the other end it may be designated to be **read-and-write** (RW), allowing Arduino IoT Cloud to remotely change the property’s value and trigger an event notification on the device to be handled via code.
19+
20+
- **Events**: When a physical event is triggered on the _Device_, Arduino IoT Cloud is made aware of it thanks to application messages. It might, for example, be notified that a proximity sensor detected someone or something outside a door.
21+
22+
- **Software**: An Arduino Create sketch is automatically generated by Arduino IoT Cloud when setting up a new thing: this simplifies starting efforts. Because the connection to the cloud is handled by the library, the user can focus on implementing the last bits of code required to handle the change of variables linked to properties.
23+
The introductory tutorial linked above explains this in an easy and comprehensive way.
24+
25+
## ArduinoIoTCloud library
26+
27+
The library is made of multiple classes:
28+
- `ArduinoIoTCloud` is the main class. It's responsible for the connection to the MQTT Broker and to Arduino IoT Cloud.
29+
This library has multiple `begin(...)` methods allowing you to take more control of its behavior when it comes to network **Client** or to use a `ConnectionManager`
30+
31+
- `ConnectionManager` is an abstract Class defining methods to be implemented in derived classes, such as `WiFiConnectionManager`, `GSMConnectionManager` and so on. The right `ConnectionManager` is chosen on a board basis during compilation.
32+
33+
- `WiFiConnectionManager` handles connection, network time retrieval, disconnection, and reconnection to Internet for WiFi equipped boards (**MKR1000**, **MKR WIFI 1010** and upcoming implementations).
34+
35+
- `GSMConnectionManager` handles connection, network time retrieval, disconnection, and reconnection to Internet for GSM equipped boards (**MKR GSM 1400**)
36+
37+
38+
- `CloudSerial` is similar to [Serial](https://www.arduino.cc/reference/en/language/functions/communication/serial/), but used in combination with the cloud, allowing the user to send and receive custom messages using Arduino IoT Cloud as a channel.
39+
40+
41+
### ConnectionManager
42+
43+
**Connection Manager** is configured via a series of compiler directives, including the correct implementation of the class based on which board is selected.
44+
45+
### How to use it
46+
- Instantiate the class with `ConnectionManager *ArduinoIoTPreferredConnection = new WiFiConnectionManager(SECRET_SSID, SECRET_PASS);` if you are using a WiFi board, otherwise replace **WiFi** with **GSM** or any future implementation.
47+
48+
- The `check()` method does all the work. It uses a finite state machine and is responsible for connection and reconnection to a network. The method is designed to be non-blocking by using time (milliseconds) to perform its tasks.
49+
50+
- `getTime()` returns different implementations of the `getTIme()` method based on the board used. Time is retrieved from an NTP server and is required for the SSL connection to the cloud.
51+
52+
- `&getClient()` returns a reference an instance of the `Client` class used to connect to the network.
53+
54+
- `getStatus()` returns the network connection status. The different states are defined in an `enum`
55+
56+
- `debugMessage(char *_msg, uint8_t _debugLevel, bool _timestamp = true, bool _newline = true)` is the method used to print debug messages on the physical serial. This helps providing troubleshooting information should anything go wrong.
57+
58+
- The `setDebugMessageLevel(int _debugLevel)` method is used to set a level of granularity in information output. Every debug message comes with a level which goes from 0 to 4. A higher level means more verbosity. Debug messages with level higher than `_debugLevel` will not be shown. The lowest level has a higher importance and is usually used for errors, which are always printed. Passing -1 as a parameter will disable logging entirely, **errors will also be ignored**.
59+
60+
### ArduinoIoTCloud
61+
62+
- The `begin(ConnectionManager *connection = ArduinoIoTPreferredConnection, String brokerAddress = "mqtts-sa.iot.arduino.cc")` method is used to initialize a connection to the Arduino IoT Cloud through MQTT. Accepts an instance of `ConnectionManager` and returns 0 in case of failure or 1 if object is successfully instantiated.
63+
64+
- `begin(Client& net, String brokerAddress = "mqtts-sa.iot.arduino.cc")` if connection is managed manually and not via a `ConnectionManager` a reference to a `Client` object can be used.
65+
66+
- The `connect()` method is used to connect to the MQTT broker.
67+
68+
- `disconnect()` closes the connection to the MQTT Client.
69+
70+
- The `update()` method can be called periodically in the loop of the `.ino` file. If a `ConnectionManager` is implemented it checks network connnections. It also makes sure that a connection with the MQTT broker is active and tries to reconnect otherwise. During `update()` data from the Cloud is retrieved and changed values are posted to the proper MQTT topic.
71+
72+
- `connected()` simply returns the current status of the MQTT connection.
73+
74+
- `reconnect(Client&)` cleans up the existing MQTT connection, creates a new one and initializes it by calling `connect()`
75+
76+
- `setThingId(String const thing_id)` sets the **THING_ID** to properly configure the MQTT topic.
77+
78+
- `getThingId()` returns the **THING_ID**.
79+
80+
- `connectionCheck()` invokes the `check()` method from a **ConnectionManager** if it is implemented. Mainly it implements a state machine and is responsible for the connection to Arduino IoT Cloud.

examples/ArduinoIoTCloud_LED_switch/ArduinoIoTCloud_LED_switch.ino

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ void setup() {
3838
3939
setDebugMessageLevel(3);
4040
*/
41-
41+
ArduinoCloud.printDebugInfo();
4242
}
4343

4444
void loop() {

src/ArduinoIoTCloud.cpp

+26-12
Original file line numberDiff line numberDiff line change
@@ -58,32 +58,37 @@ ArduinoIoTCloudClass::~ArduinoIoTCloudClass()
5858
}
5959
}
6060

61-
int ArduinoIoTCloudClass::begin(ConnectionManager *c, String brokerAddress)
61+
int ArduinoIoTCloudClass::begin(ConnectionManager *c, String brokerAddress, uint16_t brokerPort)
6262
{
6363
connection = c;
6464
Client &connectionClient = c->getClient();
6565
_brokerAddress = brokerAddress;
66-
return begin(connectionClient, _brokerAddress);
66+
_brokerPort = brokerPort;
67+
return begin(connectionClient, _brokerAddress, _brokerPort);
6768
}
6869

69-
int ArduinoIoTCloudClass::begin(Client& net, String brokerAddress)
70+
int ArduinoIoTCloudClass::begin(Client& net, String brokerAddress, uint16_t brokerPort)
7071
{
7172

7273
_net = &net;
7374
// store the broker address as class member
7475
_brokerAddress = brokerAddress;
76+
_brokerPort = brokerPort;
7577
byte thingIdBytes[72];
7678

7779
if (!ECCX08.begin()) {
80+
debugMessage("Cryptography processor failure. Make sure you have a compatible board.", 0);
7881
return 0;
7982
}
8083

8184
if (!ECCX08.readSlot(thingIdSlot, thingIdBytes, sizeof(thingIdBytes))) {
85+
debugMessage("Cryptography processor read failure.", 0);
8286
return 0;
8387
}
8488
_id = (char*)thingIdBytes;
8589

8690
if (!ECCX08Cert.beginReconstruction(keySlot, compressedCertSlot, serialNumberAndAuthorityKeyIdentifierSlot)) {
91+
debugMessage("Cryptography certificate reconstruction failure.", 0);
8792
return 0;
8893
}
8994

@@ -94,6 +99,7 @@ int ArduinoIoTCloudClass::begin(Client& net, String brokerAddress)
9499
ECCX08Cert.setIssuerCommonName("Arduino");
95100

96101
if (!ECCX08Cert.endReconstruction()) {
102+
debugMessage("Cryptography certificate reconstruction failure.", 0);
97103
return 0;
98104
}
99105

@@ -121,7 +127,6 @@ int ArduinoIoTCloudClass::begin(Client& net, String brokerAddress)
121127
mqttClientBegin();
122128

123129
Thing.begin();
124-
125130
return 1;
126131
}
127132

@@ -156,7 +161,7 @@ int ArduinoIoTCloudClass::connect()
156161
{
157162
// Username: device id
158163
// Password: empty
159-
if (!_mqttClient->connect(_brokerAddress.c_str(), 8883)) {
164+
if (!_mqttClient->connect(_brokerAddress.c_str(), _brokerPort)) {
160165
return 0;
161166
}
162167
_mqttClient->subscribe(_stdinTopic);
@@ -295,15 +300,14 @@ void ArduinoIoTCloudClass::handleMessage(int length)
295300
}
296301
}
297302

298-
void ArduinoIoTCloudClass::connectionCheck() {
303+
void ArduinoIoTCloudClass::connectionCheck()
304+
{
299305
if(connection != NULL){
300306
connection->check();
301307

302308
if (connection->getStatus() != CONNECTION_STATE_CONNECTED) {
303309
if(iotStatus == IOT_STATUS_CLOUD_CONNECTED){
304310
setIoTConnectionState(IOT_STATUS_CLOUD_DISCONNECTED);
305-
}else{
306-
//setIoTConnectionState(IOT_STATUS_CLOUD_CONNECTING);
307311
}
308312
return;
309313
}
@@ -329,7 +333,6 @@ void ArduinoIoTCloudClass::connectionCheck() {
329333
case IOT_STATUS_CLOUD_RECONNECTING:
330334
int arduinoIoTReconnectionAttempt;
331335
arduinoIoTReconnectionAttempt = reconnect(*_net);
332-
*msgBuffer = 0;
333336
sprintf(msgBuffer, "ArduinoCloud.reconnect(): %d", arduinoIoTReconnectionAttempt);
334337
debugMessage(msgBuffer, 2);
335338
if (arduinoIoTReconnectionAttempt == 1) {
@@ -339,10 +342,8 @@ void ArduinoIoTCloudClass::connectionCheck() {
339342
}
340343
break;
341344
case IOT_STATUS_CLOUD_CONNECTING:
342-
343345
int arduinoIoTConnectionAttempt;
344346
arduinoIoTConnectionAttempt = connect();
345-
*msgBuffer = 0;
346347
sprintf(msgBuffer, "ArduinoCloud.connect(): %d", arduinoIoTConnectionAttempt);
347348
debugMessage(msgBuffer, 4);
348349
if (arduinoIoTConnectionAttempt == 1) {
@@ -354,7 +355,8 @@ void ArduinoIoTCloudClass::connectionCheck() {
354355
}
355356
}
356357

357-
void ArduinoIoTCloudClass::setIoTConnectionState(ArduinoIoTConnectionStatus _newState){
358+
void ArduinoIoTCloudClass::setIoTConnectionState(ArduinoIoTConnectionStatus _newState)
359+
{
358360
switch(_newState){
359361
case IOT_STATUS_CLOUD_ERROR:
360362
debugMessage("Arduino, we have a problem.", 0);
@@ -375,4 +377,16 @@ void ArduinoIoTCloudClass::setIoTConnectionState(ArduinoIoTConnectionStatus _new
375377
iotStatus = _newState;
376378
}
377379

380+
void ArduinoIoTCloudClass::printDebugInfo()
381+
{
382+
char msgBuffer[120];
383+
debugMessage("***** Arduino IoT Cloud - configuration info *****", 2);
384+
sprintf(msgBuffer, "Device ID: %s", getDeviceId().c_str());
385+
debugMessage(msgBuffer, 2);
386+
sprintf(msgBuffer, "Thing ID: %s", getThingId().c_str());
387+
debugMessage(msgBuffer, 2);
388+
sprintf(msgBuffer, "MQTT Broker: %s:%d", _brokerAddress.c_str(), _brokerPort);
389+
debugMessage(msgBuffer, 2);
390+
}
391+
378392
ArduinoIoTCloudClass ArduinoCloud;

src/ArduinoIoTCloud.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
#include "CloudSerial.h"
2727

28+
#define DEFAULT_BROKER_ADDRESS "mqtts-sa.iot.arduino.cc"
29+
#define DEFAULT_BROKER_PORT 8883
2830
typedef enum {
2931
READ = 0x01,
3032
WRITE = 0x02,
@@ -57,8 +59,8 @@ class ArduinoIoTCloudClass {
5759
ArduinoIoTCloudClass();
5860
~ArduinoIoTCloudClass();
5961

60-
int begin(ConnectionManager *connection = ArduinoIoTPreferredConnection, String brokerAddress = "mqtts-sa.iot.arduino.cc");
61-
int begin(Client& net, String brokerAddress = "mqtts-sa.iot.arduino.cc");
62+
int begin(ConnectionManager *connection = ArduinoIoTPreferredConnection, String brokerAddress = DEFAULT_BROKER_ADDRESS, uint16_t brokerPort = DEFAULT_BROKER_PORT);
63+
int begin(Client& net, String brokerAddress = DEFAULT_BROKER_ADDRESS, uint16_t brokerPort = DEFAULT_BROKER_PORT);
6264
// Class constant declaration
6365
static const int MQTT_TRANSMIT_BUFFER_SIZE = 256;
6466
static const int MAX_RETRIES = 5;
@@ -89,6 +91,8 @@ class ArduinoIoTCloudClass {
8991

9092
static unsigned long const DEFAULT_MIN_TIME_BETWEEN_UPDATES_MILLIS = 100; /* Data rate throttled to 10 Hz */
9193

94+
95+
9296
template<typename T, typename N=T>
9397
void addPropertyReal(T & property, String name, permissionType permission_type = READWRITE, long seconds = ON_CHANGE, void(*fn)(void) = NULL, N minDelta = N(0)) {
9498
Permission permission = Permission::ReadWrite;
@@ -110,6 +114,9 @@ class ArduinoIoTCloudClass {
110114
}
111115

112116
void connectionCheck();
117+
String getBrokerAddress(){ return _brokerAddress; }
118+
uint16_t getBrokerPort() { return _brokerPort; }
119+
void printDebugInfo();
113120

114121
protected:
115122
friend class CloudSerialClass;
@@ -131,6 +138,7 @@ class ArduinoIoTCloudClass {
131138
String _id,
132139
_thing_id,
133140
_brokerAddress;
141+
uint16_t _brokerPort;
134142
ArduinoCloudThing Thing;
135143
BearSSLClient* _bearSslClient;
136144
MqttClient* _mqttClient;

src/ConnectionManager.h

+5-4
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@
1818
#ifndef CONNECTION_MANAGER_H_INCLUDED
1919
#define CONNECTION_MANAGER_H_INCLUDED
2020

21-
#ifndef ARDUINO_CLOUD_DEBUG_LEVEL
2221
#define ARDUINO_CLOUD_DEBUG_LEVEL 2
23-
#endif
2422

2523
#include <Client.h>
2624
#include <Udp.h>
@@ -80,7 +78,10 @@ class ConnectionManager {
8078
#endif
8179

8280
static int debugMessageLevel = ARDUINO_CLOUD_DEBUG_LEVEL;
83-
inline void debugMessage(char *_msg, uint8_t _debugLevel, bool _timestamp = true, bool _newline = true) {
81+
inline void debugMessage(char *_msg, int _debugLevel, bool _timestamp = true, bool _newline = true) {
82+
if(_debugLevel < 0){
83+
return;
84+
}
8485
if (_debugLevel <= debugMessageLevel) {
8586
char prepend[20];
8687
sprintf(prepend, "\n[ %d ] ", millis());
@@ -95,7 +96,7 @@ inline void debugMessage(char *_msg, uint8_t _debugLevel, bool _timestamp = true
9596
}
9697
}
9798

98-
inline void setDebugMessageLevel(uint8_t _debugLevel){
99+
inline void setDebugMessageLevel(int _debugLevel){
99100
debugMessageLevel = _debugLevel;
100101
}
101102
#endif

src/WiFiConnectionManager.h

+1
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ void WiFiConnectionManager::check() {
156156
networkTime = getTime();
157157
debugMessage(".", 3, false, false);
158158
if(networkTime > lastValidTimestamp){
159+
debugMessage("", 3, false, true);
159160
lastValidTimestamp = networkTime;
160161
sprintf(msgBuffer, "Network Time: %u", networkTime);
161162
debugMessage(msgBuffer, 3);

0 commit comments

Comments
 (0)