diff --git a/family/how-to/zont-config-compiler.md b/family/how-to/zont-config-compiler.md index 9e4d4447..6c4b3de1 100644 --- a/family/how-to/zont-config-compiler.md +++ b/family/how-to/zont-config-compiler.md @@ -20,7 +20,7 @@ tags: - homeautomation title: ⚙️ ZONT Config Compiler — конвертеры .txt ⇄ .yml type: how-to -updated: '2026-09-17e' +updated: '2026-09-17g' --- # ⚙️ ZONT Config Compiler — конвертеры `.txt ⇄ .yml` @@ -32,7 +32,7 @@ updated: '2026-09-17e' |---|---| | **Проект (Mac)** | `/Users/admin/Automation/HA-ZONT-Modbus` | | **Repo (private)** | `https://git.mallexxx.duckdns.org/git_admin/HA-ZONT-Modbus` | -| **Скрипты** | `config-to-yml.py` (TXT → YAML) · `yml-to-config.py` (YAML → TXT) | +| **Скрипты** | `config-to-yml.py` (TXT → YAML) · `yml-to-config.py` (YAML → TXT) · `test_roundtrip.py` (проверка целостности) | | **Конфиги** | `zont_config/` — свежие · `zont_config/archive/` — историчные | | **Типы объектов** | [[family/tech/zont-config-object-types]] | | **ZONT в общем контуре** | [[family/how-to/home-automation]] §6 | @@ -253,21 +253,41 @@ grep -c '^#Z' /tmp/zont_new.txt ## 4. Проверка целостности (round-trip) -`README_converters.md` заявляет round-trip **130/130 объектов**: TXT → YAML → TXT даёт идентичный файл. +✅ **Есть готовый скрипт — `test_roundtrip.py`** (в репо с 2026-09-17, коммит `199f2b1`). +Делает `TXT → YAML → TXT`, сравнивает **множеством строк** с нормализацией кодировки +(источник UTF-8 или windows-1251, выход всегда windows-1251). Exit: `0` чисто / `1` расхождения / `2` ошибка запуска. -Команда для проверки на любом конфиге: +```bash +cd /Users/admin/Automation/HA-ZONT-Modbus +python3 test_roundtrip.py # свежий конфиг из zont_config/ +python3 test_roundtrip.py zont_config/archive/H2000_PRO_config_actual-4.txt +``` + +Вывод при успехе: `✅ ROUND-TRIP ЧИСТЫЙ — расхождений нет` + счётчики `#Z` до/после. + +### Ручная проверка (если скрипт недоступен) ```bash cd /tmp && rm -rf zont-rt && mkdir zont-rt && cd zont-rt SRC=/Users/admin/Automation/HA-ZONT-Modbus/zont_config/<файл>.txt -python3 /Users/admin/Automation/HA-ZONT-Modbus/config-to-yml.py "$SRC" > a.yml +python3 /Users/admin/Automation/HA-ZONT-Modbus/config-to-yml.py "$SRC" > a.yml # проверить exit! python3 /Users/admin/Automation/HA-ZONT-Modbus/yml-to-config.py a.yml > b.txt -tr -d '\r' < "$SRC" > A.txt; tr -d '\r' < b.txt > B.txt +iconv -f cp1251 -t utf-8 "$SRC" | tr -d '\r' | sort > A.txt +iconv -f cp1251 -t utf-8 b.txt | tr -d '\r' | sort > B.txt diff A.txt B.txt # пусто = round-trip чистый -grep -c '^#Z' A.txt B.txt # счётчик объектов ``` -> 📌 **Нюанс кодировки:** источник бывает в UTF-8, а `yml-to-config.py` всегда пишет windows-1251 → наивный `diff` покажет различия на кириллице. Сравнивать структуру и числовые поля, либо нормализовать кодировку с обеих сторон. +> 🔴 **Сравнивать множеством строк (`sort` + `diff`), НЕ построчно.** `yml-to-config.py` пишет объекты +> в порядке `TYPE_ORDER`, а в исходном файле порядок другой → наивный `diff` даёт ~56 **ложных** +> расхождений при полностью корректной конвертации. + +> 📌 **Нюанс кодировки:** источник бывает в UTF-8, а `yml-to-config.py` всегда пишет windows-1251 → наивный `diff` покажет различия на кириллице. Нормализовать кодировку с обеих сторон (`iconv`), как в командах выше. + +> ⚠️ **`>` в шелле затирает целевой файл ещё до старта питона** — поэтому рядом с непустым `.txt` +> появляется пустой `.yml`. Это признак **падения** конвертера на конкретном объекте: смотреть stderr. + +> 🔴 **Не проверять результат через пайп** (`iconv … | grep -c`). Пустой промежуточный файл в пайпе +> даёт ложный «успех». Смотреть `wc -c` целевого файла напрямую. (Реальный случай 2026-09-17 — см. питфолл 16.) --- @@ -290,6 +310,11 @@ grep -c '^#Z' A.txt B.txt # счётчик объектов | 13 | ✅ **ИСПРАВЛЕНО 2026-09-17** — Тип 45 (задержка, мс) не был поддержан | Парсер + эмиттер, секция YAML `delays`. См. §5b | | 14 | ⚠️ `>` в шелле затирает `.yml` до старта питона | Проверять exit-код до переноса файла в репо | | 15 | ⚠️ Один шаг может принадлежать нескольким сценариям | `yml-to-config.py` использует хелпер `_register()` — обновляет запись по id, а не добавляет дубль | +| 16 | 🔴 **`iconv … \| grep` в пайпе маскирует пустой файл** | Промежуточный `b.txt` был 0 байт, а `grep -c` в пайпе отработал «успешно» → ложный вывод «598 → 598, чисто». **Проверять `wc -c` целевого файла напрямую**, а не через пайп | +| 17 | 🔴 **Правка `parse_atom` ради `1.0` ломает `_raw_*`-путь** | Первая попытка нормализовала whole-float → int; `_raw_divider` стал мёртвым кодом (`isinstance(v[6], int)` не срабатывал). Итог: **whole-float остаётся float** — иначе энкодер печатает `1` вместо `1.0` | +| 18 | 🔴 **Порядок объектов в файле ≠ порядок типов в `TYPE_ORDER`** | Сравнение «как есть» даёт ~56 ложных расхождений. Сравнивать **множеством строк** (`sort` + `diff`), порядок не значим | +| 19 | ⚠️ **Негативный тест-детектор проверять реальной порчей** | Подмена `id: 11109` → `111099` ничего не ломает (id косметический). Ловить нужно удаление объекта: снести `delays[11824]` → детектор обязан сработать | +| 20 | 🔴 **`read_file` возвращает контент с номерами строк — не patch-ить им vault** | Правки Obsidian-заметок делать **через obsidian-MCP** (`mcp_obsidian_patch_note`), не файловыми скриптами. Alex 2026-09-17: «какого хуя ты скриптами лезешь в обсидиан» | ### Ограничения конвертера (найдено 2026-09-17) — ВСЕ ЗАКРЫТЫ @@ -340,50 +365,141 @@ grep -c '^#Z' A.txt B.txt # счётчик объектов - `ast.parse()` на обоих файлах — синтаксис OK - `config-to-yml.py` на боевом конфиге: **больше не падает** на сценарии `11109` (ранее `Ошибка: Сценарий 11109: поддерживается только 1 шаг`, exit 2) +- ✅ **Round-trip целиком — ПРОЙДЕН на всех 4 конфигах** (см. §2.2). Сверка по множеству строк с нормализацией кодировки. -### Что НЕ проверено (осталось) +### Коммит -- ⏳ **Round-trip целиком**: `TXT → YAML → TXT`, сверка 598 объектов, `diff` чистый. Команда требует апрува, была запущена и истекла по таймауту. +✅ **Закоммичено 2026-09-17 — `199f2b1`** «Support multi-step scenarios, delays (type 45) and multi-action steps». +3 файла, +327/−75. В коммит вошли: `config-to-yml.py`, `yml-to-config.py`, `test_roundtrip.py`. -### План дальше (этапы 2–3, ждут Alex) +Не запушено (`origin/main..HEAD` = 3 коммита впереди) — пуш ждёт команды Alex. -**Этап 2 — правка YAML** под новую логику (только после ответа Alex на вопрос: (а) просто `enabled: true` для «Передернуть Автомат Котельной» / (б) добавить триггер по событию / (в) другое). +--- -**Этап 3 — `YAML → TXT`, сверка счётчиков, коммит ДО → Alex заливает руками → Alex проверяет руками → коммит ПОСЛЕ.** +## 5c. 🔄 Переработка структуры YAML сценариев — ПЛАН, ждёт апрува (2026-09-17) -> 🔴 Порядок работ с боевыми конфигами: **коммит ДО → правка → заливка → ПРОВЕРКА АЛЕКСОМ руками → коммит ПОСЛЕ**. Мой `read back` = «конфиг записался», НЕ «работает». +**Задача Alex:** «переписать блок парсинга/сборки сценариев чтобы он составлял синтаксис как у Home Assistant automations вместо текущей разбросанной структуры. с опциональными айдишниками у операторов». + +### 🔴 Правка постановки Alex'ом (ключевое — не повторять ошибку) + +Первая версия плана натягивала **HA-синтаксис** (`triggers` / `platform: state` / `to:`) на ZONT-логику. +Alex отклонил: + +> «нет структура должна быть как в zont. **триггеров нет.** у нас сценарий Передернуть Автомат Котельной буквально содержит вложенные инструкции: **если ... то... итд.** не надо натягивать сову структуры на глобус HA syntax.» + +**Правило:** в ZONT **нет триггеров** — роль триггера играет само изменение реле, а сценарий читается +как вложенные инструкции «если … то …». Структура YAML должна повторять ZONT, а не HA. + +### Утверждённая форма (предложена, ждёт финального ОК по двум вопросам) + +```yaml +scenarios: + - id: 11109 + name: 'Передернуть Автомат Котельной' + enabled: false + blocks: + - id: 11827 # шаг (46) + if: + id: 11823 # условие (49), id опционален + relay: 11190 + operator: equals # equals | not_equals + value: 0 + then: + - {id: 11191, action: relay_on, relay: 11190} + - {id: 11030, action: relay_off, relay: 11028} + - {id: 11824, action: wait, ms: 20000} + - {id: 11029, action: relay_on, relay: 11028} + - {id: 11825, action: wait, ms: 60000} + - {id: 11192, action: relay_off, relay: 11190} + - {id: 11826, action: wait, ms: 0} + tail: # хвостовые задержки из поля 2 + - {id: 11828, action: wait, ms: 0} +``` + +**Что меняется по сравнению с текущим YAML:** + +| Сейчас (разбросано) | Станет | +|---|---| +| `scenarios[].when` / `.then` — плоский дубль для 1-шаговых | убрано: **одна форма** `blocks[].if/.then` для всех 65 | +| `scenarios[].steps[]` + отдельные `delays` / `scenario_conditions` / `scenario_steps` | одна вложенная структура `blocks` | +| `wait` лежит отдельной секцией верхнего уровня | `wait` — **внутри** `then`, по месту срабатывания | +| `extra_links: [11828]` — голые id | `tail:` с блоками `wait` | + +**Открытые вопросы (заданы Alex, ответа ещё нет):** +1. Имена ключей: `blocks`/`if`/`then` — или ближе к терминам ZONT `steps`/`condition`/`actions`? +2. Пауза в конце (`11826`, `ms: 0`) — оставлять как `wait` (честно для round-trip) или схлопывать? + +**План работ (после апрува):** +1. `config-to-yml.py` — блок type 11: генерировать `blocks[].if/then`; `wait` (45) встраивать в `then`; `tail` для хвостовых +2. `yml-to-config.py` — обратный разбор `blocks`; **поддержать старые формы** (`when`/`then`, `steps`) для совместимости +3. `test_roundtrip.py` — все 4 конфига должны остаться чистыми +4. Доки — обновить §2.1 этой заметки + +**Обязано сохраниться байт-в-байт (риск round-trip):** +- порядок объектов в файле (45 идёт **после** 11, но **до** 46) +- `extra_links` — хвостовые задержки в поле 2 сценария +- число полей (7 vs 8) и `_raw_*`-поля (`_raw_field_count`, `_raw_field3`, `_raw_divider`) — **не удалять** + +**Бэкап:** коммит `199f2b1` уже есть — откат возможен в любой момент, отдельных копий не делать. + +--- + +## 5d. Что делает сценарий 11109 — и что логика УЖЕ есть + +Разбор по факту (не гипотеза) — подробно в [[family/tech/zont-scenario-logic-11109]]: + +**Порядок действий шага `11827`:** + +``` +вкл virt.Запретить(11191) → выкл Автомат(11030) → пауза 20 с(11824) +→ вкл Автомат(11029) → пауза 60 с(11825) → выкл virt.Запретить(11192) → пауза 0(11826) +``` + +Условие `11823`: `virt.Запретить(11190) == 0`. Смысл — **защита от повторного передёргивания**: +реле ставится в 1 первым действием, условие требует 0 → пока реле в 1, сценарий не перезапустится. +Минимальный интервал между передёргиваниями = 80 с (20+60). + +> 🔴 **Защита в конфиге УЖЕ есть.** Поле v[5] сценария = `0` → сценарий **выключен в контроллере**, +> поэтому защита и функция передёргивания не работают. Вопрос «дописать логику» на деле может быть +> «включить существующую» (`enabled: true`) — это НЕ подтверждено Alex'ом, не додумывать. + +--- + +## 5f. Ответы на вопросы постановки (этап 2 снят) + +Вопрос Alex'у «что именно не хватает на сценариях» (варианты а/б/в) **закрыт его же реакцией**: задача — +«дописать парсер и энкодер», а не править логику. Правка YAML сценария `11109` (этап 2 прежнего плана) +с повестки снята — работа ограничена конвертерами. + +> 🔴 **Урок коммуникации 2026-09-17.** Alex дважды резко реагировал на развёрнутые планы-опросники +> («нихуя не понял тебе че надо блядь? что блядь сломано?», «ТЫ ХУЛИ ВСТАЛ БЛЯДЬ!?»). Что сработало: +> **сжатый факт «что сломано» + сразу делать**. Не задавать уточняющих вопросов там, где симптом уже +> назван; не строить гипотезы вместо чтения конфига; не планировать сверх постановки. > ⚙️ **Бэкап кода — только git, не `/tmp`.** Alex 2026-09-17: «какой нахуй бэкап скриптов — там в гите все». Изменения скриптов откатываются через git, отдельные копии в `/tmp/` не делать. --- -## 6. Состояние проекта (проверено 2026-09-17) +## 6. Состояние проекта (проверено 2026-09-17, вечер) -Репозиторий `/Users/admin/Automation/HA-ZONT-Modbus` — **рабочее дерево грязное**, разгребание ждёт отдельной команды Alex: +✅ **Конвертеры закоммичены — `199f2b1`.** Рабочее дерево чистое (после этого коммита). | Файл | Статус | |---|---| -| `zont_config/H2000_PRO_config_actual-2.txt` / `-2.yml` | удалены из индекса (целы в `zont_config/archive/`) | -| `zont_config/H2000_PRO_config_actual-3.txt` / `-3.yml` | то же | -| `zont_config/H2000_PRO_config_actual-4.txt` / `-4.yml` | то же | -| `zont_config/archive/` | не добавлена в git | -| `zont_config/config_0FA7C33CC89F_…_2026-09-17_12-12-28.txt` | 32 689 байт — свежеснятый конфиг с контроллера, не закоммичен | -| одноимённый `.yml` | **0 байт** — см. причину ниже | -| `config-to-yml.py`, `yml-to-config.py` | ✅ **изменены 2026-09-17** (§5b) — не закоммичены | +| `config-to-yml.py`, `yml-to-config.py` | ✅ **изменены и закоммичены** (`199f2b1`, §5b) | +| `test_roundtrip.py` | ✅ **новый файл**, в коммите `199f2b1` | +| `zont_config/config_0FA7C33CC89F_…_2026-09-17_12-12-28.txt` | 32 689 байт — свежий конфиг с контроллера, **не в git** (`untracked`) | +| одноимённый `.yml` | ✅ **пересобран, 80 472 байта / 4320 строк / 24 секции**, YAML валиден. **не в git** | +| `zont_config/archive/` | **не в git** (`untracked`) — лежит в `.gitignore`-нейтральном состоянии | +| `zont_config/H2000_PRO_config_actual-{2,3,4}.txt` / `.yml` | ✅ **перемещены в `archive/` и закоммичены** (`7ae0e32`) | -> 🔴 **Причина пустого `.yml` (0 байт) — найдена 2026-09-17.** `config-to-yml.py` падал с exit 2 на **первом** невыразимом объекте и не писал ничего: -> -> ``` -> $ python3 config-to-yml.py zont_config/config_0FA7C33CC89F_…_2026-09-17_12-12-28.txt > /tmp/zont.yml -> Ошибка: Сценарий 11109: поддерживается только 1 шаг -> EXIT=2 → /tmp/zont.yml = 0 байт -> ``` -> -> ✅ **Исправлено 2026-09-17** — сценарий `11109` теперь разбирается (он двухшаговый). Причина исчезла. -> -> Проверка: `.yml` 0 байт **всегда** означает, что конвертер не «не доехал», а **упал на конкретном объекте**. Смотреть stderr, а не перезапускать вслепую. -> -> ⚠️ `>` в шелле **затирает целевой файл ещё до старта питона** — поэтому рядом с непустым `.txt` появляется пустой `.yml`. Писать через `>/tmp/out.yml` и только после успешного exit-кода переносить в репо. +Не запушено: `origin/main..HEAD` = 3 коммита (`199f2b1`, `7ae0e32`, `12ba22b`). + +> ✅ **Пустой `.yml` (0 байт) больше не актуален** — причина была в падении на сценарии `11109`, +> которое исправлено (§5b). Файл пересобран, 598 объектов. + +**Что НЕ в git и почему:** `.txt` свежего конфига и его `.yml` — рабочие артефакты конвертации, +Alex их не добавлял. Не коммитить без команды. **Содержимое проекта, не относящееся к конвертерам:** diff --git a/family/tech/zont-scenario-logic-11109.md b/family/tech/zont-scenario-logic-11109.md index cc77fc96..a01474fb 100644 --- a/family/tech/zont-scenario-logic-11109.md +++ b/family/tech/zont-scenario-logic-11109.md @@ -4,6 +4,7 @@ aliases: - Передернуть Автомат Котельной - ZONT тип 45 задержка - ZONT сценарная логика + - ZONT поле 2 сценария created: '2026-09-17' namespace: family related: @@ -18,7 +19,7 @@ tags: - homeautomation title: 🔁 ZONT — сценарная логика (типы 11 / 46 / 49 / 45) type: tech -updated: '2026-09-17' +updated: '2026-09-17b' --- # 🔁 ZONT — сценарная логика (типы 11 / 46 / 49 / 45) @@ -68,7 +69,8 @@ updated: '2026-09-17' ## 3. Разобранный кейс: `#Z11109` «Передернуть Автомат Котельной» -**Единственный сценарий в конфиге с нестандартной формой** — 2 шага и 7 действий в одном шаге. +**Единственный сценарий в конфиге с нестандартной формой** — 7 действий в шаге и задержка (`45`) +прямо в поле 2 сценария (`11828`) вместо второго шага. См. §5 «Уточнение семантики поля 2». ``` #Z11109=11,'Передернуть Автомат Котельной',[11827,11828],0,0,0,0,0 @@ -100,7 +102,8 @@ updated: '2026-09-17' | 6 | `11192` (type 9) | выключить `virt. Запретить передергивание` | — | | 7 | `11826` (type 45) | пауза | 0 | -**Шаг 2 (`11828`)** — `[45, 0]`, пустая пауза-заглушка. Оставлен планировщиком ZONT, функциональной нагрузки не несёт. +**Шаг 2 (`11828`)** — на деле это не шаг, а **задержка** `[45, 0]` прямо в поле 2 сценария: +пустая пауза-заглушка. Оставлена планировщиком ZONT, функциональной нагрузки не несёт. ### Смысл логики @@ -142,11 +145,60 @@ updated: '2026-09-17' | Многошаговый сценарий (`[11827,11828]`) | ✅ разбирается с 2026-09-17 | | 7 действий в шаге `11827` | ✅ разбирается с 2026-09-17 | | Тип 45 (4 объекта) | ✅ парсер + эмиттер, секция YAML `delays` | -| Сценарий `enabled=0` | ℹ️ факт, не баг конвертера — решается на этапе 2 (правка YAML) | +| Round-trip всех 4 конфигов | ✅ чисто (`test_roundtrip.py`, коммит `199f2b1`) | +| Сценарий `enabled=0` | ℹ️ факт, не баг конвертера | + +### 🔴 Уточнение семантики поля 2 (важно) + +Поле 2 сценария — **не «список шагов»**, а **последовательность ссылок**, куда попадают объекты +**разных типов**. Полный список: шаг (`46`) **и** задержка (`45`). + +В `#Z11109` поле 2 = `[11827, 11828]`, где: +- `11827` — настоящий шаг (`46`) с условием и 7 действиями; +- `11828` — **задержка (`45,0`)**, т.е. «шаг-ожидание» без условия. + +Поэтому формулировка «2 шага» неточна: **шаг один**, вторым элементом идёт задержка-заглушка. +Отсюда же — `extra_links` в YAML (см. [[family/how-to/zont-config-compiler]] §2.1): не-46 ссылки +сохраняются дословно, чтобы round-trip остался байт-точным. + +> ⚠️ **Не путать с типом 45 внутри шага.** В `11827` задержки `11824`/`11825`/`11826` — это +> **действия внутри** шага. `11828` — **ссылка в поле 2 сценария**, т.е. элемент верхнего уровня. --- -## 6. Связанные заметки +## 6. План переработки YAML-структуры (2026-09-17, ждёт апрува) + +Сценарии в YAML переписываются в нативную ZONT-форму **вложенных инструкций «если … то …»** — +**без HA-синтаксиса** (`triggers`, `platform: state`). Alex: «нет структура должна быть как в zont. +**триггеров нет.**» + +Предлагаемая форма для `11109`: + +```yaml +scenarios: + - id: 11109 + name: 'Передернуть Автомат Котельной' + enabled: false + blocks: + - id: 11827 + if: {id: 11823, relay: 11190, operator: equals, value: 0} + then: + - {id: 11191, action: relay_on, relay: 11190} + - {id: 11030, action: relay_off, relay: 11028} + - {id: 11824, action: wait, ms: 20000} + - {id: 11029, action: relay_on, relay: 11028} + - {id: 11825, action: wait, ms: 60000} + - {id: 11192, action: relay_off, relay: 11190} + - {id: 11826, action: wait, ms: 0} + tail: + - {id: 11828, action: wait, ms: 0} # задержка из поля 2 сценария +``` + +Полный план и открытые вопросы — [[family/how-to/zont-config-compiler]] §5c. + +--- + +## 7. Связанные заметки - [[family/how-to/zont-config-compiler]] — конвертеры `.txt ⇄ .yml`; 2 шага и тип 45 **поддержаны с 2026-09-17** (§5b) - [[family/tech/zont-config-object-types]] — полная таблица типов объектов и `#S`-настройки