Simple ESP32 OTA Code updates via MQTT
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
micropython-mqtt
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
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?