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

This commit is contained in:
Alexey Martemyanov
2026-09-17 20:58:43 +06:00
parent 041446b32c
commit dafdcf9ec6
+110 -33
View File
@@ -378,6 +378,9 @@ enabled = not (f5 & 8)
| `log: {text: …}` | ключ-контейнер на один аргумент → плоский `log: <текст>`, §10.3 |
| ⛔ **изобретать форму для смысла, у которого уже есть паттерн** | «как в schedule сделано! паттерн уже есть» — сперва `grep` принятую форму (дни, время, интервал), §10.1 круг 16 |
| ⛔ **переносить константы одного типа на другой по имени поля** | `LEAF_OPS` типа 47 применён к объекту 49 — множество значений поля по данным не проверено, §10.1 круг 18 |
| ⛔ **применять разобранную форму ко ВСЕМ объектам типа, а не только к подтверждённым** | временную форму 50 применил к `8844``op: <` / `time: 00:00`; Alex: «ты сломал его нахуй», §10.5 круг 24 |
| ⛔ **`days_mask: <число>` / `mask: <число>` / `_head` / `raw` в теле объекта 50** | «какой нахуй days», «какой mask», «откуда блядь опять raw выполз», «че за head блядь» — §10.5 |
| ⛔ **выдумывать знак сравнения, если поле не подтверждено** | `>` у `8842` получен случайным совпадением (`1``LEAF_OPS`); контрпримера нет — знак в YAML не пишется, §10.5 |
**РАЗРЕШЕНО:** `trigger:` (выводится из тела — один шаг 46), `if`/`then`/`else`/`flag` — **реальные поля
записи 46**, `action` — имя списка у шага с поднятым условием, `set_var: {id, name, object/operator/value
@@ -389,7 +392,7 @@ enabled = not (f5 & 8)
> 📌 **Общий принцип:** YAML-ключ обязан соответствовать полю строки конфига либо выводиться из тела.
> **Подстановка из другого объекта запрещена.**
### 5.8. 🔴 История формы — 18 кругов (не повторять)
### 5.8. 🔴 История формы — 24 круга (не повторять)
| Круг | Что затащил | Реплика Alex |
|---|---|---|
@@ -414,10 +417,14 @@ enabled = not (f5 & 8)
| 19 | `field: 1` (сырое имя поля 3) | «че блядь за `field/value`?» | ⛔ |
| 20 | `mode: compare\|event` — переименовал заодно с ответом про события | «какой нахуй `field`!» · «еб твою мать» | ⛔ |
| 21 | `type: condition` + `event`/`value`, поле 3 НЕ пишется | **«`type: condition` блядь!»** | ✅ **принято** |
| 22 | объект 50 разложен как расписание: `days`/`days_mask`/`mask`/`raw`/`_head` | «откуда блядь опять raw выполз» · «какой нахуй days» · «какой mask» | ⛔ §10.5 |
| 23 | `cmp` вместо `op` (термин выдуман) | «че такое `cmp`… гдето у нас еще есть термин cmp?» | ⛔ → `op`, единообразно с типом 47 |
| 24 | временную форму 50 применил ко ВСЕМ объектам 50 (`8844``op: <`/`time: 00:00`) | «ты сломал его нахуй» · «ты дебил?!» | ⛔ → две формы по полю 3, §10.5 |
> 📌 Круги 10–11 разобраны в §10.2, 1218 — в §10.1, 14 — в §10.3. Итог: `storeenv: {level: info|alert, text}`
> — два ключа, `id` команды снаружи, словами, без `event`; `set_var: {id, name, object/operator/value
> либо days/days_mask}` — плоско, без `type`; `log: <текст>` — плоская строка.
> 📌 Круги 10–11 разобраны в §10.2, 1218 — в §10.1, 14 — в §10.3, 1924 — в §10.4/§10.5.
> Итог: `storeenv: {level: info|alert, text}` — два ключа, `id` команды снаружи, словами, без `event`;
> `set_var: {id, name, type, object/event|value}` — плоско; `log: <текст>` — плоская строка;
> объект 50 — две формы (`time_condition` / `days_mask`).
> 🔴 **Три системных корня кругов 12–18:**
> **(а) ключ-контейнер на один смысл** — `{var1: …}`, `{text: …}`: обёртка ради обёртки, Alex видит
@@ -695,11 +702,12 @@ https://lk.zont-online.ru/download/firmwares/H2000_PRO_<HW>__<FW>_<PROFILE>.zip
| Что | Состояние |
|---|---|
| Round-trip | 🟢 **ЗЕЛЁНЫЙ, байт-в-байт**`698 → 698`, `723 → 723` на снимке `20-40-48` (было `661 → 661` на `19-53-21`) |
| Round-trip | 🟢 **ЗЕЛЁНЫЙ, байт-в-байт**`698 → 698`, `723 → 723` (снимок `20-40-48`); ранее `661 → 661` (`19-53-21`). Прогон на `20-55-22`**не сделан** (снимок только снят, конвертеры не менялись) |
| Форма сценария | ✅ закрыта (§5), оба конвертера переведены |
| Тела типа 59 | ✅ **`storeenv` (§10.2), `set_var` с вложенным телом цели (§10.1, круги 1221), `log` плоский (§10.3) — готовы, не закоммичены** · `objcmd`/`expr`/`objstate``descr`+`args` |
| Условия 49 (`set_var`) | ✅ **форма закрыта**`type: condition` + `object` + `event`\|`value`; поле 3 в YAML не пишется; 18 комбинаций из **Conditions Test** (§10.4) |
| Имя переменной | ✅ `set var1` **и** `set varname` — регексп `^set (var\w*|\w+)$` (§10.4) |
| Объект 50 (`set_var`) | ✅ **две формы по ПОЛЮ 2**: `0` = время → `type: time_condition` + `time`; `1` = дни → `type: days_mask` + `days` (§10.5). ⚠️ **знак сравнения лежит в ПОЛЕ 3** (найден круг 25: `9248`=`1`, `9250`=`0`, `9252`=`2`, `9254`=`4`) — коды совпадают с `LEAF_OPS` типа 47, но **`op` в YAML не пишется, пока Alex не назвал подписи этих 4 условий** |
| Имя переменной | ✅ `set var1` **и** `set varname` — регексп `^set (var\w*\|\w+)$` (§10.4) |
| `field` / `mode` | ⛔ **удалены** — 0 вхождений в файле (§10.1 круги 1921) |
| Потери объектов | ✅ **0** — было 5 (`8472`, `8821`, `8849`, `8851`, `8855`) |
| `unresolved: true` | ⚠️ висит у `#Z8860`, `#Z8864`, `#Z8601` — объекта в конфиге нет (§10, §10.4) |
@@ -770,9 +778,9 @@ git commit -m "Scenario YAML shape: bare action ids, no anchors"
⚠️ **Остаётся `raw` / `unresolved`:**
1. **Тип 50**маска дней недели: `#Z8548=50,1,0,0,109`, где `109 = 0b1101101` = пн, ср, чт, сб, вс.
Alex: «это выбор дней недели, то же самое что ставится в значение var1». ✅ **Маска локализована:
ПОЛЕ 5** (сверено по `8548`). Вне `set_var` объекты 50 по-прежнему `raw`.
1. **Тип 50****РАЗОБРАН** (§10.5, круг 25): поле 2 = признак формы (`0` время / `1` дни),
поле 3 = **знак сравнения**, поле 4 = время, поле 5 = маска дней. Осталось **одно**: подписи
4 условий Alex (`9248`/`9250`/`9252`/`9254`) из UI → тогда `op` пишется.
2. ~~**Несущие объекты `set var1`** — тело цели в `scenario_orphans`~~ → ✅ **ЗАКРЫТО**, §10.1 круг 13:
тело цели разворачивается **внутрь** `set_var`. **Вариант B выбран Alex.**
3. **`unresolved: true`** у `#Z8860`, `#Z8864`, `#Z8601` — этих объектов нет в конфиге.
@@ -1240,47 +1248,115 @@ iconv -f cp1251 -t utf-8 out.txt | tr -d '\r' | grep '^#Z8830=59'
> (вложенный шаг), а два — в `scenario_orphans`. Реальный счёт был 3 из 5, не 2. Считать без
> привязки к отступу и печатать **какие именно id** не попали, прежде чем делать вывод.
### 10.5. ✅ Объект 50 — условие по ВРЕМЕНИ, не «маска дней» (круг 22, 2026-09-17)
### 10.5. ✅ Объект 50 — ДВЕ формы: время и дни (круги 2224, 2026-09-17)
**Отправная точка:** `#Z8842=50,0,1,3351,0` выводился как `type: days_mask` + `days: []` +
`days_mask: 0` + `raw: [0, 1, 3351]`. Alex: **«откуда блядь опять raw выполз блядь»**, затем
**«там: current time ">" 13:23»**, затем **«какой нахуй days! я тебе блядь недоступно написал?!»**.
`days_mask: 0` + `raw: [0, 1, 3351]`. Alex: «откуда блядь опять raw выполз блядь», затем
«там: current time > 13:23», затем «какой нахуй days! я тебе блядь недоступно написал?!».
**Итог:** объект 50 — это условие `current time <op> HH:MM`. `3351 = 13:23` — это **время**,
тот же формат, что у расписания сценария (`time = (час << 8) | мин`, §5.6; ср. `#Z8597` = `3354` = 13:22).
**Итог:** объект 50 имеет **ДВЕ формы**, различаются **полем 3**:
| Поле 3 | Форма | Поле 4 | Поле 5 | YAML |
|---|---|---|---|---|
| `1` | условие по времени | **время** `(час<<8)\|мин` | 0 | `type: time_condition` + `time: 'HH:MM'` |
| `0` | **выбор дней недели** | 0 | **маска дней** (бит 0 = ПН) | `type: days_mask` + `days: [mon, …]` |
```yaml
- id: 8843 # #Z8843=59,'set var1',8842,0,0
set_var:
id: 8842 # #Z8842=50,0,1,3351,0
id: 8842 # #Z8842=50,0,1,3351,0 (поле 3 = 1 → время)
name: var1
type: time_condition
op: '>' # поле 3 = 1 → '>' (LEAF_OPS)
time: '13:23' # поле 4 = 3351
time: '13:23' # поле 4 = 3351 = 13*256+23
- id: 8845 # #Z8845=59,'set var1',8844,0,0
set_var:
id: 8844 # #Z8844=50,1,0,0,123 (поле 3 = 0 → дни)
name: var1
type: days_mask
days: [mon, tue, thu, fri, sat, sun] # поле 5 = 123
```
| Поле 50 | Что | В YAML |
|---|---|---|
| 2 | неизвестно (`0` у `8842`, `1` у `8844`/`8548`) | `_f2`**только если ≠ 0** |
| 3 | **оператор** сравнения (`LEAF_OPS`) | `op: '>'` |
| 4 | **время**, `(час<<8)\|мин` | `time: 'HH:MM'` |
| 5 | неизвестно (`0` / `123` / `109`) | `_f5`**только если ≠ 0** |
| `2` | **признак формы**: `1` = **дни недели**, `0` = **время** (подтверждено, круг 25) | **не пишется** — восстанавливается из `type` |
| `3` | **знак сравнения** (`0` `<` · `1` `>` · `2` `=` · `4` `>=` …) или `0` при форме «дни» | `op: ''` (нужна расшифровка всех кодов в UI) |
| `4` | при форме «время» — **время** `(час<<8)\|мин`; при «дни» — `0` | `time: 'HH:MM'` |
| `5` | при форме «время» — `0`; при «дни» — **маска дней** (бит 0 = ПН) | `days: [mon, …]` |
> ⛔ **Запрещено (круг 22):** `days`, `days_mask`, `mask`, `raw` в теле объекта 50 — Alex отверг
> все четыре подряд («какой нахуй days», «какой mask», «откуда raw выполз»). Поля 2/5 —
> служебные `_f2`/`_f5` и **не пишутся, когда нули**.
#### 🔴 Круг 25: тостинг Alex — знак сравнения НАЙДЕН (поле 3)
> 🔴 **Ключ знака — `op`, не `cmp`.** Alex: «че такое cmp… гдето у нас еще есть термин "cmp"?» —
**Как добыто:** Alex в UI переключил `8842` на другие знаки, добавил 4 разных time-условия
и снял конфиг:
```bash
cd /Users/admin/Automation/HA-ZONT-Modbus/zont_config
TS=$(date +%Y-%m-%d_%H-%M-%S)
curl -s --max-time 25 http://192.168.0.50/config.txt -o "config_local_${TS}.txt"
# → config_local_2026-09-17_20-55-22.txt, 729 строк
```
**Пять объектов 50 в новом снимке** (`#Z8548` + 4 новых тостинга + `#Z9256`):
| #Z | строка конфига | поле 2 | поле 3 | поле 4 | поле 5 | форма |
|---|---|---|---|---|---|---|
| 9248 | `50,0,1,3351,0` | `0` | **`1`** | 3351 = **13:23** | 0 | время |
| 9250 | `50,0,0,2817,0` | `0` | **`0`** | 2817 = **11:01** | 0 | время |
| 9252 | `50,0,2,3842,0` | `0` | **`2`** | 3842 = **15:02** | 0 | время |
| 9254 | `50,0,4,3847,0` | `0` | **`4`** | 3847 = **15:07** | 0 | время |
| 8548 | `50,1,0,0,109` | **`1`** | `0` | 0 | 109 | дни |
| 9256 | `50,1,0,0,123` | **`1`** | `0` | 0 | 123 | дни |
**Вывод:** у объектов 50 поле 2 — **признак формы** (`0` = время, `1` = дни), поле 3 — **знак сравнения**
(у формы «время»; у формы «дни» всегда `0`), поле 4 — время, поле 5 — маска дней.
🟢 **Коды знаков совпадают с `LEAF_OPS` типа 47 по позиции** (`1` = `>`, `0` = `=`, `2` = `<`,
`4` = `>=` или `<=`). ⚠️ **Но это по-прежнему гипотеза** — Alex тостинг сделал, а **подписи из UI
не назвал**. Пока подписи нет, `op` в YAML **не пишется** (питфолл: не выводить по совпадению без контроля).
**Что нужно, чтобы закрыть:** Alex называет подписи 4 условий (`9248`, `9250`, `9252`, `9254`) —
либо одно слово «прими по позиции `0=<, 1=>, 2===, 3=<=, 4=>=`».
**Как связывать шаги:** шаги-держатели `set var1` для новых условий:
`#Z9249=59,'set var1',9248,0,0` · `9251``9250` · `9253``9252` · `9255``9254` · `9257``9256`.
> ⚠️ **Питфолл разбора: нумерация полей у объекта 50 — с типа, а не с первого числа после `=`**
> (круг 25). `#Z9248=50,0,1,3351,0` → `поле2=0` (не `1`!), `поле3=1`, `поле4=3351`, `поле5=0`.
> Я сначала посчитал `cut -d, -f5` → получил `0` и «время 00:00» — сдвиг на единицу.
> 🔴 **Резать поля от `type`:** `fields[0]=type`, `fields[1]=поле2`, … Проверять `grep -oE` со
> **скобочной группой до конца строки** `[...](?=\r|\n)`, иначе `[0-9,\-]*` съедает не то.
Все три объекта 50 живого конфига: `#Z8548=50,1,0,0,109` (дни), `#Z8842=50,0,1,3351,0` (время),
`#Z8844=50,1,0,0,123` (дни). `109` = пн,ср,чт,сб,вс; `123` = пн,вт,чт,пт,сб,вс.
> ⛔ **Запрещено (круг 22):** ключ `days_mask` как число, `mask`, `raw`, `_head` в теле объекта 50.
> Alex отверг подряд: «какой нахуй days», «какой mask», «откуда raw выполз», «че за head блядь».
> Поля 2/3 **не пишутся** — восстанавливаются из `type` (`time_condition`/`days_mask`) и `op`.
> ⛔ **Знак сравнения (`op`) в YAML НЕ пишется, пока Alex не назвал подписи.** Место кодирования
> **найдено** (поле 3, круг 25): `9248`=`1`, `9250`=`0`, `9252`=`2`, `9254`=`4`. Коды **совпадают
> с `LEAF_OPS` типа 47 по позиции**, но совпадение не подтверждено подписью из UI — выводить нельзя
> (питфолл: «гипотезу прогнать по ВСЕМ объектам и печатать расхождения ПРЕЖДЕ вывода»).
> **Чтобы закрыть: Alex называет, что за условия `9248`/`9250`/`9252`/`9254` в UI.**
> 🔴 **Ключ знака — `op`, не `cmp`.** Alex: «че такое cmp… гдето у нас еще есть термин cmp?» —
> термина в проекте не было, я его выдумал. У типа 47 (§5.2) тот же смысл называется `op`,
> берём единообразно. `LEAF_OPS` = `{0:'<',1:'>',2:'=',3:'<=',4:'>='}`.
**Проверка §10.5:** round-trip `20-40-48` → ✅ `698 → 698`, `723 → 723`; `cmp` в файле — **0 вхождений**.
Тест на подмену: `op: >``<=`, `time: 13:23``07:45` даёт `#Z8842=50,0,3,1837,0`
(`3` = `<=`, `1837 = 7*256+45`).
(`3` = `<=`, `1837 = 7*256+45`). `days` у `8844` подменены (+`wed`) → `#Z8844=50,1,0,0,127`.
> ⚠️ **Паттерн ошибки (круги 15 → 22):** я дважды «узнавал» смысл объекта 50 по аналогии —
> сначала как расписание сценария (`days`), потом как маску. Alex оба раза бил: **сначала СЛОВА
> из UI, потом модель** (питфолл 32). Для объекта 50 слова даны: «current time > 13:23».
> ⚠️ **Паттерн ошибки (круги 15 → 22 → 24):** я трижды «узнавал» смысл объекта 50 по аналогии —
> сначала как расписание сценария (`days`), потом как маску, потом применил **временную** форму
> ко **всем** объектам 50 (получил `op: <` / `time: 00:00` у `8844` — Alex: «ты сломал его нахуй»).
> Alex объяснял только `8842`. **Правило:** разобранную семантику применять ТОЛЬКО к объектам,
> на которых она подтверждена; для остальных — проверять, что поле-различитель совпадает.
> 🔴 **Питфолл: падение конвертера затирает целевой файл в 0 байт.**
> `python3 config-to-yml.py X.txt > X.yml` открывает `X.yml` **до** старта питона. Если скрипт падает
> (у меня — `NameError: op_raw`), на диске остаётся **пустой** файл, и Alex видит «нихуя не поменялось».
> Порядок: генерировать в `/tmp`, проверять `wc -c` и `grep`, и только потом `cp` в целевой путь.
---
@@ -1288,11 +1364,12 @@ iconv -f cp1251 -t utf-8 out.txt | tr -d '\r' | grep '^#Z8830=59'
| Файл | Статус |
|---|---|
| `config-to-yml.py` | ✅ форма §5: `trigger:` подъём через `pop('if')`, шаг = `{id, [flag], action}` или `{id, [flag], if, then, [else]}` · ✅ тип 59: `set_var` (§10.1), `storeenv` (§10.2), `log` (§10.3), `type: condition` + `event`/`value` (§10.4), `type: time_condition` (§10.5) — **в рабочей копии, не закоммичено** |
| `yml-to-config.py` | ✅ `emit_step` читает `then`/`action`/`else`/`flag`; `f5` из `trigger:`/`interval_ms` + бит 8 · ✅ `set_var`/`storeenv` собраны в **`_script_body()`** — одна функция на обе точки входа (`emit_action` + инлайн `emit_step`) · ✅ `_body_type()` — карта `id → тип` по секциям + `raw`-склад (§10.4) — **не закоммичено** |
| `config-to-yml.py` | ✅ форма §5: `trigger:` подъём через `pop('if')`, шаг = `{id, [flag], action}` или `{id, [flag], if, then, [else]}` · ✅ тип 59: `set_var` (§10.1), `storeenv` (§10.2), `log` (§10.3), `type: condition` + `event`/`value` (§10.4), объект 50 двумя формами — `time_condition`/`days_mask` (§10.5) — **в рабочей копии, не закоммичено** |
| `yml-to-config.py` | ✅ `emit_step` читает `then`/`action`/`else`/`flag`; `f5` из `trigger:`/`interval_ms` + бит 8 · ✅ `set_var`/`storeenv` собраны в **`_script_body()`** — одна функция на обе точки входа (`emit_action` + инлайн `emit_step`) · ✅ `_body_type()` — карта `id → тип` по секциям + `raw`-склад (§10.4) · ✅ `days_mask`/`time_condition` (§10.5)**не закоммичено** |
| `test_roundtrip.py` | ✅ без изменений (в коммите `199f2b1`) |
| `zont_config/config_local_2026-09-17_20-40-48.{txt,yml}` | 🆕 **АКТУАЛЬНЫЙ** снимок (723 строки, 698 `#Z`) — содержит сценарий **`9144` Conditions Test** (18 шагов, все комбинации условий). Круг ✅ `698 → 698`. **Не закоммичен** |
| `zont_config/config_local_2026-09-17_19-53-21.{txt,yml}` | предыдущий снимок (686 строк, 661 `#Z`) — форма §10.2/§10.3; **форма объекта 50 в нём УСТАРЕЛА** (§10.5) |
| `zont_config/config_local_2026-09-17_20-55-22.{txt,yml}` | 🆕 **АКТУАЛЬНЫЙ** снимок (729 строк, 36204 байта) — добавлены 4 time-условия Alex (`#Z9248/9250/9252/9254`), знак сравнения локализован в поле 3 (§10.5 круг 25). **Не закоммичен** |
| `zont_config/config_local_2026-09-17_20-40-48.{txt,yml}` | предыдущий (723 строки, 698 `#Z`) — сценарий **`9144` Conditions Test** (18 шагов, все комбинации условий 49). Круг ✅ `698 → 698`. **Не закоммичен** |
| `zont_config/config_local_2026-09-17_19-53-21.{txt,yml}` | ещё раньше (686 строк, 661 `#Z`) — форма §10.2/§10.3; **форма объекта 50 в нём УСТАРЕЛА** (§10.5) |
| `zont_config/config_local_2026-09-17_18-43-24.{txt,yml}` | ещё раньше, форма §5 |
| `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`) |