From da8527f6a837a161fdb4941bfe88164f969351be Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Thu, 17 Sep 2026 12:45:05 +0600 Subject: [PATCH] [2026-09-17] eagle: family/how-to/zont-config-compiler.md --- family/how-to/zont-config-compiler.md | 93 +++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/family/how-to/zont-config-compiler.md b/family/how-to/zont-config-compiler.md index 435a8d92..9e4d4447 100644 --- a/family/how-to/zont-config-compiler.md +++ b/family/how-to/zont-config-compiler.md @@ -108,6 +108,99 @@ updated: '2026-09-17e' --- +## 2.1 Формат сценариев (type 11 / 45 / 46 / 49) — разобран 2026-09-17 + +🔴 **Ключевое открытие:** поле 2 сценария — это **не список шагов типа 46**, а последовательность +ссылок, куда попадают и **шаги (46)**, и **задержки (45)**. Проверено на 65 сценариях боевого конфига. + +``` +#Z=46,,[],[] +#Z=9,'<имя>',,'0|1' ← действие (тип 9) +#Z=45, ← задержка (тип 45) +#Z=49,,, ← условие (тип 49) +#Z=11,'<имя>',[…],0,0,,0,0 +``` + +| Поле | Значение | +|---|---| +| `11` поле 2 | список ссылок: шаги 46 **и** задержки 45 | +| `46` поле 2 | `[action_ids]` — действия 9 **и** задержки 45 внутри шага | +| `45` | пауза в **мс**; `45,0` = пауза 0 (заглушка) | +| `11` поле 6 | `1` = сценарий включён, `0` = выключен | +| `11` число полей | свежая прошивка — **8**, старая (`-2`) — **7** | + +**Пример — `#Z11109` «Передернуть Автомат Котельной»** (единственный многошаговый из 65): + +``` +#Z11109=11,'Передернуть Автомат Котельной',[11827,11828],0,0,0,0,0 ← 11828 = задержка-«хвост» +#Z11827=46,0,11823,[11191,11030,11824,11029,11825,11192,11826],[] ← 7 действий, 2 из них задержки +#Z11823=49,11190,1,0 ← virt.Запретить == 0 +#Z11824=45,20000 #Z11825=45,60000 #Z11826=45,0 #Z11828=45,0 +``` + +Читается как: *вкл `virt.Запретить` → выкл Автомат → пауза 20 с → вкл Автомат → пауза 60 с → +выкл `virt.Запретить` → пауза 0*. Поле 6 = `0` → **сценарий выключен**, защиты от повторного +передёргивания нет. + +### Как это выглядит в YAML + +Одношаговые сценарии (64 из 65) сохраняют плоский вид `when`/`then` — старые YAML не ломаются. +Многошаговые получают список `steps`, а хвостовые задержки — `extra_links`: + +```yaml +scenarios: + - id: 11109 + name: Передернуть Автомат Котельной + enabled: false + steps: + - id: 11827 + when: {id: 11823, relay_id: 11190, operator: equals, value: 0} + then: {actions: [11191, 11030, 11824, 11029, 11825, 11192, 11826]} + extra_links: [11828] +delays: + - {id: 11824, ms: 20000} + - {id: 11825, ms: 60000} + - {id: 11826, ms: 0} + - {id: 11828, ms: 0} +``` + +**Как дописывать логику:** задержки правятся в секции `delays` (поле `ms`), порядок срабатывания +задаётся порядком id в `actions` шага. Чтобы включить сценарий — `enabled: true`. + +--- + +## 2.2 Round-trip: все 4 конфига чистые + +Проверено `test_roundtrip.py` (новый скрипт в репо) — TXT → YAML → TXT, сравнение по множеству +строк с нормализацией кодировки: + +| Конфиг | Объектов | Результат | +|---|---|---| +| `zont_config/config_0FA7C33CC89F_…_2026-09-17_12-12-28.txt` | 598 | ✅ чисто | +| `zont_config/archive/H2000_PRO_config_actual-4.txt` | 558 | ✅ чисто | +| `zont_config/archive/H2000_PRO_config_actual-3.txt` | 558 | ✅ чисто | +| `zont_config/archive/H2000_PRO_config_actual-2.txt` | 594 | ✅ чисто | + +```bash +cd /Users/admin/Automation/HA-ZONT-Modbus +python3 test_roundtrip.py # свежий конфиг из zont_config/ +python3 test_roundtrip.py zont_config/archive/H2000_PRO_config_actual-4.txt +``` + +**Что исправлено 2026-09-17** (правки в обоих конвертерах): + +| # | Проблема | Причина | Правка | +|---|---|---|---| +| 1 | Падение «поддерживается только 1 шаг» | `require(len(steps) == 1)` — не знал про задержки в поле 2 | цикл по ссылкам; не-46 → `extra_links` | +| 2 | Падение «поддерживается только 1 действие» | `require(len(actions) == 1)` | список действий целиком | +| 3 | Тип **45** отсутствовал | не было парсера/энкодера | секция `delays`, `KNOWN_TYPES += 45`, `TYPE_ORDER += delays` | +| 4 | Тип 5, поле 3 (`1`→`0`) терялось | энкодер хардкодил `1` | `_raw_field3` | +| 5 | `1.0` → `1` (порча float) | `parse_atom` превращал whole-float в int | whole-float остаётся float | +| 6 | Сценарии старой прошивки (7 полей) → 8 | энкодер всегда писал 8 | `_raw_field_count` | +| 7 | `divider=1.0` → `1` | дефолт подавлялся | `_raw_divider` | + +--- + ## 3. Как пользоваться **Требования:** `python3` + `PyYAML`. Проверка: `python3 -c 'import yaml; print(yaml.__version__)'`