Self-updating ( from WEB server HTTP ) OTA firmware for ESP8266 AND ESP32!

Yes, I have Blynk server at port 8088 and python server at 8000
I’ll take a look at IIS
I have to use this demo self-updating to update my Nextion display, but the ESPNexUpload example library isn’t well explained or maybe I’m a noob :thinking:

Not sure how this will help with the Nextion update. The HTTP update is really for updating ESP’s that aren’t on your network.
Handy if you have devices deployed somewhere that you want to ‘phone home’ every night to see if you have software updates for them.

Pete.

1 Like

thank you Pete,
If I understand how ESP’s self-updating works, I will understand how to manage ESPNexUpload, not sure :wink:

@PeteKnight

that’s run fine with python !!

Firmware version URL: http://192.168.0.100:8000/.fota/807D3A592CC7.version
Current firmware version: 2020051501
Available firmware version: 
Already on latest version

but if I change const int FW_VERSION = 2020051502 and save it again
there is no effect:

Firmware version URL: http://192.168.0.100:8000/.fota/807D3A592CC7.version
Current firmware version: 2020051501
Available firmware version: 
Already on latest version

:rofl:

Sorry I can’t check now thoroughly but looking at your printings it seems that your ESP can’t read from your server that’s why you get only the internal version only and not the read from your server… So the Available firmware version is empty…

1 Like

It reads, and if I delete the file, it said error.
Don’t worry, I 'll explore more

No it seems that it’s not reading thus you get empty printing, the normal is to have normal printing at the Available firmware version… You got nothing why is that?

If I delete firmware , I got that :

Checking for firmware updates.
MAC address: 807D3A592CC7
Firmware version URL: http://192.168.0.100:8000/.fota/807D3A592CC7.version
Firmware version check failed, got HTTP response code 404

So, server is ok

What are the permissions on your firmware file. It looks like it can see the file, but doesn’t have permission to read the FW version from it.

Pete.

1 Like

I just added “all user” but no change :thinking:
2020-05-15_180228

it’s the same python server I use for blynk images

What’s in your .version file?

Pete.

I insist. It is deferent case not to have the file (deferent handling) and deferent not to read it successfully. In your case it seems that the ESP doesn’t read the content of the file… Post your sketch and in my first free time I will check it. Otherwise, put a printing in the serial out to see what the ESP is reading from the . version file…

do you mean the version in the code ?
FW_VERSION = 2020051502

const char* fwUrlBase = "http://192.168.0.100:8000/.fota/"; /// put your server URL where the *.bin & *.version files are saved in your http ( Apache? ) server
const int FW_VERSION = 2020051503 ; /// year_month_day_counternumber 2019 is the year, 04 is the month, 17 is the day 01 is the in day release
/// based on: Self-updating OTA firmware for ESP8266 :  https://www.bakke.online/index.php/2017/06/02/self-updating-ota-firmware-for-esp8266/   ///

#define Version "0.5"  /// sketch version ///

/// Blynk related setup ///
/*
   V1 virtual switch for activate or deactivate RUNning LED controlling (boolean) ledBlink

   V14 WidgetTerminal terminal V14

   V20 virtual switch in push button mode, for on demand OTA

   V21 RUNning virtual LED

   V26 virtual switch in push button mode, to activate HTTP file OTA on demand via boolean HTTP_OTA variable that activate in the loop V26

*/

const char* ssid = "xxxxxx"; /// put your AP SSID here
const char* password = "xxxxxxxxx"; /// put your AP PASSWORD oy KEY here

#define HARDWARE_LED 2 /// GPIO02 /// D4 /// change according where your ESP8266 board LED is connected to 

#include <ESP8266WiFi.h>

/// OTA dependencies ///
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

/// HTTP OTA dependencies ///
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#include <WiFiClient.h>
WiFiClient client;

//------------------------ IP ----------------------------

char server[] = "192.168.0.100";  // For WiFi - IP for your Local Server
IPAddress gateway_ip(192, 168, 0, 254);
IPAddress subnet_mask(255, 255, 255, 0);
//IPAddress ipMCU(192, 168, 0, 58);
int port = 8088;
String MyIp;


/*
  /// WiFiManager dependencies /// if you want WiFi Manager otherwise delete the line(s) bellow
  #include <DNSServer.h>            //Local DNS Server used for redirecting all requests to the configuration portal
  #include <ESP8266WebServer.h>     //Local WebServer used to serve the configuration portal
  #include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager WiFi Configuration Magic
*/

/// blynk dependencies ///
#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space
/// it is used above /// #include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "__SZhT8csGgCSVMLY4p4dTTR21pvLsV4";

// Attach virtual serial terminal to Virtual Pin V14
WidgetTerminal terminal(V14);

WidgetLED led0(V21);

/// SimpleTimer timer;
BlynkTimer timer;

/*
  /// start of WiFiManager Global Start here...  /// if you want WiFi Manager otherwise delete the line(s) bellow
  WiFiManager wifiManager;
*/

