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

399 lines
24 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-17d'
---
# 🔁 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`, поле 5 = `3354` |
| `9` | по **триггеру** (условию) | `#Z8547`, `#Z8551` — тестовые |
| `10` | по **интервалу** | `#Z8599` — поле 6 = `43200000` мс = **12 ч** |
Распределение по живому конфигу: `{1: 64, 0: 1, 8: 2, 9: 2, 10: 1}`.
**Поле 6** — параметр запуска (для `10` — интервал в мс; для `9`/`8` — иное).
**Поле 4**у `8597` = `61` (вероятно день недели / индекс расписания), у остальных `0`.
```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. Новые типы объектов
| Тип | Что | Формат | Пример |
|---|---|---|---|
| **47** | **лист дерева условий** | `[47, <оператор>, <объект>, <значение>, <порог>]` | `[47, 3, 8552, 0, -5]` — «температура ниже −5» |
| **48** | **группа условий (И/ИЛИ)** | `[48, <логика>, [<id условий>]]` | `[48, 0, [8493,8495]]`, `[48, 1, [...]]`, `[48, 2, [...]]` |
| **50** | **запуск команды/сценария по id** | `[50, 1, 0, 0, <id>]` | `[50, 1, 0, 0, 123]`, `[50, 1, 0, 0, 109]`, `[50, 0, 1, 3351, 0]` |
| **59** | **мини-скрипт ZONT** | `[59, '<код>', <арг1>, <арг2>, <флаг>]` | `[59, 'expr "%0 + %1"', 8459, 8460, 0]` |
Наблюдённые значения поля 1 у **47**: `0, 1, 3, 4` (оператор — семантика **не подтверждена**).
У **48**: `0, 1, 2` (логика группы — семантика **не подтверждена**).
### 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, ответа ещё нет)
| # | Вопрос |
|---|---|
| 1 | **Type 47, поле 1** — что за оператор? Наблюдены `0, 1, 3, 4`. Гипотеза: `0`=равно, `1`=не равно, `3`=меньше, `4`=больше — **не подтверждено** |
| 2 | **Type 48, поле 1** — логика группы? Наблюдены `0, 1, 2`. Гипотеза: `0`=И, `1`=ИЛИ, `2`=НЕ — **не подтверждено** |
| 3 | **Type 50** — что за объект? `[50, 1, 0, 0, <id>]` — запуск по расписанию/интервалу? |
| 4 | **Type 11, поле 4**у `8597` = `61`, у остальных `0`. Минуты? День недели? |
| 5 | **Type 59** — есть ли документация на язык? Или это внутренний формат |
> 🔴 **Не строить гипотезы вместо ответа.** Alex явно предложил: «если нужна будет подсказка что и
> чем является по типу/значениям — спрашивай меня». Вопросы заданы, ждём ответа.
> До ответа **правки конвертера не делать** — можно закодировать неверную семантику.
### 8.8. Скрипты разбора (в проекте)
| Файл | Назначение |
|---|---|
| `dump_new_types.py` | дамп типов 11/45/46/47/48/49/50/59 целиком |
| `probe_types.py` | распределение поля 5 у type 11; тело контейнера; блок 8450–8560 |
| `trace_scenarios.py` | трассировка сценарных графов, поиск сценариев с новыми типами |
```bash
cd /Users/admin/Automation/HA-ZONT-Modbus
python3 probe_types.py # → семантика поля 5, тестовый блок
python3 dump_new_types.py # → все сценарные объекты
```
> ⚠️ `trace_scenarios.py` падает на `TypeError: unhashable type: 'list'` (шаг `8457` — type 9,
> у него `cond` = `[16, 'Контур ГВС', …]`, а скрипт ждёт скаляр). Не критично — `probe_types.py`
> даёт те же данные. Чинить при следующем заходе.
### 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 |