91. IoT platforms
A platform is the software between devices and applications. It connects devices, stores their data, runs rules, shows charts and exposes the data to the outside. The section answers four questions: - what a platform consists of; - what kinds of platforms exist; - how to choose one; - why firmware should not depend on a particular platform.
Checked by experiment: the real open platform ThingsBoard in a container and the same device MQTT code as in section 87. Only one thing was added — a token in the user name field.
Terms used in the documentation
Term Meaning IoT platform software between devices and applications device provisioning registering devices on the platform access token the device's secret for logging in telemetry, attributes a time series; properties (the current state) RPC — remote procedure call a command to the device with a reply rule engine, rule chain the processing engine; a chain of processing steps dashboard a screen of charts and indicators multi-tenancy several independent customers on one installation cloud (SaaS), self-hosted (on-premises) a cloud service; your own installation vendor lock-in being tied to one supplier
91.1 Why a platform
Every project with devices has to solve the same tasks: - keep a register of devices and their keys; - store data; - raise alarms by rules; - show charts; - grant rights to users; - open a programming interface for other systems.
Everyone's device is different, but these tasks repeat from project to project. The platform takes them over. Without it you write all of this yourself: the server from section 94, the database, the rules, the user interface — and maintain them for years.
91.2 What a platform consists of
| Part | What it does | In the experiment |
|---|---|---|
| connectivity and normalisation | MQTT broker, CoAP and HTTP intake, a common data format | broker on port 1883, telemetry in JSON |
| device management | registration, keys, settings, state, firmware update | the device was registered through the programming interface, a token was issued |
| database | time series and attributes | three values and two attributes |
| processing and actions | rules: store, compare with a threshold, raise an alarm, send a command | the default rule chain stored the data |
| analytics | summaries, anomalies, forecasts | — |
| visualisation | dashboards and charts | — |
| administration tools | users, rights, customers | customer administrator login |
| external interfaces | REST, MQTT for applications, integrations | data read and command sent through REST |
For the device, three things matter here: how to connect, where to send and where to expect commands from. Everything else happens on the platform side.
91.3 Experiment: a device on ThingsBoard
The ThingsBoard platform runs in a container with its built-in database. The device was registered through its REST, after which the "device" — a C program — connected to its broker:
| Step | What happened |
|---|---|
| device registered through REST | the platform issued an access token — 20 characters |
| connecting with someone else's token | refused already in CONNACK, code 5 — "not authorized" |
| connecting with its own token | CONNACK with code 0 |
subscribing to v1/devices/me/rpc/request/+ |
SUBACK, QoS 0 granted |
attributes {"fw":"1.0.3","sf":7} in v1/devices/me/attributes |
stored as device attributes |
three values in v1/devices/me/telemetry |
stored as a time series: 21.5, 21.75 and −12.34 |
command setInterval through REST |
reached the device over MQTT, the reply {"ok":true,"interval":900} came back to REST |
The device needed three new pieces on top of the packets from section 87:
/* CONNECT с именем пользователя и чистой сессией: флаги 0x82 */
size_t mqtt_connect_user(uint8_t *buf, const char *client_id, const char *user, uint16_t keepalive)
{
uint32_t rem = 10u + 2u + (uint32_t)strlen(client_id) + 2u + (uint32_t)strlen(user);
size_t k = 0;
buf[k++] = 0x10;
k += mqtt_put_len(buf + k, rem);
k += put_str(buf + k, "MQTT");
buf[k++] = 4;
buf[k++] = 0x82;
buf[k++] = (uint8_t)(keepalive >> 8);
buf[k++] = (uint8_t)keepalive;
k += put_str(buf + k, client_id);
k += put_str(buf + k, user);
return k;
}
/* Разбор PUBLISH с QoS 0: тема и данные указывают внутрь пакета.
* Вернёт 0 или −1, если это не такой PUBLISH или пакет обрезан. */
int mqtt_parse_publish(const uint8_t *p, size_t n, const char **topic, size_t *tlen,
const uint8_t **data, size_t *dlen)
{
if (n < 2 || (p[0] & 0xF0) != 0x30 || (p[0] & 0x06))
return -1;
size_t k = 1, rem = 0, mul = 1;
do {
if (k >= n || k > 4)
return -1;
rem += (p[k] & 127u) * mul;
mul *= 128;
} while (p[k++] & 128);
if (rem < 2 || k + rem > n)
return -1;
size_t tl = ((size_t)p[k] << 8) | p[k + 1];
if (2 + tl > rem)
return -1;
*topic = (const char *)p + k + 2;
*tlen = tl;
*data = p + k + 2 + tl;
*dlen = rem - 2 - tl;
return 0;
}
/* Номер команды из темы v1/devices/me/rpc/request/<номер>; −1 — не команда */
long tb_rpc_id(const char *topic, size_t tlen)
{
static const char pre[] = "v1/devices/me/rpc/request/";
size_t pl = sizeof pre - 1;
if (tlen <= pl || memcmp(topic, pre, pl) != 0)
return -1;
long id = 0;
for (size_t i = pl; i < tlen; i++) {
if (topic[i] < '0' || topic[i] > '9')
return -1;
id = id * 10 + (topic[i] - '0');
}
return id;
}
A command arrives as an ordinary publish to a topic the device is
subscribed to. The device replies to the topic …/rpc/response/<the same number>, and by
the number the platform finds who was waiting for the reply. The parser copies nothing:
topic and data point straight into the received packet, it takes 16 bytes of stack.
Telemetry is built from hundredths of a degree without float, as in
section 88. It is sent with the same mqtt_publish from section 87.
The CONNECT and SUBSCRIBE packets were independently rebuilt in Python.
Telemetry and attributes are different things. Telemetry is a time series: each value has its own timestamp, and history is kept. An attribute is the current state: firmware version, SF, sending interval. Only the last value is kept. The firmware version is not sent as telemetry: you would get a thousand identical points on the chart. The platform also keeps settings as attributes and can send them to the device by itself.
A token is a password. Each device has its own, it is stored like a key (section 43), and it can be revoked. In the experiment the device connected to port 1883 without encryption — the token in the CONNECT packet went in plain text, and anyone listening to the network can read it. In production — port 8883 with TLS (section 37.4). For large fleets, certificates are issued instead of tokens.
91.4 Kinds of platforms
One platform rarely covers everything, and usually it is a chain:
| Kind | What it does | Examples |
|---|---|---|
| connectivity platform | connection over its own technology | LoRaWAN network server (section 94), operator platforms for NB-IoT SIM cards |
| cloud | broker, device register, rules, storage as a service | AWS IoT Core, Azure IoT Hub |
| device platform | register, settings, firmware update | often part of a cloud one |
| analytics | big data processing, forecasts | separate services |
| open, self-hosted | all of the above on your own servers | ThingsBoard, ChirpStack; there are Russian ones too |
⚠️ Platforms shut down. In 2023 Google Cloud IoT Core and IBM Watson IoT Platform stopped working. Their customers had to move devices that were already installed at sites to other platforms. A device whose server address and login method are hard-wired into the firmware becomes scrap on such a day.
91.5 Cloud or your own installation
| Cloud service | Own installation | |
|---|---|---|
| getting started | in a day | needs to be deployed and configured (section 87) |
| maintenance | by the vendor | yours: updates, backups, monitoring (section 90.7) |
| price | per device and per message | servers and people |
| where the data is | with the vendor, sometimes in another country | with you — important if the law requires data to be stored in the country |
| leaving | depends on data export | everything is yours |
The cost of the cloud grows with the number of messages, and this is where section 90.4 pays off. 1000 devices at 98 messages a day is 2.94 million messages a month. Sending every second — 2.59 billion.
"Build or buy" is decided soberly. Your device is unique, but the register, storage and charts are not. Your own platform is not a month of development but years of maintenance.
91.6 How to choose
| Question | Why |
|---|---|
| which protocols: MQTT, CoAP, HTTP, intake from a LoRaWAN network | the device must speak a standard, not a platform library |
| how to register thousands of devices | you cannot hand out a thousand tokens by hand |
| is there over-the-air firmware update | a bug will be found after installation (section 48) |
| rules and alarms | what the platform does without a programmer |
| programming interface and data export | this is your way off the platform |
| where the data is stored | requirements of the law and of the customer |
| what it costs at your data volume | calculate from the data flows in the design (section 90.7) |
| who the vendor is: history, plans, community | will the platform exist in five years |
| security | channel encryption, user rights, audit log |
91.7 Firmware that outlives the platform
- A standard protocol. The device speaks MQTT or CoAP. The experiment showed it: the code from section 87 worked with ThingsBoard once a user name was added to the connection.
- Everything platform-specific lives in settings. Server address, topics, field names and the token are kept in the device settings and changed over the air, not in firmware constants.
- An adapter layer. The rest of the program knows only "send a measurement" and "receive a command". A small adapter is written for each platform.
- Autonomy. Without the platform the device keeps working and buffers data (section 90.6).
91.8 Pitfalls
The device is written on the platform's proprietary library. The platform shut down or got more expensive, and reworking the firmware on thousands of devices is impossible.
One token for all devices. Steal it from one — and all of them are spoofed.
Firmware version in telemetry. A thousand identical points on the chart, and the current value cannot be found. It is an attribute.
The command times out. A LoRaWAN class A device sleeps, and the command must wait in the server queue (section 94.6), not in a synchronous call.
No data export. The platform will not let you go.
The cloud bill grew a thousandfold. The device sends every second.
The platform's demo accounts are left in place. The installation creates them, and everyone knows about them. Change them first.
91.9 Summary
- A platform covers the common tasks: connectivity, device register, storage, rules, charts and external interfaces.
- ThingsBoard in a container accepted the device over the same MQTT as in section 87, with the token in the user name field. Someone else's token was rejected in CONNACK. Data and attributes were stored. A command through REST reached the device, and the reply came back.
- Telemetry is a time series, attributes are the current state.
- Platforms shut down: the device speaks a standard and keeps everything platform-specific in settings that are changed over the air.
- The cloud is faster to start with; your own installation gives control and keeps the data with you. The cost of the cloud grows with the number of messages.
Next: section 92 "Radio site survey and coverage map".