docs: add CAN (lightspot) and rotary encoder docs from author drafts

Ported the two design docs (originally docx) to markdown with code-verified
corrections (CAN runs at 50 kbit/s); sections still in design (T:99 rotary
profiles, external SPI CAN controller) are marked 'not implemented' and
tracked in BACKLOG.md.
This commit is contained in:
2026-10-03 00:41:20 +03:00
parent 724224a503
commit 693de4da42
2 changed files with 358 additions and 0 deletions
+119
View File
@@ -0,0 +1,119 @@
# Rotary Encoder
> Источник: авторский документ «Rotary Encoder» (docx, 2026-10-02), сверен с кодом `lighthub/inputs.cpp`.
Появилась возможность подключить к контроллеру орган управления, который называется Rotary encoder (далее — энкодер).
Энкодер упрощает управление такими устройствами, как диммируемое и светодиодное освещение, позволяя выбор яркости/цвета/насыщенности/цветовой температуры делать тактильно, вращением рукоятки регулятора. Одним энкодером можно управлять несколькими, как локальными, так и удаленными устройствами. Освещение здесь приведено в качестве самого применимого примера. Если хотите — данным элементом управления можно регулировать все, что поддерживает команды на увеличение и уменьшение. Например, через автоматизации Home Assistant можно управлять громкостью ресивера или колонки Алиса.
Многие энкодеры также имеют контакт нажатия, и данная возможность тоже может быть использована. Все варианты анализа одинарных-двойных-тройных-длительных нажатий могут быть использованы аналогично с настройкой дискретных входов контроллера и использоваться для любых нужд, в том числе для включения, выключения устройств, переключения профилей управления энкодера.
Все возможности доступны при настройке энкодера через JSON-конфигурацию.
Подключить энкодер можно к прошивке LightHub на всех платформах (включенных с флагом `ROTARYENCODER`, см. «Доступность» ниже). Особенно хочется подчеркнуть возможность подключить такой элемент (наряду с дополнительными кнопками и датчиками) к контроллеру LightSpot на базе STM32 или ESP32 — минималистической системе, которая может быть смонтирована в каждом выключателе и которая может общаться с основным контроллером LightHub по двухпроводной шине CAN (см. [CAN и lightspot](../integrations/can_lightspot.md)). Также можно собрать универсальный выключатель с кнопками и рукояткой энкодера на базе ESP32 или ESP8266, взаимодействующий с остальными системами дома через WiFi (как с контроллерами LightHub, так и с другими устройствами, управляемыми через MQTT), хотя вариант проводного подключения, конечно, предпочтителен.
## Настройка
Рассмотрим настройку энкодера на примерах.
В данном примере энкодер подключен к следующим PIN-ам контроллера:
- 14 — контакт нажатия;
- 4 и 5 — контакты A и B энкодера, соответственно.
Четвертый (опциональный) параметр массива `#` может задавать режим подключения энкодера. Имеет смысл пробовать менять значение в интервале 1-3, если значение по умолчанию (2) не работает корректно для какого-то отдельно взятого энкодера.
Параметр `T` соответствует значению **32** — это тип входа «rotary encoder».
Параметр `"+-"` определяет обработчик, вызываемый при вращении рукоятки энкодера по или против часовой стрелки. Обработчик аналогичен описанному в разделе «диммирование с использованием кнопок» ([button_presses.md](button_presses.md)). Но там пары параметров `icmd`/`irev` и `ecmd`/`erev` используются поочередно, а в случае энкодера первый параметр используется в случае вращения по часовой стрелке, а второй — против часовой.
Настройка в примере ниже переключает локальное устройство `dimmer` между состояниями ON и OFF (команда `toggle`) по однократному клику на энкодер (параметр `click`), а при вращении рукоятки по и против часовой стрелки увеличивает или уменьшает яркость локального устройства `dimmer` соответственно (команды `%+1` и `%-1`):
```json
{
"T": 32, "#": [14, 4, 5, 2],
"+-": { "item": "dimmer/set", "icmd": "%+1", "irev": "%-1" },
"click": { "item": "dimmer/cmd", "icmd": "toggle" }
}
```
Поворот по часовой и против часовой стрелки можно разнести на два отдельных обработчика, если вдруг это будет необходимо, чтобы управлять разными устройствами при вращении в разных направлениях. Следующее описание эквивалентно предыдущему:
```json
{
"T": 32, "#": [14, 4, 5],
"+": { "item": "dimmer/set", "icmd": "%+1" },
"-": { "item": "dimmer/set", "icmd": "%-1" },
"click": { "item": "dimmer/cmd", "icmd": "toggle" }
}
```
Теперь попробуем управлять удаленным устройством `dimmer2`, подключенным к контроллеру с именем `light` через MQTT:
```json
{
"T": 32, "#": [14, 4, 5],
"+-": { "emit": "myhome/light/dimmer2/set", "ecmd": "%+1", "erev": "%-1" },
"click": { "emit": "myhome/light/dimmer2/cmd", "ecmd": "toggle" }
}
```
И пример по управлению удаленным устройством с itemid = 31, настроенным на контроллере с адресом 13 по CAN-шине (см. [CAN и lightspot](../integrations/can_lightspot.md)):
```json
{
"T": 32, "#": [14, 4, 5],
"+-": { "can": [13, 31, "set"], "icmd": "%+1", "irev": "%-1" },
"click": { "can": [13, 31, "cmd"], "icmd": "toggle" }
}
```
### Профили (act)
Усложним задачу. Теперь попробуем управлять одним энкодером яркостью, цветом и насыщенностью светодиодной ленты. Для этого понадобится создать несколько профилей энкодера.
Профили можно задать в виде JSON-массива или JSON-объекта в параметре `act`. Массив и объект аналогичны: в первом случае для активации нужного профиля будет использоваться целое число, определяющее порядковый номер элемента в массиве, содержащего нужный профиль (начиная с 1, так как значение 0 зарезервировано для активации «корневого профиля», который может быть описан непосредственно в объекте входа, на одном уровне с параметрами `#`, `T` — аналогично предыдущим примерам). Во втором случае для активации можно пользоваться именем объекта (пустая строка активирует корневой профиль). Это, конечно, делает конфиг более читаемым, но чуть более ресурсоемко.
В примере ниже изначально активен корневой профиль, в котором осуществляется управление яркостью светодиодной ленты. Однократный клик (команда `activate` в обработчике события `click`) активирует профиль номер 1 — в котором управляется насыщенность цвета. Однократный клик из профиля 1 переводит энкодер в профиль 2, в котором можно настроить оттенок цвета. Ну и, соответственно, клик из профиля 2 активирует корневой профиль (0). В каждом профиле длительное нажатие включает или выключает `led`.
```json
{
"T": 32, "#": [14, 4, 5],
"+-": { "item": "led/set", "icmd": "%+1", "irev": "%-1" },
"lcmd": { "item": "led/cmd", "icmd": "toggle" },
"click": { "activate": 1 },
"act": [
{
"+-": { "item": "led/hue", "icmd": "%+1", "irev": "%-1" },
"lcmd": { "item": "led/cmd", "icmd": "toggle" },
"click": { "activate": 2 }
},
{
"+-": { "item": "led/sat", "icmd": "%+1", "irev": "%-1" },
"lcmd": { "item": "led/cmd", "icmd": "toggle" },
"click": { "activate": 0 }
}
]
}
```
NB: `activate` можно использовать в описании других входов контроллера — таким образом, например, нажатием других кнопок можно выбирать режим действия энкодера.
## Доступность (сверка с кодом, 2026-10-02)
- Тип входа `T:32` (`IN_RE`) работает при компиляции с флагом `ROTARYENCODER` (`inputs.cpp`).
- Флаг включен по умолчанию: **due, esp32-wifi, esp32c3-wifi, esp8266-wifi, lighthub21, nrf52840, stm32, stm32-noip** (`build-flags/*`).
- Массив `#`: `[контакт_нажатия, A, B, режим]`; режим по умолчанию — 2 (`inputs.cpp`, `setupRotaryEncoder`).
- `activate` поддерживает число (индекс профиля, 0 — корневой), строку (имя профиля) и массив `["имя_входа", <значение>]` — активация профиля во внешнем входе (`inputs.cpp`, `checkInstructions`).
## Не реализовано
Черновик из исходного документа, **не реализованный** в текущем коде:
- вход `T:99` с профилями и обработчиками `goto`/`onenter` (переходы между профилями по событиям, «сценарный» энкодер).
## Связанные документы
- [Нажатия кнопок](button_presses.md)
- [CAN и lightspot](../integrations/can_lightspot.md)
- [Справочник суффиксов](suffixes_reference.md)