
Многие знают и даже пробовали, что микроконтроллер esp32 позволяет управлять собой удалённо через интернет, используя протокол mqtt — что позволяет избавиться от необходимости выяснять IP адрес у esp32 и не заботиться о его постоянных изменениях, например, в случае перезагрузки микроконтроллера.
Однако в наше время было бы обидно пройти мимо гораздо более удобного способа, который, на мой взгляд, частенько многократно более удобен, и к тому же находится всегда под рукой — управление с помощью телеграм-бота…
Те, кто регулярно следят за моими статьями, знают, что я частенько использую способ с mqtt, который, по результатам моих тестов, очень хорошо себя проявил, во множестве применений: от управления робототехническими манипуляторами до руления машинками в реальном времени и игры с их помощью в робохоккей.
Для тех, кто думает, что будет большой лаг: я тоже так думал, однако, практика показала, что этот лаг не превышает 100 миллисекунд (а реально даже и ещё меньше), что субъективно воспринимается как «мгновенно».
Тем не менее, у этого способа есть и свои неудобства (маленькие, но всё же):
- Требуется внешний mqtt-брокер, который частенько отваливается (скажем, по причине тех же санкций — это то, с чем я сталкивался на практике) и не только.
- У этих брокеров обычно имеются довольно жёсткие ограничения на количество запросов в секунду, чтобы не перегружать брокер (я сталкивался даже с ограничением в один запрос в секунду максимум), что может быть неудобным в деле управления в реальном времени робототехническими устройствами.
- Это опять же надо регистрироваться на брокере, заводить аккаунт, да и вообще, разбираться, что собой представляет этот протокол и как работает (если вы раньше не имели с ним дела).
- Необходимость поднимать свой брокер, если вы хотите убрать зависимость от чужого.
- И т. д.
В общем, как говорил один из персонажей «Собачьего сердца» — «это какой-то позор» © :-))), так как в наше время всё то же самое можно делать с использованием того же самого telegram-бота.
Но на самом деле, приводя выше цитату из «Собачьего сердца» я здесь утрирую, так как просто нужно учитывать, что протокол mqtt появился гораздо раньше того же telegram-а, и с появлением последнего, многое упростилось, что мы и попробуем рассмотреть ниже.
Ну и опять же, гораздо удобнее управлять через мессенджер, который всегда под рукой, чем разбираться и использовать стороннюю систему…
Правда, тут есть нюансы: насколько мне известно, mqtt обеспечивает гораздо меньшую задержку, по сравнению с telegram-ботом (0,1 сек против 1-3 сек).
Эта задержка возникает из-за того, что в случае telegram-a, устройство (esp32) вынуждено опрашивать с определённой периодичностью (например, 0,2-3 сек) сервер — «нет ли новых сообщений?» Минусом такого подхода является излишняя нагрузка на сервер, за счёт генерации пустых запросов.
Минимально допустимый интервал опроса составляет от 0,2 сек и более. Если опрашивать сервер слишком часто (т. е. с интервалом менее 0,2 сек), то сервер временно заблокирует бота и будет возникать ошибка 429.
Такой способ отличается простотой реализацией и не требует постоянного соединения на основе протокола websocket (как у mqtt).
В противовес ему, в случае mqtt, мы постоянно подключены к серверу и подписаны на обновления в определённых топиках, за счёт чего мгновенно (менее 100 миллисекунд) получаем обновления, если появилось новое сообщение. Также, как мы видим, при этом способе не генерируются пустые запросы (как в случае с telegram-ботом).
Кстати говоря, в качестве интересной идеи на будущее: а что, если реализовать управление машинкой с использованием telegram-бота в качестве пульта управления? Это интересно как минимум с точки зрения проверки в реальных условиях временного лага, который возникает при этом случае.
Мои подозрения (по опыту, так как я ставил такой лаг принудительно, во время экспериментов с mqtt, при управлении роботами-хоккеистами): 200 миллисекунд — уже чувствуется, но вполне терпимо. И даже для роботов с управлением в реальном времени. Надо протестить на досуге...
Тем не менее, если у вас нет жёстких ограничений по времени отклика системы — например, мы управляем открытием окна для вентиляции теплицы, то этот способ вполне годится.
То есть, можно сказать, что вариант управления с помощью telegram-бота годится практически для 90% IoT-устройств, поэтому он и интересен для рассмотрения.
Итак, попробуем пошагово пройти все этапы создания telegram-бота и подключения его к esp32.
На первом этапе нам нужно запустить мессенджер telegram и забить в поиск:
@BotFather
Или просто перейти вот по этой ссылке: BotFather — так мы попадём на адрес создания ботов, где нового бота создаём командой /newbot.
После чего нам выдают секретный ключ (HTTP API), которым мы будем пользоваться для подключения к этому боту:

