cotestatnt / AsyncTelegram2

Powerful, flexible and secure Arduino Telegram BOT library. Hardware independent, it can be used with any MCU capable of handling an SSL connection.
MIT License
85 stars 25 forks source link

Firmware update fails to restart #101

Closed pablopeu closed 1 year ago

pablopeu commented 1 year ago

Hi @cotestatnt , using your example for the firmware update I managed to make it work in my program, well almost, firmware updates correctly, but after finishing it fails to restart the ESP8266:

image

I can see the progress in serial monitor:

` Cargado 532480 de 548736 bytes... Cargado 540672 de 548736 bytes... Cargado 548736 de 548736 bytes... Flash Completo!

Unable to connect to Telegram server `

And after a few seconds its unable to connect to the server thus not reaching the point in the program where it restarts I guess. This is the code where it shows the flash complete, its your code but translated to spanish:

` t_httpUpdate_return ret = UPDATER.update(client, file_path); Serial.println("Flash Completo!"); // this is the last activity client.stop();

switch (ret) { case HTTP_UPDATE_FAILED: report = "HTTP_UPDATE_FALLIDO. Error ("; report += UPDATER.getLastError(); report += "): "; report += UPDATER.getLastErrorString(); myBot.sendTo(userid, report.c_str()); break;

case HTTP_UPDATE_NO_UPDATES:
  myBot.sendTo(userid, "HTTP_UPDATE_NO_UPDATES");
  break;

case HTTP_UPDATE_OK:
  myBot.begin();
  myBot.sendTo(userid, "UPDATE OK.\nReiniciando en unos segundos...");
  // Wait until bot synced with telegram to prevent cyclic reboot
  while (!myBot.noNewMessage()) {
    Serial.print(".");
    delay(50);
  }
  ESP.restart();

  break;
default:
  break;`

Thanks!!! PS: just to add context, with your untouched example and the same bin file it does the same. Updates but no restart.

cotestatnt commented 1 year ago

Hi @pablopeu Maybe something gets broken with latest updates. I will check as soon as possible

cotestatnt commented 1 year ago

Good morning @pablopeu I've tested the sketch ButtonQuery.ino and I have the same issue. It's not clear to me why ESP8266 do this (ESP32 work flawlessy), but it seems that the restart instruction inside the update handler don't work as it should.

Anyway, if you move the restart handling in the main loop using a bool flag in order to check when perform restart, it works. Try this:

/*
  Name:        OTA_buttonQuery.ino
  Created:     29/03/2021
  Author:       Tolentino Cotesta <cotestatnt@yahoo.com>
  Description: an example that check for incoming messages
              and install rom update remotely.
*/
#include <AsyncTelegram2.h>
#ifndef LED_BUILTIN
#define LED_BUILTIN 2
#endif

// Timezone definition
#define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3"
#include <time.h>

#ifdef ESP8266
#include <ESP8266WiFi.h>
  #include <ESP8266HTTPClient.h>
  #include <ESP8266httpUpdate.h>
  #define UPDATER ESPhttpUpdate
  Session   session;
  X509List  certificate(telegram_cert);
#elif defined(ESP32)
  #include <HTTPClient.h>
  #include <HTTPUpdate.h>
  #define UPDATER httpUpdate
#endif

WiFiClientSecure client;
AsyncTelegram2 myBot(client);
const char* ssid  =  "xxxxxx";     // SSID WiFi network
const char* pass  =  "xxxxxxx";     // Password  WiFi network
const char* token =  "xxxxxxxxxxxxx:xxxxxxxxxxxxx";  // Telegram token

// Check the userid with the help of bot @JsonDumpBot or @getidsbot (work also with groups)
// https://t.me/JsonDumpBot  or  https://t.me/getidsbot
int64_t userid = 123456789;

#define CANCEL  "CANCEL"
#define CONFIRM "FLASH_FW"

const char* firmware_version = __TIME__;
bool reset = false;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(115200);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);
  delay(500);

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(100);
  }

#ifdef ESP8266
  // Sync time with NTP, to check properly Telegram certificate
  configTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org");
  //Set ceritficate, session and some other base client properies
  client.setSession(&session);
  client.setTrustAnchors(&certificate);
  client.setBufferSizes(1024, 1024);
#elif defined(ESP32)
  // Sync time with NTP
  configTzTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org");
  client.setCACert(telegram_cert);
