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

Failing to receiving messages after ~60s pause in .getNewMessage #93

Closed Macropodux closed 11 months ago

Macropodux commented 1 year ago

Hi,

I am basically reproducing the echoBot example with a few modifications. Due to some other actions in the code running for 30-60s outside the loop() function, .getNewMessage gets paused for this duration. After said time, I am using .sendTo to send a status update, which works perfectly fine. However, sending messages to the telegram bot no longer produces any action on the ESP32, when using .getNewMessage - I tried checking connection by .checkConnection, which gives the value "true". Even calling myBot.begin() after the 30-60s action finished doesn't solve the issue. Restarting the ESP32 however works fine. Also subsequent .sendTo commands seem to work fine. Do you have any idea how this can be?

Cheers and many thanks

Macropodux commented 1 year ago

Actually it seems to have nothing to do with the 30-60s action. It happens also during idling. Sending messages from the ESP32 (e.g. after button press) is no issue. Receiving however seems to fail quite frequently. Is there an option to check whether the message was successfully received? Seems like it is being marked as read by the AsyncTelegram even though no action took place.

cotestatnt commented 1 year ago

Hi @Macropodux , I'm sorry for the big late reply, but I've been very busy in recent months.

Do you still have this problem or did you manage to solve it? Could you post an example in order to reproduce the issue?

Macropodux commented 1 year ago

Hi @cotestatnt, thanks for you reply. I am still somewhat having this issue. I managed to "solve" it by using the NodeRed Telegram nodes on my raspberry and sending the messages to my ESP by MQTT, this works flawlessly. I was not able to solve it on my ESP directly. I have an indicator on my OLED screen indicating the connection status to Telegram (as given by you library) and it has nothing to do with this. Not sure, whether it has something to do with interfering with Pubsubclient etc, but I have another system up and running 24/7 where you library does not produce any issues. Providing an example will be tough, because a huge chunk of stuff is happening in the script and I tried to figure out the reason by disabling most of it for the sake of testing. The issue was still present. Sending operations are working without issues, I added a button for testing and I can send messages while receiving does not work. A restart solves this issue (for some time). A re-initialization of the Telegram client does not. I think the best way (for me) to solve this would be a way to manually tell the Telegram servers that the message was received and processed. I believe this is done automatically and even without triggering handleNewMessages in my case, because the messages get "checked" even without any action. Is it understandable what my issue seems to be?

cotestatnt commented 1 year ago

The bot needs to be in sync with the server and to do this you need to call the getNewMessage() method quite frequently. Since you're using an ESP32, my advice is to run everything related to Telegram in a dedicated FreeRTOS task, even at low priority.

cotestatnt commented 1 year ago

Here a possible example:

#include <WiFi.h>
#include <PubSubClient.h>
#include <AsyncTelegram2.h>     // https://github.com/cotestatnt/asynctelegram2

const char* mqtt_server = "broker.mqtt-dashboard.com";
const char* ssid = "xxxxxxx";                                        // SSID WiFi network
const char* pass = "xxxxxx";                                        // Password  WiFi network
const char* token = "xxxxx:xxxxx-xxxxxxxxxxxxxxxx";  // 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 = 1234567890;

WiFiClient wifi_client;
PubSubClient mqtt_client(wifi_client);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;

WiFiClientSecure clientSSL;
AsyncTelegram2 myBot(clientSSL);

TaskHandle_t Telegram_TaskHandle;
TaskHandle_t MQTT_TaskHandle;

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

void reconnect() {
  // Loop until we're reconnected
  while (!mqtt_client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP32Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (mqtt_client.connect(clientId.c_str())) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      mqtt_client.publish("outTopicESP32", "hello world");
      // ... and resubscribe
      mqtt_client.subscribe("inTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqtt_client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

// This is the task deputated to handle Telegram connection
static void checkTelegram(void* args) {
  // Init and start Telegram bot
  clientSSL.setCACert(telegram_cert);
  // 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");

  // Send a welcome message to user when ready
  char welcome_msg[64];  
  snprintf(welcome_msg, 64, "BOT @%s online.\n", myBot.getBotName());
  myBot.sendTo(userid, welcome_msg);

  while (true) {
    if (WiFi.status() == WL_CONNECTED) {      
      TBMessage msg;
      // if there is an incoming message...
      if (myBot.getNewMessage(msg)) {
        MessageType msgType = msg.messageType;

        if (msgType == MessageText) {
          // Received a text message          
          String replyStr = "Message received: ";
          replyStr += msg.text;
          Serial.println(replyStr);
          myBot.sendMessage(msg, replyStr);
        }
      }    
    }

    // Feed the watchdog    
    delay(100);
  }
  // Delete this task on exit (should never occurs)
  vTaskDelete(NULL);
}

// This is the task deputated to handle MQTT connection
static void checkMQTT(void* args) {
  mqtt_client.setServer(mqtt_server, 1883);
  mqtt_client.setCallback(callback);

  while (true) {
    if (WiFi.status() == WL_CONNECTED) {

      if (!mqtt_client.connected()) {
        reconnect();
      }
      mqtt_client.loop();

      if ( millis() - lastMsg > 10000) {
        lastMsg = millis();
        ++value;
        snprintf(msg, MSG_BUFFER_SIZE, "hello world #%ld", value);
        Serial.print("Publish message: ");
        Serial.println(msg);
        mqtt_client.publish("outTopicESP32", msg);
      }
    }

    // Feed the watchdog    
    delay(100);
  }
  // Delete this task on exit (should never occurs)
  vTaskDelete(NULL);
}

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

  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  configTzTime("CET-1CEST,M3.5.0,M10.5.0/3", "time.google.com", "time.windows.com", "pool.ntp.org");
  delay(5000);

  xTaskCreatePinnedToCore(checkTelegram, "handleTelegram", 10000, NULL, 8, &Telegram_TaskHandle, 1);   
  xTaskCreatePinnedToCore(checkMQTT, "handleMQTT", 10000, NULL, 1, &MQTT_TaskHandle, 1);
}

void loop() {
}
Macropodux commented 1 year ago

Makes sense, thanks for the in-depthanswer! I have implemented parts of the script you sent. The RTOS tasks are running (the MQTT task works without problems). I think the issues now arises from both NodeRed as well as the ESP connecting to the same bot token. It seems they are interfering with each other (can it be the case?). Unfortunately, in the past weeks time I implemented parts which cannot move from NodeRed to the ESP (some MySQL stuff..) so I guess I will leave it as is, if not both can run independently with the same token. The RTOS task on my other system is running fine however and the AT lib is doing so since 12/22 without problems on this system.

cotestatnt commented 1 year ago

Yes, this is a limit of Telegram: you can update bot only from 1 device at time and not both.

But if you have NodeRed which is running somewhere, why don't you implement a small "gateway" API on your NodeRed script that processes ESP32 requests destined to the Telegram bot?