Также, как можно видеть в самой нижней части картинки выше, нам сообщили полный адрес, по которому можно найти нашего бота — запоминаем его ( t.me/......_bot), он нам понадобится дальше.
Кроме того, как можно видеть по картинке выше, здесь есть ряд возможностей, которые стоит изучить, для увеличения возможностей взаимодействия с вашим новым ботом.
Любое управление становится гораздо нагляднее, если оно имеет обратный отклик, поэтому нам потребуется код для загрузки в esp32, который выполняет две функции:
- Принимает входящие команды.
- Отправляет telegram-боту отклик, о том, как команда понята.
Один из самых простых и наглядных способов протестировать работу системы — зажигать и гасить встроенный в esp32 светодиод.
Сделаем так, чтобы мы могли из бота отправлять слова on, off (без учёта регистра, то есть система должна реагировать, независимо от того, прислали ли мы слова, написанные заглавными буквами или маленькими), в ответ на которые esp32 будет, соответственно, зажигать или гасить встроенный светодиод. Сделано так исключительно из соображений удобства, чтобы не задумываться ещё и о регистре надписей (ссылки на библиотеки для этого кода можно найти в конце статьи):
Полный код для загрузки в esp32 — с обработкой команд on/off
//Разработано с применением DeepSeek
//Весь код ниже приведён справочно, без какой-либо гарантии его надлежащей работы.
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>
// Настройки (ЗАМЕНИТЕ НА СВОИ!)
const char* WIFI_SSID = "вписать сюда"; // Название Wi-Fi-сети
const char* WIFI_PASS = "вписать сюда"; // Пароль Wi-Fi-сети
const char* BOT_TOKEN = "вписать сюда"; // Токен бота от @BotFather
WiFiClientSecure secureClient;
UniversalTelegramBot bot(BOT_TOKEN, secureClient);
const int LED_PIN = 2; // Встроенный светодиод
String CHAT_ID = ""; // Храним Chat ID
void debugLog(String message) {
Serial.println("[DEBUG] " + message);
}
void connectToWiFi() {
debugLog("Подключаемся к WiFi: " + String(WIFI_SSID));
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
debugLog("Успешно подключено! IP: " + WiFi.localIP().toString());
}
void handleCommand(String cmd, String chat_id) {
cmd.toLowerCase(); // Нормализуем команду
debugLog("Принята команда: '" + cmd + "' от chat_id: " + chat_id);
if (cmd == "on" || cmd == "/on") {
digitalWrite(LED_PIN, HIGH);
String response = "💡 Светодиод включён!";
if (bot.sendMessage(chat_id, response, "")) {
debugLog("Отправлено: '" + response + "'");
} else {
debugLog("Ошибка отправки сообщения!");
}
}
else if (cmd == "off" || cmd == "/off") {
digitalWrite(LED_PIN, LOW);
String response = "🌑 Светодиод выключен!";
if (bot.sendMessage(chat_id, response, "")) {
debugLog("Отправлено: '" + response + "'");
} else {
debugLog("Ошибка отправки сообщения!");
}
}
else {
String response = "Неизвестная команда. Используйте /on или /off";
bot.sendMessage(chat_id, response, "");
debugLog("Отправлен ответ на неизвестную команду");
}
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
connectToWiFi();
secureClient.setInsecure();
debugLog("Система инициализирована. Ожидаем команды...");
}
void loop() {
int newMessages = bot.getUpdates(bot.last_message_received + 1);
if (newMessages > 0) {
debugLog("Обнаружено новых сообщений: " + String(newMessages));
}
for (int i = 0; i < newMessages; i++) {
String chat_id = String(bot.messages[i].chat_id);
String text = bot.messages[i].text;
if (CHAT_ID == "") {
CHAT_ID = chat_id;
debugLog("Зарегистрирован новый Chat ID: " + CHAT_ID);
}
handleCommand(text, chat_id);
}
delay(500);
}
Работает это следующим образом: при первом получении сообщения от бота, микроконтроллер запоминает Chat ID и отвечает:«Бот-повелитель света готов к работе!».
Небольшая справка: наверняка на этом этапе у некоторых возникнет вопрос, а зачем вообще запоминать Chat ID, у нас ведь уже есть уникальный токен, не излишняя ли это процедура?
Дело тут в том, что токен бота и Chat ID это разные вещи, и запоминание Chat ID — необходимая процедура в целях безопасности: если этого не сделать, то любой пользователь сможет управлять вашим ботом, если узнает имя бота, а токен бота тут ни при чём, так как он только даёт доступ к API.
После чего, можно отправлять команды on, off. Можно и сразу отправить команду, без «предварительных раскланиваний» с микроконтроллером, — тогда он сначала вежливо ответит, а потом отпишется, что задание выполнено :-)
На дальнейшие отправки команд он будет отвечать только лаконично и по делу:

