AsyncTelegram2
Loading...
Searching...
No Matches
AsyncTelegram2.h
Go to the documentation of this file.
1#ifndef ASYNCTELEGRAMV2
2#define ASYNCTELEGRAMV2
3
4// for using int_64 data
5#define ARDUINOJSON_USE_LONG_LONG 1
6#define ARDUINOJSON_DECODE_UNICODE 1
7#include <ArduinoJson.h>
8
9#if defined(ESP32) || defined(ESP8266)
10#define FS_SUPPORT true
11#include <FS.h>
12#include <WiFiClientSecure.h>
13#else
14#define FS_SUPPORT false
15#endif
16
17#ifndef LED_BUILTIN
18#define LED_BUILTIN 2
19#endif
20
21#include "Client.h"
22#include "time.h"
23
24#ifndef DEBUG_ENABLE
25#define DEBUG_ENABLE 0
26#endif
27
28#if defined(ESP32) || defined(ESP8266)
29#define FS_SUPPORT true
30#include <FS.h>
31#include <WiFiClientSecure.h>
32#else
33#define FS_SUPPORT false
34#endif
35
36
37// int 32 bit long, (eg. ESP32 platform)
38#if INT_MAX == 2147483647
39 #define INT32 "d"
40#else
41 #define INT32 "ld"
42#endif
43
44/*
45 This affect only inline keyboard with at least one callback function defined.
46 If you need more than MAX_INLINEKYB_CB distinct keybords with
47 callback functions associated to buttons increase this value
48*/
49#define MAX_INLINEKYB_CB 30
50
51#define SERVER_TIMEOUT 10000
52#define MIN_UPDATE_TIME 500
53
54#define BLOCK_SIZE 1436 // 2872 // 2 * TCP_MSS
55
56#include "DataStructures.h"
57#include "InlineKeyboard.h"
58#include "ReplyKeyboard.h"
59#include "serial_log.h"
60
61#define TELEGRAM_HOST "api.telegram.org"
62#define TELEGRAM_IP "149.154.167.220"
63#define TELEGRAM_PORT 443
64
65/* This is used with ESP8266 platform only */
66static const char telegram_cert[] PROGMEM = R"EOF(
67-----BEGIN CERTIFICATE-----
68MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
69MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
70YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
71MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
72ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
73MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
74ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
75PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
76wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
77EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
78avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
79YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
80sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
81/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
82IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
83YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
84ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
85OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
86TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
87HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
88dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
89ReYNnyicsbkqWletNw+vHX/bvZ8=
90-----END CERTIFICATE-----
91)EOF";
92
94{
95
96 // using SentCallback = std::function<void(bool sent)>;
97 typedef void(*SentCallback)(bool sent);
98
99public:
100 // default constructor
101 AsyncTelegram2(Client &client, uint32_t bufferSize = BUFFER_BIG);
102 // default destructor
104
105 // test the connection between ESP8266 and the telegram server
106 // returns
107 // true if no error occurred
108 bool begin(void);
109
110 // reset the connection between ESP8266 and the telegram server (ex. when connection was lost)
111 // returns
112 // true if no error occurred
113 bool reset(void);
114
115 // set the telegram token
116 // params
117 // token: the telegram token
118 inline void setTelegramToken(const char *token) { m_token = (char *)token; }
119
120 // set the interval in milliseconds for polling
121 // in order to Avoid query Telegram server to much often (ms)
122 // params:
123 // pollingTime: interval time in milliseconds
124 void setUpdateTime(uint32_t pollingTime) { m_minUpdateTime = pollingTime; }
125
126 // Get file link and size by unique document ID
127 // params
128 // doc : document structure
129 // returns
130 // true if no error
131 bool getFile(TBDocument &doc);
132
133 // get the first unread message from the queue (text and query from inline keyboard).
134 // This is a destructive operation: once read, the message will be marked as read
135 // so a new getMessage will read the next message (if any).
136 // params
137 // message: the data structure that will contains the data retrieved
138 // returns
139 // MessageNoData: an error has occurred
140 // MessageText : the received message is a text
141 // MessageQuery : the received message is a query (from inline keyboards)
143
144 // send a message to the specified telegram user ID
145 // params
146 // msg : the TBMessage telegram recipient with user ID
147 // message : the message to send
148 // keyboard: the inline/reply keyboard (optional)
149 // (in json format or using the inlineKeyboard/ReplyKeyboard class helper)
150 // wait: true if method must be blocking
151 bool sendMessage(const TBMessage &msg, const char *message, const char *keyboard = nullptr, bool wait = false);
152
153 // sendMessage function overloads
154 inline bool sendMessage(const TBMessage &msg, const String &message, String keyboard = "")
155 {
156 return sendMessage(msg, message.c_str(), keyboard.c_str());
157 }
158
159 inline bool sendMessage(const TBMessage &msg, const char *message, InlineKeyboard &keyboard)
160 {
161 return sendMessage(msg, message, keyboard.getJSON().c_str());
162 }
163
164 inline bool sendMessage(const TBMessage &msg, const char *message, ReplyKeyboard &keyboard)
165 {
166 return sendMessage(msg, message, keyboard.getJSON().c_str());
167 }
168
169 // Forward a specific message to user or chat
170 bool forwardMessage(const TBMessage &msg, const int64_t to_chatid);
171
172 // Send message to a channel. This bot must be in the admin group
173 bool sendToChannel(const char *channel, const char *message, bool silent = false);
174
175 inline bool sendToChannel(const String &channel, const String &message, bool silent)
176 {
177 return sendToChannel(channel.c_str(), message.c_str(), silent);
178 }
179
180 // Send message to a specific user. In order to work properly two conditions is needed:
181 // - You have to find the userid (for example using the bot @JsonBumpBot https://t.me/JsonDumpBot)
182 // - User has to start your bot in it's own client. For example send a message with @<your bot name>
183 inline bool sendTo(const int64_t userid, const char *message, const char *keyboard = nullptr)
184 {
185 TBMessage msg;
186 msg.chatId = userid;
187 return sendMessage(msg, message, keyboard);
188 }
189
190 inline bool sendTo(const int64_t userid, const String &message, String keyboard = "")
191 {
192 return sendTo(userid, message.c_str(), keyboard.c_str());
193 }
194
195 // Send a document passing a stream object
197 {
206 JSON
207 };
208 bool sendDocument(int64_t chat_id, Stream &stream, size_t size,
209 DocumentType doc, const char *filename, const char *caption = nullptr);
210
211 inline bool sendDocument(const TBMessage &msg, Stream &stream, size_t size,
212 DocumentType doc, const char *filename, const char *caption = nullptr)
213 {
214 return sendDocument(msg.chatId, stream, size, doc, filename, caption);
215 }
216
217 // Send a picture passing the url
218 bool sendPhotoByUrl(const int64_t &chat_id, const char *url, const char *caption);
219
220 // Send an animation/gif passing the url
221 bool sendAnimationByUrl(const int64_t &chat_id, const char *url, const char *caption);
222
223 inline bool sendPhoto(const int64_t &chat_id, const char *url, const char *caption)
224 {
225 return sendPhotoByUrl(chat_id, url, caption);
226 }
227
228 inline bool sendPhoto(const int64_t &chat_id, const String &url, const String &caption)
229 {
230 return sendPhotoByUrl(chat_id, url.c_str(), caption.c_str());
231 }
232
233 inline bool sendPhoto(const TBMessage &msg, const String &url, const String &caption)
234 {
235 return sendPhotoByUrl(msg.chatId, url.c_str(), caption.c_str());
236 }
237
238 // Send a picture passing a stream object
239 inline bool sendPhoto(int64_t chat_id, Stream &stream, size_t size, const char *filename = nullptr, const char *caption = nullptr)
240 {
241 return sendStream(chat_id, "sendPhoto", "image/jpeg", "photo", stream, size, filename, caption);
242 }
243
244 inline bool sendPhoto(const TBMessage &msg, Stream &stream, size_t size, const char *filename, const char *caption = nullptr)
245 {
246 return sendStream(msg.chatId, "sendPhoto", "image/jpeg", "photo", stream, size, filename, caption);
247 }
248
249#if FS_SUPPORT == true // #support for <FS.h> is needed
250 // Send a picture passing a file and relative filesystem
251 inline bool sendPhoto(int64_t chat_id, const char *filename, fs::FS &fs, const char *caption = nullptr)
252 {
253 File file = fs.open(filename, "r");
254 bool res = sendStream(chat_id, "sendPhoto", "image/jpeg", "photo", file, file.size(), file.name(), caption);
255 file.close();
256 return res;
257 }
258 inline bool sendPhoto(const TBMessage &msg, const char *filename, fs::FS &fs, const char *caption = nullptr)
259 {
260 File file = fs.open(filename, "r");
261 bool res = sendStream(msg.chatId, "sendPhoto", "image/jpeg", "photo", file, file.size(), file.name(), caption);
262 file.close();
263 return res;
264 }
265#endif
266
267 // Send a picture passing a raw buffer
268 inline bool sendPhoto(int64_t chat_id, uint8_t *data, size_t size, const char *caption = nullptr)
269 {
270 return sendBuffer(chat_id, "sendPhoto", "image/jpeg", "photo", data, size, caption);
271 }
272
273 inline bool sendPhoto(const TBMessage &msg, uint8_t *data, size_t size, const char *caption = nullptr)
274 {
275 return sendBuffer(msg.chatId, "sendPhoto", "image/jpeg", "photo", data, size, caption);
276 }
277
279
280 inline bool sendPhotoByUrl(const int64_t &chat_id, const String &url, const String &caption)
281 {
282 return sendPhotoByUrl(chat_id, url.c_str(), caption.c_str());
283 }
284
285 inline bool sendPhotoByUrl(const TBMessage &msg, const String &url, const String &caption)
286 {
287 return sendPhotoByUrl(msg.chatId, url.c_str(), caption.c_str());
288 }
289
290 inline bool sendPhotoByFile(int64_t chat_id, Stream *stream, size_t size)
291 {
292 return sendStream(chat_id, "sendPhoto", "image/jpeg", "photo", *stream, size, nullptr, nullptr);
293 }
294
295#if FS_SUPPORT == true // #support for <FS.h> is needed
296 inline bool sendPhotoByFile(int64_t chat_id, const char *filename, fs::FS &fs)
297 {
298 File file = fs.open(filename, "r");
299 Serial.println(file.size());
300 bool res = sendStream(chat_id, "sendPhoto", "image/jpeg", "photo", file, file.size(), file.name(), nullptr);
301 file.close();
302 return res;
303 }
304#endif
306
307 // terminate a query started by pressing an inlineKeyboard button. The steps are:
308 // 1) send a message with an inline keyboard
309 // 2) wait for a <message> (getNewMessage) of type MessageQuery
310 // 3) handle the query and then call endQuery with <message>.callbackQueryID
311 // params
312 // msg : the TBMessage telegram recipient with unique query ID (retrieved with getNewMessage method)
313 // message : an optional message
314 // alertMode: false -> a simply popup message
315 // true --> an alert message with ok button
316 bool endQuery(const TBMessage &msg, const char *message, bool alertMode = false);
317
318 // remove an active reply keyboard for a selected user, sending a message
319 // params:
320 // msg : the TBMessage telegram recipient with the telegram user ID
321 // message : the message to be show to the selected user ID
322 // selective: enable selective mode (hide the keyboard for specific users only)
323 // Targets: 1) users that are @mentioned in the text of the Message object;
324 // 2) if the bot's message is a reply (has reply_to_message_id), sender of the original message
325 // return:
326 // true if no error occurred
327 bool removeReplyKeyboard(const TBMessage &msg, const char *message, bool selective = false);
328
329 // Get the current bot name
330 // return:
331 // the bot name
332 inline const char *getBotName()
333 {
334 return m_botusername.c_str();
335 }
336
337 // Check for no new pending message
338 // (to be sure all messages was parsed, before doing something)
339 // Example: OTA sketch
340 // return:
341 // true if no message
342 bool noNewMessage();
343
344 // If bot is a member of a group, return the id of group (negative number)
345 // In order to be sure library is able to catch the id,
346 // add bot to group while it is running, so the joining message can be parsed
347 inline int64_t getGroupId(const TBMessage &msg)
348 {
349 if (msg.chatId < 0)
350 return msg.chatId;
351 return 0;
352 }
353
354 // keep track of defined inline keybaord in order to call cb function
355 // params: pointer to inline keyboard
357 {
358 m_keyboards[m_keyboardCount++] = keyb;
359 }
360
361 // set custom commands for bot
362 // params
363 // command: Text of the command, 1-32 characters. Can contain only lowercase English letters, digits and underscores.
364 // description: Description of the command, 3-256 characters.
365 // return:
366 // true if success
367 bool setMyCommands(const String &cmd, const String &desc);
368
369 // get list of custom commands defined for bot
370 // params:
371 // A string that will contains a JSON-serialized list of bot commands
372 void getMyCommands(String &cmdList);
373
374 // clear list of custom commands defined for bot
375 // return:
376 // true if success
377 bool deleteMyCommands();
378
379 // Edit a previous sent message
380 // params:
381 // chat_id: the iD of chat
382 // message_id: the message ID to be edited
383 // txt: the new text
384 // keyboard: the new inline keyboard (if present)
385 // return:
386 // true if success
387 bool editMessage(int32_t chat_id, int32_t message_id, const String &txt, const String &keyboard);
388
389 inline bool editMessage(const TBMessage &msg, const String &txt, const String &keyboard)
390 {
391 return editMessage(msg.chatId, msg.messageID, txt, keyboard);
392 }
393
394 inline bool editMessage(int32_t chat_id, int32_t message_id, const String &txt, InlineKeyboard &keyboard)
395 {
396 return editMessage(chat_id, message_id, txt, keyboard.getJSON());
397 }
398
399 inline bool editMessage(const TBMessage &msg, const String &txt, InlineKeyboard &keyboard)
400 {
401 return editMessage(msg.chatId, msg.messageID, txt, keyboard.getJSON());
402 }
403
404 // check if connection with server is active
405 // returns
406 // true on connected
407 bool checkConnection();
408
409 // This callback function will be executed once the message was delivered succesfully
410 inline void addSentCallback(SentCallback sentcb, uint32_t timeout = 1000)
411 {
412 if (sentcb != nullptr)
413 {
414 m_sentCallback = sentcb;
415 m_sentTimeout = timeout;
416 }
417 }
418
419 // Set the default text formatting option (https://core.telegram.org/bots/api#formatting-options)
420 // params:
421 // format: the type of formatting text of sent messages. No formatting, HTML style (default), MarkdownV2 style
422 // return:
423 // void
428 };
429 inline void setFormattingStyle(uint8_t format) {
430 m_formatType = format;
431 }
432
433 inline void setJsonBufferSize(uint32_t jsonBufferSize){
434 m_JsonBufferSize = jsonBufferSize;
435 }
436
437private:
438 Client *telegramClient;
439 const char *m_token;
440 String m_rxbuffer;
441 String m_botusername; // Store only botname, instead TBUser struct
442
443 int32_t m_lastUpdateId = 0;
444 uint32_t m_lastUpdateTime;
445 uint32_t m_minUpdateTime = MIN_UPDATE_TIME;
446
447 uint32_t m_lastmsg_timestamp;
448 bool m_waitingReply;
449
450 InlineKeyboard *m_keyboards[10];
451 uint8_t m_keyboardCount = 0;
452
453 void setformData(int64_t chat_id, const char *cmd, const char *type, const char *propName, size_t size,
454 String &formData, String &request, const char *filename, const char *caption);
455 bool sendStream(int64_t chat_id, const char *command, const char *contentType, const char *binaryPropertyName,
456 Stream &stream, size_t size, const char *filename, const char *caption);
457 bool sendBuffer(int64_t chat_id, const char *cmd, const char *type, const char *propName, uint8_t *data, size_t size, const char *caption);
458
459 SentCallback m_sentCallback = nullptr;
460 bool m_waitSent = false;
461 uint32_t m_sentTimeout;
462 uint32_t m_lastSentTime;
463 uint32_t m_lastSentMsgId;
464
465 uint32_t testReconnectTime;
466
467 uint8_t m_formatType = HTML;
468 uint32_t m_JsonBufferSize = BUFFER_BIG;
469
470protected:
471 // send commands to the telegram server. For info about commands, check the telegram api https://core.telegram.org/bots/api
472 // params
473 // command : the command to send, i.e. getMe
474 // parameters: optional parameters
475 // returns
476 // an empty string if error
477 // a string containing the Telegram JSON response
478
479 bool sendCommand(const char *command, const char *payload, bool blocking = false);
480
481 // query server for new incoming messages
482 // returns
483 // http response payload if no error occurred
484 // bool getUpdates(JsonDocument &doc);
485
486 bool getUpdates();
487
488 // get some information about the bot
489 // params
490 // user: the data structure that will contains the data retreived
491 // returns
492 // true if no error occurred
493 bool getMe();
494};
495
496#endif
#define MIN_UPDATE_TIME
#define BUFFER_BIG
Definition: DataStructures.h:5
MessageType
Definition: DataStructures.h:9
bool setMyCommands(const String &cmd, const String &desc)
bool sendAnimationByUrl(const int64_t &chat_id, const char *url, const char *caption)
void getMyCommands(String &cmdList)
bool sendPhoto(int64_t chat_id, uint8_t *data, size_t size, const char *caption=nullptr)
bool sendPhotoByUrl(const int64_t &chat_id, const String &url, const String &caption)
bool begin(void)
bool sendPhoto(const int64_t &chat_id, const String &url, const String &caption)
bool getFile(TBDocument &doc)
bool sendTo(const int64_t userid, const char *message, const char *keyboard=nullptr)
void addInlineKeyboard(InlineKeyboard *keyb)
int64_t getGroupId(const TBMessage &msg)
bool endQuery(const TBMessage &msg, const char *message, bool alertMode=false)
void setJsonBufferSize(uint32_t jsonBufferSize)
bool sendPhotoByUrl(const int64_t &chat_id, const char *url, const char *caption)
void addSentCallback(SentCallback sentcb, uint32_t timeout=1000)
const char * getBotName()
bool sendDocument(int64_t chat_id, Stream &stream, size_t size, DocumentType doc, const char *filename, const char *caption=nullptr)
MessageType getNewMessage(TBMessage &message)
bool sendCommand(const char *command, const char *payload, bool blocking=false)
bool sendMessage(const TBMessage &msg, const char *message, const char *keyboard=nullptr, bool wait=false)
bool sendPhotoByFile(int64_t chat_id, Stream *stream, size_t size)
bool reset(void)
bool sendMessage(const TBMessage &msg, const String &message, String keyboard="")
void setFormattingStyle(uint8_t format)
bool sendMessage(const TBMessage &msg, const char *message, InlineKeyboard &keyboard)
bool sendPhoto(const TBMessage &msg, const String &url, const String &caption)
bool sendToChannel(const char *channel, const char *message, bool silent=false)
void setTelegramToken(const char *token)
bool sendToChannel(const String &channel, const String &message, bool silent)
bool sendMessage(const TBMessage &msg, const char *message, ReplyKeyboard &keyboard)
bool editMessage(int32_t chat_id, int32_t message_id, const String &txt, InlineKeyboard &keyboard)
bool sendTo(const int64_t userid, const String &message, String keyboard="")
void setUpdateTime(uint32_t pollingTime)
bool editMessage(const TBMessage &msg, const String &txt, const String &keyboard)
bool sendPhotoByUrl(const TBMessage &msg, const String &url, const String &caption)
bool removeReplyKeyboard(const TBMessage &msg, const char *message, bool selective=false)
bool sendPhoto(const int64_t &chat_id, const char *url, const char *caption)
bool sendPhoto(const TBMessage &msg, uint8_t *data, size_t size, const char *caption=nullptr)
bool sendPhoto(int64_t chat_id, Stream &stream, size_t size, const char *filename=nullptr, const char *caption=nullptr)
bool editMessage(const TBMessage &msg, const String &txt, InlineKeyboard &keyboard)
bool forwardMessage(const TBMessage &msg, const int64_t to_chatid)
bool sendPhoto(const TBMessage &msg, Stream &stream, size_t size, const char *filename, const char *caption=nullptr)
bool sendDocument(const TBMessage &msg, Stream &stream, size_t size, DocumentType doc, const char *filename, const char *caption=nullptr)
bool editMessage(int32_t chat_id, int32_t message_id, const String &txt, const String &keyboard)
String getJSON(void) const
String getJSON(void) const
int64_t chatId
int32_t messageID