#endif

  // Set the Telegram bot properies
  myBot.setUpdateTime(2000);
  myBot.setTelegramToken(token);

  // Check if all things are ok
  Serial.print("\nTest Telegram connection... ");
  myBot.begin() ? Serial.println("OK") : Serial.println("NOK");

  char welcome_msg[128];
  snprintf(welcome_msg, 128, "BOT @%s online\n/help all commands avalaible.", myBot.getBotName());
  myBot.sendTo(userid, welcome_msg);

  // We have to handle reboot manually after sync with TG server
  UPDATER.rebootOnUpdate(false);
}

void loop() {
  if (reset) {
    reset = false;
    // Wait until bot synced with telegram to prevent cyclic reboot
    while (!myBot.noNewMessage()) {
      Serial.print(".");
      delay(50);
    }
    Serial.println("ESP reset...");
    delay(10);
    ESP.reset();
  }

  static uint32_t ledTime = millis();
  if (millis() - ledTime > 300) {
    ledTime = millis();
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  }

  // a variable to store telegram message data
  TBMessage msg;

  // if there is an incoming message...
  if (myBot.getNewMessage(msg)) {
    String tgReply;
    static String document;

    switch (msg.messageType) {
      case MessageDocument :
        document = msg.document.file_path;
        if (msg.document.file_exists) {

          // Check file extension of received document (firmware MUST be .bin)
          if (document.endsWith(".bin") > -1 ) {
            String report = "Start firmware update?\nFile name: "
                            + String(msg.document.file_name)
                            + "\nFile size: "
                            + String(msg.document.file_size);

            // Query user for flash confirmation
            InlineKeyboard confirmKbd;
            confirmKbd.addButton("FLASH", CONFIRM, KeyboardButtonQuery);
            confirmKbd.addButton("CANCEL", CANCEL, KeyboardButtonQuery);
            myBot.sendMessage(msg, report.c_str(), confirmKbd);
          }
        }
        else {
          myBot.sendMessage(msg, "File is unavailable. Maybe size limit 20MB was reached or file deleted");
        }
        break;

      case MessageQuery:
        // received a callback query message
        tgReply = msg.callbackQueryData;

        // User has confirmed flash start
        if (tgReply.equalsIgnoreCase(CONFIRM)) {
          myBot.endQuery(msg, "Start flashing... please wait (~30/60s)", true);
          handleUpdate(msg, document);
          document.clear();
        }
        // User has canceled the command
        else if (tgReply.equalsIgnoreCase(CANCEL)) {
          myBot.endQuery(msg, "Flashing canceled");
        }
        break;

      default:
        tgReply = msg.text;
        if (tgReply.equalsIgnoreCase("/version")) {
          String fw = "Version: " ;
          fw += firmware_version;
          myBot.sendMessage(msg, fw);
        }
        else {
          myBot.sendMessage(msg, "Send firmware binary file ###.bin to start update\n"
                            "/version for print the current firmware version\n");
        }
        break;
    }
  }
}

// Install firmware update
void handleUpdate(TBMessage msg, String &file_path) {
  // Create client for rom download
  WiFiClientSecure client;
  client.setInsecure();

  String report;
  Serial.print("Firmware path: ");
  Serial.println(file_path);

  // On a good connection the LED should flash regularly. On a bad connection the LED will be
  // on much longer than it will be off. Other pins than LED_BUILTIN may be used. The second
  // value is used to put the LED on. If the LED is on with HIGH, that value should be passed
  UPDATER.setLedPin(LED_BUILTIN, LOW);

  UPDATER.onProgress([](int cur, int total) {
    static uint32_t sendT;
    if (millis() - sendT > 1000) {
      sendT = millis();
      Serial.printf("Updating %d of %d bytes...\n", cur, total);
    }
  });

  t_httpUpdate_return ret = UPDATER.update(client, file_path);
  Serial.println("Update done!");
  client.stop();

  switch (ret) {
    case HTTP_UPDATE_FAILED:
      report = "HTTP_UPDATE_FAILED Error (";
      report += UPDATER.getLastError();
      report += "): ";
      report += UPDATER.getLastErrorString();
      myBot.sendMessage(msg, report.c_str());
      break;

    case HTTP_UPDATE_NO_UPDATES:
      myBot.sendMessage(msg, "HTTP_UPDATE_NO_UPDATES");
      break;

    case HTTP_UPDATE_OK:
      myBot.sendMessage(msg, "UPDATE OK.\nRestarting in few seconds...");
      reset = true;
      break;
    default:
      break;
  }
}