Руководства · 13 мин чтения

Telegram-бот на ESP32: уведомления, управление светодиодом и реле

Telegram-бот на ESP32: токен от BotFather, chat ID, настройка UniversalTelegramBot, уведомления о движении и газе, управление реле командами и ответы только тебе.

Telegram-бот на ESP32 позволяет плате ESP32 у тебя дома отправлять сообщения на телефон и выполнять команды, которые ты присылаешь в ответ. Когда у двери появляется движение или на кухне обнаружен газ, уведомление мгновенно приходит тебе в карман; напиши «/ac» — и реле включит лампу, напиши «/kapat» — и выключит. Не нужно писать своё приложение для телефона, открывать порт на роутере или платить за облачный сервис: хватит бесплатного Bot API от Telegram и встроенного Wi-Fi у ESP32.

В этом руководстве с нуля соберём рабочую систему: создадим бота через BotFather и получим его токен, узнаем твой chat ID, установим библиотеки UniversalTelegramBot и ArduinoJson и отправим первое сообщение с ESP32. Затем добавим уведомления о движении и газе с PIR-датчиком и датчиком газа MQ-2, а также управление светодиодом и реле командами Telegram. Ещё разберём, как сделать так, чтобы бот отвечал только на твой ID, настройку сертификата, отличия на ESP8266 и Raspberry Pi Pico W и самые частые ошибки по порядку.

Отладочная плата ESP32 в роли Telegram-бота
Благодаря встроенному Wi-Fi ESP32 подключается прямо к серверу Telegram; дополнительный модуль или шлюз не нужен.

Что такое Telegram-бот на ESP32 и как он работает?

В Telegram бот — это особый аккаунт, которым управляет программа, а не человек; в нашем проекте эту программу выполняет ESP32. ESP32 и твой телефон никогда не соединяются напрямую: оба общаются с сервером Telegram. Когда ты пишешь боту «/ac» с телефона, сообщение ждёт на сервере. Каждую секунду ESP32 отправляет на api.telegram.org зашифрованный HTTPS-запрос (getUpdates) с вопросом «есть для меня новые сообщения?», забирает сообщение и выполняет его. Чтобы отправить уведомление, она делает запрос sendMessage в обратную сторону. Поскольку соединение всегда открывает ESP32, на роутере не нужны ни проброс портов, ни статический IP; плата работает в любой сети Wi-Fi 2,4 GHz с выходом в интернет.

ПонятиеДля чего нужноПример
BotFatherБот Telegram для создания ботов и управления ими/newbot, /setcommands, /revoke (команды BotFather)
Токен ботаПароль бота; с ним твой код подключается к Telegram1234567890:AAE... (число, двоеточие, длинная строка)
Chat ID (ID чата)Номер человека или группы, куда уходит сообщениеЧеловек: 123456789, группа: -1001234567890
getUpdatesЗабирает с сервера новые сообщения, отправленные ботуbot.getUpdates(...)
sendMessageОтправляет сообщение на указанный chat IDbot.sendMessage(CHAT_ID, "Привет")
КомандаКороткое сообщение, начинающееся с /, которое понимает бот/ac, /kapat, /durum

Почему Telegram? Сравнение с другими способами получать уведомления

СпособПлюсыМинусыЛучше всего для
Telegram-ботБесплатно, мгновенные уведомления, команды в обе стороны, не нужно открывать портыНет графиков и готовой панелиСигнализация и простое дистанционное управление
Blynk IoTГотовая панель с кнопками, индикаторами и графикамиОграничения на сообщения и устройства в бесплатном планеПанели мониторинга датчиков
Электронная почта (SMTP)Работает на любом телефоне, подходит для длинных отчётовЗадержки, сложно принимать командыЕжедневные отчёты
SMS (SIM800L)Не нужны ни Wi-Fi, ни интернетSIM-карта и плата за SMS, дополнительный модульДачи и сараи без интернета
Веб-сервер на ESP32Полностью локально и бесплатноОбычно доступен только из той же сети, уведомлений нетПанель управления внутри дома

Короче говоря, Telegram — самый простой и дешёвый вариант для проектов в духе «сообщи мне, когда что-то произойдёт, и сделай вот это, когда я пришлю команду». Если хочешь следить за данными датчиков на графиках, тебе может больше подойти руководство по Blynk и ESP32; если уведомления нужны из места без Wi-Fi, загляни в руководство по GSM-модулю SIM800L.

Шаг 1: создай бота через BotFather и получи токен

  1. Открой Telegram на телефоне или компьютере, введи BotFather в строку поиска и выбери официальный аккаунт с синей галочкой рядом с именем. Остерегайся поддельных аккаунтов с похожими именами.
  2. Нажми Start («Запустить») и отправь команду /newbot.
  3. Сначала BotFather спросит отображаемое имя бота; введи любое, например «Домашняя сигнализация».
  4. Затем он попросит имя пользователя. Оно должно быть уникальным, состоять только из латинских букв, цифр и подчёркиваний и заканчиваться на bot, например my_home_alarm_bot. Если имя занято, добавь в конце цифру и попробуй ещё раз.
  5. BotFather ответит сообщением «Done! Congratulations on your new bot.» (готово, поздравляем с новым ботом), в котором будут ссылка на бота и его токен. Токен выглядит как 1234567890:AAE...: число, двоеточие и длинная строка символов. Скопируй его целиком и сохрани в надёжном месте.
  6. Открой своего бота по ссылке от BotFather и нажми Start. Этот шаг обязателен: в Telegram бот не может первым написать пользователю, поэтому разговор всегда начинаешь ты.
Токен — это ключ к твоему боту: тот, кто его получит, сможет читать сообщения, отправленные боту, писать от его имени и перехватывать команды для твоей ESP32 раньше неё. Никогда не публикуй код с токеном на форумах, в скриншотах или в открытом репозитории GitHub. Если есть подозрение, что токен утёк, отмени старый командой /revoke в BotFather, получи новый токен и заново загрузи код в плату.

Шаг 2: как узнать свой chat ID в Telegram

