Cloud
Description
The Cloud library connects an OpenIndus module to the OpenIndus cloud platform. It exposes your application data as cloud variables, each backed by an MQTT topic, and takes care of device provisioning, secure transport, over-the-air firmware updates and reconnection automatically.
The communication uses MQTT over WebSocket (TLS). A dedicated background task handles the
whole lifecycle, so your application code stays minimal: declare the variables, call
Cloud::begin(), and read/write the values in your loop(). Nothing blocks.
Note
The cloud requires an active internet connection. On a OI-Core module this is
typically provided by the cellular modem or by Ethernet. Make sure the
network is up before (or shortly after) calling begin().
begin() can be called without argument, in which case the default host
oicloud.openindus.com is used; pass a host explicitly to target another instance.
Variables
A cloud variable has:
a name, which is also the leaf of its MQTT topic,
a type:
bool,int,floatorstd::string(BoolVariable,IntVariable,FloatVariable,StringVariable),an update method (
UpdateMethod):SYNCHRONOUS— published once everyrefreshIntervalmilliseconds,ASYNCHRONOUS— published when the value changes, rate-limited to at most once everyrefreshIntervalms and at least once everymaxRefreshIntervalms. AmaxRefreshIntervalof0disables the periodic heartbeat, so the variable is published only when its value actually changes,
an update type / direction (
UpdateType):PUBLISH— the module publishes the topic,SUBSCRIBE— the module subscribes to the topic (useonReceive()to get a callback),BOTH— the module both publishes and subscribes.
Every publisher variable is re-announced on each new MQTT session, so the cloud always sees a fresh value after a reconnection.
Default variables
The following variables are created and managed automatically to provide base functionality.
They live under the def topic type (see MQTT topics) and, when they publish, they are all
ASYNCHRONOUS with no heartbeat: they are emitted only when their value changes.
Name |
Type |
Direction |
Function |
|---|---|---|---|
|
string |
subscribe (+ progress published on the same topic) |
Firmware update channel, see Firmware update (OTA) below |
|
string |
publish |
Journalises info/errors from the module (see |
|
string |
publish |
Published once on connection: the |
|
string |
publish |
Published once on connection: a JSON array describing the local board and, on a master,
every module discovered on the rail. Each entry holds |
Provisioning
The preferred usage only specifies the platform credentials; the library obtains a device
uuid and token on its own and stores them in NVS. On the first boot (or when the stored
platform UUID no longer matches), the module:
registers itself against the platform (
POST /api/v1/platform/{platform_uuid}/device),waits for the device to be accepted by a user in the platform interface (
GET /api/v1/plateform/{platform_uuid}/device/{device_uuid}/status),saves the returned credentials and connects to the MQTT broker.
On subsequent boots the credentials are read back from NVS and the module connects directly.
Alternatively, if you already have a device uuid/token, call
Cloud::useDeviceCredentials() before begin() to skip provisioning entirely.
The progress of this sequence is reported by Cloud::getState()
(CloudState); Cloud::isConnected() is the simple check for “the link is
up”. A mid-session MQTT drop is first left to the transport’s own auto-reconnect and only
escalates to a full re-provisioning pass if it does not recover within 30 s.
MQTT topics
Variable topics use the form device/{device_uuid}/{type}/{variable_name} where {type} is
def (default variable), b (bool), i (int), f (float) or s (string). Values are
transmitted as plain text ("0"/"1" for booleans, the decimal representation for numbers).
Firmware update (OTA)
The whole update is driven from the OpenIndus cloud web application at oicloud.openindus.com: you upload the firmware binary there, trigger the update on the device, and the image is downloaded straight from that host — no external storage or build server is involved, and the progress is reported back in the web application.
The ota default variable carries a JSON command envelope
{"cmd": <int>, "args": <string|int>} in both directions (see CloudOtaCmd):
|
Name |
Direction |
|
|---|---|---|---|
|
UPDATE |
cloud to module |
Firmware download URL, as sent by the web application. A path-only value
(e.g. |
|
PROGRESS |
module to cloud |
Number of bytes written so far, emitted every 64 KB and once when the image is complete |
|
END |
module to cloud |
Error code, |
On UPDATE the module spawns a dedicated task that streams the image straight into its inactive OTA partition (nothing is staged in RAM), authenticating with its device token — dropped if the download is redirected off the cloud host, so it never leaks to a third-party storage bucket. Once the image is validated the module sets the new boot partition, publishes END and reboots on it. On failure the download is aborted, the error code is published as END and the module keeps running the current firmware; a new UPDATE command can start a fresh attempt. A second UPDATE is ignored while one is already in progress.
Generating the application code
You do not have to write the variable declarations by hand. Once the variables are described in
the web application at oicloud.openindus.com, its code
generation feature scaffolds a ready-to-build main.cpp for you: the platform credentials,
the OICloud instance, one declaration per cloud variable with its type, direction and refresh
policy, and the matching addVariable() calls in setup(). Download it as your starting
point and fill in the application logic in loop().
Code examples
The example below provisions a module, publishes two variables and reacts to a value pushed from the cloud:
#include "OpenIndus.h"
#include "Arduino.h"
Core core;
/* Platform credentials (from your OpenIndus cloud platform) */
#define PLATFORM_UUID "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
#define PLATFORM_TOKEN "your-platform-token"
#define PROJECT_ID 1
#define PROJECT_VERSION "1.0.0"
/* The cloud handles provisioning (device uuid/token) automatically and
* persists the credentials in NVS. */
OICloud cloud(PLATFORM_UUID, PLATFORM_TOKEN, PROJECT_ID, PROJECT_VERSION);
/* Cloud variables: each maps to an MQTT topic. */
IntVariable counter("counter", 0, UpdateMethod::SYNCHRONOUS, UpdateType::PUBLISH, 1000);
BoolVariable buttonOn("buttonon", false, UpdateMethod::ASYNCHRONOUS, UpdateType::PUBLISH, 1000, 10000);
FloatVariable setpoint("setpoint", 0.0f, UpdateMethod::ASYNCHRONOUS, UpdateType::SUBSCRIBE);
int i = 0;
void setup(void)
{
printf("Hello OpenIndus!\n");
/* 1. Bring up network connectivity (cellular / PPP) */
core.modem = new Modem();
core.modem->begin("TM"); // APN of your SIM provider
core.modem->connect();
/* 2. React to values pushed from the cloud */
setpoint.onReceive([](const float &value) {
printf("New setpoint received from cloud: %f\n", value);
});
/* 3. Register the variables and start the cloud client.
* begin() returns immediately; provisioning and the MQTT connection
* run in a background task. */
cloud.addVariable(&counter);
cloud.addVariable(&buttonOn);
cloud.addVariable(&setpoint);
cloud.begin();
}
void loop(void)
{
/* Just update the values; the cloud task publishes them according to
* each variable's refresh policy. */
i++;
counter.setValue(i);
buttonOn.setValue((i % 2) == 0);
delay(1000);
}
Software API
-
class Cloud
Cloud API class.
Handles device provisioning (spec section 3), credential persistence in NVS, MQTT-over-WebSocket transport and typed cloud variables. All provisioning, connection and variable servicing runs in a background task so user code never blocks: construct, addVariable(), begin(host), then setValue()/getValue().
Public Functions
-
Cloud(const char *platformUuid, const char *platformToken, int projectId, const char *projectVersion = nullptr)
Constructor for Cloud API (auto-provisioning, preferred).
- Parameters:
platformUuid – Platform UUID
platformToken – Platform authentication token
projectId – Project id the device belongs to
projectVersion – Project version to publish as the “version” cloud variable. If null/empty (not provisioned), falls back to the firmware’s software version (Board::getSoftwareVersion()).
-
void useDeviceCredentials(const char *uuid, const char *token)
Provide device credentials directly, bypassing provisioning/NVS.
- Parameters:
uuid – Device UUID
token – Device token
-
bool begin(const char *host)
Start the cloud client. Launches the background task and returns immediately; provisioning and connection happen asynchronously.
- Parameters:
host – Cloud host, e.g. “cloud.openindus.com”
- Returns:
true if the task was started
-
void end(void)
Stop the cloud client and disconnect.
-
CloudState getState(void) const
Get the current connection/provisioning state.
-
bool isConnected(void) const
Checks if the device is connected to the cloud.
- Returns:
true if connected, false otherwise.
-
template<typename T>
inline void addVariable(CloudVariable<T> *variable) Register a CloudVariable with the Cloud system.
- Template Parameters:
T – CloudVariable type
- Parameters:
variable – Pointer to a CloudVariable
-
void unregisterVariable(const std::string &name)
Unregister a variable by name.
- Parameters:
name – Variable name to unregister
-
void log(const std::string &message)
Publish a log message (default “log” variable).
-
Cloud(const char *platformUuid, const char *platformToken, int projectId, const char *projectVersion = nullptr)
-
template<typename T>
class CloudVariable : public ICloudVariable CloudVariable class.
- Template Parameters:
T – Data type (bool, int, float, std::string)
Public Functions
-
inline CloudVariable(const std::string &name, const T &initialValue = T(), UpdateMethod updateMethod = UpdateMethod::SYNCHRONOUS, UpdateType updateType = UpdateType::PUBLISH, uint32_t refreshInterval = 1000, uint32_t maxRefreshInterval = 10000)
CloudVariable constructor.
- Parameters:
name – Variable name and MQTT topic
initialValue – Initial value
updateMethod – Update method (default: SYNCHRONOUS)
updateType – Update type/direction (default: PUBLISH)
refreshInterval – SYNCHRONOUS interval, or ASYNCHRONOUS min interval, in ms
maxRefreshInterval – ASYNCHRONOUS max interval without publish, in ms
-
inline void onReceive(std::function<void(const T&)> cb)
Register a callback fired whenever a new value is received from the cloud.
-
inline bool setValue(const T &newValue)
Set a new value.
- Parameters:
newValue – New value
- Returns:
true if the value changed
-
virtual std::string serialize(void) const override
Serialize the current value to the plain-text MQTT payload.
-
inline virtual void applyPayload(const std::string &payload) override
Apply an inbound MQTT payload to the value and fire the callback.
-
inline virtual std::string serialize(void) const
Serialize the current value to the plain-text MQTT payload.
-
inline virtual std::string serialize(void) const
Serialize the current value to the plain-text MQTT payload.
-
inline virtual std::string serialize(void) const
Serialize the current value to the plain-text MQTT payload.
-
inline virtual std::string serialize(void) const
Serialize the current value to the plain-text MQTT payload.
-
enum class UpdateMethod
Update methods (how often the value is published).
SYNCHRONOUS : published once every refresh interval.
ASYNCHRONOUS: published on change, rate-limited between minRefreshInterval and maxRefreshInterval.
Values:
-
enumerator SYNCHRONOUS
-
enumerator ASYNCHRONOUS
-
enum class UpdateType
Update types (direction relative to the MQTT topic).
PUBLISH : the module publishes the topic.
SUBSCRIBE: the module subscribes to the topic.
BOTH : the module both publishes and subscribes.
Values:
-
enumerator PUBLISH
-
enumerator SUBSCRIBE
-
enumerator BOTH
-
enum class CloudState
Cloud connection / provisioning state.
Values:
-
enumerator IDLE
-
enumerator LOADING_CREDS
-
enumerator PROVISION_CREATE
-
enumerator PROVISION_PENDING
-
enumerator CONNECTING
-
enumerator CONNECTED
-
enumerator RECONNECTING
-
enumerator ERR_REJECTED
-
enumerator ERR_ALREADY_CREATED
-
enumerator IDLE
-
enum class CloudOtaCmd
Commands carried by the “ota” topic, in the “cmd” field of the JSON payload {“cmd”: <int>, “args”: <string|int>}.
UPDATE (cloud -> device): args is the firmware download URL (string).
PROGRESS (device -> cloud): args is the number of bytes written (int).
END (device -> cloud): args is the error code (int), 0 == success.
Values:
-
enumerator UPDATE
-
enumerator PROGRESS
-
enumerator END