• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Делюсь опытом. Простой Telegram Bot без библиотеки.

p-a-h-a

Member
Разбирался с телеграм ботом, захотелось написать на POST запросах.
Реализовано - чтение id чата с последним написавшем юзером, определение его имени, отправка сообщения.
Пример использования - датчик открытия двери. Дверь открылась - единственный пользователь получил сообщение.
Для работы необходимо в телеграмме написать боту @botfather /start и создать своего бота, присвоить ему логин и имя.
В ответ получите сообщение вида
По ссылке t.me/ESP_Flo_bot переходите в чат с новоиспеченным ботом и пишете ему /start
Берем свой токен типа 1654645764490:AAH01HEDQguTZp-GjhGjhgjhgivkjbngc и вставляем в скеч
C++:
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>
char TelegrammBOTtoken[50] = "165476586:AAH01HfdhytjhmDSHnpZuUoi6YwLzqaIpVPs";// https://api.telegram.org/bot165476586:AAH01HfdhytjhmDSHnpZuUoi6YwLzqaIpVPs/getMe
String Messange = "Сообщение !";

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);//
  WiFi.begin("ssid", "pass");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
   Serial.println();
   Serial.println("UserName: " + UserName());
   Serial.println("chatid: " + String(chatid()));
   SendMessage(chatid(), UserName() + Messange); // Тут отправляем сообщение.  chatid() необходимо запомнить и вставлять сюда uint32_t вместо chatid() что значительно ускорит работу. UserName() тоже нужно заранее запоминать если будем обращаться по имени.
  ESP.deepSleep(0, RF_NO_CAL);
}

void loop() {}

String telegramPOST(String jsonarr) {
  std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);
  client->setInsecure();
  HTTPClient https;
  String token = TelegrammBOTtoken;
  if (https.begin(*client, "https://api.telegram.org/bot" + token + "/")) { // HTTPS
    https.addHeader("Content-Type", "application/json");
    https.POST(jsonarr);
    String Answer = https.getString();
    //Serial.println(Answer);
    https.end();
    return Answer;
  }
}

uint32_t chatid() {
  StaticJsonDocument<30> doc; // Создаем и наполняем json для последующей отправки на сервер
  doc["method"] = "getUpdates";
  doc["offset"] = -1; //Для проверки последнего сообщения
  DynamicJsonDocument Answer(1532);
  deserializeJson(Answer, telegramPOST(doc.as<String>()));                     // Парсим JSON-содержимое ответа сервера
  //   serializeJsonPretty(Answer, Serial);    Serial.println();
  return Answer["result"][0]["message"]["chat"]["id"];//id
}

String UserName() {
  StaticJsonDocument<30> doc; // Создаем и наполняем json для последующей отправки на сервер
  doc["method"] = "getUpdates";
  doc["offset"] = -1; //Для проверки последнего сообщения
  DynamicJsonDocument Answer(1532);
  deserializeJson(Answer, telegramPOST(doc.as<String>()));                     // Парсим JSON-содержимое ответа сервера
  //const char* first_name = Answer["result"][0]["message"]["from"]["first_name"];
  return Answer["result"][0]["message"]["from"]["first_name"];//id
}

void SendMessage(uint32_t chatid, String message) {
  StaticJsonDocument<100> doc; // Создаем и наполняем json для последующей отправки на сервер
  doc["method"] = "sendMessage";
  doc["chat_id"] = chatid;
  doc["text"] = message;
  DynamicJsonDocument Answer(1532);
  deserializeJson(Answer, telegramPOST(doc.as<String>()));                     // Парсим JSON-содержимое ответа сервера
  analogWrite(LED_BUILTIN, 0);
}
1612292164293.png
 

vrd

Member
А без бота можно использовать этот код как сериал, для отладки?
 

p-a-h-a

Member
А без бота можно использовать этот код как сериал, для отладки?
Можно. С ботом. Один раз узнайте chatid отправив /start боту и получив id из функции chatid(), и потом достаточно одной функции SendMessage(id_что_узнали, "Отладочное сообщение");
Но бота заранее создать нужно написав в телеграмме боту @botfather
 

p-a-h-a

Member
А без бота можно использовать этот код как сериал, для отладки?
Хорошая идея. Реализовал ее по минимуму сейчас. Все что нужно - зарегистрировать бота и получить api ключ. Написать новоиспеченному боту /start и из прошлого кода узнать chat_id. Далее отправку debug сообщений можно делать из 8 строчек кода функцией TelegramPrint.
Код:
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ESP8266HTTPClient.h>