Казалось бы, всё работает и всё хорошо… Однако, telegram предоставляет чуть большие возможности, и грех было бы не воспользоваться ими!
А конкретнее: каждый раз набивать команды неудобно, что, если бы под эти команды сделать кнопки, нажимая на которые мы могли бы управлять устройством?
Запросто: telegram как раз предоставляет такой функционал.
Кроме того, для удобства наблюдения за происходящим, продублируем вывод сообщений ещё и в монитор порта Arduino IDE, а также добавим логирование происходящего на всех этапах:
[DEBUG] Подключаемся к WiFi: MyWiFi
.....
[DEBUG] Успешно подключено! IP: 192.168.1.100
[DEBUG] Система инициализирована. Ожидаем команды...
[DEBUG] Обнаружено новых сообщений: 1
[DEBUG] Зарегистрирован новый Chat ID: 123456789
[DEBUG] Принята команда: '/on' от chat_id: 123456789
[DEBUG] Отправлено: '💡 Светодиод включён!'
Теперь наш код принимает не только текстовые сообщения вида on/off, но и выполняет тот же самый функционал, только ещё и при нажатии на кнопки:
Полный код для загрузки в esp32 — с кнопками для telegram
//Разработано с применением DeepSeek
//Весь код ниже приведён справочно, без какой-либо гарантии его надлежащей работы.
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>
const char* WIFI_SSID = "вписать сюда"; // Название Wi-Fi-сети
const char* WIFI_PASS = "вписать сюда"; // Пароль Wi-Fi-сети
const char* BOT_TOKEN = "вписать сюда"; // Токен бота от @BotFather
WiFiClientSecure secureClient;
UniversalTelegramBot bot(BOT_TOKEN, secureClient);
const int LED_PIN = 2;
String CHAT_ID = "";
// Создаём клавиатуру с кнопками
String makeKeyboard() {
return "[["
"{ \"text\":\"🔆 ВКЛЮЧИТЬ\", \"callback_data\":\"LED_ON\" },"
"{ \"text\":\"🌑 ВЫКЛЮЧИТЬ\", \"callback_data\":\"LED_OFF\" }"
"]]";
}
void connectToWiFi() {
Serial.begin(115200);
Serial.print("Подключаемся к WiFi...");
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nПодключено! IP: " + WiFi.localIP().toString());
}
void handleCommand(String cmd, String chat_id) {
Serial.print("Получена команда: ");
Serial.println(cmd);
if (cmd == "LED_ON" || cmd == "/on" || cmd == "on" || cmd == "🔆 ВКЛЮЧИТЬ") {
digitalWrite(LED_PIN, HIGH);
bot.sendMessageWithReplyKeyboard(chat_id, "💡 Светодиод включён!", "", makeKeyboard());
Serial.println("Светодиод включён");
}
else if (cmd == "LED_OFF" || cmd == "/off" || cmd == "off" || cmd == "🌑 ВЫКЛЮЧИТЬ") {
digitalWrite(LED_PIN, LOW);
bot.sendMessageWithReplyKeyboard(chat_id, "🌑 Светодиод выключен!", "", makeKeyboard());
Serial.println("Светодиод выключен");
}
else {
bot.sendMessageWithReplyKeyboard(chat_id, "Используйте кнопки ниже:", "", makeKeyboard());
Serial.println("Неизвестная команда");
}
}
void setup() {
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
connectToWiFi();
secureClient.setInsecure();
Serial.println("Бот запущен. Ожидаем сообщений...");
}
void loop() {
int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
for (int i = 0; i < numNewMessages; i++) {
String chat_id = String(bot.messages[i].chat_id);
CHAT_ID = chat_id;
// Обрабатываем текст сообщения или callback_data
String message_text = bot.messages[i].text;
if (message_text != "") {
handleCommand(message_text, chat_id);
}
}
// Отправляем клавиатуру при первом запуске
static bool firstRun = true;
if (firstRun && CHAT_ID != "") {
bot.sendMessageWithReplyKeyboard(CHAT_ID, "Выберите действие:", "", makeKeyboard());
firstRun = false;
}
delay(500);
}
Теперь попробуем загрузить этот код в esp32, после чего запустим нашего telegram-бота и обратимся к микроконтроллеру:

