[2026-09-15] eagle: family/how-to/ha-automations.md family/how-to/home-automation.md family/tech/zigbee-t610-z2m-i-zha.md

This commit is contained in:
Alexey Martemyanov
2026-09-15 20:18:26 +06:00
parent 51d0051e86
commit 8f8768d751
3 changed files with 93 additions and 39 deletions
+4
View File
@@ -2,6 +2,10 @@
> **Справочник логики автоматизаций** (`automations.yaml` на t610). Топология/команды/Modbus — [[family/how-to/home-automation]].
> 🔴 **ВНИМАНИЕ НА 2026-09-15: идёт переезд Zigbee Z2M → ZHA.** Сущности, перечисленные ниже, **сейчас `unavailable`** — они `platform=mqtt` (Z2M) и мертвы. Автоматизации будут бить в пустоту, пока ZHA-сущности не переименованы обратно в эти id. **Порядок восстановления и карта переименования — [[family/tech/zigbee-t610-z2m-i-zha]] §БЛОКЕР.** Не «чинить» автоматизации правкой до завершения переименования — иначе получится двойная миграция ссылок.
>
> Класс сущностей тоже меняется: `switch.night_light_shower_2` → ZHA даёт `light.*`; `switch.recirculation_pump` → ZHA `switch.*` (та же роль); `light.bed_dimmer` → ZHA отдаёт `switch.tz3210_nhqka112_ts011f` (домен `switch`, не `light`).
## 1. Где живёт
- **Файл:** `/config/automations.yaml` в HA Core на t610.
+7 -3
View File
@@ -2,7 +2,7 @@
title: "🏠 Домашняя автоматизация"
aliases: [Умный дом, Home automation, HA, Zigbee, Modbus, вентиляция, t610, RCU stall, USB reset]
tags: [family, how-to, smarthome]
updated: 2026-09-15 (ночь-12: Zigbee — переезд на ZHA ИДЁТ, ZHA сама приняла 12/16 устройств без перепаривания; Z2M остановлен, данные целы)
updated: 2026-09-15 (ночь-13: переезд на ZHA ИДЁТ — план из 4 шагов составлен, полная карта переименования по IEEE; блокер = 3 слоя мусорных сущностей)
---
# 🏠 Домашняя автоматизация
@@ -41,9 +41,13 @@ updated: 2026-09-15 (ночь-12: Zigbee — переезд на ZHA ИДЁТ, Z
> 🔴 **Камера сейчас на xHCI (`USB3-1`), Zigbee — на OHCI (`USB1-2`).** Но перестановка портов **НЕ является фиксом** — после чистого старта сбросы камеры вернулись и на xHCI. Причину RCU stall см. §3.1, ограничения диагностики — §3.4, §3.5.
> 🟡 **ZIGBEE: ИДЁТ ПЕРЕЕЗД НА ZHA (2026-09-15, ночь-12).** ZHA создана повторно (`reuse_settings`, сеть со стика) и 🔑 **САМА приняла 12 из 16 устройств — без перепаривания, без «Add device»**. Z2M **остановлен** (не удалён, данные целы). Осталось: переименовать сущности (блокер — старые id заняты мёртвыми Z2M-двойниками) + разбудить 4 батарейных.
> 🟡 **ZIGBEE: ИДЁТ ПЕРЕЕЗД НА ZHA (2026-09-15).** ZHA создана (`reuse_settings`, сеть со стика) и 🔑 **САМА приняла 12 из 16 устройств — без перепаривания, без «Add device»**. Z2M **остановлен** (не удалён, данные целы).
>
> 📌 **Перепаривание НЕ нужно — подтверждено фактом.** Устройства отвечают координатору, ZHA их принимает по NVRAM-сети. Имена даёт технические (`light.tz3000_*`), т.к. `friendly_name` из Z2M не читает. Рецепт, карта переименования, питфоллы — [[family/tech/zigbee-t610-z2m-i-zha]].
> **Блокер — три слоя сущностей одновременно:** `platform=mqtt` (мёртвые Z2M, ~120), `platform=switch_as_x` (прослойка под Z2M, ~6), `platform=zha` (живые, ~90). Автоматизации ссылаются на мёртвые → бьют в пустоту. Порядок: удалить два мёртвых слоя → переименовать ZHA-сущности в освободившиеся id.
>
> **План из 4 шагов составлен, ждёт подтверждения Alex.** Полная карта переименования по IEEE (16 главных сущностей), разбор неоднозначностей, питфоллы — [[family/tech/zigbee-t610-z2m-i-zha]] §БЛОКЕР.
>
> 📌 **Перепаривание НЕ нужно — подтверждено фактом.** Устройства отвечают координатору, ZHA их принимает по NVRAM-сети. Имена даёт технические (`light.tz3000_*`), т.к. `friendly_name` из Z2M не читает.
---
+82 -36
View File
@@ -161,13 +161,13 @@ ZHA их обнаруживает (уже в сети) — заново спар
1. ✅ **ВЫПОЛНЕНО — Полный snapshot HA.** Slug `ada4c8e5`, job `7d7aea7e536241e4af0ed5fc50cc83fb`, тип `full`, **123 МБ**, 2026-09-15 13:37 UTC. Второй, более ранний: `2880be7c` (13:35). Содержимое обоих: `homeassistant: true`, folders `share/ssl/media`, addons — все 7. **Бэкапы живы и остаются страховкой.**
2. ✅ **ВЫПОЛНЕНО — скачаны `coordinator_backup.json` + `database.db` + `configuration.yaml` + `state.json`** на Mac, md5 сверены (см. §Бэкапы).
3. ✅ **ВЫПОЛНЕНО — Z2M был остановлен** (`45df7312_zigbee2mqtt`, `stop`). **Сейчас снова запущен** (`state=started`).
4. ✅ **ВЫПОЛНЕНО — ZHA была создана** через config flow (`entry_id` `01M2JNE7J4EG6ZN08M06927SM0`, `state=loaded`, стратегия `reuse_settings`). **Сейчас УДАЛЕНА** прерванным `rollback.sh` — в списке config entries её нет.
5. **НЕ ДОДЕЛАНО — интервью устройств.** Требует UI: HA → Настройки → Устройства и службы → ZHA → **«Добавить устройство»**.
6. ⬜ Батарейные `EndDevice` (6 шт.) спят — разбудить кнопкой. Это **не перепаривание**.
7. ⬜ Задать 16 friendly names заново; переназначить `modbus-bridge`; переписать ссылки в 16 автоматизациях.
3. ✅ **ВЫПОЛНЕНО — Z2M остановлен** (`45df7312_zigbee2mqtt`, `stop`). ⚠️ Затем поднялся сам после прерывания скриптов; **на ночь-13 снова остановлен** (`mig-1-stop-z2m.sh`).
4. ✅ **ВЫПОЛНЕНО — ZHA создана** (`entry_id` `01M2JP57Y2FGSD17P829HFV44N`, `state=loaded`, `reuse_settings`). Первая попытка `01M2JNE7J4EG6ZN08M06927SM0` — удалена прерванным `rollback.sh`.
5. **ВЫПОЛНЕНО ФАКТОМ (ночь-12) — устройства приняты ZHA САМИ.** 12 из 16, без «Add device» и без `zha.permit`. **Это не нужно делать руками.**
6. ⬜ **Осталось — разбудить 4 не отозвавшихся** (`office_temperature_sensor`, `light_sensor_stairs`, `sauna`, `wireless_light_switch_bed`). Кнопкой на устройстве, **НЕ перепаривание**.
7. ⬜ **Осталось — переименование и починка ссылок** (блокер: 3 слоя мусора, см. §БЛОКЕР ночь-13). План из 4 шагов составлен, **ждёт подтверждения Alex**.
> 🔴 **Повтор возможен ТОЛЬКО как ручная операция в UI.** Агент может сделать шаги 1-4 (они отработаны, скрипты есть), но шаги 5-7 — за клавиатурой с кнопками в руках. Не начинать без готовности довести до конца.
> 🔴 **ИСПРАВЛЕНО ночью-13:** прежде здесь стояло «шаги 5-7 — только в UI, за клавиатурой, агентом нельзя». **Отменено.** Агент снял реестры через WebSocket, построил карту по IEEE и может выполнить переименование (`rename.py --apply`). Руками нужны **только батарейные** — физически нажать кнопку.
### 🔑 Рабочий рецепт: создание ZHA через config flow (HA core API)
@@ -289,59 +289,100 @@ ZHA их принимает и создаёт сущности — сама, б
имена даёт ТЕХНИЧЕСКИЕ (modelId_manufName), friendly_name из Z2M не читает
```
### Кто НЕ подхватился — 4 устройства, все батарейные (спят)
### Кто НЕ подхватился — 4 устройства (ночь-13, уточнено)
| IEEE | friendly_name | Почему нет |
|---|---|---|
| `0xa4c13862d39377e6` | office_temperature_sensor | EndDevice, спит |
| `0xa4c1386d40ddb67b` | light_sensor_stairs | EndDevice, спит |
| `0xa4c13882a4b42db0` | bed_dimmer | давно молчит (Router, но не отчитался) |
| `0xa4c13882a4b42db0` | **sauna** | Router, но давно молчит |
| `0xa4c138b0f9e674a5` | wireless_light_switch_bed | EndDevice, спит |
> 🔴 **ИСПРАВЛЕНО ночью-13.** В ночи-12 здесь ошибочно стоял `bed_dimmer` как «Router, но не отчитался». **Неверно:** `bed_dimmer` (`0xa4c1384fbe0b3a6b`) **подхватился** — в ZHA он `switch.tz3210_nhqka112_ts011f` с 7 сущностями. А вот **`sauna`** (`0xa4c13882a4b42db0`) действительно отсутствует, хотя в инвентаре числится Router'ом.
> ⚠️ Урок: тип «Router/EndDevice» в инвентаре выше — из Z2M-конфига и **не гарантирует присутствие**. Проверять фактом (WebSocket-реестр), а не по типу.
> 📌 Разбудить кнопкой — **это не перепаривание**, сети они уже принадлежат. 12 из 16 подхватились вообще без действий.
---
## 🔴 БЛОКЕР (ночь-12): старые `entity_id` заняты мёртвыми двойниками
## 🔴 БЛОКЕР (ночь-13): три слоя мусора, а не «просто переименовать»
ZHA создала **новые** сущности **рядом** со старыми, а не вместо них:
**Уточнение к ночи-12.** Проблема оказалась не «переименовать одно в другое», а **три независимых слоя** сущностей одновременно:
| Слой | `platform` | Что это | Сколько | Состояние |
|---|---|---|---|---|
| **A** | `mqtt` | мёртвые Z2M-сущности (`switch.recirculation_pump`, `light.smart_light_office_right`) | ~120 | ❌ `unavailable` навсегда |
| **B** | `switch_as_x` | прослойка-обёртка, ставилась под Z2M (`light.smart_light_office_left`) | ~6 | ❌ мертва, ZHA даёт `light` сама |
| **C** | `zha` | новые рабочие сущности с техническими id | ~90 | ✅ работают |
**Автоматизации и `modbus-bridge` ссылаются на A и B** → бьют в пустоту.
### Почему переименовать нельзя сразу
`config/entity_registry/update` **не переименует в занятый `entity_id`** — 9 из 16 целевых имён заняты слоями A/B.
> 🔴 **Порядок обязателен: удалить A и B → переименовать C в освободившиеся id.**
> ⚠️ Удаление сущностей **необратимо** — только по явной команде Alex. Страховка: snapshot `ada4c8e5` (123 МБ, full).
### ⚠️ Важно: имена слоёв A и C НЕ совпадают напрямую
Соблазн «удалить `switch.X` и переименовать в него zha-шный `switch.tz3000_*_2`» — **работает не везде**. Мёртвые имена не совпадают с новыми посуффиксно:
```
light.smart_light_office ← СТАРАЯ (Z2M), unavailable, мусор
light.tz3000_0e6uvexf_ts0012_osveshchenie ← НОВАЯ (ZHA), работает
слой A (мертво): switch.recirculation_pump
sensor.recirculation_pump_power / _current / _voltage / _energy
number.recirculation_pump_countdown
слой C (живо): switch.tz3000_gjnozsaz_ts011f_2
sensor.tz3000_gjnozsaz_ts011f_moshchnost_2 ← «мощность»
sensor.tz3000_gjnozsaz_ts011f_tok_2 ← «ток»
sensor.tz3000_gjnozsaz_ts011f_napriazhenie_2 ← «напряжение»
```
Оба набора висят одновременно. Автоматизации и `modbus-bridge` ссылаются на **старые** → бьют в пустоту.
**Мёртвые id — английские, ZHA даёт русские** (`moshchnost`, `tok`, `napriazhenie`, `itogo_postavleno`, `blokirovka_ot_detei`). Сопоставление делать **по функции, не по строке** — вручную через таблицу ниже.
**Переименовать нельзя:** при попытке `config/entity_registry/update``new_entity_id` маркируется **[СТАРОЕ ЗАНЯТО]`** (9 из 16 позиций).
> 📌 Практический вывод: у 12 подхватившихся устройств есть по 6–13 сущностей, но **главная — одна** (switch/light/binary_sensor). Её и переименовывать. Второстепенные (`sensor.*_lqi`, `sensor.*_rssi`, `update.*_obnovlenie_proshivki`, `button.*_identifikatsiia`) автоматизации не трогают — оставить техническими.
> 🔴 **Порядок обязателен: сначала удалить мёртвые Z2M-сущности, потом переименовывать ZHA-сущности в освободившиеся id.**
> ⚠️ Удаление сущностей **необратимо** — только по явной команде Alex.
### Полная карта переименования ГЛАВНЫХ сущностей (по IEEE, ночь-13)
### Карта переименования (составлена по IEEE, готова к применению)
| ZHA entity_id (текущий) | → целевой (= старый Z2M) | IEEE | пров. |
|---|---|---|---|
| `light.tz3000_3a9beq8a_ts0001` | `light.night_light_shower_2` | `84fd27fffed9e137` | ✅ |
| `light.tz3000_0e6uvexf_ts0012_osveshchenie` | `light.smart_light_office_left` | `a4c1381186ed1a32` | ⚠️ канал? |
| `light.tz3000_0e6uvexf_ts0012_osveshchenie_2` | `light.smart_light_office_right` | `a4c1381186ed1a32` | ⚠️ канал? |
| `light.tz3000_5gey1ohx_ts0002_osveshchenie` | `light.office_table_light_switch_l1` | `a4c13873b5c1575b` | ✅ |
| `light.tz3000_5gey1ohx_ts0002_osveshchenie_2` | `light.office_table_light_switch_l2` | `a4c13873b5c1575b` | ✅ |
| `light.tz3000_5gey1ohx_ts0002_osveshchenie_3` | `light.smart_light_stairs_l1` | `a4c1386d0839706a` | ✅ |
| `light.tz3000_5gey1ohx_ts0002_osveshchenie_4` | `light.smart_light_stairs_l2` | `a4c1386d0839706a` | ✅ |
| `light.tz3000_odzoiovu_ts0003_osveshchenie` | `light.kitchen_hood_l1` | `a4c13807b64c7fd4` | ✅ |
| `light.tz3000_odzoiovu_ts0003_osveshchenie_2` | `light.kitchen_hood_l2` | `a4c13807b64c7fd4` | ✅ |
| `light.tz3000_odzoiovu_ts0003_osveshchenie_3` | `light.kitchen_hood_l3` | `a4c13807b64c7fd4` | ✅ |
| `switch.tz3000_gjnozsaz_ts011f_2` | `switch.recirculation_pump` | `a4c138f8da8bc478` | ✅ 🔴 **на нём modbus-bridge** |
| `switch.tz3000_gjnozsaz_ts011f_3` | `switch.heating_cable_plug` | `a4c138eb6fbe9d19` | ✅ |
| `switch.tz3000_gjnozsaz_ts011f` | `switch.boiler_controller_power` | `a4c1381694217e10` | ✅ |
| `switch.tz3210_nhqka112_ts011f` | `light.bed_dimmer` | `a4c1384fbe0b3a6b` | ✅ ⚠️ класс switch→light |
| `binary_sensor.zbeacon_ts0207` | `binary_sensor.boiler_water_leak_water_leak` | `a4c1383d5fcaa063` | ✅ |
| `binary_sensor.tze204_qasjif9e_ts0601` | `binary_sensor.shower_2_presence_sensor_presence` | `a4c138c4a94a6a31` | ✅ |
| ZHA entity_id (текущий) | → целевой (= старый Z2M) |
|---|---|
| `light.tz3000_3a9beq8a_ts0001` | `light.night_light_shower_2` |
| `light.tz3000_0e6uvexf_ts0012_osveshchenie` | `light.smart_light_office_left` |
| `light.tz3000_0e6uvexf_ts0012_osveshchenie_2` | `light.smart_light_office_right` |
| `light.tz3000_5gey1ohx_ts0002_osveshchenie` | `light.office_table_light_switch_l1` |
| `light.tz3000_5gey1ohx_ts0002_osveshchenie_2` | `light.office_table_light_switch_l2` |
| `light.tz3000_5gey1ohx_ts0002_osveshchenie_3` | `light.smart_light_stairs_l1` |
| `light.tz3000_5gey1ohx_ts0002_osveshchenie_4` | `light.smart_light_stairs_l2` |
| `light.tz3000_odzoiovu_ts0003_osveshchenie` | `light.kitchen_hood_l1` |
| `light.tz3000_odzoiovu_ts0003_osveshchenie_2` | `light.kitchen_hood_l2` |
| `light.tz3000_odzoiovu_ts0003_osveshchenie_3` | `light.kitchen_hood_l3` |
| `switch.tz3000_gjnozsaz_ts011f_2` | `switch.recirculation_pump` |
| `switch.tz3210_nhqka112_ts011f` | `light.bed_dimmer` |
| `switch.tz3000_gjnozsaz_ts011f_3` | `switch.heating_cable_plug` |
| `switch.tz3000_gjnozsaz_ts011f` | `switch.boiler_controller_power` |
| `binary_sensor.zbeacon_ts0207` | `binary_sensor.boiler_water_leak_water_leak` |
| `binary_sensor.tze204_qasjif9e_ts0601` | `binary_sensor.shower_2_presence_sensor_presence` |
> 🔴 **Три устройства с одинаковым `_TZ3000_gjnozsaz`/`TS011F`** (`recirculation_pump`, `heating_cable_plug`, `boiler_controller_power`) различаются **только по IEEE**. Суффиксы `_2`/`_3` у ZHA — сквозная нумерация конфликтов имён, НЕ «второй канал».
> ⚠️ **`smart_light_office`: неоднозначность каналов.** ZHA дала `_osveshchenie` и `_osveshchenie_2`, а в Z2M было `left`/`right`. Слепое сопоставление неверно — **проверять вживую**: включить один канал, посмотреть, какая лампа загорелась.
> ⚠️ **`bed_dimmer`: смена класса домена.** В Z2M был `light.bed_dimmer` (обёртка `switch_as_x`), в ZHA — `switch.tz3210_nhqka112_ts011f`. Переименование в `light.*` потребует правки `entity_id` вместе с доменом; проверить, что автоматизации ждут именно `light`.
> ⚠️ **Сопоставление по IEEE, не по названию!** Три устройства имеют одинаковый `manufName _TZ3000_gjnozsaz` / `modelId TS011F` (`recirculation_pump`, `heating_cable_plug`, `boiler_controller_power`) — различить можно **только по IEEE**. Суффиксы `_2`/`_3` у ZHA не означают «второй канал» — это сквозная нумерация конфликтующих имён.
### План из 4 шагов (ожидает подтверждения Alex)
1. **Удалить слой A** — ~120 мёртвых `platform=mqtt` сущностей + их устройства-призраки. Необратимо.
2. **Удалить слой B** — ~6 `switch_as_x`. Прослойка была под Z2M, ZHA отдаёт `light` сама.
3. **Переименовать слой C** — 16 главных сущностей по таблице выше (второстепенные оставить техническими).
4. **Проверить** 16 автоматизаций + `modbus-bridge`.
**Три вопроса, на которые нужен ответ Alex:**
1. Удалять A и B? (страховка — snapshot `ada4c8e5`)
2. Как развести каналы `smart_light_office` — проверкой вживую?
3. Второстепенные сущности переименовывать или оставить техническими?
**Скрипт:** `~/tmp-t610/rename.py` (WS API, есть `--apply`), карта — `~/tmp-t610/rename-map.json`, построение по IEEE — `~/tmp-t610/map-full.py`.
**Скрипты ночи-13:** `~/tmp-t610/ws_dump.py` (реестры по WebSocket, env `HAHOST`/`HAPORT`/`HATOK`), `map_build.py` (ZHA-устройства по IEEE → сверка с `rename-map.json`), `map_ents.py` (сущности на устройство + поиск мёртвых по именам), `plan_build.py``plan-rows.json` (сводка по каждому устройству), `plan_show.py` (парное сравнение «старое ↔ ZHA»).
> 📌 **`ws_dump.py` важнее прежнего `ws-mac.py`** — не требует пакета `websocket-client`, работает на голом `socket` + `struct` (свой мини-клиент WS, включая pong на ping). Запуск: `HAHOST=192.168.2.176 HAPORT=80 HATOK="$(tr -d '\n\r ' < ha_token.txt)" python3 ws_dump.py``regs.json`. Снял **52 устройства, 624 сущности, 13 ZHA-устройств**.
---
@@ -545,6 +586,11 @@ state.json MD5 20bfb775cbab002e59d1be31a15db9e6
20. 🔴 **`config/entity_registry/update` не переименует в занятый `entity_id`.** Пока мёртвые Z2M-сущности на месте — 9 из 16 переименований заблокированы. Порядок: удалить мёртвые → переименовать.
21. ⚠️ **Суффиксы `_2`/`_3` у ZHA — не «второй канал», а сквозная нумерация конфликтующих имён.** Три разных устройства с `_TZ3000_gjnozsaz`/`TS011F` различаются **только по IEEE**.
22. ⚠️ **`zha.permit` для этой задачи бесполезен** — устройства уже в сети, они не «подключаются».
23. 🔴 **Имена мёртвых Z2M-сущностей (англ.) НЕ совпадают с ZHA-именами (рус.).** `sensor.recirculation_pump_power``sensor.tz3000_gjnozsaz_ts011f_moshchnost_2`. Сопоставлять **по функции**, не по строке. Прямое «удалить X → переименовать в X» работает не везде.
24. 🔴 **Три слоя, а не два.** `platform` бывает `mqtt` (мёртвые Z2M, ~120), `switch_as_x` (прослойка под Z2M, ~6) и `zha` (живые, ~90). Удалять надо **два** первых, а не только mqtt.
25. ⚠️ **Тип `Router` в Z2M-инвентаре не гарантирует, что устройство отзовётся ZHA.** `sauna` числится Router'ом, но в сеть не вернулась. Проверять по WebSocket-реестру фактом.
26. 🔴 **Токен НЕ передавать в python через argv/файл** — фильтр секретов режет строку при записи и портит файл (получал `TOKEN=os.env...`). **Фикс: читать из env (`os.environ["HATOK"]`), значение подставлять в bash-команде через `$(tr -d '\n\r ' < ha_token.txt)`.** Искажение видно только в отображении чата — файл на диске цел, проверять `grep -n` по нему.
27. 🔴 **Свой мини-клиент WebSocket без зависимостей.** `ws_dump.py` использует голый `socket` + `struct` + `base64`: рукопожатие `Sec-WebSocket-Key`, маскирование кадров, **обязательный pong на ping (opcode 0x9)** — без pong HA рвёт соединение. Пакет `websocket-client` больше не нужен.
---