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
84 stars 25 forks source link

Works for about 30 minutes. #13

Closed pablopeu closed 3 years ago

pablopeu commented 3 years ago

My project uses an esp8266 to do two things, announce via broadcast UDP and via telegram message that the doorbell button was pressed. The UDP part works every time, but the telegram bot always work at startup but around 30 minutes after start, telegram messages are no longer delivered. Check the screen capture, time is in 24hs format and I wrote the last message to simply show the timestamp.

Is there something I need to do to keep the telegram bot session alive?

Messages are sent using: myBot.sendTo(userid, "Timbre...!");

Thanks!

image

cotestatnt commented 3 years ago

Hi @pablopeu Thanks for your feedback! I will try to simulate this behaviour as soon as possible. In the meantime, could you enable serial logging for library (AsyncTelegram2.h) in order to have some additional information?

pablopeu commented 3 years ago

Hi Tolentino, you mean esp8266 debugging? I could not find the option to log for a specific library. Please let me know. Thanks

On Mon, Jul 26, 2021 at 8:19 AM Tolentino Cotesta @.***> wrote:

Hi @pablopeu https://github.com/pablopeu Thanks for your feedback! I will try to simulate this behaviour as soon as possible. In the meantime, could you enable serial logging for library (AsyncTelegram2.h) in order to have some additional information?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/cotestatnt/AsyncTelegram2/issues/13#issuecomment-886613460, or unsubscribe https://github.com/notifications/unsubscribe-auth/AGEW43BVYVBX6O3XX6VJNYLTZVAFRANCNFSM5A7IFLHA .

cotestatnt commented 3 years ago

Here (inside you Arduino libraries folder) https://github.com/cotestatnt/AsyncTelegram2/blob/main/src/AsyncTelegram2.h#L20

pablopeu commented 3 years ago

There is not much debug info while running, I edited out my bot details. Again, after about 30 minutes udp keeps announcing the button press, but the bot doesn't receive the message.

I'm using wifimanager instead of hardcoding the wifi settings.

*WM: AutoConnect
*WM: Connecting as wifi client...
*WM: Status:
*WM: 0
*WM: Using last saved values, should be faster
*WM: Connection result: 
*WM: 3
*WM: IP Address:
*WM: 192.168.1.99
Abriendo puerto UDP...9999

Test Telegram connection... 
[D][AsyncTelegram2.cpp:36] checkConnection():   Start handshaking...
[D][AsyncTelegram2.cpp:42] checkConnection():   Connected using Telegram hostname
Last connection was 7 seconds ago

[D][AsyncTelegram2.cpp:268] getMe():    
{
  "ok": true,
  "result": {
    "id": 1843xxxxx, //EDITED
    "is_bot": true,
    "first_name": "xxxxx", //EDITED
    "username": "xxxxxx", //EDITED
    "can_join_groups": true,
    "can_read_all_group_messages": false,
    "supports_inline_queries": false
  }
}
OK
Bot name: @xxxx //EDITED

[D][AsyncTelegram2.cpp:347] sendMessage():  
{
  "chat_id": xxxxx, //EDITED
  "text": "Arranque del anunciador"
}
Arranque del anunciador
*WM: freeing allocated params!
*WM: freeing allocated params!
Duracion del pulso: 158

