Skip to content

[RFC] Implement OTA delay and allow overriding default transport #265

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
This sketch demonstrates how to exchange data between your board and the Arduino IoT Cloud.

* Connect a potentiometer (or other analog sensor) to A0.
* When the potentiometer (or sensor) value changes the data is sent to the Cloud.
* When you flip the switch in the Cloud dashboard the onboard LED lights gets turned ON or OFF.

IMPORTANT:
This sketch works with WiFi, GSM, NB and Lora enabled boards supported by Arduino IoT Cloud.
On a LoRa board, if it is configuered as a class A device (default and preferred option), values from Cloud dashboard are received
only after a value is sent to Cloud.

This sketch is compatible with:
- MKR 1000
- MKR WIFI 1010
- MKR GSM 1400
- MKR NB 1500
- MKR WAN 1300/1310
- Nano 33 IoT
- ESP 8266
*/

#include "arduino_secrets.h"
#include "thingProperties.h"

#if defined(ESP32)
static int const LED_BUILTIN = 2;
#endif

/*
// Can use it as soon as https://github.com/arduino-libraries/Arduino_ConnectionHandler/pull/63 gets merged

ConnectionHandler& get_default_connection_handler() {
char ssid[MAX_LEN];
char password[MAX_LEN];
retrieveCredentialsFromFile("/fs/credential.txt", ssid, password);
static WiFiConnectionHandlerDynamic ArduinoIoTPreferredConnection(ssid, password);
return ArduinoIoTPreferredConnection;
}
*/

bool always_deny() {
return false;
}

bool always_allow() {
return true;
}

static bool ask_user_via_serial_first_run = true;
bool ask_user_via_serial() {
if (ask_user_via_serial_first_run) {
Serial.println("Apply OTA? y / [n]");
ask_user_via_serial_first_run = false;
}
if (Serial.available()) {
char c = Serial.read();
if (c == 'y' || c == 'Y') {
return true;
}
}
return false;
}

void setup() {
/* Initialize serial and wait up to 5 seconds for port to open */
Serial.begin(9600);
for(unsigned long const serialBeginTime = millis(); !Serial && (millis() - serialBeginTime > 5000); ) { }

/* Configure LED pin as an output */
pinMode(LED_BUILTIN, OUTPUT);

/* This function takes care of connecting your sketch variables to the ArduinoIoTCloud object */
initProperties();

/* Initialize Arduino IoT Cloud library */
ArduinoCloud.begin(get_default_connection_handler());

ArduinoCloud.onOTARequestCb(always_deny);

setDebugMessageLevel(DBG_INFO);
ArduinoCloud.printDebugInfo();
}

void loop() {
ArduinoCloud.update();
potentiometer = analogRead(A0);
seconds = millis() / 1000;
}

/*
* 'onLedChange' is called when the "led" property of your Thing changes
*/
void onLedChange() {
Serial.print("LED set to ");
Serial.println(led);
digitalWrite(LED_BUILTIN, led);
}
34 changes: 34 additions & 0 deletions examples/ArduinoIoTCloud-Basic-dynamic/arduino_secrets.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <Arduino_ConnectionHandler.h>

/* MKR1000, MKR WiFi 1010 */
#if defined(BOARD_HAS_WIFI)
#define SECRET_SSID "YOUR_WIFI_NETWORK_NAME"
#define SECRET_PASS "YOUR_WIFI_PASSWORD"
#endif

/* ESP8266 */
#if defined(BOARD_ESP8266)
#define SECRET_DEVICE_KEY "my-device-password"
#endif

/* MKR GSM 1400 */
#if defined(BOARD_HAS_GSM)
#define SECRET_PIN ""
#define SECRET_APN ""
#define SECRET_LOGIN ""
#define SECRET_PASS ""
#endif

/* MKR WAN 1300/1310 */
#if defined(BOARD_HAS_LORA)
#define SECRET_APP_EUI ""
#define SECRET_APP_KEY ""
#endif

/* MKR NB 1500 */
#if defined(BOARD_HAS_NB)
#define SECRET_PIN ""
#define SECRET_APN ""
#define SECRET_LOGIN ""
#define SECRET_PASS ""
#endif
16 changes: 16 additions & 0 deletions examples/ArduinoIoTCloud-Basic-dynamic/default_connection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <ArduinoIoTCloud.h>
#include <Arduino_ConnectionHandler.h>
#include "arduino_secrets.h"