void setup() {
  WiFi.mode(WIFI_STA);//
  WiFi.begin("ssid", "pass");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  TelegramPrint("Отладочное сообщение");

  ESP.deepSleep(0, RF_NO_CAL);//спим
}

void loop() {}

void TelegramPrint(String message) {
  std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);
  client->setInsecure();
  HTTPClient https;
  if (https.begin(*client, "https://api.telegram.org/bot1663160000:AAH01GFDQguCVp-dnpZuUoi6YwLqwaIpVPs/")) { // Тут свой ключ пишем
    https.addHeader("Content-Type", "application/json");
    https.POST("{\"method\":\"sendMessage\",\"chat_id\":400064015,\"text\":\"" + message + "\"}"); // Тут свой чат id пишем
    https.end();
  }
}
Естественно chat_id, apiKEY должны быть свои. Тут нерабочие данные.
 

vrd

Member
Немного не понял - куда переменные прописывать? Или по умолчанию из сериала подхватывает?
 

p-a-h-a

Member
Переменные прописывать вместо текста "Отладочное сообщение" в виде
Int x = 5;
TelegramPrint(String(x));
А лучше в строку все сложить и за один раз отправить.
String debagStr;
debagStr = "Отладочное сообщение: \n";
Int x = 5;
debagStr += "X=";
debagStr += String(x);
debagStr += "\n Конец сообщения;
TelegramPrint(debagStr);
Каждая отправка занимает время. У меня от секунды до 4х секунд примерно.
 

vrd

Member
Отправка каждого сообщения или пакета из например 10 переменных выходит до 4-х секунд?
Если я возьму три основные переменные (x, y, z) и буду их одной строкой слать в бота каждый цикл (4,5 секунды), это выйдет почти 10-16 секунд на цикл?
 

p-a-h-a

Member
Отправка каждого сообщения или пакета из например 10 переменных выходит до 4-х секунд?
Если я возьму три основные переменные (x, y, z) и буду их одной строкой слать в бота каждый цикл (4,5 секунды), это выйдет почти 10-16 секунд на цикл?
Одно сообщение это и есть пакет из множества символов. Строку собрали за 1-4 секунды ее отправили. Серверы телеграмм долго ответ на запрос посылают. Наверное связано с нагрузкой на серверы. Ботов много развелось нынче.
 

vrd

Member
Спасибо за помощь. Смог оптимизировать отправку сообщений под изменение переменных.

if ( sum != (x + y + z + (int(t / mi)) + (int(check / mi)))) {
mess = " Озонатор ";
mess += " \n";
mess += " X=";
mess += String(x);
mess += " Y=";
mess += String( y );
mess += " Z=";
mess += String(z);
mess += " F=";
mess += String(f);
mess += " \n";
mess += " Срабатывание таймера через-";
mess += String(int((t - (millis() - ti)) / mi));
mess += " мин";
mess += " \n";
mess += " Проверка времени через-";
mess += String(int((check - (millis() - t1)) / mi));
mess += " мин";
mess += " \n";
mess += " ";
mess += " \n";
delay(2);
TelegramPrint(mess);
delay(2);
sum = x + y + z + (int(t / mi)) + (int(check / mi));
delay(2);
mess = " ";
delay(2);
}

Появилась "хотелка" - считывать сообщения пользователя.
 

vrd

Member
Ботов много развелось нынче.
{"ok":true,"result":[{"update_id":74664327,
"message":{"message_id":646,"from":{"id":668666666,"is_bot":false,"first_name":"A","last_name":"Z","language_code":"ru"},"chat":{"id":668666666,"first_name":"A","last_name":"Z","type":"private"},"date":1625078161,"text":"Ozon reb"}}]}
Подскажите как выдрать ("text":"Ozon reb") из этого набора символов.
 

Виктор

New member
А как прочитать сообщение? Чтоб не только уведомления Бот отсылал, но и читать мог для дальнейшего анализа.
 

Сергей_Ф

Moderator
Команда форума

vrd

Member
Доработал таки этот код:
#include <ESP8266mDNS.h>
#include <WiFiClientSecure.h>
#include <ArduinoOTA.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>
#include "secrets.h"
int f = 0;
uint32_t t1 = 0;
int check = 0;
String mess;
int sum = 1;
const int h = 3600000;//час
const int mi = 60000;//минута
const int sek = 1000;//секунда
String doc;

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(115200);
mess = " Test ";
mess += " \n";
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { //Соеденение с WIFI
delay(100);
digitalWrite(LED_BUILTIN, HIGH);
delay(200);
digitalWrite(LED_BUILTIN, LOW);
delay(100);
f++;
Serial.print(" f=");
Serial.print(f);
if (f >= 999) { //Нет WIFI
Serial.flush();
delay(1000);
SPIFFS.end();
delay(1000);
ESP.restart();
}
Serial.println(" ");
}
mess += "Количество попыток подключения ";
mess += String(f);
mess += " \n";
f = 0;

