# LightHub и шина CAN > Источник: авторский документ «Lighthub и шина CAN» (docx, 2026-10-02), сверен с кодом `lighthub/candriver.cpp/h`. > CAN-поддержка в прошивке появилась в **v4.4.0**. ## Что такое CAN шина CAN-шины очень широко используются в промышленной и автомобильной автоматике как дешевый, но надежный транспорт для взаимодействия модулей и блоков автоматики между собой. Такие шины есть, фактически, в каждом современном автомобиле. В прошивке LightHub используется фиксированная скорость **50 kbit/s** (`candriver.cpp`: `STMCan.setBaudRate(50000)` / `CAN.begin(50000)` / `Can0.begin(CAN_BPS_50K)`), что обеспечивает длину шины до нескольких сотен метров — достаточно для большинства домовладений. Поддержка CAN встроена во многие современные (и не очень) микроконтроллеры. Из тех микроконтроллеров, на которых работает прошивка LightHub, встроенная поддержка используется в следующих чипах: - ARM SAM3E (Arduino DUE) — библиотека `due_can` - ESP32 — библиотека `arduino-CAN` (пины: GPIO 35 — RX, GPIO 5 — TX) - STM32 — библиотека `STM32_CAN` > Подключение внешнего CAN-контроллера по SPI для чипов без встроенной поддержки **не реализовано** в текущем коде (`candriver.cpp` использует только встроенные контроллеры). ## Какие возможности появляются у LightHub Теперь нет необходимости организовывать подключение локальной сети (или WiFi) к каждому устройству. Необходим минимум один контроллер (лучше пара), который подключен одновременно и к локальной сети, и к шине CAN. Он будет выполнять роль шлюза и держателя настроек периферийных контроллеров. Периферийные устройства могут подключаться только к электропитанию и двухпроводной шине CAN. А это значит, что устройств может стать кратно больше, можно использовать очень простые, небольшие и дешевые устройства и, в пределе, размещать их в любом удобном месте. Например, в подрозетниках, выключателях, кондиционерах, датчиках движения. При всем прочем, даже такие упрощенные устройства умеют почти то же самое, что их «старшие братья»: - тот же формат JSON-файла настройки позволяет организовывать как локальное, так и удаленное управление устройством; - малое устройство может иметь на борту термостаты, возможность подключения термодатчиков и прочих сенсоров, PID-регуляторы, UART для управления кондиционером или для Modbus; - к таким устройствам можно подключать элементы управления: кнопки, переключатели, энкодеры (элемент с вращающейся ручкой), герконы дверей и датчики движения/присутствия; - они также поддерживают все возможности по определению одинарных-двойных-тройных-длительных нажатий кнопок, как и все LightHub. Такая архитектура позволяет еще более децентрализовать управление умным домом: каждый маленький автономный контроллер (расположенный даже в выключателе) способен решить задачи простой автоматизации и локального управления даже в том случае, если часть системы вышла из строя. Кроме того, CAN-шина позволяет таким простым устройствам напрямую общаться между собой, например: - для реализации сценариев переключения сцен освещения, проходных выключателей; - для передачи измерений сенсоров на удаленные контроллеры (например, измерения влажности помещений на контроллер форсуночного увлажнения, значения CO2 в помещениях на систему вентиляции). Причем такое взаимодействие теперь может происходить без посредничества локальной сети и MQTT-брокера, что еще более увеличивает надежность и живучесть системы в целом. ### Примеры применения контроллеров, подключенных только по шине CAN (далее — lightspot) - Автономный управляемый термостат теплого пола - Автономное, управляемое локальным выключателем реле или диммер света (AC или RGB) - Датчик движения, локально и удаленно управляющий светом, с сенсорами температуры, влажности, CO2 на борту - Многоклавишный многофункциональный выключатель с сенсорами температуры-влажности, энкодером - Удаленные счетчики воды-газа-электричества - Управляемые клапаны вентиляции - Удаленные ультразвуковые датчики приближения для управления подсветкой ступеней ## Как организована передача данных по шине CAN Таким образом, каждое устройство в произвольный момент времени может инициировать передачу кадра данных размером до 8 байт, и этот кадр будет принят сразу всеми подключенными к шине устройствами. ### Формат идентификатора кадра Идентификатор кадра (до 32 бит, `canid_t` в `candriver.h`): | Поле | Биты | Назначение | |--|--|--| | reserve | 3 | Должно быть 0 | | status | 1 | 1 — статус, 0 — запрос | | payloadType | 4 | Тип передаваемых данных | | deviceId | 8 | devID устройства (1..255) | | itemId | 10 | 0..1023 (или sequence # для длинных кадров) | | subItemId | 6 | 0..62 (63 — субайтем не задан) | ### Типы полезной нагрузки (payloadType) | Значение | Имя | Назначение | |--|--|--| | 1 | `itemCommand` | Команда или статус для/от того или иного item | | 2 | `lookupMAC` | Запрос devID по MAC-адресу устройства (в ответе передается devID) | | 3 | `configFrame` | Кадр передачи конфигурации (JSON, частями) | | 4 | `OTAFrame` | Кадр передачи прошивки по CAN | | 5 | `auth` | Аутентификация | | 6 | `metric` | Метрики (см. metricType) | | 7 | `sysCmd` | Системные команды (см. commandType) | | 8 | `rawPinCtrl` | Прямое управление пинами | ### Формат данных (datagram\_t) ```c enum metricType { MAC=1, IP=2, NetMask=3, GW=4, DNS=5, UpTime=6, Salt=7 }; typedef union { uint8_t data[8]; char payload[8]; struct { itemCmdStore cmd; // команда itemArgStore param; // аргумент команды }; struct { macAddress mac; // MAC-адрес uint16_t currentConfCRC; // CRC текущей конфигурации }; struct { uint8_t sysCmd; uint8_t sysCmdData[7]; }; struct { uint32_t metric1; uint32_t metric2; }; } datagram_t; ``` Системные команды (sysCmd, `commandType`): | Значение | Команда | |--|--| | 1 | `reboot` — перезагрузка контроллера | | 2 | `get` — получить информацию | | 3 | `save` — сохранить конфигурацию | | 4 | `load` — загрузить конфигурацию | ## Процедура инициализации устройства и загрузки конфигурации 1. **Вычисление MAC-адреса.** Этот адрес является уникальным идентификатором устройства, даже если у него отсутствует сетевой интерфейс и имеется в наличии только CAN. MAC-адрес вычисляется из уникального серийного номера чипа для ARM-базированных устройств, для AVR считывается из EEPROM, для ESP используется MAC-адрес интерфейса WiFi. 2. Устройство отправляет запрос в CAN-шину, установив `payloadType = lookupMAC (2)` в пакете и передав 6 байт MAC-адреса. 3. Мастер-контроллер, содержащий конфигурацию устройства внутри своего файла настроек, формирует ответный пакет нулевой длины с установленным битом `status` в id и заполненным полем `deviceId`. С этого момента устройство знает свой devID. 4. Устройство отправляет запрос в CAN-шину, установив `payloadType = configFrame (3)` и полученный на предыдущем этапе devID. В качестве sequence # для первого пакета используется значение 0xFFFF (-1), запрос каждого последующего пакета осуществляется с увеличением sequence # на единицу. В ответ на каждый запрос устройство получает кадр данных; последовательность данных содержит JSON-конфигурацию. ### Пример конфигурации CAN внутри конфига мастер-устройства ```json "can": { "addr": 14, "conf": { "DE:54:71:48:17:2E": { "can": { "addr": 21, "name": "olmexino" }, "items": { "relay1": [[6, 1], 1], "relay2": [[6, 2], 5], "relays": [["GROUP", 3], ["relay1", "relay2"]] }, "in": { "41": { "T": 2, "item": "relays", "can": [10, 2], "scmd": "TOGGLE", "rcmd": "" } } }, "DE:48:4E:03:B3:DF": { "can": { "addr": 22, "name": "sonar" }, "items": { "relay1": [[6, 1], 1] }, "in": [ { "T": 7, "#": [14, 15], "act": [ { "map": [0, 100], "scmd": { "can": [13, 32], "icmd": "XON 10000" } }, { "map": [0, 200], "scmd": { "can": [13, 31], "icmd": "XON 15000" } } ] } ] } } } ``` `can.addr` — devID этого контроллера. `can.conf` — объект «MAC-адрес → конфигурация периферийного контроллера»; каждая периферия содержит собственный `can` (devID и имя) и обычные секции `items`/`in`. ## Способ настройки взаимодействия контроллеров с использованием шины CAN В процессе работы контроллеры имеют возможность отправки на один или несколько других контроллеров, подключенных по шине CAN, следующего набора пакетов: | Тип управляющего воздействия | Числовое значение суффикса | Суффикс (символьное значение) | |--|--:|--| | Команды для управления удаленными устройствами | 1 | `cmd` | | Уставки для удаленного устройства | 2 | `set` | | Текущие значения сенсоров | 3 | `val` | | Отложенная команда | 4 | `del` | | Цвет в нотации HSV | 5 | `hsv` | | Цвет в нотации RGB | 6 | `rgb` | | Интенсивность вентиляции | 7 | `fan` | | Режим работы климатической установки | 8 | `mode` | | Вспомогательная команда (FREEZE / UNFREEZE / ENABLE / DISABLE) | 9 | `ctrl` | | Цвет (hue) | 10 | `hue` | | Насыщенность цвета | 11 | `sat` | | Цветовая температура | 12 | `temp` | ### Адресация объекта назначения (item) Для адресации объекта назначения (item), который обработает соответствующую команду в сети CAN, используется следующая нотация: ``` [ , , ] ``` - **DevID** — адрес устройства, определяется на этапе конфигурирования (см. выше). DevID = 0 адресует сообщение всем устройствам сети. - **ItemID** — числовой идентификатор объекта (item). Задается при настройке удаленного объекта в JSON-конфигурации того контроллера, к которому объект подключен: первый элемент массива настройки item должен быть массивом, в котором первый объект определяет тип объекта, а второй — требуемый ItemID. Пример: ```json "items": { "relay1": [[6, 1], 1], "relay2": [[6, 2], 5], "relays": [["GROUP", 3], ["relay1", "relay2"]] } ``` В примере выше для объекта `relay1` определяется itemID = 1, для объекта `relay2` — itemID = 2, а для группы `relays` — itemID = 3. В том случае, если ItemID пересекаются между контроллерами и пакет отправлен на широковещательный адрес 0, пакет будет выполнен сразу всеми контроллерами, в которых определен объект с данным ID. - **Suffix** — числовое или символьное значение, определяющее тип управляющего воздействия согласно таблице выше. Допустимо определять дополнительные числовые суффиксы, например, для управления теми регистрами устройства Modbus, которые не укладываются в таблицу выше. В этом случае при описании устройства Modbus можно задать параметр `"id": <значение>`, где значение — число в интервале 13-31, и этот параметр можно будет адресовать, задавая данное число в массиве `can` на третьей позиции. - **Subitem** — опциональный параметр, который может использоваться двояко: - если указана **цифра** — адресация суб-объекта, входящего в удаленный управляемый объект. Примеры объектов, которые имеют внутри перечень суб-объектов: MULTIVENT (многоканальная вентиляция/кондиционирование), HUM (многоканальный форсуночный увлажнитель), адресная светодиодная лента. Для адресации соответствующего суб-объекта используется порядковый номер, согласно которому данный суб-объект описан в JSON-конфигурации контроллера назначения; - если указана **строка** — делается попытка преобразовать данную строку в команду, и это значение передается удаленному устройству. Удаленное устройство исполнит пакет только в том случае, если текущее состояние устройства эквивалентно данной команде. Данная функция особо полезна для удаленных групп устройств: например, можно адресовать команды управления яркостью группе светильников, а исполнят их только светильники, находящиеся в состоянии «ON». ## Функция шлюза Мастер-контроллер, который хранит конфигурацию периферийного, также выполняет функцию шлюза между шиной CAN и интерфейсами MQTT и HTTP. Так как мастер-контроллер знает имя периферийного, при подключении к MQTT-брокеру он дополнительно подписывается на командный топик периферийного. Это позволяет управлять устройствами, подключенными через шину CAN, абсолютно прозрачно, с использованием стандартной нотации командных топиков `root/name/item/[subitem/]suffix`, например, через `myhome/sonar/relay1/cmd` для примера конфига выше. Когда удаленный периферийный контроллер выполнит команду (либо вследствие изменения внутреннего состояния устройства) — изменение его статуса транслируется в шину CAN. Мастер-контроллер, который владеет конфигом периферийного, транслирует такое изменение статуса в свой стандартный статусный топик, например, в `myhome/s_out/relay1/cmd`. ## Доступность в сборках (сверка с кодом, 2026-10-02) - Флаг `CANDRV` включен по умолчанию: **esp32-wifi, lighthub21, stm32-noip**; в **esp32c3-wifi** закомментирован (`build-flags/*`). - Скорость: 50 kbit/s, фиксированная (`candriver.cpp`). - ESP32: CAN на GPIO 35 (RX) / GPIO 5 (TX) (`candriver.cpp`). - Поддержка SPI-кан-контроллеров для чипов без встроенной CAN — **не реализована** (см. выше). ## Не реализовано Черновики из исходного документа, допущенные до релиза, но **не реализованные** в текущем коде: - вход `T:99` с профилями, обработчиками `goto`/`onenter` и сценарным переходом между профилями; - подключение CAN через внешний SPI-контроллер для чипов без встроенной поддержки. ## Связанные документы - [Rotary Encoder](../core/rotary_encoder.md) — энкодер как орган управления (в т.ч. на lightspot) - [Быстрая справка по MQTT](../core/mqtt_quick_reference.md) - [Справочник типов каналов](../core/channel_types_reference.md)