ConnectionHandler& __attribute__((weak)) get_default_connection_handler() {
#if defined(BOARD_HAS_WIFI)
static WiFiConnectionHandler ArduinoIoTPreferredConnection(SECRET_SSID, SECRET_PASS);
#elif defined(BOARD_HAS_GSM)
static GSMConnectionHandler ArduinoIoTPreferredConnection(SECRET_PIN, SECRET_APN, SECRET_LOGIN, SECRET_PASS);
#elif defined(BOARD_HAS_LORA)
static LoRaConnectionHandler ArduinoIoTPreferredConnection(SECRET_APP_EUI, SECRET_APP_KEY, _lora_band::EU868, _lora_class::CLASS_A);
#elif defined(BOARD_HAS_NB)
static NBConnectionHandler ArduinoIoTPreferredConnection(SECRET_PIN, SECRET_APN, SECRET_LOGIN, SECRET_PASS);
#endif
return ArduinoIoTPreferredConnection;
}
38 changes: 38 additions & 0 deletions examples/ArduinoIoTCloud-Basic-dynamic/thingProperties.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include <ArduinoIoTCloud.h>
#include <Arduino_ConnectionHandler.h>

#if defined(BOARD_HAS_WIFI)
#elif defined(BOARD_HAS_GSM)
#elif defined(BOARD_HAS_LORA)
#elif defined(BOARD_HAS_NB)
#else
#error "Arduino IoT Cloud currently only supports MKR1000, MKR WiFi 1010, MKR WAN 1300/1310, MKR NB 1500 and MKR GSM 1400"
#endif

#define THING_ID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
#define BOARD_ID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

void onLedChange();

bool led;
int potentiometer;
int seconds;

void initProperties() {
#if defined(BOARD_ESP8266)
ArduinoCloud.setBoardId(BOARD_ID);
ArduinoCloud.setSecretDeviceKey(SECRET_DEVICE_KEY);
#endif
ArduinoCloud.setThingId(THING_ID);
#if defined(BOARD_HAS_WIFI) || defined(BOARD_HAS_GSM) || defined(BOARD_HAS_NB)
ArduinoCloud.addProperty(led, Permission::Write).onUpdate(onLedChange);
ArduinoCloud.addProperty(potentiometer, Permission::Read).publishOnChange(10);
ArduinoCloud.addProperty(seconds, Permission::Read).publishOnChange(1);
#elif defined(BOARD_HAS_LORA)
ArduinoCloud.addProperty(led, 1, READWRITE, ON_CHANGE, onLedChange);
ArduinoCloud.addProperty(potentiometer, 2, READ, ON_CHANGE);
ArduinoCloud.addProperty(seconds, 3, READ, 5 * MINUTES);
#endif
}

ConnectionHandler& __attribute__((weak)) get_default_connection_handler();
18 changes: 10 additions & 8 deletions src/ArduinoIoTCloudTCP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,14 +511,16 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_Connected()

if (_ota_req)
{
/* Clear the error flag. */
_ota_error = static_cast<int>(OTAError::None);
/* Transmit the cleared error flag to the cloud. */
sendPropertiesToCloud();
/* Clear the request flag. */
_ota_req = false;
/* Call member function to handle OTA request. */
onOTARequest();
if (_automatic_ota || (_get_ota_confirmation != nullptr && _get_ota_confirmation())) {
/* Clear the error flag. */
_ota_error = static_cast<int>(OTAError::None);
/* Transmit the cleared error flag to the cloud. */
sendPropertiesToCloud();
/* Clear the request flag. */
_ota_req = false;
/* Call member function to handle OTA request. */
onOTARequest();
}
}
#endif /* OTA_ENABLED */

Expand Down
26 changes: 26 additions & 0 deletions src/ArduinoIoTCloudTCP.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ static uint16_t const DEFAULT_BROKER_PORT_SECURE_AUTH = 8883;
static char const DEFAULT_BROKER_ADDRESS_USER_PASS_AUTH[] = "mqtts-up.iot.arduino.cc";
static uint16_t const DEFAULT_BROKER_PORT_USER_PASS_AUTH = 8884;

typedef bool (*otaConfirmationStatus)(void);

/******************************************************************************
* CLASS DECLARATION
******************************************************************************/
Expand Down Expand Up @@ -80,6 +82,27 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
inline String getBrokerAddress() const { return _brokerAddress; }
inline uint16_t getBrokerPort () const { return _brokerPort; }

#if OTA_ENABLED

// The callback is triggered when the OTA is initiated
// Should return true when the OTA can be applied, false otherwise

/*
static first_run = true;
bool sample_ota_confirmation() {
if (first_run) {
HMI.show(confirmationModal)
first_run = false;
}
return HMI.getConfirmation();
}
*/

void onOTARequestCb(otaConfirmationStatus cb) {
_get_ota_confirmation = cb;
_automatic_ota = false;
}
#endif

private:
static const int MQTT_TRANSMIT_BUFFER_SIZE = 256;
Expand Down Expand Up @@ -130,6 +153,7 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
String _ota_img_sha256;
String _ota_url;
bool _ota_req;
bool _automatic_ota = true;
#endif /* OTA_ENABLED */

inline String getTopic_shadowout() { return ( getThingId().length() == 0) ? String("") : String("/a/t/" + getThingId() + "/shadow/o"); }
Expand All @@ -153,6 +177,8 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
#if OTA_ENABLED
void onOTARequest();
#endif

otaConfirmationStatus _get_ota_confirmation = {nullptr};
};

/******************************************************************************
Expand Down