Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 7bae6d2

Browse files
committedAug 20, 2024·
feat: NotecardConnectionHandler
1 parent 4419df1 commit 7bae6d2

14 files changed

+1513
-33
lines changed
 

‎.github/workflows/compile-examples.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ jobs:
3535
- name: MKRNB
3636
- name: MKRWAN
3737
- name: Arduino_Cellular
38+
- name: Blues Wireless Notecard
3839
ARDUINOCORE_MBED_STAGING_PATH: extras/ArduinoCore-mbed
3940
ARDUINOCORE_API_STAGING_PATH: extras/ArduinoCore-API
4041
SKETCHES_REPORTS_PATH: sketches-reports
@@ -135,7 +136,7 @@ jobs:
135136
# Install ESP8266 platform via Boards Manager
136137
- name: esp8266:esp8266
137138
source-url: https://arduino.esp8266.com/stable/package_esp8266com_index.json
138-
version: 2.5.0
139+
version: 3.1.2
139140
- board:
140141
platform-name: esp32:esp32
141142
platforms: |

‎README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,25 @@ Arduino Library for network connections management
66
[![Spell Check status](https://github.com/arduino-libraries/Arduino_ConnectionHandler/actions/workflows/spell-check.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_ConnectionHandler/actions/workflows/spell-check.yml)
77

88
Library for handling and managing network connections by providing keep-alive functionality and automatic reconnection in case of connection-loss. It supports the following boards:
9-
* **WiFi**: [`MKR 1000`](https://store.arduino.cc/arduino-mkr1000-wifi), [`MKR WiFi 1010`](https://store.arduino.cc/arduino-mkr-wifi-1010), [`Nano 33 IoT`](https://store.arduino.cc/arduino-nano-33-iot), [`Portenta H7`](https://store.arduino.cc/products/portenta-h7), [`Nano RP2040 Connect`](https://store.arduino.cc/products/arduino-nano-rp2040-connect), [`Nicla Vision`](https://store.arduino.cc/products/nicla-vision), [`OPTA WiFi`](https://store.arduino.cc/products/opta-wifi), [`GIGA R1 WiFi`](https://store.arduino.cc/products/giga-r1-wifi), [`Portenta C33`](https://store.arduino.cc/products/portenta-c33), [`UNO R4 WiFi`](https://store.arduino.cc/products/uno-r4-wifi), [`Nano ESP32`](https://store.arduino.cc/products/nano-esp32), [`ESP8266`](https://github.com/esp8266/Arduino/releases/tag/2.5.0), [`ESP32`](https://github.com/espressif/arduino-esp32)
9+
10+
* **Wi-Fi**: [`MKR 1000`](https://store.arduino.cc/arduino-mkr1000-wifi), [`MKR WiFi 1010`](https://store.arduino.cc/arduino-mkr-wifi-1010), [`Nano 33 IoT`](https://store.arduino.cc/arduino-nano-33-iot), [`Portenta H7`](https://store.arduino.cc/products/portenta-h7), [`Nano RP2040 Connect`](https://store.arduino.cc/products/arduino-nano-rp2040-connect), [`Nicla Vision`](https://store.arduino.cc/products/nicla-vision), [`OPTA WiFi`](https://store.arduino.cc/products/opta-wifi), [`GIGA R1 WiFi`](https://store.arduino.cc/products/giga-r1-wifi), [`Portenta C33`](https://store.arduino.cc/products/portenta-c33), [`UNO R4 WiFi`](https://store.arduino.cc/products/uno-r4-wifi), [`Nano ESP32`](https://store.arduino.cc/products/nano-esp32), [`ESP8266`](https://github.com/esp8266/Arduino/releases/tag/2.5.0), [`ESP32`](https://github.com/espressif/arduino-esp32)
1011
* **GSM**: [`MKR GSM 1400`](https://store.arduino.cc/arduino-mkr-gsm-1400-1415)
1112
* **5G**: [`MKR NB 1500`](https://store.arduino.cc/arduino-mkr-nb-1500-1413)
1213
* **LoRa**: [`MKR WAN 1300/1310`](https://store.arduino.cc/mkr-wan-1310)
1314
* **Ethernet**: [`Portenta H7`](https://store.arduino.cc/products/portenta-h7) + [`Vision Shield Ethernet`](https://store.arduino.cc/products/arduino-portenta-vision-shield-ethernet), [`Max Carrier`](https://store.arduino.cc/products/portenta-max-carrier), [`Breakout`](https://store.arduino.cc/products/arduino-portenta-breakout), [`Portenta Machine Control`](https://store.arduino.cc/products/arduino-portenta-machine-control), [`OPTA WiFi`](https://store.arduino.cc/products/opta-wifi), [`OPTA RS485`](https://store.arduino.cc/products/opta-rs485), [`OPTA Lite`](https://store.arduino.cc/products/opta-lite), [`Portenta C33`](https://store.arduino.cc/products/portenta-c33) + [`Vision Shield Ethernet`](https://store.arduino.cc/products/arduino-portenta-vision-shield-ethernet)
15+
* **Notecard**: [Provides Cellular/LoRa/Satellite/Wi-Fi to any modern board/architecture](https://shop.blues.com/collections/notecard)
1416

1517
### How-to-use
1618

1719
```C++
1820
#include <Arduino_ConnectionHandler.h>
1921
/* ... */
20-
#if defined(BOARD_HAS_ETHERNET)
22+
#if defined(BOARD_HAS_NOTECARD)
23+
NotecardConnectionHandler conMan("com.domain.you:product");
24+
#elif defined(BOARD_HAS_ETHERNET)
2125
EthernetConnectionHandler conMan;
2226
#elif defined(BOARD_HAS_WIFI)
23-
WiFiConnectionHandler conMan("SECRET_SSID", "SECRET_PASS");
27+
WiFiConnectionHandler conMan("SECRET_WIFI_SSID", "SECRET_WIFI_PASS");
2428
#elif defined(BOARD_HAS_GSM)
2529
GSMConnectionHandler conMan("SECRET_PIN", "SECRET_APN", "SECRET_GSM_LOGIN", "SECRET_GSM_PASS");
2630
#elif defined(BOARD_HAS_NB)
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/* SECRET_ fields are in `arduino_secrets.h` (included below)
2+
*
3+
* If using a Host + Notecard connected over I2C you'll need a
4+
* NotecardConnectionHandler object as follows:
5+
*
6+
* NotecardConnectionHandler conMan(NOTECARD_PRODUCT_UID);
7+
*
8+
* If using a Host + Notecard connected over Serial you'll need a
9+
* NotecardConnectionHandler object as follows:
10+
*
11+
* NotecardConnectionHandler conMan(NOTECARD_PRODUCT_UID, UART_INTERFACE);
12+
*/
13+
14+
#include <Notecard.h> // MUST include this first to enable Notecard support
15+
#include <ConnectionHandler.h>
16+
17+
#include "arduino_secrets.h"
18+
19+
/* Uncomment the following line to use this example in a manner that is more
20+
* compatible with LoRa.
21+
*/
22+
// #define USE_NOTE_LORA
23+
24+
#ifndef USE_NOTE_LORA
25+
#define CONN_TOGGLE_MS 60000
26+
#else
27+
#define CONN_TOGGLE_MS 300000
28+
#endif
29+
30+
/* The Notecard can provide connectivity to almost any board via ESLOV (I2C)
31+
* or UART. An empty string (or the default value provided below) will not
32+
* override the Notecard's existing configuration.
33+
* Learn more at: https://dev.blues.io */
34+
#define NOTECARD_PRODUCT_UID "com.domain.you:product"
35+
36+
/* Uncomment the following line to use the Notecard over UART */
37+
// #define UART_INTERFACE Serial1
38+
39+
#ifndef UART_INTERFACE
40+
NotecardConnectionHandler conMan(NOTECARD_PRODUCT_UID);
41+
#else
42+
NotecardConnectionHandler conMan(NOTECARD_PRODUCT_UID, UART_INTERFACE);
43+
#endif
44+
45+
bool attemptConnect = false;
46+
uint32_t lastConnToggleMs = 0;
47+
48+
void setup() {
49+
/* Initialize serial debug port and wait up to 5 seconds for port to open */
50+
Serial.begin(9600);
51+
for(unsigned long const serialBeginTime = millis(); !Serial && (millis() - serialBeginTime <= 5000); ) { }
52+
53+
/* Set the debug message level:
54+
* - DBG_ERROR: Only show error messages
55+
* - DBG_WARNING: Show warning and error messages
56+
* - DBG_INFO: Show info, warning, and error messages
57+
* - DBG_DEBUG: Show debug, info, warning, and error messages
58+
* - DBG_VERBOSE: Show all messages
59+
*/
60+
setDebugMessageLevel(DBG_INFO);
61+
62+
/* Add callbacks to the ConnectionHandler object to get notified of network
63+
* connection events. */
64+
conMan.addCallback(NetworkConnectionEvent::CONNECTED, onNetworkConnect);
65+
conMan.addCallback(NetworkConnectionEvent::DISCONNECTED, onNetworkDisconnect);
66+
conMan.addCallback(NetworkConnectionEvent::ERROR, onNetworkError);
67+
68+
/* First call to `check()` initializes the connection to the Notecard. While
69+
* not strictly necessary, it cleans up the logging from this application.
70+
*/
71+
conMan.check();
72+
73+
#ifndef USE_NOTE_LORA
74+
/* Set the Wi-Fi credentials for the Notecard */
75+
String ssid = SECRET_WIFI_SSID;
76+
if (ssid.length() > 0 && ssid != "NETWORK NAME") {
77+
conMan.setWiFiCredentials(SECRET_WIFI_SSID, SECRET_WIFI_PASS);
78+
}
79+
#else
80+
conMan.setNotehubPollingInterval(720); // poll twice per day
81+
#endif
82+
83+
/* Confirm Interface */
84+
Serial.print("Network Adapter Interface: ");
85+
if (NetworkAdapter::NOTECARD == conMan.getInterface()) {
86+
Serial.print("Notecard ");
87+
Serial.print(conMan.getNotecardUid());
88+
#ifndef UART_INTERFACE
89+
Serial.println(" (via I2C)");
90+
#else
91+
Serial.println(" (via UART)");
92+
#endif
93+
} else {
94+
Serial.println("ERROR: Unexpected Interface");
95+
while(1);
96+
}
97+
98+
/* Display the Arduino IoT Cloud Device ID */
99+
displayCachedDeviceId();
100+
}
101+
102+
void loop() {
103+
/* Toggle the connection every `CONN_TOGGLE_MS` milliseconds */
104+
if ((millis() - lastConnToggleMs) > CONN_TOGGLE_MS) {
105+
Serial.println("Toggling connection...");
106+
if (attemptConnect) {
107+
displayCachedDeviceId();
108+
conMan.connect();
109+
} else {
110+
// Flush any queued Notecard requests before disconnecting
111+
conMan.initiateNotehubSync(NotecardConnectionHandler::SyncType::Outbound);
112+
conMan.disconnect();
113+
}
114+
attemptConnect = !attemptConnect;
115+
lastConnToggleMs = millis();
116+
}
117+
118+
/* The following code keeps on running connection workflows on our
119+
* ConnectionHandler object, hence allowing reconnection in case of failure
120+
* and notification of connect/disconnect event if enabled (see
121+
* addConnectCallback/addDisconnectCallback) NOTE: any use of delay() within
122+
* the loop or methods called from it will delay the execution of .update(),
123+
* which might not guarantee the correct functioning of the ConnectionHandler
124+
* object.
125+
*/
126+
conMan.check();
127+
}
128+
129+
void displayCachedDeviceId() {
130+
Serial.print("Cached Arduino IoT Cloud Device ID: ");
131+
Serial.println(conMan.getDeviceId());
132+
}
133+
134+
void onNetworkConnect() {
135+
Serial.println(">>>> CONNECTED to network");
136+
}
137+
138+
void onNetworkDisconnect() {
139+
Serial.println(">>>> DISCONNECTED from network");
140+
}
141+
142+
void onNetworkError() {
143+
Serial.println(">>>> ERROR");
144+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
Notecard Connectivity
2+
=====================
3+
4+
The Notecard is a wireless, secure abstraction for device connectivity, that can
5+
be used to enable _ANY*_ device with I2C, or UART, to connect to the Arduino IoT
6+
Cloud via cellular, LoRa, satellite or Wi-Fi!
7+
8+
As a result, your existing device architecture can now have first class support
9+
in the Arduino IoT Cloud, by using a Notecard as a secure communication channel.
10+
11+
> \*_While any device with I2C/UART may use the Notecard, the Arduino IoT Cloud
12+
> library is not supported by the AVR toolchain. Therefore, devices based on the
13+
> AVR architecture cannot access the Arduino IoT Cloud via the Notecard._
14+
>
15+
> _However, any device (including AVR), may use the Notecard library to send data
16+
> to Notehub, then that data may be routed to any endpoint of your choosing. See the
17+
> [Notecard Routing Guide](https://dev.blues.io/guides-and-tutorials/routing-data-to-cloud)
18+
> for more information..._
19+
20+
Wireless Connectivity Options
21+
-----------------------------
22+
23+
- [Cellular](https://shop.blues.com/collections/notecard/products/notecard-cellular)
24+
- [Cellular + Wi-Fi](https://shop.blues.com/collections/notecard/products/notecard-cell-wifi)
25+
- [Wi-Fi](https://shop.blues.com/collections/notecard/products/wifi-notecard)
26+
- [LoRa](https://shop.blues.com/collections/notecard/products/notecard-lora)
27+
- [Satellite](https://shop.blues.com/products/starnote)
28+
29+
How it Works
30+
------------
31+
32+
**Architecture Diagram:**
33+
34+
```
35+
-------- ------------ ----------- -----------
36+
| | | | | | | |
37+
| Host | | | Secure | | | Arduino |
38+
| MCU |---<I2C/UART>---| Notecard | ( ( Wireless ) ) | Notehub |---<TLS>---| IoT |
39+
| | | | Protocol | | | Cloud |
40+
|______| |__________| |_________| |_________|
41+
```
42+
43+
Getting Started
44+
---------------
45+
46+
### Setup a Notehub Account
47+
48+
Using the Notecard only requires a couple of easy steps:
49+
50+
1. [Purchase a Notecard](https://shop.blues.com/collections/notecard) (and
51+
[Notecarrier](https://shop.blues.com/collections/notecarrier)) that fits the
52+
needs of your device.
53+
> _**NOTE:** We recommend starting with our [Dev Kit](https://shop.blues.com/products/blues-global-starter-kit)
54+
> if you are unsure._
55+
1. [Setup a Notehub account](https://dev.blues.io/quickstart/notecard-quickstart/notecard-and-notecarrier-f/#set-up-notehub).
56+
> _**NOTE:** Notehub accounts are free (no credit card required)._
57+
1. [Create a project on your Notehub account](https://dev.blues.io/quickstart/notecard-quickstart/notecard-and-notecarrier-f/#create-a-notehub-project).
58+
1. In `ConnectionHandlerDemo-Notecard`, replace "com.domain.you:product" (from
59+
`NOTECARD_PRODUCT_UID`) with the ProductUID of your new Notehub project.
60+
61+
### Power-up the Device
62+
63+
1. [Connect the Notecard to your Host MCU](https://dev.blues.io/quickstart/notecard-quickstart/notecard-and-notecarrier-f/#connect-your-notecard-and-notecarrier)
64+
1. Flash the `ConnectionHanderDemo-Notecard` example sketch to your device. You
65+
should see the device reporting itself as online in your [Notehub Project](https://notehub.io).
66+
67+
### More Information
68+
69+
For more information about the Notecard and Notehub in general, please see our
70+
[Quickstart Guide](https://dev.blues.io/quickstart/) for a general overview of
71+
how the Notecard and Notehub are designed to work.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/* If provided, the Wi-Fi Credentials will be passed along to the Notecard. If
2+
* the Notecard supports Wi-Fi, it will attempt to connect to the network using
3+
* these credentials, if not, the Notecard will safely ignore these values. */
4+
const char SECRET_WIFI_SSID[] = "NETWORK NAME";
5+
const char SECRET_WIFI_PASS[] = "NETWORK PASSWORD";

‎examples/ConnectionHandlerDemo/ConnectionHandlerDemo.ino

Lines changed: 71 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
/* SECRET_ fields are in arduino_secrets.h included above
2-
* if using a WiFi board (Arduino MKR1000, MKR WiFi 1010, Nano 33 IoT, UNO
1+
/* SECRET_ fields are in `arduino_secrets.h` (included below)
2+
*
3+
* If using a WiFi board (Arduino MKR1000, MKR WiFi 1010, Nano 33 IoT, UNO
34
* WiFi Rev 2 or ESP8266/32), create a WiFiConnectionHandler object by adding
4-
* Network Name (SECRET_SSID) and password (SECRET_PASS) in the arduino_secrets.h
5-
* file (or Secrets tab in Create Web Editor).
5+
* Network Name (SECRET_WIFI_SSID) and password (SECRET_WIFI_PASS) in the
6+
* arduino_secrets.h file (or Secrets tab in Create Web Editor).
67
*
7-
* WiFiConnectionHandler conMan(SECRET_SSID, SECRET_PASS);
8+
* WiFiConnectionHandler conMan(SECRET_WIFI_SSID, SECRET_WIFI_PASS);
89
*
910
* If using a MKR GSM 1400 or other GSM boards supporting the same API you'll
1011
* need a GSMConnectionHandler object as follows
@@ -27,14 +28,21 @@
2728
*
2829
*/
2930

31+
#include <Arduino_ConnectionHandler.h>
32+
3033
#include "arduino_secrets.h"
3134

32-
#include <Arduino_ConnectionHandler.h>
35+
#define CONN_TOGGLE_MS 60000
36+
37+
#if !(defined(BOARD_HAS_WIFI) || defined(BOARD_HAS_GSM) || defined(BOARD_HAS_LORA) || \
38+
defined(BOARD_HAS_NB) || defined(BOARD_HAS_ETHERNET) || defined(BOARD_HAS_CATM1_NBIOT))
39+
#error "Please check Arduino Connection Handler supported boards list: https://github.com/arduino-libraries/Arduino_ConnectionHandler/blob/master/README.md"
40+
#endif
3341

3442
#if defined(BOARD_HAS_ETHERNET)
3543
EthernetConnectionHandler conMan(SECRET_IP, SECRET_DNS, SECRET_GATEWAY, SECRET_NETMASK);
3644
#elif defined(BOARD_HAS_WIFI)
37-
WiFiConnectionHandler conMan(SECRET_SSID, SECRET_PASS);
45+
WiFiConnectionHandler conMan(SECRET_WIFI_SSID, SECRET_WIFI_PASS);
3846
#elif defined(BOARD_HAS_GSM)
3947
GSMConnectionHandler conMan(SECRET_PIN, SECRET_APN, SECRET_GSM_USER, SECRET_GSM_PASS);
4048
#elif defined(BOARD_HAS_NB)
@@ -47,19 +55,73 @@ CatM1ConnectionHandler conMan(SECRET_PIN, SECRET_APN, SECRET_GSM_USER, SECRET_GS
4755
CellularConnectionHandler conMan(SECRET_PIN, SECRET_APN, SECRET_GSM_USER, SECRET_GSM_PASS);
4856
#endif
4957

58+
bool attemptConnect = false;
59+
uint32_t lastConnToggleMs = 0;
60+
5061
void setup() {
62+
/* Initialize serial debug port and wait up to 5 seconds for port to open */
5163
Serial.begin(9600);
52-
/* Give a few seconds for the Serial connection to be available */
53-
delay(4000);
64+
for(unsigned long const serialBeginTime = millis(); !Serial && (millis() - serialBeginTime <= 5000); ) { }
65+
5466
#ifndef __AVR__
67+
/* Set the debug message level:
68+
* - DBG_ERROR: Only show error messages
69+
* - DBG_WARNING: Show warning and error messages
70+
* - DBG_INFO: Show info, warning, and error messages
71+
* - DBG_DEBUG: Show debug, info, warning, and error messages
72+
* - DBG_VERBOSE: Show all messages
73+
*/
5574
setDebugMessageLevel(DBG_INFO);
5675
#endif
76+
77+
/* Add callbacks to the ConnectionHandler object to get notified of network
78+
* connection events. */
5779
conMan.addCallback(NetworkConnectionEvent::CONNECTED, onNetworkConnect);
5880
conMan.addCallback(NetworkConnectionEvent::DISCONNECTED, onNetworkDisconnect);
5981
conMan.addCallback(NetworkConnectionEvent::ERROR, onNetworkError);
82+
83+
Serial.print("Network Adapter Interface: ");
84+
switch (conMan.getInterface()) {
85+
case NetworkAdapter::WIFI:
86+
Serial.println("Wi-Fi");
87+
break;
88+
case NetworkAdapter::ETHERNET:
89+
Serial.println("Ethernet");
90+
break;
91+
case NetworkAdapter::NB:
92+
Serial.println("Narrowband");
93+
break;
94+
case NetworkAdapter::GSM:
95+
Serial.println("GSM");
96+
break;
97+
case NetworkAdapter::LORA:
98+
Serial.println("LoRa");
99+
break;
100+
case NetworkAdapter::CATM1:
101+
Serial.println("Category M1");
102+
break;
103+
case NetworkAdapter::CELL:
104+
Serial.println("Cellular");
105+
break;
106+
default:
107+
Serial.println("Unknown");
108+
break;
109+
}
60110
}
61111

62112
void loop() {
113+
/* Toggle the connection every `CONN_TOGGLE_MS` milliseconds */
114+
if ((millis() - lastConnToggleMs) > CONN_TOGGLE_MS) {
115+
Serial.println("Toggling connection...");
116+
if (attemptConnect) {
117+
conMan.connect();
118+
} else {
119+
conMan.disconnect();
120+
}
121+
attemptConnect = !attemptConnect;
122+
lastConnToggleMs = millis();
123+
}
124+
63125
/* The following code keeps on running connection workflows on our
64126
* ConnectionHandler object, hence allowing reconnection in case of failure
65127
* and notification of connect/disconnect event if enabled (see
@@ -68,7 +130,6 @@ void loop() {
68130
* which might not guarantee the correct functioning of the ConnectionHandler
69131
* object.
70132
*/
71-
72133
conMan.check();
73134
}
74135

‎examples/ConnectionHandlerDemo/arduino_secrets.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Required for WiFiConnectionHandler
2-
const char SECRET_SSID[] = "NETWORK NAME";
3-
const char SECRET_PASS[] = "NETWORK PASSWORD";
2+
const char SECRET_WIFI_SSID[] = "NETWORK NAME";
3+
const char SECRET_WIFI_PASS[] = "NETWORK PASSWORD";
44

55
// Required for GSMConnectionHandler
6-
const char SECRET_APN[] = "MOBILE PROVIDER APN ADDRESS";
7-
const char SECRET_PIN[] = "0000"; // Required for NBConnectionHandler
8-
const char SECRET_GSM_USER[] = "GSM USERNAME";
9-
const char SECRET_GSM_PASS[] = "GSM PASSWORD";
6+
const char SECRET_APN[] = "MOBILE PROVIDER APN ADDRESS";
7+
const char SECRET_PIN[] = "0000"; // Required for NBConnectionHandler
8+
const char SECRET_GSM_USER[] = "GSM USERNAME";
9+
const char SECRET_GSM_PASS[] = "GSM PASSWORD";
1010

1111
// Required for LoRaConnectionHandler
1212
const char SECRET_APP_EUI[] = "APP_EUI";

‎keywords.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,17 @@ GSMConnectionHandler KEYWORD1
1111
NBConnectionHandler KEYWORD1
1212
LoRaConnectionHandler KEYWORD1
1313
EthernetConnectionHandler KEYWORD1
14-
CatM1ConnectionHandler KEYWORD1
14+
CatM1ConnectionHandler KEYWORD1
15+
NotecardConnectionHandler KEYWORD1
1516

1617
####################################################
1718
# Methods and Functions (KEYWORD2)
1819
####################################################
1920

2021
ConnectionHandler KEYWORD2
22+
available KEYWORD2
23+
read KEYWORD2
24+
write KEYWORD2
2125
check KEYWORD2
2226
connect KEYWORD2
2327
disconnect KEYWORD2
@@ -26,6 +30,10 @@ getTime KEYWORD2
2630
getClient KEYWORD2
2731
getUDP KEYWORD2
2832

33+
# NotecardConnectionHandler.h
34+
initiateNotehubSync KEYWORD2
35+
setWiFiCredentials KEYWORD2
36+
2937
####################################################
3038
# Constants (LITERAL1)
3139
####################################################

‎library.properties

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name=Arduino_ConnectionHandler
22
version=0.9.0
33
author=Ubi de Feo, Cristian Maglie, Andrea Catozzi, Alexander Entinger et al.
44
maintainer=Arduino <info@arduino.cc>
5-
sentence=Arduino Library for network connection management (WiFi, GSM, NB, [Ethernet])
5+
sentence=Arduino Library for network connection management (WiFi, GSM, NB, [Ethernet], Notecard)
66
paragraph=Originally part of ArduinoIoTCloud
77
category=Communication
88
url=https://github.com/arduino-libraries/Arduino_ConnectionHandler
9-
architectures=samd,esp32,esp8266,mbed,megaavr,mbed_nano,mbed_portenta,mbed_nicla,mbed_opta,mbed_giga,renesas_portenta,renesas_uno,mbed_edge
10-
depends=Arduino_DebugUtils, WiFi101, WiFiNINA, MKRGSM, MKRNB, MKRWAN
9+
architectures=samd,esp32,esp8266,mbed,megaavr,mbed_nano,mbed_portenta,mbed_nicla,mbed_opta,mbed_giga,renesas_portenta,renesas_uno,mbed_edge,stm32
10+
depends=Arduino_DebugUtils, WiFi101, WiFiNINA, MKRGSM, MKRNB, MKRWAN, Blues Wireless Notecard (>=1.6.2)

‎src/Arduino_ConnectionHandler.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
#include <Arduino.h>
3030
#include "ConnectionHandlerDefinitions.h"
3131

32+
#if defined(BOARD_HAS_NOTECARD)
33+
#include "NotecardConnectionHandler.h"
34+
#else
35+
3236
#if defined(BOARD_HAS_WIFI)
3337
#include "WiFiConnectionHandler.h"
3438
#endif
@@ -57,4 +61,6 @@
5761
#include "CellularConnectionHandler.h"
5862
#endif
5963

64+
#endif // BOARD_HAS_NOTECARD
65+
6066
#endif /* CONNECTION_HANDLER_H_ */

‎src/ConnectionHandlerDefinitions.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,16 @@
2121
INCLUDES
2222
******************************************************************************/
2323

24+
#if defined __has_include
25+
#if __has_include (<Notecard.h>)
26+
#define BOARD_HAS_NOTECARD
27+
#endif
28+
#endif
29+
2430
#include <Arduino.h>
2531

32+
#ifndef BOARD_HAS_NOTECARD
33+
2634
#ifdef ARDUINO_SAMD_MKR1000
2735
#define BOARD_HAS_WIFI
2836
#define NETWORK_HARDWARE_ERROR WL_NO_SHIELD
@@ -136,6 +144,8 @@
136144
#define NETWORK_HARDWARE_ERROR
137145
#endif
138146

147+
#endif // BOARD_HAS_NOTECARD
148+
139149
/******************************************************************************
140150
TYPEDEFS
141151
******************************************************************************/
@@ -163,7 +173,8 @@ enum class NetworkAdapter {
163173
GSM,
164174
LORA,
165175
CATM1,
166-
CELL
176+
CELL,
177+
NOTECARD
167178
};
168179

169180
/******************************************************************************
@@ -173,7 +184,7 @@ enum class NetworkAdapter {
173184
static unsigned int const CHECK_INTERVAL_TABLE[] =
174185
{
175186
/* INIT */ 100,
176-
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
187+
#if defined(BOARD_HAS_NOTECARD) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
177188
/* CONNECTING */ 4000,
178189
#else
179190
/* CONNECTING */ 500,

‎src/ConnectionHandlerInterface.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,17 @@ class ConnectionHandler {
4848

4949
NetworkConnectionState check();
5050

51-
#if defined(BOARD_HAS_WIFI) || defined(BOARD_HAS_GSM) || defined(BOARD_HAS_NB) || defined(BOARD_HAS_ETHERNET) || defined(BOARD_HAS_CATM1_NBIOT)
51+
#if not defined(BOARD_HAS_LORA)
5252
virtual unsigned long getTime() = 0;
53-
virtual Client &getClient() = 0;
54-
virtual UDP &getUDP() = 0;
5553
#endif
5654

57-
#if defined(BOARD_HAS_LORA)
58-
virtual int write(const uint8_t *buf, size_t size) = 0;
59-
virtual int read() = 0;
55+
#if defined(BOARD_HAS_NOTECARD) || defined(BOARD_HAS_LORA)
6056
virtual bool available() = 0;
57+
virtual int read() = 0;
58+
virtual int write(const uint8_t *buf, size_t size) = 0;
59+
#else
60+
virtual Client &getClient() = 0;
61+
virtual UDP &getUDP() = 0;
6162
#endif
6263

6364
NetworkConnectionState getStatus() __attribute__((deprecated)) {
@@ -87,7 +88,6 @@ class ConnectionHandler {
8788
virtual NetworkConnectionState update_handleDisconnecting() = 0;
8889
virtual NetworkConnectionState update_handleDisconnected () = 0;
8990

90-
9191
private:
9292

9393
unsigned long _lastConnectionTickTime;

‎src/NotecardConnectionHandler.cpp

Lines changed: 828 additions & 0 deletions
Large diffs are not rendered by default.

‎src/NotecardConnectionHandler.h

Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
1+
/*
2+
This file is part of the ArduinoIoTCloud library.
3+
4+
Copyright 2024 Blues (http://www.blues.com/)
5+
6+
This Source Code Form is subject to the terms of the Mozilla Public
7+
License, v. 2.0. If a copy of the MPL was not distributed with this
8+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
11+
#ifndef ARDUINO_NOTECARD_CONNECTION_HANDLER_H_
12+
#define ARDUINO_NOTECARD_CONNECTION_HANDLER_H_
13+
14+
/******************************************************************************
15+
INCLUDE
16+
******************************************************************************/
17+
18+
#include <stdint.h>
19+
20+
#include <Arduino.h>
21+
#include <Notecard.h>
22+
#include <Wire.h>
23+
24+
#include "ConnectionHandlerInterface.h"
25+
26+
/******************************************************************************
27+
DEFINES
28+
******************************************************************************/
29+
30+
#define NOTECARD_CONNECTION_HANDLER_VERSION_MAJOR 1
31+
#define NOTECARD_CONNECTION_HANDLER_VERSION_MINOR 0
32+
#define NOTECARD_CONNECTION_HANDLER_VERSION_PATCH 0
33+
34+
#define NOTECARD_CONNECTION_HANDLER_VERSION NOTE_C_STRINGIZE(NOTECARD_CONNECTION_HANDLER_VERSION_MAJOR) "." NOTE_C_STRINGIZE(NOTECARD_CONNECTION_HANDLER_VERSION_MINOR) "." NOTE_C_STRINGIZE(NOTECARD_CONNECTION_HANDLER_VERSION_PATCH)
35+
36+
/******************************************************************************
37+
CLASS DECLARATION
38+
******************************************************************************/
39+
40+
/**
41+
* @brief The NotecardConnectionHandler class
42+
*
43+
* The NotecardConnectionHandler class is a concrete implementation of the
44+
* ConnectionHandler interface that provides connectivity to the Arduino IoT
45+
* Cloud using a Notecard.
46+
*/
47+
class NotecardConnectionHandler final : public ConnectionHandler
48+
{
49+
public:
50+
/**
51+
* @brief The manner in which the Notecard is synchronized with Notehub
52+
*
53+
* The SyncType enum defines the valid types of synchronization operations
54+
* that can be performed by the NotecardConnectionHandler class.
55+
*
56+
* @par
57+
* - Full - synchronize both the inbound and outbound queues.
58+
* - Inbound - synchronize only the inbound queues.
59+
* - Outbound - synchronize only the outbound queues.
60+
*/
61+
enum class SyncType : uint8_t {
62+
Full,
63+
Inbound,
64+
Outbound,
65+
};
66+
67+
/**
68+
* @brief The type of topic to be used for R/W operations
69+
*
70+
* The Notecard uses topics to identify the target of a read or write
71+
* operation. The TopicType enum defines the valid types of topics.
72+
*
73+
* @par
74+
* - Command - used to interact with the Arduino IoT Cloud.
75+
* - Thing - used to send application data to the Arduino IoT Cloud.
76+
*/
77+
enum class TopicType : uint8_t {
78+
Invalid = 0,
79+
Command,
80+
Thing,
81+
};
82+
83+
/**
84+
* @brief The error codes for communicating with the Notecard
85+
*
86+
* The NotecardCommunicationError enum defines the error codes that can be
87+
* returned by the NotecardConnectionHandler class.
88+
*
89+
* @par
90+
* - NOTECARD_ERROR_NONE - No error occurred.
91+
* - NOTECARD_ERROR_NO_DATA_AVAILABLE - No data is available.
92+
* - NOTECARD_ERROR_GENERIC - A generic error occurred.
93+
* - HOST_ERROR_OUT_OF_MEMORY - The host is out of memory.
94+
*/
95+
typedef enum {
96+
NOTECARD_ERROR_NONE = 0,
97+
NOTECARD_ERROR_NO_DATA_AVAILABLE = -1,
98+
NOTECARD_ERROR_GENERIC = -2,
99+
HOST_ERROR_OUT_OF_MEMORY = -3,
100+
} NotecardCommunicationError;
101+
102+
/**
103+
* @brief The default timeout for the Notecard to connect to Notehub
104+
*/
105+
static const uint32_t NOTEHUB_CONN_TIMEOUT_MS = 185000;
106+
107+
/**
108+
* @brief The I2C constructor for the Notecard
109+
*
110+
* @param project_uid[in] The project UID of the related Notehub account
111+
* @param i2c_address[in] The I2C address of the Notecard
112+
* @param i2c_max[in] The maximum I2C transaction size (MTU)
113+
* @param wire[in] The I2C bus to use
114+
* @param keep_alive[in] Keep the connection alive if connection to Notehub drops
115+
*/
116+
NotecardConnectionHandler(
117+
const String & project_uid,
118+
uint32_t i2c_address = NOTE_I2C_ADDR_DEFAULT,
119+
uint32_t i2c_max = NOTE_I2C_MAX_DEFAULT,
120+
TwoWire & wire = Wire,
121+
bool keep_alive = true
122+
);
123+
124+
/**
125+
* @brief The UART constructor for the Notecard
126+
*
127+
* @param project_uid[in] The project UID of the related Notehub account
128+
* @param serial[in] The serial port to use
129+
* @param baud[in] The baud rate of the serial port
130+
* @param keep_alive[in] Keep the connection alive if connection to Notehub drops
131+
*/
132+
NotecardConnectionHandler(
133+
const String & project_uid,
134+
HardwareSerial & serial,
135+
uint32_t baud = 9600,
136+
bool keep_alive = true
137+
);
138+
139+
/**
140+
* @brief Disable hardware interrupts
141+
*
142+
* When hardware interrupts are disabled, the `NotecardConnectionHandler`
143+
* must be polled for incoming data. This is necessary when the host
144+
* microcontroller is unable to use the ATTN pin of the Notecard.
145+
*/
146+
inline void disableHardwareInterrupts (void) {
147+
_en_hw_int = false;
148+
}
149+
150+
/**
151+
* @brief Enable hardware interrupts
152+
*
153+
* Hardware interrupts allow the `NotecardConnectionHandler` to leverage the
154+
* ATTN pin of the Notecard. This improves the responsiveness of the
155+
* `NotecardConnectionHandler` by eliminating the need for the host
156+
* microcontroller to poll the Notecard for incoming data.
157+
*/
158+
inline void enableHardwareInterrupts (void) {
159+
_en_hw_int = true;
160+
}
161+
162+
/**
163+
* @brief Get the Arduino IoT Cloud Device ID
164+
*
165+
* The Arduino IoT Cloud Device ID is set as the serial number of the
166+
* Notecard when the device is provisioned in Notehub. The serial number is
167+
* updated on each sync between the Notecard and Notehub and cached by the
168+
* Notecard. As a result, this value can lag behind the actual value of the
169+
* Arduino IoT Cloud Device ID used by the Notehub. However, this value is
170+
* typically unchanged during the life of the Notecard, so this is rarely,
171+
* if ever, an issue.
172+
*
173+
* @return The Arduino IoT Cloud Device ID
174+
*/
175+
inline const String & getDeviceId (void) {
176+
check(); // Ensure the connection to the Notecard is initialized
177+
return _device_id;
178+
}
179+
180+
/**
181+
* @brief Get the Notecard object
182+
*
183+
* The Notecard object is used to interact with the Notecard. This object
184+
* provides methods to read and write data to the Notecard, as well as
185+
* methods to configure the Notecard.
186+
*
187+
* @return The Notecard object
188+
*/
189+
inline const Notecard & getNotecard (void) {
190+
return _notecard;
191+
}
192+
193+
/**
194+
* @brief Get the Notecard Device ID
195+
*
196+
* The Notecard Device ID is the unique identifier of the Notecard. This
197+
* value is set at time of manufacture, and is used to identify the Notecard
198+
* in Notehub.
199+
*
200+
* @return The Notecard Device ID
201+
*/
202+
inline const String & getNotecardUid (void) {
203+
check(); // Ensure the connection to the Notecard is initialized
204+
return _notecard_uid;
205+
}
206+
207+
/**
208+
* @brief Get the topic type of the most recent R/W operations
209+
*
210+
* @return The current topic type
211+
*
212+
* @see TopicType
213+
*/
214+
TopicType getTopicType (void) const {
215+
return _topic_type;
216+
}
217+
218+
/**
219+
* @brief Initiate a synchronization operation with Notehub
220+
*
221+
* The Notecard maintains two queues: an inbound queue and an outbound
222+
* queue. The inbound queue is used to receive data from Notehub, while the
223+
* outbound queue is used to send data to Notehub. This method initiates a
224+
* synchronization operation between the Notecard and Notehub.
225+
*
226+
* As the name implies, this method is asynchronous and will only initiate
227+
* the synchronization operation. The actual synchronization operation will
228+
* be performed by the Notecard in the background.
229+
*
230+
* @param type[in] The type of synchronization operation to perform
231+
* @par
232+
* - SyncType::Full - synchronize both the inbound and outbound queues (default)
233+
* - SyncType::Inbound - synchronize only the inbound queues.
234+
* - SyncType::Outbound - synchronize only the outbound queues.
235+
*
236+
* @return 0 if successful, otherwise an error code
237+
*
238+
* @see SyncType
239+
* @see NotecardCommunicationError
240+
*/
241+
int initiateNotehubSync (SyncType type = SyncType::Full) const;
242+
243+
/**
244+
* @brief Set the inbound polling interval (in minutes)
245+
*
246+
* A cellular Notecard will receive inbound traffic from the Arduino IoT
247+
* Cloud in real-time. As such, the polling interval is used as a fail-safe
248+
* to ensure the Notecard is guaranteed to receive inbound traffic at the
249+
* interval specified by this method.
250+
*
251+
* Alternatively, a LoRa (or Satellite) Notecard does not maintain a
252+
* continuous connection, and therefore must rely on the polling interval to
253+
* establish the maximum acceptable delay before receiving any unsolicited,
254+
* inbound traffic from the Arduino IoT Cloud. The polling interval must
255+
* balance the needs of the application against the regulatory limitations
256+
* of LoRa (or bandwidth limitations and cost of Satellite).
257+
*
258+
* LoRaWAN Fair Use Policy:
259+
* https://www.thethingsnetwork.org/forum/t/fair-use-policy-explained/1300
260+
*
261+
* @param interval_min[in] The inbound polling interval (in minutes)
262+
*
263+
* @note Set the interval to 0 to disable inbound polling.
264+
*/
265+
inline void setNotehubPollingInterval (int32_t interval_min) {
266+
_inbound_polling_interval_min = (interval_min ? interval_min : -1);
267+
}
268+
269+
/**
270+
* @brief Set the topic type for R/W operations
271+
*
272+
* @param topic[in] The topic type
273+
* @par
274+
* - TopicType::Command - used to interact with the Arduino IoT Cloud.
275+
* - TopicType::Thing - used to send application data to the Arduino IoT Cloud.
276+
*
277+
* @see TopicType
278+
*/
279+
void setTopicType (TopicType topic) {
280+
_topic_type = topic;
281+
}
282+
283+
/**
284+
* @brief Set the WiFi credentials to be used by the Notecard
285+
*
286+
* @param ssid[in] The SSID of the WiFi network
287+
* @param pass[in] The password of the WiFi network
288+
*
289+
* @return 0 if successful, otherwise an error code
290+
*
291+
* @note This method is only applicable when using a Wi-Fi capable Notecard,
292+
* and is unnecessary when using a Notecard with cellular connectivity.
293+
* If the Notecard is not Wi-Fi capable, this method will be a no-op.
294+
*
295+
* @see NotecardCommunicationError
296+
*/
297+
int setWiFiCredentials (const String & ssid, const String & pass);
298+
299+
// ConnectionHandler interface
300+
virtual bool available() override;
301+
virtual unsigned long getTime() override;
302+
virtual int read() override;
303+
virtual int write(const uint8_t *buf, size_t size) override;
304+
305+
protected:
306+
307+
virtual NetworkConnectionState update_handleInit () override;
308+
virtual NetworkConnectionState update_handleConnecting () override;
309+
virtual NetworkConnectionState update_handleConnected () override;
310+
virtual NetworkConnectionState update_handleDisconnecting() override;
311+
virtual NetworkConnectionState update_handleDisconnected () override;
312+
313+
private:
314+
315+
// Private members
316+
Notecard _notecard;
317+
String _device_id;
318+
String _notecard_uid;
319+
String _project_uid;
320+
HardwareSerial * _serial;
321+
TwoWire * _wire;
322+
uint8_t * _inbound_buffer;
323+
uint32_t _conn_start_ms;
324+
uint32_t _i2c_address;
325+
uint32_t _i2c_max;
326+
uint32_t _inbound_buffer_index;
327+
uint32_t _inbound_buffer_size;
328+
int32_t _inbound_polling_interval_min;
329+
uint32_t _uart_baud;
330+
bool _en_hw_int;
331+
TopicType _topic_type;
332+
333+
// Private methods
334+
bool armInterrupt (void) const;
335+
bool configureConnection (bool connect) const;
336+
uint_fast8_t connected (void) const;
337+
J * getNote (bool pop = false) const;
338+
bool updateUidCache (void);
339+
};
340+
341+
#endif /* ARDUINO_NOTECARD_CONNECTION_HANDLER_H_ */

0 commit comments

Comments
 (0)
Please sign in to comment.