Part 1 — How to build your own ESP8266/ESP32 Over-The-Air firmware updater
By: Derk Zomer
Tags: Arduino, Esp8266, Nodejs, Esp8266 Nodemcu

This guide explains how to build a simple ESP8266/32 firmware updater in NodeJS.

This is the first part of a two-part guide. If you already know how the OTA update works and want to build an automated firmware version controller you can skip ahead to Part 2 here.

The ESP8266 will send a GET request to my application with some key information stored in its header. This will then be used to serve up the appropriate binary.

For this example I’m using the ESP8266 ESP12E.

NodeJS Application

Let’s get started by generating a new Express app using the following command in terminal:

express ota_updater

This creates a fresh instance of Express which we’ll use as the foundation of our version controller.

For the sketch that I want to upload to the ESP8266 I’m using the example Blink sketch from the Arduino library.

void setup() {

// initialize digital pin LED_BUILTIN as an output.

pinMode(LED_BUILTIN, OUTPUT);

} // the loop function runs over and over again forever

void loop() {

digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)

delay(1000); // wait for a second

digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW

delay(1000); // wait for a second

}

We’ll need the compiled binary to upload to the sketch, which you can find in the debugger once you turn on the option “Show verbose output” for sketch compilations.

After clicking the verify button you can find the compiled binary as per your debugger.

Place your blink.ino.bin inside a new /updates folder and updating our index.js file inside the routes folder to serve up our binary.

var express = require('express');

var path = require('path');

var fs = require("fs");

var router = express.Router();

var md5 = require("md5-file"); router.get('/update', function(req, res, next) { console.log(req.headers); var filePath = path.join(__dirname, '../updates/blink.ino.bin'); var options = {

headers: {

"x-MD5": md5.sync(filePath)

}

} res.sendFile(file, function (err) {

if (err) {

next(err)

} else {

console.log('Sent:', file)

}

}); }); module.exports = router;

After you confirm this works on your local machine it’s time to move your application to an external instance such as EC2 or Linode. After setting this all up you should be presented with the download dialog after navigating to your external domain.

Now that you know your application works you can start testing it out on your ESP8266.

ESP8266 sketch

For the ESP8266 sketch we use the ESP8266httpUpdate.h library.

#include <ESP8266httpUpdate.h> const char* ssid = "ssid"; // Set your router SSID

const char* password = "password"; // Set your router password void setup() {



Serial.begin(74880);

Serial.setDebugOutput(true);

WiFi.begin(ssid, password);

/*connection to WiFi*/

while (WiFi.status() != WL_CONNECTED) {

Serial.print(".");

delay(1000);

}



switch(ret) {

case HTTP_UPDATE_FAILED:

Serial.printf("[update] Update failed (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());

break;

case HTTP_UPDATE_NO_UPDATES:

Serial.println("[update] Update no Update.");

break;

case HTTP_UPDATE_OK:

Serial.println("[update] Update ok.");

break;

} t_httpUpdate_return ret = ESPhttpUpdate.update(" http://domain.com/update ","1.0");switch(ret) {case HTTP_UPDATE_FAILED:Serial.printf("[update] Update failed (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());break;case HTTP_UPDATE_NO_UPDATES:Serial.println("[update] Update no Update.");break;case HTTP_UPDATE_OK:Serial.println("[update] Update ok.");break; } void loop() { }

Upload the sketch to your ESP8266 and your console will output the something similar to the following, after which your ESP8266 module resets and executes the blink sketch.

And when looking at our NodeJS app we see information about the ESP8266 be outputted to the screen:

{ connection: 'upgrade',

host: 'domain.com',

'content-length': '0',

'user-agent': 'ESP8266-http-Update',

'x-esp8266-chip-id': '14454826',

'x-esp8266-sta-mac': 'CC:50:E3:DC:90:2A',

'x-esp8266-ap-mac': 'CE:50:E3:DC:90:2A',

'x-esp8266-free-space': '659456',

'x-esp8266-sketch-size': '302832',

'x-esp8266-sketch-md5': '97bbf0d228c88673b9c040df1f7317f4',

'x-esp8266-chip-size': '4194304',

'x-esp8266-sdk-version': '2.2.2-dev(38a443e)',

'x-esp8266-mode': 'sketch',

'x-esp8266-version': '1.0' }

Now this appears to work very nicely. However, now that the blink sketch is uploaded there is no way for us to upload a new sketch to the module. The preferred outcome would be that your ESP8266 will periodically check whether there are new firmware updates available, and update the module if necessary.

For all of that, please take a look at Part 2 of this guide.