[2026-09-17] eagle: family/how-to/zont-config-compiler.md family/tech/zont-config-object-types.md

This commit is contained in:
Alexey Martemyanov
2026-09-17 19:01:41 +06:00
parent 72ba9f774c
commit d8e4973c3d
2 changed files with 58 additions and 12 deletions
+46 -12
View File
@@ -343,8 +343,13 @@ diff A.txt B.txt # пусто = round-trip чистый
| 39 | 🔴 **«Тип сценария» брать из имён сценариев — выдумка** | Я строил тип по словам в `name` («по расписанию», «по триггеру») и назвал это типами. Alex: «из какого блядь имени?!». Типы назвал Alex: `manual`/`trigger`/`interval`/`schedule`. Имя сценария — подпись, не тип | | 39 | 🔴 **«Тип сценария» брать из имён сценариев — выдумка** | Я строил тип по словам в `name` («по расписанию», «по триггеру») и назвал это типами. Alex: «из какого блядь имени?!». Типы назвал Alex: `manual`/`trigger`/`interval`/`schedule`. Имя сценария — подпись, не тип |
| 40 | 🔴 **Гипотезу проверять ПОЛНЫМ прогоном до того, как о ней говорить** | Разбор поля 5 занял ~20 итераций: гипотезы («значение условия», «один шаг → 1») падали по 32 расхождения. Дважды скрипт проверки был с ошибкой индекса и выдавал «всё сходится». **Прогнать по всем 70 и печатать расхождения списком**, прежде чем строить вывод | | 40 | 🔴 **Гипотезу проверять ПОЛНЫМ прогоном до того, как о ней говорить** | Разбор поля 5 занял ~20 итераций: гипотезы («значение условия», «один шаг → 1») падали по 32 расхождения. Дважды скрипт проверки был с ошибкой индекса и выдавал «всё сходится». **Прогнать по всем 70 и печатать расхождения списком**, прежде чем строить вывод |
| 41 | 🔴 **Тостинг в UI + свежий `curl` — единственный способ добыть включённые значения флаговых полей** | Пока `8597`/`8599` были выключены, значения `0`/`2` для `schedule`/`interval` вкл были неизвестны. Alex включил их в UI → новый снимок `18-43-24` → правило замкнулось. Для флаговых полей конфига: спросить Alex включить/выключить и снять конфиг заново | | 41 | 🔴 **Тостинг в UI + свежий `curl` — единственный способ добыть включённые значения флаговых полей** | Пока `8597`/`8599` были выключены, значения `0`/`2` для `schedule`/`interval` вкл были неизвестны. Alex включил их в UI → новый снимок `18-43-24` → правило замкнулось. Для флаговых полей конфига: спросить Alex включить/выключить и снять конфиг заново |
| 42 | ⚠️ **`#Z<id>=11` может лежать в `steps` другого сценария как ссылка** | `#Z8456` в поле 2 держит `11109` — это **ссылка на сценарий**, а не шаг. Отдельного объекта-шага нет, `id:` в YAML вводит в заблуждение (Alex: «нихуя не понял а id step-а?»). Открыто — §5j `run_scenario` | | 42 | 🔴 **`#Z<id>=11` может лежать в `steps` другого сценария как ссылка** | `#Z8456` в поле 2 держит `11109` — это **ссылка на сценарий**, не шаг; отдельного объекта-шага нет. **ИСПРАВЛЕНО**: в YAML только `id`, `run_scenario` с именем убран (питфолл 44, §5j) |
| 43 | ⚠️ **Проверочные скрипты на кириллице падают на `cut`/`awk`** | `cut: stdin: Illegal byte sequence` на cp1251-строках. Читать файл в Python (`open(...,'rb').read().decode('cp1251')`), не резать шеллом | | 43 | ⚠️ **Проверочные скрипты на кириллице падают на `cut`/`awk`** | `cut: stdin: Illegal byte sequence` на cp1251-строках. Читать файл в Python (`open(...,'rb').read().decode('cp1251')`), не резать шеллом |
| 44 | 🔴 **`run_scenario: <имя>` — выдуманное поле с подстановкой из чужого объекта** | Alex: «какого хуя блядь поля которых не было даже в конфиге то всплывают?». В конфиге у ссылки на сценарий — **только id**. Убрано из обоих конвертеров (§5j) |
| 45 | 🔴 **Один и тот же класс ошибки трижды за сессию** | `target_name`/`target_type`/`raw_value``descr` у шага → `run_scenario`. Все три — дорисовка парсером того, чего в строке конфига нет. **Правило:** YAML-ключ обязан соответствовать полю строки либо выводиться из тела; подстановка из **другого** объекта запрещена |
| 46 | 🔴 **Служебные ключи в YAML — отвергнуты как подход** | `_f5` держался 20+ сообщений. Alex: «какое нахуй служебное». Сначала искать вывод из данных, служебный ключ — последнее средство и только на нестандартных случаях (`_op`, `_then`, `_else`) |
| 47 | 🔴 **Правило вывода `type` даёт сбой на `#Z11109`** | Есть шаг 46, но он `manual`. Отличие: в поле 2 **два** элемента. Число элементов ≠ 1 → не `trigger`. **Гипотеза, не проверена** (§5j) |
| 48 | ⚠️ **`type` выводится из тела, но `manual` и `schedule` дают одно поле 5 = `0`** | Различаются только полями 3/4 (`days`/`time`). Alex: «manual от schedule очевидно отличаются наличием блядь schedule» |
### Ограничения конвертера (найдено 2026-09-17) — ВСЕ ЗАКРЫТЫ ### Ограничения конвертера (найдено 2026-09-17) — ВСЕ ЗАКРЫТЫ
@@ -1174,7 +1179,7 @@ manual: иначе
что писать? Вариант `action: 9563` покрывает только первый. У `11109` их **7** — сейчас уходят что писать? Вариант `action: 9563` покрывает только первый. У `11109` их **7** — сейчас уходят
в служебный `_then`. **Решение за Alex.** Всё остальное по форме закрыто. в служебный `_then`. **Решение за Alex.** Всё остальное по форме закрыто.
### ⚠️ `run_scenario` — имя вместо id (открыто, 2026-09-17) ### `run_scenario` — УБРАНО, оставлен голый id (2026-09-17)
Сценарий может вызывать другой сценарий: `#Z8456` в поле 2 держит **id сценария** `11109` Сценарий может вызывать другой сценарий: `#Z8456` в поле 2 держит **id сценария** `11109`
прямой ссылкой (не отдельным объектом-шагом): прямой ссылкой (не отдельным объектом-шагом):
@@ -1184,20 +1189,29 @@ manual: иначе
#Z11109=11,'Передернуть Автомат Котельной',[11827,11828],0,0,0,0,0 #Z11109=11,'Передернуть Автомат Котельной',[11827,11828],0,0,0,0,0
``` ```
Парсер рендерит это так: Раньше парсер рендерил это как `- id: 11109` + `run_scenario: <имя сценария>`.
🔴 **Это была выдумка** — поля `run_scenario` в конфиге нет, а имя подставлялось из **другого**
объекта (`#Z11109` поле 2). Alex: «какого хуя блядь поля которых не было даже в конфиге то
всплывают?» и «если там в списке один id сценария и это и есть шаг (sub), то какого хуя там
`run_scenario: Передернуть Автомат Котельной` взялся?!».
**Исправлено в обоих конвертерах.** Элемент списка — только id, ровно как в конфиге:
```yaml ```yaml
- id: 11109 - id: 11109
run_scenario: Передернуть Автомат Котельной
``` ```
🔴 **Проблема:** `id:` здесь вводит в заблуждение — это id **сценария**, а не шага; | Файл | Правка |
отдельного объекта-шага у такой ссылки нет. И `run_scenario` хранит **имя**, а не id — |---|---|
при переименовании сценария энкодер не найдёт цель. Alex: «нихуя не понял а id step-а?», | `config-to-yml.py` (`dump_step`, ветка `t == 11`) | `return {'id': step_id}` вместо `{'id':…, 'run_scenario': step[1]}` |
«`11109` это id сценария же». | `yml-to-config.py` (сборка шага) | `if set(step) <= {'id'}: return sid` вместо `if 'run_scenario' in step` |
**Решение за Alex:** `run_scenario` по id (надёжнее) или по имени (читаемее, как сейчас). Проверено: `grep -c run_scenario` по свежему YAML = **0**.
Один объект `11109` играет две роли — он самостоятельный сценарий **и** элемент в `steps` у `8456`.
**Правило (общее):** если у элемента списка нет своего объекта — в YAML только `id`, без
подстановки имени/типа из чужого объекта. То же правило, что уже применялось к `target_name` /
`target_type` / `raw_value`.
--- ---
@@ -1219,6 +1233,26 @@ Round-trip сейчас **не сходится** — `yml-to-config.py` ждё
**Round-trip был чистый на 4/4 конфигах** (§5c, до правки формы). Счётчики совпадали: 661 → 661. **Round-trip был чистый на 4/4 конфигах** (§5c, до правки формы). Счётчики совпадали: 661 → 661.
**После правки формы — сломан, ждёт энкодера.** **После правки формы — сломан, ждёт энкодера.**
🔴 **Точная ошибка round-trip (2026-09-17, последний прогон):**
```text
python3 test_roundtrip.py
❌ YAML->TXT exit=2
Ошибка конвертации: Step 9756: unrecognised node {'id': 9756, 'action': 9500}
```
Энкодер не знает новую форму. **Что осталось сделать в `yml-to-config.py`** (объём ~80 строк):
| # | Что | Где искать |
|---|---|---|
| 1 | `emit_action`/сборка шага — не понимает `{'id': N}` (ссылка на сценарий) | уже поправлено: `if set(step) <= {'id'}: return sid` |
| 2 | Сборка шага — читать `action: <id>``[46, 0, cond_id, [action], []]` | убрать ветку `'if' in step or 'then' in step` (стр. ~508) |
| 3 | Сценарий — читать `trigger:` (список с `object`/`value`), а не `if:` внутри шага | цикл `for scenario in data.get('scenarios')`, стр. ~548 |
| 4 | Тип → поле 5: `type` + `enabled``0`/`1`/`2`/`8`/`9`/`10` | строка сценария, стр. ~554–590 |
| 5 | `_scenario_from_legacy` (стр. ~521) — мёртвый код под старую форму, вычистить | — |
Правило сборки поля 5: `f5 = {manual:0, schedule:0, trigger:1, interval:2}[type] + (0 if enabled else 8)`.
**Уставка температуры раскодирована**`код = (t °C + 273) × 10`, подтверждено 3 точками **Уставка температуры раскодирована**`код = (t °C + 273) × 10`, подтверждено 3 точками
(`22→2950`, `23.8→2968`, `5.2→2782`; §8.13 в [[family/tech/zont-scenario-logic-11109]]). (`22→2950`, `23.8→2968`, `5.2→2782`; §8.13 в [[family/tech/zont-scenario-logic-11109]]).
@@ -1235,8 +1269,8 @@ Round-trip сейчас **не сходится** — `yml-to-config.py` ждё
| Файл | Статус | | Файл | Статус |
|---|---| |---|---|
| `config-to-yml.py` | 🆕 **изменён** — форма §5j: `trigger` на уровне сценария, `steps[].{id, action}`, поле `type` из тела, `_f5`/`descr` у шага убраны, `object` вместо `condition.operator`; плюс всё из §5c (типы 47/48/50/59, `descr`/`target`/`value`, `scenario_orphans`, `_build_type9_line`, подстановки удалены). **не закоммичено** | | `config-to-yml.py` | 🆕 **изменён** — форма §5j: `trigger` на уровне сценария, `steps[].{id, action}`, поле `type` из тела (`manual`/`trigger`/`interval`/`schedule`), `_f5`/`descr` у шага убраны, `run_scenario` заменён на голый `id`, `object` вместо `condition.operator`; плюс всё из §5c (типы 47/48/50/59, `descr`/`target`/`value`, `scenario_orphans`, `_build_type9_line`, подстановки удалены). **не закоммичено** |
| `yml-to-config.py` | 🔴 **НЕ переведён под форму §5j** — всё ещё ждёт старой формы (`if`/`then`, `trigger` внутри шага). **Round-trip сломан.** Остальное из §5c на месте: `_build_type9_line()`, `_encode_type9_value()`, блок «2b». **не закоммичено** | | `yml-to-config.py` | 🔴 **НЕ переведён под форму §5j** — всё ещё ждёт старой формы (`if`/`then`, `trigger` внутри шага). **Round-trip падает:** `Step 9756: unrecognised node {'id': 9756, 'action': 9500}`. Частично поправлено (`set(step) <= {'id'}` вместо `run_scenario`). План правки — §6. **не закоммичено** |
| `test_roundtrip.py` | ✅ в коммите `199f2b1`, без изменений | | `test_roundtrip.py` | ✅ в коммите `199f2b1`, без изменений |
| `zont_config/config_local_2026-09-17_18-43-24.txt` | 🆕 **34 962 байт****САМЫЙ ПОСЛЕДНИЙ** конфиг. Снят `curl -s http://192.168.0.50/config.txt` после включения `8597`/`8599` в UI. **не в git** | | `zont_config/config_local_2026-09-17_18-43-24.txt` | 🆕 **34 962 байт****САМЫЙ ПОСЛЕДНИЙ** конфиг. Снят `curl -s http://192.168.0.50/config.txt` после включения `8597`/`8599` в UI. **не в git** |
| `zont_config/config_local_2026-09-17_18-43-24.yml` | 🆕 форма §5j + поле `type`. **не в git** | | `zont_config/config_local_2026-09-17_18-43-24.yml` | 🆕 форма §5j + поле `type`. **не в git** |
+12
View File
@@ -148,6 +148,18 @@ Modbus-регистры (тип 52) в конфиге — **отдельные
**Действие в шаге может быть объектом трёх типов:** `5` (действие над выходом, 11 полей), `9` (команда реле, 4 поля, `value`**строка** `'1'`/`'0'`), `45` (пауза в мс, 2 поля). **Действие в шаге может быть объектом трёх типов:** `5` (действие над выходом, 11 полей), `9` (команда реле, 4 поля, `value`**строка** `'1'`/`'0'`), `45` (пауза в мс, 2 поля).
**Ссылка на другой сценарий (тип 11 внутри `steps`)** — в YAML остаётся **только `id`**:
`#Z8456` в поле 2 держит `11109` — это id **сценария**, отдельного объекта-шага нет.
Подстановка имени (`run_scenario: <имя>`) убрана как выдумка — см. [[family/how-to/zont-config-compiler]] §5j.
**Поле `type` сценария в YAML** (`manual`/`trigger`/`interval`/`schedule`) выводится из тела:
`trigger` = поднятый триггер (шаг 46), `interval` = есть `interval_ms`, `schedule` = есть
`days`/`time`, иначе `manual`. Поле 5 при сборке = `{manual:0, schedule:0, trigger:1, interval:2}[type] + (0 if enabled else 8)`.
> ⚠️ **Известная ошибка вывода `type`:** `#Z11109` получает `trigger`, хотя он `manual` (поле 5 = `0`).
> У него тоже есть шаг 46, но в поле 2 **два** элемента (`11827` + пауза `11828`), у настоящих
> trigger — ровно один. Правка-гипотеза: `trigger` = ровно один элемент в `steps` И он типа 46. **Не проверена.**
> ⚠️ **Тип 45 ≠ `delay_ms` типа 5.** `delay_ms` (поле 4 типа 5) — задержка внутри действия. Тип 45 — отдельный объект-пауза между действиями. > ⚠️ **Тип 45 ≠ `delay_ms` типа 5.** `delay_ms` (поле 4 типа 5) — задержка внутри действия. Тип 45 — отдельный объект-пауза между действиями.
### 2.4. `*`-маркеры ### 2.4. `*`-маркеры