Files
obsidian-vault/family/tech/zont-scenario-logic-11109.md
T

502 lines
34 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
aliases:
- ZONT сценарий 11109
- Передернуть Автомат Котельной
- ZONT тип 45 задержка
- ZONT сценарная логика
- ZONT поле 2 сценария
created: '2026-09-17'
namespace: family
related:
- '[[family/how-to/zont-config-compiler]]'
- '[[family/tech/zont-config-object-types]]'
- '[[family/how-to/home-automation]]'
tags:
- family
- tech
- zont
- modbus
- homeautomation
title: 🔁 ZONT — сценарная логика и конструктор (11/46/47/48/49/50/59/45)
type: tech
updated: '2026-09-17e'
---
# 🔁 ZONT — сценарная логика и конструктор логики
> 🔴 **ВНИМАНИЕ: раздел §1 ниже содержит УСТАРЕВШУЮ модель.** Поле 5 типа 11 — **НЕ «enabled»**,
> это **тип запуска сценария** (0/1 ручной, 8 расписание, 9 триггер, 10 интервал). Исправление и
> полная модель — **§8**. Раздел §1 оставлен как история разбора; актуальная семантика в §8.
Как устроены сценарии в конфиге ZONT и что именно разобрано в боевом конфиге
`config_0FA7C33CC89F_0FA7C33CC89F_2026-09-17_12-12-28.txt` (598 `#Z`, 25 `#S`, 65 сценариев).
Контекст конвертеров — [[family/how-to/zont-config-compiler]].
---
## 1. Структура сценария
Сценарий — это **4 связанных типа объектов**:
```
#Z<sid>=11,'Имя',[<шаг>,<шаг>,…],0,0,<enabled>,0,0 ← сценарий
#Z<step>=46,<prio>,<cond>,[<действие>,…],[] ← шаг
#Z<cond>=49,<relay_id>,<operator>,<value> ← условие
#Z<act>=… ← действие (тип 5, 9 или 45)
```
| Тип | Роль | Формат | Поля |
|---|---|---|---|
| **11** | Сценарий | `[11, name, [step_ids], 0, 0, enabled, 0, 0]` | **8** полей. `enabled` — поле v[5] (0/1) |
| **46** | Шаг | `[46, prio, cond_id, [action_ids], []]` | **5** полей. `prio` и последнее поле — всегда 0/`[]` |
| **49** | Условие | `[49, relay_id, operator, value]` | **4** поля. `operator`: `1`=equals, иначе not_equals |
| **45** | Задержка | `[45, <миллисекунды>]` | **2** поля |
**Каноническая форма** (99% конфига): 1 сценарий → 1 шаг → 1 условие → 1 действие.
---
## 2. Действия в шаге — три разных типа
Список действий шага (`46` поле 3) может содержать объекты **трёх** типов:
| Тип | Что это | Формат | Декодирование |
|---|---|---|---|
| **5** | Действие над выходом контроллера | `[5, name, output_ref, 1, delay, impulse_dur, [], sched_bmp, sched_time, impulse_period, value]` | 11 полей. `output_ref >> 4` = id выхода; `delay` — поле 4 (мс) |
| **9** | Команда реле | `[9, name, target_relay, '1'/'0']` | 4 поля. `value`**строка** `'1'`/`'0'`, не число |
| **45** | Пауза между действиями | `[45, ms]` | 2 поля |
> ⚠️ **Тип 45 ≠ `delay_ms` типа 5.** `delay_ms` — задержка **внутри** действия перед его выполнением.
> Тип 45 — **отдельный объект-пауза** в последовательности. Их часто путают при чтении конфига.
---
## 3. Разобранный кейс: `#Z11109` «Передернуть Автомат Котельной»
**Единственный сценарий в конфиге с нестандартной формой** — 7 действий в шаге и задержка (`45`)
прямо в поле 2 сценария (`11828`) вместо второго шага. См. §5 «Уточнение семантики поля 2».
```
#Z11109=11,'Передернуть Автомат Котельной',[11827,11828],0,0,0,0,0
#Z11823=49,11190,1,0 ← условие
#Z11827=46,0,11823,[11191,11030,11824,11029,11825,11192,11826],[]
#Z11828=45,0 ← шаг 2
#Z11824=45,20000 #Z11825=45,60000 #Z11826=45,0
#Z11029=9,'Включить реле «20/1 Автомат Котельная»',11028,'1'
#Z11030=9,'Выключить реле «20/1 Автомат Котельная»',11028,'0'
#Z11191=9,'Включить реле «virt. Запретить передергивание»',11190,'1'
#Z11192=9,'Выключить реле «virt. Запретить передергивание»',11190,'0'
#Z11028=14,'20/1 Автомат Котельная',175728,0
#Z11190=14,'virt. Запретить передергивание',179904,0
```
### Что происходит по шагам
**Условие:** `relay 11190 ('virt. Запретить передергивание') == 0` — т.е. передёргивание **не** запрещено.
**Шаг 1 (`11827`) — 7 действий подряд:**
| # | Объект | Действие | Пауза после |
|---|---|---|---|
| 1 | `11191` (type 9) | включить `virt. Запретить передергивание` | — |
| 2 | `11030` (type 9) | **выключить** `20/1 Автомат Котельная` | — |
| 3 | `11824` (type 45) | пауза | **20 000 мс** |
| 4 | `11029` (type 9) | **включить** `20/1 Автомат Котельная` | — |
| 5 | `11825` (type 45) | пауза | **60 000 мс** |
| 6 | `11192` (type 9) | выключить `virt. Запретить передергивание` | — |
| 7 | `11826` (type 45) | пауза | 0 |
**Шаг 2 (`11828`)** — на деле это не шаг, а **задержка** `[45, 0]` прямо в поле 2 сценария:
пустая пауза-заглушка. Оставлена планировщиком ZONT, функциональной нагрузки не несёт.
### Смысл логики
Это **защита от повторного передёргивания**:
1. Виртуальное реле `virt. Запретить передергивание` (id `11190`) ставится в 1 **первым** действием.
2. Условие сценария (`11823`) требует `== 0` → пока реле в 1, сценарий повторно **не запустится**.
3. Снимается реле только **после** 20 с + 60 с пауз (действие 6), т.е. через 80 секунд после старта → минимальный интервал между передёргиваниями автомата = 80 с.
### 🔴 Проблема
`#Z11109` поле v[5] = **`0`** → **сценарий выключен в контроллере**. Защита и сама функция передёргивания не работают.
---
## 4. Полные счётчики по конфигу (для сверки после правок)
| Тип | Кол-во | Комментарий |
|---|---|---|
| 11 / 46 | 65 / 65 | все одношаговые, кроме `11109` |
| 49 | 65 | все ровно 4 поля, `op=1` (equals) у всех |
| 45 | 4 | `11824`, `11825`, `11826`, `11828` — только в `11109` |
| 9 | 42 | 21 пара ВКЛ/ВЫКЛ, `value` — строка `'1'`/`'0'` |
| 5 | 66 | действия над выходами |
| 14 | 40 | реле |
| 10 | 22 | GUI-переключатели |
| 0 / 36 | 13 / 13 | дискретные датчики + вложенные конфиги |
| 52 / 51 / 53 | 93 / 11 / 64 | Modbus-регистры / устройства / ещё один слой |
| 16 / 20 | 10 / 1 | контуры и режимы отопления |
| **Всего `#Z`** | **598** | |
> Проверка после любой правки: `grep -c '^#Z' <файл>` должен дать **598**.
---
## 5. Статус разбора конвертером
| Что | Статус |
|---|---|
| Многошаговый сценарий (`[11827,11828]`) | ✅ разбирается с 2026-09-17 |
| 7 действий в шаге `11827` | ✅ разбирается с 2026-09-17 |
| Тип 45 (4 объекта) | ✅ парсер + эмиттер, секция YAML `delays` |
| Round-trip всех 4 конфигов | ✅ чисто (`test_roundtrip.py`, коммит `199f2b1`) |
| Сценарий `enabled=0` | ℹ️ факт, не баг конвертера |
### 🔴 Уточнение семантики поля 2 (важно)
Поле 2 сценария — **не «список шагов»**, а **последовательность ссылок**, куда попадают объекты
**разных типов**. Полный список: шаг (`46`) **и** задержка (`45`).
В `#Z11109` поле 2 = `[11827, 11828]`, где:
- `11827` — настоящий шаг (`46`) с условием и 7 действиями;
- `11828`**задержка (`45,0`)**, т.е. «шаг-ожидание» без условия.
Поэтому формулировка «2 шага» неточна: **шаг один**, вторым элементом идёт задержка-заглушка.
Отсюда же — `extra_links` в YAML (см. [[family/how-to/zont-config-compiler]] §2.1): не-46 ссылки
сохраняются дословно, чтобы round-trip остался байт-точным.
> ⚠️ **Не путать с типом 45 внутри шага.** В `11827` задержки `11824`/`11825`/`11826` — это
> **действия внутри** шага. `11828` — **ссылка в поле 2 сценария**, т.е. элемент верхнего уровня.
---
## 6. План переработки YAML-структуры (2026-09-17, ждёт апрува)
Сценарии в YAML переписываются в нативную ZONT-форму **вложенных инструкций «если … то …»**
**без HA-синтаксиса** (`triggers`, `platform: state`). Alex: «нет структура должна быть как в zont.
**триггеров нет.**»
Предлагаемая форма для `11109`:
```yaml
scenarios:
- id: 11109
name: 'Передернуть Автомат Котельной'
enabled: false
blocks:
- id: 11827
if: {id: 11823, relay: 11190, operator: 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:
- {id: 11828, action: wait, ms: 0} # задержка из поля 2 сценария
```
Полный план — [[family/how-to/zont-config-compiler]] §5c.
> ⏸ **РАБОТА ПО §5c ПРИОСТАНОВЛЕНА (2026-09-17).** Alex дал «стоп» и запросил исследование облачного
> API ZONT — есть ли альтернатива конвертеру. **Ответ: API конфиг не поддерживает** (сценарии/реле/
> 11/14/46/49 в API отсутствуют). Переписывать с 0 не на что, конвертер остаётся единственным путём.
> Разбор — [[family/tech/zont-api]]. Форма `blocks/if/then` выше — **предложение, в коде не реализовано**.
---
## 7. Связанные заметки
- [[family/how-to/zont-config-compiler]] — конвертеры `.txt ⇄ .yml`; 2 шага и тип 45 **поддержаны с 2026-09-17** (§5b)
- [[family/tech/zont-api]] — облачный API ZONT: конфиг не поддерживает, альтернативы конвертеру нет
- [[family/tech/zont-config-object-types]] — полная таблица типов объектов и `#S`-настройки
- [[family/how-to/home-automation]] — контур автоматизации, ZONT, Modbus slave ID и регистры
---
## 8. 🔴 КОНСТРУКТОР ЛОГИКИ ZONT — типы 47 / 48 / 50 / 59 (разобрано 2026-09-17)
> **Источник:** локальный конфиг с контроллера, снят с `http://192.168.0.50/config.txt`
> (без авторизации, см. [[family/tech/zont-api]] §6bis):
> `zont_config/config_local_2026-09-17_14-16-35.txt` — **34 907 байт, 660 `#Z`, 25 `#S`**.
>
> Alex создал тестовые сценарии в UI, «постарался использовать все доступные триггеры и варианты
> логики». Это позволило вскрыть **полноценный визуальный конструктор логики** со скриптовым движком.
### 8.1. 🔴 ИСПРАВЛЕНИЕ: поле 5 типа 11 — ТИП ЗАПУСКА, а не `enabled`
Прежняя модель (§1, строка `[11, name, [step_ids], 0, 0, enabled, 0, 0]`) **неверна**.
Поле 5 (индекс 5) — **тип запуска сценария**:
| Значение | Что это | Доказательство из тестовых сценариев |
|---|---|---|
| `0` / `1` | ручной запуск (кнопка), вкл/выкл | 64 старых сценария = `1`; `11109` = `0` |
| `8` | по **расписанию** | `#Z8597` — поле 4 = `61`, поле 6 = `3354` ✅ расшифровано |
| `9` | по **триггеру** (условию) | `#Z8547`, `#Z8551` — оба триггерные (подтверждено Alex) |
| `10` | по **интервалу** | `#Z8599` — поле 6 = `43200000` мс = **12 ч** |
**Поле 6** — параметр запуска (для `10` — интервал в мс; для `8` — время запуска).
### 🔴 Поле 4 + поле 6 при запуске по расписанию — РАСШИФРОВАНО (2026-09-17)
`#Z8597` «Тестовый сценарий по расписанию», Alex: **ПН, СР, ЧТ, ПТ, СБ, в 13:26**.
| Поле | Значение | Расшифровка |
|---|---|---|
| поле 4 | `61` = `0b00111101` | **битовая маска дней недели**: бит 0=ПН, 1=ВТ, …, 6=ВС. Установлены биты **0,2,3,4,5** = ПН, СР, ЧТ, ПТ, СБ ✅ |
| поле 6 | `3354` = `0x0D1A` | **время**: старший байт `0x0D` = **13** (час), младший `0x1A` = **26** (минута) → **13:26** ✅ |
```text
#Z8597 = 11, 'Тестовый сценарий по расписанию', [8598], 61, 3354, 8, 0, 0
^годнедели ^время ^тип
```
> Формула времени: `поле6 = (час << 8) | минута`. Начало недели — **ПН** (бит 0), не ВС.
> Проверка: `61 >> 0 & 1 = 1` (ПН есть), `61 >> 1 & 1 = 0` (ВТ нет — у Alex ВТ не отмечен) ✅.
```text
#Z8456=11,'Простой тестовый сценарий',[<26 ссылок>],0,0, 8,0,0
#Z8547=11,'тестовый сценарий по времени', [8550],0,0, 9,0,0
#Z8551=11,'Тестовый сценарий по триггеру',[8555],0,0, 9,0,0
#Z8597=11,'Тестовый сценарий по расписанию',[8598],61,3354, 8,0,0
#Z8599=11,'Тестовый сценарий по интервалу',[8600,8601],0,0, 10,43200000,0
```
> ⚠️ **Следствие для конвертера:** `enabled` в YAML сейчас выводится из поля 5 как булево —
> это **потеря информации** для значений 8/9/10. Конвертер на новом конфиге **падает**
> (`Ошибка: Условие 8496: не type 49`) — новые типы не поддержаны.
### 8.2. Новые типы объектов (УТОЧНЕНО ответами Alex 2026-09-17)
| Тип | Что | Формат | Пример |
|---|---|---|---|
| **47** | **лист дерева условий** (сравнение) | `[47, <оператор>, <левый>, <правый_или_0>, <константа>]` | `[47, 3, 8552, 0, -5]` — «погода <= -5» |
| **48** | **группа условий** | `[48, <логика>, [<id условий>]]` | `[48, 0, [8493,8495]]` |
| **50** | **объект-триггер запуска** (внешний/системный) | `[50, 1, 0, 0, <ext_id>]` | `[50, 1, 0, 0, 109]` |
| **59** | **мини-скрипт ZONT** | `[59, '<код>', <арг1>, <арг2>, <флаг>]` | `[59, 'expr "%0 + %1"', 8459, 8460, 0]` |
**Type 47 — модель полей.** `[47, op, LEFT, RIGHT, K]`:
- `LEFT` — объект/скрипт-выражение слева;
- если `RIGHT` != `0`**второй объект**, сравнение двух объектов (`8495`: `var1 >= objstate 9838`, RIGHT = `8494`);
- если `RIGHT` = `0` — сравнение **с константой** из поля 4 (`8493`: `OBJECT < 3`).
**Type 47, операторы — ПОДТВЕРЖДЕНО Alex** (порядок пунктов UI: `<`, `>`, `=`, `<=`, `>=`):
| Поле 1 | Оператор | Доказательство (формулировка Alex) |
|---|---|---|
| `0` | `<` | `8493` «значение элемента управления < 3»; `8497` «var1 < 2» |
| `1` | `>` | `8499` «Pickle(2) > 3» |
| `2` | `=` | в тестовом блоке нет; следует из порядка UI |
| `3` | `<=` | `8553` «погода из интернета <= -5» |
| `4` | `>=` | `8495` «var1 >= значение 13/9 рад. ванная 2эт» |
> 🔴 **Ловушка:** порядок пунктов UI (`<`,`>`,`=`,`<=`,`>=`) **не** логически упорядочен.
> `=` стоит **третьим** (код `2`), между `>` и `<=`. Не «додумывать» порядок как
> «сначала все меньше, потом все больше» — это даёт неверные коды.
**Type 48, логика группы — ПОДТВЕРЖДЕНО Alex** (по описанию теста 8456):
| Поле 1 | Логика | Доказательство |
|---|---|---|
| `0` | **И** (все условия) | `8496 = [48,0,[8493,8495]]` — «условие И: ...» |
| `1` | **ИЛИ** (любое) | `8501 = [48,1,[8497,8500]]` — «ИЛИ: ...» |
| `2` | **НЕ** (отрицание) | `8500 = [48,2,[8499]]` — «НЕ (...)» |
**Type 50 — триггер запуска.** `[50, 1, 0, 0, <ext_id>]`, где `<ext_id>` — **внешний/системный
объект**, которого нет среди `#Z` (напр. `109` — «погода из интернета»). Сценарий «по времени»
(`8547`, шаг `8550`) ссылается на `109` — в UI это тоже триггер-условие запуска
(поле 5 типа 11 = `9`).
### 8.3. Type 59 — встроенный скриптовый язык
Найденные команды (в поле 1, в кавычках — аргументы):
| Команда | Пример | Смысл (предположительно) |
|---|---|---|
| `objcmd <id> "<args>"` | `objcmd 8700 "1 %0"` | команда объекту с подстановкой `%0`, `%1` |
| `objstate <id> <n> <n>` | `objstate 9838 0 0` | чтение состояния объекта |
| `expr "<формула>"` | `expr "%0 + %1"`, `expr "%0 - %1"` | арифметика |
| `set <var>` | `set var1` | присваивание переменной |
| `puts "текст"` | `puts "Отладка"`, `puts "test"` | вывод (отладка) |
| `storeev I "z"` / `storeev A "asdf"` | — | запись события (I = integer?, A = alert/array?) |
| просто число/строка | `3`, `2 ;#p` | константа; суффиксы `;#a`, `;#h`, `;#p` |
Есть **переменные** (`var1`), **подстановки** `%0`/`%1` (аргументы из полей 2/3), **суффиксы** `;#a`/`;#h`/`;#p`.
Это объясняет всё: у ZONT есть **полноценный визуальный конструктор логики** поверх скриптового движка.
### 8.4. Дерево условий — рабочий пример (`#Z8505`, `#Z8506`)
Вложенная логика читается так:
```
#Z8506 = [46, 0, 8496, [8505], []] ← шаг: условие 8496, действие 8505
#Z8496 = [48, 0, [8493, 8495]] ← группа: 8493 И 8495
#Z8493 = [47, 0, 8492, 0, 3] ← лист: объект 8492, значение 0, порог 3
#Z8492 = [59, 'objstate 9838 0 0', 0, 0, 0] ← объект = скрипт!
#Z8495 = [47, 4, 8472, 8494, 0]
#Z8494 = [59, 'objstate 9838 0 0', 0, 0, 0]
#Z8505 = [46, 1, 8501, [8502, 8503], [8504]] ← шаг: приоритет 1, доп. список [8504]
#Z8501 = [48, 1, [8497, 8500]] ← группа: 8497 ИЛИ 8500
#Z8497 = [47, 0, 8472, 0, 2]
#Z8500 = [48, 2, [8499]] ← группа: логика 2 над [8499]
#Z8499 = [47, 1, 8498, 0, 3]
#Z8498 = [59, '2 ;#p', 0, 0, 0]
```
> 📌 В `#Z8505` поле 1 (приоритет) = **1**, и поле 4 (последнее) = **непустой список `[8504]`** —
> в отличие от «канонических» шагов, где там всегда `[]`. Конвертер это отвергает
> (`require(step[4] == [])`). Семантика поля 4 — **не подтверждена**.
### 8.5. Контейнер-сценарий `#Z8456` (поле 2 = смесь типов)
`#Z8456 = [11, 'Простой тестовый сценарий', [<26 ссылок>], 0, 0, 8, 0, 0]` — поле 2 содержит
объекты **разных типов**, а не только шаги:
| Тип | Кол-во | Примеры |
|---|---|---|
| 9 (команда реле) | 2 | `8457` «Установить целевую температуру 23.8…», `8470` «Активировать режим…» |
| 59 (скрипт) | 17 | `8458``8504` |
| 11 (другой сценарий!) | 1 | `11109` «Передернуть Автомат Котельной» |
| 3 (SMS) | 1 | `8195` «CMC оповещение» |
| 5 (действие) | 1 | `9500` «Вкл. Рад. ванная 2эт» |
| 45 (задержка) | 1 | `8489` = 432 000 000 мс = **5 суток** |
| 46 (шаг) | 1 | `8506` |
> 🔴 **Сценарий может ссылаться на другой сценарий** (`11109` внутри `8456`). Это **не дерево**,
> а плоский список ссылок.
### 8.6. Сводка тестового блока (id 84508601)
Типы в блоке: `{9: 2, 11: 3, 14: 1, 16: 1, 27: 1, 45: 1, 46: 4, 47: 5, 48: 3, 49: 11, 50: 3, 59: 26}`.
| Сценарий | Имя | Поле 5 (запуск) |
|---|---|---|
| `8456` | Простой тестовый сценарий | `8` (расписание) |
| `8547` | тестовый сценарий по времени | `9` (триггер) |
| `8551` | Тестовый сценарий по триггеру | `9` (триггер) |
| `8597` | Тестовый сценарий по расписанию | `8` (расписание) |
| `8599` | Тестовый сценарий по интервалу | `10` (интервал, 12 ч) |
### 8.7. ✅ ВОПРОСЫ ЗАКРЫТЫ — ответы Alex (2026-09-17)
Alex создал тестовые сценарии и описал, что видно в UI. Все пять вопросов закрыты:
| # | Вопрос | Ответ | Проверка по конфигу |
|---|---|---|---|
| 1 | **Type 47, оператор** | Операнды в UI: **`<`, `>`, `=`, `<=`, `>=`** → коды `0..4` | ✅ все 5 листов сошлись |
| 2 | **Type 48, логика** | **`0`=И, `1`=ИЛИ, `2`=НЕ** | ✅ по описанию теста 8456 |
| 3 | **Type 50** | **Объект-триггер запуска** (внешний, напр. `109` «погода из интернета») | ✅ |
| 4 | **Type 11, поле 4** | **Маска дней недели** (`61` = ПН,СР,ЧТ,ПТ,СБ), поле 6 = `(час<<8)|мин` | ✅ 13:26 |
| 5 | **`;#a`/`;#h`/`;#p`** | (не переспрашивал; остаются гипотезой) | ⏳ |
**Разбор тестовых сценариев Alex (ответы дословно → факты конфига):**
| Сценарий | Что сказал Alex | Что в конфиге |
|---|---|---|
| `8597` расписание | «пн, ср, чт, пт, сб, в 13:26» | поле 4=`61`, поле 6=`3354`=13:26 ✅ |
| `8547` «по времени» | «по триггеру, триггер на день недели: пн,ср,чт,сб,вс» | поле 5=`9`, шаг `8550``[50,1,0,0,109]` |
| `8551` «по триггеру» | «триггер сравнение: погода из интернета <= -5, действие вывод в терминал» | `8553=[47,3,8552,0,-5]`, `8552=[49,8254,0,4]`, `8254`=«Погода из интернета», then `8554`=`puts "Температура упала ниже -5"` ✅ |
| `8547` шаг `8550` | «только одно действие: вывод "test" в терминал» | `8549=[59,'puts "test"',0,0,0]` ✅ |
| `8456` (26 ссылок) | «set var много, у каждого разный тип значения» | 7× `set var1` + 7 разных типов объектов ✅ |
**Type 46 — модель полей ПОДТВЕРЖДЕНА (5 полей = если/то/иначе):**
```text
#Z<step> = [46, <вид>, <id_условия_или_0>, [<ТОГДА>...], [<ИНАЧЕ>...]]
```
Alex по тесту `8456` описал: «если (условие И: …) То: … Иначе: Сохранить событие» —
и это точно соответствует `8506 = [46, 0, 8496, [8505], []]` + `8505 = [46, 1, 8501, [8502,8503], [8504]]`,
где `[8504]` = ветка **ИНАЧЕ**. Поле 4 = список **ИНАЧЕ** (ранее помечено «семантика не подтверждена» — теперь подтверждена).
> ⚠️ Поле 1 шага: `0` у внешнего, `1` у вложенного (`8505`) — вероятно «уровень вложенности»
> или признак вложенного блока. Точная семантика не подтверждена, но round-trip требует
> сохранять как есть.
### 8.8. Скрипты разбора (в проекте)
| Файл | Назначение |
|---|---|
| `read_scenarios.py` | 🆕 **читаемый дамп любого сценария** — дерево если/то/иначе с именами объектов. `python3 read_scenarios.py <config> <id>` |
| `dump_new_types.py` | дамп типов 11/45/46/47/48/49/50/59 целиком |
| `probe_types.py` | распределение поля 5 у type 11; тело контейнера; блок 8450–8560 |
| `trace_scenarios.py` | трассировка сценарных графов, поиск сценариев с новыми типами |
| `probe_sched.py` | 🆕 проверка расписания: маска дней + время |
| `verify_answers.py` | 🆕 кросс-проверка ответов Alex против фактов конфига |
| `check_ops.py` | 🆕 проверка таблицы операторов type 47 |
| `audit_8456.py`, `audit2.py` | 🆕 аудит прозрачности элементов сценария 8456 |
```bash
cd /Users/admin/Automation/HA-ZONT-Modbus
python3 read_scenarios.py zont_config/config_local_2026-09-17_14-16-35.txt 8456 # дерево сценария
python3 read_scenarios.py zont_config/config_local_2026-09-17_14-16-35.txt # все сценарии
python3 probe_types.py # семантика поля 5, тестовый блок
python3 dump_new_types.py # все сценарные объекты
```
> ✅ **Токенайзер починен.** Старый `read_scenarios.py` рвал строки со скриптами на запятых
> внутри кавычек (`objcmd 9102 "6,%0";#a` разваливалось). Новый `split_top()` учитывает
> кавычки, экранирование `\` и вложенные `[]` — теперь скрипты печатаются как есть.
### 8.10. ⏳ НЕПРОЗРАЧНЫЕ ЭЛЕМЕНТЫ СЦЕНАРИЯ 8456 (вопросы заданы Alex 2026-09-17, ответа нет)
Alex спросил: «а по всем действиям в "Простой тестовый сценарий" — тебе всё кристально прозрачно?»
Ответ — **нет**. Ниже ровно то, что не выводится из конфига. **Не строить гипотезы — ждать ответа.**
| # | Элемент | Что неясно |
|---|---|---|
| 1 | `#Z8456` поле 5 = `8` (расписание), но поле 4 = `0`, поле 6 = `0` | **Как запускается 8456?** Расписание не задано. Что значит `8` без маски/времени? Ручной запуск? |
| 2 | `#Z8458 = [59, 'objcmd 8700 "1 %0"', 10.5, 0, 1]` | Единственный скрипт с **нецелым** `%0` (`10.5`) и **флагом `1`** в поле 4 (у всех остальных `0`). Что за инструкция в UI? |
| 3 | `#Z8463 = [59, 'objcmd 9102 "6,%0";#a', 8462, 0, 0]`, где `8462` = скрипт `expr "%0 + %1"` | Аргумент = **ссылка на другой скрипт**. Что за суффикс `;#a`? |
| 4 | `#Z8465 = [59, 'objcmd 11907 ",,,%0";#h', 8464, 0, 0]`, где `8464` = `[49, 4099, 0, 8]` (условие) | Аргумент = **условие**. Что за `;#h`? |
| 5 | `#Z8467 = [59, '3', 0, 0, 0]` | Скрипт = просто цифра `3`. Константа? Зачем отдельным действием? |
| 6 | `#Z8486`/`#Z8488` = `set var1`, arg1 = `8485`/`8487`**type 50** | Type 50 стоит как **источник значения** для var1, а не как триггер. Это то же самое, что триггер? |
| 7 | `#Z9500 = [5,'Вкл. Рад. ванная 2эт',145728,1,0,0,[],0,0,0,512]` | Объект выхода `145728` **отсутствует** в конфиге. Поле 10 = `512` — что это? |
| 8 | `#Z8457 = [9,'Установить целевую температуру 23.8...',8669,'2968']`, `#Z8470 = [9,...,8669,'8574']` | Значение `'2968'`**отсутствующий объект**. Это «установить температуру»/«активировать режим»? |
**Что уже прозрачно (не переспрашивать):**
- 7× `set var1` и их источники: `8450`(Температура подачи, тип 27), `9864`(Статус 13/9, тип 0),
`8560`(Контур газ котла, тип 16), `9263`(Реле 1 конвектор, тип 14), `8254`(Погода из интернета, тип 1),
`4098`(Адаптер газ. котла, тип 6), `8382`(Температура Zigbee, тип 1) ✅
- `#8466` `puts "Отладка"`, `#8468` `storeev I "z"`, `#8469` `storeev A "asdf"` — вывод/события ✅
- `#8489` пауза 5 суток (`432000000` мс), дерево `#8506``#8505` (И/ИЛИ/НЕ + ИНАЧЕ) ✅
- `#8195` SMS `CMC оповещение``8192` (2 номера) ✅
- `#11109` как **вложенный сценарий** внутри 8456 ✅
- `#8507` — ссылка на **отсутствующий объект** (хвост поля 2) ✅
**Почему неясные элементы не блокируют парсер:** стратегия — сохранять их **дословно**
(type 59 как сырые строки с `arg1..arg3`, отсутствующие id — как есть). Round-trip останется
байт-точным независимо от того, понята семантика или нет.
### 8.9. Состояние: конвертер на новом конфиге ПАДАЕТ
```bash
$ python3 config-to-yml.py zont_config/config_local_2026-09-17_14-16-35.txt > /tmp/new.yml
Ошибка: Условие 8496: не type 49
EXIT=2
```
**Причина:** `config-to-yml.py` в блоке сценариев требует `cond[0] == 49` и
`step[4] == []`. Новые типы (47/48/50/59) и непустое поле 4 не поддерживаются.
**Что нужно (после ответов Alex на §8.7):**
1. Парсер типов **47/48/50/59** + рекурсивная сборка дерева условий
2. Поле 5 типа 11 — хранить как **тип запуска** (0/1/8/9/10) + поле 6 (параметр), не как `enabled`
3. Поле 4 шага — принимать непустые списки
4. Ссылки в поле 2 — допускать не-46 типы (45, 11, 3, 5, 9)
5. Round-trip всех 5 конфигов (боевой + 3 архива + новый локальный)
**Счётчики нового конфига (для сверки):** `660 #Z`, `25 #S`, байт — 34 907.
| Тип | Кол-во | | Тип | Кол-во |
|---|---|---|---|---|
| 11 | 70 | | 49 | 76 |
| 46 | 69 | | 47 | 5 |
| 45 | 5 | | 48 | 3 |
| 9 | 44 | | 50 | 3 |
| 59 | 28 | | 0/36 | 13/13 |