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

This commit is contained in:
Alexey Martemyanov
2026-09-17 11:54:10 +06:00
parent c384bab511
commit f9e4e19dad
+93 -111
View File
@@ -1,162 +1,144 @@
--- ---
title: ⚙️ ZONT Config Compiler — конвертеры .txt ⇄ .yml
aliases: aliases:
- ZONT config compiler - ZONT config compiler
- config-to-yml - config-to-yml
- yml-to-config - yml-to-config
- HA-ZONT-Modbus - HA-ZONT-Modbus
- ZONT конфиг конвертеры - ZONT конвертеры конфига
created: '2026-09-17'
namespace: family
related:
- '[[family/tech/zont-config-object-types]]'
- '[[family/how-to/home-automation]]'
- '[[family/how-to/gitea-config]]'
tags: tags:
- family - family
- how-to - how-to
- zont - zont
- modbus - modbus
- homeautomation - homeautomation
created: '2026-09-17' title: ⚙️ ZONT Config Compiler — конвертеры .txt ⇄ .yml
updated: '2026-09-17'
type: how-to type: how-to
namespace: family updated: '2026-09-17'
related:
- '[[family/tech/zont-config-object-types]]'
- '[[family/how-to/home-automation]]'
- '[[family/how-to/gitea-config]]'
--- ---
# ⚙️ ZONT Config Compiler — конвертеры конфига (.txt ⇄ .yml) # ⚙️ ZONT Config Compiler — конвертеры `.txt ⇄ .yml`
> **Что это:** двусторонние конвертеры между форматом конфига контроллера **ZONT** (`.txt`) и читаемым **YAML**. Позволяют править конфиг руками (имена реле, адреса Modbus, датчики), не лазя в UI контроллера. Двусторонние конвертеры между конфигом контроллера **ZONT** (`.txt`) и читаемым **YAML**.
> **Справочник типов объектов:** [[family/tech/zont-config-object-types]] Позволяют править конфиг руками — имена реле, адреса Modbus, интервалы опроса, датчики — не заходя в UI контроллера.
> **Контекст (ZONT в общем контуре, slave ID, регистры):** [[family/how-to/home-automation]] §6
> **Repo (private):** `https://git.mallexxx.duckdns.org/git_admin/HA-ZONT-Modbus` — [[family/how-to/gitea-config]]
---
## 1. Где лежит
| | | | | |
|---|---| |---|---|
| **Локальный путь (Mac)** | `/Users/admin/Automation/HA-ZONT-Modbus` | | **Проект (Mac)** | `/Users/admin/Automation/HA-ZONT-Modbus` |
| **Git remote** | `https://git.mallexxx.duckdns.org/git_admin/HA-ZONT-Modbus.git` (private) | | **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) |
| **README конвертеров** | `README_converters.md` в корне проекта | | **Конфиги** | `zont_config/` — свежие · `zont_config/archive/` — историчные |
| **Рабочие конфиги** | `zont_config/` (свежие), `zont_config/archive/` (историчные `H2000_PRO_config_actual-*`) | | **Типы объектов** | [[family/tech/zont-config-object-types]] |
| **Инфраструктурный контекст проекта** | `INFRASTRUCTURE.md` в корне — **описывает старый стек на TrueNAS** (docker-контейнеры `homeassistant`/`modbus-bridge`/`mbusd` там уже погашены, автоматизация переехала на t610). Актуальный контур — [[family/how-to/home-automation]] | | **ZONT в общем контуре** | [[family/how-to/home-automation]] §6 |
> ⚠️ `INFRASTRUCTURE.md` + `docker-compose.yml` + `docker run.txt` в репозитории — **исторические** (TrueNAS-стек). Не использовать как инструкцию по текущей инфраструктуре. ---
> 🔴 `zont_config/*.yml` в репозитории частично удалены/пересозданы — `git status` в проекте грязный (6 удалений + новые файлы незакоммичены).
## 1. Формат конфига ZONT
Текстовый файл, одна запись = одна строка, разделитель строк **CRLF**, кодировка **windows-1251**:
```
#Z<id>=<тип>,<поле>,<поле>,…
#S<id>=<значение>
```
| Префикс | Что это | Пример |
|---|---|---|
| `#Z<id>` | объект конфига: реле, датчик, сценарий, Modbus-устройство | `#Z12=14,'Спальня левый',…` — id 12, тип 14 (реле) |
| `#S<id>` | системная настройка | `#S7=H2000_PRO 723 678` — модель и версии ПО |
- Тип объекта — **первое поле** после `=`.
- Строки — в `'одинарных кавычках'`, списки — `[...]`, числа — как есть.
- `#Z<id>=*` — служебный маркер (пустой/унаследованный объект).
- **Порядок строк значим** и сохраняется при конвертации.
--- ---
## 2. Как работает ## 2. Как работает
### Формат конфига ZONT ### `config-to-yml.py` — TXT → YAML
Текстовый файл, по одной записи на строку, **CRLF**, кодировка **windows-1251** (fallback чтения — UTF-8): 1. Читает файл, определяет кодировку: UTF-8, при неудаче — windows-1251.
2. Парсит строки регекспом `^#([ZS])(\d+)=(.*)$` (хвостовые пробелы в payload сохраняются).
3. `split_payload()` — режет payload по запятым **с учётом кавычек и вложенных `[…]`**.
4. `parse_atom()` — пусто/`''``None`, `'строка'` → строка, `[…]` → список, иначе int → float → строка.
5. Раскладывает объекты по секциям YAML. Вложенное прячет под родителя: Modbus-регистры (тип 52) → внутрь своего устройства (тип 51).
6. `system_settings` (`#S…`) выводит **в начало файла**, чтобы было видно при правке.
``` ### `yml-to-config.py` — YAML → TXT
#Z<id>=<type>,<поле>,<поле>,...
#S<id>=<значение>
```
- `#Z…` — объекты конфигурации (реле, датчики, сценарии, Modbus-устройства и т.д.). Порядок строк значим — сохраняется. 1. Загружает **YAML (UTF-8)** и собирает строки `#Z<id>=…` обратно, в порядке типов.
- `#S…` — системные настройки (`#S7=` модель, `#S202=` серийник, `#S217=` MQTT-URL и пр.). 2. Форматирование: числа без кавычек, строки в `'…'`, bool → `0/1`, пустая строка → `''`, списки → `[…]`.
- Тип объекта — **числом первым полем**: `#Z12=14,'Спальня левый',...` = объект id 12, тип 14 (реле). 3. Разворачивает вложенное: регистры типа 52 снова становятся отдельными строками после своего устройства.
- Специальные записи-маркеры: `#Z<id>=*`. 4. `validate_config()` проверяет структуру **до вывода**. При ошибках — `❌ VALIDATION ERRORS`, **exit 4**, файл не отдаётся.
- Значения в `'одинарных кавычках'`; списки — `[...]`; числа — как есть. 5. Вывод: **windows-1251**, переводы строк **CRLF**, финальный перевод строки как в оригинале.
### Идентификаторы объектов
| Префикс | Смысл | В YAML |
|---|---|---|
| `#Z<id>` | объект конфигурации | разложен по секциям (`relays`, `modbus_devices`, …) |
| `#S<id>` | системная настройка | секция `system_settings` (сохраняется как `id` + `raw_payload`) |
### Что делает `config-to-yml.py`
1. Читает файл, определяет кодировку (UTF-8 → windows-1251).
2. Парсит строки по регекспу `^#([ZS])(\d+)=(.*)$`**хвостовые пробелы в payload сохраняются**.
3. `split_payload()` — разбирает payload с учётом вложенности `[…` и кавычек (запятые внутри кавычек/скобок не разделяют).
4. `parse_atom()``''`/пусто → `None`, `'строка'` → строка, `[список]` → список, иначе int → float → строка.
5. Раскладывает объекты по секциям YAML, вложенные объекты прячет под родителя (регистры типа 52 → внутрь Modbus-устройства типа 51).
6. `system_settings` выносит **в начало** файла — чтобы было видно при правке.
### Что делает `yml-to-config.py`
1. Загружает YAML.
2. Едет обратно по секциям **в порядке типов** и собирает строки `#Z<id>=…`.
3. Форматирование: числа — без кавычек, строки — в `'…'`, bool → `0/1`, пустая строка → `''`, списки → `[…]`.
4. Восстанавливает вложенное: регистры типа 52 пишутся отдельными строками после своего устройства.
5. `validate_config()` — проверяет структуру **до вывода**; при ошибках печатает `❌ VALIDATION ERRORS`, exit code **4**, файл не отдаётся.
6. Вывод: **windows-1251** (`errors='replace'`), строки через **CRLF**, финальный перевод строки — как в оригинале.
### Коды возврата ### Коды возврата
| Скрипт | Код | Значение | | Скрипт | Код | Значение |
|---|---|---| |---|---|---|
| `yml-to-config.py` | 1 | файл не найден |
| | 2 | `ConversionError` (нет `raw`, неизвестный тип) |
| | 3 | прочее исключение |
| | 4 | ❌ ошибки валидации |
| `config-to-yml.py` | 1 | неверное число аргументов | | `config-to-yml.py` | 1 | неверное число аргументов |
| | 2 | `ParseError` (неизвестный формат строки, неразбираемое значение) | | | 2 | `ParseError` неизвестный формат строки или неразбираемое значение |
| `yml-to-config.py` | 1 | файл не найден |
| | 2 | `ConversionError` — нет `raw` или неизвестный тип объекта |
| | 3 | прочее исключение |
| | 4 | ❌ ошибки валидации (файл не выдан) |
> Неизвестный тип объекта — **падение с ошибкой**, а не тихий пропуск. Сделано намеренно: молча потерять объект хуже, чем не отдать файл.
--- ---
## 3. Как пользоваться ## 3. Как пользоваться
### Зависимости **Требования:** `python3` + `PyYAML`. Проверка: `python3 -c 'import yaml; print(yaml.__version__)'`
- `python3`
- `PyYAML` (`import yaml`). Проверить: `python3 -c 'import yaml; print(yaml.__version__)'`
### ⚠️ Правильный обход (важно: имена файлов и каналы)
Оба скрипта **пишут в stdout**, а `yml-to-config.py` **отдаёт windows-1251** — редирект через `>` в терминале Mac сохранит байты как надо, но копипаст из терминала кодировку убьёт.
```bash ```bash
cd /Users/admin/Automation/HA-ZONT-Modbus cd /Users/admin/Automation/HA-ZONT-Modbus
# 1. Снять текущий конфиг с контроллера → положить в zont_config/ # 1. Снять текущий конфиг с контроллера → в zont_config/
# (файлы вида config_<SN>_<SN>_<YYYY-MM-DD_HH-MM-SS>.txt) # имя файла: config_<SN>_<SN>_<YYYY-MM-DD_HH-MM-SS>.txt
# 2. TXT → YAML # 2. TXT → YAML
python3 config-to-yml.py zont_config/config_XXXX.txt > /tmp/zont.yml python3 config-to-yml.py zont_config/config_XXXX.txt > /tmp/zont.yml
# 3. Правка YAML (имена, адреса, пороги) # 3. Править YAML: имена, адреса, интервалы опроса, пороги
# ⚠️ НЕ добавлять/удалять объекты с новыми id без нужды — порядок и id значимы # ⚠️ id объектов и их порядок значимы — не переставлять без нужды
# 4. YAML → TXT # 4. YAML → TXT
python3 yml-to-config.py /tmp/zont.yml > /tmp/zont_new.txt python3 yml-to-config.py /tmp/zont.yml > /tmp/zont_new.txt
# 5. Сверить: число строк #Z и #S до/после # 5. Сверить число объектов до/после
grep -c '^#Z' /tmp/zont_new.txt grep -c '^#Z' /tmp/zont_new.txt
# 6. Только после сверки — загружать zont_new.txt в контроллер # 6. Загрузить /tmp/zont_new.txt в контроллер (UI / облако ZONT)
``` ```
### Разделение «сырое» ↔ «человеческое» ### 🔴 Главное правило: `raw` не трогать
Часть полей в YAML декодирована (адрес, интервал опроса, регистры), часть остаётся как `raw` / `raw_params` / `raw_field_N` — это **страховка**. `yml-to-config.py` при пустом `raw` подставит дефолты (для типа 0 — жёстко зашитый набор, для типа 36 — `[],[],[],10,0`), и такие объекты **потеряют исходные значения**. В YAML часть полей декодирована (адрес, интервал опроса, регистры), часть лежит как `raw` / `raw_params` / `raw_field_N` — это **страховка от потери данных**.
> 🔴 **Правило: правь декодированные поля, `raw` не трогай вообще.** Если поле не декодировано — правка возможна только с пониманием исходного формата. Если у объекта пустой `raw`, скрипт подставит **жёстко зашитые дефолты** (тип 0 — набор из 16 полей, тип 36 — `[],[],[],10,0`), и исходные настройки будут потеряны молча.
### Поддерживаемые типы объектов (по README) > ✅ **Правь декодированные поля. `raw`-поля не удаляй и не «чисти».** Если поле не декодировано — правка возможна только с пониманием исходного формата.
Типы: `1, 3, 4, 5, 6, 7, 9, 10, 11, 14, 16, 20, 24, 25, 27, 28, 42, 46, 49, 51, 52, 53, 57` ### Поддерживаемые типы
➕ фактически обрабатываются ещё **`0`** (дискретные датчики — индикаторы состояния реле) и **`36`** (конфиги дискретных датчиков, вытащенные из вложенной структуры).
Полная таблица — [[family/tech/zont-config-object-types]].
Неизвестный тип → скрипт **падает с ошибкой**, а не молча теряет объект. Это сделано намеренно, чтобы не портить конфиг. `1, 3, 4, 5, 6, 7, 9, 10, 11, 14, 16, 20, 24, 25, 27, 28, 42, 46, 49, 51, 52, 53, 57`
➕ дополнительно обрабатываются **`0`** (дискретные датчики — индикаторы состояния реле) и **`36`** (их вложенные конфиги).
Полная таблица с полями — [[family/tech/zont-config-object-types]].
--- ---
## 4. Round-trip (проверка целостности) ## 4. Проверка целостности (round-trip)
Заявлено в `README_converters.md`: **round-trip 130/130 объектов, TXT → YAML → TXT идентичен**. `README_converters.md` заявляет round-trip **130/130 объектов**: TXT → YAML → TXT даёт идентичный файл.
> ⚠️ **Не воспроизводил** — при подготовке этой доки прогон не выполнялся. Относиться как к заявлению README, а не как к проверенному факту. Команда для проверки на любом конфиге:
Команда для самостоятельной проверки (безопасна, работает в `/tmp`):
```bash ```bash
cd /tmp && rm -rf zont-rt && mkdir zont-rt && cd zont-rt cd /tmp && rm -rf zont-rt && mkdir zont-rt && cd zont-rt
@@ -164,34 +146,34 @@ 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
python3 /Users/admin/Automation/HA-ZONT-Modbus/yml-to-config.py a.yml > b.txt 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 tr -d '\r' < "$SRC" > A.txt; tr -d '\r' < b.txt > B.txt
diff A.txt B.txt # пустой вывод = round-trip чистый diff A.txt B.txt # пусто = round-trip чистый
grep -c '^#Z' A.txt B.txt grep -c '^#Z' A.txt B.txt # счётчик объектов
``` ```
> 📌 **Нюанс:** источник бывает в UTF-8, а вывод `yml-to-config.py` всегда windows-1251. При diff кириллица в именах даст различия на уровне байтов. Сравнивать по структуре (`#Z` / `#S` + числовые поля), либо предварительно нормализовать кодировку с обеих сторон. > 📌 **Нюанс кодировки:** источник бывает в UTF-8, а `yml-to-config.py` всегда пишет windows-1251 → наивный `diff` покажет различия на кириллице. Сравнивать структуру и числовые поля, либо нормализовать кодировку с обеих сторон.
--- ---
## 5. Питфоллы ## 5. Питфоллы
| # | Питфолл | Обход | | # | Питфолл | Как обойти |
|---|---|---| |---|---|---|
| 1 | 🔴 **`yml-to-config.py` пишет windows-1251**, не UTF-8 | Редирект в **файл** (`> out.txt`), не копипаст. Файл загружать байтами, не через текстовый редактор с перекодировкой | | 1 | 🔴 Вывод `yml-to-config.py` **windows-1251 + CRLF**, не UTF-8 | Редирект **в файл** и передавать байтами. Не копипастить из терминала, не пересохранять в редакторе |
| 2 | 🔴 **CRLF-переводы строк** обязательны | Скрипт сам ставит `\r\n`. Не «нормализовать» вывод | | 2 | 🔴 Пустой `raw` у типов 0/36 → **молчаливая подстановка дефолтов** | Не трогать `raw*`-поля |
| 3 | 🔴 **Потеря `raw` → подстановка дефолтов** | Не трогать `raw*`-поля. Пустой `raw` у типа 0/36 → жёсткие дефолты в скрипте | | 3 | 🔴 Правка `#S…` в YAML бессмысленна — они хранятся как `raw_payload` | Системные настройки менять только через UI контроллера |
| 4 | **`#S`-настройки сохраняются как `raw_payload`** | Править их руками в YAML бессмысленно/опасно — только через UI контроллера | | 4 | Кодировка чтения автоопределяется (UTF-8 → windows-1251) | Не пересохранять исходный конфиг в редакторе |
| 5 | **Кодировка чтения автоопределяется** (UTF-8 → windows-1251) | Не пересохранять исходник в редакторе — можно уехать в другую кодировку | | 5 | Неизвестный тип объекта → exit 2, файл не создаётся | Смотреть stderr — там причина |
| 6 | **Неизвестный тип объекта = exit 2, а не тихий пропуск** | Читать stderr; файл не создаётся | | 6 | `validate_config()` → exit 4 | Печатает `❌ VALIDATION ERRORS` + список причин; файл намеренно **не выдан** (вывод пустой) |
| 7 | **`validate_config` отдаёт exit 4 без вывода файла** | При `❌ VALIDATION ERRORS` смотреть список; вывод пустой — это норма | | 7 | Регистр без своего устройства / аналоговый выход с битой ссылкой | WARNING в stderr, конвертация продолжается — проверить ссылки вручную |
| 8 | **`INFRASTRUCTURE.md` в проекте описывает мёртвый TrueNAS-стек** | Актуальное — [[family/how-to/home-automation]]. Не искать docker-контейнеры `modbus-bridge`/`mbusd` на TrueNAS | | 8 | Загрузка конфига в контроллер — **руками**, скрипты только конвертируют | Конвертер не имеет доступа к ZONT |
| 9 | **Изменённый конфиг загружать в ZONT руками (UI/облако), не скриптом** | Скрипты только конвертируют. Проверку результата делает Alex | | 9 | `INFRASTRUCTURE.md`, `docker-compose.yml`, `docker run.txt` в проекте — **исторический TrueNAS-стек** | Актуальный контур — [[family/how-to/home-automation]]. Не искать `modbus-bridge`/`mbusd` на NAS |
| 10 | **`jsonschema`/`ruamel` НЕ нужны** | Только `pyyaml` | | 10 | Дополнительных зависимостей нет | Только `pyyaml``jsonschema`/`ruamel` не нужны |
--- ---
## 6. Связанные заметки ## 6. Связанные заметки
- [[family/tech/zont-config-object-types]] — таблица типов объектов (1…57, 0, 36) - [[family/tech/zont-config-object-types]] — таблица типов объектов (0, 1…57, 36) и `#S`-настройки
- [[family/how-to/home-automation]] — общий контур автоматизации, ZONT, Modbus slave ID и регистры (§6) - [[family/how-to/home-automation]] — контур автоматизации, ZONT, Modbus slave ID и регистры (§6)
- [[family/how-to/gitea-config]] — Gitea, креды, создание репо - [[family/how-to/gitea-config]] — Gitea: креды, создание репо, питфоллы
- [[family/how-to/ha-automations]] — автоматизации HA - [[family/how-to/ha-automations]] — автоматизации HA