OpenPLC

OpenPLC

Open in ChatGPT
Ask ChatGPT about this page
Open in Claude
Ask Claude about this page

OTA blocks

OTA

Updates a ModBee node's firmware over MQTT from inside the PLC program. The
node pulls the new firmware a piece at a time, checks it, switches to it and
reboots. If the new firmware does not come back on MQTT, the board goes back
to the old one by itself.

Block Does
OTA_NODE The updater. One per board, wired to an MQTT_CLIENT
OTA_SIGNING Optional: only firmware signed with your key installs
OTA_SPARKPLUG Optional: the update as Sparkplug metrics, run from SCADA

Getting started

  1. Enable the MQTT and OTA libraries in the project.

  2. In the comms task (T#50ms or slower), next to the MQTT_CLIENT:

    ota(CLIENT := mqtt, BASE := 'modbee/pump-01/ota', VERSION := '1.4.0');
    

    VERSION is this program's version. Raise it for every release: an update
    for the same version is refused, and an older one unless ALLOW_DOWNGRADE.

  3. Publish the update from the PC with modbee_ota.py, from the tools/
    folder of the modbee-ota repository:

    python modbee_ota.py push firmware.bin --broker <broker> \
        --base modbee/pump-01/ota --board modbee-node-uio --version 1.4.1 --retain
    

    firmware.bin is the program the editor built for the board.
    --retain lets a node that is offline now take the update when it comes
    back, and lets a node that lost power carry on where it stopped.

Choosing when

Firmware updates restart the PLC. Let the program decide the moment:

Pin Then
AUTO_ACCEPT := FALSE STATE waits at OTA_OFFERED. ACCEPT starts the download, REJECT refuses it
AUTO_APPLY := FALSE STATE waits at OTA_READY with the update checked. APPLY reboots into it
ABORT stops an update at any point before the reboot

While an update downloads, each 4 kB written to flash can delay a fast task
by one release. Accepting only while the machine is stopped avoids it.

After the reboot

The new firmware is on trial (STATE = OTA_TESTING) until CONFIRM_MODE
says it is good:

CONFIRM_MODE Kept when
OTA_CONFIRM_LINK (default) MQTT is back
OTA_CONFIRM_PROGRAM CONFIRM is set by the program
OTA_CONFIRM_BOOT straight away

If it is not confirmed within CONFIRM_TIME (2 minutes), or the board
restarts three times on trial, the old firmware comes back and RESULT says
OTA_NOT_CONFIRMED or OTA_ROLLED_BACK.

Signing

Without OTA_SIGNING the node checks that an update arrived whole and is for
this board, not who made it. With it, and REQUIRE_SIGNED := TRUE on the
node, only firmware signed with your private key installs:

python modbee_ota.py keygen ota-key.pem        (once; keep it off the boards)
python modbee_ota.py pubkey ota-key.pem        (the KEY, without commas and 0x)
python modbee_ota.py push ... --key ota-key.pem

Over Sparkplug

The image always travels on BASE's own topics - Sparkplug has no file
transfer - over the same MQTT_CLIENT connection a SPARKPLUG_NODE rides on.
OTA_SPARKPLUG adds what a SCADA host needs to run the update from its own
screens:

sp   (CLIENT := mqtt, GROUP := 'Plant1', NODE := 'pump-01');
ota  (CLIENT := mqtt, BASE := 'modbee/pump-01/ota', VERSION := '1.4.0',
      AUTO_APPLY := FALSE);
otasp(NODE := ota, SPARKPLUG := sp);

The node then reports Firmware/Version, Firmware/State, Firmware/Progress
(whole percent, as it moves), Firmware/Offered and Firmware/Status (the JSON
status), and takes Node Control/Firmware Accept, Reject, Apply, Abort,
Confirm and Rollback - Booleans the host writes TRUE, reported FALSE again.

Where it runs

  • In the same task as its MQTT_CLIENT, with OTA_SIGNING and
    OTA_SPARKPLUG. The update arrives inside the client's scan; in another task
    the block does nothing and says so on ERROR.
  • Not in a logic task. While a download runs, the comms task's scans
    stretch to tens of milliseconds.
  • ESP32 boards only. On the Runtime the block reports OTA_UNSUPPORTED.

Status

Pin Means
STATE OTA_IDLE, OTA_CHECKING, OTA_OFFERED, OTA_DOWNLOADING, OTA_VERIFYING, OTA_READY, OTA_APPLYING, OTA_TESTING
PROGRESS, RECEIVED, SIZE how far
OUTCOME, RESULT how the last update ended, and why
ERROR, LAST_ERROR the block cannot run, in words
Last updated 2 hours ago
Was this helpful?
Thanks!