From 72ba9f774c8bdfb45d67910b46a217b43afbadeb Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Thu, 17 Sep 2026 18:56:36 +0600 Subject: [PATCH] [2026-09-17] eagle: family/how-to/zont-config-compiler.md family/tech/zont-scenario-logic-11109.md --- family/how-to/zont-config-compiler.md | 154 ++++++++++++++++++----- family/tech/zont-scenario-logic-11109.md | 72 +++++++---- 2 files changed, 171 insertions(+), 55 deletions(-) diff --git a/family/how-to/zont-config-compiler.md b/family/how-to/zont-config-compiler.md index 09d9ba88..614cdded 100644 --- a/family/how-to/zont-config-compiler.md +++ b/family/how-to/zont-config-compiler.md @@ -21,7 +21,7 @@ tags: - homeautomation title: ⚙️ ZONT Config Compiler — конвертеры .txt ⇄ .yml type: how-to -updated: 2026-09-17m +updated: 2026-09-17 --- # ⚙️ ZONT Config Compiler — конвертеры `.txt ⇄ .yml` @@ -146,9 +146,9 @@ updated: 2026-09-17m ### Как это выглядит в YAML -> ✅ **АКТУАЛЬНАЯ форма (2026-09-17).** Сценарий = `trigger:` (условие) + `steps[]` (шаги, -> каждый со своим `action:`), тела инлайн. **Форма — §5c.** Здесь оставлены только исторические -> варианты, чтобы было видно, что отвергнуто Alex и почему. +> ✅ **АКТУАЛЬНАЯ форма (2026-09-17).** Сценарий = `enabled` + `type` + `trigger:` (условие) + +> `steps[]` (шаги, каждый со своим `action:`), тела инлайн. **Форма — §5j.** Здесь оставлены +> только исторические варианты, чтобы было видно, что отвергнуто Alex и почему. **Устаревшая форма (коммит `199f2b1`)** — плоский `when`/`then` для 1-шаговых + `steps` + `extra_links`: @@ -339,6 +339,12 @@ diff A.txt B.txt # пусто = round-trip чистый | 35 | 🔴 **`descr` не ставить туда, где текста нет в строке** | У `#Z9819` (шаг) своего текста нет — значит `descr` у него быть не должно. Alex: «нахуй там тогда descr?! если его нет в оригинале?» | | 36 | ⚠️ **`grep -n "id: N"` по YAML даёт несколько совпадений** | Объект живёт и в своей секции, и внутри сценария. Номер строки меняется между генерациями (4877 → 3932) — индексировать по первому совпадению нельзя | | 37 | ⚠️ **Не забегать вперёд с вопросами о том, чего в кейсе нет** | Вопрос «что писать, если в `trigger` окажется type 47» Alex воспринял как шум («что за type 47? нихуя не понятно»). Сначала форма на текущем кейсе, потом обобщение | +| 38 | 🔴 **`_f5` (служебный ключ в YAML) — отвергнут Alex, и он был прав** | Alex: «какое нахуй служебное». Поле 5 **полностью выводится** из типа + `enabled`. Упорство в служебном ключе = 20+ сообщений про `kind`. Сначала искать вывод из данных, служебный ключ — последнее средство | +| 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` | +| 43 | ⚠️ **Проверочные скрипты на кириллице падают на `cut`/`awk`** | `cut: stdin: Illegal byte sequence` на cp1251-строках. Читать файл в Python (`open(...,'rb').read().decode('cp1251')`), не резать шеллом | ### Ограничения конвертера (найдено 2026-09-17) — ВСЕ ЗАКРЫТЫ @@ -413,15 +419,15 @@ diff A.txt B.txt # пусто = round-trip чистый > **64 из 65** сценариев. Многошаговый `11109` (7 id в `then`) из неё выпадает — сейчас они уходят > в служебный `_then`. Ждём решения Alex. Детали — [[family/tech/zont-scenario-logic-11109]] §8.17(б). > -> 🔴 **Поле 5 типа 11 — семантика НЕ раскрыта.** Модель `kind = field5 & 7` **опровергнута** -> (развалилась на `11109`: даёт `kind=0`, хотя устроен как триггерные `1`). Подтверждён только -> `enabled = not (field5 & 8)`. Полная таблица 5 значений и разбор — **§5j**. +> 🔴 **Поле 5 типа 11 — семантика РАСКРЫТА И ПОДТВЕРЖДЕНА ПРИБОРОМ** (см. §5j): +> `поле5 = тип + 8 при выключенном`, типы `manual`/`trigger`/`interval`/`schedule` (названы Alex), +> `enabled = not (field5 & 8)`. Модель `kind = field5 & 7` опровергнута и снята. +> Включённые значения `schedule`/`interval` добыты тостингом в UI (`8597` → `0`, `8599` → `2`). > -> 📄 **Артефакты (в проекте):** `zont_config/config_local_2026-09-17_17-45-00.yml` — **актуальный** -> (4405 строк, форма `trigger`/`steps` с `trigger` на уровне сценария, уставка 5.2 + -> «Температура Детская»); `zont_config/config_local_2026-09-17_16-13-28.yml` — предыдущая -> генерация (5452 строки, старая форма). Оба в `zont_config/`, не в `/tmp`. -> **Не закоммичено** — ждёт команды Alex. +> 📄 **Артефакты (в проекте):** `zont_config/config_local_2026-09-17_18-43-24.yml` — **актуальный** +> (форма §5j **+ поле `type`**); `zont_config/config_local_2026-09-17_17-45-00.yml` — форма §5j +> **без** `type` (4405 строк); `zont_config/config_local_2026-09-17_16-13-28.yml` — старая форма +> (5452 строки). Всё в `zont_config/`, не в `/tmp`. **Не закоммичено** — ждёт команды Alex. ### 🔴 Актуальная форма сценария в YAML (принята Alex, 2026-09-17) @@ -450,13 +456,18 @@ diff A.txt B.txt # пусто = round-trip чистый |---|---|---| | `id: 9691`, `name` | `#Z9691=11,…` | 1, 2 | | `enabled: true` | `#Z9691` поле 5 | `not (f5 & 8)` | -| `_f5` | `#Z9691` поле 5 | `f5` целиком (не выводится из остального) | +| `type: trigger` | `#Z9691` поле 5 | `f5 & 7` — выводится из тела (см. §5j «Поле `type`») | +| `days` / `days_mask` / `time` | `#Z9691` поля 3, 4 | у `schedule`; у остальных пусто | +| `interval_ms` | `#Z9691` поле 6 | у `interval` | | `trigger[].id: 9729` | `#Z9729=49,…` | 1 (id условия) | | `trigger[].object: 9495` | `#Z9729` | 2 (объект) | | `trigger[].value: 1` | `#Z9729` | 4 (значение; поле 3 = оператор → `_op` если ≠ 1) | | `steps[].id: 9819` | `#Z9819=46,…` | 1 (id шага) | | `steps[].action: 9563` | `#Z9819` | 4 (первый id из `[9563]`) | +> 🔴 `_f5` в таблице **больше нет** — поле 5 восстанавливается из `enabled` + `type`. Строка +> оставлена только как явное «снято», чтобы не вернуться к служебному ключу. + ### 🔴 Секции-дубли убраны (2026-09-17) Раньше каждый сценарный объект (45/46/47/48/49/50/59) жил **дважды**: тело инлайн в `steps[]` @@ -1057,33 +1068,81 @@ steps?!»). В конфиге условие лежит внутри `#Z9819` ( (энкодеру нужно поле 5 целиком). 5. **`yaml`-теги вида `object: '9495'` — строкой** (id объекта), как в `trigger.id`. -### ✅ Поле 5 типа 11 — ЧЕТЫРЕ ТИПА + `enabled` (подтверждено Alex, 2026-09-17) +### ✅ Поле 5 типа 11 — ЧЕТЫРЕ ТИПА + `enabled` (подтверждено Alex + прибором, 2026-09-17) Alex назвал типы прямо: **`manual`, `trigger`, `interval`, `schedule`**. -Сводка по боевому конфигу (70 сценариев): +Сводка по боевому конфигу (70 сценариев). 🔴 **Включённые значения `schedule`/`interval` +получены тостингом на приборе** (Alex включил `8597` и `8599` в UI, конфиг снят заново → `0` и `2`): | ТИП | enabled | поле 5 | шт | кто | |---|---|---|---|---| | `trigger` | вкл | `1` | 64 | все «Автомат.: …» (ВКЛ и ВЫКЛ, по 32) | | `manual` | вкл | `0` | 1 | `11109` Передернуть Автомат Котельной | -| `trigger` | выкл | `9` | 2 | `8547` «по времени», `8551` «по триггеру» | -| `schedule` | выкл | `8` | 1 | `8597` «по расписанию» | -| `interval` | выкл | `10` | 1 | `8599` «по интервалу» | +| `schedule` | вкл | `0` | 1 | `8597` «по расписанию» | +| `interval` | вкл | `2` | 1 | `8599` «по интервалу» | | `manual` | выкл | `8` | 1 | `8456` «Простой тестовый» | +| `schedule` | выкл | `8` | — | (до включения `8597` было `8`) | +| `trigger` | выкл | `9` | 2 | `8547` «по времени», `8551` «по триггеру» | +| `interval` | выкл | `10` | — | (до включения `8599` было `10`) | **Правило (полное, покрывает все 70):** ```text поле5 = тип + 8, если сценарий ВЫКЛЮЧЕН тип: 0 = manual | schedule 1 = trigger 2 = interval -enabled = not (поле5 & 8) ← подтверждено на всех 5 значениях +enabled = not (поле5 & 8) ← подтверждено на всех 7 значениях ``` -Проверка выключенных: `manual 0+8=8` (8456 ✓), `schedule 0+8=8` (8597 ✓), -`trigger 1+8=9` (8547, 8551 ✓), `interval 2+8=10` (8599 ✓). +Проверка обоими направлениями — у **каждого** типа есть вкл/выкл: + +| тип | вкл | выкл | вкл − 8 = выкл ✓ | +|---|---|---|---| +| `manual` | `0` (11109) | `8` (8456) | 0+8=8 ✓ | +| `schedule` | `0` (8597 включён) | `8` (8597 был) | 0+8=8 ✓ | +| `trigger` | `1` (64 шт) | `9` (8547, 8551) | 1+8=9 ✓ | +| `interval` | `2` (8599 включён) | `10` (8599 был) | 2+8=10 ✓ | ⚠️ **`manual` и `schedule` дают одно число `0`** — различаются только полями 3/4 -(`days_mask`, `time`): у `8597` = `61`/`3354`, у `8456` = `0`/`0`. +(`days_mask`, `time`): у `8597` = `61`/`3354`, у `8456` = `0`/`0`. Alex: «manual от schedule +очевидно отличаются наличием блядь schedule!» + +### ✅ Поле `type` в YAML — реализовано в парсере (2026-09-17) + +```yaml +- id: 8597 + name: Тестовый сценарий по расписанию + enabled: true + type: schedule + days: [mon, wed, thu, fri, sat] + days_mask: 61 + time: 13:26 + steps: + - id: 8598 + descr: 'storeev I "инфо событие в пн, ср, чт, пт, сб"' + args: [0, 0, 0] +``` + +Порядок ключей: `id`, `name`, `enabled`, `type`, `days`, `days_mask`, `time`, `interval_ms`, +`_raw_field_count`, далее `trigger`, `steps`. Реализовано переупорядочиванием словаря +после обхода шагов (`config-to-yml.py`, блок `# Reorder so the type sits with the other header fields`). + +🔴 **Правило вывода `type` (текущее, порядок веток важен):** + +```text +trigger: есть поднятый `trigger` (первый шаг — тип 46) +interval: есть `interval_ms` (поле 6) +schedule: есть `days` или `time` +manual: иначе +``` + +⚠️ **ИЗВЕСТНАЯ ОШИБКА в этом правиле:** `#Z11109` получает `type: trigger`, хотя по полю 5 +он **`manual`** (`f5=0`). Причина: у него тоже есть шаг типа 46. Отличие от настоящих trigger — +у `11109` **два** элемента в поле 2 (`11827` шаг + `11828` пауза), у trigger-сценариев — **ровно +один**. Гипотеза правки: `trigger` = **ровно один** элемент в `steps` **и** он типа 46. +**Не проверена** (команда прогона не выполнена — approval timeout). + +Проверено на тот момент: `schedule` (8597) ✓, `interval` (8599) ✓, `trigger` (9628, 9691, 8547, 8551) ✓, +`manual` (8456) ✓, **`manual` (11109) ✗**. **Что опровергнуто и снято (не возвращаться):** @@ -1092,8 +1151,12 @@ enabled = not (поле5 & 8) ← подтвержд - ❌ **Гипотеза «поле5 & 7 = значение из условия шага 46»** — проверена скриптом по всем 70: **32 расхождения**. Пары ВКЛ/ВЫКЛ одной линии (`9628` ВКЛ и `9629` ВЫКЛ) имеют **одинаковое** поле 5 = `1`, но противоположные условия (`1` и `0`). Гипотеза развалилась — **снята**. +- ❌ **Гипотеза «поле5 = 1 ⇔ ровно один шаг 46 с одним действием»** — проверена, дала + «предсказано 0» на всех 70 (индекс поля в скрипте был сдвинут, результат мусорный). **Снята.** - ❌ «Поле 5 не выводится из содержимого» — **неверно**: выводится по правилу выше (`тип` + бит 8). Ранее записанный вывод был получен до того, как Alex назвал типы. +- ❌ Слово «триггерный» как тип сценария — тоже выдумка. Alex: «в смысле блядь триггерные». + Типов ровно четыре, названы Alex: `manual`/`trigger`/`interval`/`schedule`. ### ✅ Служебные ключи — БОЛЬШЕ НЕ НУЖНЫ @@ -1111,17 +1174,47 @@ enabled = not (поле5 & 8) ← подтвержд что писать? Вариант `action: 9563` покрывает только первый. У `11109` их **7** — сейчас уходят в служебный `_then`. **Решение за Alex.** Всё остальное по форме закрыто. +### ⚠️ `run_scenario` — имя вместо id (открыто, 2026-09-17) + +Сценарий может вызывать другой сценарий: `#Z8456` в поле 2 держит **id сценария** `11109` +прямой ссылкой (не отдельным объектом-шагом): + +```text +#Z8456 =11,'Простой тестовый сценарий',[8817,8818,8822,8824,11109,8195,9500,…] +#Z11109=11,'Передернуть Автомат Котельной',[11827,11828],0,0,0,0,0 +``` + +Парсер рендерит это так: + +```yaml +- id: 11109 + run_scenario: Передернуть Автомат Котельной +``` + +🔴 **Проблема:** `id:` здесь вводит в заблуждение — это id **сценария**, а не шага; +отдельного объекта-шага у такой ссылки нет. И `run_scenario` хранит **имя**, а не id — +при переименовании сценария энкодер не найдёт цель. Alex: «нихуя не понял а id step-а?», +«`11109` это id сценария же». + +**Решение за Alex:** `run_scenario` по id (надёжнее) или по имени (читаемее, как сейчас). +Один объект `11109` играет две роли — он самостоятельный сценарий **и** элемент в `steps` у `8456`. + --- ## 6. Состояние проекта (проверено 2026-09-17, финал) -🟡 **Парсер переписан под форму §5j (триггер на уровне сценария), энкодер — ЕЩЁ НЕТ.** +🟡 **Парсер переписан под форму §5j (триггер на уровне сценария + поле `type`), энкодер — ЕЩЁ НЕТ.** Round-trip сейчас **не сходится** — `yml-to-config.py` ждёт перевода. Рабочее дерево **не закоммичено**, ждёт команды Alex. Последний коммит — `199f2b1`. ✅ **Парсер `config-to-yml.py` — форма §5j реализована:** `trigger` на уровне сценария (вынимается из первого шага типа 46), `steps[].{id, action}`, `descr` у шага не выводится, -`if`/`then`/`else`/`condition`/`operator`/`kind` из вывода убраны. +`type` (`manual`/`trigger`/`interval`/`schedule`) выводится из тела, `if`/`then`/`else`/ +`condition`/`operator`/`kind`/`_f5` из вывода убраны. + +🔴 **Известный баг парсера (единственный):** `#Z11109` получает `type: trigger`, хотя он `manual` +(поле 5 = `0`). Гипотеза правки: `trigger` = ровно один элемент в `steps` И он типа 46. +Прогон не выполнен. Детали — §5j. ✅ **Round-trip был чистый на 4/4 конфигах** (§5c, до правки формы). Счётчики совпадали: 661 → 661. **После правки формы — сломан, ждёт энкодера.** @@ -1132,19 +1225,22 @@ Round-trip сейчас **не сходится** — `yml-to-config.py` ждё ✅ **YAML сжат вдвое:** 6093 → 4405 строк. Секции-дубли убраны, поля переименованы (`descr`/`target`/`value`). -✅ **Поле 5 типа 11 — РАСКРЫТО** (§5j): `тип + 8 при выключенном`; +✅ **Поле 5 типа 11 — РАСКРЫТО И ПОДТВЕРЖДЕНО ПРИБОРОМ** (§5j): `тип + 8 при выключенном`; типы `manual`/`trigger`/`interval`/`schedule` (Alex), `enabled = not (f5 & 8)`. +Включённые `schedule`/`interval` добыты тостингом в UI (`8597` → `0`, `8599` → `2`). `_f5` из YAML убран — поле восстанавливается из `enabled` + типа. -⚠️ **Открыт один вопрос:** `steps[].action` при >1 id в поле 4 шага 46 (у `11109` их 7) — §5j. +⚠️ **Открыто два вопроса:** (1) `steps[].action` при >1 id в поле 4 шага 46 (у `11109` их 7); +(2) `run_scenario` — имя или id. Оба — §5j. | Файл | Статус | |---|---| -| `config-to-yml.py` | 🆕 **изменён** — форма §5j: `trigger` на уровне сценария, `steps[].{id, action}`, `_f5`/`_op`/`_then`/`_else`, `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` из тела, `_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». **не закоммичено** | | `test_roundtrip.py` | ✅ в коммите `199f2b1`, без изменений | -| `zont_config/config_local_2026-09-17_17-45-00.txt` | 🆕 **34 963 байт** — **ПОСЛЕДНИЙ** конфиг. Снят с `http://192.168.0.50/config.txt`. **не в git** | -| `zont_config/config_local_2026-09-17_17-45-00.yml` | 🆕 **4405 строк** — **актуальная форма §5j**. **не в 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_17-45-00.txt` / `.yml` | 34 963 байт, 4405 строк — предыдущий (форма §5j, **без** поля `type`). **не в git** | | `zont_config/config_local_2026-09-17_16-13-28.txt` / `.yml` | 34 963 байт, 5560 строк — предыдущая генерация (старая форма). **не в git** | | `zont_config/config_local_2026-09-17_16-02-18.txt` / `.yml` | 34 962 байт — контур `Спальня`, режим `Режим отопления`. **не в git** | | `zont_config/config_local_2026-09-17_14-16-35.txt` / `.yml` | 34 907 байт, 660 `#Z` — с тестовыми сценариями логики. **не в git** | diff --git a/family/tech/zont-scenario-logic-11109.md b/family/tech/zont-scenario-logic-11109.md index 505c76c4..0ab10a0f 100644 --- a/family/tech/zont-scenario-logic-11109.md +++ b/family/tech/zont-scenario-logic-11109.md @@ -1,41 +1,60 @@ # 8.17. ✅ МОДЕЛЬ ЗАКРЫТА (2026-09-17, финал) — поле 5, форма сценария, type 47/49 > **Статус:** все открытые вопросы §8.16 закрыты. Ниже — подтверждённые факты. -> Таблица `TRIGGER_KINDS` **удалена из кода**; доказательство получено **тостингом 5 сценариев -> в UI**: Alex выключил и снова включил каждый тестовый сценарий, поле 5 снято до и после. +> Таблица `TRIGGER_KINDS` **удалена из кода**; доказательство получено **тостингом сценариев +> в UI**: Alex выключил/включил тестовые сценарии, поле 5 снято до и после, плюс повторный +> тостинг `8597`/`8599` дал **включённые** значения `schedule`/`interval` (`0` и `2`). -## (а) 🔴 Поле 5 типа 11 = тип запуска + флаг «выключен». ПОДТВЕРЖДЕНО тостингом +## (а) 🔴 Поле 5 типа 11 = **тип сценария** + флаг «выключен». ПОДТВЕРЖДЕНО прибора + Alex ```text -kind = field5 & 7 # 0 = ручной/расписание, 1 = триггер, 2 = интервал +type = field5 & 7 # 0 = manual | schedule, 1 = trigger, 2 = interval enabled = not (field5 & 8) # бит 8 = сценарий ВЫКЛЮЧЕН ``` -| Сценарий | Выкл | Вкл | `kind` | Прочие поля | +> 🔴 **Слово — `type`, не `kind`.** Слова `kind` в конфиге и UI нет; я его выдумал. Alex: +> «какой нахуй kind?? что это блядь значит?! я его откуда тебе высру?!» Типы назвал Alex: +> **`manual`, `trigger`, `interval`, `schedule`**. + +| Сценарий | Выкл | Вкл | `type` | Прочие поля | |---|---|---|---|---| -| `8456` «Простой тестовый» | `8` | `0` | 0 | — | -| `8597` «по расписанию» | `8` | `0` | 0 | поля 3/4 = `61`, `3354` | -| `8547` «по времени» | `9` | `1` | 1 | — | -| `8551` «по триггеру» | `9` | `1` | 1 | — | -| `9628` «Автомат.: Рад. ванная 2эт ВКЛ» | `9` | `1` | 1 | — | -| `8599` «по интервалу» | `10` | `2` | 2 | поле 6 = `43200000` мс | +| `8456` «Простой тестовый» | `8` | — | 0 = `manual` | — | +| `8597` «по расписанию» | `8` | **`0`** | 0 = `schedule` | поля 3/4 = `61`, `3354` | +| `11109` «Передернуть Котельной» | — | `0` | 0 = `manual` | 2 элемента в поле 2 | +| `8547` «по времени» | `9` | — | 1 = `trigger` | — | +| `8551` «по триггеру» | `9` | — | 1 = `trigger` | — | +| `9628` «Автомат.: Рад. ванная 2эт ВКЛ» | `9` | `1` | 1 = `trigger` | — | +| `8599` «по интервалу» | `10` | **`2`** | 2 = `interval` | поле 6 = `43200000` мс | + +**🔴 Включённые `0` (8597) и `2` (8599) получены тостингом на приборе:** Alex включил оба +сценария в UI, конфиг снят заново (`curl -s http://192.168.0.50/config.txt`). До этого момента +включённые значения `schedule`/`interval` были неизвестны — были только выключенные `8`/`10`. + +**Итог: у каждого типа есть вкл/выкл, и всегда `вкл + 8 = выкл`:** + +| тип | вкл | выкл | +|---|---|---| +| `manual` | `0` (11109) | `8` (8456) | +| `schedule` | `0` (8597) | `8` (был) | +| `trigger` | `1` (64 шт) | `9` (8547, 8551) | +| `interval` | `2` (8599) | `10` (был) | + +> ⚠️ **`manual` (0) и `schedule` (0) — один и тот же `type`.** Различаются **наличием полей 3/4** +> (`days_mask` + `time`): у расписания они заполнены, у ручного — нули. Alex: «manual от schedule +> очевидно отличаются наличием блядь schedule!» +> Кодировку расписания см. §8.1 (`61` = ПН,СР,ЧТ,ПТ,СБ; `3354` = `(13<<8)|26` = 13:26). **Почему старая модель `{0:manual,1:manual,8:schedule,9:trigger,10:interval}` была неверна:** она читала число как «класс запуска» целиком. На самом деле число **двухбитовое по смыслу**: -младшие 3 бита = тип, бит `8` = выключено. Отсюда все противоречия §8.16: -`9628` с `1` — триггерный (бит 8 не стоит, kind = 1), `8456` с `8` — ручной, но выключенный. +младшие 3 бита = тип, бит `8` = выключено. Отсюда все противоречия §8.16. -> ⚠️ **Ручной (0) и расписание (0) — один и тот же `kind`.** Различаются **наличием полей 3/4** -> (`days_mask` + `time`): у расписания они заполнены, у ручного — нули. -> Кодировку расписания см. §8.1 (`61` = ПН,СР,ЧТ,ПТ,СБ; `3354` = `(13<<8)|26` = 13:26). +> ❌ **Снятые гипотезы (не возвращаться):** «`field5 & 7` = значение из условия шага 46» +> (32 расхождения из 70 — пары ВКЛ/ВЫКЛ `9628`/`9629` имеют одинаковое поле `1` при +> противоположных условиях); «поле 5 не выводится из содержимого» (выводится: тип + бит 8). **Что в коде:** `TRIGGER_KINDS`, `_raw_trigger_kind`, `_raw_trigger_params`, `time_raw` **удалены**. -Заголовок сценария в YAML теперь: `enabled`, `_f5` (поле 5 целиком), `_kind` (только если -`f5 & 7 ≠ 0`), `days_mask`, `time`, `interval_ms`. - -> ⚠️ **Обновлено после правок формы:** `kind`/`kind_raw` из видимой части **убраны** — это тоже -> была выдумка (слова `kind` в конфиге нет). Всё, что нужно энкодеру, лежит в служебных -> `_f5`/`_kind` с подчёркиванием. +Заголовок сценария в YAML теперь: `enabled`, **`type`**, `days`/`days_mask`, `time`, `interval_ms`. +Служебные `_f5`/`_kind` **тоже убраны** — поле 5 полностью восстанавливается из `enabled` + `type`. ## (б) Форма YAML сценария — ПЕРЕСМОТРЕНА Alex'ом (финал сессии) @@ -115,11 +134,12 @@ Alex отверг `if`/`then`/`else` в YAML как **выдумку**: | # | Что | Статус | |---|---|---| | 1 | `dump_condition` type 49 → `{id, object, value}` вместо `{id, condition: {object, operator, value}}` | ✅ сделано | -| 2 | `dump_step` type 46 → `{id, trigger: <условие>, action: <первый then id>}`, без `if`/`then`/`else` | ✅ сделано | -| 3 | Заголовок сценария — `kind`/`kind_raw` убраны в служебные `_kind`/`_f5` | ✅ сделано | +| 2 | `dump_step` type 46 → `{id, action: <первый then id>}`; `trigger` **вынимается на уровень сценария** | ✅ сделано | +| 3 | Заголовок сценария — `kind`/`kind_raw`/`_kind`/`_f5` **убраны**, вместо них видимое поле **`type`** | ✅ сделано | | 4 | Непустые `then`/`else` / второй+ id → что писать в форме | 🔴 **открытый вопрос, ждёт Alex** | -| 5 | `dump_action` — делегирование в `dump_step` (чтобы type 5/9 в телах не падали в `raw`) | ✅ сделано (было раньше) | -| 6 | Энкодер под новую форму | ⏸ не начат — ждёт подтверждения формы | +| 5 | `dump_action` — делегирование в `dump_step` (чтобы type 5/9 в телах не падали в `raw`) | ✅ сделано | +| 6 | Энкодер под новую форму | ⏸ **не начат** — ждёт подтверждения формы. Round-trip сломан | +| 7 | `type` для `11109` выходит `trigger` вместо `manual` | ⚠️ **баг**, гипотеза правки: `trigger` = ровно один элемент в `steps` И он типа 46. Прогон не выполнен | ### ✅ Фактический вывод парсера после правок (проверено 2026-09-17)