730 lines
53 KiB
Markdown
730 lines
53 KiB
Markdown
---
|
||
aliases:
|
||
- ZONT config compiler
|
||
- config-to-yml
|
||
- yml-to-config
|
||
- HA-ZONT-Modbus
|
||
- ZONT конвертеры конфига
|
||
created: '2026-09-17'
|
||
namespace: family
|
||
related:
|
||
- '[[family/tech/zont-api]]'
|
||
- '[[family/tech/zont-config-object-types]]'
|
||
- '[[family/tech/zont-scenario-logic-11109]]'
|
||
- '[[family/how-to/home-automation]]'
|
||
- '[[family/how-to/gitea-config]]'
|
||
tags:
|
||
- family
|
||
- how-to
|
||
- zont
|
||
- modbus
|
||
- homeautomation
|
||
title: ⚙️ ZONT Config Compiler — конвертеры .txt ⇄ .yml
|
||
type: how-to
|
||
updated: 2026-09-17j
|
||
---
|
||
|
||
# ⚙️ 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) · `test_roundtrip.py` (проверка целостности) |
|
||
| **Конфиги** | `zont_config/` — свежие · `zont_config/archive/` — историчные |
|
||
| **Типы объектов** | [[family/tech/zont-config-object-types]] |
|
||
| **ZONT в общем контуре** | [[family/how-to/home-automation]] §6 |
|
||
| **Снять живой конфиг с прибора** | 🔴 `curl -s http://192.168.0.50/config.txt` — **без авторизации**, формат ровно как у парсера. См. [[family/tech/zont-api]] §6bis |
|
||
|
||
---
|
||
|
||
## 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 → ошибка валидации).
|
||
|
||
---
|
||
|
||
## 2.1 Формат сценариев (type 11 / 45 / 46 / 49) — разобран 2026-09-17
|
||
|
||
🔴 **Ключевое открытие:** поле 2 сценария — это **не список шагов типа 46**, а последовательность
|
||
ссылок, куда попадают и **шаги (46)**, и **задержки (45)**. Проверено на 65 сценариях боевого конфига.
|
||
|
||
```
|
||
#Z<step_46_id>=46,<priority>,[<action_ids…>],[]
|
||
#Z<act_id>=9,'<имя>',<relay_id>,'0|1' ← действие (тип 9)
|
||
#Z<delay_id>=45,<ms> ← задержка (тип 45)
|
||
#Z<cond_id>=49,<relay_id>,<operator>,<value> ← условие (тип 49)
|
||
#Z<scen_id>=11,'<имя>',[<step_46_id>…],0,0,<enabled>,0,0
|
||
```
|
||
|
||
| Поле | Значение |
|
||
|---|---|
|
||
| `11` поле 2 | список ссылок: шаги 46 **и** задержки 45 |
|
||
| `46` поле 2 | `[action_ids]` — действия 9 **и** задержки 45 внутри шага |
|
||
| `45` | пауза в **мс**; `45,0` = пауза 0 (заглушка) |
|
||
| `11` поле 6 | `1` = сценарий включён, `0` = выключен |
|
||
| `11` число полей | свежая прошивка — **8**, старая (`-2`) — **7** |
|
||
|
||
**Пример — `#Z11109` «Передернуть Автомат Котельной»** (единственный многошаговый из 65):
|
||
|
||
```
|
||
#Z11109=11,'Передернуть Автомат Котельной',[11827,11828],0,0,0,0,0 ← 11828 = задержка-«хвост»
|
||
#Z11827=46,0,11823,[11191,11030,11824,11029,11825,11192,11826],[] ← 7 действий, 2 из них задержки
|
||
#Z11823=49,11190,1,0 ← virt.Запретить == 0
|
||
#Z11824=45,20000 #Z11825=45,60000 #Z11826=45,0 #Z11828=45,0
|
||
```
|
||
|
||
Читается как: *вкл `virt.Запретить` → выкл Автомат → пауза 20 с → вкл Автомат → пауза 60 с →
|
||
выкл `virt.Запретить` → пауза 0*. Поле 6 = `0` → **сценарий выключен**, защиты от повторного
|
||
передёргивания нет.
|
||
|
||
### Как это выглядит в YAML
|
||
|
||
> ✅ **НОВАЯ форма (2026-09-17, §5c).** Все сценарии — единая вложенная структура `blocks[].if/then/else`
|
||
> плюс блок `trigger:`. Плоские `when`/`then` и секции `steps`/`delays`/`scenario_conditions` убраны.
|
||
> **Форма `11109` ниже — устаревшая**, оставлена для истории; актуальная — §5c.
|
||
|
||
**Устаревшая форма (коммит `199f2b1`)** — плоский `when`/`then` для 1-шаговых + `steps` + `extra_links`:
|
||
|
||
```yaml
|
||
scenarios:
|
||
- id: 11109
|
||
name: Передернуть Автомат Котельной
|
||
enabled: false
|
||
steps:
|
||
- id: 11827
|
||
when: {id: 11823, relay_id: 11190, operator: equals, value: 0}
|
||
then: {actions: [11191, 11030, 11824, 11029, 11825, 11192, 11826]}
|
||
extra_links: [11828]
|
||
delays:
|
||
- {id: 11824, ms: 20000}
|
||
- {id: 11825, ms: 60000}
|
||
- {id: 11826, ms: 0}
|
||
- {id: 11828, ms: 0}
|
||
```
|
||
|
||
**Как дописывать логику:** задержки правятся в секции `delays` (поле `ms`), порядок срабатывания
|
||
задаётся порядком id в `actions` шага. Чтобы включить сценарий — `enabled: true`.
|
||
|
||
---
|
||
|
||
## 2.2 Round-trip: все 4 конфига чистые
|
||
|
||
Проверено `test_roundtrip.py` (новый скрипт в репо) — TXT → YAML → TXT, сравнение по множеству
|
||
строк с нормализацией кодировки:
|
||
|
||
| Конфиг | Объектов | Результат |
|
||
|---|---|---|
|
||
| `zont_config/config_0FA7C33CC89F_…_2026-09-17_12-12-28.txt` | 598 | ✅ чисто |
|
||
| `zont_config/archive/H2000_PRO_config_actual-4.txt` | 558 | ✅ чисто |
|
||
| `zont_config/archive/H2000_PRO_config_actual-3.txt` | 558 | ✅ чисто |
|
||
| `zont_config/archive/H2000_PRO_config_actual-2.txt` | 594 | ✅ чисто |
|
||
|
||
```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
|
||
```
|
||
|
||
**Что исправлено 2026-09-17** (правки в обоих конвертерах):
|
||
|
||
| # | Проблема | Причина | Правка |
|
||
|---|---|---|---|
|
||
| 1 | Падение «поддерживается только 1 шаг» | `require(len(steps) == 1)` — не знал про задержки в поле 2 | цикл по ссылкам; не-46 → `extra_links` |
|
||
| 2 | Падение «поддерживается только 1 действие» | `require(len(actions) == 1)` | список действий целиком |
|
||
| 3 | Тип **45** отсутствовал | не было парсера/энкодера | секция `delays`, `KNOWN_TYPES += 45`, `TYPE_ORDER += delays` |
|
||
| 4 | Тип 5, поле 3 (`1`→`0`) терялось | энкодер хардкодил `1` | `_raw_field3` |
|
||
| 5 | `1.0` → `1` (порча float) | `parse_atom` превращал whole-float в int | whole-float остаётся float |
|
||
| 6 | Сценарии старой прошивки (7 полей) → 8 | энкодер всегда писал 8 | `_raw_field_count` |
|
||
| 7 | `divider=1.0` → `1` | дефолт подавлялся | `_raw_divider` |
|
||
|
||
---
|
||
|
||
## 3. Как пользоваться
|
||
|
||
**Требования:** `python3` + `PyYAML`. Проверка: `python3 -c 'import yaml; print(yaml.__version__)'`
|
||
|
||
```bash
|
||
cd /Users/admin/Automation/HA-ZONT-Modbus
|
||
|
||
# 1. Снять текущий конфиг с контроллера → в zont_config/
|
||
# имя файла: config_<SN>_<SN>_<YYYY-MM-DD_HH-MM-SS>.txt
|
||
# ✅ Напрямую с контроллера, без авторизации (см. §5g):
|
||
curl -s http://192.168.0.50/config.txt -o zont_config/config_$(date +%Y-%m-%d_%H-%M-%S).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, 45, 46, 49, 51, 52, 53, 57`
|
||
➕ дополнительно обрабатываются **`0`** (дискретные датчики — индикаторы состояния реле) и **`36`** (их вложенные конфиги).
|
||
Полная таблица с полями — [[family/tech/zont-config-object-types]].
|
||
|
||
**Сценарные типы — полностью поддержаны с 2026-09-17 (см. §5b):**
|
||
|
||
| Тип | Роль | Формат | YAML-секция |
|
||
|---|---|---|---|
|
||
| `11` | сценарий | `[11, name, [step_ids], 0, 0, enabled, 0, 0]` | `scenarios` |
|
||
| `45` | задержка, мс | `[45, ms]` | `delays` |
|
||
| `46` | шаг | `[46, 0, cond_id, [action_ids], []]` | `scenario_steps` |
|
||
| `49` | условие | `[49, relay_id, operator, value]` | `scenario_conditions` |
|
||
|
||
---
|
||
|
||
## 4. Проверка целостности (round-trip)
|
||
|
||
✅ **Есть готовый скрипт — `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 # проверить exit!
|
||
python3 /Users/admin/Automation/HA-ZONT-Modbus/yml-to-config.py a.yml > 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 чистый
|
||
```
|
||
|
||
> 🔴 **Сравнивать множеством строк (`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.)
|
||
|
||
---
|
||
|
||
## 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. ⚠️ **Снятие конфига — уже не ручное:** `http://192.168.0.50/config.txt` отдаёт весь конфиг без авторизации (§5g). Заливка — утилита по USB / облако / WS **только для `#S`** (§5g-2) |
|
||
| 9 | `INFRASTRUCTURE.md`, `docker-compose.yml`, `docker run.txt` в проекте — **исторический TrueNAS-стек** | Актуальный контур — [[family/how-to/home-automation]]. Не искать `modbus-bridge`/`mbusd` на NAS |
|
||
| 10 | Дополнительных зависимостей нет | Только `pyyaml` — `jsonschema`/`ruamel` не нужны |
|
||
| 11 | ✅ **ИСПРАВЛЕНО 2026-09-17** — Сценарий с >1 шагом падал (exit 2) | `config-to-yml.py` теперь цикл по всем шагам; `yml-to-config.py` пишет все `step_ids` |
|
||
| 12 | ✅ **ИСПРАВЛЕНО 2026-09-17** — Шаг с >1 действием падал (exit 2) | Оба скрипта работают со всем списком действий |
|
||
| 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) — ВСЕ ЗАКРЫТЫ
|
||
|
||
Прогон боевого конфига `config_0FA7C33CC89F_…_2026-09-17_12-12-28.txt` (598 `#Z`, 25 `#S`) вскрыл **4 дырки** в сценарной логике — все четыре независимы, падал на первой же. **Все четыре исправлены, см. §5b.**
|
||
|
||
| # | Чего не было | Что терялось | Масштаб в конфиге | Статус |
|
||
|---|---|---|---|---|
|
||
| 1 | 2-й и последующие шаги сценария | шаг `11828` сценария `11109` | 1 сценарий из 65 | ✅ закрыто |
|
||
| 2 | Тип **45** — задержка в мс, `[45, ms]` | 4 объекта: `11824`=20000, `11825`=60000, `11826`=0, `11828`=0 | 4 объекта | ✅ закрыто |
|
||
| 3 | Несколько действий в одном шаге | шаг `11827` содержит **7** действий | 1 шаг из 65 | ✅ закрыто |
|
||
| 4 | — (информационно) сценарий выключен | `#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 объектах, больше в конфиге не встречается.
|
||
|
||
---
|
||
|
||
## 5b. Доработка сценариев — СДЕЛАНО 2026-09-17
|
||
|
||
Задача Alex: «перегнать в yml, дописав парсер и энкодер». Правка кода конвертеров, боевой конфиг не тронут.
|
||
|
||
### Изменения в `config-to-yml.py` (парсер)
|
||
|
||
| Что | Детали |
|
||
|---|---|
|
||
| Многошаговые сценарии | Убрано `require(len(steps) == 1)`. Цикл `for step_id in steps` → `parsed_steps[]`, каждый со своим `when`/`then` |
|
||
| Много действий в шаге | Убрано `require(len(actions) == 1)`. Все id проверяются на существование в `Z_dict` |
|
||
| Новый тип **45** | Отдельная секция `# --- scenario delays (type 45)`. Валидация: ровно 2 поля, `ms` — неотрицательный int → `out['delays']` = `[{'id':…, 'ms':…}]` |
|
||
| `KNOWN_TYPES` | Добавлен `45` (был `{0,1,…,42,46,49,…}`) |
|
||
| Выходной dict | Добавлен ключ `delays: []` |
|
||
| **Обратная совместимость** | Если у сценария 1 шаг — дополнительно пишутся плоские `when`/`then` (как раньше). Старые YAML не ломаются |
|
||
|
||
### Изменения в `yml-to-config.py` (энкодер)
|
||
|
||
| Что | Детали |
|
||
|---|---|
|
||
| Все шаги | Собирает `step_ids` из `scenario['steps']` (fallback — плоский `then.id`) и пишет в строку сценария |
|
||
| Все действия | `[46, 0, cond_id, actions, []]` — весь список, без `[action_id]` |
|
||
| Новый тип **45** | Секция эмиттера: `raw` passthrough **или** `ms` → `[45, ms]`. Валидация: `ms` — неотрицательный int. **Вставлена ДО шагов (46)** — порядок строк значим |
|
||
| `TYPE_ORDER` | Добавлено `('delays', 45)` между `gui_tabs` и `scenario_steps` |
|
||
| Хелпер `_register()` | Локальная функция рядом с `add_z_line`. Регистрирует шаг/условие по id, **обновляя** существующую запись вместо добавления дубля — один шаг может принадлежать нескольким сценариям |
|
||
| Без `when` в шаге | Если у шага нет `when`, но есть запись в `scenario_steps` — переиспользует известный `cond_id` из неё. Если нет — `ConversionError` |
|
||
|
||
### Что проверено
|
||
|
||
- `ast.parse()` на обоих файлах — синтаксис OK
|
||
- `config-to-yml.py` на боевом конфиге: **больше не падает** на сценарии `11109` (ранее `Ошибка: Сценарий 11109: поддерживается только 1 шаг`, exit 2)
|
||
- ✅ **Round-trip целиком — ПРОЙДЕН на всех 4 конфигах** (см. §2.2). Сверка по множеству строк с нормализацией кодировки.
|
||
|
||
### Коммит
|
||
|
||
✅ **Закоммичено 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`.
|
||
|
||
Не запушено (`origin/main..HEAD` = 3 коммита впереди) — пуш ждёт команды Alex.
|
||
|
||
---
|
||
|
||
## 5c. 🔄 Переработка структуры YAML сценариев — ✅ СДЕЛАНО 2026-09-17
|
||
|
||
> ✅ **СТАТУС (2026-09-17, ночь): парсер и энкодер дописаны, round-trip чистый на 6 конфигах.**
|
||
> Семантика типов 47/48/50/59 раскрыта (ответы Alex — [[family/tech/zont-scenario-logic-11109]] §8.7),
|
||
> операторы и логика подтверждены фактами конфига. Код реализован.
|
||
> **Не закоммичено** — ждёт команды Alex.
|
||
|
||
**Задача Alex (исходная):** «переписать блок парсинга/сборки сценариев чтобы он составлял синтаксис как у Home Assistant automations вместо текущей разбросанной структуры. с опциональными айдишниками у операторов».
|
||
|
||
### 🔴 Правка постановки Alex'ом (ключевое — не повторять ошибку)
|
||
|
||
Первая версия плана натягивала **HA-синтаксис** (`triggers` / `platform: state` / `to:`) на ZONT-логику.
|
||
Alex отклонил:
|
||
|
||
> «нет структура должна быть как в zont. **триггеров нет.** у нас сценарий Передернуть Автомат Котельной буквально содержит вложенные инструкции: **если ... то... итд.** не надо натягивать сову структуры на глобус HA syntax.»
|
||
|
||
**Правило:** в ZONT **нет триггеров** — роль триггера играет само изменение реле, а сценарий читается
|
||
как вложенные инструкции «если … то …». Структура YAML должна повторять ZONT, а не HA.
|
||
|
||
### ✅ Реализованная форма
|
||
|
||
```yaml
|
||
scenarios:
|
||
- id: 8456
|
||
name: Простой тестовый сценарий
|
||
trigger: {type: schedule} # manual | trigger | schedule | interval
|
||
_raw_trigger_kind: 8 # исходное поле 5
|
||
blocks:
|
||
- id: 8506 # шаг (46)
|
||
if:
|
||
id: 8496
|
||
group: and # and | or | not
|
||
children:
|
||
- {id: 8493, op: '<', left: 8492, value: 3}
|
||
- {id: 8495, op: '>=', left: 8472, right: 8494}
|
||
then:
|
||
- id: 8505
|
||
kind: 1
|
||
if: {id: 8501, group: or, children: [...]}
|
||
then:
|
||
- {id: 8502, script: 'puts "then-text"', args: [0, 0, 0]}
|
||
else:
|
||
- {id: 8504, script: 'storeev A "alert"', args: [0, 0, 0]}
|
||
extra_links: [8457, 8458, ..., 8507] # прочие ссылки поля 2, в исходном порядке
|
||
_raw_links: [8457, ..., 8506, 8507] # точный порядок поля 2 (для байт-tочности)
|
||
```
|
||
|
||
**Маппинг типов на YAML:**
|
||
|
||
| Тип | В YAML | Пример |
|
||
|---|---|---|
|
||
| `11` | `trigger: {type, …}` + `blocks[]` | `trigger: {type: schedule, days: [mon,…], time: '13:26'}` |
|
||
| `46` | `blocks[].{if, then, else}` | `{id, kind?, if, then: […], else?: […]}` |
|
||
| `47` | `{op, left, value}` или `{op, left, right}` | `{id: 8493, op: '<', left: 8492, value: 3}` |
|
||
| `48` | `{group, children}` | `{id: 8496, group: and, children: […]}` |
|
||
| `49` | `{condition: {object, operator, value}}` | старая форма, поддержана |
|
||
| `59` | `{script: <код дословно>, args: […]}` | `{id: 8502, script: 'puts "then-text"'}` |
|
||
| `50`, неизвестные | `raw: […]` | `{id: 8548, raw: [50, 1, 0, 0, 109]}` |
|
||
|
||
**Операторы type 47 (порядок UI `<, >, =, <=, >=`):** `0`=`<`, `1`=`>`, `2`=`=`, `3`=`<=`, `4`=`>=`.
|
||
**Логика type 48:** `0`=`and`, `1`=`or`, `2`=`not`.
|
||
|
||
**Триггер (поле 5 типа 11):**
|
||
|
||
| Поле 5 | `trigger.type` | Доп. поля |
|
||
|---|---|---|
|
||
| `0`/`1` | `manual` | `enabled: bool` |
|
||
| `8` | `schedule` | `days[]`, `days_mask`, `time`, `time_raw` (поле 4 = маска дней, бит 0=ПН; поле 6 = `(час<<8)\|мин`) |
|
||
| `9` | `trigger` | — |
|
||
| `10` | `interval` | `interval_ms` |
|
||
|
||
### Реализация (код)
|
||
|
||
**`config-to-yml.py`** — рекурсивные хелперы `dump_step()` / `dump_condition()` / `dump_leaf()` /
|
||
`dump_action()`; сборщики `scenario_scripts` / `scenario_conditions` / `scenario_raw_objects`;
|
||
`_raw_links` для точного порядка поля 2; **fixed-point sweep** операндов (`left`/`right`/`args`) —
|
||
без него теряются скрипты второго порядка (напр. `8459`/`8460` через `8462`); неизвестные типы →
|
||
`raw_objects` вместо падения (там же `KNOWN_TYPES += 47,48,50,59`).
|
||
|
||
**`yml-to-config.py`** — обратные `emit_step()` / `emit_condition()` / `emit_action()`; поддержка
|
||
старых форм (`steps`/`when`/`then`) через `_scenario_from_legacy()`; восстановление порядка ссылок
|
||
из `_raw_links`; новые секции `scenario_scripts`/`scenario_conditions`/`scenario_raw_objects`/`raw_objects`
|
||
в `TYPE_ORDER`.
|
||
|
||
### 🔴 Три питфолла реализации (round-trip ловил каждый)
|
||
|
||
| # | Проблема | Причина | Решение |
|
||
|---|---|---|---|
|
||
| 1 | Объекты не попадали в вывод | `result_lines` в энкодере — **фильтрованное подмножество**: объект должен быть и в `lines`, и в `TYPE_ORDER` | Добавить секции в `TYPE_ORDER` |
|
||
| 2 | Операнды терялись | `left`/`right`/`args` — **не рёбра дерева**, обход их не видит | Fixed-point sweep: собирать референсы из `raw`-тел, докидывать, повторять |
|
||
| 3 | exit 4 «Duplicate ID» | Секции эмитились дважды (явный цикл + `TYPE_ORDER`) | Убрать явный цикл; типы 5/9/3/0/36 не регистрировать в `raw_objects` (у них свои секции) |
|
||
|
||
**Обязано сохраниться байт-в-байт (сохранено):**
|
||
- порядок объектов в файле (45 идёт **после** 11, но **до** 46)
|
||
- порядок ссылок поля 2 сценария → `_raw_links`
|
||
- число полей (7 vs 8) и `_raw_*`-поля (`_raw_field_count`, `_raw_trigger_kind`, `_raw_trigger_params`) — **не удалять**
|
||
|
||
### ✅ Round-trip — 6/6 конфигов чисто
|
||
|
||
```bash
|
||
cd /Users/admin/Automation/HA-ZONT-Modbus
|
||
python3 test_roundtrip.py zont_config/config_local_2026-09-17_14-16-35.txt # ✅ 685/685
|
||
python3 test_roundtrip.py zont_config/config_0FA7C33CC89F_…_12-12-28.txt # ✅
|
||
for f in zont_config/archive/*.txt; do python3 test_roundtrip.py "$f"; done # ✅ -2, -3, -4
|
||
python3 test_roundtrip.py zont_local_ui_recon/config_live_192.168.0.50.txt # ✅
|
||
```
|
||
|
||
**Бэкапы кода:** `/tmp/config-to-yml.py.bak`, `/tmp/yml-to-config.py.bak` (сняты перед правкой).
|
||
**Откат:** git (`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` → ручной запуск
|
||
> в положении «выкл». ⚠️ **Исправлено 2026-09-17:** поле 5 — это **тип запуска** (`0`/`1` ручной,
|
||
> `8` расписание, `9` триггер, `10` интервал), а **не** булев `enabled`. См. §5i и
|
||
> [[family/tech/zont-scenario-logic-11109]] §8.1.
|
||
|
||
---
|
||
|
||
## 5f. Ответы на вопросы постановки (этап 2 снят)
|
||
|
||
Вопрос Alex'у «что именно не хватает на сценариях» (варианты а/б/в) **закрыт его же реакцией**: задача —
|
||
«дописать парсер и энкодер», а не править логику. Правка YAML сценария `11109` (этап 2 прежнего плана)
|
||
с повестки снята — работа ограничена конвертерами.
|
||
|
||
> 🔴 **Урок коммуникации 2026-09-17.** Alex дважды резко реагировал на развёрнутые планы-опросники
|
||
> («нихуя не понял тебе че надо блядь? что блядь сломано?», «ТЫ ХУЛИ ВСТАЛ БЛЯДЬ!?»). Что сработало:
|
||
> **сжатый факт «что сломано» + сразу делать**. Не задавать уточняющих вопросов там, где симптом уже
|
||
> назван; не строить гипотезы вместо чтения конфига; не планировать сверх постановки.
|
||
|
||
> ⚙️ **Бэкап кода — только git, не `/tmp`.** Alex 2026-09-17: «какой нахуй бэкап скриптов — там в гите все». Изменения скриптов откатываются через git, отдельные копии в `/tmp/` не делать.
|
||
|
||
---
|
||
|
||
## 5g. 🔴 Локальный эндпоинт контроллера
|
||
|
||
Контроллер отдаёт **весь конфиг** по HTTP **без авторизации**:
|
||
|
||
```bash
|
||
curl -s http://192.168.0.50/config.txt -o zont_config/config_$(date +%Y-%m-%d_%H-%M-%S).txt
|
||
```
|
||
|
||
Формат — тот же `#Z…` / `#S…`, что парсит `config-to-yml.py`. Снятие конфига больше не ручная
|
||
операция через облако.
|
||
|
||
**Полный разбор локального интерфейса** — WebSocket-протокол, чтение/запись `#S`-настроек,
|
||
кнопка сохранения `#S15=1`, 25 настроек против 9 в UI, утечка секретов, инструменты разведки:
|
||
|
||
➡️ **[[family/tech/zont-api]] §6bis**
|
||
|
||
---
|
||
|
||
## 5g-2. 🔼 ЗАЛИВКА конфига обратно — чем и как (добыто 2026-09-17)
|
||
|
||
Снятие конфига автоматизировано (§5g), но **заливка остаётся ручной** — идёт **не** через
|
||
`config.txt` (этот путь только на чтение). Доступные каналы:
|
||
|
||
| Канал | Что умеет | Ограничение |
|
||
|---|---|---|
|
||
| **Настроечная утилита по USB** | заливка конфига + **прошивки** | Windows-only, нужен USB-кабель и драйвер |
|
||
| Облако ZONT (`my.zont.online`) | правка сценариев/реле через веб-UI | руками, по одному объекту |
|
||
| Локальный WebSocket `ws://192.168.0.50/ws` | запись `#S`-настроек (`{"scmd":"#S<n>=<val>"}` + `#S15=1`) | **`#Z`-объекты не пишутся** — только `#S` |
|
||
|
||
> 🔴 Локальный WS даёт запись **только системных `#S`-настроек** (Wi-Fi, MQTT, номер). Сценарии,
|
||
> реле, шаги (`#Z11/14/46/49`) через него **не заливаются** — для них по-прежнему утилита или облако.
|
||
|
||
### Утилита `H1000 Programmator` 2.8.5 — добыта
|
||
|
||
```bash
|
||
# официальный источник, скачивается без авторизации
|
||
curl -sL -o h1000_utility_beta.bin https://lk.zont-online.ru/download/simple/h1000_utility_beta
|
||
```
|
||
|
||
| Параметр | Значение |
|
||
|---|---|
|
||
| Версия | **2.8.5** (`prgm.2.8.5.exe`, 2.9 MB, Delphi/Borland) |
|
||
| Интерфейс | USB serial-over-USB (`usbser.sys` + `Hxxxx.inf`) |
|
||
| Архив на Mac | `~/rasputin-tmp/zont-util/h1000_utility_beta.bin` (4.5 MB) |
|
||
| Распаковано | `~/rasputin-tmp/zont-util/util_beta/H1000 Programmator/` |
|
||
| Хелпы внутри | `выходы.rtf`, `Отопление.rtf`, `пользователи.rtf`, `смс управление.rtf`, `DTMF управление.rtf` |
|
||
|
||
> 🔴 **Питфолл распаковки.** macOS `unzip` падает на кириллических именах в архиве
|
||
> (`write error (disk full?)` — на самом деле **не** disk full). Имена в CP866.
|
||
> Решение — Python `zipfile` с перекодировкой `cp437 → cp866`: `~/rasputin-tmp/zont-util/extract.py`.
|
||
|
||
> ⚠️ Пятно на репутации формата: файлы `Configs/*.set` внутри архива — **НЕ конфиги устройства**.
|
||
> Это UTF-8 JSON-словари подписей интерфейса (`{"Value":0,"Edit":"Пользователь 1"}`).
|
||
> Не пытаться парсить их нашим конвертером.
|
||
|
||
### Прошивка — формат `.enc` (зашифрован)
|
||
|
||
```bash
|
||
curl -sL -o H2000_fw.zip https://lk.zont-online.ru/download/firmwares/H2000_515__330_290.zip
|
||
```
|
||
|
||
| Файл | Размер | Энтропия | Вывод |
|
||
|---|---|---|---|
|
||
| `STM_MEGA_400_.enc` | 145 177 B | **7.9986** / 8.0 | зашифрован, не сжат |
|
||
| `main_c.evc` | 49 610 B | 5.6487 | частично структурный (`Mega-CX`) |
|
||
|
||
Прошивка тоже отдаётся **без авторизации**. Утилита грузит именно `*.enc`
|
||
(строки `firmware_.enc`, `.enc|*.enc` найдены в exe). Расшифровка — отдельное исследование.
|
||
|
||
#### 🎯 Схема URL прошивки — НАЙДЕНА 2026-09-17
|
||
|
||
```text
|
||
https://lk.zont-online.ru/download/firmwares/H2000_PRO_<HW>__<FW>_<PROFILE>.zip
|
||
H2000_PRO_723__678_1.zip ← наш контроллер, 1.2 MB
|
||
```
|
||
|
||
**Правило:** префикс серии (`H2000_PRO_`) + **двойное** подчёркивание перед версией ПО.
|
||
Одиночные варианты (`H2000_723__678_1.zip`, `H2000_PRO_723__678.zip`) → **404**.
|
||
|
||
Проверка соответствия (конфиг `#S7` ↔ API морды ↔ имя файла):
|
||
|
||
| Источник | Значение |
|
||
|---|---|
|
||
| `#S7` прибора | `H2000_PRO 723 678` |
|
||
| `get_firmware_releases` (DevTools) | `"version":"678:1"`, `"firmware_version":678` |
|
||
| Имя архива | `H2000_PRO_723__678_1.zip` → `h2000_pro_v2_.enc` |
|
||
|
||
→ **`723` = плата (HW), `678` = прошивка, `1` = profile_version.** `678` — последняя
|
||
**стабильная**; 602/585/564 — бета.
|
||
|
||
> 📁 Скачанные прошивки, утилита, скрипты разведки и живой конфиг лежат в проекте:
|
||
> `/Users/admin/Automation/HA-ZONT-Modbus/zont_local_ui_recon/` (см. её `README.md`).
|
||
|
||
➡️ Полный разбор утилиты, прошивок и API морды — **[[family/tech/zont-api]] §10**
|
||
|
||
---
|
||
|
||
## 5h. 🌐 Облачный API ZONT — конфига не даёт
|
||
|
||
Исследовано 2026-09-17. Доки скачаны в проект: `zont_api_docs/`.
|
||
|
||
**Главный вывод:** облачный API (`my.zont.online/api/*`, 11 методов) — это **состояния и история**,
|
||
не конфигурация. Слово `scenario` в доке — **0 раз**. Методов для типов `11/14/46/49` нет.
|
||
`z3k_config` упоминается только как источник ID.
|
||
|
||
**Следствие:** конвертер `.txt ⇄ .yml` — **единственный** путь правки сценариев и реле.
|
||
|
||
**Что API всё же умеет (для H-2000 PRO):** чтение состояний (`devices?load_io=true`),
|
||
история (`load_data`), режимы отопления (`update_device`), сирена/охрана (`set_io_port`).
|
||
|
||
➡️ **Полный разбор API — [[family/tech/zont-api]]**
|
||
|
||
---
|
||
|
||
## 5i. 🔴 Конструктор логики ZONT (типы 47/48/50/59) — ✅ ПОДДЕРЖАН 2026-09-17
|
||
|
||
> **Найдено 2026-09-17.** Alex создал в UI тестовые сценарии («все доступные триггеры и варианты
|
||
> логики»). Разбор локального конфига `config_local_2026-09-17_14-16-35.txt` (660 `#Z`) вскрыл
|
||
> **визуальный конструктор логики** со скриптовым движком.
|
||
>
|
||
> ✅ **Статус: поддержан.** Парсер и энкодер дописаны (§5c), round-trip чистый. Ранее падал с
|
||
> `Ошибка: Условие 8496: не type 49` (exit 2) — **больше не падает**.
|
||
|
||
**Две ключевые находки:**
|
||
|
||
1. 🔴 **Поле 5 типа 11 — НЕ `enabled`, а ТИП ЗАПУСКА:** `0`/`1` ручной, `8` расписание,
|
||
`9` триггер, `10` интервал. Поле 6 — параметр (для интервала — мс; для расписания — `(час<<8)|мин`,
|
||
поле 4 — маска дней недели, бит 0=ПН).
|
||
2. **Новые типы:** `47` (лист условия: `op, left, value|right`), `48` (группа `and`/`or`/`not`),
|
||
`50` (объект-триггер, хранится как `raw`), `59` (мини-скрипт: `objcmd`/`objstate`/`expr`/`set`/
|
||
`puts`/`storeev`; код и args сохраняются **дословно**).
|
||
|
||
**Операторы type 47 (порядок UI `<, >, =, <=, >=`):** `0`=`<`, `1`=`>`, `2`=`=`, `3`=`<=`, `4`=`>=`.
|
||
|
||
> 📌 **Стратегия (реализована):** всё непонятое (скрипты `59` дословно, суффиксы `;#a`/`;#h`/`;#p`,
|
||
> отсутствующие id, `type 50`) сохраняется байт-в-байт через `raw` / `unresolved` — без «умного»
|
||
> перевода. Round-trip остаётся чистым, а непонятное не портится.
|
||
|
||
➡️ **Полный разбор — [[family/tech/zont-scenario-logic-11109]] §8**
|
||
|
||
---
|
||
|
||
## 6. Состояние проекта (проверено 2026-09-17, ночь)
|
||
|
||
✅ **Конвертеры переписаны под сценарный конструктор (§5c).** Рабочее дерево — **не закоммичено**,
|
||
ждёт команды Alex. Последний коммит — `199f2b1`.
|
||
|
||
✅ **Round-trip чистый на 6/6 конфигах** (включая новый локальный с 660 `#Z` и legacy 7-поле `-2`).
|
||
|
||
| Файл | Статус |
|
||
|---|---|
|
||
| `config-to-yml.py` | 🆕 **изменён** — парсер типов 47/48/50/59, `blocks/if/then/else`, триггер, raw-фоллбэк (§5c). **не закоммичено** |
|
||
| `yml-to-config.py` | 🆕 **изменён** — обратные `emit_*`, `_raw_links`, новые секции в `TYPE_ORDER` (§5c). **не закоммичено** |
|
||
| `test_roundtrip.py` | ✅ в коммите `199f2b1`, без изменений |
|
||
| `zont_config/config_local_2026-09-17_14-16-35.txt` | 🆕 **34 907 байт, 660 `#Z`, 25 `#S`** — конфиг с **тестовыми сценариями** Alex. Снят с `http://192.168.0.50/config.txt`. **не в git** |
|
||
| `zont_config/config_0FA7C33CC89F_…_2026-09-17_12-12-28.txt` | 32 689 байт — свежий боевой конфиг, **не в git** |
|
||
| `zont_config/archive/` | `-2`/`-3`/`-4` — ✅ **закоммичены** (`7ae0e32`) |
|
||
| `zont_local_ui_recon/config_live_192.168.0.50.txt` | живой конфиг для разведки WS-интерфейса, **не в git** |
|
||
| `zont_api_docs/` | ✅ локальная копия доки облачного API (`zont_api_docs.html`, `.txt`, `convert.py`). **не в git** |
|
||
| `read_scenarios.py` | 🆕 **читаемый дамп сценария** — дерево если/то/иначе с именами. Токенайзер `split_top()`. **не в git** |
|
||
| `dump_new_types.py`, `probe_types.py`, `trace_scenarios.py` | 🆕 скрипты разбора сценарных типов. Разбор — [[family/tech/zont-scenario-logic-11109]] §8.8. **не в git** |
|
||
| `probe_sched.py`, `verify_answers.py`, `check_ops.py`, `audit_8456.py`, `audit2.py`, `chk_extra.py` | 🆕 проверочные скрипты. **не в git** |
|
||
| `~/rasputin-tmp/zont-util/` | ✅ настроечная утилита `H1000 Programmator` 2.8.5, прошивка `.enc`, `extract.py`. Разбор — §5g-2 |
|
||
| `~/rasputin-tmp/zont-{auth-probe,recon,recon2,ws-probe}.js` | ✅ скрипты разведки локального WS. **не в git** |
|
||
|
||
**Бэкапы кода перед правкой §5c:** `/tmp/config-to-yml.py.bak`, `/tmp/yml-to-config.py.bak`.
|
||
|
||
Не запушено: `origin/main..HEAD` = 3 коммита (`199f2b1`, `7ae0e32`, `12ba22b`). Плюс **новые правки
|
||
§5c — незакоммичены**.
|
||
|
||
> ✅ **Пустой `.yml` (0 байт) больше не актуален** — причина была в падении на сценарии `11109`,
|
||
> исправлено (§5b).
|
||
|
||
**Что НЕ в git и почему:** `.txt` свежего конфига и его `.yml` — рабочие артефакты конвертации,
|
||
Alex их не добавлял. Не коммитить без команды.
|
||
|
||
**Содержимое проекта, не относящееся к конвертерам:**
|
||
|
||
- `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/tech/zont-api]] — **облачный API ZONT: конфиг не поддерживает**; альтернатива конвертеру отсутствует
|
||
- [[family/how-to/home-automation]] — контур автоматизации, ZONT, Modbus slave ID и регистры (§6)
|
||
- [[family/how-to/gitea-config]] — Gitea: креды, создание репо, питфоллы
|
||
- [[family/how-to/ha-automations]] — автоматизации HA
|