Как можно видеть по картинке выше, после отправки любой команды, даже некорректной, микроконтроллер отвечает, присылая кнопки — изначально их нет, и они появляются внизу экрана, после первого сообщения от микроконтроллера.
После чего можно управлять микроконтроллером, нажимая на эти кнопки (в данном случае мы управляем встроенным светодиодом, включая и выключая его).
Кнопки в коде описываются в формате json, и это позволяет создавать весьма сложные клавиатуры, разной степени вложенности:
String keyboard = "[["
"{\"text\":\"🔆 ВКЛЮЧИТЬ\", \"callback_data\":\"ON\"},"
"{\"text\":\"🌑 ВЫКЛЮЧИТЬ\", \"callback_data\":\"OFF\"}"
"]]";
В коде выше: text — это то, что наблюдает пользователь, а callback_data — команда для esp32 (например, «ON»).
Непосредственная отправка кнопок происходит с помощью прикрепления их к сообщению одной строкой:
bot.sendMessageWithReplyKeyboard(chat_id, "Выберите действие:", "", keyboard);
В свою очередь, микроконтроллер мониторит эти сообщения в цикле:
int updates = bot.getUpdates(bot.last_message_received + 1);
for (int i=0; i<updates; i++) {
if (bot.messages[i].callback_data == "ON") {
digitalWrite(LED_PIN, HIGH);
bot.sendMessage(chat_id, "💡 Включено!");
}
}
Таким образом, используя описанные выше подходы, можно управлять IoT-устройствами весьма простым способом, который в большинстве случаев будет намного проще, чем mqtt: теплицы, полив цветов, видеонаблюдение (разворот вебкамеры, например) и прочее, прочее, прочее (на что воображения хватит).
Тем не менее, не стоит списывать и mqtt со счетов, так как потенциальные задержки при прохождении команд в варианте управления с использованием telegram-бота могут быть неприемлемыми для особо чувствительных к этому устройств.
Ниже вы можете найти библиотеки, которые следует установить, чтобы приведённые выше прошивки микроконтроллера работали. К слову — тестировалась вся работа на микроконтроллере esp32-wroom-32:
- ArduinoJson (Вызывается неявно, в составе одной из библиотек ниже, поэтому тоже надо установить).
- Universal-Arduino-Telegram-Bot.
- ESP32_WiFiClientSecure.
© 2025 ООО «МТ ФИНАНС»
Telegram-канал со скидками, розыгрышами призов и новостями IT 💻
