[2026-09-17] eagle: personal/projects/zont-config-compiler.md
This commit is contained in:
@@ -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+ действий |
|
||||
| 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) |
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user