diff --git a/family/how-to/zont-config-compiler.md b/family/how-to/zont-config-compiler.md index 614cdded..498221ca 100644 --- a/family/how-to/zont-config-compiler.md +++ b/family/how-to/zont-config-compiler.md @@ -343,8 +343,13 @@ diff A.txt B.txt # пусто = round-trip чистый | 39 | 🔴 **«Тип сценария» брать из имён сценариев — выдумка** | Я строил тип по словам в `name` («по расписанию», «по триггеру») и назвал это типами. Alex: «из какого блядь имени?!». Типы назвал Alex: `manual`/`trigger`/`interval`/`schedule`. Имя сценария — подпись, не тип | | 40 | 🔴 **Гипотезу проверять ПОЛНЫМ прогоном до того, как о ней говорить** | Разбор поля 5 занял ~20 итераций: гипотезы («значение условия», «один шаг → 1») падали по 32 расхождения. Дважды скрипт проверки был с ошибкой индекса и выдавал «всё сходится». **Прогнать по всем 70 и печатать расхождения списком**, прежде чем строить вывод | | 41 | 🔴 **Тостинг в UI + свежий `curl` — единственный способ добыть включённые значения флаговых полей** | Пока `8597`/`8599` были выключены, значения `0`/`2` для `schedule`/`interval` вкл были неизвестны. Alex включил их в UI → новый снимок `18-43-24` → правило замкнулось. Для флаговых полей конфига: спросить Alex включить/выключить и снять конфиг заново | -| 42 | ⚠️ **`#Z=11` может лежать в `steps` другого сценария как ссылка** | `#Z8456` в поле 2 держит `11109` — это **ссылка на сценарий**, а не шаг. Отдельного объекта-шага нет, `id:` в YAML вводит в заблуждение (Alex: «нихуя не понял а id step-а?»). Открыто — §5j `run_scenario` | +| 42 | 🔴 **`#Z=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')`), не резать шеллом | +| 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) — ВСЕ ЗАКРЫТЫ @@ -1174,7 +1179,7 @@ manual: иначе что писать? Вариант `action: 9563` покрывает только первый. У `11109` их **7** — сейчас уходят в служебный `_then`. **Решение за Alex.** Всё остальное по форме закрыто. -### ⚠️ `run_scenario` — имя вместо id (открыто, 2026-09-17) +### ✅ `run_scenario` — УБРАНО, оставлен голый id (2026-09-17) Сценарий может вызывать другой сценарий: `#Z8456` в поле 2 держит **id сценария** `11109` прямой ссылкой (не отдельным объектом-шагом): @@ -1184,20 +1189,29 @@ manual: иначе #Z11109=11,'Передернуть Автомат Котельной',[11827,11828],0,0,0,0,0 ``` -Парсер рендерит это так: +Раньше парсер рендерил это как `- id: 11109` + `run_scenario: <имя сценария>`. + +🔴 **Это была выдумка** — поля `run_scenario` в конфиге нет, а имя подставлялось из **другого** +объекта (`#Z11109` поле 2). Alex: «какого хуя блядь поля которых не было даже в конфиге то +всплывают?» и «если там в списке один id сценария и это и есть шаг (sub), то какого хуя там +`run_scenario: Передернуть Автомат Котельной` взялся?!». + +**Исправлено в обоих конвертерах.** Элемент списка — только id, ровно как в конфиге: ```yaml - id: 11109 - run_scenario: Передернуть Автомат Котельной ``` -🔴 **Проблема:** `id:` здесь вводит в заблуждение — это id **сценария**, а не шага; -отдельного объекта-шага у такой ссылки нет. И `run_scenario` хранит **имя**, а не id — -при переименовании сценария энкодер не найдёт цель. Alex: «нихуя не понял а id step-а?», -«`11109` это id сценария же». +| Файл | Правка | +|---|---| +| `config-to-yml.py` (`dump_step`, ветка `t == 11`) | `return {'id': step_id}` вместо `{'id':…, 'run_scenario': step[1]}` | +| `yml-to-config.py` (сборка шага) | `if set(step) <= {'id'}: return sid` вместо `if 'run_scenario' in step` | -**Решение за Alex:** `run_scenario` по id (надёжнее) или по имени (читаемее, как сейчас). -Один объект `11109` играет две роли — он самостоятельный сценарий **и** элемент в `steps` у `8456`. +Проверено: `grep -c run_scenario` по свежему YAML = **0**. + +**Правило (общее):** если у элемента списка нет своего объекта — в 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 (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: ` → `[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 точками (`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`, подстановки удалены). **не закоммичено** | -| `yml-to-config.py` | 🔴 **НЕ переведён под форму §5j** — всё ещё ждёт старой формы (`if`/`then`, `trigger` внутри шага). **Round-trip сломан.** Остальное из §5c на месте: `_build_type9_line()`, `_encode_type9_value()`, блок «2b». **не закоммичено** | +| `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 падает:** `Step 9756: unrecognised node {'id': 9756, 'action': 9500}`. Частично поправлено (`set(step) <= {'id'}` вместо `run_scenario`). План правки — §6. **не закоммичено** | | `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.yml` | 🆕 форма §5j + поле `type`. **не в git** | diff --git a/family/tech/zont-config-object-types.md b/family/tech/zont-config-object-types.md index 36338a14..1808e3d9 100644 --- a/family/tech/zont-config-object-types.md +++ b/family/tech/zont-config-object-types.md @@ -148,6 +148,18 @@ Modbus-регистры (тип 52) в конфиге — **отдельные **Действие в шаге может быть объектом трёх типов:** `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 — отдельный объект-пауза между действиями. ### 2.4. `*`-маркеры