Конституция — свод незыблемых правил, по которым контроллер moduleBox общается с внешним миром через UART, UDP, OSC и MQTT. Правила одинаковы для всех модулей и не меняются без веской причины: на них опираются прошивка, конфигуратор mbApp и сторонние интеграции.

Актуальный набор модулей и их событий и команд для конкретной прошивки берётся из сгенерированного manifest.json — он и есть живой реестр возможностей. Код обязан соответствовать конституции; отдельной рукописной таблицы по модулям нет, чтобы исключить расхождения.

Идея в одном абзаце

Контроллер состоит из модулей. Каждый модуль либо что-то сообщает миру (нажали кнопку, кончился трек, изменилось значение датчика), либо принимает команды (зажги лампу, играй трек, усни). Первое — event, второе — action. Больше направлений нет. Та же пара event/action используется и для внутренних связей между модулями (crossLink), и для связи с внешним брокером — язык один.

Структура топика

<deviceName>/<модуль>_<слот>/<направление>/<имя>
ЧастьЧто этоПример
deviceNameИмя устройства, задаёт пользовательhall-panel
модульИмя модуля, одинаково для родственныхbutton
слотНомер слота, отделён _2
направлениеevent или actionevent
имяЧто именно произошло или что сделатьlongPress

Полный пример:

hall-panel/button_2/event/longPress        payload: 1
hall-panel/led_2/action/setMaxBright       payload: 200

==Минимум четыре уровня после deviceName.== Имя обязательно всегда — односложных модулей без имени нет. Имя может содержать дополнительные сегменты (ch_0, ch_1 и т. п.): глубина растёт вправо от имени, а не вставляется между фиксированными уровнями. Это позволяет прошивке разбирать топик без ветвлений — первые три уровня читаются по позиции.

Направления

НаправлениеКто пишетСмысл
eventмодуль (контроллер)«случилось вот это» — модуль → мир
actionмир или crossLink«сделай вот это» — мир → модуль

