Wi-Fi · умный дом

MQTT и умный дом: как плата разговаривает через интернет

Веб-страница на плате видна только дома. Чтобы поделка отвечала из другого города и жила в умном доме, нужен посредник. Разбираем, что это такое простыми словами, как устроены топики, где взять посредника, что делать с безопасностью — и как плата напишет вам в мессенджер. Три скетча собраны компилятором.

Короткий ответ. Чтобы управлять поделкой не только из дома, не открывайте порт на роутере. Вместо этого поставьте посредника: и плата, и телефон соединяются с ним изнутри наружу, а он передаёт сообщения в обе стороны. Так работают MQTT и боты в мессенджерах. Библиотека нужна одна — PubSubClient, она есть в нашем каталоге.

Почему нельзя просто «открыть порт»

Первая мысль всегда одна: раз страница платы открывается дома, надо сделать так, чтобы она открывалась и снаружи. На роутере для этого есть настройка «проброс порта». Она работает — и это самая опасная вещь, которую советуют в интернете новичкам.

Проброс выставляет вашу плату в открытый интернет. У платы нет ни пароля, ни разграничения прав, ни защиты от лишних запросов. Автоматические сканеры обходят весь интернет непрерывно, и устройство, выставленное наружу, находят за часы, а не за годы. Дальше поделка становится либо чужой игрушкой, либо участником чужих неприятностей.

Есть и вторая причина, более прозаичная: у большинства домашних подключений сегодня нет собственного внешнего адреса — провайдер прячет за одним адресом сотни квартир. В этом случае проброс просто не заработает, сколько его ни настраивай.

Правильное решение известно давно и называется посредником. Плата не ждёт, когда к ней постучатся, — она сама соединяется с сервером и держит соединение открытым. То же самое делает телефон. Роутер такому соединению не мешает: изнутри наружу выходить можно всегда.

Плата публикует, телефон получаетПлатапубликуетПосредникхранит и раздаётТелефонподписанdom/kuhnya/temperatura → 21.4Плата отправляет число посреднику и забывает о нём. Кто на этот топик подписан — тот иполучит: телефон, домашний сервер, второй компьютер, все сразу.Плата не знает и не должна знать, кто её слушает. В этом весь смысл посредника.
Четыре сцены, из которых складывается вся работа с посредником. Третья и четвёртая — то, чего нет у веб-страницы на плате: память последнего значения и честное сообщение об обрыве.

Шесть слов, которые пугают зря

Половина непонимания в теме MQTT — от терминов. На самом деле за ними стоят очень простые вещи.

СловоЧто это на самом делеПример
Посредник (брокер)Программа, через которую все разговаривают. Сама она ничего не решает — только принимает сообщения и раздаёт их тем, кто просилСтоит на домашнем компьютере или в облаке
ТопикПуть, по которому лежит сообщение. Придумываете его вы сами, никакого списка разрешённых нетdom/kuhnya/temperatura
ПубликацияОтправить сообщение в топик. Отправитель не знает, кто его получит, и это нормальноПлата шлёт 21.4
ПодпискаПопросить посредника присылать всё, что появляется в топикеТелефон подписан на dom/kuhnya/#
Флаг «запомнить»Просьба к посреднику хранить последнее сообщение и отдавать его каждому новому подписчикуПриложение сразу видит температуру, а не прочерк
Последняя воляСообщение, которое посредник отправит сам, если устройство пропало со связиВ топик связи прилетит offline

Главное, что стоит вынести: отправитель и получатель ничего не знают друг о друге. Плата шлёт число в топик и забывает о нём. Кто подписан — тот и получит: телефон, домашний сервер, второй компьютер, все сразу или никто. Именно поэтому такую систему легко наращивать: новое устройство просто подписывается на нужный путь, и ничего переделывать не надо.

Топики: как их называть, чтобы потом не путаться

Топик — это просто путь со ступенями через косую черту. Никакого утверждённого списка нет, вы придумываете их сами. Но пара привычек экономит много времени потом.

  • От общего к частному: сначала дом, потом комната, потом устройство, потом величина. Так шаблоны подписки становятся осмысленными.
  • Только латиница, без пробелов и русских букв. Формально можно и русские, но потом это аукнется в каждой второй программе.
  • Команды и состояние — разные топики. Если плата и пишет, и читает один и тот же топик, она услышит собственное сообщение и начнёт спорить сама с собой. Обычно к топику команд добавляют ступень set.
  • Не начинайте топик с косой черты — формально можно, но появляется пустая первая ступень, и шаблоны перестают совпадать.