Токен бота отвечает на вопрос «какой бот?», а chat ID — на вопрос «кому идёт сообщение?». У каждого пользователя, группы и канала Telegram есть постоянный числовой ID, и это не то же самое, что имя пользователя, начинающееся с @. Есть три простых способа узнать свой chat ID:

  1. Через ID-бота: найди в Telegram ID-бота, например @userinfobot, и нажми «Запустить» (Start); он пришлёт твой номер в строке Id. Эти боты не твои, они только показывают твой ID.
  2. Через браузер: сначала отправь любое сообщение своему боту. Затем открой в браузере на компьютере api.telegram.org/botTOKEN/getUpdates (вставь свой токен вместо TOKEN, а слово «bot» перед ним оставь). В появившемся тексте число в "chat":{"id":123456789 и есть твой chat ID. Если страница показывает пустой список result, напиши боту ещё раз и обнови страницу.
  3. Через ESP32: после загрузки кода с командами (он ниже) ID каждого, у кого нет доступа, выводится в монитор порта в строке «unauthorized ID» (неавторизованный ID). Когда захочешь добавить члена семьи, попроси его написать боту и посмотри его номер там.
Если бот будет работать в семейной группе, добавь его в группу, напиши там сообщение и снова открой страницу getUpdates: ID групп начинается со знака минус, а ID супергрупп — с -100. Забытый минус — самая частая причина ошибки «chat not found». В режиме приватности, который включён по умолчанию, бот не читает переписку в группе; он видит только адресованные ему команды, начинающиеся с /, а боту, который работает по командам, больше ничего и не нужно.

Шаг 3: установи UniversalTelegramBot и ArduinoJson

  1. Если пакет плат ESP32 ещё не установлен в Arduino IDE, сначала установи его; шаги описаны в статье Что такое ESP32?.
  2. Открой «Инструменты › Управлять библиотеками» (Tools › Manage Libraries), введи UniversalTelegramBot в строку поиска и установи библиотеку от автора Brian Lough. Код из этого руководства скомпилирован с UniversalTelegramBot 1.3.0, ArduinoJson 7 и пакетом плат ESP32 версии 2.0.11.
  3. Если установщик спросит про зависимости, выбери Установить все (Install all); если не спросит, найди в том же окне ArduinoJson и отдельно установи библиотеку Benoit Blanchon.
  4. В меню «Файл › Примеры › UniversalTelegramBot › ESP32» есть готовые примеры вроде FlashLED; код из этого руководства — их упрощённая версия с добавленной защитой.

UniversalTelegramBot написана в стиле ArduinoJson 6-й версии, но без проблем компилируется и с ArduinoJson 7. Если в Arduino IDE включены предупреждения компилятора, появятся строки вроде «'DynamicJsonDocument' is deprecated: use JsonDocument instead» (класс устарел, используй JsonDocument); это предупреждения, а не ошибки, и программа работает нормально. Если при установке библиотек что-то не получается, загляни в руководство Как установить библиотеку Arduino.

Компоненты и подключение

Для полного проекта понадобятся отладочная плата ESP32, PIR-датчик движения HC-SR501, модуль датчика газа MQ-2, модуль реле на 5 V, по одному резистору на 10 kΩ и 20 kΩ, макетная плата и провода-перемычки. В качестве светодиода используем встроенный синий светодиод ESP32 на GPIO 2. Чтобы попробовать первые два шага, хватит только ESP32 и USB-кабеля; датчики можно добавить позже.

ESP32
ESP32
PIR HC-SR501
PIR HC-SR501
MQ-2
MQ-2
Модуль реле
Модуль реле
ПодключениеESP32ESP8266 (NodeMCU)Raspberry Pi Pico W
PIR VCCVIN (5V)VIN (5V)VBUS (5V)
PIR OUTGPIO 27D5 (GPIO 14)GP16
MQ-2 VCCVIN (5V)VIN (5V)VBUS (5V)
MQ-2 AO (через делитель 10 kΩ / 20 kΩ)GPIO 34A0GP26 (ADC0)
Реле VCCVIN (5V)VIN (5V)VBUS (5V)
Реле INGPIO 26D1 (GPIO 5)GP15
СветодиодGPIO 2 (встроенный)D4 (встроенный, горит при LOW)«LED» (встроенный)
Все GNDGNDGNDGND
Пины ESP32, ESP8266 и Pico работают от 3,3 V. Когда модуль MQ-2 питается от 5 V, его выход AO может подниматься до 5 V, поэтому собери делитель напряжения (номиналы удобно проверить в утилите делителя напряжения): подключи AO к аналоговому пину через 10 kΩ, а аналоговый пин к GND через 20 kΩ. Так 5 V снижаются примерно до 3,3 V. Если реле будет коммутировать сетевую нагрузку 230 V, всегда делай подключение при вынутой из розетки вилке и попроси помощи у взрослого; подробности в статье Что такое модуль реле?.

Удели внимание и питанию: один только нагреватель MQ-2 потребляет около 150 mA, катушка реле — около 70 mA, а ESP32 при передаче по Wi-Fi может кратковременно потреблять до 250 mA. USB-порт компьютера не всегда выдаёт такой суммарный ток, и плата может перезагрузиться как раз в момент отправки сообщения. Используй блок питания 5 V не меньше чем на 1 A и хороший кабель; если проблема не уходит, прочитай статью Brownout и Guru Meditation на ESP32. Все пины своей платы можно посмотреть в утилите распиновки.

Первый тест: отправляем сообщение с ESP32 в Telegram

Прежде чем переходить к датчикам, проверим токен и chat ID самым простым скетчем. В коде ниже замени строки с именем сети Wi-Fi, паролем, BOT_TOKEN и CHAT_ID своими данными и загрузи скетч в плату. Затем открой монитор порта на скорости 115200 бод:

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <WiFiClientSecure.h>
3#include <UniversalTelegramBot.h>
4#include <ArduinoJson.h>
5
6const char* WIFI_SSID = "AgAdi";          // Wi-Fi adın (yalnız 2,4 GHz) / your Wi-Fi name (2.4 GHz only)
7const char* WIFI_PASS = "Sifre123";       // Wi-Fi şifren / your Wi-Fi password
8#define BOT_TOKEN "1234567890:AAExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"   // BotFather'ın verdiği token / token from BotFather
9#define CHAT_ID   "123456789"             // kendi Telegram ID'n / your own Telegram ID
10
11WiFiClientSecure client;                  // şifreli (HTTPS) bağlantı / encrypted (HTTPS) connection
12UniversalTelegramBot bot(BOT_TOKEN, client);
13
14void setup() {
15  Serial.begin(115200);
16  WiFi.mode(WIFI_STA);
17  WiFi.begin(WIFI_SSID, WIFI_PASS);
18  Serial.print("Wi-Fi'ye baglaniyor / connecting to Wi-Fi");
19  while (WiFi.status() != WL_CONNECTED) {
20    delay(500);
21    Serial.print(".");
22  }
23  Serial.println();
24  Serial.println(WiFi.localIP());
25
26  client.setCACert(TELEGRAM_CERTIFICATE_ROOT);   // api.telegram.org kök sertifikası / root certificate of api.telegram.org
27
28  if (bot.sendMessage(CHAT_ID, "Merhaba! ESP32 çevrimiçi / Hello! ESP32 is online")) {
29    Serial.println("Mesaj gonderildi / message sent");
30  } else {
31    Serial.println("Mesaj gonderilemedi / message failed");
32  }
33}
34
35void loop() {
36}

Через несколько секунд бот должен прислать тебе в Telegram «Hello! ESP32 is online», а в мониторе порта должно появиться «Mesaj gonderildi / message sent». sendMessage() возвращает true, когда сообщение доставлено; если видишь «message failed», проблема в подключении к Wi-Fi, токене, chat ID или настройке сертификата. Прежде чем винить код, открой в браузере api.telegram.org/botTOKEN/getMe: при правильном токене появятся "ok":true и имя бота, при неправильном — «Unauthorized».

Настройка сертификата: setCACert или setInsecure?

Telegram принимает только HTTPS, поэтому в коде используется WiFiClientSecure вместо обычного WiFiClient. При зашифрованном соединении ESP32 должна убедиться, что сервер на другом конце действительно api.telegram.org; для этого она проверяет сертификат сервера по корневому сертификату на вершине цепочки. UniversalTelegramBot поставляется с этим корневым сертификатом, готовым к использованию, под именем TELEGRAM_CERTIFICATE_ROOT. Цепочка сертификатов Telegram ведёт к корневому центру Go Daddy Root Certificate Authority - G2, который действует до конца 2037 года; если Telegram когда-нибудь сменит поставщика сертификатов, библиотеку тоже придётся обновить.

НастройкаЧто делаетБезопасностьКогда использовать
client.setCACert(TELEGRAM_CERTIFICATE_ROOT)Шифрует соединение и проверяет подлинность сервераВысокаяВсегда: это рекомендуемая настройка
client.setInsecure()Шифрует соединение, но не проверяет подлинность сервераСредняя: не заметит поддельный сервер посерединеБыстрый тест, чтобы исключить проблемы с сертификатом
Ни одной из этих строкВ актуальных ядрах ESP32 соединение вообще не устанавливаетсяНе работаетНикогда: сообщение не уходит, а в мониторе порта нет никакой ошибки
ESP8266: setTrustAnchors(&cert)Аналог для ESP8266; сертификат передаётся как X509ListВысокаяNodeMCU и Wemos D1 Mini; нужно правильное время

Управление светодиодом и реле командами Telegram (/ac, /kapat)

Теперь сделаем бота двусторонним. Код ниже раз в секунду спрашивает у Telegram новые сообщения; если текст — /ac (по-турецки «вкл»), он включает реле и светодиод, /kapat («выкл») выключает их, /durum («состояние») сообщает текущее состояние, а /start присылает список команд. Команды можно переименовать в /on и /off, но учти: команды Telegram могут содержать только строчные латинские буквы, цифры и подчёркивания и быть длиной не больше 32 символов. Команда с буквами с диакритикой, например «/aç», не распознаётся как команда, на которую можно нажать.

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <WiFiClientSecure.h>
3#include <UniversalTelegramBot.h>
4#include <ArduinoJson.h>
5
6const char* WIFI_SSID = "AgAdi";
7const char* WIFI_PASS = "Sifre123";
8#define BOT_TOKEN "1234567890:AAExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
9#define CHAT_ID   "123456789"                 // yalnız bu ID'ye yanıt verilir / only this ID gets answers
10
11const int LED_PIN  = 2;                       // çoğu DevKit'te dahili LED / onboard LED on most DevKits
12const int ROLE_PIN = 26;                      // röle modülünün IN pini / relay module IN pin
13const bool ROLE_AKTIF_LOW = true;             // çoğu modül LOW'da çeker / most modules switch on with LOW
14
15const unsigned long KONTROL_ARALIGI = 1000;   // Telegram'a saniyede bir sor / ask Telegram once per second
16unsigned long sonKontrol = 0;
17bool roleAcik = false;
18
19WiFiClientSecure client;
20UniversalTelegramBot bot(BOT_TOKEN, client);
21
22void roleYaz(bool acik) {
23  roleAcik = acik;
24  if (ROLE_AKTIF_LOW) digitalWrite(ROLE_PIN, acik ? LOW : HIGH);
25  else                digitalWrite(ROLE_PIN, acik ? HIGH : LOW);
26  digitalWrite(LED_PIN, acik ? HIGH : LOW);   // LED röle durumunu gösterir / LED mirrors the relay
27}
28
29void mesajlariIsle(int adet) {
30  for (int i = 0; i < adet; i++) {
31    String chatId = bot.messages[i].chat_id;
32    String metin  = bot.messages[i].text;
33
34    // Güvenlik: tanımadığın kişiye cevap verme / security: never answer strangers
35    if (chatId != CHAT_ID) {
36      Serial.println("Yetkisiz ID / unauthorized ID: " + chatId);
37      continue;
38    }
39
40    int at = metin.indexOf('@');              // gruptaki "/ac@bot_adi" -> "/ac" / "/ac@bot_name" in groups -> "/ac"
41    if (at > 0) metin = metin.substring(0, at);
42
43    if (metin == "/start") {
44      String yardim = "Merhaba " + bot.messages[i].from_name + "!\n";
45      yardim += "/ac - röleyi aç / relay ON\n";
46      yardim += "/kapat - röleyi kapat / relay OFF\n";
47      yardim += "/durum - son durum / status";
48      bot.sendMessage(chatId, yardim);
49    } else if (metin == "/ac") {
50      roleYaz(true);
51      bot.sendMessage(chatId, "Röle AÇIK / relay ON");
52    } else if (metin == "/kapat") {
53      roleYaz(false);
54      bot.sendMessage(chatId, "Röle KAPALI / relay OFF");
55    } else if (metin == "/durum") {
56      bot.sendMessage(chatId, roleAcik ? "Röle AÇIK / relay ON" : "Röle KAPALI / relay OFF");
57    } else {
58      bot.sendMessage(chatId, "Bilinmeyen komut, /start yaz / unknown command, send /start");
59    }
60  }
61}
62
63void setup() {
64  Serial.begin(115200);
65  pinMode(LED_PIN, OUTPUT);
66  pinMode(ROLE_PIN, OUTPUT);
67  roleYaz(false);                             // açılışta röle kapalı / relay off at boot
68
69  WiFi.mode(WIFI_STA);
70  WiFi.begin(WIFI_SSID, WIFI_PASS);
71  while (WiFi.status() != WL_CONNECTED) delay(500);
72  Serial.println(WiFi.localIP());
73
74  client.setCACert(TELEGRAM_CERTIFICATE_ROOT);
75  bot.sendMessage(CHAT_ID, "Bot hazır, /start yaz / bot ready, send /start");
76}
77
78void loop() {
79  if (millis() - sonKontrol > KONTROL_ARALIGI) {
80    int adet = bot.getUpdates(bot.last_message_received + 1);   // yeni mesaj var mı? / any new messages?
81    while (adet) {
82      mesajlariIsle(adet);
83      adet = bot.getUpdates(bot.last_message_received + 1);
84    }
85    sonKontrol = millis();
86  }
87}
СтрокаЧто делает
bot.getUpdates(bot.last_message_received + 1)Запрашивает сообщения после последнего обработанного и возвращает, сколько их пришло; +1 не даёт тому же сообщению прийти снова
bot.messages[i].chat_idID чата, из которого пришло сообщение; туда уходит ответ, и по нему идёт проверка безопасности
bot.messages[i].text (текст сообщения)Входящий текст; с ним сравнивается команда
metin.indexOf('@')Отрезает часть @bot_name, которую Telegram добавляет к командам в группах
ROLE_AKTIF_LOWБольшинство модулей реле включаются сигналом LOW; если твой модуль включается сигналом HIGH, поставь false
KONTROL_ARALIGIЧастота опроса; при 1000 мс реакция быстрая, при 3000–5000 мс нагрузка на сеть меньше

Безопасность: пусть бот отвечает только на твой ID

Имена ботов в Telegram публичны, и их можно найти поиском. Если кто-то угадает my_home_alarm_bot или увидит его на скриншоте и отправит ему /ac, ESP32 без проверки выполнит и эту команду. Поэтому самая важная строка в коде — проверка chatId != CHAT_ID. Твой chat ID не обязан быть секретным: защита держится на том, что Telegram на своей стороне проверяет, кто отправил каждое сообщение, и подделать чужой ID никто не может. Совсем не отвечать незнакомцам — тоже осознанное решение: пока бот молчит, никто даже не поймёт, что он работает.

  • Используй белый список: храни разрешённые ID в массиве, игнорируй все остальные сообщения и добавляй членов семьи по одному.
  • Проверяй человека в группах: в группе chat ID — это ID группы; если команды должны отправлять только определённые люди, сравнивай from_id, а не chat_id.
  • Храни токен в отдельном файле: вынеси токен и пароль Wi-Fi в файл вроде secrets.h и не прикладывай его, когда делишься кодом.
  • Пропускай старые команды: /ac, отправленная во время отключения электричества, не должна сработать в неожиданный момент, когда плата снова включится; об этом заботится очистка при запуске в полном коде.
  • Безопасное состояние при запуске: при каждой загрузке платы начинай с выключенного реле; для таких нагрузок, как обогреватель или насос, это очень важно.
  • Не доверяй критичные задачи только боту: для дверного замка или котла подумай, к чему может привести ошибочная команда, и добавь подтверждающее сообщение или ограничение по времени.

Сигнализация движения и газа: полный проект с уведомлениями в Telegram

Теперь соберём всё вместе. Код ниже присылает тебе уведомление в Telegram с отметкой времени, когда PIR-датчик замечает движение и когда показание газа MQ-2 превышает порог. Одновременно он слушает команды /ac, /kapat, /alarm_ac, /alarm_kapat и /durum, по команде /start показывает внизу экрана меню из кнопок, которые отправляют команду одним нажатием, и добавляет команды в кнопку «Меню» Telegram. Подробности о каждом датчике — в руководствах по PIR-датчику движения и датчику газа MQ-2.

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <WiFiClientSecure.h>
3#include <UniversalTelegramBot.h>
4#include <ArduinoJson.h>
5#include <time.h>
6
7const char* WIFI_SSID = "AgAdi";
8const char* WIFI_PASS = "Sifre123";
9#define BOT_TOKEN "1234567890:AAExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
10#define CHAT_ID   "123456789"                  // bildirimlerin gideceği ID / the ID that receives alerts
11
12// Komut verebilecek kişiler; aile üyesi eklemek için: { CHAT_ID, "222222222" }
13// People allowed to send commands; to add a family member: { CHAT_ID, "222222222" }
14const char* YETKILI[] = { CHAT_ID };
15const int YETKILI_SAYISI = sizeof(YETKILI) / sizeof(YETKILI[0]);
16
17const int LED_PIN  = 2;                        // dahili LED / onboard LED
18const int ROLE_PIN = 26;                       // röle modülü IN / relay module IN
19const int PIR_PIN  = 27;                       // PIR sensörü OUT / PIR sensor OUT
20const int GAZ_PIN  = 34;                       // MQ-2 AO, gerilim bölücü üzerinden / MQ-2 AO through a voltage divider
21const bool ROLE_AKTIF_LOW = true;              // çoğu modül LOW'da çeker / most modules switch on with LOW
22
23const int GAZ_ESIK = 1800;                     // temiz havadaki değere göre ayarla / tune it from your clean-air reading
24const int GAZ_FARK = 200;                      // histerezis payı / hysteresis margin
25const unsigned long HAREKET_BEKLEME = 60000;   // iki hareket bildirimi arası en az 60 sn / at least 60 s between motion alerts
26const unsigned long GAZ_ISINMA = 120000;       // MQ-2 ilk 2 dakika ısınır / MQ-2 warms up for the first 2 minutes
27const unsigned long KONTROL_ARALIGI = 1000;    // Telegram'a saniyede bir sor / poll Telegram once per second
28
29WiFiClientSecure client;
30UniversalTelegramBot bot(BOT_TOKEN, client);
31
32bool alarmKurulu = true;                       // hareket alarmı açık mı / is the motion alarm armed
33bool roleAcik = false;
34bool gazVar = false;
35unsigned long sonKontrol = 0;
36unsigned long sonHareket = 0;
37
38String saat() {                                // "14:05:31" biçiminde saat / time as "14:05:31"
39  struct tm t;
40  if (!getLocalTime(&t, 100)) return "--:--:--";
41  char buf[9];
42  strftime(buf, sizeof(buf), "%H:%M:%S", &t);
43  return String(buf);
44}
45
46bool yetkiliMi(const String& id) {
47  for (int i = 0; i < YETKILI_SAYISI; i++) {
48    if (id == YETKILI[i]) return true;
49  }
50  return false;
51}
52
53void roleYaz(bool acik) {
54  roleAcik = acik;
55  if (ROLE_AKTIF_LOW) digitalWrite(ROLE_PIN, acik ? LOW : HIGH);
56  else                digitalWrite(ROLE_PIN, acik ? HIGH : LOW);
57}
58
59String durumMetni() {
60  String s = "Röle / relay: ";
61  s += roleAcik ? "AÇIK / ON" : "KAPALI / OFF";
62  s += "\nAlarm: ";
63  s += alarmKurulu ? "KURULU / ARMED" : "KAPALI / DISARMED";
64  s += "\nGaz / gas: " + String(analogRead(GAZ_PIN));
65  s += "\nWi-Fi: " + String(WiFi.RSSI()) + " dBm";
66  return s;
67}
68
69void mesajlariIsle(int adet) {
70  for (int i = 0; i < adet; i++) {
71    String chatId = bot.messages[i].chat_id;
72    String metin  = bot.messages[i].text;
73
74    if (!yetkiliMi(chatId)) {                  // yabancıya sessiz kal / stay silent to strangers
75      Serial.println("Yetkisiz ID / unauthorized ID: " + chatId);
76      continue;
77    }
78    int at = metin.indexOf('@');               // "/ac@bot_adi" -> "/ac"
79    if (at > 0) metin = metin.substring(0, at);
80
81    if (metin == "/ac") {
82      roleYaz(true);
83      bot.sendMessage(chatId, "Röle AÇIK / relay ON");
84    } else if (metin == "/kapat") {
85      roleYaz(false);
86      bot.sendMessage(chatId, "Röle KAPALI / relay OFF");
87    } else if (metin == "/alarm_ac") {
88      alarmKurulu = true;
89      bot.sendMessage(chatId, "Hareket alarmı kuruldu / motion alarm armed");
90    } else if (metin == "/alarm_kapat") {
91      alarmKurulu = false;
92      bot.sendMessage(chatId, "Hareket alarmı kapatıldı / motion alarm disarmed");
93    } else if (metin == "/durum") {
94      bot.sendMessage(chatId, durumMetni());
95    } else {                                   // /start ve diğer her şey: tuş menüsü / /start and anything else: button menu
96      String klavye = "[[\"/ac\",\"/kapat\"],[\"/alarm_ac\",\"/alarm_kapat\"],[\"/durum\"]]";
97      bot.sendMessageWithReplyKeyboard(chatId, "Komut seç / choose a command", "", klavye, true);
98    }
99  }
100}
101
102void setup() {
103  Serial.begin(115200);
104  pinMode(LED_PIN, OUTPUT);
105  pinMode(ROLE_PIN, OUTPUT);
106  pinMode(PIR_PIN, INPUT);
107  roleYaz(false);                              // açılışta röle kapalı / relay off at boot
108
109  WiFi.mode(WIFI_STA);
110  WiFi.begin(WIFI_SSID, WIFI_PASS);
111  while (WiFi.status() != WL_CONNECTED) {
112    delay(500);
113    Serial.print(".");
114  }
115  Serial.println(WiFi.localIP());
116
117  client.setCACert(TELEGRAM_CERTIFICATE_ROOT); // api.telegram.org kök sertifikası / root certificate of api.telegram.org
118  bot.maxMessageLength = 4000;                 // büyük mesajlarda takılmayı önler / prevents hanging on big messages
119  configTime(3 * 3600, 0, "pool.ntp.org");     // Türkiye UTC+3; kendi saat dilimini yaz / Turkey is UTC+3, set your own zone
120
121  // Telegram'daki Menü düğmesi; komutlar küçük harf, Türkçe karakter yok
122  // The Menu button in Telegram; commands are lowercase with no special letters
123  bot.setMyCommands("[{\"command\":\"ac\",\"description\":\"Röleyi aç\"},"
124                    "{\"command\":\"kapat\",\"description\":\"Röleyi kapat\"},"
125                    "{\"command\":\"alarm_ac\",\"description\":\"Hareket alarmını kur\"},"
126                    "{\"command\":\"alarm_kapat\",\"description\":\"Hareket alarmını kapat\"},"
127                    "{\"command\":\"durum\",\"description\":\"Durumu göster\"}]");
128
129  // Kart kapalıyken gelen eski komutları atla / skip old commands sent while the board was off
130  while (bot.getUpdates(bot.last_message_received + 1)) { }
131
132  bot.sendMessage(CHAT_ID, "Sistem açıldı / system started " + saat());
133}
134
135void loop() {
136  unsigned long simdi = millis();
137
138  // 1) Hareket alarmı / motion alarm
139  if (alarmKurulu && digitalRead(PIR_PIN) == HIGH && simdi - sonHareket > HAREKET_BEKLEME) {
140    sonHareket = simdi;
141    digitalWrite(LED_PIN, HIGH);
142    bot.sendMessage(CHAT_ID, "Hareket algılandı! / motion detected! " + saat());
143    digitalWrite(LED_PIN, LOW);
144  }
145
146  // 2) Gaz alarmı: ısınmadan sonra, susturulamaz / gas alarm: after warm-up, cannot be muted
147  if (simdi > GAZ_ISINMA) {
148    int gaz = analogRead(GAZ_PIN);             // 0-4095
149    if (!gazVar && gaz > GAZ_ESIK) {
150      gazVar = true;
151      bot.sendMessage(CHAT_ID, "GAZ ALARMI! / GAS ALARM! " + String(gaz) + " " + saat());
152    } else if (gazVar && gaz < GAZ_ESIK - GAZ_FARK) {
153      gazVar = false;
154      bot.sendMessage(CHAT_ID, "Gaz normale döndü / gas back to normal: " + String(gaz));
155    }
156  }
157
158  // 3) Telegram komutları / Telegram commands
159  if (simdi - sonKontrol > KONTROL_ARALIGI && WiFi.status() == WL_CONNECTED) {
160    int adet = bot.getUpdates(bot.last_message_received + 1);
161    while (adet) {
162      mesajlariIsle(adet);
163      adet = bot.getUpdates(bot.last_message_received + 1);
164    }
165    sonKontrol = millis();
166  }
167}
НастройкаЗначениеПояснение
GAZ_ESIK1800Сырое значение АЦП от 0 до 4095; подбери его по своему показанию на чистом воздухе
GAZ_FARK200Насколько показание должно опуститься ниже порога, прежде чем придёт сообщение «снова норма»; не даёт уведомлениям скакать туда-сюда на границе
HAREKET_BEKLEME60000 мсОставляет не меньше 60 секунд между двумя уведомлениями о движении
GAZ_ISINMA120000 мсПока MQ-2 прогревается, показания завышены; первые 2 минуты газ не проверяется
KONTROL_ARALIGI1000 мсКак часто у Telegram запрашиваются новые сообщения
bot.maxMessageLength4000Самый длинный ответ, который читает библиотека; по умолчанию 1500

Две сигнализации в коде намеренно работают по-разному. Сигнализацию движения защищает пауза между уведомлениями (cooldown): PIR-датчик срабатывает снова и снова, пока кто-то ходит по комнате, и без паузы телефон заполнился бы десятками сообщений в минуту. Поскольку таймер паузы стартует с нуля, первое уведомление может прийти не раньше чем через 60 секунд после запуска платы, и это как раз совпадает с примерно одной минутой, которая нужна PIR-датчику, чтобы стабилизироваться после включения. Газовая сигнализация вместо этого использует гистерезис: она предупреждает один раз, когда показание превышает порог, сообщает «снова норма», только когда оно опустится на 200 единиц ниже порога, и в целях безопасности её нельзя заглушить командой /alarm_kapat. Telegram тоже не разрешает слишком частые сообщения: если пытаться отправить больше одного сообщения в секунду в один чат или больше 20 в минуту в группу, придёт ошибка «Too Many Requests: retry after» (слишком много запросов).

Подбирай GAZ_ESIK измерением, а не на глаз: дай плате поработать на чистом воздухе 5–10 минут, отправь /durum в Telegram и запиши значение газа из ответа. Поставь порог на несколько сотен единиц выше этого значения. Полезно знать и про переменную bot.longPoll: если задать ей значение вроде 20, getUpdates будет ждать нового сообщения до 20 секунд, поэтому на команды бот отвечает мгновенно, но всё это время loop() стоит и датчики не опрашиваются. В проектах сигнализации оставляй longPoll равным 0.
MQ-2 — датчик для учёбы и хобби, а не сертифицированный газоанализатор, к тому же при пропадании Wi-Fi или интернета уведомление не придёт. Никогда не используй его как единственную защиту от утечки газа дома; установи сертифицированный бытовой газоанализатор, соответствующий стандартам, а этот проект считай дополнительной системой оповещения рядом с ним.

Telegram-бот на ESP8266 (NodeMCU)

Та же библиотека работает и на платах ESP8266 NodeMCU и Wemos D1 Mini; логика команд и сигнализации точно такая же, меняется только часть с подключением. Вместо WiFi.h используется ESP8266WiFi.h, корневой сертификат передаётся как X509List в setTrustAnchors(), а поскольку ESP8266 проверяет сроки действия сертификата, перед подключением нужно получить время по NTP. Без времени каждое подключение молча завершается неудачей. Встроенный светодиод NodeMCU находится на пине D4 и горит при LOW, а аналоговый вход всего один — A0.

C++ (Arduino IDE)
1#include <ESP8266WiFi.h>
2#include <WiFiClientSecure.h>
3#include <UniversalTelegramBot.h>
4#include <ArduinoJson.h>
5#include <time.h>
6
7const char* WIFI_SSID = "AgAdi";
8const char* WIFI_PASS = "Sifre123";
9#define BOT_TOKEN "1234567890:AAExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
10#define CHAT_ID   "123456789"
11
12X509List cert(TELEGRAM_CERTIFICATE_ROOT);      // ESP8266'da kök sertifika böyle verilir / how ESP8266 takes the root certificate
13WiFiClientSecure client;
14UniversalTelegramBot bot(BOT_TOKEN, client);
15
16void setup() {
17  Serial.begin(115200);
18  configTime(0, 0, "pool.ntp.org");            // sertifika kontrolü için saat şart / the clock is needed to check the certificate
19  client.setTrustAnchors(&cert);
20
21  WiFi.mode(WIFI_STA);
22  WiFi.begin(WIFI_SSID, WIFI_PASS);
23  while (WiFi.status() != WL_CONNECTED) delay(500);
24
25  time_t simdi = time(nullptr);                // NTP saatini bekle / wait for the NTP time
26  while (simdi < 24 * 3600) {
27    delay(100);
28    simdi = time(nullptr);
29  }
30  bot.sendMessage(CHAT_ID, "ESP8266 çevrimiçi / ESP8266 is online");
31}
32
33void loop() {
34}

Telegram-бот на Raspberry Pi Pico W и MicroPython

Для Raspberry Pi Pico W отдельная библиотека не нужна: запросы к Telegram Bot API можно отправлять напрямую модулем requests из MicroPython. Код ниже присылает уведомление при обнаружении движения, переключает реле на GP15 и встроенный светодиод платы командами /ac и /kapat и отвечает только на твой chat ID. Установи на Pico W свежую версию MicroPython через Thonny и сохрани код как main.py. Модуль requests в MicroPython шифрует соединение, но не проверяет сертификат сервера, поэтому уровень безопасности такой же, как у setInsecure() на ESP32.

MicroPython
1import network, time
2import requests
3from machine import Pin
4
5WIFI_SSID = "AgAdi"                    # Wi-Fi adın / your Wi-Fi name
6WIFI_PASS = "Sifre123"                 # Wi-Fi şifren / your Wi-Fi password
7TOKEN = "1234567890:AAExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
8CHAT_ID = 123456789                    # sayı olarak yaz / write it as a number
9API = "https://api.telegram.org/bot" + TOKEN
10
11led = Pin("LED", Pin.OUT)              # Pico W dahili LED / Pico W onboard LED
12role = Pin(15, Pin.OUT, value=1)       # aktif LOW röle kapalı başlar / active-LOW relay starts off
13pir = Pin(16, Pin.IN)                  # PIR OUT
14
15wlan = network.WLAN(network.STA_IF)
16wlan.active(True)
17wlan.connect(WIFI_SSID, WIFI_PASS)
18while not wlan.isconnected():
19    time.sleep(0.5)
20print("IP:", wlan.ifconfig()[0])
21
22def gonder(metin):
23    try:
24        r = requests.post(API + "/sendMessage", json={"chat_id": CHAT_ID, "text": metin})
25        r.close()
26    except Exception as e:
27        print("Gonderilemedi / send failed:", e)
28
29def yeni_mesajlar(offset):
30    try:
31        r = requests.get(API + "/getUpdates?timeout=0&limit=5&offset=%d" % offset)
32        sonuc = r.json().get("result", [])
33        r.close()
34        return sonuc
35    except Exception as e:
36        print("Okunamadi / read failed:", e)
37        return []
38
39# Kart kapalıyken gelen eski komutları atla / skip old commands sent while the board was off
40offset = 0
41eski = yeni_mesajlar(offset)
42while eski:
43    offset = eski[-1]["update_id"] + 1
44    eski = yeni_mesajlar(offset)
45
46gonder("Pico W çevrimiçi / Pico W is online")
47son_hareket = time.ticks_ms()          # ilk 60 sn PIR dengelenir / the PIR settles in the first 60 s
48
49while True:
50    if pir.value() and time.ticks_diff(time.ticks_ms(), son_hareket) > 60000:
51        son_hareket = time.ticks_ms()
52        gonder("Hareket algılandı! / motion detected!")
53
54    for u in yeni_mesajlar(offset):
55        offset = u["update_id"] + 1
56        mesaj = u.get("message", {})
57        if mesaj.get("chat", {}).get("id") != CHAT_ID:     # yalnız sana yanıt ver / answer only you
58            continue
59        komut = mesaj.get("text", "").split("@")[0]
60        if komut == "/ac":
61            role.value(0)              # aktif LOW: 0 = açık / active LOW: 0 = on
62            led.on()
63            gonder("Röle AÇIK / relay ON")
64        elif komut == "/kapat":
65            role.value(1)
66            led.off()
67            gonder("Röle KAPALI / relay OFF")
68        elif komut == "/durum":
69            gonder("Röle / relay: " + ("AÇIK / ON" if role.value() == 0 else "KAPALI / OFF"))
70    time.sleep(1)

Идеи проектов с Telegram-ботом на ESP32

  • Сигнализация для двери и окна: с герконом или PIR-датчиком отправляй сообщение на телефон, когда дома никого нет, а движение есть.
  • Камера наблюдения с фото: при обнаружении движения делай снимок на ESP32-CAM и отправляй его в Telegram; шаги — в руководстве ESP32-CAM и Telegram.
  • Мониторинг комнаты и теплицы: получай предупреждение, когда температура, измеренная DHT11, выходит за предел, и запрашивай текущее показание командой /durum.
  • Напоминание о поливе растений: получай уведомление, когда датчик влажности почвы показывает, что земля сухая, и включай насос на несколько секунд командой вроде /sula («полить»).
  • Предупреждение о пожаре: объедини датчик пламени с MQ-2, чтобы следить сразу за двумя опасностями.
  • Датчик почтового ящика на батарейках: держи ESP32 в глубоком сне, буди её при открытии крышки, отправляй одно сообщение и снова усыпляй.
  • Удалённая розетка: включай и выключай настольную лампу или вентилятор через реле из любой точки мира командами /ac и /kapat.

Частые ошибки Telegram-бота на ESP32 и их решение

Симптом или сообщениеПричинаРешение
sendMessage возвращает false, в мониторе порта ошибок нетНет строки setCACert или setInsecure, в токене есть пробел или Wi-Fi не подключёнДобавь строку сертификата, заново скопируй токен, сначала проверь подключение к Wi-Fi
«Forbidden: bot can't initiate conversation with a user» (бот не может начать диалог) при проверке в браузереВ боте ни разу не нажата кнопка «Запустить» (Start), или бот заблокированОткрой бота в Telegram и нажми «Запустить»; если бот заблокирован, разблокируй его
«Bad Request: chat not found» (чат не найден)Неверный chat ID, пропущен минус в ID группы или бот удалён из группыЗаново посмотри ID через getUpdates и пиши ID групп со знаком минус
«Unauthorized» (нет авторизации)Токен неверный или заменён через /revokeСкопируй актуальный токен из BotFather и заново загрузи код
Отправляет сообщения, но не реагирует на командыДолгая delay() в loop(), неверный chat ID или @bot_name, добавленный к команде в группеИспользуй millis() для ожидания, отрежь часть с @, проверь строку «unauthorized ID» в мониторе порта
Бот совсем перестаёт отвечать после фото или стикераБиблиотека читает только первые 1500 символов ответа; длинный ответ не разбирается, и одно и то же сообщение приходит снова и сноваДобавь в setup() строку bot.maxMessageLength = 4000;
Плата при запуске выполняет старые командыTelegram хранит непрочитанные сообщения до 24 часовПри запуске прочитай и отбрось ожидающие сообщения
«Conflict: terminated by other getUpdates request» (конфликт с другим запросом getUpdates)Один и тот же токен работает одновременно на двух устройствах или в скрипте на компьютереСоздай в BotFather отдельного бота для каждого устройства
«Too Many Requests: retry after 30» (слишком много запросов)Сообщения отправляются слишком частоДобавь паузу; отправляй в один чат не больше одного сообщения в секунду
«ArduinoJson.h: No such file or directory» (файл не найден) при компиляцииБиблиотека ArduinoJson не установленаУстанови ArduinoJson через «Менеджер библиотек» (Library Manager)
Плата перезагружается при отправке сообщенияИсточник питания не справляется с пиком тока при передаче по Wi-Fi (просадка питания, brownout)Блок питания на 1 A, короткий качественный кабель и конденсатор 100–470 µF между 3V3 и GND
При поиске проблемы соблюдай порядок: сначала убедись в мониторе порта, что Wi-Fi подключён, затем проверь в браузере токен через getMe и chat ID через sendMessage, а код смотри в последнюю очередь. Для проверки в браузере достаточно открыть api.telegram.org/botTOKEN/sendMessage?chat_id=123456789&text=test; Telegram простым текстом пишет причину любой ошибки в строке description. Если застреваешь на этапе Wi-Fi, загляни в руководство ESP32 не подключается к Wi-Fi.

С токеном, chat ID и несколькими строками кода твоя ESP32 превращается в маленького помощника, который сообщает, что происходит дома, и выполняет твои команды. Эту же схему можно расширить датчиками температуры, уровня воды или двери и направлять уведомления в семейную группу. В приложении BlueGrays есть охранная система на ESP32 с PIR-датчиком, зуммером и светодиодом, которая отправляет уведомления в Telegram, сигнализация газа и дыма на MQ-2 и проекты ESP32 с Wi-Fi — пошагово, со схемами подключения и кодом.

Частые вопросы

Telegram-бот на ESP32 бесплатный?

Да. Создание бота в Telegram, использование Bot API и отправка сообщений полностью бесплатны, и месячного лимита сообщений нет. Есть только ограничения частоты: примерно одно сообщение в секунду в один чат и 20 сообщений в минуту в группу. Для домашних проектов этого более чем достаточно.

Как узнать свой chat ID в Telegram?

Проще всего нажать «Запустить» (Start) в ID-боте вроде @userinfobot в Telegram: он пришлёт тебе твой ID. Другой способ — написать своему боту, открыть в браузере api.telegram.org/botTOKEN/getUpdates и найти значение id в разделе «chat». ID групп начинается со знака минус.

Почему ESP32 не отправляет сообщения в Telegram?

Чаще всего причина в том, что в боте ни разу не нажата кнопка «Запустить» (Start), указан неверный chat ID, в токене есть пробел или в коде нет строки setCACert или setInsecure. Токен и chat ID можно проверить независимо от кода, открыв в браузере адреса getMe и sendMessage. Также убедись, что плата подключена к сети Wi-Fi 2,4 GHz.

Может ли кто-то другой управлять моим Telegram-ботом?

Имена ботов публичны, поэтому если в коде нет проверки ID, то да: любой, кто найдёт бота, сможет отправлять ему команды. Чтобы этого не случилось, сравнивай chat ID каждого входящего сообщения со своим и игнорируй остальные: отправителя подтверждает Telegram, и подделать его нельзя. Токен тоже никому не показывай; если он утёк, замени его командой /revoke в BotFather.

Можно ли сделать Telegram-бота на ESP8266?

Да. Библиотека UniversalTelegramBot работает и на платах ESP8266, таких как NodeMCU и Wemos D1 Mini. Корневой сертификат передаётся как X509List в setTrustAnchors(), а перед подключением нужно получить время по NTP. У ESP8266 меньше памяти, поэтому с длинными сообщениями ESP32 справляется лучше.

Может ли ESP32 отправлять фото в Telegram?

Да. Функцией sendPhotoByBinary() из библиотеки можно отправить кадр, снятый ESP32-CAM, прямо в Telegram. ESP32 без камеры точно так же может отправить изображение с SD-карты, а через sendPhoto() — ссылку на изображение в интернете. Системы, которые присылают фото при обнаружении движения, — одни из самых популярных охранных проектов.

Все проекты
Мигающий светодиод на ESP32
#103Новичок

Мигающий светодиод на ESP32

Учит базовой работе с выходами GPIO на ESP32. Эффект мигания получается включением и выключением светодиода с цифрового пина. Это ESP32-версия классического проекта мигания на Arduino UNO; базовые команды мигания в среде Arduino те же, но расположение пинов ESP32 и уровни GPIO 3,3 V отличаются от Arduino UNO.

4.7(37)
99
Мигание встроенным светодиодом ESP32
#106Новичок

Мигание встроенным светодиодом ESP32

Мигание встроенным синим светодиодом на ESP32 DevKit V1. Внешние компоненты не нужны! Первый проект, который стоит попробовать после покупки ESP32. Встроенный светодиод подключён к GPIO 2.

4.8(29)
53
Сигнализация движения на ESP32 (PIR + зуммер + светодиод + Telegram)
#145Продвинутый
Premium

Сигнализация движения на ESP32 (PIR + зуммер + светодиод + Telegram)

Умная охранная сигнализация, которая при обнаружении движения PIR-датчиком включает зуммер и светодиод и одновременно сразу отправляет владельцу уведомление в Telegram. В ней есть 30-секундная пауза, ограничивающая частоту повторных тревог; этот механизм не проверяет срабатывания PIR и не устраняет ложные тревоги. Подходит для дома, гаража, склада или мастерской. С ESP32-CAM можно добавить уведомления с фото, а с обычной ESP32 DevKit V1 приходят текстовые.

0.0(0)
9
Сигнализация газа и дыма MQ-2 на ESP32
#122Средний

Сигнализация газа и дыма MQ-2 на ESP32

В этом проекте модуль датчика газа MQ-2 обнаруживает горючие газы (сжиженный газ, метан, пропан) и дым, а при обнаружении пассивный зуммер играет тревогу, похожую на сирену. Цифровой пороговый выход датчика (DO) подключён к GPIO 4 у ESP32; когда газ или дым превышают порог, DO переходит в LOW, и срабатывает тревога. Чувствительность настраивается потенциометром модуля. Пассивный зуммер управляется через tone() и даёт сирену на двух частотах.

4.7(28)
43
Умное освещение на ESP32 (PIR + LDR + реле + OLED)
#141Продвинутый
Premium

Умное освещение на ESP32 (PIR + LDR + реле + OLED)

Сделай умное освещение для коридора, ванной или кладовки на ESP32! С PIR-датчиком движения, датчиком освещённости LDR и модулем реле собирается классический сценарий «свет включается при движении в темноте»: если вокруг уже светло, движение свет НЕ включает, и днём энергия экономится. Свет горит 30 секунд; если движение продолжается, таймер сбрасывается, и свет горит дольше. OLED SSD1306 крупно показывает состояние (ON / DAYTIME / WAITING) и обратный отсчёт.

4.3(6)
11
Автоматическое освещение с PIR-датчиком движения на ESP32
#121Средний
Premium

Автоматическое освещение с PIR-датчиком движения на ESP32

В этом проекте PIR-датчик движения HC-SR501 замечает, что кто-то вошёл в комнату, и автоматически включает светодиод. Время свечения отслеживается через millis(); каждое показание HIGH обновляет время последнего движения, и светодиод гаснет не раньше чем через 10 секунд после последнего HIGH. Текущий код ещё и ждёт 50 ms на каждом цикле через delay(50), поэтому цикл не полностью неблокирующий. Подходит для освещения лестниц, шкафов и ванной.

4.4(24)
38
Подключение ESP32 к Wi-Fi в режиме STA (с экраном LCD)
#127Продвинутый

Подключение ESP32 к Wi-Fi в режиме STA (с экраном LCD)

В этом проекте ESP32 надёжно и устойчиво к сбоям подключается к домашней сети Wi-Fi в режиме станции (STA). SSID и пароль хранятся в отдельном файле secrets.h, чтобы не утекли в Git; настроено автоматическое переподключение, а уровень сигнала RSSI и IP-адрес выводятся на I2C LCD-экран. Встроенный светодиод служит индикатором состояния. Это менеджер подключения уровня реальных устройств.

4.4(21)
34