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

That is your problem. Needs to be < 50%.

Which MCU are you using?

@iBK: ESP12E

In board settings you should be able to increase flash size to 1MB.

@IBK: That is means flash size 4MB(1MB SPIFFS) right.

Yes, but it will only give 1MB max sketch size. You should then be good to go.

Hi Mike

Sorry for be a newbie but I have a question

Thanks for your imputs :slight_smile:

When you have a ESP8266 making Self-updating i always end with manual reset the unit, how to make this automatic without adding a extra hardware on my board ?

Preben

Dear @Pgran,
sorry but I am not sure what do you mean. Normally, when you do ā€œhttpā€ file firmware update also known as FOTA, the ESP8266 set at a special mode that when the FOTA completed normally, reset itself then and restarted with the new firmware, your new compiled Sketch + libraries + Arduino ESP8266 Core.
What doesnā€™t go this way at your project?

Best Regards,
Mike Kranidis

Hi Mike
I know I am doing this wrongā€¦

I like to see the full working version, in the bottom I have a working esp8266 sketch with download but demand manual reset to work.

I like to make total remote OTA, no human involved. ā€¦ Thanks in advance :slight_smile:

const int FW_VERSION = 2017102501 ; /// year_month_day_same day release number
const char* fwUrlBase = "http://yourserver/.fota/";
bool HTTP_OTA = false;
/// V26 switch to activate HTTP file OTA on demand via boolean HTTP_OTA variable that activate in the loop V26 ///

/// 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 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);
  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 );
  ///terminal.printf("\nChecking for firmware updates.\nMAC address: %s ",mac);
  terminal.printf("\nChecking for firmware updates.\nMAC address: ");
  terminal.print( macAddr );
  Serial.print( "Firmware version URL: " );
  Serial.println( fwVersionURL );
  ///terminal.printf("\nFirmware version URL: %s ",fwVersionURL);
  terminal.printf("\nFirmware version URL: ");
  terminal.print(fwVersionURL);
  terminal.flush();

  HTTPClient httpClient;
  httpClient.begin( 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 );
    ///terminal.printf("\nCurrent firmware version: %s  Available firmware version: %s ",FW_VERSION,newFWVersion);
    terminal.print("\nCurrent firmware version: ");
    terminal.print(FW_VERSION);  
    terminal.print("\nAvailable firmware version: ");
    terminal.println(newFWVersion);
    terminal.flush();
    int newVersion = newFWVersion.toInt();

    if( newVersion > FW_VERSION ) {
      Serial.println( "Preparing to update" );
    terminal.println( "\nPreparing to update" ); 
    terminal.flush();
      String fwImageURL = fwURL;
      fwImageURL.concat( ".bin" );
      t_httpUpdate_return ret = ESPhttpUpdate.update( fwImageURL );

      switch(ret) {
        case HTTP_UPDATE_FAILED:
          Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
          terminal.printf("\nHTTP_UPDATE_FAILD Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
          terminal.flush();
          break;

        case HTTP_UPDATE_NO_UPDATES:
          Serial.println("HTTP_UPDATE_NO_UPDATES");
          terminal.println("\nHTTP_UPDATE_NO_UPDATES\n");
          terminal.flush();
          break;
      }
    }
    else {
      Serial.println( "Already on latest version" );
      terminal.println( "\nAlready on latest version\n" );
      terminal.flush();
    }
  }
  else {
    Serial.print( "Firmware version check failed, got HTTP response code " );
    Serial.println( httpCode );
    terminal.printf( "\nFirmware version check failed, got HTTP response code : %d\n",httpCode );
    terminal.flush();
  }
  httpClient.end();
}
/// End of main function that performs HTTP OTA /// 

