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

editMessage() not working #111

Open tomi229 opened 1 year ago

tomi229 commented 1 year ago

editMessage() command doesn't seem to do anything. This is the test code I used:

#include <AsyncTelegram2.h>

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

#include <WiFi.h>
#if USE_CLIENTSSL
#include <WiFiClient.h>
#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

AsyncTelegram2 myBot(client);
const char *ssid = "hidden";                        // SSID WiFi network
const char *pass = "hidden";                       // Password  WiFi network
const char *token = "hidden";                     // Telegram token

InlineKeyboard myInlineKbd1, myInlineKbd2; // inline keyboards object helper

#define LIGHT_ON_CALLBACK "lightON"   // callback data sent when "LIGHT ON" button is pressed
#define BUTTON1_CALLBACK "Button1"    // callback data sent when "Button1" button is pressed
#define BUTTON2_CALLBACK "Button2"    // callback data sent when "Button1" button is pressed

void setup()
{
  // initialize the Serial
  Serial.begin(115200);

  // connects to access point
  WiFi.setAutoConnect(true);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);
  delay(500);
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print('.');
    delay(500);
  }

  // Sync time with NTP
  configTzTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org");
#if USE_CLIENTSSL == false
  client.setCACert(telegram_cert);
#endif

  // 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 sample inline keyboard
  myInlineKbd1.addButton("ON", LIGHT_ON_CALLBACK, KeyboardButtonQuery);

  // Add another inline keyboard
  myInlineKbd2.addButton("Button 1", BUTTON1_CALLBACK, KeyboardButtonQuery);
  myInlineKbd2.addButton("Button 2", BUTTON2_CALLBACK, KeyboardButtonQuery);
  Serial.printf("Added %d buttons to keyboard\n", myInlineKbd2.getButtonsNumber());

  // Add pointer to this keyboard to bot (in order to run callback function)
  myBot.addInlineKeyboard(&myInlineKbd1);
  myBot.addInlineKeyboard(&myInlineKbd2);
}

void loop()
{
  // a 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
    String tgReply;
    MessageType msgType = msg.messageType;

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

      if (tgReply.equalsIgnoreCase("/inline_keyboard1"))
      {
        myBot.sendMessage(msg, "This is inline keyboard 1:", myInlineKbd1);
      }
      else
      {
        // write back feedback message and show a hint
        String text = "You write: \"";
        text += msg.text;
        text += "\"\nTry /inline_keyboard1";
        myBot.sendMessage(msg, text);
      }
      break;

    case MessageQuery:
      tgReply = msg.callbackQueryData;

      if (tgReply.equalsIgnoreCase("lightON"))
      {
        myBot.editMessage(msg, "message modified.", myInlineKbd2);
        Serial.println("Edit message");
      }
      break;

    default:
      break;
    }
  }
}
cotestatnt commented 11 months ago

Hi @tomi229 I will check as soon as possible.

gmparnell commented 8 months ago

@tomi229 I am also having trouble but I attempted to use the function differently than you. Notice (near the end of my code snippet) that I have an additional parameter in editMessage() because I tried to follow the structure in AsyncTelegram2.h. I am keenly awaiting updates about this from @cotestatnt!

Serial Monitor output from running my code example:

Button pressed Starting message messageID: 0 CallbackQuery received: /updateInlineKb2 messageID: 1008 edit messageID 1007 Button pressed Starting message messageID: 1008 CallbackQuery received: /updateInlineKb2 messageID: 1009 edit messageID 1008 CallbackQuery received: /updateInlineKb2 messageID: 1009 edit messageID 1008

//AsyncTelegram2.h
    // Edit a previous sent message
    // params:
    //    chat_id: the iD of chat
    //    message_id: the message ID to be edited
    //    txt: the new text
    //    keyboard: the new inline keyboard (if present)
    // return:
    //    true if success
    bool editMessage(int32_t chat_id, int32_t message_id, const String &txt, const String &keyboard);

    inline bool editMessage(const TBMessage &msg, const String &txt, const String &keyboard)
    {
        return editMessage(msg.chatId, msg.messageID, txt, keyboard);
    }

    inline bool editMessage(int32_t chat_id, int32_t message_id, const String &txt, InlineKeyboard &keyboard)
    {
        return editMessage(chat_id, message_id, txt, keyboard.getJSON());
    }

    inline bool editMessage(const TBMessage &msg, const String &txt, InlineKeyboard &keyboard)
    {
        return editMessage(msg.chatId, msg.messageID, txt, keyboard.getJSON());
    } 
