20 KiB
aliases, created, namespace, related, tags, title, type, updated
| aliases | created | namespace | related | tags | title | type | updated | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
2026-09-17 | family |
|
|
⚙️ ZONT Config Compiler — конвертеры .txt ⇄ .yml | how-to | 2026-09-17d |
⚙️ ZONT Config Compiler — конвертеры .txt ⇄ .yml
Двусторонние конвертеры между конфигом контроллера ZONT (.txt) и читаемым YAML.
Позволяют править конфиг руками — имена реле, адреса Modbus, интервалы опроса, датчики — не заходя в UI контроллера.
| Проект (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) |
| Конфиги | zont_config/ — свежие · zont_config/archive/ — историчные |
| Типы объектов | family/tech/zont-config-object-types |
| ZONT в общем контуре | family/how-to/home-automation §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. Как работает
config-to-yml.py — TXT → YAML
- Читает файл, определяет кодировку: UTF-8, при неудаче — windows-1251.
- Парсит строки регекспом
^#([ZS])(\d+)=(.*)$(хвостовые пробелы в payload сохраняются). split_payload()— режет payload по запятым с учётом кавычек и вложенных[…].parse_atom()— пусто/''→None,'строка'→ строка,[…]→ список, иначе int → float → строка.- Раскладывает объекты по секциям YAML. Вложенное прячет под родителя: Modbus-регистры (тип 52) → внутрь своего устройства (тип 51).
system_settings(#S…) выводит в начало файла, чтобы было видно при правке.
yml-to-config.py — YAML → TXT
- Загружает YAML (UTF-8) и собирает строки
#Z<id>=…обратно, в порядке типов. - Форматирование: числа без кавычек, строки в
'…', bool →0/1, пустая строка →'', списки →[…]. - Разворачивает вложенное: регистры типа 52 снова становятся отдельными строками после своего устройства.
validate_config()проверяет структуру до вывода. При ошибках —❌ VALIDATION ERRORS, exit 4, файл не отдаётся.- Вывод: windows-1251, переводы строк CRLF, финальный перевод строки как в оригинале.
Коды возврата
| Скрипт | Код | Значение |
|---|---|---|
config-to-yml.py |
1 | неверное число аргументов |
| 2 | ParseError — неизвестный формат строки или неразбираемое значение |
|
yml-to-config.py |
1 | файл не найден |
| 2 | ConversionError — нет raw или неизвестный тип объекта |
|
| 3 | прочее исключение | |
| 4 | ❌ ошибки валидации (файл не выдан) |
Неизвестный тип объекта — падение с ошибкой, а не тихий пропуск. Сделано намеренно: молча потерять объект хуже, чем не отдать файл.
Проверено против исходников (2026-09-17)
| Факт | Где в коде |
|---|---|
config-to-yml.py exit-коды {1, 2} |
sys.exit(1) — argc; sys.exit(2) — ParseError |
yml-to-config.py exit-коды {1, 2, 3, 4} |
argc / FileNotFoundError / ConversionError / общее / validation |
validate_config() вызывается до вывода |
стр. 913 validation_errors = validate_config(data, lines) |
| Вход YAML — UTF-8, выход — windows-1251 | стр. 907 open(…, encoding='utf-8'); стр. 921 stdout.reconfigure(encoding='windows-1251', errors='replace') |
| Дефолт типа 0 (16 полей) | add_z_line(obj['id'], 0, register_ref, name, 0, 0, 1000, 2000, 7424, [], 20, [], [], 1, config_id, 0, 0) |
| Дефолт типа 36 | add_z_line(config_id, 36, [], [], [], 10, 0) |
| README перечисляет 23 типа; код обрабатывает 25 | README пропускает 0 и 36 |
📌
validate_config()дополнительно проверяет кодируемость каждой строки в windows-1251 (символ вне CP1251 → ошибка валидации).
3. Как пользоваться
Требования: python3 + PyYAML. Проверка: python3 -c 'import yaml; print(yaml.__version__)'
cd /Users/admin/Automation/HA-ZONT-Modbus
# 1. Снять текущий конфиг с контроллера → в zont_config/
# имя файла: config_<SN>_<SN>_<YYYY-MM-DD_HH-MM-SS>.txt
# 2. TXT → YAML
python3 config-to-yml.py zont_config/config_XXXX.txt > /tmp/zont.yml
# 3. Править YAML: имена, адреса, интервалы опроса, пороги
# ⚠️ id объектов и их порядок значимы — не переставлять без нужды
# 4. YAML → TXT
python3 yml-to-config.py /tmp/zont.yml > /tmp/zont_new.txt
# 5. Сверить число объектов до/после
grep -c '^#Z' /tmp/zont_new.txt
# 6. Загрузить /tmp/zont_new.txt в контроллер (UI / облако ZONT)
🔴 Главное правило: raw не трогать
В YAML часть полей декодирована (адрес, интервал опроса, регистры), часть лежит как raw / raw_params / raw_field_N — это страховка от потери данных.
Если у объекта пустой raw, скрипт подставит жёстко зашитые дефолты (тип 0 — набор из 16 полей, тип 36 — [],[],[],10,0), и исходные настройки будут потеряны молча.
✅ Правь декодированные поля.
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 (их вложенные конфиги).
❌ НЕ обрабатывается 45 (задержка-объект) — см. §5, п. 13.
Полная таблица с полями — family/tech/zont-config-object-types.
4. Проверка целостности (round-trip)
README_converters.md заявляет round-trip 130/130 объектов: TXT → YAML → TXT даёт идентичный файл.
Команда для проверки на любом конфиге:
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/yml-to-config.py a.yml > b.txt
tr -d '\r' < "$SRC" > A.txt; tr -d '\r' < b.txt > 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покажет различия на кириллице. Сравнивать структуру и числовые поля, либо нормализовать кодировку с обеих сторон.
5. Питфоллы
| # | Питфолл | Как обойти |
|---|---|---|
| 1 | 🔴 Вывод yml-to-config.py — windows-1251 + CRLF, не UTF-8 |
Редирект в файл и передавать байтами. Не копипастить из терминала, не пересохранять в редакторе |
| 2 | 🔴 Пустой raw у типов 0/36 → молчаливая подстановка дефолтов |
Не трогать raw*-поля |
| 3 | 🔴 Правка #S… в YAML бессмысленна — они хранятся как raw_payload |
Системные настройки менять только через UI контроллера |
| 4 | YAML на входе yml-to-config.py — строго UTF-8; выход — windows-1251. Плюс автоопределение кодировки при чтении .txt (UTF-8 → windows-1251) |
Править YAML в UTF-8. Исходный .txt не пересохранять в редакторе |
| 5 | Неизвестный тип объекта → exit 2, файл не создаётся | Смотреть stderr — там причина |
| 6 | validate_config() → exit 4 |
Печатает ❌ VALIDATION ERRORS + список причин; файл намеренно не выдан (вывод пустой) |
| 7 | Регистр без своего устройства / аналоговый выход с битой ссылкой | WARNING в stderr, конвертация продолжается — проверить ссылки вручную |
| 8 | Загрузка конфига в контроллер — руками, скрипты только конвертируют | Конвертер не имеет доступа к ZONT |
| 9 | INFRASTRUCTURE.md, docker-compose.yml, docker run.txt в проекте — исторический TrueNAS-стек |
Актуальный контур — family/how-to/home-automation. Не искать modbus-bridge/mbusd на NAS |
| 10 | Дополнительных зависимостей нет | Только pyyaml — jsonschema/ruamel не нужны |
| 11 | 🔴 Сценарий с >1 шагом → exit 2 | config-to-yml.py:473 require(len(steps) == 1) жёстко. Обход: нет — нужна правка кода |
| 12 | 🔴 Шаг с >1 действием → exit 2 | config-to-yml.py:489 require(len(actions) == 1). Обход: нет |
| 13 | 🔴 Тип 45 (задержка, мс) не поддержан вообще | Нет парсера в config-to-yml.py, нет эмиттера в yml-to-config.py. Объект молча теряется при round-trip |
| 14 | ⚠️ > в шелле затирает .yml до старта питона |
Проверять exit-код до переноса файла в репо |
Ограничения конвертера, требующие доработки (найдено 2026-09-17)
Прогон боевого конфига config_0FA7C33CC89F_…_2026-09-17_12-12-28.txt (598 #Z, 25 #S) вскрыл 4 дырки в сценарной логике — все четыре независимы, падает на первой же:
| # | Чего нет | Где в коде | Что теряется | Масштаб в конфиге |
|---|---|---|---|---|
| 1 | 2-й и последующие шаги сценария | config-to-yml.py:473 (только 1 шаг); yml-to-config.py:314 — [step_id] захардкожен, :328 — пишет один шаг |
шаг 11828 сценария 11109 |
1 сценарий из 65 |
| 2 | Тип 45 — задержка в мс, [45, ms] |
нет ни в одном скрипте | 4 объекта: 11824=20000, 11825=60000, 11826=0, 11828=0 |
4 объекта |
| 3 | Несколько действий в одном шаге | config-to-yml.py:489 (len(actions)==1) |
шаг 11827 содержит 7 действий |
1 шаг из 65 |
| 4 | — (информационно) сценарий выключен | enabled = поле v[5] сценария |
#Z11109 — enabled=0 |
1 сценарий |
✅ Остальные 64 сценария — каноническая одношаговая форма
11 → [46] → 49, конвертер их разбирает корректно. Все 65 условий (49) имеют ровно 4 поля[49, relay, op, value],op=1= equals у всех. Все 64 «простых» шага — ровно 5 полей[46, prio, cond, [1 действие], []].
Тип 45 vs delay_ms у типа 5 — это разные вещи:
delay_msживёт внутри объекта-действия типа 5 (поле 4) — уже поддержан обоими скриптами.- Тип 45 — самостоятельный объект-задержка в списке действий шага. Восстановленный формат:
[45, <миллисекунды>], 2 поля. Проверено на 4 объектах, больше в конфиге не встречается.
5a. План доработки сценариев (согласован 2026-09-17, ожидает апрува)
Этап 1 — только конвертеры, конфиг не трогать.
- Бэкап обоих скриптов:
cp config-to-yml.py yml-to-config.py /tmp/zont-backup-<дата>/ config-to-yml.py: снятьlen(steps)==1→ список шагов; снятьlen(actions)==1→ список действий; добавить парсер type 45 в новую секциюdelays.yml-to-config.py: эмитить все шагиv[2](не один), все действия; добавить эмиттер type 45.- Проверка round-trip:
TXT → YAML → TXTна боевом конфиге, 598 объектов,diffчистый (см. §4).
Стоп-точка: показать Alex профиль YAML по 11109 перед правкой логики.
Этап 2 — правка YAML (только после ответа на вопрос: (а) просто enabled: true / (б) добавить триггер по событию / (в) другое).
Этап 3 — YAML → TXT, сверка счётчиков, коммит ДО → Alex заливает руками → Alex проверяет руками → коммит ПОСЛЕ.
🔴 Порядок работ с боевыми конфигами: коммит ДО → правка → заливка → ПРОВЕРКА АЛЕКСОМ руками → коммит ПОСЛЕ. Мой
read back= «конфиг записался», НЕ «работает».
6. Состояние проекта (проверено 2026-09-17)
Репозиторий /Users/admin/Automation/HA-ZONT-Modbus — рабочее дерево грязное, разгребание ждёт отдельной команды Alex:
| Файл | Статус |
|---|---|
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 байт — см. причину ниже (не «недоделанная конвертация», а падение на 1 объекте) |
🔴 Причина пустого
.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 байтПроверка:
.yml0 байт всегда означает, что конвертер не «не доехал», а упал на конкретном объекте. Смотреть stderr, а не перезапускать вслепую.⚠️
>в шелле затирает целевой файл ещё до старта питона — поэтому рядом с непустым.txtпоявляется пустой.yml. Писать через>/tmp/out.ymlи только после успешного exit-кода переносить в репо.
Содержимое проекта, не относящееся к конвертерам:
INFRASTRUCTURE.md(342 стр.),docker-compose.yml,docker run.txt— исторический TrueNAS-стек (docker-контейнерыhomeassistant,mbusd,modbus-bridge,mosquitto,zigbee2mqtt,nodered,caddy,immich,transmission,webdav,inpxer,cups-splix,portainer,watchtower,rclone). Стек декомиссирован, автоматизация живёт на t610 — актуальное: family/how-to/home-automation.modbus_ha_bridge.py,modbus_mqtt_bridge.py— исходники мостов (исторические, для TrueNAS).nodered-flows-backup.json,nodered-flows-updated.json— дампы потоков Node-RED (Node-RED остановлен).homeassistant/,floorplan/— снапшоты конфига HA и планировки (исторические, там же workflow «fetch from NAS → edit → deploy»).README_converters.md— исходное описание конвертеров (типы: 23, без0и36)..gitignore— исключает*.cur, логи,__pycache__,.venv,.DS_Store,project_home.pdf(крупный бинарь).
7. Связанные заметки
- family/tech/zont-config-object-types — таблица типов объектов (0, 1…57, 36) и
#S-настройки - family/tech/zont-scenario-logic-11109 — разобранная логика сценария «Передёрнуть Автомат Котельной»
- family/how-to/home-automation — контур автоматизации, ZONT, Modbus slave ID и регистры (§6)
- family/how-to/gitea-config — Gitea: креды, создание репо, питфоллы
- family/how-to/ha-automations — автоматизации HA