Главная → Академия → Основы умного дома → MQTT: язык Интернета вещей

MQTT: язык Интернета вещей

Урок 5 · Основы умного дома · 30 мин · theory

Что такое MQTT и почему он стал стандартом для IoT?

В предыдущих уроках мы рассмотрели протоколы, которые исторически использовались для связи устройств на объекте, такие как Modbus RTU и CAN. Они надежны и эффективны для локальных задач, но имеют ограничения при работе в глобальных сетях. MQTT (Message Queuing Telemetry Transport) — это протокол, созданный специально для эпохи «Интернета вещей» (IoT). Он работает поверх стека TCP/IP и использует совершенно иную модель взаимодействия, которая идеально подходит для распределенных систем с большим количеством устройств и потенциально ненадежными каналами связи.

> 💡 Подсказка: Модель Publish/Subscribe можно сравнить с подпиской на журнал. Вы подписываетесь на интересующую вас тему (topic), и почтальон (broker) доставляет вам свежий выпуск (message), как только он выходит. Вам не нужно постоянно спрашивать в редакции, не вышел ли новый номер.

Архитектура "Публикатор-Подписчик" (Publish/Subscribe)

В отличие от модели «запрос-ответ», используемой, например, в Modbus (где Master постоянно опрашивает Slave), MQTT построен на архитектуре «публикатор-подписчик» (Publish/Subscribe, или Pub/Sub). В этой модели устройства не общаются друг с другом напрямую. Вместо этого они общаются через центрального посредника.

📋 Ключевые понятия:

  • Клиент (Client): Любое устройство или приложение, которое может подключаться к брокеру. Клиент может быть как публикатором (отправляет сообщения), так и подписчиком (получает сообщения), или и тем, и другим одновременно. Датчик температуры — типичный публикатор. Панель управления или сценарий автоматизации — типичный подписчик.
  • Брокер (Broker): Центральный сервер, который действует как почтовая служба или диспетчер. Его задача — получать сообщения от публикаторов и доставлять их всем клиентам, которые подписаны на соответствующую тему. Брокер — это сердце всей MQTT-системы.
  • Топик (Topic): Строковый идентификатор, который определяет "канал" или "тему" сообщения. Например, `home/living_room/temperature`. Публикаторы отправляют сообщения в определенный топик, а подписчики подписываются на топики, которые их интересуют.

Эта архитектура полностью разделяет (decouples) клиентов. Датчик, публикующий температуру, ничего не знает о том, кто будет использовать эти данные. Это может быть мобильное приложение, система климат-контроля и система сбора статистики одновременно. Они просто подписываются на один и тот же топик.

