Шаблон 2: Edge + MQTT Broker
---
id: COURSE-01-M06-L02
title: "Шаблон 2: Edge + MQTT Broker"
level: Foundation
tags:
- архитектура
- edge computing
- mqtt
- mqtt broker
- node-red
- mosquitto
- publish-subscribe
- интеграция
prerequisites:
- COURSE-01-M06-L01
version: 1.0
status: published
learning_outcomes:
- "Студент должен уметь объяснить разницу между архитектурными шаблонами 'Standalone' и 'Edge + MQTT'."
- "Студент должен быть способен установить и выполнить базовую настройку MQTT-брокера Mosquitto на Debian."
- "Студент должен уметь настроить поток в Node-RED для публикации данных с устройства в MQTT-брокер."
- "Студент должен уметь подписаться на MQTT-топик для получения и визуализации данных."
key_concepts:
- "MQTT"
- "MQTT Broker"
- "Edge Computing"
- "Publish-Subscribe"
- "Топик (Topic)"
- "Node-RED"
- "Mosquitto"
- "Разделение (Decoupling)"
---
# COURSE-01-M06-L02: Шаблон архитектуры 2: Edge + MQTT Broker
Введение в архитектуру "Edge + MQTT Broker"
🔗 Связанный материал: Для полного понимания преимуществ данного шаблона настоятельно рекомендуется изучить предыдущий урок COURSE-01-M06-L01 "Шаблон 1: Standalone (Автономный контроллер)".
В предыдущем уроке мы рассмотрели полностью автономный шаблон "Standalone", где один контроллер является и мозгом, и исполнительным устройством системы. Эта модель превосходно подходит для небольших объектов, таких как квартиры или малые офисы, где все задачи автоматизации могут быть решены в рамках одного устройства.
Однако по мере роста масштаба и сложности проекта, "Standalone" архитектура начинает проявлять свои ограничения:
Сложность интеграции: Подключение сторонних систем (панели визуализации, голосовые ассистенты, облачные сервисы аналитики) требует создания отдельных, часто уникальных шлюзов для каждого соединения.
Масштабируемость: Расширение системы путем добавления новых контроллеров превращается в сложную задачу по их взаимной синхронизации, что приводит к созданию запутанных "паутинных" связей "каждый с каждым".
Централизованный мониторинг: Сбор данных с нескольких независимых контроллеров для единой панели мониторинга или системы отчетности затруднен.
Для решения этих проблем применяется распределенная архитектура "Edge + MQTT Broker".
📋 Ключевые понятия:
- Edge Computing (Граничные вычисления): Концепция, при которой обработка данных и принятие решений происходят максимально близко к источнику данных — на "границе" сети. В нашем контексте, Edge-устройством является наш контроллер. Он самостоятельно собирает данные с датчиков, выполняет критически важную локальную логику (например, выключение света по датчику движения) и лишь затем отправляет информацию о своем состоянии в центральную систему. Это повышает надежность: даже если центральный сервер недоступен, базовая автоматизация продолжает работать.
- MQTT Broker (Брокер сообщений): Центральный программный компонент, который действует как почтовое отделение для сообщений. Устройства (издатели) отправляют сообщения на определенные "адреса" (топики), а другие устройства и приложения (подписчики) получают эти сообщения, если они подписаны на эти топики. Брокер не знает о содержании сообщений, его задача — гарантировать их доставку.
Общая схема потоков данных в данной архитектуре выглядит следующим образом:
ascii
+-------------------+
| MQTT-брокер |
| (Центральный узел)|
+--------^----------+
| (3) Публикация в топик
| /devices/wb-ms_1/temperature
|
+-----------+ (1) Сбор данных +-------------------+ (4) Подписка на топик
| Датчик | <----(Modbus)---- | Edge-контроллер |----> | Клиенты: |
| WB-MS v3 | | (Логика в Node-RED| | - Панель визуализации |
+-----------+ | преобразование) | | - Мобильное приложение |
+-------------------+ | - Система аналитики |
(2) Обработка +------------------------+
Сбор данных: Edge-контроллер опрашивает датчик температуры по шине Modbus.
Обработка: Логика в Node-RED на контроллере получает сырое значение, преобразует его в стандартный JSON-формат и, при необходимости, выполняет локальные сценарии (например, управляет климатом).
Публикация: Контроллер подключается к центральному MQTT-брокеру и публикует (Publish) сообщение с данными о температуре в предопределенный топик.
Подписка: Различные клиенты (панель визуализации, мобильное приложение, другой контроллер) заранее подписаны (Subscribe) на этот топик у брокера. Как только брокер получает сообщение, он немедленно пересылает его всем активным подписчикам.
Таким образом, контроллер и клиенты не знают о существовании друг друга. Они взаимодействуют исключительно через брокера, что обеспечивает гибкость и масштабируемость системы.
Роль и базовая настройка MQTT-брокера
💡 Подсказка: Используйте утилиту MQTT Explorer. Это незаменимый графический инструмент для отладки и визуализации сообщений на вашем брокере. Он позволяет в реальном времени видеть все топики, их содержимое, а также публиковать тестовые сообщения.
Как мы выяснили, MQTT-брокер — это сердце нашей распределенной системы. Протокол MQTT основан на простой и эффективной модели "Издатель/Подписчик" (Publish/Subscribe), которая является индустриальным стандартом для IIoT (Промышленный Интернет Вещей) и систем автоматизации.
Ключевые параметры MQTT, которые необходимо понимать инженеру:
- QoS (Quality of Service - Качество обслуживания):
* `QoS 0: At most once` - "Не более одного раза". Сообщение отправляется без подтверждения доставки. Максимально быстро, но возможны потери. Подходит для часто обновляемых данных, где потеря одного значения не критична (например, температура).
* `QoS 1: At least once` - "Не менее одного раза". Гарантирует, что сообщение будет доставлено хотя бы один раз. Издатель будет повторно отправлять сообщение, пока не получит подтверждение от брокера. Используется для команд управления (включить реле, изменить уставку).
* `QoS 2: Exactly once` - "Ровно один раз". Самый надежный, но и самый медленный уровень. Гарантирует, что сообщение будет доставлено ровно один раз через механизм двойного подтверждения. Используется крайне редко, в основном в финансовых или медицинских системах.
- Retain Flag (Флаг удержания): Если сообщение публикуется с флагом `retain=true`, брокер сохранит это сообщение как "последнее известное значение" для данного топика. Любой новый клиент, который подпишется на этот топик, немедленно получит это сохраненное сообщение. Это критически важно для получения актуального состояния устройств (например, включен ли свет) сразу после подключения клиента, а не ждать следующего обновления.
Выбор и установка MQTT-брокера (Mosquitto)
Существует несколько вариантов развертывания брокера:
Встроенный брокер контроллера: Наш контроллер (на базе Wiren Board) имеет собственный встроенный MQTT-брокер `wb-mqtt-serial`. Он удобен, но привязывает центральную точку к одному конкретному контроллеру.
Облачные сервисы: AWS IoT Core, Google Cloud IoT, Azure IoT Hub и др. предоставляют управляемые и масштабируемые MQTT-брокеры. Это решение для крупных, географически распределенных систем.
Собственный сервер: Установка брокера на выделенный сервер (виртуальный или физический) дает полный контроль над конфигурацией и безопасностью. Наиболее популярным open-source брокером является Eclipse Mosquitto.
Для целей обучения и большинства реальных проектов мы будем использовать Mosquitto, установленный на сервер с ОС Debian (это может быть как отдельная виртуальная машина, так и сам контроллер, если проект небольшой).
Практика: Установка и минимальная конфигурация Mosquitto
Подключитесь к вашему серверу/контроллеру по SSH.
Установите Mosquitto и клиентские утилиты:
bash
sudo apt update
sudo apt install mosquitto mosquitto-clients -y
3. Проверьте статус службы, чтобы убедиться, что брокер запущен:
bash
sudo systemctl status mosquitto
Вы должны увидеть статус `active (running)`.
По умолчанию Mosquitto работает на порту 1883 и разрешает анонимные подключения. Для производственных систем это недопустимо, но для начала обучения — достаточно. Создадим базовый конфигурационный файл для включения логирования и сохранения состояний. Создайте файл `/etc/mosquitto/conf.d/local.conf`:
bash
sudo nano /etc/mosquitto/conf.d/local.conf
Добавьте в файл следующие строки:
ini
# local.conf for Mosquitto
# Разрешить анонимные подключения. Для продакшена установить в false
# и настроить аутентификацию по логину/паролю или сертификатам.
allow_anonymous true
# Указываем порт для прослушивания. Стандартный порт MQTT.
listener 1883
# Настройки персистентности (сохранения данных)
# Включить сохранение сообщений с флагом Retain и сессий клиентов
persistence true
# Файл для сохранения базы данных
persistence_file mosquitto.db
# Местоположение файла
persistence_location /var/lib/mosquitto/
# Ведение логов для отладки
log_dest file /var/log/mosquitto/mosquitto.log
log_type all
6. Перезапустите Mosquitto, чтобы применить конфигурацию:
bash
sudo systemctl restart mosquitto
Теперь у вас есть работающий MQTT-брокер, готовый принимать и пересылать сообщения.
Практика: Настройка Edge-контроллера в Node-RED
⚠️ Внимание: Критически важно с самого начала проекта выработать и строго соблюдать соглашение об именовании топиков (Topic Naming Convention). Беспорядочная структура топиков приводит к хаосу и неразберихе в больших системах. Рекомендуемая структура: `проект/место/устройство/параметр`. Например: `/house/floor1/livingroom/wb-msw3_sn12345/temperature`.
Теперь настроим наш контроллер для работы в роли Edge-устройства. Он будет считывать данные с физического датчика и публиковать их на наш новый MQTT-брокер.
Сценарий: Считываем температуру с датчика WB-MSW v.3, подключенного по Modbus RTU к контроллеру, и публикуем ее на MQTT-брокер.
Создание подключения к брокеру:
В палитре Node-RED найдите узел `mqtt out` и перетащите его на холст. Дважды кликните по нему. В поле "Server" выберите "Add new mqtt-broker..." и нажмите на иконку карандаша. В открывшемся окне укажите:
* Name: My MQTT Broker (или любое понятное имя)
* Server: IP-адрес вашего сервера с Mosquitto (например, `192.168.1.10`)
* Port: `1883`
Нажмите "Add".
Чтение данных с устройства:
Как мы рассматривали в предыдущих уроках, данные с подключенных к контроллеру устройств уже доступны в виде MQTT-топиков во внутреннем брокере `wb-mqtt-serial`. Используем узел `mqtt in`, чтобы подписаться на топик датчика температуры.
* Настройте узел `mqtt in` на подключение к локальному брокеру (обычно `localhost:1883` на самом контроллере).
* Укажите топик датчика, например: `/devices/wb-msw-v3_25/controls/Temperature`.
Форматирование данных (Контракт сообщения):
Узел `mqtt in` выдаст нам простое числовое значение. Хорошей практикой является "обертывание" этих данных в стандартизированный JSON-объект. Это делает сообщение самодостаточным и расширяемым в будущем. Используем для этого узел `function`.
javascript
// Получаем значение температуры из входящего сообщения
const tempValue = parseFloat(msg.payload);
// Проверяем, что значение является числом
if (isNaN(tempValue)) {
// Если данные некорректны, прерываем поток
node.warn("Invalid temperature value: " + msg.payload);
return null; // Прекращаем выполнение
}
// Формируем новый объект msg с нужной структурой
msg.payload = {
"value": tempValue,
"unit": "C", // Указываем единицы измерения
"ts": Date.now() // Добавляем временную метку (timestamp)
};
// Устанавливаем топик для публикации на внешний брокер
msg.topic = "/myhome/floor1/livingroom/sensors/temperature";
// Отправляем сообщение дальше по потоку
return msg;
Этот JSON-объект `{ "value": 23.5, "unit": "C", "ts": 1677611223000 }` называется контрактом сообщения. Все участники системы теперь "договариваются", что данные о температуре всегда будут приходить именно в таком формате.
Публикация на внешний брокер:
Соедините выход узла `function` со входом узла `mqtt out`, который мы настроили в шаге 1. Убедитесь, что в настройках `mqtt out` поля `Topic`, `QoS` и `Retain` оставлены пустыми. В этом случае узел будет использовать `msg.topic`, `msg.qos` и `msg.retain` из пришедшего сообщения, что делает наш поток более гибким.
Итоговый поток в Node-RED:
ascii
[mqtt in]------------>[function]------------>[mqtt out]
(Подписка на (Форматирование (Публикация на
локальный датчик) в JSON и установка внешний брокер)
нового топика)
Интеграция с клиентами: Визуализация и управление
Главное преимущество архитектуры с MQTT-брокером — разделение (decoupling). Производитель данных (наш контроллер) и потребители (приложения) ничего не знают друг о друге. Мы можем добавлять и убирать потребителей, не внося никаких изменений в логику контроллера.
Пример 1: Визуализация в Node-RED Dashboard
Предположим, у нас есть второй экземпляр Node-RED (или даже этот же), который выступает в роли панели визуализации.
Перетащите на холст узел `mqtt in`.
Настройте его на подключение к нашему внешнему MQTT-брокеру (тому, где работает Mosquitto).
В поле "Topic" укажите топик, в который мы публикуем данные: `/myhome/floor1/livingroom/sensors/temperature`.
Установите "Output" в "a parsed JSON object". Это позволит сразу работать с объектом, а не со строкой.
Подключите к выходу узла `mqtt in` узел `change` для извлечения значения. Настройте его на установку `msg.payload` в значение `msg.payload.value`.
Подключите к выходу узла `change` узел из палитры `dashboard`, например `gauge` (стрелочный прибор). Задайте для него диапазон и название.
Разверните поток. Теперьgauge будет в реальном времени отображать температуру, получая данные через центральный MQTT-брокер.
Пример 2: Управление реле со сторонней панели (iRidium)
Теперь рассмотрим обратный процесс — управление.
На контроллере: Создайте новый поток в Node-RED.
* Добавьте узел `mqtt in`, подписанный на топик команды, например: `/myhome/floor1/livingroom/relay1/set`. Настроен на внешний брокер.
* Добавьте узел `switch`, который проверяет `msg.payload`. Если `msg.payload` равно строке `"ON"`, перенаправляет на один выход. Если `"OFF"` — на другой.
* К этим выходам подключите узлы `mqtt out`, которые публикуют значение `1` или `0` в локальный MQTT-топик управления реле контроллера, например `/devices/wb-mr6c_21/controls/K1/on`.
На панели iRidium (или в MQTT Explorer для теста):
* Подключитесь к внешнему MQTT-брокеру.
* Создайте кнопку, которая при нажатии будет публиковать сообщение с payload `"ON"` в топик `/myhome/floor1/livingroom/relay1/set`.
* Создайте вторую кнопку для отправки `"OFF"`.
Теперь, при нажатии кнопки на панели iRidium, команда пройдет через MQTT-брокер, будет получена Node-RED на контроллере, который, в свою очередь, отправит команду на физическое реле. Контроллер и панель визуализации полностью независимы.
Сравнение шаблонов и итоговые выводы
Архитектура "Edge + MQTT Broker" является мощным шагом вперед по сравнению с автономной моделью, открывая двери для создания по-настоящему масштабируемых и гибких систем.
Преимущества:
- Масштабируемость: Легко добавлять новые контроллеры. Каждый новый контроллер просто подключается к тому же брокеру и начинает публиковать свои данные и слушать команды.
- Гибкость и интеграция: Любая система, поддерживающая MQTT (а это почти все современные платформы визуализации, голосовые ассистенты, SCADA-системы), может быть легко интегрирована.
- Отказоустойчивость (на уровне Edge): Если центральный брокер или сеть пропадают, локальная логика на Edge-контроллере продолжает работать автономно. Свет по-прежнему будет включаться по датчику движения.
- Централизованный мониторинг и управление: Все данные со всех объектов стекаются в одно место (брокер), откуда их легко собирать, анализировать и визуализировать.
Недостатки (и пути их решения):
- Повышение сложности: Система становится сложнее из-за появления нового компонента — брокера, который нужно устанавливать, настраивать и обслуживать.
- Единая точка отказа (SPOF): Сам MQTT-брокер становится критически важным узлом. Его отказ приведет к потере связи между всеми компонентами системы (хотя локальная автоматика продолжит работать).
Решение:* В высоконадежных системах применяется кластеризация MQTT-брокеров, где несколько серверов работают в паре для обеспечения бесперебойной работы.
Сравнительная таблица шаблонов
| Характеристика | Шаблон "Standalone" (Урок L01) | Шаблон "Edge + MQTT" (Текущий урок) |
| :--- | :--- | :--- |
| Масштабируемость | Низкая. Сложно добавлять контроллеры. | Высокая. Легко добавлять контроллеры и клиенты. |
| Интеграция | Сложная. Требуются кастомные шлюзы. | Простая. Через стандартный протокол MQTT. |
| Отказоустойчивость| Высокая (в пределах одного устройства).| Комбинированная. Локальная логика работает, межсистемная связь пропадает при отказе брокера.|
| Сложность настройки| Низкая. Все в одном месте. | Средняя. Требуется настройка брокера и связей. |
| Типовой проект | Квартира, небольшой дом, одна функция. | Коттедж, офис, гостиница, любой объект с интеграциями.|
Рекомендации по применению:
Переходить к архитектуре "Edge + MQTT Broker" следует в проектах, где:
- Задействовано более одного контроллера.
- Требуется интеграция с внешними системами: панелями визуализации, мобильными приложениями, голосовыми ассистентами, SCADA.
- Планируется дальнейшее расширение системы.
- Необходим централизованный сбор данных для аналитики и отчетности.
---
Лабораторные работы и проверка знаний
Лабораторная работа: COURSE-01-M06-LAB01
- Название: Публикация данных с симулированного датчика на MQTT-брокер.
- Цель: Отработать навык чтения данных, их форматирования в стандартный JSON и публикации на внешний MQTT-брокер.
- Flow Diagram:
ascii
[inject]------>[function]------>[mqtt out]------>[debug]
(Симуляция (Форматирование (Публикация) (Проверка
датчика) в JSON) отправки)
* Skeleton (вставьте в узел `function`):
javascript
// Симулируем значение датчика
const simValue = Math.random() * 10 + 15; // Случайная температура от 15 до 25
msg.payload = {
"value": parseFloat(simValue.toFixed(2)),
"unit": "C",
"ts": Date.now()
};
msg.topic = "/lab/device01/temperature";
msg.qos = 1;
msg.retain = true;
return msg;
* Чек-лист выполнения:
1. [ ] Настроен узел `mqtt out` для подключения к внешнему Mosquitto-брокеру.
2. [ ] Узел `inject` настроен на запуск раз в 5 секунд.
3. [ ] Код вставлен в узел `function`.
4. [ ] Узел `mqtt out` соединен с узлом `debug`.
5. [ ] После развертывания, в окне отладки появляются JSON-объекты, отправленные в MQTT.
6. [ ] (Проверка) В MQTT Explorer виден топик `/lab/device01/temperature` с обновляемыми значениями.
- Усложнение: Добавьте в JSON-объект поле `"status": "ok"` и второй узел `inject`, который отправляет некорректные данные (например, строку `"error"`). Доработайте `function` так, чтобы он либо прерывал поток, либо отправлял JSON с `"status": "error"`.
Лабораторная работа: COURSE-01-M06-LAB02
- Название: Создание дашборда на основе данных из MQTT.
- Цель: Научиться подписываться на MQTT-топики и визуализировать полученные данные.
- Flow Diagram:
ascii
[mqtt in]------>[change]------>[ui_gauge]
(Подписка) (Извлечение (Визуализация)
поля "value")
```
- Чек-лист выполнения:
2. [ ] Узел `mqtt in` настроен на подключение к внешнему брокеру и подписку на топик `/lab/device01/temperature` из LAB01.
3. [ ] В узле `mqtt in` выход (`Output`) установлен в `a parsed JSON object`.
4. [ ] Узел `change` настроен на `Set msg.payload to msg.payload.value`.
5. [ ] Узел `ui_gauge` добавлен на дашборд и настроен (диапазон 10-30, заголовок "Температура").
6. [ ] После развертывания, на странице дашборда (`http://_ваш_ip_:1880/ui`) отображается прибор, показывающий температуру.
- Усложнение: Добавьте на дашборд узел `ui_chart` для отображения графика изменения температуры за последний час.
Квиз модуля: COURSE-01-M06-QUIZ
* a) Низкая скорость работы.
* b) Сложность интеграции и масштабирования.
* c) Высокое энергопотребление.
* d) Невозможность работать с Modbus.
* a) Все вычисления производятся в облаке.
* b) Выполнение критической логики непосредственно на контроллере у источника данных.
* c) Использование только проприетарных протоколов.
* d) Отказ от использования контроллеров.
* a) Хранить историю всех сообщений за год.
* b) Выполнять логику автоматизации.
* c) Анализировать содержание сообщений.
* d) Принимать сообщения от издателей и доставлять их подписчикам.
* a) Контроллер перезагрузится.
* b) Вся автоматика остановится.
* c) Локальные сценарии (свет по датчику движения) продолжат работать.
* d) Все реле перейдут в безопасное состояние "выключено".
* a) QoS 1
* b) QoS 2
* c) Retain
* d) Clean Session
* a) Юридический документ между заказчиком и интегратором.
* b) Стандартизированный формат данных (например, JSON), которого придерживаются все участники системы.
* c) Название MQTT-топика.
* d) Настройки шифрования канала связи.
* a) Для написания кода логики в Node-RED.
* b) Для физического подключения датчиков.
* c) Для визуализации топиков и сообщений на брокере в реальном времени.
* d) Для обновления прошивки контроллера.
* a) Уменьшается сетевой трафик.
* b) Систему сложнее взломать.
* c) Можно добавлять или изменять клиентов, не затрагивая логику на контроллере.
* d) Логика выполняется быстрее.
* a) QoS 0
* b) QoS 1
* c) QoS 2
* d) QoS 3
* a) Из глобального контекста.
* b) Из поля `msg.topic` во входящем сообщении.
* c) Он всегда жестко прописан в настройках узла.
* d) Топик не нужен, достаточно IP-адреса.
---
Мини-runbook: Если что-то не работает (Edge + MQTT)
| Проблема | Что проверить (чек-лист) |
| :--- | :--- |
| Сообщения от контроллера не появляются на брокере (в MQTT Explorer) | 1. Сеть: Доступен ли IP-адрес брокера с контроллера? (`ping
2. Порт: Не блокирует ли файрвол порт `1883`?
3. Node-RED: Правильно ли настроен узел `mqtt out` (IP, порт)?
4. Node-RED: Поступает ли сообщение на вход узла `mqtt out` (проверить с помощью `debug`)?
5. Mosquitto Log: Проверить логи брокера (`/var/log/mosquitto/mosquitto.log`) на предмет ошибок подключения. |
| Клиент (дашборд, панель) не получает сообщения с брокера | 1. Сеть и Порт: Аналогично предыдущему пункту, но для клиента.
2. Топик: Абсолютное совпадение топика подписки у клиента и топика публикации у контроллера (включая регистр, слеши). `/MyHome/Temp` и `/myhome/temp` — это разные топики.
3. Подписка со wildcard: Попробуйте подписаться на `#` в MQTT Explorer. Если сообщения приходят туда, значит проблема в написании конкретного топика у клиента.
4. Retain Flag: Если клиент подключается и не видит состояния, возможно, оно было отправлено без флага `retain=true`. |
| Команда от клиента не доходит до контроллера | 1. Направление: Убедитесь, что клиент публикует (Publish) в топик команды, а контроллер подписан (Subscribe) на этот же топик.
2. Payload: Проверьте точное совпадение полезной нагрузки (payload). Если контроллер ждет `"ON"`, а клиент шлет `"on"` или `1`, команда не сработает.
3. Логика в Node-RED: Проверьте узел `switch` или `function` на контроллере, который обрабатывает входящую команду. Добавьте узел `debug` сразу после узла `mqtt in`, чтобы видеть, что именно приходит от клиента. |
Что дальше
В следующем уроке, COURSE-01-M06-L03: "Шаблон 3: Multi-Controller (Распределенная логика)", мы рассмотрим, как объединить несколько Edge-контроллеров в единую систему для работы на крупных объектах, где одного устройства уже недостаточно.