/// switch value to control if the WeMos internal led will be blinking if HIGH or not if LOW ///
boolean ledBlink = true;

/// timestamp variable to keep track of millis() unsigned long ticks = millis() / 1000;  That is for debugging printings ///
unsigned long timestamp;

/// for HTTP based file OTA update ///
bool HTTP_OTA = false; /// we control this boolean variable through V26 switch that is in push button mode

/// START routine for manual (on demand) requesting HTTP file OTA. Virtual Button SW V26 is used ///
BLYNK_WRITE(V26)
{
  if (param.asInt()) {
    HTTP_OTA = true;
  }
  else {
    HTTP_OTA = false;
  }
}
/// END routine for manual (on demend) requesting HTTP file OTA. Virtual Button SW V15 is used ///

/// START of SimpleTimer timer activating function blinkLedWidget ///
void blinkLedWidget()
{
  if (led0.getValue()) {
    led0.off();
    ///BLYNK_LOG("LED0: off");
  } else {
    led0.on();
    ///BLYNK_LOG("LED0: on");
  }
  /// END of SimpleTimer timer activating function blinkLedWidget ///

  /// put the routine here to blink WeMos LED (D4) each ? second(s), using the "control software switch" ledBlink ///
  if (ledBlink)
  { int test = digitalRead(HARDWARE_LED); /// Could also be : pinMode(BUILTIN_LED, OUTPUT); OR digitalRead(BUILTIN_LED);  /// onboard LED as output
    digitalWrite(HARDWARE_LED, !test);
  }
}

/// Start of main function that performs HTTP OTA ///
void checkForUpdates() {
  uint8_t mac[6];
  char macAddr[14];
  WiFi.macAddress( mac );
  ///sprintf(macAddr,"%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); /// small letters at MAC address
  sprintf(macAddr, "%02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); /// capital letters at MAC address
  ///terminal.println(macAddr);
  Blynk.virtualWrite(V14, macAddr);
  String fwURL = String( fwUrlBase );
  fwURL.concat( macAddr );
  String fwVersionURL = fwURL;
  fwVersionURL.concat( ".version" );
  Serial.println( "Checking for firmware updates." );
  Serial.print( "MAC address: " );
  Serial.println( macAddr );
  Blynk.virtualWrite(V14, "\nChecking for firmware updates.\nMAC address: ");
  Blynk.virtualWrite(V14, macAddr);
  Serial.print( "Firmware version URL: " );
  Serial.println( fwVersionURL );
  Blynk.virtualWrite(V14, "\nFirmware version URL: ");
  Blynk.virtualWrite(V14, fwVersionURL);
  HTTPClient httpClient;
  httpClient.begin( client, fwVersionURL );
  int httpCode = httpClient.GET();
  if ( httpCode == 200 ) {
    String newFWVersion = httpClient.getString();
    Serial.print( "Current firmware version: " );
    Serial.println( FW_VERSION );
    Serial.print( "Available firmware version: " );
    Serial.println( newFWVersion );
    Blynk.virtualWrite(V14, "\nCurrent firmware version: ");
    Blynk.virtualWrite(V14, FW_VERSION);
    Blynk.virtualWrite(V14, "\nAvailable firmware version: ");
    Blynk.virtualWrite(V14, newFWVersion);
    int newVersion = newFWVersion.toInt();
    if ( newVersion > FW_VERSION ) {
      Serial.println( "Preparing to update" );
      Blynk.virtualWrite(V14, "\nPreparing to update");
      String fwImageURL = fwURL;
      fwImageURL.concat( ".bin" );
      t_httpUpdate_return ret = ESPhttpUpdate.update( client, fwImageURL );
      switch (ret) {
        case HTTP_UPDATE_FAILED:
          Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
          char currentString[64];
          sprintf(currentString, "\nHTTP_UPDATE_FAILD Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
          Blynk.virtualWrite(V14, currentString);
          break;

        case HTTP_UPDATE_NO_UPDATES:
          Serial.println("HTTP_UPDATE_NO_UPDATES");
          Blynk.virtualWrite(V14, "\nHTTP_UPDATE_NO_UPDATES\n");
          break;
      }
    }
    else {
      Serial.println( "Already on latest version" );
      Blynk.virtualWrite(V14, "\nAlready on latest version\n");
    }
  }
  else {
    Serial.print( "Firmware version check failed, got HTTP response code " );
    Serial.println( httpCode );
    char currentString[64];
    sprintf(currentString, "\nFirmware version check failed, got HTTP response code : %d\n", httpCode);
    Blynk.virtualWrite(V14, currentString);
  }
  httpClient.end();
}
/// End of main function that performs HTTP OTA ///


/// START OF SETUP ///
void setup() {
  Serial.begin(115200);
  Serial.println("Booting...");

  /// on board LED ///
  pinMode(HARDWARE_LED, OUTPUT);

  /*
    /// if you want WiFi Manager otherwise delete the line(s) bellow
    WiFi.persistent(false);
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    delay(100);
  */

  WiFi.begin(ssid, password);
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("Connecting to Wifi AP...");
    for ( int i = 0; i < 300; i++) {                  ///       try to connect to WiFi for max 30s
      if (WiFi.status() == WL_CONNECTED) {
        Serial.printf("it is connected after %d seconds", (i / 10));
        break;
      }
      yield();
      delay(100);
    }
  }
  if (WiFi.status() == WL_CONNECTED) {
    //if you get here you have connected to the WiFi
    Serial.println("\nconnected...yesss! :)");
  } else {
    Serial.println("TimeOut! Not Connected even after 10 Seconds trying...\n *** Something wrong happened. It did not connected... *** ");
  }

  /*
    /// if you want WiFi Manager otherwise delete the line(s) bellow
    wifiManager.autoConnect("AutoConnectAP");
  */

  //if you get here you have connected to the WiFi
  Serial.println("connected...yesss! :)");

  ArduinoOTA.onStart([]() {
    Serial.println("Start");
  });

  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });

  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });

  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });

  ArduinoOTA.begin();
  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  unsigned long maxMillis = millis() + 50000;
  
  Blynk.config(auth, server, port);  // For WiFi

  Serial.println(" Trying to connected to Blynk... ");
  Serial.printf(" Enter millis is: %d\n", millis());
  ///while ((Blynk.connect() == false) && ( millis() < maxMillis)) {
  do {
    // Wait until connected or 10 seconds passed without connection ( maxMillis )
    if (Blynk.connect() == true) {
      Serial.println(" Blynk is connected !!! ... ");
      Serial.printf(" Break millis is: %d\n", millis());
      break;
    }
    yield();
    delay(200);
  } while ((Blynk.connect() == false) && ( millis() < maxMillis));
  Serial.printf(" Exit millis is: %d\n", millis());
  if (Blynk.connect() == false) Serial.println(" Not Connected to Blynk. Something wrong happens... ");
  if (Blynk.connect() == true) Serial.println(" Blynk is connected!!! ... ");

  pinMode(HARDWARE_LED, OUTPUT);  // initialize onboard LED as output
  digitalWrite(HARDWARE_LED, HIGH); // dim the LED
  Serial.println(FW_VERSION);
  Blynk.virtualWrite(V14, FW_VERSION);

  /// start of SimpleTimer timer Functions
  /// This blink LED function be called every 2 seconds
  timer.setInterval(2000L, blinkLedWidget);
  /// end of SimpleTimer timer Functions
}
/// END OF SETUP ///