Подписка: dom/kuhnya/temperaturadom/kuhnya/temperaturaпридётdom/kuhnya/vlazhnostне придётdom/kuhnya/svetне придётdom/spalnya/temperaturaне придётdom/ulica/temperaturaне придётdacha/nasos/statusне придётПодписка на один-единственный топик. Так и подписываются, когда устройство одно.
Топик — это просто путь, который вы придумываете сами. Шаблоны нужны тому, кто подписывается: плюс заменяет одну ступень, решётка — всё, что ниже.

Два знака в шаблонах подписки нужно запомнить. Плюс заменяет ровно одну ступень: dom/+/temperatura соберёт температуру со всех комнат, но не тронет влажность. Решётка забирает всё, что лежит ниже, и ставится только в самом конце: dom/kuhnya/# — это все величины кухни.

Где взять посредника

Посредник — обычная программа. Её ставят на домашний компьютер, на мини-компьютер, который и так работает круглосуточно, или берут готовую в облаке.

Посредник на домашнем компьютере или мини-компьютереВаша квартираПлатаПосредникИнтернетТелефонЛучший вариант для домаПлюс: Ставится одной командой, работает без интернета вообще, данные не уходят никуда.Пароль и права настраиваете вы.Минус: Компьютер должен быть включён. Из другого города так тоже не достучаться — дляэтого посредник должен стоять снаружи.
Четыре места, где может жить посредник. Открытый чужой годится только для проверки: там нет ни пароля, ни разграничения — читать и писать может кто угодно.

Для дома лучший вариант — свой посредник в своей же сети: данные никуда не уходят, работает даже при отключённом интернете, а пароли и права вы задаёте сами. Если у вас уже стоит система умного дома, посредник часто встроен в неё и включается одной кнопкой.

Отдельно про открытых чужих посредников, которые советуют в туториалах. Это городская площадь: любой может читать ваши топики и писать в них. Для проверки «а работает ли вообще мой скетч» они годятся, для управления реальными вещами — нет. Если всё-таки берёте такого на время опытов, придумайте топик с длинным случайным словом внутри и не подключайте к нему ничего, что может причинить вред.

Скетч первый: плата отправляет показания

Библиотека одна — PubSubClient, версия 2.8.0 из каталога. В скетче стоит обратить внимание на три вещи: переподключение по часам, а не ожиданием; флаг «запомнить» в конце публикации; и «последняя воля», которую плата передаёт в момент подключения.

// Плата отправляет показания посреднику (брокеру) раз в тридцать секунд.
// Библиотека PubSubClient - из каталога libraries.trema.ru.
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#else
#include <WiFi.h>
#endif
#include <PubSubClient.h>

const char WIFI_SSID[] = "имя вашей сети";
const char WIFI_PASS[] = "пароль от сети";

// Адрес брокера в вашей сети и его обычный порт.
const char MQTT_HOST[] = "192.168.1.10";
const int MQTT_PORT = 1883;

// Имя должно быть уникальным: второго с тем же именем брокер выгонит.
const char CLIENT_ID[] = "plata-kuhnya";

// Топики - это просто пути. Их придумываете вы сами.
const char TOPIC_TEMP[] = "dom/kuhnya/temperatura";
const char TOPIC_LIFE[] = "dom/kuhnya/svyaz";

WiFiClient net;
PubSubClient mqtt(net);

unsigned long lastSend = 0;
unsigned long lastTry = 0;

// Переподключение без остановки программы: пробуем раз в пять секунд.
void keepMqtt() {
  if (mqtt.connected()) {
    return;
  }
  if (millis() - lastTry < 5000) {
    return;
  }
  lastTry = millis();

  // Последняя воля: если плата пропадёт, брокер сам напишет в топик связи
  // слово offline. Флаг true означает «запомни это сообщение».
  if (mqtt.connect(CLIENT_ID, TOPIC_LIFE, 0, true, "offline")) {
    Serial.println("Брокер принял");
    mqtt.publish(TOPIC_LIFE, "online", true);
  } else {
    Serial.print("Брокер не отвечает, код ");
    Serial.println(mqtt.state());
  }
}

void setup() {
  Serial.begin(115200);
  delay(200);
  Serial.println();

  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  mqtt.setServer(MQTT_HOST, MQTT_PORT);
}

