This is a continuation of for the ESP8266 or ESP32. In this next part we’ll look into how we can build a more comprehensive OTA solution that does the following: Part 1 of our initial simple OTA solution Build the ESP8266 into something that is actually half useful; a humidity, temperature and moisture plant sensor. ‘Dial home’ to check whether there are new firmware updates available. Update the module depending to the latest version number as defined by our database. I have found this a very useful thing to learn while I’ve been trying to reduce the size of my projects through the use of surface mounted ICs. While they can be incredibly small, it’s pretty much impossible to reprogram them after soldering them to a PCB! Setting the scene showed a relatively useless example where we uploaded the ‘Blink’ sketch over-the-air. For this guide we’ll turn our project into a plant monitor that can sense the humidity of the soil, in addition to sensing the ambient temperature and humidity. Part 1 For the guide we’ll be using the following: ( will work as well) ESP8266/ESP12E ESP32 DHT11 Capacitive soil moisture sensor We’ll build a quick and dirty prototype where we connect all sensors to the ESP8266. Database setup We want to check the ESP8266 to periodically ping our database and ask whether there is a new firmware update available. If the answer is yes we perform an automatic update. First we set up our database and associated table. For this we use MySQL and the follow SQL: Query OK, 1 row affected (0.00 sec) -> mac_id CHAR(17) PRIMARY KEY NOT NULL, -> available_firmware_version INT(2) NOT NULL, -> last_update TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -> ); Query OK, 0 rows affected (0.01 sec) mysql> CREATE DATABASE OTA; mysql> CREATE TABLE Ping ( Now that we’ve got a table we can use to query whether our ESP8266 needs an update we can go ahead and insert a row for our device. We know from the previous lesson that out MAC address is CC:50:E3:DC:90:2A. Query OK, 1 row affected (0.01 sec) mysql> INSERT INTO Ping (mac_id, available_firmware_version) VALUES ( ,2); 'CC:50:E3:DC:90:2A' Now let’s set up our NodeJS app. NodeJS module We want to build a module that pings our database with the MAC address and let’s us know whether an update is available. We then want to update the module and update the database to reflect the new firmware on the device. Note that the below code is a continuation of what we’ve already built in . Part 1 Firstly my database handler: mysql = ( ) config = ( ) connection = mysql.createConnection({ : , : , : config.db_password, : }) ping = { sql = connection.query(sql, mac_id, { (!err) { (rows.length === ) { callback( , ) } { callback( , rows) } } { .log(err) callback(err, ) } }) } .exports = { : ping } var require 'mysql' var require '../js/config' var host 'localhost' user 'root' password database 'OTA' var ( ) function mac_id, callback var "SELECT * FROM Ping WHERE mac_id = ?" ( ) function err, rows, fields if if 0 null null else null else console null module ping And we add the new POST and update logic to our NodeJS app: express = ( ) path = ( ) router = express.Router() md5 = ( ) db = ( ) router.get( , { updateVersion = req.headers[ ] filePath = path.join(__dirname, +updateVersion+ ) options = { : { : md5.sync(filePath) } } res.sendFile(filePath, { (err) { next(err) } { .log( , filePath) } }) }) router.post( , { mac_id = req.body.mac_id .log(req.body) .log(mac_id) db.ping(mac_id, { (results) ? res.send({ :results[ ].mac_id, :results[ ].available_firmware_version}) : res.send({ :err}) }) }) .exports = router var require 'express' var require 'path' var var require 'md5-file' var require '../js/databaseHandler' '/update' ( ) function req, res, next var 'x-esp8266-version' var '../updates/plant_sensor_v' '.bin' var headers "x-MD5" ( ) function err if else console 'Sent:' '/ping' ( ) function req, res, next var console console ( ) function err, results 'mac_id' 0 'available_firmware_version' 0 'error' module ESP8266 sketch Now we build out our sketch and generate two different version numbers. The sketch works as follows: We connect to Wifi. We send our MAC address to the server which pings back the latest firmware version. We check whether our firmware needs an update and update if necessary. We start the sensor measurements. And finally we upload our binaries to the server, and make sure we have different version numbers for each build. # firmware_version 1 define // For the first sketch # firmware_version 2 define // For the second sketch The complete code: * ssid = ; * password = ; ; output_value; output_raw; { Serial.begin( ); Serial.setDebugOutput( ); HTTPClient http; WiFi.begin(ssid, password); (WiFi.status() != WL_CONNECTED) { Serial.print( ); delay( ); } String mac = + String(WiFi.macAddress()); capacity = JSON_OBJECT_SIZE( ) + ; ; http.begin( ); http.addHeader( , ); httpCode = http.POST(mac); String payload = http.getString(); http.end(); deserializeJson(doc, payload); * macId = doc[ ]; available_firmware_version = doc[ ]; String fwv = String(available_firmware_version); (available_firmware_version > firmware_version) { Serial.println( +String(firmware_version)+ +available_firmware_version)+ ; Serial.println( ); t_httpUpdate_return ret = ESPhttpUpdate.update( ,fwv); (ret) { HTTP_UPDATE_FAILED: Serial. ( , ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str()); ; HTTP_UPDATE_NO_UPDATES: Serial.println( ); ; HTTP_UPDATE_OK: Serial.println( ); ; } } { Serial.println( +String(firmware_version)+ +available_firmware_version)+ ; Serial.println( ); } dht.begin(); } { output_raw = analogRead(CSMS); output_value = (output_raw, , , , ); Serial.print( ); Serial.print(output_value); Serial.println( ); h = dht.readHumidity(); t = dht.readTemperature(); f = dht.readTemperature( ); (isnan(h) || isnan(t) || isnan(f)) { Serial.println(F( )); delay( ); ; } hif = dht.computeHeatIndex(f, h); hic = dht.computeHeatIndex(t, h, ); Serial.print(F( )); Serial.print(h); Serial.print(F( )); Serial.print(t); delay( ); } # include <ESP8266httpUpdate.h> # include <ESP8266HTTPClient.h> # include <ArduinoJson.h> # include "DHT.h" // Set out Wifi auth constants. const char "Yolo" const char "password" // Define our constants. # DHTPIN 5 define # DHTTYPE DHT11 define # CSMS A0 define // Set your firmware version here. Your other sketch should have a different version number. # firmware_version 1 define // Initialise the DHT11 sensor. DHT dht (DHTPIN, DHTTYPE) // Declare DHT output value variables. int int void setup () // Initialise Serial connection. 74880 true // Start HTTPClient. // Start Wifi. while "." 1000 // Record our MAC address. "mac_id=" // Allocate the JSON document. const size_t 2 60 DynamicJsonDocument doc (capacity) // Set up our HTTP request. "http://test.derkzomer.com/ping" //Specify request destination "Content-Type" "application/x-www-form-urlencoded" //Specify content-type header // Send the request and get the response payload. int //Close HTTP connection. // Parse the received JSON object. const char "macId" int "available_firmware_version" // Check whether your firmware is outdated. if "Your firmware version is V" ", the latest available firmware version is V" "." "Installing the new update now..." "http://test.derkzomer.com/update" switch case printf "[update] Update failed (%d): %s" break case "[update] Update no Update." break case "[update] Update ok." // may not be called since we reboot the ESP break else "Your firmware version is V" ", the latest available firmware version is V" "." "You have the latest version." // Start the DHT11 sensor. void loop () // Measure and map the raw moisture output from the moisture sensor. map 725 330 0 100 // Print the mapped output from the moisture sensor. "Moisture : " "%" // Measure the humidity and temperature from the DHT11. float float float true // Check whether the DHT11 sensor is working. if "Failed to read from DHT sensor!" 2000 return // Index the DHT11 values. float float false // Print the DHT11 humidity and temperature values. "Humidity: " "% Temperature: " // Wait five seconds before the next measurement. 5000 Let’s now move the binaries over to our server under the ‘/uploads/’ folder and test it out. Let’s upload the initial V1 sketch to our ESP8266 via serial and see what happens. The above shows you the serial output of how the ESP8266 checks for new updates by pinging the server, it gets told there is a new firmware update available, and then flashes the module. It then restarts, pings the server again, but now it skips the firmware update because you already have the latest version and starts its sensor measuring activities. So now you’ve built a complete version controlled OTA solution that allows you to install new firmware wirelessly onto your ESP8266! Next I’m thinking of reducing the size of my project from around 170 square cm to about 25 square cm, or about a ~7x reduction in size, through the use of a custom built PCB and smaller IC’s. So for all of that, and more, please stay tuned for a new article. Previously published at https://medium.com/@derk_zomer/esp8266-ota-solution-part-2-28bbd9b82429