// Port defaults to 8266
ArduinoOTA.setPort(8266);

// Hostname defaults to esp8266-[ChipID]
ArduinoOTA.setHostname("Test"); //Для каждой платы своё имя

// No authentication by default
ArduinoOTA.setPassword("z"); //Ставим свой пароль - можно закоментить

// Password can be set with it's md5 value as well
// MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
// ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");

ArduinoOTA.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH) {
type = "sketch";
} else { // U_FS
type = "filesystem";
}

// NOTE: if updating FS this would be the place to unmount FS using FS.end()
//Serial.println("Start updating " + type);
});
ArduinoOTA.onEnd([]() {
//Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
//Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
mess += "Ошибка ";
//Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) {
//Serial.println("Auth Failed");
mess += "Auth Failed ";
} else if (error == OTA_BEGIN_ERROR) {
//Serial.println("Begin Failed");
mess += "Begin Failed ";
} else if (error == OTA_CONNECT_ERROR) {
//Serial.println("Connect Failed");
mess += "Connect Failed ";
} else if (error == OTA_RECEIVE_ERROR) {
//Serial.println("Receive Failed");
mess += "Receive Failed ";
} else if (error == OTA_END_ERROR) {
//Serial.println("End Failed");
mess += "End Failed ";
}
mess += " \n";
});
ArduinoOTA.begin();
//Serial.println("Ready");
mess += "Ready ";
//Serial.print("IP address: ");
//Serial.println(WiFi.localIP());
mess += " \n";
}

void loop() {
digitalWrite(LED_BUILTIN, HIGH);
ArduinoOTA.handle();
if ( sum != ( f + check )) {
mess += " F=";
mess += String(f);
mess += " \n";
mess += " ";
mess += " \n";
doc = "";
delay(0);
TelegramPrint(mess, doc);
delay(0);
sum = f + check;
delay(0);
delay(0);
mess = " Test ";
mess += " \n";
}
digitalWrite(LED_BUILTIN, LOW);
if (millis() - t1 >= check) {
//check = mi * 10;
check = h;
t1 = millis();
f++;
}
if (f >= 99) {
f = 0;
check = sek;
delay(1000);
}
doc = Text();
delay(0);
//Работайте со стрингом как хотите
//Вариант на ифах ниже
if (doc.length() >= 7) { //Test f88
if (doc.charAt(0) == 'T') {
if (doc.charAt(1) == 'e') {
if (doc.charAt(2) == 's') {
if (doc.charAt(3) == 't') {
//doc = doc.charAt(6);
doc = doc.substring(6);
f = doc.toInt();
//f = atoi( + 5);
}
}
}
}
}

}

String TelegramPrint(String mess, String doc) {
std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);
client->setInsecure();
HTTPClient https;
https.begin(*client, "https://api.telegram.org/токен/" + doc); // Тут свой ключ пишем
https.addHeader("Content-Type", "application/json");
https.POST("{\"method\":\"sendMessage\",\"chat_id\":668666666 ,\"text\":\"" + mess + "\"}"); // Тут свой чат id пишем
delay(1);
String Answer = https.getString();
https.end();
delay(1);
//Serial.println(Answer);
return Answer;
}

String Text() {
delay(1);
doc = "getUpdates?offset=-1";//Для проверки последнего сообщения
delay(1);
DynamicJsonDocument Answer(1532);
deserializeJson(Answer, TelegramPrint(mess, doc), DeserializationOption::NestingLimit(5));// Парсим JSON-содержимое ответа сервера
//serializeJsonPretty(Answer, Serial); //Serial.println();
doc = "";
return Answer["result"][0]["message"]["text"];//text
}

В secrets.h спрятал повторяющиеся постоянные и дефайны.
Лежит этот файлик в "C:\Users\Admin\Documents\Arduino\libraries\Secrets" на вин10.
Присоединяется к любому скетчу как библиотека :)
 

Mоnk

Member
Прошу прощения, а BearSSL с какого ядра для ArduinoIDE появился? Мне с 2.4.2 на какую ближайшую подняться надо?
 
Сверху Снизу