void loop() {
  keepMqtt();
  mqtt.loop();          // без этой строчки связь с брокером отвалится

  if (millis() - lastSend > 30000 && mqtt.connected()) {
    lastSend = millis();

    // Здесь вместо случайного числа подставьте показания своего датчика.
    float temperature = 20.0 + (millis() % 500) / 100.0;

    char text[12];
    dtostrf(temperature, 0, 1, text);   // число превращаем в текст
    mqtt.publish(TOPIC_TEMP, text, true);

    Serial.print("Отправлено: ");
    Serial.println(text);
  }
}

Строчка mqtt.loop() так же обязательна, как server.handleClient() в веб-сервере: именно она поддерживает соединение живым и разбирает входящие сообщения. Если её не вызывать хотя бы раз в несколько секунд, посредник посчитает плату мёртвой и отключит её.

«Последняя воля» — самая недооценённая вещь в протоколе. Плата заранее говорит посреднику: «если я замолчу, напиши вот это вот сюда». Дальше можно спокойно отличать «датчик показывает ноль» от «датчика больше нет», а это разница между спокойным сном и затопленной кухней.

Скетч второй: плата слушает команды

Обратная сторона: плата подписывается на топик команд и включает свет по слову ON.

// Плата слушает команды от посредника и включает светодиод.
// Обратная сторона предыдущего скетча: не отправка, а приём.
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#define STATUS_LED LED_BUILTIN
#define LED_ON LOW
#define LED_OFF HIGH
#else
#include <WiFi.h>
#define STATUS_LED 2
#define LED_ON HIGH
#define LED_OFF LOW
#endif
#include <PubSubClient.h>

const char WIFI_SSID[] = "имя вашей сети";
const char WIFI_PASS[] = "пароль от сети";

const char MQTT_HOST[] = "192.168.1.10";
const int MQTT_PORT = 1883;
const char CLIENT_ID[] = "plata-svet";

// В топик команд нам пишут, в топик состояния пишем мы.
const char TOPIC_SET[] = "dom/kuhnya/svet/set";
const char TOPIC_STATE[] = "dom/kuhnya/svet";

WiFiClient net;
PubSubClient mqtt(net);

bool lampOn = false;
unsigned long lastTry = 0;

void applyLamp() {
  digitalWrite(STATUS_LED, lampOn ? LED_ON : LED_OFF);
  // Флаг true просит брокер запомнить сообщение: новый подписчик сразу
  // узнает, горит лампа или нет, не дожидаясь следующего изменения.
  mqtt.publish(TOPIC_STATE, lampOn ? "ON" : "OFF", true);
}

// Сюда попадает каждое сообщение из топиков, на которые мы подписаны.
// Payload - это НЕ строка: в конце нет нуля, длина приходит отдельно.
void onMessage(char* topic, byte* payload, unsigned int length) {
  String text;
  text.reserve(length);
  for (unsigned int i = 0; i < length; i++) {
    text += (char)payload[i];
  }

  Serial.print(topic);
  Serial.print(" -> ");
  Serial.println(text);

  if (String(topic) == TOPIC_SET) {
    lampOn = (text == "ON" || text == "1");
    applyLamp();
  }
}

void keepMqtt() {
  if (mqtt.connected()) {
    return;
  }
  if (millis() - lastTry < 5000) {
    return;
  }
  lastTry = millis();

  if (mqtt.connect(CLIENT_ID)) {
    Serial.println("Брокер принял");
    mqtt.subscribe(TOPIC_SET);   // подписку надо повторять после каждого обрыва
    applyLamp();
  } else {
    Serial.print("Брокер не отвечает, код ");
    Serial.println(mqtt.state());
  }
}

void setup() {
  Serial.begin(115200);
  delay(200);
  Serial.println();
  pinMode(STATUS_LED, OUTPUT);

  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  mqtt.setServer(MQTT_HOST, MQTT_PORT);
  mqtt.setCallback(onMessage);
}

void loop() {
  keepMqtt();
  mqtt.loop();
}

Здесь три подводных камня, на которых спотыкаются все.

  • Приходящее сообщение — не строка. В функцию попадает кусок памяти и отдельно его длина; нуля в конце нет. Если попробовать напечатать его как обычный текст, получится мусор и иногда перезагрузка. Поэтому в скетче сообщение аккуратно перекладывается посимвольно.
  • Подписку надо повторять. После каждого обрыва связи подписки теряются. В скетче subscribe() вызывается прямо внутри процедуры подключения — так о нём невозможно забыть.
  • Имя устройства должно быть уникальным. Если две платы назвать одинаково, посредник будет выгонять то одну, то другую, и обе окажутся в бесконечном цикле переподключения. Симптом характерный: код состояния −3.