Преимущества MQTT

  • Легковесность: Заголовки MQTT-сообщений очень малы (минимально 2 байта). Это делает протокол чрезвычайно эффективным с точки зрения трафика, что критично для устройств с ограниченной пропускной способностью, например, работающих через GSM или LoRaWAN.
  • Низкое энергопотребление: Благодаря своей эффективности и асинхронной природе, MQTT идеально подходит для устройств с батарейным питанием. Устройству не нужно постоянно поддерживать активное соединение; оно может "проснуться", отправить данные и снова "уснуть".
  • Работа в ненадежных сетях: MQTT был разработан для работы в условиях нестабильных соединений. Он имеет встроенные механизмы (Quality of Service, Last Will and Testament), которые обеспечивают гарантированную доставку сообщений и оповещение о разрыве связи с клиентом.
  • Благодаря этим качествам MQTT превратился из нишевого протокола для телеметрии в нефтегазовой отрасли (где он и был создан в конце 1990-х) в глобальный стандарт для миллионов IoT-устройств по всему миру — от умных лампочек до промышленных контроллеров и автомобилей.

    ---

    MQTT-брокер: цифровой почтальон вашего умного дома

    Как мы уже выяснили, брокер — это центральный узел всей MQTT-инфраструктуры. Он принимает на себя всю работу по управлению подписками и маршрутизации сообщений. На контроллере HI, работающем под управлением Debian, вы можете развернуть собственный MQTT-брокер, создав полностью автономную и независимую от облачных сервисов систему.

    Роль и задачи брокера

    • Прием сообщений: Получает сообщения от всех подключенных клиентов (публикаторов).
    • Аутентификация и авторизация: Проверяет, имеет ли клиент право на подключение к брокеру и на публикацию/подписку на определенные топики.
    • Фильтрация и доставка: Определяет, каким подписчикам необходимо доставить каждое конкретное сообщение на основе их подписок.
    • Управление сессиями: Хранит информацию о подписках клиентов, в том числе для тех, кто временно находится не в сети (для доставки сообщений после восстановления связи).

    Популярные реализации и установка Mosquitto

    Существует множество реализаций MQTT-брокеров, но наиболее популярным для локальных установок является Mosquitto. Это легковесный, надежный и очень производительный брокер с открытым исходным кодом.

    Для его установки на контроллер HI (или любую другую систему на базе Debian) достаточно выполнить одну команду:

    sudo apt-get update
    

    sudo apt-get install mosquitto mosquitto-clients -y

    Пакет `mosquitto-clients` содержит полезные утилиты командной строки (`mosquitto_pub` и `mosquitto_sub`) для отладки и тестирования.

    После установки брокер автоматически запустится как системный сервис и будет готов принимать подключения на стандартном порту `1883`.

    Основы безопасности: аутентификация и контроль доступа

    Запускать брокер в открытом виде, без пароля — крайне плохая практика даже в локальной сети. Любое устройство в сети сможет отправлять ложные команды и нарушать работу системы.

  • Создание файла паролей:
  • Сначала необходимо создать файл, в котором будут храниться имена пользователей и их зашифрованные пароли. Создадим пользователя `admin`:

        sudo mosquitto_passwd -c /etc/mosquitto/passwd admin

    Система дважды запросит пароль для нового пользователя.

  • Настройка конфигурации брокера:
  • Далее, нужно указать брокеру использовать этот файл для аутентификации. Создадим или отредактируем файл конфигурации `/etc/mosquitto/conf.d/default.conf` и добавим в него строки:

        # Запретить анонимные подключения

    allow_anonymous false

    # Указать путь к файлу с паролями

    password_file /etc/mosquitto/passwd

  • Применение настроек:
  • После сохранения файла конфигурации перезапустите сервис Mosquitto:

        sudo systemctl restart mosquitto

    Теперь для подключения к вашему брокеру любому клиенту потребуется указать логин `admin` и заданный вами пароль. Более сложные системы могут использовать списки контроля доступа (ACL, Access Control Lists), которые позволяют детально настроить, в какие топики каждый конкретный пользователь может публиковать (`write`) или из каких подписываться (`read`).

    ---

    Топики, полезная нагрузка и QoS

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

    Структура и иерархия топиков

    Топик — это не просто имя, это иерархический путь, похожий на структуру папок в файловой системе. Уровни иерархии разделяются косой чертой (`/`). Грамотное проектирование иерархии топиков — залог создания масштабируемой и понятной системы.

    Рекомендуемая структура для проектов на платформе HI: `project/location/device_class/device_id/control_or_sensor`.

    | Уровень | Пример | Описание |

    | ----------------- | --------------- | ----------------------------------------- |

    | Проект/Объект | `office` | Глобальный идентификатор объекта |

    | Расположение | `floor-1/room-101` | Физическое расположение устройства |

    | Класс устройства | `light` | Тип устройства (свет, розетка, датчик) |

    | ID устройства | `main` | Уникальный идентификатор в своем классе |

    | Контрол/Сенсор | `state` | Конкретный параметр или команда |

    Пример полного топика: `office/floor-1/room-101/light/main/state`. Для отправки команды управления используется суффикс `/set`, например: `office/floor-1/room-101/light/main/set`.

    Использование спецсимволов (Wildcards)

    Подписчики могут использовать два специальных символа (wildcards) для подписки сразу на несколько топиков:

    • `+` (плюс): заменяет один уровень иерархии.
    * Подписка на `office/floor-1/+/light/main/state` позволит получать состояние основного света во всех комнатах на первом этаже.
    • `#` (решетка): заменяет один или несколько уровней иерархии в конце топика.
    * Подписка на `office/floor-1/room-101/#` позволит получать абсолютно все сообщения, касающиеся комнаты 101 (свет, температура, движение и т.д.).

    Полезная нагрузка (Payload) и JSON

    Полезная нагрузка (payload) — это сами данные, которые передаются в сообщении. MQTT не накладывает никаких ограничений на формат этих данных, это могут быть просто строки (`"ON"`, `"OFF"`), числа (`23.5`) или бинарные данные.

    Однако, как мы уже установили в наших стандартах проектирования, для создания надежных систем необходимо придерживаться контракта сообщения. Стандартом де-факто для передачи структурированных данных в MQTT является формат JSON.

    Неправильно: отправлять просто `23.5`.

    Правильно: отправлять структурированный JSON-объект.

    {
    

    "value": 23.5,

    "unit": "C",

    "ts": 1678886400000,

    "source": "temp-sensor-room101"

    }

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

    Уровни качества обслуживания (QoS)

    MQTT предоставляет три уровня качества обслуживания (Quality of Service, QoS), которые позволяют выбрать компромисс между надежностью доставки и накладными расходами.

    | Уровень | Название | Описание | Применение |

    | ------- | ------------------------ | ------------------------------------------------------------------------------------------------------- | ----------------------------------------------- |

    | QoS 0 | At most once (Не более одного раза) | Сообщение отправляется один раз, доставка не подтверждается. "Отправил и забыл". Самый быстрый, но ненадежный. | Периодические данные с датчиков (температура). |

    | QoS 1 | At least once (Не менее одного раза) | Сообщение гарантированно будет доставлено, но может прийти несколько раз (дубликаты) в случае сбоев сети. | Команды управления (включить/выключить свет). |

    | QoS 2 | Exactly once (Ровно один раз) | Сообщение гарантированно будет доставлено ровно один раз. Самый надежный, но и самый медленный, требует 4 рукопожатий. | Критически важные транзакции (списание средств).|

    > ⚠️ Внимание: Использование QoS 2 гарантирует доставку ровно один раз, но создает значительную нагрузку на сеть и устройства. В 99% сценариев домашней и офисной автоматизации достаточно QoS 0 (для телеметрии) или QoS 1 (для команд).

    ---

    Практика: интеграция MQTT в Node-RED

    Контроллер HI с его средой Node-RED является идеальным инструментом для работы с MQTT. В палитре Node-RED по умолчанию есть узлы для взаимодействия с MQTT-брокером.

    Обзор узлов `mqtt in` и `mqtt out`

    • `mqtt in`: Узел-подписчик. Он подписывается на указанный топик на брокере и создает новое сообщение в потоке Node-RED каждый раз, когда приходит сообщение в этот топик.
    • `mqtt out`: Узел-публикатор. Он принимает сообщение из потока и публикует его `msg.payload` в указанный `msg.topic` на брокере.

    Настройка подключения к MQTT-брокеру

    Оба узла используют общий узел конфигурации "MQTT-Broker".

  • Дважды кликните по узлу `mqtt in` или `mqtt out`.
  • В поле "Server" нажмите на иконку карандаша для редактирования.
  • На вкладке "Connection" укажите:
  • * Server: IP-адрес или доменное имя вашего брокера (например, `localhost` или `192.168.1.10`).

    * Port: `1883` (стандартный порт).

    * Client ID: Оставьте пустым, Node-RED сгенерирует уникальный ID.

  • На вкладке "Security" укажите:
  • * Username: `admin` (или ваш логин).

    * Password: Ваш пароль.

  • Нажмите "Update", а затем "Done".
  • Создание потока для управления виртуальной лампой

    Создадим два простых потока, чтобы продемонстрировать принцип работы.

    Поток 1: Публикация команды

    Этот поток будет имитировать отправку команды на включение/выключение света.

  • Разместите на поле узел `inject`. Настройте его на отправку JSON.
  •     {

    "command": "ON",

    "brightness": 100

    }

  • Добавьте еще один узел `inject`, настроенный на отправку:
  •     {

    "command": "OFF"

    }

  • Добавьте узел `function` для формирования `msg.topic` и `msg.payload`. Назовем его "Prepare Command".
  •     // Устанавливаем топик для команды

    msg.topic = "home/kitchen/light/main/set";

    // Передаем в payload только команду

    msg.payload = msg.payload.command;

    return msg;

  • Соедините оба узла `inject` с узлом `function`.
  • Подключите выход узла `function` к узлу `mqtt out`. В настройках `mqtt out` выберите созданный ранее сервер и оставьте поле "Topic" пустым, так как мы задаем его динамически в `msg.topic`.
  • Поток 2: Подписка на состояние

    Этот поток будет слушать команды и выводить их в отладочную консоль.

  • Разместите узел `mqtt in`.
  • В настройках узла укажите:
  • * Server: Выберите ваш настроенный брокер.

    * Topic: `home/kitchen/light/main/set`

    * QoS: `1`

    * Output: `a parsed JSON object` (если вы отправляете JSON, но в нашем примере мы отправляем строку `ON`/`OFF`, поэтому лучше оставить `a string`).

  • Соедините выход узла `mqtt in` с узлом `debug`.
  • Теперь, развернув (Deploy) этот проект, при нажатии на первый `inject` узел, в консоль отладки придет сообщение `"ON"`. При нажатии на второй — `"OFF"`. Мы создали систему, где отправитель и получатель ничего не знают друг о друге, а общаются через посредника — MQTT-брокера.

    ---

    Пример: MQTT как "клей" для разных протоколов (на примере стороннего оборудования)

    Одна из самых мощных функций MQTT — это возможность служить универсальным слоем (шиной данных) для объединения систем, работающих на совершенно разных физических протоколах. Эту концепцию хорошо иллюстрирует контроллер с MQTT-шлюзом, например сторонний контроллер Wiren Board. В системе HI устройства, приложения и панель также связаны между собой по MQTT через брокер домашнего сервера.

    Концепция протокольного шлюза

    Представьте типичный сценарий автоматизации:

    • Контроллер установлен в электрощите.
    • К его порту RS-485 подключена шина с несколькими устройствами: счетчик электроэнергии (например, WB-MAP12E), модуль реле (WB-MR6C) и настенный датчик CO2 (WB-MSW3).
    • Все эти устройства общаются по протоколу Modbus RTU, который мы рассматривали в уроке `COURSE-01-M04-L02`.

    Вручную опрашивать каждое устройство и парсить его регистры в Node-RED — это трудоемкая задача. Вместо этого на таком контроллере работает специальный сервис-шлюз (у Wiren Board он называется `wb-mqtt-serial`).

    Автоматическая публикация данных в MQTT

    Задача сервиса `wb-mqtt-serial` очень проста:

  • Он постоянно опрашивает все сконфигурированные устройства на шине RS-485 по протоколу Modbus.
  • Как только он получает новые данные (например, текущее напряжение от счетчика или состояние реле), он немедленно публикует эти данные в предопределенный MQTT-топик на локальном брокере Mosquitto.
  • Он также подписывается на `/set` топики, и при получении в них сообщения, транслирует эту команду в Modbus-запись на соответствующее устройство.
  • Пример со счетчиком электроэнергии

    Допустим, у нас есть счетчик WB-MAP12E с Modbus-адресом `1`. Сервис `wb-mqtt-serial` автоматически создаст для него в MQTT-брокере целое дерево топиков:

    • `devices/wb-map12e_1/controls/U_L1`: здесь будет публиковаться текущее напряжение на Фазе 1 (например, `231.5`).
    • `devices/wb-map12e_1/controls/I_L1`: здесь будет публиковаться ток на Фазе 1 (например, `1.2`).
    • `devices/wb-map12e_1/controls/P_L1`: здесь будет публиковаться активная мощность на Фазе 1 (например, `270`).

    Теперь, чтобы получить значение напряжения, нашему сценарию в Node-RED не нужно ничего знать о Modbus, адресах регистров, типах данных и портах RS-485. Ему достаточно подписаться с помощью узла `mqtt in` на топик `devices/wb-map12e_1/controls/U_L1`.

    Точно так же, чтобы включить реле на модуле WB-MR6C, достаточно отправить значение `1` в топик `devices/wb-mr6_15/controls/K1/on`. Сервис `wb-mqtt-serial` поймает это сообщение и отправит нужную Modbus-команду на шину RS-485.

    Таким образом, MQTT становится универсальным "языком" внутри контроллера. Любое устройство, подключенное по любому физическому протоколу (Modbus, CAN, 1-Wire), через соответствующий сервис-шлюз представляет свои данные и команды в едином формате — через MQTT-топики. Это и есть главный принцип построения гибких и масштабируемых систем автоматизации.

    ---

    Итоги: MQTT — нервная система современного умного дома

    В этом уроке мы совершили глубокое погружение в самый важный протокол для «Интернета вещей». MQTT — это не просто технология, это философия построения распределенных систем.

    Давайте закрепим ключевые概念:

    • Архитектура Pub/Sub с Клиентами и центральным Брокером обеспечивает слабую связанность и асинхронность компонентов системы.
    • Топик — это иерархический адрес сообщения, а Полезная нагрузка (Payload), в идеале в формате JSON, несет сами данные.
    • Качество обслуживания (QoS) позволяет выбрать баланс между скоростью и надежностью доставки.
    • На контроллере HI связка Mosquitto (брокер) и Node-RED (логика) позволяет строить мощные и гибкие сценарии.
    • MQTT выступает в роли универсального клея, объединяя устройства с разными физическими интерфейсами (Modbus, CAN) в единое информационное пространство.

    Благодаря своей гибкости, масштабируемости и эффективности, MQTT по праву можно назвать цифровой нервной системой современного умного дома или офиса, по которой бегут все сигналы — от простого нажатия кнопки до сложных команд управления климатом.

    Что дальше

    Мы рассмотрели основы MQTT, но у протокола есть и более продвинутые функции, которые делают его еще мощнее:

    • Флаг `retain`: Позволяет брокеру хранить последнее сообщение в топике и немедленно отправлять его новым подписчикам.
    • Last Will and Testament (LWT): "Последняя воля и завещание" клиента — специальное сообщение, которое брокер опубликует, если клиент внезапно оборвет связь.
    • Шифрование TLS: Обеспечение безопасности и конфиденциальности данных при передаче через публичные сети.

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