Simple ESP32 OTA Code updates via MQTT

Simple ESP32 OTA Code updates via MQTT
Photo by Markus Spiske / Unsplash

This is a very basic system for remotely updating files on an ESP32 and optionally triggering a reboot.  Lots of other projects do something similar and have more features but I wanted something lightweight that didn't depend on a web server.   The device just needs to listen to an OTA topic and pass the message to the OTA module which will handle the filesystem updates and rebooting.

There are no fancy features here.  No rolling back broken code if the updated code is so broken that it can no longer connect to MQTT. So you'll want to be careful and test your changes.

Any file can be updated not just python so can also update configuration text or JSON files, etc.  If you're updating multiple python files you probably don't want to request a reboot until they are all updated.


How it works

We need some way to get the new code on the device.  Since it seems most of my networked projects use MQTT I figured I'd use that to deliver the new code.  No need for a separate web server.  If we just put the contents of the new file into a topic then we wouldn't know what file we want to update and whether it should reboot after the new code was there.

Headers

We basically just need some metadata along with the file contents.  I thought about putting the file contents in a field in a JSON document but there would be too many special characters that would be a pain to escape.  Base64 encoding would also be a pain and make the content a good bit larger.  In the end I just went with some header lines in a specific format (# OTA:<name>:<value>) that let you pass arbitrary name/value pairs.

# OTA:file:main.py
# OTA:reboot:true
from machine import Pin
import time
...

MQTT code

The application code just needs to listen to an OTA topic of its choice and pass those messages to the code in this project.  It will parse the headers, write the file, and maybe reboot.

    if topic == self.ota_topic:
        ota.process_ota_msg(msg_string)

Code

Getting Started With Micropython

1. Getting started with MicroPython on the ESP32 — MicroPython latest documentation

micropython-mqtt

GitHub - peterhinch/micropython-mqtt: A ‘resilient’ asynchronous MQTT driver. Plus a means of using an ESP8266 to bring MQTT to non-networked targets.
A &#39;resilient&#39; asynchronous MQTT driver. Plus a means of using an ESP8266 to bring MQTT to non-networked targets. - GitHub - peterhinch/micropython-mqtt: A &#39;resilient&#39; asynchronous M…

Grab mqtt_as/mqtt_as.py and mqtt_as/mqtt_local.py and upload them to the root of the ESP32 without the subdirs.  We'll need to tweak mqtt_local.py with your WiFi and MQTT broker settings.

This project's code

GitHub - scarey/simple-ota-updater: Micropython code to read updated code via MQTT and update the ESP32 filesystem
Micropython code to read updated code via MQTT and update the ESP32 filesystem - GitHub - scarey/simple-ota-updater: Micropython code to read updated code via MQTT and update the ESP32 filesystem

Copy main.py, ota.py, and mqtt_handler.py to the root of the ESP32. The example will blink the LED at 1 second intervals.  Modify main.py to with any changes you want.  Maybe change the "version" variable to 2 and "led_sleep_time" to 0.5 and publish the contents of main.py to esp32/otatest/ota.  The new code should be written to main.py and the ESP32 rebooted.  The LED should blink at 0.5 second intervals and esp32/otatest/version should be updated to 2.  Cool.


Notes

  • Any other headers that might be handy?
Technology icons created by Freepik - Flaticon