Skip to content

Commit

Permalink
Merge branch 'master' of github.com:witnessmenow/Universal-Arduino-Te…
Browse files Browse the repository at this point in the history
…legram-Bot
  • Loading branch information
witnessmenow committed Nov 8, 2020
2 parents 585ee19 + 262757c commit 7b56463
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 15 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ env:
- SCRIPT=platformioSingle EXAMPLE_NAME=ChatAction EXAMPLE_FOLDER=/ BOARDTYPE=ESP32 BOARD=esp32dev
- SCRIPT=platformioSingle EXAMPLE_NAME=InlineKeyboardMarkup EXAMPLE_FOLDER=/CustomKeyboard/ BOARDTYPE=ESP32 BOARD=esp32dev
- SCRIPT=platformioSingle EXAMPLE_NAME=ReplyKeyboardMarkup EXAMPLE_FOLDER=/CustomKeyboard/ BOARDTYPE=ESP32 BOARD=esp32doit-devkit-v1
- SCRIPT=platformioSingle EXAMPLE_NAME=UpdateInlineKeyboard EXAMPLE_FOLDER=/CustomKeyboard/ BOARDTYPE=ESP32 BOARD=esp32dev
- SCRIPT=platformioSingle EXAMPLE_NAME=EchoBot EXAMPLE_FOLDER=/ BOARDTYPE=ESP32 BOARD=esp32dev
- SCRIPT=platformioSingle EXAMPLE_NAME=FlashLED EXAMPLE_FOLDER=/ BOARDTYPE=ESP32 BOARD=esp32doit-devkit-v1
- SCRIPT=platformioSingle EXAMPLE_NAME=Location EXAMPLE_FOLDER=/ BOARDTYPE=ESP32 BOARD=esp32dev
Expand Down
21 changes: 21 additions & 0 deletions examples/ESP32/CustomKeyboard/UpdateInlineKeyboard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ESP32 - LED button update

This is an example of how one can update inline keyboard messages (buttons).
The message_id of the specific message is sent when a message is received.
This message_id can be used to UPDATE that message.
One can update text inside a message, but also buttons can be updated.
This way one can build menu's, like the menu the botfather uses.

In this simple example we use a inlinekeyboard button to toggle (and update) the state of a LED.

NOTE: You will need to enter your SSID, password and bot Token for the example to work.

Example and update to Universal-Arduino-Telegram-Bot originally written by
[Frits Jan van Kempen] (https://github.com/fritsjan) with inspiration from [RomeHein] (https://github.com/RomeHein)

Adapted by [Brian Lough](https://github.com/witnessmenow)

## License

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/*******************************************************************
An example to show how to edit an existing inline keyboard.
In this example the keyboard is updated with the state of
the LED.
written by Frits Jan van Kempen
*******************************************************************/
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>

// Initialize Wifi connection to the router
const char *ssid = "mySSID";
const char *password = "myPASSWORD";

// Initialize Telegram BOT
#define BOTtoken "xxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxx" // your Bot Token (Get from Botfather)
WiFiClientSecure client;
UniversalTelegramBot bot(BOTtoken, client);

int Bot_mtbs = 1000; //mean time between scan messages
long Bot_lasttime; //last time messages' scan has been done
int last_message_id = 0;

// LED parameters
const int ledPin = 2; // Internal LED on DevKit ESP32-WROOM (GPIO2)
int ledState = LOW;

void handleNewMessages(int numNewMessages)
{

for (int i = 0; i < numNewMessages; i++)
{

// Get all the important data from the message
int message_id = bot.messages[i].message_id;
String chat_id = String(bot.messages[i].chat_id);
String text = bot.messages[i].text;
String from_name = bot.messages[i].from_name;
if (from_name == "")
from_name = "Guest";
String msg = ""; // init a message string to use

// Output the message_id to give you feeling on how this example works
Serial.print("Message id: ");
Serial.println(message_id);

// Inline buttons with callbacks when pressed will raise a callback_query message
if (bot.messages[i].type == "callback_query")
{
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);

if (text == "/toggleLED")
{

// Toggle the ledState and update the LED itself
ledState = !ledState;
digitalWrite(ledPin, ledState);

// Now we can UPDATE the message, lets prepare it for sending:
msg = "Hi " + from_name + "!\n";
msg += "Notice how the LED state has changed!\n\n";
msg += "Try it again, see the button has updated as well:\n\n";

// Prepare the buttons
String keyboardJson = "["; // start Json
keyboardJson += "[{ \"text\" : \"The LED is ";
if (ledState)
{
keyboardJson += "ON";
}
else
{
keyboardJson += "OFF";
}
keyboardJson += "\", \"callback_data\" : \"/toggleLED\" }]";
keyboardJson += ", [{ \"text\" : \"Send text\", \"callback_data\" : \"This text was sent by inline button\" }]"; // add another button
//keyboardJson += ", [{ \"text\" : \"Go to Google\", \"url\" : \"https://www.google.com\" }]"; // add another button, this one appears after first Update
keyboardJson += "]"; // end Json

// Now send this message including the current message_id as the 5th input to UPDATE that message
bot.sendMessageWithInlineKeyboard(chat_id, msg, "Markdown", keyboardJson, message_id);
}

else
{
// echo back callback_query which is not handled above
bot.sendMessage(chat_id, text, "Markdown");
}
}

// 'Normal' messages are handled here
else
{
if (text == "/start")
{
// lets create a friendly welcome message
msg = "Hi " + from_name + "!\n";
msg += "I am your Telegram Bot running on ESP32.\n\n";
msg += "Lets test this updating LED button below:\n\n";

// lets create a button depending on the current ledState
String keyboardJson = "["; // start of keyboard json
keyboardJson += "[{ \"text\" : \"The LED is ";
if (ledState)
{
keyboardJson += "ON";
}
else
{
keyboardJson += "OFF";
}
keyboardJson += "\", \"callback_data\" : \"/toggleLED\" }]"; //callback is /toggleLED
keyboardJson += ", [{ \"text\" : \"Send text\", \"callback_data\" : \"This text was sent by inline button\" }]"; // add another button
keyboardJson += "]"; // end of keyboard json

//first time, send this message as a normal inline keyboard message:
bot.sendMessageWithInlineKeyboard(chat_id, msg, "Markdown", keyboardJson);
}
if (text == "/options")
{
String keyboardJson = "[[{ \"text\" : \"Go to Google\", \"url\" : \"https://www.google.com\" }], [{ \"text\" : \"Send\", \"callback_data\" : \"This was sent by inline\" }]]";
bot.sendMessageWithInlineKeyboard(chat_id, "Choose from one of the following options", "", keyboardJson);
}
}
}
}

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

// Attempt to connect to Wifi network:
Serial.print("Connecting Wifi: ");
Serial.println(ssid);

// Set WiFi to station mode and disconnect from an AP if it was Previously
// connected
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(500);
}

Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());