Внешняя система подписывается на event/* и публикует в action/*. CrossLink делает то же самое внутри контроллера: слушает чей-то event/* и пишет в чей-то action/*. Поэтому одна и та же автоматизация работает одинаково и локально, и через брокер.

Payload

Полезная нагрузка — голое значение, без обёрток и JSON.

ТипФорматПример
bool0 / 11
intцелое в виде строки80
floatдробное в виде строки3.14
stringстрокаflash
rgbтри числа через пробел255 255 255

Имя величины всегда в топике, значение — в payload. Двоеточие и прочие разделители «имя:значение» внутри одной строки не используются.

Note

Записи вида longPress:1 или ledMode:flash — это человеческая нотация «топик <имя> со значением <value>», она применяется в конфигурационном файле и в правилах crossLink. В реальном MQTT имя и значение разнесены:

topic:   hall-panel/led_3/action/ledMode
payload: flash

Такое разделение даёт подписку <deviceName>/+/event/longPress — она поймает все долгие нажатия в системе независимо от значения, а 0 и 1 различаются по payload.

Зарезервированное имя enable

enable — зарезервированное имя для жизненного цикла модуля (активен или спит). Поддержка enable не обязательна и решается для каждого модуля отдельно — единой команды «для всех модулей» нет, каждый модуль сам регистрирует то, что ему нужно. Если модуль реализует enable, он использует именно это имя внутри обычной пары event/action, а не отдельную ветку топиков:

<dev>/<модуль>_<слот>/action/enable    1   — команда: проснись
<dev>/<модуль>_<слот>/action/enable    0   — команда: усни
<dev>/<модуль>_<слот>/event/enable     1   — рапорт: я активен
<dev>/<модуль>_<слот>/event/enable     0   — рапорт: я сплю

Команда и рапорт независимы — модуль выбирает нужную комбинацию:

Случайaction/enableevent/enableКогда
нет жизненного цикламодулю нечего усыплять (разовый пускатель, чистый вход)
команда и рапортдадамиром управляем и сообщаем своё состояние
только командадамодулем управляют, но статус наружу не нужен
только рапортдамодуль сам решает спать или работать и лишь сообщает

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

Флаг конфигурации disableOnStart (для модулей с командой enable) оставляет модуль спящим до явной action/enable со значением 1; по умолчанию модуль активен на старте.

Сценарий «crossLink разбудил модуль — мир должен узнать»: приходит action/enable со значением 1, модуль просыпается и публикует event/enable со значением 1; подписчик на <dev>/+/event/enable видит, с кем можно работать.

Правила именования

deviceName

Используется и в MQTT-топике, и в mDNS (имя хоста), поэтому ограничен жёстче:

  • разрешены строчные латинские буквы, цифры и дефис -;
  • запрещены подчёркивание _, точка, пробел, спецсимволы;
  • примеры: hall-panel, mb1, stage-left.

Подчёркивание запрещено только в deviceName (из-за mDNS). В номерах модулей _ — обычный разделитель, в mDNS он не попадает.

модуль_слот

Генерируется прошивкой, пользователь не задаёт вручную:

  • <имяМодуля> + _ + <номерСлота>;
  • имя модуля в стиле camelCase, как в манифесте;
  • родственные модули носят одно имя в топике ради преемственности — например mp3Player и wavPlayer оба публикуются как player, а все датчики расстояния — как distanceSens.

имя события или действия

  • короткий глагол или существительное в camelCase: press, longPress, setVal, play;
  • без пунктуации, скобок и спецсимволов;
  • одно и то же явление называется одинаково во всех модулях — см. словарь ниже.

Канонический словарь имён

Чтобы родственные модули не плодили синонимы (press / pressed / btn), новые компоненты по возможности берут имена отсюда. Список расширяется по мере надобности, существующие имена не переименовываются без причины.

Словарь рекомендательный, не жёсткий. Для конкретной измеряемой величины модуль вправе использовать описательное имя вместо общего val (например distance, angle, frequency), если так понятнее. val — выбор по умолчанию, когда специфичного имени нет.

Общие (любой модуль)

ИмяНаправлениеТипСмысл
enableevent + actionboolАктивен или спит

Кнопки и ввод

ИмяНаправлениеТипСмысл
presseventboolНажатие (1) или отпускание (0)
longPresseventboolДолгое нажатие
clickeventboolОдиночный клик
doubleClickeventboolДвойной клик

Значения и датчики

ИмяНаправлениеТипСмысл
valeventint/floatТекущее значение
setValactionint/floatЗадать значение
thresholdeventboolПорог пройден

Свет и индикация

ИмяНаправлениеТипСмысл
setRGBactionrgbЦвет подсветки
setMaxBrightactionintМаксимальная яркость
setMinBrightactionintМинимальная яркость

Воспроизведение

ИмяНаправлениеТипСмысл
playactionintИграть трек номер N
stopactionboolОстановить
setVolumeactionintГромкость
endOfTrackeventbool/intТрек закончился

Note

Таблицы выше — стартовый словарь канонических имён, а не полный перечень. Точный набор событий и команд каждого модуля в конкретной прошивке смотрите на странице модуля либо в manifest.json.

Что НЕ входит в схему

  • Телеметрия не образует отдельной ветки. Периодический рапорт идёт в тот же event/<имя>, что и рапорт по изменению. Периодичность — свойство модуля (periodic, refreshRate, statusPeriod), а не отдельный топик.
  • Конфигурация не хранится в MQTT. Параметры модуля (volume, inverse, debounceGap и прочие) задаются в config.ini, а не топиками. MQTT — это рантайм-обмен событиями и командами, не база настроек.

Сводка одной картинкой

hall-panel/button_2/event/press          1            кнопку нажали
hall-panel/button_2/event/longPress      1            держат долго
hall-panel/button_2/event/enable         1            модуль активен
hall-panel/led_2/action/setRGB           0 128 255    зажги синим
hall-panel/led_2/action/setMaxBright     200          яркость 200
hall-panel/led_2/action/enable           0            усни

hall-panel/player_0/event/endOfTrack     5            трек 5 кончился
hall-panel/player_0/action/play          5            играй трек 5
hall-panel/player_0/action/setVolume     70           громкость 70

hall-panel/led_3/action/setMode          flash        режим подсветки (строка)

hall-panel/in_3/event/val                1            вход активен
hall-panel/out_3/action/setVal           0            выключи выход

hall-panel/pwmLeds_2/event/enable            1            модуль активен
hall-panel/pwmLeds_2/action/setRGB           255 128 0    установить цвет (R G B)
hall-panel/pwmLeds_2/action/ch_0/setBright   128          яркость канала 0
hall-panel/pwmLeds_2/action/ch_1/setBright   200          яркость канала 1
hall-panel/pwmLeds_2/action/ch_2/setBright   64           яркость канала 2

Note

ch_0/setBright — пример многосегментного имени: канал указан как префикс, действие — как суффикс. Парсер читает первые три уровня по позиции (deviceName / модуль_слот / направление), остальное — имя целиком.

Смотрите также