Files
obsidian-vault/family/how-to/zont-config-compiler.md
T

20 KiB
Raw Blame History

aliases, created, namespace, related, tags, title, type, updated
aliases created namespace related tags title type updated
ZONT config compiler
config-to-yml
yml-to-config
HA-ZONT-Modbus
ZONT конвертеры конфига
2026-09-17 family
family/tech/zont-config-object-types
family/tech/zont-scenario-logic-11109
family/how-to/home-automation
family/how-to/gitea-config
family
how-to
zont
modbus
homeautomation
⚙️ 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

  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

  1. Загружает YAML (UTF-8) и собирает строки #Z<id>=… обратно, в порядке типов.
  2. Форматирование: числа без кавычек, строки в '…', bool → 0/1, пустая строка → '', списки → […].
  3. Разворачивает вложенное: регистры типа 52 снова становятся отдельными строками после своего устройства.
  4. validate_config() проверяет структуру до вывода. При ошибках — ❌ VALIDATION ERRORS, exit 4, файл не отдаётся.
  5. Вывод: 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.pywindows-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 Дополнительных зависимостей нет Только pyyamljsonschema/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] сценария #Z11109enabled=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 — только конвертеры, конфиг не трогать.

  1. Бэкап обоих скриптов: cp config-to-yml.py yml-to-config.py /tmp/zont-backup-<дата>/
  2. config-to-yml.py: снять len(steps)==1 → список шагов; снять len(actions)==1 → список действий; добавить парсер type 45 в новую секцию delays.
  3. yml-to-config.py: эмитить все шаги v[2] (не один), все действия; добавить эмиттер type 45.
  4. Проверка 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 байт

Проверка: .yml 0 байт всегда означает, что конвертер не «не доехал», а упал на конкретном объекте. Смотреть 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. Связанные заметки