Конституция — свод незыблемых правил, по которым контроллер moduleBox общается с внешним миром через UART, UDP, OSC и MQTT. Правила одинаковы для всех модулей и не меняются без веской причины: на них опираются прошивка, конфигуратор mbApp и сторонние интеграции.
Актуальный набор модулей и их событий и команд для конкретной прошивки берётся
из сгенерированного manifest.json — он и есть живой реестр возможностей.
Код обязан соответствовать конституции; отдельной рукописной таблицы по модулям
нет, чтобы исключить расхождения.
Идея в одном абзаце
Контроллер состоит из модулей. Каждый модуль либо что-то сообщает миру
(нажали кнопку, кончился трек, изменилось значение датчика), либо принимает
команды (зажги лампу, играй трек, усни). Первое — event, второе — action.
Больше направлений нет. Та же пара event/action используется и для внутренних
связей между модулями (crossLink), и для связи
с внешним брокером — язык один.
Структура топика
<deviceName>/<модуль>_<слот>/<направление>/<имя>
| Часть | Что это | Пример |
|---|---|---|
deviceName | Имя устройства, задаёт пользователь | hall-panel |
модуль | Имя модуля, одинаково для родственных | button |
слот | Номер слота, отделён _ | 2 |
направление | event или action | event |
имя | Что именно произошло или что сделать | 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.
| Тип | Формат | Пример |
|---|---|---|
| bool | 0 / 1 | 1 |
| 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/enable | event/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 — выбор по умолчанию, когда
специфичного имени нет.
Общие (любой модуль)
| Имя | Направление | Тип | Смысл |
|---|---|---|---|
enable | event + action | bool | Активен или спит |
Кнопки и ввод
| Имя | Направление | Тип | Смысл |
|---|---|---|---|
press | event | bool | Нажатие (1) или отпускание (0) |
longPress | event | bool | Долгое нажатие |
click | event | bool | Одиночный клик |
doubleClick | event | bool | Двойной клик |
Значения и датчики
| Имя | Направление | Тип | Смысл |
|---|---|---|---|
val | event | int/float | Текущее значение |
setVal | action | int/float | Задать значение |
threshold | event | bool | Порог пройден |
Свет и индикация
| Имя | Направление | Тип | Смысл |
|---|---|---|---|
setRGB | action | rgb | Цвет подсветки |
setMaxBright | action | int | Максимальная яркость |
setMinBright | action | int | Минимальная яркость |
Воспроизведение
| Имя | Направление | Тип | Смысл |
|---|---|---|---|
play | action | int | Играть трек номер N |
stop | action | bool | Остановить |
setVolume | action | int | Громкость |
endOfTrack | event | bool/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/модуль_слот/ направление), остальное — имя целиком.
Смотрите также
- Внутренние связи (crossLink) — тот же язык внутри устройства
- Системные команды — команды устройства вне слотов
- Настройки — структура
config.ini