Ограничения, о которых лучше знать заранее

  • Размер сообщения — 256 байт вместе со служебной частью и именем топика. Это значение по умолчанию у PubSubClient; длинное сообщение просто не уйдёт, причём молча. Если нужно больше, размер меняется вызовом setBufferSize(), но лучше сначала подумать, зачем плате слать столько за раз.
  • Молчание дольше 15 секунд посредник считает потерей связи. Именно поэтому библиотека сама отправляет служебные «я жив» — но только если вызывается mqtt.loop().
  • Гарантии доставки. В протоколе три уровня, но библиотека при отправке умеет только самый простой: «отправил и забыл». Для показаний датчика этого достаточно, для команды «открыть ворота» — стоит подтверждать выполнение ответным сообщением в топик состояния.

Как показать плату в системе умного дома

Дальше начинается приятное: поделка становится обычным устройством в общем интерфейсе — со своей плиткой, историей и участием в сценариях. Настройка сводится к тому, чтобы назвать системе те же топики, которые вы использовали в скетче.

Что спрашивает системаЧто писатьПочему так
Топик состоянияdom/kuhnya/svetСюда плата пишет, включён свет или нет
Топик командdom/kuhnya/svet/setОтсюда плата читает команды. Разные топики — чтобы не было эха
Топик доступностиdom/kuhnya/svyazonline и offline. Второе пишет сам посредник, если плата пропала
ЗначенияON и OFFДоговорённость, которую соблюдают обе стороны. Можно любые, лишь бы одинаковые
Флаг «запомнить»включёнИначе после перезапуска приложение будет показывать прочерк

Некоторые системы умеют находить устройства сами: плата один раз публикует своё описание в служебный топик, и плитка появляется без ручной настройки. Это удобно, когда устройств много, но начинать проще с ручного описания — так виднее, что куда идёт.

Если умного дома нет: сообщение в мессенджер

Посредником может быть и сам мессенджер. Плата соединяется с его сервером изнутри наружу — и присылает вам сообщение, когда что-то случилось. Ни роутер настраивать, ни посредника ставить не нужно.

Одна оговорка, которая всё определяет: разговор с любым современным сервисом идёт по защищённому каналу, а это требует памяти и точного времени. Поэтому скетч написан для ESP32 — у ESP8266 такое тоже получается, но памяти впритык и код становится капризным.

// Плата пишет вам в мессенджер. Посредник тут - сам сервис: и плата,
// и телефон соединяются с ним, поэтому дырок в роутере открывать не нужно.
// Скетч для ESP32: у неё хватает памяти на защищённое соединение.
#include <WiFi.h>
#include <WiFiClientSecure.h>

const char WIFI_SSID[] = "имя вашей сети";
const char WIFI_PASS[] = "пароль от сети";

// Ключ бота выдаёт сам мессенджер, номер разговора узнают у бота-помощника.
const char BOT_TOKEN[] = "0000000000:ЗАМЕНИТЕ_НА_СВОЙ_КЛЮЧ";
const char CHAT_ID[] = "000000000";

const char TG_HOST[] = "api.telegram.org";

// Русский текст в адресе надо закодировать: каждый байт, кроме букв
// латиницы и цифр, превращается в знак процента и две шестнадцатеричные цифры.
String urlEncode(const String& text) {
  const char digits[] = "0123456789ABCDEF";
  String out;
  for (unsigned int i = 0; i < text.length(); i++) {
    char c = text[i];
    if (isalnum(c)) {
      out += c;
    } else {
      out += (char)37;              // знак процента
      out += digits[((byte)c) >> 4];
      out += digits[((byte)c) & 15];
    }
  }
  return out;
}

bool sendMessage(const String& text) {
  WiFiClientSecure client;
  // Проверку сертификата не делаем: для домашней поделки это разумный
  // размен. Если нужна строгая проверка - положите сюда корневой
  // сертификат сервиса методом setCACert().
  client.setInsecure();

  if (!client.connect(TG_HOST, 443)) {
    Serial.println("Не соединился с сервисом");
    return false;
  }

  String path = "/bot";
  path += BOT_TOKEN;
  path += "/sendMessage?chat_id=";
  path += CHAT_ID;
  path += "&text=";
  path += urlEncode(text);

  // println сам дописывает конец строки, поэтому экранировать ничего не нужно.
  client.println("GET " + path + " HTTP/1.1");
  client.println("Host: " + String(TG_HOST));
  client.println("Connection: close");
  client.println();

  // Первая строка ответа скажет, приняли ли запрос.
  String status = client.readStringUntil((char)10);
  Serial.print("Ответ сервиса: ");
  Serial.println(status);

  client.stop();
  return status.indexOf("200") > 0;
}

