Пока датчиков на ферме два-три, система из предыдущих статей работает отлично: ESP32 напрямую отправляет данные в Telegram (или VK, или email). Но когда датчиков становится десять? Двадцать? Метеостанция в теплице, автополив на грядках, влагомер в поле, трекер на тракторе, весы на приёмке — и каждый шлёт HTTP-запросы напрямую в мессенджер?
Начинаются проблемы. ESP32 тратит 2–3 секунды на каждый HTTP-запрос и не может в это время делать замеры. Wi-Fi буфер переполняется. Бот получает 200 сообщений в час и превращается в свалку. Вы не понимаете, какое из устройств отправило алерт, а какое просто прислало плановый отчёт.
Решение — MQTT-брокер как центральный хаб. Все устройства публикуют данные в топики, а один сервер обрабатывает их и отправляет уведомления через VK-бота — структурированно, с фильтрацией и приоритетами.
Архитектура: почему MQTT, а не прямые запросы
MQTT — это лёгкий протокол обмена сообщениями, придуманный специально для IoT. Три ключевых преимущества для фермера:
- Мгновенная отправка. MQTT-пакет — 50–200 байт. HTTP-запрос в Telegram — 2–5 КБ + SSL-хендшейк. На нестабильном Wi-Fi (а в поле он всегда нестабильный) разница между «отправил за 50 мс» и «отправлял 3 секунды» — критична
- Отделение устройств от логики. ESP32 не знает про VK, Telegram, email. Он просто публикует данные в топик:
ferma/teплица1/temp = 24.5. А сервер решает — отправить алерт, записать в базу, нарисовать график - Масштабирование. Добавить новый датчик = воткнуть ESP32 и настроить топик. Сервер подхватит автоматически. Не нужно менять код бота, не нужно добавлять новые Chat ID
Что нам понадобится
- ESP32 — любые платы из предыдущих проектов (уже с датчиками)
- MQTT-брокер Mosquitto — бесплатный, ставится за минуту. Работает на любом Linux-сервере, Raspberry Pi или даже на старом ноутбуке
- Node.js — для серверной логики (обработка сообщений + VK-бот)
- VK Community (группа) — через неё работает бот
Бюджет: 0 ₽ (всё бесплатное ПО). Сервер — любой Linux-компьютер с постоянным интернетом. Подойдёт даже Raspberry Pi 3 за 3 000 ₽.
Шаг 1: Mosquitto — MQTT-брокер за 2 минуты
На Ubuntu/Debian:
sudo apt update
sudo apt install -y mosquitto mosquitto-clients
sudo systemctl enable mosquitto
sudo systemctl start mosquitto
Брокер запущен на порту 1883. Проверяем:
# В одном терминале — подписка
mosquitto_sub -t "ferma/#" -v
# В другом — публикация
mosquitto_pub -t "ferma/test" -m "Привет, MQTT!"
В первом терминале появится: ferma/test Привет, MQTT! — брокер работает.
Безопасность: по умолчанию Mosquitto принимает подключения без пароля. Для локальной сети это нормально, но если брокер доступен из интернета — обязательно настройте аутентификацию:
# Создаём файл паролей
sudo mosquitto_passwd -c /etc/mosquitto/passwd ferma_user
# В /etc/mosquitto/conf.d/auth.conf:
listener 1883
allow_anonymous false
password_file /etc/mosquitto/passwd
Шаг 2: ESP32 → MQTT — 40 строк кода
Устанавливаем библиотеку: Arduino IDE → Tools → Manage Libraries → ищем PubSubClient by Nick O'Leary → Install.
Добавляем MQTT в любой существующий проект (метеостанция, автополив, и т.д.):
#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
const char* WIFI_SSID = "Название_сети";
const char* WIFI_PASSWORD = "пароль";
const char* MQTT_SERVER = "192.168.1.100"; // IP вашего сервера
const int MQTT_PORT = 1883;
const char* DEVICE_ID = "teplica1"; // уникальный ID устройства
WiFiClient wifiClient;
PubSubClient mqtt(wifiClient);
DHT dht(4, DHT22);
void reconnectMQTT() {
while (!mqtt.connected()) {
if (mqtt.connect(DEVICE_ID)) {
Serial.println("MQTT подключён");
// Подписка на команды
mqtt.subscribe(("ferma/" + String(DEVICE_ID) + "/cmd").c_str());
} else {
delay(5000);
}
}
}
// Обработка входящих команд
void onMessage(char* topic, byte* payload, unsigned int length) {
String msg = "";
for (unsigned int i = 0; i < length; i++) msg += (char)payload[i];
Serial.println("Команда: " + msg);
if (msg == "status") {
float t = dht.readTemperature();
float h = dht.readHumidity();
String reply = "{\"temp\":" + String(t,1) + ",\"hum\":" + String(h,1) + "}";
mqtt.publish(("ferma/" + String(DEVICE_ID) + "/data").c_str(), reply.c_str());
}
if (msg == "reboot") {
ESP.restart();
}
}
void setup() {
Serial.begin(115200);
dht.begin();
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) delay(500);
mqtt.setServer(MQTT_SERVER, MQTT_PORT);
mqtt.setCallback(onMessage);
}
void loop() {
if (!mqtt.connected()) reconnectMQTT();
mqtt.loop();
// Отправка данных каждые 5 минут
static unsigned long lastSend = 0;
if (millis() - lastSend > 300000) {
float t = dht.readTemperature();
float h = dht.readHumidity();
if (!isnan(t) && !isnan(h)) {
String json = "{\"temp\":" + String(t,1) + ",\"hum\":" + String(h,1) + "}";
mqtt.publish(("ferma/" + String(DEVICE_ID) + "/data").c_str(), json.c_str());
}
lastSend = millis();
}
}
Важное отличие от прошлых проектов: ESP32 теперь не просто отправляет данные — он ещё слушает команды. Вы можете запросить текущие показания (status) или перезагрузить устройство (reboot) — прямо из VK-бота.
Шаг 3: VK-бот — получаем токен
VK Bot API — бесплатный и не требует регистрации домена или SSL-сертификата (в отличие от Telegram Webhook). Работает через Long Polling — бот сам периодически проверяет новые сообщения.
Создаём сообщество ВКонтакте (если нет): vk.com → Создать сообщество → Бизнес. Название — например, «Моя ферма IoT».
Получаем токен: Управление → Работа с API → Создать ключ. Даём права: «Разрешить сообщения сообщества», «Доступ к сообщениям». Копируем ключ — это VK_TOKEN.
Включаем Long Poll API: Управление → Работа с API → Long Poll API → Включено. Версия API: 5.199. Типы событий: «Входящее сообщение».
Шаг 4: Node.js сервер — мост между MQTT и VK
Вот полный код серверной части. Сохраняем в файл farm-hub.js:
const mqtt = require('mqtt');
const { VK } = require('vk-io');
// === НАСТРОЙКИ === //
const MQTT_URL = 'mqtt://localhost:1883';
const VK_TOKEN = 'ваш_токен_сообщества';
const ADMIN_ID = 123456789; // ваш VK user ID
const vk = new VK({ token: VK_TOKEN });
const client = mqtt.connect(MQTT_URL);
// Хранилище последних данных
const devices = {};
// MQTT: подписка на все устройства
client.on('connect', () => {
console.log('MQTT подключён');
client.subscribe('ferma/#');
});
// MQTT: обработка входящих данных
client.on('message', (topic, message) => {
const parts = topic.split('/');
const deviceId = parts[1];
const type = parts[2]; // "data", "alert", "status"
if (type === 'data') {
try {
const data = JSON.parse(message.toString());
devices[deviceId] = { ...data, updatedAt: new Date() };
// Проверка порогов
if (data.temp !== undefined) {
if (data.temp < 5) sendAlert(deviceId, `❄️ ${deviceId}: ${data.temp}°C — холодно!`);
if (data.temp > 35) sendAlert(deviceId, `🔥 ${deviceId}: ${data.temp}°C — перегрев!`);
}
if (data.hum !== undefined && data.hum > 90) {
sendAlert(deviceId, `💦 ${deviceId}: влажность ${data.hum}% — выше нормы`);
}
} catch (e) {
console.error('Parse error:', e);
}
}
});
// Дедупликация алертов: не чаще раза в 15 минут на устройство
const lastAlerts = {};
function sendAlert(deviceId, text) {
const key = deviceId + text.substring(0, 2);
const now = Date.now();
if (lastAlerts[key] && now - lastAlerts[key] < 900000) return;
lastAlerts[key] = now;
vk.api.messages.send({
user_id: ADMIN_ID,
message: text,
random_id: Math.floor(Math.random() * 1e9),
}).catch(console.error);
}
// VK Bot: обработка команд
vk.updates.on('message_new', async (context) => {
const text = context.text?.toLowerCase().trim();
if (text === 'статус' || text === 'status') {
const lines = Object.entries(devices).map(([id, d]) => {
const age = Math.round((Date.now() - new Date(d.updatedAt).getTime()) / 60000);
return `📍 ${id}: ${d.temp ?? '?'}°C, ${d.hum ?? '?'}%, ${age} мин назад`;
});
await context.send(lines.length
? '📊 Статус устройств:\n\n' + lines.join('\n')
: '🔇 Нет данных от устройств');
}
else if (text?.startsWith('cmd ')) {
// Формат: cmd teplica1 reboot
const [, deviceId, ...cmdParts] = text.split(' ');
const cmd = cmdParts.join(' ');
client.publish(`ferma/${deviceId}/cmd`, cmd);
await context.send(`✅ Команда "${cmd}" отправлена на ${deviceId}`);
}
else {
await context.send(
'🤖 Команды:\n' +
'• статус — показать все устройства\n' +
'• cmd [устройство] [команда] — отправить команду\n' +
' Пример: cmd teplica1 status'
);
}
});
// Запуск VK Long Poll
vk.updates.start().then(() => console.log('VK бот запущен'));
console.log('Farm Hub запущен');
Установка зависимостей и запуск:
npm init -y
npm install mqtt vk-io
node farm-hub.js
Для постоянной работы используйте PM2:
npm install -g pm2
pm2 start farm-hub.js --name farm-hub
pm2 save
pm2 startup
Шаг 5: используем бота
Откройте диалог с вашим сообществом ВКонтакте и напишите «статус». Бот ответит списком всех устройств с последними данными и временем обновления.
Напишите «cmd teplica1 status» — бот отправит команду на ESP32 через MQTT, устройство ответит свежими данными, и бот покажет их вам.
Напишите «cmd poliv1 reboot» — ESP32 автополива перезагрузится удалённо. Полезно, когда зависло соединение или нужно перечитать настройки.
Алерты приходят автоматически: если температура выходит за пороги — бот присылает сообщение. Дедупликация не даёт засыпать вас одинаковыми алертами — не чаще одного раза в 15 минут на каждый тип события.
Структура топиков: порядок вместо хаоса
Правильная иерархия топиков — залог масштабирования. Рекомендуемая схема:
ferma/
teplica1/
data → {"temp":24.5,"hum":65} (от ESP32)
cmd → "status" | "reboot" (от бота к ESP32)
teplica2/
data
cmd
poliv1/
data → {"soilMoisture":45}
cmd → "start" | "stop"
treker1/
data → {"lat":54.123,"lng":37.456,"speed":12}
vesy1/
data → {"weight":45.6,"crop":"tomato"}
Каждое устройство — отдельная ветка. Сервер подписывается на ferma/# и получает всё. ESP32 подписывается только на свой cmd-канал и никогда не знает про соседей.
Почему VK, а не Telegram
В статье про блокировки мы разбирали риски. Telegram работает — но завтра может перестать. VK Bot API:
- Работает без VPN и прокси на территории России
- Не требует SSL-сертификата и белого IP (Long Poll)
- Те же возможности: текст, кнопки, файлы, клавиатуры
- Бесплатен для сообществ
Если у вас уже есть Telegram-бот — ничто не мешает подключить оба канала. Один MQTT-сервер, два отправщика. Добавить второй мессенджер — 20 строк кода.
Что дальше
MQTT + VK бот — это «мозг» фермерской IoT-системы. Устройства присылают данные, сервер обрабатывает, бот уведомляет и принимает команды. Но текстовые сообщения — не самый удобный интерфейс для мониторинга 20 датчиков.
В следующей статье серии — дашборд на Nuxt: собственный веб-интерфейс с графиками, картой устройств и push-уведомлениями. Полностью под вашим контролем, без Grafana и облачных сервисов.
Весь код из статьи — рабочий. Mosquitto, Node.js сервер, ESP32-клиент — всё проверено и работает вместе. Копируйте, настраивайте под своё хозяйство. Вопросы — в комментарии.


