Wi-Fi · умный дом
MQTT и умный дом: как плата разговаривает через интернет
Веб-страница на плате видна только дома. Чтобы поделка отвечала из другого города и жила в умном доме, нужен посредник. Разбираем, что это такое простыми словами, как устроены топики, где взять посредника, что делать с безопасностью — и как плата напишет вам в мессенджер. Три скетча собраны компилятором.
Короткий ответ. Чтобы управлять поделкой не только из дома, не открывайте порт на роутере. Вместо этого поставьте посредника: и плата, и телефон соединяются с ним изнутри наружу, а он передаёт сообщения в обе стороны. Так работают MQTT и боты в мессенджерах. Библиотека нужна одна — PubSubClient, она есть в нашем каталоге.
Почему нельзя просто «открыть порт»
Первая мысль всегда одна: раз страница платы открывается дома, надо сделать так, чтобы она открывалась и снаружи. На роутере для этого есть настройка «проброс порта». Она работает — и это самая опасная вещь, которую советуют в интернете новичкам.
Проброс выставляет вашу плату в открытый интернет. У платы нет ни пароля, ни разграничения прав, ни защиты от лишних запросов. Автоматические сканеры обходят весь интернет непрерывно, и устройство, выставленное наружу, находят за часы, а не за годы. Дальше поделка становится либо чужой игрушкой, либо участником чужих неприятностей.
Есть и вторая причина, более прозаичная: у большинства домашних подключений сегодня нет собственного внешнего адреса — провайдер прячет за одним адресом сотни квартир. В этом случае проброс просто не заработает, сколько его ни настраивай.
Правильное решение известно давно и называется посредником. Плата не ждёт, когда к ней постучатся, — она сама соединяется с сервером и держит соединение открытым. То же самое делает телефон. Роутер такому соединению не мешает: изнутри наружу выходить можно всегда.
Шесть слов, которые пугают зря
Половина непонимания в теме MQTT — от терминов. На самом деле за ними стоят очень простые вещи.
| Слово | Что это на самом деле | Пример |
|---|---|---|
| Посредник (брокер) | Программа, через которую все разговаривают. Сама она ничего не решает — только принимает сообщения и раздаёт их тем, кто просил | Стоит на домашнем компьютере или в облаке |
| Топик | Путь, по которому лежит сообщение. Придумываете его вы сами, никакого списка разрешённых нет | dom/kuhnya/temperatura |
| Публикация | Отправить сообщение в топик. Отправитель не знает, кто его получит, и это нормально | Плата шлёт 21.4 |
| Подписка | Попросить посредника присылать всё, что появляется в топике | Телефон подписан на dom/kuhnya/# |
| Флаг «запомнить» | Просьба к посреднику хранить последнее сообщение и отдавать его каждому новому подписчику | Приложение сразу видит температуру, а не прочерк |
| Последняя воля | Сообщение, которое посредник отправит сам, если устройство пропало со связи | В топик связи прилетит offline |
Главное, что стоит вынести: отправитель и получатель ничего не знают друг о друге. Плата шлёт число в топик и забывает о нём. Кто подписан — тот и получит: телефон, домашний сервер, второй компьютер, все сразу или никто. Именно поэтому такую систему легко наращивать: новое устройство просто подписывается на нужный путь, и ничего переделывать не надо.
Топики: как их называть, чтобы потом не путаться
Топик — это просто путь со ступенями через косую черту. Никакого утверждённого списка нет, вы придумываете их сами. Но пара привычек экономит много времени потом.
- От общего к частному: сначала дом, потом комната, потом устройство, потом величина. Так шаблоны подписки становятся осмысленными.
- Только латиница, без пробелов и русских букв. Формально можно и русские, но потом это аукнется в каждой второй программе.
- Команды и состояние — разные топики. Если плата и пишет, и читает один и тот же топик, она услышит собственное сообщение и начнёт спорить сама с собой. Обычно к топику команд добавляют ступень set.
- Не начинайте топик с косой черты — формально можно, но появляется пустая первая ступень, и шаблоны перестают совпадать.
Два знака в шаблонах подписки нужно запомнить. Плюс заменяет ровно одну ступень: 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/svyaz | online и 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
Для умного дома это разумный минимум: памяти хватает и на защищённое соединение с посредником, и на сообщения в мессенджер, а второе ядро занимается радио, пока ваша программа занимается делом.
WeMos D1 mini на ESP8266
Если посредник стоит дома и защищённый канал не нужен, этой платы хватает: отправлять показания и принимать команды она будет годами. Самый дешёвый вход в тему.
Источник питания 5 В, 2 А
Устройство умного дома работает круглосуточно, а значит, питание должно быть отдельным и с запасом. Половина «зависаний» лечится именно этим.
Сетевой модуль W5500
Если поделка стоит рядом с роутером, провод надёжнее радио: ни помех, ни переподключений. Тот же посредник, тот же код — только вместо Wi-Fi кабель.
Дальше по теме
- Wi-Fi для Arduino — как плата попадает в сеть и почему перезагружается.
- Веб-сервер на плате — управление из браузера, когда вы дома.
- Прошивка по воздуху — обновлять устройство умного дома, не доставая его из корпуса.
- Библиотеки Arduino — как поставить PubSubClient из каталога.
- Датчики для Arduino — что подключить к плате, чтобы было что отправлять.
Частые вопросы
Что такое 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 среда берёт с нашего зеркала.
Что почитать рядом: подключение к сети, веб-сервер на плате, монитор порта и разбор ошибок сборки.
