paint-brush
Building your own ESP8266/ESP32 Over-The-Air Firmware Updater [A How-To Guide] Part Iby@dazzatron
1,911 reads
1,911 reads

Building your own ESP8266/ESP32 Over-The-Air Firmware Updater [A How-To Guide] Part I

by DerkMarch 3rd, 2020
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Building your own ESP8266/ESP32 Over-The-Air Firmware Updater [A How-To Guide] Part I: Part I. This guide explains how to build a simple ESP866 firmware updater in NodeJS. It 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 an example Blink sketch from the Arduino library. We’ll need the compiled binary to upload to the sketch.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Building your own ESP8266/ESP32 Over-The-Air Firmware Updater [A How-To Guide] Part I
Derk HackerNoon profile picture

This guide explains how to build a simple ESP8266 firmware updater in NodeJS. 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. But you can use the ESP32 as well.

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);
  }
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, and more, please see Part 2 of this article.