diff --git a/family/how-to/zont-config-compiler.md b/family/how-to/zont-config-compiler.md index 19562e8f..865fcd2f 100644 --- a/family/how-to/zont-config-compiler.md +++ b/family/how-to/zont-config-compiler.md @@ -9,6 +9,7 @@ created: '2026-09-17' namespace: family related: - '[[family/tech/zont-config-object-types]]' + - '[[family/tech/zont-scenario-logic-11109]]' - '[[family/how-to/home-automation]]' - '[[family/how-to/gitea-config]]' tags: @@ -19,7 +20,7 @@ tags: - homeautomation title: ⚙️ ZONT Config Compiler — конвертеры .txt ⇄ .yml type: how-to -updated: '2026-09-17c' +updated: '2026-09-17d' --- # ⚙️ ZONT Config Compiler — конвертеры `.txt ⇄ .yml` @@ -144,6 +145,7 @@ grep -c '^#Z' /tmp/zont_new.txt `1, 3, 4, 5, 6, 7, 9, 10, 11, 14, 16, 20, 24, 25, 27, 28, 42, 46, 49, 51, 52, 53, 57` ➕ дополнительно обрабатываются **`0`** (дискретные датчики — индикаторы состояния реле) и **`36`** (их вложенные конфиги). +❌ **НЕ обрабатывается `45`** (задержка-объект) — см. §5, п. 13. Полная таблица с полями — [[family/tech/zont-config-object-types]]. --- @@ -182,6 +184,45 @@ grep -c '^#Z' A.txt B.txt # счётчик объектов | 8 | Загрузка конфига в контроллер — **руками**, скрипты только конвертируют | Конвертер не имеет доступа к ZONT | | 9 | `INFRASTRUCTURE.md`, `docker-compose.yml`, `docker run.txt` в проекте — **исторический TrueNAS-стек** | Актуальный контур — [[family/how-to/home-automation]]. Не искать `modbus-bridge`/`mbusd` на NAS | | 10 | Дополнительных зависимостей нет | Только `pyyaml` — `jsonschema`/`ruamel` не нужны | +| 11 | 🔴 **Сценарий с >1 шагом → exit 2** | `config-to-yml.py:473` `require(len(steps) == 1)` жёстко. Обход: нет — нужна правка кода | +| 12 | 🔴 **Шаг с >1 действием → exit 2** | `config-to-yml.py:489` `require(len(actions) == 1)`. Обход: нет | +| 13 | 🔴 **Тип 45 (задержка, мс) не поддержан вообще** | Нет парсера в `config-to-yml.py`, нет эмиттера в `yml-to-config.py`. Объект молча теряется при round-trip | +| 14 | ⚠️ `>` в шелле затирает `.yml` до старта питона | Проверять exit-код до переноса файла в репо | + +### Ограничения конвертера, требующие доработки (найдено 2026-09-17) + +Прогон боевого конфига `config_0FA7C33CC89F_…_2026-09-17_12-12-28.txt` (598 `#Z`, 25 `#S`) вскрыл **4 дырки** в сценарной логике — все четыре независимы, падает на первой же: + +| # | Чего нет | Где в коде | Что теряется | Масштаб в конфиге | +|---|---|---|---|---| +| 1 | 2-й и последующие шаги сценария | `config-to-yml.py:473` (только 1 шаг); `yml-to-config.py:314` — `[step_id]` захардкожен, `:328` — пишет один шаг | шаг `11828` сценария `11109` | 1 сценарий из 65 | +| 2 | Тип **45** — задержка в мс, `[45, ms]` | нет ни в одном скрипте | 4 объекта: `11824`=20000, `11825`=60000, `11826`=0, `11828`=0 | 4 объекта | +| 3 | Несколько действий в одном шаге | `config-to-yml.py:489` (`len(actions)==1`) | шаг `11827` содержит **7** действий | 1 шаг из 65 | +| 4 | — (информационно) сценарий выключен | `enabled` = поле v[5] сценария | `#Z11109` — `enabled=0` | 1 сценарий | + +> ✅ Остальные 64 сценария — каноническая одношаговая форма `11 → [46] → 49`, конвертер их разбирает корректно. Все 65 условий (49) имеют ровно 4 поля `[49, relay, op, value]`, `op=1` = equals у всех. Все 64 «простых» шага — ровно 5 полей `[46, prio, cond, [1 действие], []]`. + +**Тип 45 vs `delay_ms` у типа 5 — это разные вещи:** +- `delay_ms` живёт **внутри** объекта-действия типа 5 (поле 4) — уже поддержан обоими скриптами. +- Тип **45** — **самостоятельный объект-задержка** в списке действий шага. Восстановленный формат: `[45, <миллисекунды>]`, 2 поля. Проверено на 4 объектах, больше в конфиге не встречается. + +--- + +## 5a. План доработки сценариев (согласован 2026-09-17, ожидает апрува) + +**Этап 1 — только конвертеры, конфиг не трогать.** +1. Бэкап обоих скриптов: `cp config-to-yml.py yml-to-config.py /tmp/zont-backup-<дата>/` +2. `config-to-yml.py`: снять `len(steps)==1` → список шагов; снять `len(actions)==1` → список действий; добавить парсер type 45 в новую секцию `delays`. +3. `yml-to-config.py`: эмитить все шаги `v[2]` (не один), все действия; добавить эмиттер type 45. +4. Проверка round-trip: `TXT → YAML → TXT` на боевом конфиге, 598 объектов, `diff` чистый (см. §4). + +**Стоп-точка:** показать Alex профиль YAML по `11109` перед правкой логики. + +**Этап 2 — правка YAML** (только после ответа на вопрос: (а) просто `enabled: true` / (б) добавить триггер по событию / (в) другое). + +**Этап 3 — `YAML → TXT`, сверка счётчиков, коммит ДО → Alex заливает руками → Alex проверяет руками → коммит ПОСЛЕ.** + +> 🔴 Порядок работ с боевыми конфигами: **коммит ДО → правка → заливка → ПРОВЕРКА АЛЕКСОМ руками → коммит ПОСЛЕ**. Мой `read back` = «конфиг записался», НЕ «работает». --- @@ -196,9 +237,19 @@ grep -c '^#Z' A.txt B.txt # счётчик объектов | `zont_config/H2000_PRO_config_actual-4.txt` / `-4.yml` | то же | | `zont_config/archive/` | не добавлена в git | | `zont_config/config_0FA7C33CC89F_…_2026-09-17_12-12-28.txt` | 32 689 байт — свежеснятый конфиг с контроллера, не закоммичен | -| одноимённый `.yml` | **0 байт** — конвертация запускалась и не завершилась | +| одноимённый `.yml` | **0 байт** — см. причину ниже (не «недоделанная конвертация», а падение на 1 объекте) | -> 🔴 **Пустой `.yml` (0 байт) рядом с непустым `.txt`** — признак незавершённой конвертации. Пересобрать шагом 2 из §3 перед использованием. +> 🔴 **Причина пустого `.yml` (0 байт) — найдена 2026-09-17.** `config-to-yml.py` падает с exit 2 на **первом** невыразимом объекте и не пишет ничего: +> +> ``` +> $ python3 config-to-yml.py zont_config/config_0FA7C33CC89F_…_2026-09-17_12-12-28.txt > /tmp/zont.yml +> Ошибка: Сценарий 11109: поддерживается только 1 шаг +> EXIT=2 → /tmp/zont.yml = 0 байт +> ``` +> +> Проверка: `.yml` 0 байт **всегда** означает, что конвертер не «не доехал», а **упал на конкретном объекте**. Смотреть stderr, а не перезапускать вслепую. +> +> ⚠️ `>` в шелле **затирает целевой файл ещё до старта питона** — поэтому рядом с непустым `.txt` появляется пустой `.yml`. Писать через `>/tmp/out.yml` и только после успешного exit-кода переносить в репо. **Содержимое проекта, не относящееся к конвертерам:** @@ -214,6 +265,7 @@ grep -c '^#Z' A.txt B.txt # счётчик объектов ## 7. Связанные заметки - [[family/tech/zont-config-object-types]] — таблица типов объектов (0, 1…57, 36) и `#S`-настройки +- [[family/tech/zont-scenario-logic-11109]] — разобранная логика сценария «Передёрнуть Автомат Котельной» - [[family/how-to/home-automation]] — контур автоматизации, ZONT, Modbus slave ID и регистры (§6) - [[family/how-to/gitea-config]] — Gitea: креды, создание репо, питфоллы - [[family/how-to/ha-automations]] — автоматизации HA diff --git a/family/tech/zont-config-object-types.md b/family/tech/zont-config-object-types.md index fb5314e0..c32d3246 100644 --- a/family/tech/zont-config-object-types.md +++ b/family/tech/zont-config-object-types.md @@ -52,7 +52,8 @@ updated: '2026-09-17b' | 28 | Таблицы сопротивлений | *(raw)* | `resistance_tables` | | **36** | Конфиги дискретных датчиков (вытащены из вложенной структуры типа 0) | `raw` | вложено в `discrete_sensors[].config` | | 42 | GUI-вкладки | `name` | `gui_tabs` | -| 46 | Шаги сценариев | *(raw; помечаются как уже разобранные)* | внутри `scenarios` | +| **45** | 🔴 **Задержка-объект (пауза в мс) в списке действий шага** — `[45, ms]`. **Конвертером НЕ поддержан** | *ничего — объекта нет в YAML* | **нет секции** — теряется | +| 46 | Шаги сценариев | `[46, prio, cond_id, [action_ids], []]` — 5 полей | внутри `scenarios` | | 49 | Условия сценариев | *(raw; помечаются как уже разобранные)* | внутри `scenarios` | | 51 | Modbus-устройства | `slave_id`, `name`, `poll_interval`, `timeout`, `registers`, `raw_params` | `modbus_devices` | | 52 | Modbus-регистры | `name`, `register`, `bit_width`, `repeat_period`, `num_vars`, `raw_params` | **вложены в своё устройство 51** | @@ -87,10 +88,21 @@ Modbus-регистры (тип 52) в конфиге — **отдельные ⚠️ Если регистр ссылается на устройство, которого нет — `config-to-yml.py` предупреждает в stderr (`WARNING: … references non-existent …`), но не падает. Аналогично для аналоговых выходов (53). -### 2.3. Сценарии (11 + 46 + 49) +### 2.3. Сценарии (11 + 46 + 49 + 45) Тип 11 парсится **целиком** — `when` (условия) и `do` (действия) собираются в человекочитаемый вид, включая шаги (46) и условия (49). Сами 46/49 при разборе помечаются как «уже вложенные» — в YAML отдельными секциями их нет. +Полная структура, формат полей и разобранный боевой кейс — [[family/tech/zont-scenario-logic-11109]]. + +🔴 **Жёсткие лимиты конвертера (найдено 2026-09-17)** — падение с exit 2 на первом же невыразимом объекте: +- `config-to-yml.py:473` — сценарий ровно с **1 шагом** (`len(steps) == 1`). 2-й шаг = падение. +- `config-to-yml.py:489` — шаг ровно с **1 действием** (`len(actions) == 1`). 2+ действий = падение. +- Тип **45** не обрабатывается вообще → объект молча теряется при round-trip. + +**Действие в шаге может быть объектом трёх типов:** `5` (действие над выходом, 11 полей), `9` (команда реле, 4 поля, `value` — **строка** `'1'`/`'0'`), `45` (пауза в мс, 2 поля). + +> ⚠️ **Тип 45 ≠ `delay_ms` типа 5.** `delay_ms` (поле 4 типа 5) — задержка внутри действия. Тип 45 — отдельный объект-пауза между действиями. + ### 2.4. `*`-маркеры Специальные записи вида `#Z=*` — «пустой» / унаследованный объект. Обрабатываются отдельным блоком; в YAML сохраняются как маркер. @@ -116,5 +128,6 @@ Modbus-регистры (тип 52) в конфиге — **отдельные ## 3. Связанные заметки - [[family/how-to/zont-config-compiler]] — как пользоваться конвертерами, питфоллы, обход +- [[family/tech/zont-scenario-logic-11109]] — структура сценариев 11/46/49/45, разбор «Передёрнуть Автомат Котельной» - [[family/how-to/home-automation]] §6 — карта slave ID, регистры AT2/реле/заслонок в HA - [[family/tech/t610-hang-investigation]] — расследование зависаний хоста (не связано напрямую, но тот же контур) diff --git a/family/tech/zont-scenario-logic-11109.md b/family/tech/zont-scenario-logic-11109.md new file mode 100644 index 00000000..9f9b2a0d --- /dev/null +++ b/family/tech/zont-scenario-logic-11109.md @@ -0,0 +1,142 @@ +--- +aliases: + - ZONT сценарий 11109 + - Передернуть Автомат Котельной + - ZONT тип 45 задержка + - ZONT сценарная логика +created: '2026-09-17' +namespace: family +related: + - '[[family/how-to/zont-config-compiler]]' + - '[[family/tech/zont-config-object-types]]' + - '[[family/how-to/home-automation]]' +tags: + - family + - tech + - zont + - modbus + - homeautomation +title: 🔁 ZONT — сценарная логика (типы 11 / 46 / 49 / 45) +type: tech +updated: '2026-09-17' +--- + +# 🔁 ZONT — сценарная логика (типы 11 / 46 / 49 / 45) + +Как устроены сценарии в конфиге ZONT и что именно разобрано в боевом конфиге +`config_0FA7C33CC89F_0FA7C33CC89F_2026-09-17_12-12-28.txt` (598 `#Z`, 25 `#S`, 65 сценариев). +Контекст конвертеров — [[family/how-to/zont-config-compiler]]. + +--- + +## 1. Структура сценария + +Сценарий — это **4 связанных типа объектов**: + +``` +#Z=11,'Имя',[<шаг>,<шаг>,…],0,0,,0,0 ← сценарий +#Z=46,,,[<действие>,…],[] ← шаг +#Z=49,,, ← условие +#Z=… ← действие (тип 5, 9 или 45) +``` + +| Тип | Роль | Формат | Поля | +|---|---|---|---| +| **11** | Сценарий | `[11, name, [step_ids], 0, 0, enabled, 0, 0]` | **8** полей. `enabled` — поле v[5] (0/1) | +| **46** | Шаг | `[46, prio, cond_id, [action_ids], []]` | **5** полей. `prio` и последнее поле — всегда 0/`[]` | +| **49** | Условие | `[49, relay_id, operator, value]` | **4** поля. `operator`: `1`=equals, иначе not_equals | +| **45** | Задержка | `[45, <миллисекунды>]` | **2** поля | + +**Каноническая форма** (99% конфига): 1 сценарий → 1 шаг → 1 условие → 1 действие. + +--- + +## 2. Действия в шаге — три разных типа + +Список действий шага (`46` поле 3) может содержать объекты **трёх** типов: + +| Тип | Что это | Формат | Декодирование | +|---|---|---|---| +| **5** | Действие над выходом контроллера | `[5, name, output_ref, 1, delay, impulse_dur, [], sched_bmp, sched_time, impulse_period, value]` | 11 полей. `output_ref >> 4` = id выхода; `delay` — поле 4 (мс) | +| **9** | Команда реле | `[9, name, target_relay, '1'/'0']` | 4 поля. `value` — **строка** `'1'`/`'0'`, не число | +| **45** | Пауза между действиями | `[45, ms]` | 2 поля | + +> ⚠️ **Тип 45 ≠ `delay_ms` типа 5.** `delay_ms` — задержка **внутри** действия перед его выполнением. +> Тип 45 — **отдельный объект-пауза** в последовательности. Их часто путают при чтении конфига. + +--- + +## 3. Разобранный кейс: `#Z11109` «Передернуть Автомат Котельной» + +**Единственный сценарий в конфиге с нестандартной формой** — 2 шага и 7 действий в одном шаге. + +``` +#Z11109=11,'Передернуть Автомат Котельной',[11827,11828],0,0,0,0,0 +#Z11823=49,11190,1,0 ← условие +#Z11827=46,0,11823,[11191,11030,11824,11029,11825,11192,11826],[] +#Z11828=45,0 ← шаг 2 +#Z11824=45,20000 #Z11825=45,60000 #Z11826=45,0 +#Z11029=9,'Включить реле «20/1 Автомат Котельная»',11028,'1' +#Z11030=9,'Выключить реле «20/1 Автомат Котельная»',11028,'0' +#Z11191=9,'Включить реле «virt. Запретить передергивание»',11190,'1' +#Z11192=9,'Выключить реле «virt. Запретить передергивание»',11190,'0' +#Z11028=14,'20/1 Автомат Котельная',175728,0 +#Z11190=14,'virt. Запретить передергивание',179904,0 +``` + +### Что происходит по шагам + +**Условие:** `relay 11190 ('virt. Запретить передергивание') == 0` — т.е. передёргивание **не** запрещено. + +**Шаг 1 (`11827`) — 7 действий подряд:** + +| # | Объект | Действие | Пауза после | +|---|---|---|---| +| 1 | `11191` (type 9) | включить `virt. Запретить передергивание` | — | +| 2 | `11030` (type 9) | **выключить** `20/1 Автомат Котельная` | — | +| 3 | `11824` (type 45) | пауза | **20 000 мс** | +| 4 | `11029` (type 9) | **включить** `20/1 Автомат Котельная` | — | +| 5 | `11825` (type 45) | пауза | **60 000 мс** | +| 6 | `11192` (type 9) | выключить `virt. Запретить передергивание` | — | +| 7 | `11826` (type 45) | пауза | 0 | + +**Шаг 2 (`11828`)** — `[45, 0]`, пустая пауза-заглушка. Оставлен планировщиком ZONT, функциональной нагрузки не несёт. + +### Смысл логики + +Это **защита от повторного передёргивания**: +1. Виртуальное реле `virt. Запретить передергивание` (id `11190`) ставится в 1 **первым** действием. +2. Условие сценария (`11823`) требует `== 0` → пока реле в 1, сценарий повторно **не запустится**. +3. Снимается реле только **после** 20 с + 60 с пауз (действие 6), т.е. через 80 секунд после старта → минимальный интервал между передёргиваниями автомата = 80 с. + +### 🔴 Проблема + +`#Z11109` поле v[5] = **`0`** → **сценарий выключен в контроллере**. Защита и сама функция передёргивания не работают. + +--- + +## 4. Полные счётчики по конфигу (для сверки после правок) + +| Тип | Кол-во | Комментарий | +|---|---|---| +| 11 / 46 | 65 / 65 | все одношаговые, кроме `11109` | +| 49 | 65 | все ровно 4 поля, `op=1` (equals) у всех | +| 45 | 4 | `11824`, `11825`, `11826`, `11828` — только в `11109` | +| 9 | 42 | 21 пара ВКЛ/ВЫКЛ, `value` — строка `'1'`/`'0'` | +| 5 | 66 | действия над выходами | +| 14 | 40 | реле | +| 10 | 22 | GUI-переключатели | +| 0 / 36 | 13 / 13 | дискретные датчики + вложенные конфиги | +| 52 / 51 / 53 | 93 / 11 / 64 | Modbus-регистры / устройства / ещё один слой | +| 16 / 20 | 10 / 1 | контуры и режимы отопления | +| **Всего `#Z`** | **598** | | + +> Проверка после любой правки: `grep -c '^#Z' <файл>` должен дать **598**. + +--- + +## 5. Связанные заметки + +- [[family/how-to/zont-config-compiler]] — конвертеры `.txt ⇄ .yml`, план доработки под 2 шага и тип 45 +- [[family/tech/zont-config-object-types]] — полная таблица типов объектов и `#S`-настройки +- [[family/how-to/home-automation]] — контур автоматизации, ZONT, Modbus slave ID и регистры