void setup() {
  Serial.begin(115200);
  delay(200);
  Serial.println();

  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  // Часы нужны защищённому соединению: без верного времени проверка
  // сертификата не работает даже в мягком режиме.
  configTime(3 * 3600, 0, "ru.pool.ntp.org", "pool.ntp.org");
  delay(1500);

  sendMessage("Плата включилась и вышла на связь");
}

void loop() {
  // Здесь может быть проверка датчика: протечка, движение, температура.
  // Главное правило - не слать сообщения чаще, чем раз в несколько секунд.
}

Обратите внимание на две детали. Первая: перед отправкой плата заводит часы по сети — без верного времени проверка защищённого соединения не работает даже в мягком режиме. Вторая: русский текст в адресе кодируется, иначе сервис его не примет; маленькая функция в начале скетча этим и занимается.

Ключ бота в скетче лежит открытым текстом и вместе с прошивкой попадает во флеш-память платы. Тот, у кого плата окажется в руках, прочитает его. Это не повод отказываться от способа, но повод не делать ботом ничего опаснее уведомлений.

Что означают коды состояния

Метод state() возвращает число, и по нему сразу понятно, где искать причину. Значения взяты из самой библиотеки.

КодЧто означаетЧто делать
0ПодключеноВсё хорошо
−1ОтключеноПлата сама закрыла соединение или ещё не подключалась
−2Не удалось соединитьсяНеверный адрес посредника, не тот порт, посредник не запущен или закрыт межсетевым экраном
−3Связь потерянаОборвался Wi-Fi или посредник выгнал: чаще всего два устройства с одинаковым именем
−4Не дождался ответаПосредник отвечает слишком медленно или сеть очень плохая
1Не та версия протоколаРедкость: посредник не принимает версию 3.1.1. Обновите посредника
2Плохое имя устройстваИмя слишком длинное или содержит недопустимые знаки. Возьмите латиницу и дефисы
3Посредник занятОн запущен, но сейчас не принимает подключения. Подождите и попробуйте снова
4Неверные имя или парольПроверьте учётную запись на посреднике
5Доступ запрещёнУчётная запись верная, но ей не разрешён этот топик. Проверьте права на посреднике

Честно про безопасность

Посредник решает проблему «как достучаться снаружи», но не решает проблему «кто имеет право». Три правила, которые стоит соблюдать с самого начала.

  • Заведите на посреднике учётные записи. Открытый доступ без пароля допустим только в изолированной домашней сети, и то до первого гостя с телефоном.
  • Разграничьте права по топикам. Плате обычно нужно писать в свои топики и читать один топик команд — больше ничего. Если её взломают, ущерб ограничится этим.
  • Наружу — только защищённое соединение. Обычный порт 1883 передаёт всё открытым текстом, включая пароль. Для доступа через интернет используют порт 8883 и защищённый канал; ESP32 это по силам.

И общее правило, которое не отменяется ничем: самодельная поделка не должна отвечать за безопасность людей и имущества. Управлять лампой, поливом и вентилятором — да. Открывать замки и ворота — нет.

Что купить

Проверено 24 августа 2026 года: каждая карточка открыта отдельно, цена и артикул взяты со страницы товара. Того, чего нет в наличии, в подборке нет.

Piranha ESP32 v2

Для умного дома это разумный минимум: памяти хватает и на защищённое соединение с посредником, и на сообщения в мессенджер, а второе ядро занимается радио, пока ваша программа занимается делом.

690 ₽
Открыть карточку
арт. 1453 · цена и наличие на 24.08.2026

WeMos D1 mini на ESP8266

Если посредник стоит дома и защищённый канал не нужен, этой платы хватает: отправлять показания и принимать команды она будет годами. Самый дешёвый вход в тему.

290 ₽
Открыть карточку
арт. 867 · цена и наличие на 24.08.2026

Источник питания 5 В, 2 А

Устройство умного дома работает круглосуточно, а значит, питание должно быть отдельным и с запасом. Половина «зависаний» лечится именно этим.