pinMode(ledPin, OUTPUT); // initialize ledPin as an output.
digitalWrite(ledPin, ledState); // initialize pin as low (LED Off)
}

void loop()
{
// run this in loop to poll new messages
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();
}
}
36 changes: 24 additions & 12 deletions src/UniversalTelegramBot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ String UniversalTelegramBot::sendMultipartFormDataToTelegram(
client->print(buildCommand(command));
client->println(F(" HTTP/1.1"));
// Host header
client->print(F("Host: " TELEGRAM_HOST));
client->println(F("Host: " TELEGRAM_HOST)); // bugfix - https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot/issues/186
client->println(F("User-Agent: arduino/1.0"));
client->println(F("Accept: */*"));

Expand Down Expand Up @@ -267,7 +267,6 @@ String UniversalTelegramBot::sendMultipartFormDataToTelegram(
#endif
byte buffer[512];
int count = 0;

while (moreDataAvailableCallback()) {
buffer[count] = getNextByteCallback();
count++;
Expand Down Expand Up @@ -460,6 +459,7 @@ bool UniversalTelegramBot::processResult(JsonObject result, int messageIndex) {
messages[messageIndex].chat_id = message["chat"]["id"].as<String>();
messages[messageIndex].chat_title = message["chat"]["title"].as<String>();
messages[messageIndex].hasDocument = false;
messages[messageIndex].message_id = message["message_id"].as<int>(); // added message id
if (message.containsKey("text")) {
messages[messageIndex].text = message["text"].as<String>();

Expand All @@ -479,14 +479,16 @@ bool UniversalTelegramBot::processResult(JsonObject result, int messageIndex) {
messages[messageIndex].reply_to_message_id = message["reply_to_message"]["message_id"];
// no need to check if containsKey["text"]. If it doesn't, it default to null
messages[messageIndex].reply_to_text = message["reply_to_message"]["text"].as<String>();
}
}

} else if (result.containsKey("channel_post")) {
JsonObject message = result["channel_post"];
messages[messageIndex].type = F("channel_post");
messages[messageIndex].text = message["text"].as<String>();
messages[messageIndex].date = message["date"].as<String>();
messages[messageIndex].chat_id = message["chat"]["id"].as<String>();
messages[messageIndex].chat_title = message["chat"]["title"].as<String>();
messages[messageIndex].message_id = message["message_id"].as<int>(); // added message id

} else if (result.containsKey("callback_query")) {
JsonObject message = result["callback_query"];
Expand All @@ -499,6 +501,8 @@ bool UniversalTelegramBot::processResult(JsonObject result, int messageIndex) {
messages[messageIndex].reply_to_text = message["message"]["text"].as<String>();
messages[messageIndex].chat_title = F("");
messages[messageIndex].query_id = message["id"].as<String>();
messages[messageIndex].message_id = message["message"]["message_id"].as<int>(); // added message id

} else if (result.containsKey("edited_message")) {
JsonObject message = result["edited_message"];
messages[messageIndex].type = F("edited_message");
Expand All @@ -507,6 +511,7 @@ bool UniversalTelegramBot::processResult(JsonObject result, int messageIndex) {
messages[messageIndex].date = message["date"].as<String>();
messages[messageIndex].chat_id = message["chat"]["id"].as<String>();
messages[messageIndex].chat_title = message["chat"]["title"].as<String>();
messages[messageIndex].message_id = message["message_id"].as<int>(); // added message id

if (message.containsKey("text")) {
messages[messageIndex].text = message["text"].as<String>();
Expand Down Expand Up @@ -555,16 +560,19 @@ bool UniversalTelegramBot::sendSimpleMessage(const String& chat_id, const String
}

bool UniversalTelegramBot::sendMessage(const String& chat_id, const String& text,
const String& parse_mode) {
const String& parse_mode, int message_id) { // added message_id

DynamicJsonDocument payload(maxMessageLength);
payload["chat_id"] = chat_id;
payload["text"] = text;

if (message_id != 0)
payload["message_id"] = message_id; // added message_id

if (parse_mode != "")
payload["parse_mode"] = parse_mode;

return sendPostMessage(payload.as<JsonObject>());
return sendPostMessage(payload.as<JsonObject>(), message_id); // if message id == 0 then edit is false, else edit is true
}

bool UniversalTelegramBot::sendMessageWithReplyKeyboard(
Expand Down Expand Up @@ -599,25 +607,29 @@ bool UniversalTelegramBot::sendMessageWithReplyKeyboard(
bool UniversalTelegramBot::sendMessageWithInlineKeyboard(const String& chat_id,
const String& text,
const String& parse_mode,
const String& keyboard) {
const String& keyboard,
int message_id) { // added message_id

DynamicJsonDocument payload(maxMessageLength);
payload["chat_id"] = chat_id;
payload["text"] = text;

if (message_id != 0)
payload["message_id"] = message_id; // added message_id

if (parse_mode != "")
payload["parse_mode"] = parse_mode;

JsonObject replyMarkup = payload.createNestedObject("reply_markup");
replyMarkup["inline_keyboard"] = serialized(keyboard);
return sendPostMessage(payload.as<JsonObject>());
return sendPostMessage(payload.as<JsonObject>(), message_id); // if message id == 0 then edit is false, else edit is true
}

/***********************************************************************
* SendPostMessage - function to send message to telegram *
* SendPostMessage - function to send message to telegram *
* (Arguments to pass: chat_id, text to transmit and markup(optional)) *
***********************************************************************/
bool UniversalTelegramBot::sendPostMessage(JsonObject payload) {
bool UniversalTelegramBot::sendPostMessage(JsonObject payload, bool edit) { // added message_id

bool sent = false;
#ifdef TELEGRAM_DEBUG
Expand All @@ -628,9 +640,9 @@ bool UniversalTelegramBot::sendPostMessage(JsonObject payload) {
unsigned long sttime = millis();

if (payload.containsKey("text")) {
while (millis() - sttime < 8000ul) { // loop for a while to send the message
String response = sendPostToTelegram(BOT_CMD("sendMessage"), payload);
#ifdef TELEGRAM_DEBUG
while (millis() < sttime + 8000) { // loop for a while to send the message
String response = sendPostToTelegram((edit ? BOT_CMD("editMessageText") : BOT_CMD("sendMessage")), payload); // if edit is true we send a editMessageText CMD
#ifdef TELEGRAM_DEBUG
Serial.println(response);
#endif
sent = checkForOkResponse(response);
Expand Down
7 changes: 4 additions & 3 deletions src/UniversalTelegramBot.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ struct telegramMessage {
float longitude;
float latitude;
int update_id;
int message_id;

int reply_to_message_id;
String reply_to_text;
Expand All @@ -84,17 +85,17 @@ class UniversalTelegramBot {
bool getMe();

bool sendSimpleMessage(const String& chat_id, const String& text, const String& parse_mode);
bool sendMessage(const String& chat_id, const String& text, const String& parse_mode = "");
bool sendMessage(const String& chat_id, const String& text, const String& parse_mode = "", int message_id = 0);
bool sendMessageWithReplyKeyboard(const String& chat_id, const String& text,
const String& parse_mode, const String& keyboard,
bool resize = false, bool oneTime = false,
bool selective = false);
bool sendMessageWithInlineKeyboard(const String& chat_id, const String& text,
const String& parse_mode, const String& keyboard);
const String& parse_mode, const String& keyboard, int message_id = 0);

bool sendChatAction(const String& chat_id, const String& text);

bool sendPostMessage(JsonObject payload);
bool sendPostMessage(JsonObject payload, bool edit = false);
String sendPostPhoto(JsonObject payload);
String sendPhotoByBinary(const String& chat_id, const String& contentType, int fileSize,
MoreDataAvailable moreDataAvailableCallback,
Expand Down

0 comments on commit 7b56463

Please sign in to comment.