/// YOU NEED SOMEWHERE THIS, I PUT IT on LOOP
if(HTTP_OTA) {
    /// shall I stop timers and Blynk related in order to ensure succesful WEB OTA ??? ///
    checkForUpdates();

I have this running:

#include <Arduino.h>

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>

#define USE_SERIAL Serial

ESP8266WiFiMulti WiFiMulti;

void setup() {

    USE_SERIAL.begin(115200);
    // USE_SERIAL.setDebugOutput(true);

    USE_SERIAL.println();
    USE_SERIAL.println();
    USE_SERIAL.println();

    for(uint8_t t = 4; t > 0; t--) {
        USE_SERIAL.printf("[SETUP] WAIT %d...\n", t);
        USE_SERIAL.flush();
        delay(1000);
    }

    
    WiFiMulti.addAP("x", "xx");

}

void loop() {
    // wait for WiFi connection
    if((WiFiMulti.run() == WL_CONNECTED)) {

        t_httpUpdate_return ret = ESPhttpUpdate.update("http://xxxxxxxxxx.com/Blink.ino.generic.bin");
        

        switch(ret) {
        
            case HTTP_UPDATE_FAILED:
                USE_SERIAL.printf("HTTP_UPDATE_FAILD Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
                +"/n";
                break;

            case HTTP_UPDATE_NO_UPDATES:
                USE_SERIAL.println("HTTP_UPDATE_NO_UPDATES");
                break;

            case HTTP_UPDATE_OK:
            
                USE_SERIAL.println("HTTP_UPDATE_OK");
                ESP.restart();
                break;
        }
    }
}

Dear @Pgran,
so you need someone to combine your code and the HTTP OTA in one sketch, right?
I am busy right now but I will try it when I have time.

Hi Mike

Thanks for your always quick answer :slight_smile:

I like your HTTP OTA sketch but canĀ“t get it to work, i like the file verification and everything but canĀ“t get it running so I can program the rest of my sketch.

I just need the #includeĀ“s and the void setup() settings and I am sure is working ā€¦
Sorry for be that newbie ā€¦ Thanks that will help me a lot :slight_smile:
Best Regards,
Preben

ok I understood . I will try to make a ā€œtemplateā€ like sketch for you. Give me a little time I canā€™t nowā€¦

1 Like

Thanks Mike :+1:

Dear @Pgran
try the following as a general template. Donā€™t forget to put the correct values in the specified fields, read the comments. As a general suggestion: READ THE COMMENTS
Let me know if that is working for you.

const char* fwUrlBase = "http://yourserver.com/.fota/"; /// put your server URL where the *.bin & *.version files are saved in your http ( Apache? ) server
const int FW_VERSION = 2019041701 ; /// 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 = "mywifiap"; /// put your AP SSID here
const char* password = "12345678"; /// 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;

/*
/// 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[] = "puthereyourBlynkAUTHnumber";

// 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);
    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(V1)
  { 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 ///
5 Likes

Mr. Mike ā€¦ THANKS !!, now everything is now working !!! :+1::+1::+1::+1::+1: Preben

1 Like

I am very glad to read that now you have a working http FOTA.
Best Regards,
Mike Kranidis

1 Like

FOR THE ESP32:

const char* fwUrlBase = "http://yourserver.com/.fota/"; /// put your server URL where the *.bin & *.version files are saved in your http ( Apache? ) server
const int FW_VERSION = 2019041802 ; /// year_month_day_counternumber 2019 is the year, 04 is the month, 17 is the day 01 is the in day release

#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 = "mywifiap"; /// put your AP SSID here
const char* password = "12345678"; /// put your AP PASSWORD oy KEY here


#define HARDWARE_LED 5 /// GPIO05 /// sparkfun ESP32 thing LED

/// ESP32 HTTP OTA dependencies ///
#include <Arduino.h> /// FOR ESP32 HTTP FOTA UPDATE ///
#include <WiFi.h> /// FOR ESP32 
#include <HTTPClient.h> /// FOR ESP32 HTTP FOTA UPDATE ///
#include <HTTPUpdate.h> /// FOR ESP32 HTTP FOTA UPDATE ///
#include <WiFiClient.h> /// FOR ESP32 HTTP FOTA UPDATE ///
WiFiClient client;  /// FOR ESP32 HTTP FOTA UPDATE ///

/// blynk dependencies ///
#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space
#include <BlynkSimpleEsp32.h> /// FOR ESP32

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

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

WidgetLED led0(V21);

/// SimpleTimer timer;
BlynkTimer timer;

/// 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 = httpUpdate.update( client, fwImageURL ); /// FOR ESP32 HTTP FOTA
      switch(ret) {
        case HTTP_UPDATE_FAILED:
          Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str()); /// FOR ESP32
          char currentString[64];
          sprintf(currentString, "\nHTTP_UPDATE_FAILD Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str()); /// FOR ESP32
          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);
  
  WiFi.mode(WIFI_STA);
  Serial.println(WiFi.macAddress()); /// PRINT MAC ADDRESS TO SERIAL ... use this in order to see the MAC Address that is used for the http FOTA update 

  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... *** ");
  }  

/// Blynk.begin(auth, ssid, password);
  //if you get here you have connected to the WiFi
  Serial.println("connected...yesss! :)");
  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  unsigned long maxMillis=millis() + 50000;
  Blynk.config(auth);
    Serial.println(" Trying to connected to Blynk... ");
    Serial.printf(" Enter millis is: %d\n",millis());
    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(V1)
  { 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(); /// ESP8266 OTA
    }
  }
/// 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() {
  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 ///


3 Likes

FOR ESP32 HTTP FOTA, Please see post: Self-updating ( from WEB server HTTP ) OTA firmware for ESP8266 AND ESP32!

@Gunner @PeteKnight If it possible for an admin, please edit the first post and put this link in the first lines. Thanks

Done - Pete. Thanks a lot Pete!

1 Like

Hi Mike

I still fight with the need of reset.
When I update with our code everything work and it reboots the new version, when I want to update again it need hardware reset before I am allow doing it.
I have been seeking for that at it seems that its general problem, do you have any advice? :wink:
Thanks Preben

Hello @Pgran,
the template that I shared with you is a fully 100% working automatic FOTA update over HTTP server. I run it in my numerous projects all without any problem ( these days, for both ESP8266 that are the majority and ESP32. ). I suspect something wrong with your sketch then. So please post your full sketch here ( without the sensitive information like Blynk AUTH etc ) to look at this at my first free time.
B.R.

I might be barking up the wrong tree but here goes.

Every time you flash an OTA sketch to an ESP the ESP requires a manual reboot before it will work. Once you have done the initial flash you never need to manually reset the ESP again if you update via OTA but if you flash the ESP at a later date it will require the manual reset.

Some people consider the first manual reset to be an Espressif bug but their argument is that it reflects the real world use of their MCUā€™s i.e. I flash an OTA sketch to an ESP and then I send the device to you by mail. In doing this the MCU will have naturally had the required manual reset when you power it up following receipt from the postie.

1 Like