
Многие знают и даже пробовали, что микроконтроллер 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 💻

