diff --git a/personal/projects/zont-config-compiler.md b/personal/projects/zont-config-compiler.md index a3a333f1..68486a0e 100644 --- a/personal/projects/zont-config-compiler.md +++ b/personal/projects/zont-config-compiler.md @@ -3,7 +3,7 @@ title: ⚙️ ZONT Config Compiler — конвертеры .txt ⇄ .yml namespace: personal type: how-to created: '2026-09-17' -updated: '2026-09-17b' +updated: '2026-09-17d' tags: - personal - zont @@ -192,7 +192,7 @@ python3 test_roundtrip.py zont_config/config_X.txt | 52 | Modbus-регистры | `name`, `register`, `bit_width`, `repeat_period`, `num_vars` | вложены в устройство 51 | | 53 | Аналоговые выходы | `name`, `min`, `max`, `value`, `offset`, `scale`, `flags`, `address` | `analog_outputs` | | 57 | MQTT-топики | `topic`, `sensors` | `mqtt_topics` | -| **59** | Мини-скрипт ZONT | `descr`, `args[]` | инлайн в `then`/`else` | +| **59** | Мини-скрипт ZONT | `descr`, `args[]` (+ `target`/`value` для `objcmd *`); тела `set var`/`puts`/`storeev` — §5.10 | инлайн в `then`/`else` | > 🔴 Для каждого типа указаны только **реально декодируемые** поля; остальное — `raw` и пишется как есть. @@ -407,7 +407,41 @@ enabled = not (f5 & 8) --- -## 6. Проверка целостности (round-trip) +### 5.10. Тела записи 59 — таксономия (разобрано 2026-09-17) + +Разведка по снимку `19-53-21` (686 строк, 661 `#Z`, round-trip 🟢 чистый). **28 записей типа 59** +разложены по телу (поле 1, `descr`) — три названные Alex конструкции + вызовы подсистем: + +| Тело (`descr`) | Кол-во | Что это | Где живёт значение | +|---|---|---|---| +| `set var1` | 12 | **запись значения объекту** | `args[0]` = id целевого объекта (`8844`, `8831`, `8429`) | +| `puts "…"` | 5 | **print log** — вывод текста | args = `0,0,0` (текст в самом `descr`) | +| `storeev I "…"` / `storeev A "…"` | 5 | **журнал событий**: `I` = инфо, `A` = alert | args = `0,0,0` | +| `objcmd "fmt"` | 3 | команда объекту (в т.ч. с хвостом `;#a` / `;#h`) | `args[0]` = id/операнд | +| `expr "%0 + %1"` | 1 | вычисление | `args[0]`, `args[1]` = операнды (`8819`, `8820`) | +| `objstate 0 0` | 2 | запрос состояния | — | +| `3`, `2 ;#p` | 2 | короткие скрипты-заглушки | — | + +Полный список тел — в живом конфиге: +`#Z8472=59,'set var1',0,0,0` · `#Z8549=59,'puts "test"',0,0,0` · +`#Z8598=59,'storeev I "инфо событие в пн, ср, чт, пт, сб"',0,0,0` · +`#Z8818=59,'objcmd 8700 "1 %0"',14.5,0,1` · `#Z8821=59,'expr "%0 + %1"',8819,8820,0` + +**В YAML сейчас:** `{id, descr: 'set var1', args: [8829, 0, 0]}` — verbatim, без семантики. +`target`/`value` дорисовываются только для тел, начинающихся с `objcmd `. + +> 🔴 **Alarm — отдельного типа НЕТ.** Сигнализация/события выражаются телом `storeev` (журнал +> событий) и условием на битовую маску. Не искать «тип alarm» в конфиге. + +> 🔴 **Дыра в читаемости:** 12 записей `set var1` **переиспользуют** один и тот же `descr` — по YAML +> не видно, что они разные. А несущие объекты (`#Z8830` → `#Z8829=49,8450,1,0`; маски `#Z8844=50,1,0,0,123`) +> лежат в `scenario_orphans` как raw-склад и в теле сценария **не развёрнуты**. + +> ⚠️ **Артефакт парсера:** `#Z8195` (SMS) в `steps` → `raw: *id002` — PyYAML-анкор на секцию +> `sms_notifications`. Два анкора в файле (`&id001` sensors, `&id002` SMS) — **законные**, это не +> баг формы §5. Round-trip при них зелёный. + +--- ```bash cd /Users/admin/Automation/HA-ZONT-Modbus @@ -482,6 +516,8 @@ diff A.txt B.txt # пусто = чисто | 26 | 🔴 **Правка комментария — не правка кода** | Три ответа подряд «готово, зелёный», при том что горячий блок стоял выше моего нового. Мёртвый новый код = ложный зелёный | | 27 | ⚠️ **`>` в шелле затирает `.yml` до старта питона** | Проверять exit-код | | 28 | ⚠️ **Один шаг может принадлежать нескольким сценариям** | Хелпер `_register()` — обновляет запись по id, не добавляет дубль | +| 28a | 🔴 **12 разных `set var1` выглядят в YAML одинаково** | `descr` у всех один, различие — только в `args[0]`. Не «оптимизировать» их обратно в одну запись. Смысл теряется: см. §5.10, план §10.1 | +| 28b | ⚠️ **Несущие объекты 49/50 живут в `scenario_orphans`, не в теле шага** | `#Z8830` → `#Z8829=49,8450,1,0`. Sweep (§7.4) докидывает их только как raw-склад. Раскрытие = отдельное решение (вариант B §10.1), не «попутная починка» | ### 7.3. Проверка гипотез @@ -578,15 +614,18 @@ https://lk.zont-online.ru/download/firmwares/H2000_PRO____.zip | Что | Состояние | |---|---| -| Round-trip | 🟢 **ЗЕЛЁНЫЙ, байт-в-байт** — `661 → 661`, `686 → 686`, `diff` = 0 | +| Round-trip | 🟢 **ЗЕЛЁНЫЙ, байт-в-байт** — `661 → 661`, `686 → 686`, `diff` = 0 (проверен на `19-53-21`) | | Форма сценария | ✅ закрыта (§5), оба конвертера переведены | +| Тела типа 59 | 📖 таксономия собрана (§5.10) · ⏳ `set_var` не развёрнут — **план §10.1, ждём ответа** | | Коммит | `823fabd` на `main` — «Scenario YAML shape: bare action ids, no anchors» (3 файла, +200/−1000) | +| Последний | `b75c51f` — «Drop stale YAML snapshots in old scenario shape» | | Предыдущий | `1cc010a` — **содержит сломанные версии** (анкоры, лишний `if`, `then` вместо `action`); закрыт §9.1 | | Документация | ✅ **три дока сведены в один** — `personal/projects/zont-config-compiler.md` (§9.2) | | Push | ❌ **не сделан** | -**Проверка на снимке `18-43-24` (файл с диска):** `trigger:` 66 · `action:` 66 · `if:` 2 · `then:` 2 · -анкоров 3 (законные: `[]`, `raw`, `sensors`). `type`, `field5`, `kind`, `_f5`, `_kind`, `_else` — **0 вхождений**. +**Проверка на снимке `19-53-21`:** `trigger:` 66 · `action:` · `if:`/`then:` (тест `8456`) · +анкоров **2** (`&id001` sensors, `&id002` SMS — оба законные, §5.10). +`type`, `field5`, `kind`, `_f5`, `_kind`, `_else` — **0 вхождений**. **Не в коммите** (untracked): 14 скриптов разбора (`read_scenarios.py`, `dump_new_types.py`, `probe_types.py`, `trace_scenarios.py`, `audit2.py`, `fit_temp*.py`, …, ), папки `zont_api_docs/`, `zont_local_ui_recon/`. @@ -644,25 +683,57 @@ git commit -m "Scenario YAML shape: bare action ids, no anchors" Alex: «это выбор дней недели, то же самое что ставится в значение var1». Сейчас `raw`. 2. **`set var1` с `args: [8844, 0, 0]`** — внутри объекта `8844` лежит та же маска дней недели, объект не раскрыт: «что какого-то хуя уехало вовне сценария вообще — только там пн, вт, чт, пт, сб, вс». + → **см. §10.1, план в работе.** 3. **`unresolved: true`** у `#Z8860`, `#Z8864`, `#Z8601` — этих объектов нет в конфиге. 4. **Тип 3** (SMS `8195`) — тело лежит якорем в `sms_notifications`, не раскрыто. 5. **Тип 11 внутри `steps` другого сценария** — ссылка на сценарий голым `id` (`#Z8456` держит `11109`). 6. **Старые снапшоты `14-16-35.yml` / `16-02-18.yml`** — по 2 вхождения старого `type:`, не перегенерированы. +### 10.1. 📋 ПЛАН: развернуть `set var` / `print log` / alarm (2026-09-17, ОЖИДАЕТ ОТВЕТА) + +**Запрос Alex:** «Теперь разверни set var, print log и alarm нотификации». + +**Разведка (сделана):** снят живой конфиг `config_local_2026-09-17_19-53-21.txt` (686 строк, +661 `#Z`), round-trip 🟢 чистый, таксономия §5.10. Три конструкции = тела **типа 59**. + +| Шаг | Что | Файл | +|---|---|---| +| 1 | ✅ **Бэкап** | `zont_config/backups_before_scripts_20260917_195411/` (оба конвертера + `test_roundtrip.py` + txt) | +| 2 | В `dump` типа 59: если `descr` начинается с `set var` → добавить `set_var: ` (голый id; резолв имени **запрещён** §5.7) | `config-to-yml.py` | +| 3 | В `emit_action`: `set_var` → собрать `[59, 'set var', set_var, 0, 0]` | `yml-to-config.py` | +| 4 | ⚠️ Развернуть 12 несущих условий (`#Z8829`/`8831`/…/`8847`, типы 49/50) из `scenario_orphans` | оба | +| 5 | Round-trip + правка §4/§5.7 + снять п.2 этого списка | док | + +**Открытый вопрос (задан Alex, ответа нет):** делать ли шаг 4. + +- **Вариант A (рекомендован)** — только `set_var` в 59 (шаги 2, 3, 5). Минимум риска, + round-trip гарантированно зелёный. Шаг 4 не трогаем. +- **Вариант B** — A + развернуть несущие условия 49/50. Полный смысл, но **меняет форму `8456`** + (сейчас та байт-совместима через `scenario_orphans`). + +**Порядок работ (правило Alex):** коммит ДО → правка → заливка → проверка Alex → коммит ПОСЛЕ. + +**Текущее состояние:** разведка + бэкап сделаны, **правок кода НЕТ**. Ждём «A» или «B». + --- ## 11. Файлы проекта | Файл | Статус | |---|---| -| `config-to-yml.py` | ✅ форма §5: `trigger:` подъём через `pop('if')`, шаг = `{id, [flag], action}` или `{id, [flag], if, then, [else]}` | -| `yml-to-config.py` | ✅ `emit_step` читает `then`/`action`/`else`/`flag`; `f5` из `trigger:`/`interval_ms` + бит 8 | +| `config-to-yml.py` | ✅ форма §5: `trigger:` подъём через `pop('if')`, шаг = `{id, [flag], action}` или `{id, [flag], if, then, [else]}` · ⏳ тип 59 без `set_var` (§10.1) | +| `yml-to-config.py` | ✅ `emit_step` читает `then`/`action`/`else`/`flag`; `f5` из `trigger:`/`interval_ms` + бит 8 · ⏳ тип 59 без `set_var` (§10.1) | | `test_roundtrip.py` | ✅ без изменений (в коммите `199f2b1`) | -| `zont_config/config_local_2026-09-17_18-43-24.{txt,yml}` | 🆕 **актуальный** снапшот, форма §5 | +| `zont_config/config_local_2026-09-17_19-53-21.{txt}` | 🆕 **актуальный** снимок с прибора (686 строк, 661 `#Z`) | +| `zont_config/config_local_2026-09-17_18-43-24.{txt,yml}` | предыдущий снимок, форма §5 | +| `zont_config/backups_before_scripts_20260917_195411/` | 🆕 бэкап **перед** правками типа 59 (оба конвертера + `test_roundtrip.py` + txt) | | `zont_config/config_local_2026-09-17_{17-45-00,16-13-28,16-02-18,14-16-35}.*` | исторические снапшоты | | `zont_config/config_0FA7C33CC89F_…_12-12-28.txt` | боевой конфиг (598 `#Z`, 25 `#S`) | | `zont_config/archive/` | `-2`/`-3`/`-4` — закоммичены (`7ae0e32`) | +> 📌 **Бэкап кода — только git** (питфолл 8), но **перед правкой типа 59** Alex просил бэкап +> рабочей копии — он лежит в `backups_before_scripts_/`, не в `/tmp`. + **Не относится к конвертерам** (исторический TrueNAS-стек, **декомиссирован**): `INFRASTRUCTURE.md`, `docker-compose.yml`, `docker run.txt`, `modbus_*_bridge.py`, `nodered-flows-*.json`, `homeassistant/`, `floorplan/`. Актуальный контур — [[family/how-to/home-automation]].