[2026-09-17] eagle: family/how-to/zont-config-compiler.md family/tech/zont-scenario-logic-11109.md
This commit is contained in:
@@ -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 их не добавлял. Не коммитить без команды.
|
||||
|
||||
**Содержимое проекта, не относящееся к конвертерам:**
|
||||
|
||||
|
||||
Reference in New Issue
Block a user