[D][AsyncTelegram2.cpp:347] sendMessage():  
{
  "chat_id": xxxx, //EDITED
  "text": "Timbre...!"
cotestatnt commented 3 years ago

I'm trying to reproduce this issue from my side, but the sketch is now up and running since 4 hours sending a message every 5 minutes. I need some additional info: wich version of library are you using? Wich version of esp8266 Arduino core? I' m using the last avalaible for both. Finally, if you want, share the whole code (without sensitive data of course) please.

pablopeu commented 3 years ago

Glad to read that, can you share that sample code so I can test it on my side too, that way is easier to debug methinks.

cotestatnt commented 3 years ago

Yes, for sure! It is basically the keyboards.ino example (the first i've opened) with the addition of "timed" message every 300 seconds to my userid.

https://gist.github.com/cotestatnt/eff3d2acbbf6c57410c6ebfc1764eef4

This is my setup for Arduino IDE (I haven't nodeMCU board actually)

pablopeu commented 3 years ago

let me edit the private details and send you my program

pablopeu commented 3 years ago
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#include <WiFiManager.h>  
#include "Button2.h";
#include <ArduinoOTA.h>
#include <AsyncTelegram2.h>
#include <time.h>

// Telegram BOT Token (Get from Botfather)
const char* token =  "xxx";  // Telegram token

// timer para mandar señal de estoy vivo
unsigned long alive=0;
unsigned long unahora=3600000;
unsigned long estoyvivo=0;

#define USE_CLIENTSSL true  
#define MYTZ "UTC+3" //timezone https://sites.google.com/a/usapiens.com/opnode/time-zones

  BearSSL::WiFiClientSecure client;
  BearSSL::Session   session;
  BearSSL::X509List  certificate(telegram_cert);
  AsyncTelegram2 myBot(client);

// Use @myidbot (IDBot) to find out the chat ID of an individual or a group
// Also note that you need to click "start" on a bot before it can
// message you
int64_t userid = 9999999; // sin poner ID de grupo o de usuario no funciona

#define BUTTON_PIN  4
Button2 button = Button2(BUTTON_PIN);

// UDP
WiFiUDP UDP;
IPAddress broadcastIp(255,255,255,255);
IPAddress netmask(255, 255, 255, 0);
#define UDP_PORT 9999

const char* mensaje="DaleRojo"; // poner aca el mensaje broadcasteado 

void setup() {
  Serial.begin(115200);
  Serial.println();

//inicializar las entradas y salidas
  button.setReleasedHandler(released);
  pinMode(LED_BUILTIN, OUTPUT);

// inicio de configuracion wifi

  WiFi.hostname("Anunciador");
  WiFiManager wifi;             //WiFiManager local initialization
  WiFiManager wifiManager;
  wifiManager.setTimeout(30);
  wifiManager.setAPCallback(configModeCallback);
  wifiManager.autoConnect("Timbre-Anunciador");

// Begin UDP port
  UDP.begin(UDP_PORT);
  Serial.print("Abriendo puerto UDP...");
  Serial.println(UDP_PORT);

  //OTA
ArduinoOTA.setHostname("Timbre-Anunciador");
ArduinoOTA.begin();

  // Sync time with NTP, to check properly Telegram certificate
  configTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org");
  time_t now = time(nullptr);

  //Set certficate, session and some other base client properies
  client.setSession(&session);
  client.setTrustAnchors(&certificate);
  client.setBufferSizes(1024, 1024);

  // 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");

  Serial.print("Bot name: @");
  Serial.println(myBot.getBotName());

  myBot.sendTo(userid, "Arranque del anunciador");
  Serial.println("Arranque del anunciador");

}

void loop() {
  ArduinoOTA.handle();
  button.loop();

  if (millis() - estoyvivo >= 1000){
    digitalWrite(LED_BUILTIN, LOW);   // turn the LED on (HIGH is the voltage level)
    delay(200);                       // wait for a second
    digitalWrite(LED_BUILTIN, HIGH);    // turn the LED off by making the voltage LOW
    estoyvivo=millis();
  }

  if (millis() - alive >= unahora){

      // Send Packet
      UDP.beginPacket(broadcastIp, UDP_PORT);
      UDP.write("EstoyVivo");
      UDP.endPacket();    
      myBot.sendTo(userid, "EstoyVivo");
      Serial.print("EstoyVivo // ");
      Serial.println(millis());
      alive=millis();

  }
}

void configModeCallback (WiFiManager *myWiFiManager) {
  Serial.println("Entered config mode");
  Serial.println(WiFi.softAPIP());
  //if you used auto generated SSID, print it
  Serial.println(myWiFiManager->getConfigPortalSSID());
}

void released(Button2& btn) {
  unsigned long duracion = btn.wasPressedFor();

  if (duracion > 0 and duracion < 51){ //si es mayor a 50ms gatillar
      Serial.print("Espureo de: ");
      Serial.println(duracion);
  }

  if (duracion > 50){ //si es mayor a 50ms gatillar
      Serial.print("Duracion del pulso: ");
      Serial.println(duracion);    
      Serial.print("Time now ");
      Serial.println(time(&now));
      myBot.sendTo(userid, "Timbre...!");   
      delay(100);
      // Send Packet
      UDP.beginPacket(broadcastIp, UDP_PORT);
      UDP.write(mensaje);
      UDP.endPacket();    

  }
}
pablopeu commented 3 years ago
pablopeu commented 3 years ago

Thanks for the example, modified it so it announces its alive once per hour not every 5 minutes and to use wifimanager (I love wifimanager lol)

will leave it overnight at the office, if It works I will know via telegram ;)

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

#include <ESP8266WiFi.h>
BearSSL::WiFiClientSecure client;
BearSSL::Session   session;
BearSSL::X509List  certificate(telegram_cert);

AsyncTelegram2 myBot(client);

//const char* ssid  =  "xxxxxxxxx";     // SSID WiFi network
//const char* pass  =  "xxxxxxxxx";     // Password  WiFi network
const char* token =  "xxx";     // 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 = 999999;

ReplyKeyboard myReplyKbd;   // reply keyboard object helper
InlineKeyboard myInlineKbd; // inline keyboard object helper
bool isKeyboardActive;      // store if the reply keyboard is shown

#define LIGHT_ON_CALLBACK  "lightON"  // callback data sent when "LIGHT ON" button is pressed
#define LIGHT_OFF_CALLBACK "lightOFF" // callback data sent when "LIGHT OFF" button is pressed
const uint8_t LED = 4;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(LED, OUTPUT);
  // initialize the Serial
  Serial.begin(115200);

  WiFi.hostname("Anunciador");
  WiFiManager wifi;             //WiFiManager local initialization
  WiFiManager wifiManager;
  wifiManager.setTimeout(30);
  wifiManager.setAPCallback(configModeCallback);
  wifiManager.autoConnect("Timbre-Anunciador");

  // Sync time with NTP, to check properly Telegram certificate
  configTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org");
  //Set certficate, session and some other base client properies
  client.setSession(&session);
  client.setTrustAnchors(&certificate);
  client.setBufferSizes(1024, 1024);

  // Set the Telegram bot properties
  myBot.setUpdateTime(1000);
  myBot.setTelegramToken(token);

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

  // Add reply keyboard
  isKeyboardActive = false;
  // add a button that send a message with "Simple button" text
  myReplyKbd.addButton("Button1");
  myReplyKbd.addButton("Button2");
  myReplyKbd.addButton("Button3");
  // add a new empty button row
  myReplyKbd.addRow();
  // add another button that send the user position (location)
  myReplyKbd.addButton("Send Location", KeyboardButtonLocation);
  // add another button that send the user contact
  myReplyKbd.addButton("Send contact", KeyboardButtonContact);
  // add a new empty button row
  myReplyKbd.addRow();
  // add a button that send a message with "Hide replyKeyboard" text
  // (it will be used to hide the reply keyboard)
  myReplyKbd.addButton("/hide_keyboard");
  // resize the keyboard to fit only the needed space
  myReplyKbd.enableResize();

  // Add sample inline keyboard
  myInlineKbd.addButton("ON", LIGHT_ON_CALLBACK, KeyboardButtonQuery);
  myInlineKbd.addButton("OFF", LIGHT_OFF_CALLBACK, KeyboardButtonQuery);
  myInlineKbd.addRow();
  myInlineKbd.addButton("GitHub", "https://github.com/cotestatnt/AsyncTelegram/", KeyboardButtonURL);

  const char* botName = myBot.getBotName();
  Serial.printf("Nome del bot: @%s", botName);

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

void loop() {

  // In the meantime LED_BUILTIN will blink with a fixed frequency
  // to evaluate async and non-blocking working of library
  static uint32_t ledTime = millis();
  if (millis() - ledTime > 200) {
    ledTime = millis();
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  }

  static uint32_t aliveTime = millis();
  if (millis() - aliveTime > 3600000) {
    aliveTime = millis();
    time_t epoch = time(nullptr);
    tm now = *localtime(&epoch);
    char buffer [50];
    strftime (buffer, 50, "Alive: %c", &now);
    myBot.sendTo(userid, buffer);
  }

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

  // if there is an incoming message...
  if (myBot.getNewMessage(msg)) {
    // check what kind of message I received
    MessageType msgType = msg.messageType;
    String msgText = msg.text;

    switch (msgType) {
      case MessageText :
        // received a text message       
        Serial.print("\nText message received: ");
        Serial.println(msgText);

        // check if is show keyboard command
        if (msgText.equalsIgnoreCase("/reply_keyboard")) {
          // the user is asking to show the reply keyboard --> show it
          myBot.sendMessage(msg, "This is reply keyboard:", myReplyKbd);
          isKeyboardActive = true;
        }
        else if (msgText.equalsIgnoreCase("/inline_keyboard")) {
          myBot.sendMessage(msg, "This is inline keyboard:", myInlineKbd);

        }

        // check if the reply keyboard is active
        else if (isKeyboardActive) {
          // is active -> manage the text messages sent by pressing the reply keyboard buttons
          if (msgText.equalsIgnoreCase("/hide_keyboard")) {
            // sent the "hide keyboard" message --> hide the reply keyboard
            myBot.removeReplyKeyboard(msg, "Reply keyboard removed");
            isKeyboardActive = false;
          } else {
            // print every others messages received
            myBot.sendMessage(msg, msg.text);
          }
        } 

        // the user write anything else and the reply keyboard is not active --> show a hint message
        else {          
          myBot.sendMessage(msg, "Try /reply_keyboard or /inline_keyboard");
        }
        break;

      case MessageQuery:
        // received a callback query message
        msgText = msg.callbackQueryData;
        Serial.print("\nCallback query message received: ");
        Serial.println(msgText);

        if (msgText.equalsIgnoreCase(LIGHT_ON_CALLBACK)) {
          // pushed "LIGHT ON" button...
          Serial.println("\nSet light ON");
          digitalWrite(LED, HIGH);
          // terminate the callback with an alert message
          myBot.endQuery(msg, "Light on", true);
        } 
        else if (msgText.equalsIgnoreCase(LIGHT_OFF_CALLBACK)) {
          // pushed "LIGHT OFF" button...
          Serial.println("\nSet light OFF");
          digitalWrite(LED, LOW);
          // terminate the callback with a popup message
          myBot.endQuery(msg, "Light off");
        }

        break;

      case MessageLocation:
        // received a location message --> send a message with the location coordinates
        char bufL[50];
        snprintf(bufL, sizeof(bufL), "Longitude: %f\nLatitude: %f\n", msg.location.longitude, msg.location.latitude) ;
        myBot.sendMessage(msg, bufL);
        Serial.println(bufL);
        break;

      case MessageContact:
        char bufC[50];
        snprintf(bufC, sizeof(bufC), "Contact information received: %s - %s\n", msg.contact.firstName, msg.contact.phoneNumber ) ;
        // received a contact message --> send a message with the contact information
        myBot.sendMessage(msg, bufC);
        Serial.println(bufC);
        break;

      default:
        break;
    }
  }
}

void configModeCallback (WiFiManager *myWiFiManager) {
  Serial.println("Entered config mode");
  Serial.println(WiFi.softAPIP());
  //if you used auto generated SSID, print it
  Serial.println(myWiFiManager->getConfigPortalSSID());
}
pablopeu commented 3 years ago

what I see even before the 1 hour period in the debug date is this:

D][AsyncTelegram2.cpp:151] getUpdates(): Connection closed from server [D][AsyncTelegram2.cpp:36] checkConnection(): Start handshaking... [D][AsyncTelegram2.cpp:42] checkConnection(): Connected using Telegram hostname Last connection was 251 seconds ago

the debug data of my program does not generate the same output.

pablopeu commented 3 years ago

As expected, your program works flawlessly. Can you point me to where the debug information from last post is generated? it seems to be related to keeping the connection alive and this doesn't happen in my program. Thanks!

cotestatnt commented 3 years ago

Hi @pablopeu I suspect your problem is this instructions missing in your loop()

 TBMessage msg;
 myBot.getNewMessage(msg);

Even if you don't need to handle input messages, it is necessary in order to keep connection with Telegram server online. If you don't want to leave it in the main loop, you can try running it just before sending the message. It should work anyway.

pablopeu commented 3 years ago

Hi @cotestatnt thanks for taking the time to review the code. I thought since I only use telegram to announce things this wasn't needed. Will add it and report back. Maybe there is the need for something like a keepalive function for the library for cases like these.

cotestatnt commented 3 years ago

I've tested putting this two lines of code just before sending new message and it works as expected (not in the main loop).

At the end you only need to reconnect to the server and this getNewMessage() do the job.

pablopeu commented 3 years ago

Thanks for helping me out @cotestatnt problem is solved..!

sekharathome commented 2 weeks ago

I have the similar issue. the bot stop responding after some time. using example file echobot The error is:

`Message from @IoTClock_bot:
.n

Unable to connect to Telegram server`

the below code:

/*
  Name:        echoBot.ino
  Created:     26/03/2021
  Author:      Tolentino Cotesta <cotestatnt@yahoo.com>
  Description: a simple example that check for incoming messages
               and reply the sender with the received message.
                 The message will be forwarded also in a public channel
                 anad to a specific userid.
*/

#define` USE_CLIENTSSL false  

#include <AsyncTelegram2.h>

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

#ifdef ESP8266
  #include <ESP8266WiFi.h>
  BearSSL::WiFiClientSecure client;
  BearSSL::Session   session;
  BearSSL::X509List  certificate(telegram_cert);

#elif defined(ESP32)
  #include <WiFi.h>
  #include <WiFiClient.h>
  #if USE_CLIENTSSL
    #include <SSLClient.h>  
    #include "tg_certificate.h"
    WiFiClient base_client;
    SSLClient client(base_client, TAs, (size_t)TAs_NUM, A0, 1, SSLClient::SSL_ERROR);
  #else
    #include <WiFiClientSecure.h>
    WiFiClientSecure client;  
  #endif
#endif

AsyncTelegram2 myBot(client);

const char* ssid  =  "HomeFiber_4g";     // SSID WiFi network
const char* pass  =  "Hima@nilu123";     // Password  WiFi network
const char* token =  "7xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx87Q";  // Telegram token

// Target user can find it's own userid with the bot @JsonDumpBot
// https://t.me/JsonDumpBot
int64_t userid = 1359xxxxxxx;

// Name of public channel (your bot must be in admin group)
const char* channel = "@tolentino_cotesta";

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  // initialize the Serial
  Serial.begin(115200);
  Serial.println("\nStarting TelegramBot...");

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);
  delay(500);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(500);
  }

#ifdef ESP8266
  // Sync time with NTP, to check properly Telegram certificate
  configTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org");
  //Set certficate, 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");
  #if USE_CLIENTSSL == false
    client.setCACert(telegram_cert);
  #endif
#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());

  // Send a message to specific user who has started your bot
  myBot.sendTo(userid, welcome_msg);
}

void loop() {

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

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

  // if there is an incoming message...
  if (myBot.getNewMessage(msg)) {    
    // Send a message to your public channel
    String message ;
    message += "Message from @";
    message += myBot.getBotName();
    message += ":\n";
    message += msg.text;
    Serial.println(message);
    myBot.sendToChannel(channel, message, true);

    // echo the received message
    myBot.sendMessage(msg, msg.text);
  }
}

`