//My code which is a revision of the example program "AsyncTelegram2/keyboards"
//There is more code which I have left out. This is the important part and it's triggered by pressing a button.

InlineKeyboard kb1;
InlineKeyboard kb2;

void addKeyboards()
{
  kb1.addButton("First text", "/updateInlineKb2", KeyboardButtonQuery);
  kb2.addButton("Updated text", "/bogusCommand", KeyboardButtonQuery);
  kb2.addButton("third text", "/bogusCommand2", KeyboardButtonQuery);
}

void buttonPress()
{
    myBot.sendMessage(msg, "Starting message", kb1);
    Serial.print("Starting message  messageID: ");
    Serial.println(msg.messageID);
}

void asyncGetMessage()
{ 
 if (myBot.getNewMessage(msg)) 
  {
    MessageType msgType = msg.messageType;
    String msgText = msg.text;
    switch (msgType)
      case MessageQuery:
        msgText = msg.callbackQueryData;
        Serial.print("CallbackQuery received: ");
        Serial.print(msg.callbackQueryData);
        Serial.print("   messageID: ");
        Serial.println(msg.messageID);

        if (msgText.equalsIgnoreCase("/updateInlineKb2"))
        {
          setRed();
          myBot.editMessage(msg.chatId, (msg.messageID - 1), "updated", kb2);
          Serial.print("edit messageID ");
          Serial.println(msg.messageID - 1);
        }
    }
}
cotestatnt commented 8 months ago

I'm sorry for late reply, but in last months I was very busy and I hadn't free time to dedicate at this library.

I've checked and fixed a lot of things with latest commits and release. The issue which was related to editMessage() was really dumb! The chat ID is a int64 data type, but the method was defined with int32 data type. This cause the chat id to be a wrong number :(

gmparnell commented 8 months ago

@cotestatnt This fixed it! Thank you so much for the incredibly fast turnaround! It was fantastic to watch the inline keyboard and its associated caption message all transform into a new message!

gmparnell commented 7 months ago

@cotestatnt I am not a programmer. However, I did a half-approach at extending your library to include the deleteMessage() Telegram API function. I edited the asyncTelegram2.cpp and asyncTelegram2.h files by copying and adapting the editMessage() functions, below. I invoke my function like this:

void deleteLastMessage()
{
  myBot.deleteMessage(msg.chatId, msg.messageID);
  msg.messageID++;
  Serial.print("deleteMessage ID:"); 
  Serial.println(msg.messageID);
}

asyncTelegram2.cpp addition:

bool AsyncTelegram2::deleteMessage(int64_t chat_id, int32_t message_id)
{
  DynamicJsonDocument root(m_JsonBufferSize);
  root["chat_id"] = chat_id;
  root["message_id"] = message_id;
  root.shrinkToFit();
  String payload;
  serializeJson(root, payload);
  return sendCommand("deleteMessage", payload.c_str());
}

asyncTelegram2.h addition: bool deleteMessage(int64_t chat_id, int32_t message_id);

If this is helpful to you, please feel free to use this to clean up and implement my addition!

I am making a controller to make my washing machine and clothes dryer become smart appliances. The controller sends a Telegram message and then, through a combination of messageDelete() and editMessage() replies, I send updated message captions with dynamic buttons. This creates a sort of simple UI app to get 1) Phone notifications. 2) One button interaction. 3) Automatically rescheduling reminder messages are updated by menu button tap.

The controller can detect appliance status by looking for the Power light and Done lights to illuminate. Messages send the minimum amount of information necessary to control with minimal interaction but while still being easily+sufficiently understood to inform the interaction. The deleteMessage() function is necessary for generating new phone notifications while outside the Telegram app. This was all too much for the UniversalTelegramBot library so your async library has been very helpful. I use the flashing LED "busy" routine as a status indicator by alternating between two sets of RGB colors. This has been very useful during development.

Again, my thanks to you!

cotestatnt commented 7 months ago

I will add soon, thanks!