[2026-09-17] eagle: personal/projects/zont-config-compiler.md

This commit is contained in:
Alexey Martemyanov
2026-09-17 23:26:18 +06:00
parent d5f6e1476a
commit 6a7924a6a5
+156 -4
View File
@@ -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, '<descr>', output_ref, value, …]` | `{descr, target, value, params?}` |
| `5` | действие над выходом | `[5, '<descr>', output_ref, 1, 0,0,[],0,0,0, <action>]` — поля 3..9 дефолты | `{descr, target, action}` (§22) |
| `9` | команда (реле/контур/режим) | `[9, '<descr>', target, '<value>']` | `{descr, target, value}` |
**Операторы type 47** (порядок UI `<, >, =, <=, >=`): `0`=`<`, `1`=`>`, `2`=`=`, `3`=`<=`, `4`=`>=`.
@@ -480,7 +485,8 @@ enabled = not (f5 & 8)
| ⛔ **`action: <id>` и вообще ключ `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+ действий |
| 49 | `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) |
---