986 ₽
Открыть карточку
арт. 491 · цена и наличие на 24.08.2026

Сетевой модуль W5500

Если поделка стоит рядом с роутером, провод надёжнее радио: ни помех, ни переподключений. Тот же посредник, тот же код — только вместо Wi-Fi кабель.

640 ₽
Открыть карточку
арт. 854 · цена и наличие на 24.08.2026

Дальше по теме

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

Что такое MQTT простыми словами?

Это способ обмена короткими сообщениями через посредника. Устройства не разговаривают друг с другом напрямую: каждое соединяется с одной общей программой — брокером — и либо кладёт сообщение в топик, либо просит присылать всё, что в топике появляется. Топик это просто путь, который вы придумываете сами, например dom/kuhnya/temperatura. Отправитель не знает, кто его читает, и это главное удобство: новое устройство просто подписывается на нужный путь, и переделывать ничего не нужно.

Зачем нужен брокер, если можно открыть порт на роутере?

По двум причинам. Первая — безопасность: проброс порта выставляет в открытый интернет устройство, у которого нет ни пароля, ни разграничения прав, а автоматические сканеры находят такие устройства за часы. Вторая — техническая: у большинства домашних подключений сегодня нет собственного внешнего адреса, провайдер прячет за одним адресом сотни квартир, и проброс просто не заработает. С брокером обе проблемы исчезают: и плата, и телефон соединяются с ним изнутри наружу, а такому соединению роутер не мешает никогда.

Какую библиотеку взять для MQTT на ESP8266 и ESP32?

PubSubClient — она проверена временем, работает на обеих платах и есть в нашем каталоге библиотек, версия 2.8.0. Ставится в один клик, ничего скачивать руками не нужно. Учтите два её значения по умолчанию: размер сообщения ограничен 256 байтами вместе со служебной частью, а молчание дольше 15 секунд брокер считает потерей связи. Первое меняется вызовом setBufferSize(), второе решается тем, что в loop() обязательно вызывается mqtt.loop().

Почему плата подключается к брокеру и сразу отваливается?

Чаще всего два устройства подключились с одинаковым именем клиента. Брокер разрешает только одно соединение на имя и выгоняет предыдущее — а оно тут же подключается снова и выгоняет второе. Получается бесконечная карусель, а метод state() показывает −3. Дайте каждой плате своё имя. Вторая по частоте причина — не вызывается mqtt.loop(): без него библиотека не отправляет служебные сигналы «я жив», и через пятнадцать секунд брокер закрывает соединение.

Можно ли пользоваться чужим открытым брокером из интернета?

Для опытов — да, для дела — нет. Открытый брокер это городская площадь: любой может читать ваши топики и писать в них, а значит, и включать вашу лампу. Проверить, что скетч вообще жив, через такой брокер удобно; управлять реальными вещами — нельзя. Если всё же пользуетесь им во время опытов, придумайте топик с длинным случайным словом внутри и не подключайте к нему ничего, что может причинить вред.

Как плата сообщит, что она отключилась?

Для этого в протоколе есть «последняя воля»: в момент подключения плата говорит брокеру, что написать и куда, если она замолчит. Обычно это слово offline в топике связи, а сразу после подключения плата сама пишет туда online. Дальше вы всегда отличаете «датчик показывает ноль» от «датчика больше нет» — а это разница между спокойным сном и затопленной кухней. Флаг «запомнить» при этом обязателен, иначе новое приложение не увидит текущего состояния до следующего изменения.

Можно ли вместо MQTT просто присылать сообщения в мессенджер?

Да, и для уведомлений это часто проще: посредником становится сам сервис мессенджера, ставить ничего не надо. Плата соединяется с его сервером изнутри наружу и отправляет текст. Две оговорки. Первая: разговор идёт по защищённому каналу, поэтому нужна ESP32 — у ESP8266 памяти впритык. Вторая: плате нужны верные часы, иначе защищённое соединение не устанавливается; время берут из интернета одной строчкой. И помните, что ключ бота лежит в прошивке открытым текстом.

Что для этого нужно в среде

Из библиотек нужна одна — PubSubClient. Она есть в каталоге libraries.trema.ru, и Trema IDE ставит её в один клик, без ручного скачивания архивов. Поддержку плат ESP8266 и ESP32 среда берёт с нашего зеркала.

Что почитать рядом: подключение к сети, веб-сервер на плате, монитор порта и разбор ошибок сборки.