Use ArduinoOTA library but with ESP8266 as the WiFi module for downloads?

Hi. I have a setup in which there is an Arduino Mega2560 and an ESP8266 and I want to implement some basic firmware OTA functionality. The workflow which I had in mind was as follows:

  1. Query the server for a JSON payload that checks if a new firmware version is available.
  2. If yes, download that version (an Intel .hex file).
  3. Transfer it over serial to the Mega after restarting it so the Mega's bootloader can accept it and write it to application flash.

Steps 1 and 2 were relatively easy to accomplish with some standard ESP8266 wifi libraries and ArduinoJson. However step 3 has really stumped me and I have found myself trying, for the last few days, to unsuccessfully emulate the behavior of code that is way too sophisticated for me to understand (it did give me an opportunity to learn about bootloaders, fuse and lock bits and all that though).

So I was wondering if it would be possible to have libraries in the likes of ArduinoOTA handle ONLY step 3 for me whilest still doing steps 1 and 2 via the regular ESP8266 libraries on the ESP end? .

Here is the skeleton of the code that I have in mind:

// Code for ESP8266
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>
#include <ArduinoJson.h>

void setup()
{
    // step 1
    connect2WiFi(ssid, password); // uses WiFi.begin() and WiFi.status()
    if (fimwareUpdateAvailable(API1_url)) // uses HTTPClient::begin(), HTTPClient::POST() and ArduinoJson
    {
        // step 2
        String hexfile = download(URL); // uses HTTPClient::GET()
        File file = write2SPIFFS(hexfile); // uses SPIFFS.open(), write(), etc.
       
       // step 3
       bool transferComplete = false;
       while (!transferComplete)
           transferComplete = transfer2Mega(file); // using Serial.write() over UART 
    }

}

I'm not sure what to do on the Mega 2560 end. Looking through the code examples I found the InternalStorage class with its .write() function (here onwards):

  byte b;
  while (length > 0) {
    if (!client.readBytes(&b, 1)) // reading a byte with timeout
      break;
    InternalStorage.write(b);
    length--;
  }
  InternalStorage.close();
  client.stop();
  if (length > 0) {
    Serial.print("Timeout downloading update file at ");
    Serial.print(length);
    Serial.println(" bytes. Can't continue with update.");
    return;
  }

  Serial.println("Sketch update apply and reset.");
  Serial.flush();
  InternalStorage.apply(); // this doesn't return

so, I'm thinking something like:

#include <ArduinoOTA.h>

void setup()
{
    byte b;
    while (b = receiveFromESP()) // over Serial UART
    {
        InternalStorage.write(b);
    }
    InternalStorage.close();
    InternalStorage.apply();
}

Would this be a valid way of approaching this? is there some thing that I am missing or perhaps something that can be handled more easily with ArduinoOTA itself? (I have read the notes about installing Optiboot bootloader for Arduino Mega and will be trying that out as well). Any advice is welcome.

InternalStorage.open is missing.

1 Like

why do you want to write a sketch for esp8266. put AT firmware into the esp8266 and use my WiFiEspAT library in Mega. Then you can use my ArduinoOTA library the normal way.

1 Like

thanks for the response. basically the esp8266 is doing some work of syncing data computed by the mega with a server. The goal is to integrate the esp8266 sketch that I wrote with that existing syncing sketch. I wasn't even aware of the WiFiEspAT library that you mentioned. Thanks. I'll give that a shot if this doesn't work.

Hi @Juraj, a little update for you. I was trying to get the optiboot bootloader installed. I think its set up and working now. This weekend I had posted a related question and you had responded with:

on the ATmega2560, only the bootloader can write into the flash memory.
the Optiboot 8 has a function that can do it. there is a .h file which declares a function call to this function in the bootloader.
but it s just the start. you need a way for running application to move the new application. but the application runs from the flash so it can't overwrite itself. so I added a function to Optiboot which does this.
it is used here
https://github.com/JAndrassy/ArduinoOTA/blob/master/src/InternalStorageAVR.cpp

What I did was write a small test program similar to the one in the question I had posted this weekend:

#include <ArduinoOTA.h>

#include "hexfile.h" // bytes of a hex file for a test blink + serial monitor program

void setup()
{
  Serial.begin(9600);
  size_t fileSize = sizeof(hexcode); // hexcode is the name of the buffer containing the byte from the hex file
  if (!InternalStorage.open(fileSize))
  {
    Serial.println("Not enough space. Failed to update firmware.");
    while (true);
  }
  Serial.println("Writing program to flash...");
  for (int i = 0; i < fileSize; ++i)
  {
    InternalStorage.write(hexcode[i]);
  }
  InternalStorage.close();
  Serial.println("Done flashing.");
  delay(1000);
  InternalStorage.apply();
  // press reset
}

void loop()
{
}

I uploaded with Tools > Board > "Arduino Mega 2560 (Optiboot)" selected.

When I run this program and reset, the processor doesn't respond with the blink sketch. But it also doesn't run same program again (like from this weekend) which leads me to believe that the code is being written to flash. But it wont start it. I went back and checked your response:

you need a way for running application to move the new application. but the application runs from the flash so it can't overwrite itself. so I added a function to Optiboot which does this.

can you tell me which specific function you were referring to?

Just for your information, hexfile.h looks like this:

const uint8_t hexcode[] PROGMEM = {0x3a, 0x31,...}; // all 7594 bytes

you have to read progmem with the pgm_read functions

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.