[2026-09-18] eagle: family/how-to/home-automation.md personal/projects/zont-config-compiler.md

This commit is contained in:
Alexey Martemyanov
2026-09-18 00:47:48 +06:00
parent 60c044520f
commit 83715aa980
2 changed files with 269 additions and 8 deletions
+208 -6
View File
@@ -162,16 +162,19 @@ related:
| **Снять живой конфиг** | 🔴 `curl -s http://192.168.0.50/config.txt`**без авторизации** |
| **ZONT в общем контуре** | [[family/how-to/home-automation]] §6 |
> ### 📍 Текущее состояние (2026-09-18, после круга 49)
> ### 📍 Текущее состояние (2026-09-18, после §31)
>
> | | |
> |---|---|
> | **HEAD** | `5d31d6e`**запушен** в Gitea (`origin/main`) |
> | **Круг** | **9/9 зелёный**, 759 → 759 объектов |
> | **Артефакт** | `zont_config/config_local_2026-09-17_23-21-20.yml` |
> | **Открыто** | 5 `objcmd`-орфанов · поле 4 = `2` у `expr` (`10077``10085`) · авто-id (`max+1`, 17 точек, план есть) |
> | **HEAD** | `7e34ee1` — «авто-id для листьев + валидация ссылок (круг 50)» |
> | **Круг** | **10/10 зелёный**, 759 → 759 объектов |
> | **Артефакт** | `zont_config/config_local_2026-09-18_00-45-31.yml` (идентичен `23-21-20`) |
> | **Свежий дамп** | ✅ снят 2026-09-18 00:45 — **идентичен** `23-21-20` (`diff` пуст) |
> | **Открыто** | 🔴 **§31: 7 Zigbee-датчиков тёплых полов → slave'ы 105111.** Решения Alex получены (авто-id, имена в стиле ZONT), замер показал: типы 51/52/1 требуют снятия барьеров `'id'`. Bridge-правка НЕ нужна. Ждёт 1 ответ: добавлять ли slave 112. · авто-id: верх окна не назван (§30.3) |
>
> Свежие круги: §27 (46 — `set_contour_target`), §28 (4749 — `call_sub`, `send_sms`, `exit`, `scenario_orphans`).
> Свежие круги: §27 (46 — `set_contour_target`), §28 (4749 — `call_sub`, `send_sms`, `exit`, `scenario_orphans`), §30 (50 — авто-id + валидация ссылок), §31 (Zigbee → Modbus).
>
> ✅ Снято с открытого в §28.6: «5 `objcmd`-орфанов» и «поле 4 = `2` у `expr`» — **работы не требуют** (орфанов нет; поле производное).
---
@@ -4382,3 +4385,202 @@ Alex: **«Я думаю надо жестоко ограничить диапа
| Артефакт | ✅ `zont_config/config_local_2026-09-17_23-21-20.yml` свежий (содержит `call_sub: 11109`, `send_sms: 8195`, `exit: true`) |
| HEAD / origin | ✅ `5d31d6e`, запушено |
---
## 31. 🆕 Zigbee-датчики тёплых полов → виртуальные Modbus-устройства (2026-09-18, план)
**Задача Alex:** «Тяни и конвертируй свежий конфиг и добавь в него entity zigbee датчиков температуры
которых в нем нет через виртуальные modbus устройства в bridge».
### 31.1. ✅ Разведка: свежий конфиг **байт-в-байт** равен снапшоту `23-21-20`
```bash
curl -s http://192.168.0.50/config.txt -o /tmp/zont_fresh_test.txt # 38174 байта, exit 0
diff <(iconv -f windows-1251 -t utf-8 zont_config/config_local_2026-09-17_23-21-20.txt) \
<(iconv -f windows-1251 -t utf-8 /tmp/zont_fresh_test.txt) # → пусто
```
📌 **Ничего не изменилось на контроллере с 2026-09-17 23:21.** «Свежий конфиг» = тот же `23-21-20`,
уже лежащий в репо; артефакт `.yml` перегенерировать не нужно. 785 строк / 759 объектов `#Z` + 26 `#S`.
🔴 **Проверять идентичность конфига ДО работы:** если `diff` пуст — вся работа идёт по существующему
снапшоту, а не по новой копии (иначе в репо плодятся одинаковые дампы, а «свежесть» артефакта
становится неотличима — ср. питфолл 97, §27.4).
### 31.2. Что уже есть: ZONT опрашивает 4 Zigbee-датчика через slaves 100103
**11 Modbus-устройств (тип 51) на стороне ZONT:** slaves `1, 2, 3, 13, 14, 20, 100, 101, 102, 103, 104`.
| Slave | Имя в ZONT | Виртуальный датчик (тип 1) | Регистр (тип 52) |
|---|---|---|---|
| 100 | `Tuya Zigbee Thermal Sensor` | `#Z8382` «Температура Zigbee» | `#Z8383` |
| 101 | `Температура гостиная` | `#Z8911` «Температура Гостиная» | `#Z8912` |
| 102 | `Температура детская` | `#Z8700` «Температура Детская» | `#Z8701` |
| 103 | `Температура спальня` | `#Z8932` «Температура Спальня» | `#Z8933` |
Форма записи (три типа работают в связке — **устройство → регистр → виртуальный датчик**):
```text
#Z8381=51,100,'Tuya Zigbee Thermal Sensor',5000,300000,[],[],0,[8383] ← устройство: поле 2 = slave_id, поле 9 = [id регистра]
#Z8383=52,'Темп. датч.',100,16,0,1,16,0,1,29,1,4 ← регистр: поле 2 = адрес регистра, поле 3 = кол-во бит (16 = int16)
#Z8382=1,'0','Температура Zigbee',0,0,0,60000,[],[],[],8383,[],0,0,0 ← датчик: поле 10 = id регистра
```
### 31.3. 🔴 Что отсутствует: 7 Zigbee-датчиков тёплых полов
В конфиге ZONT **нет** этих сущностей — `grep` по «тёпл|пол» даёт только контур отопления
`#Z10152=16,'Тёплый пол'` и его датчик `#Z8432=27,'Температура тёплого пола'`. Остальные 6 записей
типа 27 — `Температура подачи` (`#Z8450`), `Температура улица` (`#Z9259`).
| HA-сущность | Наличие в ZONT |
|---|---|
| `sensor.living_room_floor_temperature_temperature` | ❌ нет |
| `sensor.severnaia_floor_temperature_temperature` | ❌ нет |
| `sensor.kabinet_floor_temperature_temperature` | ❌ нет |
| `sensor.kitchen_floor_temperature_temperature` | ❌ нет |
| `sensor.vannaia_floor_temperature_temperature` | ❌ нет |
| `sensor.prikhozhaia_floor_temperature_temperature` | ❌ нет |
| `sensor.dushevaia_floor_temperature_temperature` | ❌ нет |
**История:** датчики заведены в HA и прописаны в bridge-шаблон ещё 2026-09-15
([[family/plans/t610-zigbee-ids-battery-freshsensors-modbus]] §4, slaves 105112), но **на стороне
ZONT как Modbus-устройства не зарегистрированы никогда**. Мост отдаёт значения — ZONT их не спрашивает.
⚠️ `config.yml` **в репо устарел**: маппинг slave 100 всё ещё ссылается на
`sensor.office_temperature_sensor_temperature` (мёртвое имя после переименования 2026-09-15).
Живой шаблон — `/addons/modbus-bridge/data/config.template.tmpl` **на t610**, не в репо
(ср. урок №3 того же плана: переименование рвёт маппинг bridge → slave молча отдаёт `0`).
### 31.4. ✅ Решения Alex (2026-09-18, ответ на два вопроса плана)
| Вопрос | Решение Alex | Следствие |
|---|---|---|
| id для 21 нового объекта | **«Let allocator decide»** | Расширять `_LEAF_TYPES` + снимать барьеры `'id'`; вручную id НЕ прописывать |
| Имена датчиков в ZONT | **«Имена в стиле существующих на зонте»** | «Температура \<место\> тёплый пол», как «Температура гостиная»/«Температура детская» |
### 31.5. 🔴 Замер: авто-id для 51/52/1 НЕ работает — три падения `Ошибка: 'id'`
Решение «Let allocator decide» потребовало **проверить**, а не предположить. Написан замер
`/tmp/test_autoid_granica2.py` (по образцу `/tmp/test_autoid_granica.py` из круга 50): снять `id`
у одного объекта нужного типа в **копии** целевого YAML → собрать энкодером → посмотреть exit и
наличие строки.
```bash
python3 /tmp/test_autoid_granica2.py
```
| Тест | Тип | Результат |
|---|---|---|
| A | 51 `modbus_devices` без id | ❌ `exit=3` · `Ошибка: 'id'` |
| B | 52 `modbus_registers` без id | ❌ `exit=3` · `Ошибка: 'id'` |
| C | 1 `virtual_sensors` без id | ❌ `exit=3` · `Ошибка: 'id'` |
**Это тот же питфолл 104 (§25.9), но в новых местах:** жёсткие обращения `obj['id']` срабатывают
**раньше** `_is_leaf_without_id`, поэтому до аллокатора дело не доходит. Белый список `_LEAF_TYPES`
расширить **недостаточно** — надо снимать барьеры в самих циклах сборки.
**Карта барьеров** (`grep -n "'id' in obj\|'id' not in obj" yml-to-config.py` — 6 мест):
| Строка | Место | Отношение к задаче |
|---|---|---|
| 553 | `_body_index` (тип 3) | не затрагивает |
| 1346 | цикл орфанов | не затрагивает |
| 1601 | `_is_body_inline` | не затрагивает |
| 2108 | цикл `TYPE_ORDER` — уже снят в круге 50 (комментарий на месте) | ✅ готово |
| 2112 | там же: `if 'id' not in obj:``_is_leaf_without_id` | расширяется через `_LEAF_TYPES` |
| 2145 | цикл helper-объектов | не затрагивает |
**Точки жёсткого доступа, которые надо править под 51/52/1:**
| Строка | Что | Почему падает |
|---|---|---|
| 327/345 | `virtual_sensors``_alloc_id(obj['id'])` | `obj['id']` при отсутствии ключа |
| 1783 | `register_ids = [reg['id'] for reg in nested_registers]` | 🔴 **вложенный** регистр без id — падение до присвоения |
| 1784 | `all_registers_to_write.sort(key=lambda r: r['id'])` | сортировка до выдачи id |
| 1831 | текст ошибки `register {obj['id']}` | обращение в сообщении |
🔴 **Тип 52 — НЕ секция, а вложенный объект** (`modbus_devices[].registers[]`), поэтому через
`_LEAF_TYPES` он не проедет: id регистра надо выдавать **внутри** прохода по устройствам (строка 1776),
до сбора `register_ids` и до сортировки. В белый список идут только **`{9, 1, 51}`**.
### 31.6. ✅ Bridge: работа НЕ нужна — slave'ы 105–112 уже прописаны
Фаза 2 плана (правка bridge) **отменена по факту**: живой шаблон на t610 уже содержит все 8 маппингов.
```bash
ssh root@192.168.2.176 'grep -nE "slave_id: (10[0-9]|11[0-9])" \
/addons/modbus-bridge/data/config.template.tmpl'
# → 100, 101, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112 (14 маппингов)
ssh root@192.168.2.176 'grep -nE "floor_temperature" \
/addons/modbus-bridge/data/config.template.tmpl'
# → все 8 entity_id на месте (living_room, severnaia, kabinet, kitchen,
# vannaia, prikhozhaia, dushevaia, toilet_1)
```
Файл: `config.template.tmpl`, mtime `2026-09-15 23:54`, 6473 байта. Бэкапы рядом:
`.bak-gard-20260915-225404`, `.bak-preids-20260915-223427` и др.
**⚠️ Проверка «мост реально отдаёт» НЕ завершена:** в логе аддона видны только
`Response: … from 100` (slaves 100104). Строк с 105–112 нет, потому что **ZONT их не опрашивает**
он не знает этих устройств. Мост отвечает только на запрос (ср. урок №5 плана §101: slave без ZONT'а
не проверить иначе, чем по `HA poll ->` в логе). После регистрации устройств на ZONT'е — проверить
логи заново.
### 31.7. Уточнённый план работ (2 фазы вместо 4)
| Фаза | Что | Статус |
|---|---|---|
| **1** | Снять + сконвертировать свежий конфиг, круг по всем снапшотам | ✅ **сделано**: 10/10 зелёный, `config_local_2026-09-18_00-45-31.{txt,yml}`, YAML идентичен `23-21-20` |
| ~~2~~ | ~~Bridge: добавить 7 маппингов~~ | ✅ **не требуется** — уже есть (§31.6) |
| **3** | Энкодер: расширить `_LEAF_TYPES` до `{9, 1, 51}` + снять барьеры `'id'` в 4 точках (§31.5) | ❌ не начато |
| **4** | ZONT YAML: +21 объект — 7 × тип 51 (slave 105111) + 7 × тип 52 (вложенные) + 7 × тип 1 | ❌ не начато |
| **5** | Энкодер → txt, круг зелёный, показать Alex'у 21 строку с выданными id | ❌ не начато |
| **6** | **Проверка Alex'ом в UI ZONT** → заливка → коммит | ❌ не начато |
**Имена (стиль существующих, решение Alex):**
| Slave | HA-сущность | Имя в ZONT |
|---|---|---|
| 105 | `sensor.living_room_floor_temperature_temperature` | Температура гостиная тёплый пол |
| 106 | `sensor.severnaia_floor_temperature_temperature` | Температура серая тёплый пол |
| 107 | `sensor.kabinet_floor_temperature_temperature` | Температура кабинет тёплый пол |
| 108 | `sensor.kitchen_floor_temperature_temperature` | Температура кухня тёплый пол |
| 109 | `sensor.vannaia_floor_temperature_temperature` | Температура ванная тёплый пол |
| 110 | `sensor.prikhozhaia_floor_temperature_temperature` | Температура прихожая тёплый пол |
| 111 | `sensor.dushevaia_floor_temperature_temperature` | Температура душевая тёплый пол |
Форма каждого объекта (зеркало `#Z8381`/`#Z8383`/`#Z8382` из §31.2):
```yaml
modbus_devices:
- slave_id: 105
name: Температура гостиная тёплый пол
poll_interval: 5000
timeout: 300000
registers:[{address: 100, function: holding_3_6, bit_width: 16,
signal_type: param_int16, direction: read}]
raw_params: [[], [], 0]
virtual_sensors:
- serial_number: '0'
name: Температура гостиная тёплый пол
register_id: <id выданного регистра>
connection_loss_delay_ms: 60000
```
**Один открытый вопрос:** slave **112** (`toilet_1_floor_temperature_temperature`) — мост его уже
отдаёт, но в план Alex'а он не входил. Добавлять 8-й датчик или оставить на потом?
### 31.8. Статус
| Что | Состояние |
|---|---|
| Свежий конфиг снят, конвертирован | ✅ `config_local_2026-09-18_00-45-31.{txt,yml}` — идентичен `23-21-20`, круг **10/10** |
| Разведка (11 slaves, 7 отсутствующих датчиков) | ✅ выполнена, факты §31.2–31.3 |
| Решения Alex | ✅ оба получены: авто-id + имена в стиле ZONT (§31.4) |
| Замер авто-id для 51/52/1 | ✅ выполнен — **все три типа падают** `Ошибка: 'id'` (§31.5) |
| Bridge | ✅ правка НЕ нужна — slaves 105–112 уже в шаблоне (§31.6) |
| План | ✅ уточнён: 6 фаз, фаза 1 закрыта (§31.7) |
| Правки кода / конфига | ❌ не начаты (правило: план прежде кода) |
| HEAD | `7e34ee1` (авто-id листьев + валидация ссылок) |