From 6a7924a6a5facbbe1e051ec06ee2e7392a0467a1 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Thu, 17 Sep 2026 23:26:18 +0600 Subject: [PATCH] [2026-09-17] eagle: personal/projects/zont-config-compiler.md --- personal/projects/zont-config-compiler.md | 160 +++++++++++++++++++++- 1 file changed, 156 insertions(+), 4 deletions(-) diff --git a/personal/projects/zont-config-compiler.md b/personal/projects/zont-config-compiler.md index 83289196..862663a2 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-17k42' +updated: '2026-09-17k43' tags: - personal - zont @@ -43,10 +43,15 @@ aliases: - ZONT круг 40 - ZONT круг 41 - ZONT круг 42 + - ZONT круг 43 - ZONT шаг 5 хвост полей - ZONT params выдуманный ключ - ZONT value поле 10 действия - ZONT запись типа 5 + - ZONT action код действия + - ZONT код действия 256 512 + - ZONT новый тестовый конфиг 23-21-20 + - ZONT scenario_step_actions related: - '[[family/tech/zont-api]]' - '[[family/how-to/home-automation]]' @@ -269,7 +274,7 @@ echo "=== pass=$pass fail=$fail" | `59` | мини-скрипт | `[59, '<код>', поле2, поле4, поле5]` | `set_var` / `log` / `storeenv` / `pickle` / `descr`+`args`+`target` (`objcmd`) | | — | **тела 59** | все разобраны (круг 38): `set var` → `set_var` ‖ `puts` → `log` ‖ `storeev` → `storeenv` ‖ `objcmd` → `descr`+`args`+`target` ‖ `expr`/`pickle`/`pickle_value`/`objstate`/`var` | неразобранных нет | | — | **тело цели `set_var`** | `49` → `type: param` + `event`/`param`; `50` → `time_condition`/`days_mask` | §10.1 / §10.5 / §10.6 | -| `5` | действие над выходом | `[5, '', output_ref, value, …]` | `{descr, target, value, params?}` | +| `5` | действие над выходом | `[5, '', output_ref, 1, 0,0,[],0,0,0, ]` — поля 3..9 дефолты | `{descr, target, action}` (§22) | | `9` | команда (реле/контур/режим) | `[9, '', target, '']` | `{descr, target, value}` | **Операторы type 47** (порядок UI `<, >, =, <=, >=`): `0`=`<`, `1`=`>`, `2`=`=`, `3`=`<=`, `4`=`>=`. @@ -480,7 +485,8 @@ enabled = not (f5 & 8) | ⛔ **`action: ` и вообще ключ `action`** | **ОТМЕНЁН** (круг 39, `8f2edd4`). При поднятом условии шага в `steps` нет вообще: id шага едет в `trigger.step_id`, `steps` = тела действий. См. §5.3, §21.3 | | ⛔ **`args: [0, 1]` у `set_var` с числовым полем 2** | поле 5 записи 59 — **производное** («поле 2 = литерал, а не id»), энкодер ставит сам. Alex: «да блядь! опять?!» (§21.5) | | ⛔ **раскрывать поля 4/5 записи 59 в YAML** | у `expr` поле 4 = `2` и у `set` поле 5 = `1` — **одно и то же производное поле** («операнд/значение — литерал»). В YAML не пишется, восстановимо по составу (§21.5) | -| ⛔ **`params:` у шага-действия (запись типа 5)** | хвост `0,0,[],0,0,0` (поля 4..9) — дефолты, а поле 10 = `512`/`256` — **код действия**, он и есть `value`. Alex: «тут просто выполнить действие по id». Шаг = `descr` + `target` + `value`, всё (§22, `9f3c1ab`) | +| ⛔ **`params:` у шага-действия (запись типа 5)** | хвост `0,0,[],0,0,0` (поля 4..9) — дефолты, а поле 10 = `512`/`256` — **код действия**. Alex: «тут просто выполнить действие по id». Шаг = `descr` + `target` + `action`, всё (§22) | +| ⛔ **`value:` у шага-действия (запись типа 5)** | **имя выдумано**. Alex: «че за `value: 512` нахуй?! вызов блядь действия» → «там блядь действие» → ключ **`action`** (§22) | | ⛔ **`value: 1` как «значение действия»** | `1` — поле 3 (флаг формы), у всех 100+ действий одинаков. Настоящий код — в поле 10: `256` = выкл, `512` = вкл (§22) | ✅ **РАЗРЕШЕНО:** `trigger:` (выводится из тела — один шаг 46) с ключом **`step_id`** (id шага 46) и @@ -3283,7 +3289,153 @@ Alex прочитал `git show --stat ba6ef44` (2 файла, 10 строк) и Орфаны: **6 → 4** (`8549`, `8554` развернулись на месте). Круг ✅ 9/9. ⚠️ **Коммит `6d0b6a5` оставлен как есть**, хотя форма `action:` затем отвергнута (§21.3): он **не ломает** -круг и не теряет данные, а откат вернул бы орфаны. Форма будет заменена, когда Alex назовёт целевую. +круг и не теряет данных, а откат вернул бы орфаны. Форма будет заменена, когда Alex назовёт целевую. + +--- + +## 22. ✅ Круг 43 — запись типа 5 в шаге: `params` снесён, ключ `action` + +> 🔴 **Это самая дорогая ошибка сессии.** Ниже — что сделано и какие питфоллы. + +### 22.1. Что было сломано + +Alex прислал шаг сценария и спросил «это че за хуйня у нас зарегрессилась?»: + +```yaml + - id: 9500 + descr: Вкл. Рад. ванная 2эт + target: 145728 + value: 1 + params: [0, 0, [], 0, 0, 0, 512] +``` + +**Строка конфига:** `#Z9500=5,'Вкл. Рад. ванная 2эт',145728,1,0,0,[],0,0,0,512` + +| Поле | Значение | Что это | +|---|---|---| +| 1 | `'Вкл. Рад. ванная 2эт'` | `descr` | +| 2 | `145728` | **output_ref** (выход `>> 4` = `9108`) | +| 3 | `1` | флаг формы, одинаков у всех 100+ действий | +| 4–9 | `0,0,[],0,0,0` | дефолты (задержка, импульс, расписание) | +| **10** | **`512`** | **код действия: `256` = выкл, `512` = вкл** | + +Парсер типа 5 внутри шага брал `step[2]` как `target` (верно), но `value` — из **поля 3** +(константа `1`), а поля 4..10 вываливал в выдуманный `params`. Итог: настоящий код действия +уезжал в хвост, а `value` показывал флаг формы. + +**Доказательство кода действия** — таблица выходов и парность записей: + +```text +#Z9500=5,'Вкл. Рад. ванная 2эт',145728,1,0,0,[],0,0,0,512 ← вкл +#Z9501=5,'Выкл. Рад. ванная 2эт',145728,1,0,0,[],0,0,0,256 ← выкл +#Z9108=53,'Вых 13/9: Рад. ванная 2эт',256,512,... ← min=256, max=512 +``` + +🔴 **Alex: «че за `value: 512` нахуй?! вызов блядь действия»** → **«там нет нахуй `value`!»** → +**«там блядь действие»**. Имя `value` я выдумал; правильное — **`action`**. + +### 22.2. Итоговая форма + +```yaml + - id: 9500 + descr: Вкл. Рад. ванная 2эт + target: 145728 + action: 512 +``` + +Поля 3..9 (флаг + дефолты) **не пишутся** — энкодер ставит их сам. Ключ `action` = **поле 10**. + +### 22.3. Три бага, вскрывшихся после правки + +**Баг 1 — `params` у типа 5.** Правка декодера: `value: step[3]` + хвост → `action: step[10]`, хвост убран. +Энкодер: `[5, descr, target, 1, 0, 0, [], 0, 0, 0, action]` вместо `[5, descr, target, value] + params`. + +**Баг 2 — `'int' object has no attribute 'get'`.** Появился на новом конфиге. Причина: декодер отдаёт +`action: <голый id>` у шага без собственного `if` (§5.3, `config-to-yml.py` ~894), а энкодер слепо звал +`emit_step()` и падал на числе. Фикс — хелпер: + +```python +def _ref(a): + return a if isinstance(a, int) else emit_step(a) +``` + +Голый id остаётся **допустимым**: так выглядит ссылка на объект, который эмитит своя секция. + +**Баг 3 — дубли id (exit 4, `Duplicate ID 9500: first=scenario_step (type 46)`).** Тип 5 в шаге имеет +ключ `action` — и ветка `if 'action' in step` ловила его **раньше** ветки типа 5, регистрируя как шаг 46. +Фикс — явная ветка типа 5 **до** ветки 46 в `emit_step`, плюс ветка в `emit_action` (после `args`-проверки, +до `'action' in node`). Признак отличия от типа 9: у 5 есть `action`, у 9 — `value`. + +Плюс тело эмитится в **отдельную секцию** `scenario_step_actions`, а не в `actions`: секция `actions` +собирает объекты по `output_id`, которого у действия-шага нет (у него `target` = output_ref). + +| Точка | Что | +|---|---| +| `config-to-yml.py` `dump_step` (`~1064`) | тип 5 → `{id, descr, target, action}`; хвост не пишется | +| `yml-to-config.py` `emit_step` (`~878`) | **новая ветка типа 5 до ветки 46** | +| `yml-to-config.py` `emit_action` (`~794`) | ветка типа 5 после `args`-проверки | +| `yml-to-config.py` (`~1151`) | эмиссия секции `scenario_step_actions` | + +**Круг ✅ 9/9 чистый**, включая новый конфиг `config_local_2026-09-17_23-21-20.txt` (759 объектов). + +### 22.4. Новый тестовый конфиг Alex + +Alex добавил пачку тестовых значений в UI контроллера: **objcmd** и **action calls**. + +```bash +cd /Users/admin/Automation/HA-ZONT-Modbus +TS=$(date +%Y-%m-%d_%H-%M-%S) +curl -s --max-time 30 http://192.168.0.50/config.txt -o "zont_config/config_local_${TS}.txt" +``` + +| Что нового | id | Форма | +|---|---|---| +| `objcmd` 6 шаблонов | `10371`–`10398` | `objcmd 8700 "1 %0"` / `objcmd 9102 "6,%0";#a` / `objcmd 11907 ",,,%0";#h` | +| `set var1` / `set varname` | `10378`–`10430` | цель-число (`42`), цель-id, цель-`49`/`50` | +| вложенный `46` с `else` | `10444`/`10445` | `[46,1,10440,[10441,10442],[10443]]` | +| группы `48` | `10435`/`10439`/`10440` | `and` / `not` / `or` | +| `45` большая задержка | `10407` | `[45, 432000000]` | + +Дубли id на `9500`/`9505`/`9510` вскрылись именно из-за нового сценария `8456`, где тип 5 стоит и +прямо в списке шагов, и внутри `9756`/`9761`/`9766`. + +### 22.5. 🔴 Питфоллы круга 43 + +🔴 **ПИТФОЛЛ 87 — гонять конвертер ТОЛЬКО в целевой файл.** Я проверил вывод в `/tmp/check-9500.yml`, +целевой артефакт остался **старым**, и Alex трижды видел дефект, который уже был исправлен в коде. +**Alex: «какого хуя ты в tmp его сделал? я как в него блядь смотреть должен?»** + +```bash +# ✅ всегда так — проверка = тот же файл, который смотрит Alex +python3 config-to-yml.py zont_config/config_X.txt > zont_config/config_X.yml +echo "exit=$?"; ls -la zont_config/config_X.yml +``` + +🔴 **ПИТФОЛЛ 88 — «исправлено» ≠ «видно».** Правка исходника без перегенерации артефакта для Alex +не существует. Он читает **артефакт**, а не код. После каждой правки конвертера — перегенерировать +`.yml` и **показать строку глазами**. + +🔴 **ПИТФОЛЛ 89 — не выдумывать имя поля по смыслу.** Я назвал поле 10 «`value`», хотя это код вызова +действия. Прежде чем давать ключу имя, проверить его **полевой состав по всем записям типа** (как в +§21.5) и сверить с парными записями (`9500` вкл / `9501` выкл). Имя даёт Alex или оно выводится +**однозначно** из формы. См. также §5.7. + +🔴 **ПИТФОЛЛ 90 — регресс может ждать нового дампа.** Баги 2 и 3 существовали в коде, но старые +8 снапшотов их не вскрывали: не было типа 5 прямо в списке шагов. **Симптом на новом конфиге = +немедленно добавить его в набор круга** и гонять все 9. + +--- + +## 23. Прочие наблюдения по конфигу (2026-09-17) + +| Наблюдение | Значение | +|---|---| +| `#Z8456` вырос | 27 → **43** шага: Alex добавил тестовых | +| Сценарий `8456` | `manual`, 43 элемента, включает `10445`→`10446` (`end`) | +| `#Z10382` | `puts "Отладка"` → `log: Отладка` | +| `#Z10447=*` | маркер пустого объекта, встречается в конфиге | +| Маска дней `109` | `0b1101101` = пн, ср, чт, сб, вс (§10.1 круг 16) | + ---