From a824d560c43c63086b9c38baa964545ee61b8a26 Mon Sep 17 00:00:00 2001 From: Filipe Laborde Date: Sat, 5 Oct 2024 21:09:58 +0100 Subject: [PATCH 1/3] Allowed empty constructor, added updateClient() method. --- .../EmptyConstructor/EmptyConstructor.ino | 81 +++++++++++++++++++ examples/EmptyConstructor/README.md | 11 +++ src/UniversalTelegramBot.cpp | 40 +++++---- src/UniversalTelegramBot.h | 5 +- 4 files changed, 119 insertions(+), 18 deletions(-) create mode 100644 examples/EmptyConstructor/EmptyConstructor.ino create mode 100644 examples/EmptyConstructor/README.md diff --git a/examples/EmptyConstructor/EmptyConstructor.ino b/examples/EmptyConstructor/EmptyConstructor.ino new file mode 100644 index 0000000..ecf9e1f --- /dev/null +++ b/examples/EmptyConstructor/EmptyConstructor.ino @@ -0,0 +1,81 @@ +/******************************************************************* + Based on the echo bot, this one has an EMPTY constructor. + + Useful where you're setting the bot in a task parallel to wifi. + + Adapted by Filipe Laborde from Brian Lough's work + Github: https://github.com/mindflowgo + *******************************************************************/ + +#include +#include +#include + +// Wifi network station credentials +#define WIFI_SSID "YOUR_SSID" +#define WIFI_PASSWORD "YOUR_PASSWORD" +// Telegram BOT Token (Get from Botfather) +#define BOT_TOKEN "XXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + +const unsigned long BOT_MTBS = 1000; // mean time between scan messages + +WiFiClientSecure secured_client; +UniversalTelegramBot bot; // these are given LATER: (BOT_TOKEN, secured_client); +unsigned long bot_lasttime; // last time messages' scan has been done + +void handleNewMessages(int numNewMessages) +{ + for (int i = 0; i < numNewMessages; i++) + { + bot.sendMessage(bot.messages[i].chat_id, bot.messages[i].text, ""); + } +} + +void setup() +{ + Serial.begin(115200); + Serial.println(); + + // attempt to connect to Wifi network: + Serial.print("Connecting to Wifi SSID "); + Serial.print(WIFI_SSID); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + bot.updateClient(secured_client); + bot.updateToken(BOT_TOKEN); + secured_client.setCACert(TELEGRAM_CERTIFICATE_ROOT); // Add root certificate for api.telegram.org + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(500); + } + Serial.print("\nWiFi connected. IP address: "); + Serial.println(WiFi.localIP()); + + Serial.print("Retrieving time: "); + configTime(0, 0, "pool.ntp.org"); // get UTC time via NTP + time_t now = time(nullptr); + while (now < 24 * 3600) + { + Serial.print("."); + delay(100); + now = time(nullptr); + } + Serial.println(now); +} + +void loop() +{ + if (millis() - bot_lasttime > BOT_MTBS) + { + int numNewMessages = bot.getUpdates(bot.last_message_received + 1); + + while (numNewMessages) + { + Serial.println("got response"); + handleNewMessages(numNewMessages); + numNewMessages = bot.getUpdates(bot.last_message_received + 1); + } + + bot_lasttime = millis(); + } +} diff --git a/examples/EmptyConstructor/README.md b/examples/EmptyConstructor/README.md new file mode 100644 index 0000000..67796e9 --- /dev/null +++ b/examples/EmptyConstructor/README.md @@ -0,0 +1,11 @@ +#ESP32 - Empty Constructor - configure Client/Token After + +In situations where you are setting up wifi parallel to the telegram bot task, you may not have token/client available. + +This slight modification built on Brian Lough's excellent telegram bot. + +Adapted by [Filipe Laborde](https://github.com/mindflowgo) + +## License + +You may copy, distribute and modify the software provided that modifications are described and licensed for free under [LGPL-3](http://www.gnu.org/licenses/lgpl-3.0.html). Derivatives works (including modifications or anything statically linked to the library) can only be redistributed under [LGPL-3](http://www.gnu.org/licenses/lgpl-3.0.html), but applications that use the library don't have to be. diff --git a/src/UniversalTelegramBot.cpp b/src/UniversalTelegramBot.cpp index 86cd747..3b7c275 100644 --- a/src/UniversalTelegramBot.cpp +++ b/src/UniversalTelegramBot.cpp @@ -43,6 +43,10 @@ UniversalTelegramBot::UniversalTelegramBot(const String& token, Client &client) this->client = &client; } +void UniversalTelegramBot::updateClient(Client &_client) { + client = &_client; +} + void UniversalTelegramBot::updateToken(const String& token) { _token = token; } @@ -66,17 +70,17 @@ String UniversalTelegramBot::sendGetToTelegram(const String& command) { String body, headers; // Connect with api.telegram.org if not already connected - if (!client->connected()) { + if (client && !client->connected()) { #ifdef TELEGRAM_DEBUG Serial.println(F("[BOT]Connecting to server")); #endif - if (!client->connect(TELEGRAM_HOST, TELEGRAM_SSL_PORT)) { + if (client && !client->connect(TELEGRAM_HOST, TELEGRAM_SSL_PORT)) { #ifdef TELEGRAM_DEBUG Serial.println(F("[BOT]Connection error")); #endif } } - if (client->connected()) { + if (client && client->connected()) { #ifdef TELEGRAM_DEBUG Serial.println("sending: " + command); @@ -104,7 +108,7 @@ bool UniversalTelegramBot::readHTTPAnswer(String &body, String &headers) { bool responseReceived = false; while (millis() - now < longPoll * 1000 + waitForResponse) { - while (client->available()) { + while (client && client->available()) { char c = client->read(); responseReceived = true; @@ -143,17 +147,17 @@ String UniversalTelegramBot::sendPostToTelegram(const String& command, JsonObjec String headers; // Connect with api.telegram.org if not already connected - if (!client->connected()) { + if (client && !client->connected()) { #ifdef TELEGRAM_DEBUG Serial.println(F("[BOT Client]Connecting to server")); #endif - if (!client->connect(TELEGRAM_HOST, TELEGRAM_SSL_PORT)) { + if (client && !client->connect(TELEGRAM_HOST, TELEGRAM_SSL_PORT)) { #ifdef TELEGRAM_DEBUG Serial.println(F("[BOT Client]Connection error")); #endif } } - if (client->connected()) { + if (client && client->connected()) { // POST URI client->print(F("POST /")); client->print(command); @@ -198,17 +202,17 @@ String UniversalTelegramBot::sendMultipartFormDataToTelegram( const String boundary = F("------------------------b8f610217e83e29b"); // Connect with api.telegram.org if not already connected - if (!client->connected()) { + if (client && !client->connected()) { #ifdef TELEGRAM_DEBUG Serial.println(F("[BOT Client]Connecting to server")); #endif - if (!client->connect(TELEGRAM_HOST, TELEGRAM_SSL_PORT)) { + if (client && !client->connect(TELEGRAM_HOST, TELEGRAM_SSL_PORT)) { #ifdef TELEGRAM_DEBUG Serial.println(F("[BOT Client]Connection error")); #endif } } - if (client->connected()) { + if (client && client->connected()) { String start_request; String end_request; @@ -328,14 +332,14 @@ bool UniversalTelegramBot::setMyCommands(const String& commandArray) { payload["commands"] = serialized(commandArray); bool sent = false; String response = ""; - #if defined(_debug) + #ifdef TELEGRAM_DEBUG Serial.println(F("sendSetMyCommands: SEND Post /setMyCommands")); - #endif // defined(_debug) + #endif unsigned long sttime = millis(); while (millis() - sttime < 8000ul) { // loop for a while to send the message response = sendPostToTelegram(BOT_CMD("setMyCommands"), payload.as()); - #ifdef _debug + #ifdef TELEGRAM_DEBUG Serial.println("setMyCommands response" + response); #endif sent = checkForOkResponse(response); @@ -357,6 +361,12 @@ int UniversalTelegramBot::getUpdates(long offset) { #ifdef TELEGRAM_DEBUG Serial.println(F("GET Update Messages")); #endif + if( !client ){ + #ifdef TELEGRAM_DEBUG + Serial.println(F("Sorry invalid client (use updateClient())! Cannot fetch updates!")); + #endif + return -1; // only time a -1 returned, is when client not set up. + } String command = BOT_CMD("getUpdates?offset="); command += offset; command += F("&limit="); @@ -770,7 +780,7 @@ bool UniversalTelegramBot::sendChatAction(const String& chat_id, const String& t } void UniversalTelegramBot::closeClient() { - if (client->connected()) { + if (client && client->connected()) { #ifdef TELEGRAM_DEBUG Serial.println(F("Closing client")); #endif @@ -809,7 +819,7 @@ bool UniversalTelegramBot::answerCallbackQuery(const String &query_id, const Str if (url.length() > 0) payload["url"] = url; String response = sendPostToTelegram(BOT_CMD("answerCallbackQuery"), payload.as()); - #ifdef _debug + #ifdef TELEGRAM_DEBUG Serial.print(F("answerCallbackQuery response:")); Serial.println(response); #endif diff --git a/src/UniversalTelegramBot.h b/src/UniversalTelegramBot.h index 5fc97ee..0bcbdf2 100644 --- a/src/UniversalTelegramBot.h +++ b/src/UniversalTelegramBot.h @@ -34,9 +34,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define TELEGRAM_SSL_PORT 443 #define HANDLE_MESSAGES 1 -//unmark following line to enable debug mode -//#define _debug - typedef bool (*MoreDataAvailable)(); typedef byte (*GetNextByte)(); typedef byte* (*GetNextBuffer)(); @@ -68,6 +65,8 @@ struct telegramMessage { class UniversalTelegramBot { public: UniversalTelegramBot(const String& token, Client &client); + UniversalTelegramBot() {}; // allows setting token/client later. + void updateClient(Client &_client); void updateToken(const String& token); String getToken(); String sendGetToTelegram(const String& command); From 51fb77c33e755c6819d69990b65105705ca6b218 Mon Sep 17 00:00:00 2001 From: Filipe Laborde Date: Sat, 5 Oct 2024 22:21:11 +0100 Subject: [PATCH 2/3] Moved EmptyConstructor.ino to ESP32 directory --- examples/{ => ESP32}/EmptyConstructor/EmptyConstructor.ino | 0 examples/{ => ESP32}/EmptyConstructor/README.md | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename examples/{ => ESP32}/EmptyConstructor/EmptyConstructor.ino (100%) rename examples/{ => ESP32}/EmptyConstructor/README.md (100%) diff --git a/examples/EmptyConstructor/EmptyConstructor.ino b/examples/ESP32/EmptyConstructor/EmptyConstructor.ino similarity index 100% rename from examples/EmptyConstructor/EmptyConstructor.ino rename to examples/ESP32/EmptyConstructor/EmptyConstructor.ino diff --git a/examples/EmptyConstructor/README.md b/examples/ESP32/EmptyConstructor/README.md similarity index 100% rename from examples/EmptyConstructor/README.md rename to examples/ESP32/EmptyConstructor/README.md From ab5665e8cf32543b4be5cebce92b649c28a24719 Mon Sep 17 00:00:00 2001 From: Filipe Laborde Date: Sun, 6 Oct 2024 01:06:17 +0100 Subject: [PATCH 3/3] Fixed the InlineKeyboardMarkup example to include answerCallbackQuery(). --- .../InlineKeyboardMarkup/InlineKeyboardMarkup.ino | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/ESP32/CustomKeyboard/InlineKeyboardMarkup/InlineKeyboardMarkup.ino b/examples/ESP32/CustomKeyboard/InlineKeyboardMarkup/InlineKeyboardMarkup.ino index ac24156..62c6d00 100644 --- a/examples/ESP32/CustomKeyboard/InlineKeyboardMarkup/InlineKeyboardMarkup.ino +++ b/examples/ESP32/CustomKeyboard/InlineKeyboardMarkup/InlineKeyboardMarkup.ino @@ -27,10 +27,13 @@ void handleNewMessages(int numNewMessages) // Inline buttons with callbacks when pressed will raise a callback_query message if (bot.messages[i].type == "callback_query") { + // acknowledge the callback (it will display Thank you text in place of the Loading... toast at top) + bot.answerCallbackQuery(bot.messages[i].query_id, "Thank you!", true ); + Serial.print("Call back button pressed by: "); Serial.println(bot.messages[i].from_id); Serial.print("Data on the button: "); - Serial.println(bot.messages[i].text); + Serial.println(bot.messages[i].text); // 'data' field is saved as 'text' in UTB bot.sendMessage(bot.messages[i].from_id, bot.messages[i].text, ""); } else