/// start routine for V1 controlling ledBlink boolean global variable ///
BLYNK_WRITE(V0)
{ char currentMillis[64];
  if (param.asInt()) {
    sprintf(currentMillis, "\n\n Enter millis()= %d", millis());
    Blynk.virtualWrite(V14, currentMillis);
    ledBlink = true;
    digitalWrite(HARDWARE_LED, HIGH); /// switch off the internal LED
  }
  else {
    sprintf(currentMillis, "\n\n Exit  millis()= %d", millis());
    Blynk.virtualWrite(V14, currentMillis);
    ledBlink = false;
    digitalWrite(HARDWARE_LED, HIGH); /// switch on the internal LED
  }
}
/// end of routine for V1 controlling ledBlink boolean global variable ///

/// start routine for manual (on demand) requesting OTA The Virtual Button SW V20 is used ///
BLYNK_WRITE(V20)
{
  if (param.asInt()) {
    ArduinoOTA.handle();
  }
}
/// end of routine for manual (on demand) requesting OTA The Virtual Button SW V20 is used ///

// This function will run every time Blynk connection is established
BLYNK_CONNECTED() {
  ///   if (isFirstConnect) {
  //     Request Blynk server to re-send latest values for all pins
  /// }
  Blynk.syncAll();
}

/// START OF LOOP ///

void loop() {
  ArduinoOTA.handle();
  if (HTTP_OTA) {
    /// shall I stop timers and Blynk related in order to ensure succesful WEB OTA ??? ///
    checkForUpdates();
  } /// We need this in order to do WEB file OTA update ///

  Blynk.run();
  timer.run();
}
/// END OF LOOP ///

No, I mean what does your 807D3A592CC7.version file contain.

Pete.

It contains the export of my sketch from arduino IDE that I renamed
2020-05-15_182504

2020-05-15_182145

Checking for firmware updates.
MAC address: 807D3A592CC7
Firmware version URL: http://192.168.0.100:8000/.fota/807D3A592CC7.version
httpCode 200
Current firmware version: 2020051502
Available firmware version: 
Already on latest version

httpClient.getString() retrurn nothing

I don’t use this particular method for HTTP updates, but looking at the original article it seems that the .version file should hold just the version number (6 bytes of data in this screenshot, value “1234”)…

image
image

Pete.

If I well understand, I need two files, .bin and .version ?
the .version isn’t the .bin renamed ?
I think I missed something :rofl:

For sure you need two files…

No it can be bigger as in my example that is working fine quite a long time