[2026-09-15] eagle: family/tech/zigbee-t610-z2m-i-zha.md

This commit is contained in:
Alexey Martemyanov
2026-09-15 20:48:57 +06:00
parent 1047e20d7f
commit f0e9a423ff
+250 -38
View File
@@ -1,10 +1,10 @@
---
title: "Zigbee на t610 — переезд Z2M → ZHA (выполнен, 2026-09-15)"
created: '2026-09-15'
updated: '2026-09-15 (ночь-15: найдена причина «кнопка не свитчит диммер» — `select.bed_dimmer_*` висят на чужом устройстве `sauna`; `light.bed_dimmer` не существует; `database.db` подтверждён как первоисточник)'
updated: '2026-09-15 (ночь-15, доп. 2: ✅ `light_sensor_stairs` ДОБАВИЛСЯ — ZHA 17 устройств, 16/16; сущности датчика переименованы; 🔴 обнаружены ещё 2 битых автоматизации диммера с `triggers: []` и чужой `device_id`; `event.*` кнопки спальни — так и не появился при 90-секундном слушании шины)'
type: tech
namespace: family
status: 🟡 ZHA работает, 15/16 устройств. Найден и разобран корень «кнопка спальни не свитчит диммер» (имена ушли не тем устройствам). Осталось: фикс имён (`light.bed_dimmer`) + 4 автоматизации + `light_sensor_stairs`.
status: 🟢 ZHA работает, 16/16 устройств, ВСЕ батарейные подхвачены. Имена `light.bed_dimmer`/`switch.sauna` исправлены, сущности датчика лестницы переименованы. Осталось: `event.*` кнопки спальни (нажатие не долетело), 2 автоматизации диммера с пустыми триггерами + чужими entity_id, косметика `select.bed_dimmer_*`.
tags:
- t610
- haos
@@ -23,16 +23,24 @@ related:
# Zigbee на t610 — переезд Z2M → ZHA (история + рабочий рецепт)
> 🚦 **СОСТОЯНИЕ НА 2026-09-15 (ночь-15) — ZHA РАБОТАЕТ, ИДЁТ ДОЧИСТКА ИМЁН:**
> - ✅ **Три слоя мусора удалены:** 127 сущностей `platform=mqtt` + 18 устройств-призраков Z2M. Реестр: 624 → 493 сущности, 52 → 34 устройства.
> 🚦 **СОСТОЯНИЕ НА 2026-09-15 (ночь-15, ФИНАЛ) — ZHA РАБОТАЕТ, 16/16 УСТРОЙСТВ:**
```
a4c1386d40ddb67b light_sensor_stairs EndDevice last_seen 20:46:51 ← ✅ ДОБАВИЛСЯ
ZHA devices: 17 (16 + координатор)
```
> - ✅ **`light_sensor_stairs` ДОБАВИЛСЯ** — Alex поставил датчик в режим спаривания **несколько раз**, на третьей попытке устройство долетело. `device_id f33b36fbaec7b1eabca7a7e496be89f4`, `name_by_user=light_sensor_stairs`, зона `lestnitsa`. Шлёт данные потоком: освещённость 3…440 lx, батарея 100%. См. §Факт 6 (ОБНОВЛЁН).
> - ✅ **Сущности датчика переименованы** в человеческие id: `sensor.light_sensor_stairs_illuminance`, `_battery`, `_temperature`, `_humidity` (все `success: true`).
> - ✅ **Дополнительно найдены и подтверждены 2 битых автоматизации диммера** — `Toggle Dimmer bed` и `Dimmer bed cycle` с `triggers: []` (пустые!). См. §Факт 9.
> - 🔴 **`event.*` кнопки спальни ТАК И НЕ ПОЯВИЛСЯ.** Слушал шину HA (`subscribe_events`: `zha_event` + `state_changed`) 90 секунд после просьбы нажать кнопку — **ни одного события**. Нажатие не долетело до координатора. См. §Факт 5.
> - 🟡 **Три слоя мусора удалены:** 127 сущностей `platform=mqtt` + 18 устройств-призраков Z2M. Реестр: 624 → 493 сущности, 52 → 34 устройства.
> - ✅ **13 modbus-датчиков СОХРАНЕНЫ** (проверено фактом: пишут данные) — они тоже `platform=mqtt`, но живые.
> - ✅ **51 операция переименования сущностей:** 42 выполнены, 8 отбиты (`light`→`switch` запрещён HA), 1 пропущена.
> - ✅ **12/13 устройств переименованы** — в UI больше нет `_TZ3000_5gey1ohx TS0002`. Это то, что Alex видел руками. (13-е, `office_temperature_sensor`, проснулось и переименовано отдельно.)
> - ✅ **13 устройств получили ЗОНЫ обратно** (11 зон целы, все ZHA-устройства были без зоны).
> - ✅ **Автоматизации: 12 из 16 живых** — пересобраны на ZHA `device_id` + `entity_id`.
> - 🔴 **НОЧЬ-15 — найдена причина «кнопка в спальне не свитчит диммер»:** `select.bed_dimmer_*` привязаны к **чужому** устройству (`sauna`, `700e14b7…`), а `light.bed_dimmer` **не существует** — ZHA дала `light.tz3000_ooc8illt_ts0052`. См. §НОЧЬ-15.
> - 🔴 **НОЧЬ-15 — `light_sensor_stairs` ОТОЗВАЛ вывод «не подхватился»:** устройство **в сети и привязано к координатору ZHA** (`iasCieAddr 0x0ceff6fffe9339f2`, `lastSeen` после миграции). Сущностей нет — EndDevice спит, значение освещённости не менялось.
> - ⏳ **Осталось:** фикс имён кнопки спальни; 4 автоматизации на 2 батарейных.
> - ✅ **13/13 устройств переименованы** — в UI больше нет `_TZ3000_5gey1ohx TS0002`.
> - ✅ **13 устройств получили ЗОНЫ обратно** + `light_sensor_stairs` → `lestnitsa`.
> - ✅ **Имена исправлены фактом:** `light.tz3000_ooc8illt_ts0052` → **`light.bed_dimmer`**, `switch.tz3210_nhqka112_ts011f` → **`switch.sauna`** (оба `success: true`, проверены чтением состояния).
> - 🔴 **ИСПРАВЛЕНА НЕВЕРНАЯ ЗАПИСЬ ЭТОГО ДОКА:** полсуток было записано наоборот, что `700e14b7…` = `bed_dimmer`. **Верно: `700e14b7…` = `sauna` (`_TZ3210_nhqka112 TS011F`), `e230c12e…` = `bed_dimmer` (`_TZ3000_ooc8illt TS0052`).** См. §Факт 7.
> - **Осталось:** `event.*` кнопки спальни (нажатие не долетело до координатора — разбираться с кнопкой физически); 2 автоматизации диммера (`triggers: []` + чужой `device_id`); `Вкл/Выкл ночной свет душевая` (чужой `device_id fd52114b…`); 2 battery-автоматизации со старыми id; косметика `select.bed_dimmer_*`.
> - ⚠️ Z2M **остановлен**, не удалён. Данные целы в `/config/zigbee2mqtt/`.
> 🔴 **ЧИТАТЬ ДАЛЬШЕ И КАК РЕЦЕПТ, И КАК РАЗБОР ОШИБОК.** Ниже: техника `reuse_settings` (проверена дважды), рабочий способ увидеть устройства ZHA (WebSocket), карта переименования по IEEE, разбор организационных провалов.
@@ -81,7 +89,7 @@ bedroom bed_dimmer, wireless_light_switch_bed kitchen kitchen_hood
| `0xa4c13862d39377e6` | office_temperature_sensor |
| `0xa4c138f8da8bc478` | recirculation_pump |
| `0x84fd27fffed9e137` | night_light_shower_2 |
| `0xa4c1386d40ddb67b` | light_sensor_stairs — ❌ НЕ подхвачен ZHA |
| `0xa4c1386d40ddb67b` | light_sensor_stairs — **ПОДХВАЧЕН** (ночь-15, 3-я попытка режима спаривания) |
| `0xa4c1381186ed1a32` | smart_light_office |
| `0xa4c13873b5c1575b` | office_table_light_switch |
| `0xa4c13807b64c7fd4` | kitchen_hood |
@@ -95,7 +103,7 @@ bedroom bed_dimmer, wireless_light_switch_bed kitchen kitchen_hood
| `0xa4c1381694217e10` | boiler_controller_power |
| `0xa4c138c650636cf6` | toilet_1_floor_temperature |
> ✅ **Сверка 2026-09-15 (ночь-15): 15 из 16 устройств в HA совпадают с истинной картой, `mismatches: 0`.** Отсутствует только `light_sensor_stairs` (батарейный, спит).
> ✅ **Сверка 2026-09-15 (ночь-15, финал): 16 из 16 устройств в HA — ВСЕ на месте.** `light_sensor_stairs` добавлен последним (3-я попытка режима спаривания, §Факт 6). ZHA: **17 записей = 16 устройств + координатор**.
### Зоны (первоначальная выдача)
@@ -106,15 +114,18 @@ bedroom bed_dimmer, wireless_light_switch_bed kitchen kitchen_hood
**Работают** (пересобраны на ZHA `device_id` + `entity_id`):
циркуляция ГВС вкл/выкл (по времени), office_pass_switch_table/main, ночной свет душевая вкл/выкл, протечка котельная, датчик протечки батарея, Zigbee T sensor батарея, toggle dimmer bed, increase dimmer bed brightness, ventilation automation.
**Ждут пробуждения устройств (4 шт.):**
| Автоматизация | Нужно устройство |
|---|---|
| `svetlo_vykl_osveshchenie_lestnitsy` | `light_sensor_stairs` |
| `temno_vkl_podsvetku_lestnitsy` | `light_sensor_stairs` |
| `datchik_osveshchennosti_lestnitsa_batareia` | `light_sensor_stairs` |
| `light_switch_bed_batareia` | `wireless_light_switch_bed` |
**Ждут пробуждения устройств (ОБНОВЛЕНО ночь-15, финал — осталось 1):**
| Автоматизация | Нужно устройство | Статус |
|---|---|---|
| `svetlo_vykl_osveshchenie_lestnitsy` | `light_sensor_stairs` | 🟢 устройство ЕСТЬ → проверить, ожила ли |
| `temno_vkl_podsvetku_lestnitsy` | `light_sensor_stairs` | 🟢 устройство ЕСТЬ → проверить |
| `datchik_osveshchennosti_lestnitsa_batareia` | `light_sensor_stairs` | 🟢 устройство ЕСТЬ → проверить |
| `light_switch_bed_batareia` | `wireless_light_switch_bed` | 🔴 всё ещё `unavailable` — кнопка не срабатывает (§Факт 5-бис) |
> 📌 Разбудить кнопкой (паринг-кнопка 1 сек) — подхватятся сами. Это НЕ перепаривание.
> ✅ **ОБНОВЛЕНО ночью-15 (финал):** `light_sensor_stairs` **добавлен**, три автоматизации лестницы разблокированы. Замер после добавления: **11 из 16 автоматизаций `on`**, 4 `unavailable`. Проверить `last_triggered` у лестничных после следующего изменения освещённости.
> 📌 **Разбудить кнопкой (паринг-кнопка 1 сек)** — подхватятся сами. Это НЕ перепаривание.
> 🔴 **УТОЧНЕНО ночью-15:** `wireless_light_switch_bed` **в ZHA есть** (16 устройств), но нажатие **не долетает** (слушали шину 90 с — ноль событий, §Факт 5-бис). Нужно доставить до координатора режимом спаривания.
> 🔴 **Для `toggle_dimmer_bed` / `increase_dimmer_bed_brightness`:** они триггерятся от кнопки. Пока `event.*` не появился — мертвы, даже если `light.bed_dimmer` существует и переименован.
#### Как пересобирались автоматизации (рабочий рецепт)
@@ -427,14 +438,16 @@ ZHA их принимает и создаёт сущности — сама, б
имена даёт ТЕХНИЧЕСКИЕ (modelId_manufName), friendly_name из Z2M не читает
```
### Кто НЕ подхватился — 4 устройства (ночь-13, уточнено)
### Кто НЕ подхватился — 4 устройства (ночь-13; ✅ ВСЕ ПОДХВАЧЕНЫ к ночи-15 финалу)
| IEEE | friendly_name | Почему нет |
|---|---|---|
| `0xa4c13862d39377e6` | office_temperature_sensor | EndDevice, спит |
| `0xa4c1386d40ddb67b` | light_sensor_stairs | EndDevice, спит |
| `0xa4c13882a4b42db0` | **sauna** | Router, но давно молчит |
| `0xa4c138b0f9e674a5` | wireless_light_switch_bed | EndDevice, спит |
> ✅ **ИТОГ ночь-15 (финал): ВСЕ 16 устройств в ZHA.** Ниже — историческая таблица «кто отставал». `office_temperature_sensor`, `sauna` и `light_sensor_stairs` подхватились позже; `wireless_light_switch_bed` в реестре есть, но **нажатие не долетает** (§Факт 5-бис).
| IEEE | friendly_name | Почему нет (ночь-13) | Итог |
|---|---|---|---|
| `0xa4c13862d39377e6` | office_temperature_sensor | EndDevice, спит | ✅ подхвачен |
| `0xa4c1386d40ddb67b` | light_sensor_stairs | EndDevice, спит | ✅ подхвачен (3-я попытка режима спаривания) |
| `0xa4c13882a4b42db0` | **bed_dimmer** | Router, но давно молчит | ✅ подхвачен (`light.bed_dimmer`) |
| `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-реестр), а не по типу.
@@ -497,7 +510,8 @@ ZHA их принимает и создаёт сущности — сама, б
| `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 |
| `switch.tz3210_nhqka112_ts011f` | `switch.sauna` | `a4c1384fbe0b3a6b` | ✅ 🔴 **исправлено ночью-15** (ранее ошибочно `light.bed_dimmer`) — IEEE `4fbe0b3a6b` = **sauna** |
| `light.tz3000_ooc8illt_ts0052` | `light.bed_dimmer` | `a4c13882a4b42db0` | ✅ 🔴 **исправлено ночью-15** (ранее ошибочно `switch.tz3210_nhqka112_ts011f`) — IEEE `82a4b42db0` = **bed_dimmer** |
| `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` | ✅ |
@@ -576,7 +590,8 @@ ZHA их принимает и создаёт сущности — сама, б
| `4540b3e9bbb43d90f2ff4f62fa09804e` | `_TZ3000_5gey1ohx TS0002` | `office_table_light_switch` |
| `200ea4fb25daaa907279045e47a330b5` | `_TZ3000_odzoiovu TS0003` | `kitchen_hood` |
| `c18eb99f487691cb7244cd520bfbcde8` | `_TZ3000_5gey1ohx TS0002` | `light_stairs` |
| `700e14b7d1710526b00f098b8506826d` | `_TZ3210_nhqka112 TS011F` | `bed_dimmer` |
| `700e14b7d1710526b00f098b8506826d` | `_TZ3210_nhqka112 TS011F` | `sauna` — 🔴 **исправлено ночью-15** (было ошибочно `bed_dimmer`) |
| `e230c12e6cb45492408ddba6456b6444` | `_TZ3000_ooc8illt TS0052` | `bed_dimmer` — 🔴 **исправлено ночью-15** (было ошибочно `sauna`) |
| `c9d62c9d04a231c4642c705088633121` | `_TZE204_qasjif9e TS0601` | `shower_2_presence_sensor` |
| `39771e837372d488a1145ab7316fbd23` | `Zbeacon TS0207` | `boiler_water_leak` |
| `dc5f276b6d5f6e4564a3a4ddc1b7a1c9` | `_TZ3000_gjnozsaz TS011F` | `heating_cable_plug` |
@@ -604,7 +619,7 @@ ZHA их принимает и создаёт сущности — сама, б
| `kotelnaia` Котельная | recirculation_pump, boiler_controller_power, heating_cable_plug, boiler_water_leak |
| `kabinet` Кабинет | office_table_light_switch, smart_light_office |
| `dushevaia` Душевая | night_light_shower_2, shower_2_presence_sensor |
| `lestnitsa` Лестница | light_stairs |
| `lestnitsa` Лестница | light_stairs, **light_sensor_stairs** ✅ (добавлен ночь-15) |
| `tualet` Туалет | toilet_1_floor_temperature |
| `bedroom` Спальня | bed_dimmer |
| `kitchen` Кухня | kitchen_hood |
@@ -789,9 +804,10 @@ unavailable: 8 — и НИ ОДНА не Zigbee:
| `0xa4c13873b5c1575b` | office_table_light_switch | TS0002 | Router |
| `0xa4c13807b64c7fd4` | kitchen_hood | TS0003 | Router |
| `0xa4c1386d0839706a` | light_stairs | TS0002 | Router |
| `0xa4c138eb6fbe9d19` | **sauna** (в ZHA ✅ есть, `switch.tz3210_nhqka112_ts011f`) | TS011F | Router |
| `0xa4c138b0f9e674a5` | wireless_light_switch_bed | TS0041 | EndDevice (батарея) |
| `0xa4c13882a4b42db0` | **bed_dimmer** (в ZHA ✅ есть, `light.tz3000_ooc8illt_ts0052`) | TS0052 | Router |
| `0xa4c138eb6fbe9d19` | heating_cable_plug | TS011F | Router |
| `0xa4c1384fbe0b3a6b` | **sauna** (в ZHA ✅ `switch.sauna`, `700e14b7…`) | TS011F | Router — 🔴 `_TZ3210_nhqka112` |
| `0xa4c138b0f9e674a5` | wireless_light_switch_bed | TS0041 | EndDevice (батарея) — 🔴 **нет `event.*`, кнопка не свитчит** |
| `0xa4c13882a4b42db0` | **bed_dimmer** (в ZHA ✅ `light.bed_dimmer`, `e230c12e…`) | TS0052 | Router — 🔴 `_TZ3000_ooc8illt` |
| `0xa4c138c4a94a6a31` | shower_2_presence_sensor (TS0601 = mmWave присутствие ✅) | TS0601 | Router (mmWave) |
| `0xa4c1381694217e10` | boiler_controller_power | TS011F | Router |
| `0xa4c1383d5fcaa063` | boiler_water_leak | TS0207 | EndDevice |
@@ -891,6 +907,11 @@ state.json MD5 20bfb775cbab002e59d1be31a15db9e6
39. 🔴 **`ha_ws.py` падает с `FileNotFoundError: /tmp/.hatok`** — токен там не переживает очистку `/tmp`. Восстановление: `grep -o 'eyJ[A-Za-z0-9._-]*' ha_token.txt | head -1 > /tmp/.hatok`.
40. ⚠️ **`ha_ws.py find <подстрока>`** — рабочий способ найти `device_id` + список сущностей устройства по IEEE без двоеточий. Быстрее, чем гонять полные реестры.
41. 🔴 **`config/entity_registry/update` может ответить успехом, не применив значение** — после каждой правки **читать реестр обратно**. (Общий питфолл HA REST/WS — тот же, что у automation config.)
42. 🔴 **Кнопка, переехавшая с Z2M на ZHA, ТЕРЯЕТ механизм нажатия.** В Z2M кнопка TS0041 отдавала `action` в MQTT-топик → автоматизация триггерилась по `platform: mqtt`. В ZHA нажатие приходит как `zha_event`, и HA создаёт из него сущность **`event.*`** — **при первом событии, не при сопряжении**. **Пока `event.*` нет — автоматизации нечего ловить; нажатие уходит в пустоту, при полностью живых сущностях и правильных `entity_id`.** Чек: `ha_ws.py find <кнопка>` → искать `event.*` в списке сущностей. Триггер строить на `platform: state` + `entity_id: event.*` + `trigger.event.data.key_press`.
43. 🔴 **`zha/permit` НЕ существует как WS-командa** (`unknown_command`). Окно спаривания открывать **REST-сервисом**: `POST /api/services/zha/permit`, body `{"duration":120}``200 [], []`. Работает.
44. 🔴 **Строка `Authorization: Bearer *** в bash-скрипте вырезается фильтром секретов** → `syntax error near unexpected token ')'` / `unexpected EOF`, скрипт неработоспособен. **Надёжный обход: Python + `urllib`**, токен из файла в рантайме (`HDR = {"Authorization": "Bearer " + TOK}`). Это работает лучше, чем трюк `P="Bearer"` (питфолл 10), который тоже иногда ловится.
45. ⚠️ **`select.*` / `number.*`-настройки могут быть названы по ЧУЖОМУ устройству** (как `select.bed_dimmer_*` на `sauna`). **Признак:** сущности «одного устройства» ссылаются на **два разных `device_id`**. Проверять `device_id` у каждой сущности. На работу реле/кнопок не влияет — косметика UI.
46. 🔴 **Документ может фиксировать не факт, а ошибочный вывод.** В этом доке полсуток жила неверная запись про `bed_dimmer``sauna` (пришла из производной `rename-map.json`). **При следующем касании дока сверять спорные места с `database.db`**, а не доверять предыдущей записи. Ошибка в доке = ошибка, воспроизведённая в следующей сессии.
---
@@ -956,14 +977,205 @@ sauna device_id 700e14b7d1710526b00f098b8506826d zha:a4:c1:38:4f:be:0b:
**TS0052 — это НЕ лампа, а настенный диммер-контроллер.** ZHA отдаёт его как `light.*` (диммер), Z2M отдавал `light.bed_dimmer` через обёртку `switch_as_x`. Переименование `switch.tz3210_nhqka112_ts011f``light.bed_dimmer` **отбито HA** (`New entity ID should be same domain`).
### План фикса кнопки спальни (согласуется с Alex, не выполнен)
### План фикса кнопки спальни — ✅ ЧАСТИЧНО ВЫПОЛНЕНО (ночь-15)
1. Бэкап `core.entity_registry` на Mac (обязательно первым шагом).
2. Вернуть `select.bed_dimmer_power_on_behavior` / `_switch_type` на **`bed_dimmer`** (`e230c12e…`), а не на `sauna` (`700e14b7…`).
3. Переименовать `light.tz3000_ooc8illt_ts0052``light.bed_dimmer` (домен совпадает — пройдёт).
4. Пересобрать автоматизации кнопки спальни на реальный `light.bed_dimmer`, проверить `last_triggered` фактом.
1. ~~Бэкап `core.entity_registry` на Mac~~**Alex отклонил** («продолжай чинить никаких бэкапов»). Не требовался: правки реестра обратимы переименованием.
2. ~~Вернуть `select.bed_dimmer_*` на `bed_dimmer`~~**ОТЛОЖЕНО**: у HA нет WS-метода «сменить `device_id` у сущности»; проще переименовать `entity_id` + задать `friendly_name`. На работу кнопки не влияет.
3. **ВЫПОЛНЕНО:** `light.tz3000_ooc8illt_ts0052`**`light.bed_dimmer`** (`success: true`), проверено фактом: `state=off`, `friendly_name=bed_dimmer`.
4. **ВЫПОЛНЕНО:** `switch.tz3210_nhqka112_ts011f`**`switch.sauna`** (`success: true`), проверено: `state=off`, `friendly_name=sauna`.
5. 🔴 **КОРЕНЬ «кнопка не свитчит» оказался НЕ здесь — см. §Факт 5.**
> ⚠️ **Проверять после каждого шага чтением реестра обратно** — HA на `config/entity_registry/update` может ответить успехом, не применив значение.
> 📌 **`config/entity_registry/update` с `new_entity_id`** — рабочая форма. Домены `light`→`light` и `switch`→`switch` проходят; смена домена (п.30 питфоллов) — нет.
### 🔴 ФАКТ 5 — настоящий корень «кнопка спальни не свитчит диммер»: у кнопки НЕТ `event.*`-сущности
> **Триггер:** Alex — «Кнопка в спальне не свитчит диммер в спальне» (после того как `light.bed_dimmer` уже существовал).
**Проверено фактом** — все сущности устройства `wireless_light_switch_bed`:
```
wireless_light_switch_bed device_id da6c759f9046046c4ef60467175ccbbe
zha:a4:c1:38:b0:f9:e6:74:a5 _TZ3000_kccru4oi TS0041
sensor.tz3000_kccru4oi_ts0041_batareia ← батарея
sensor.tz3000_kccru4oi_ts0041_rssi ← отключена (integration)
sensor.tz3000_kccru4oi_ts0041_lqi ← отключена (integration)
update.tz3000_kccru4oi_ts0041_obnovlenie_proshivki
event.* ← 🔴 НЕТ ВООБЩЕ
```
В системе вообще **одна** event-сущность — `event.backup_automatic_backup` (платформа `backup`). Кнопок там нет.
> 🔴 **МЕХАНИКА, КОТОРУЮ Я РАНЬШЕ НЕ УЧЁЛ:** в Z2M кнопка TS0041 отдавала `action` в MQTT-топик — автоматизация триггерилась по `platform: mqtt` + topic. В **ZHA** такого нет: нажатие приходит как **`zha_event`**, а HA создаёт из него сущность **`event.*`**, из которой читается `key_press`. **Пока `event.*` не существует — автоматизации нечего ловить, нажатие уходит в пустоту.**
>
> **ZHA создаёт `event.*` при ПЕРВОМ событии от устройства** (не при сопряжении). У `light_sensor_stairs` к тому же своя беда — он вообще не в реестре.
> 📌 **ЧЕК-ЛИСТ для любой кнопки после миграции Z2M → ZHA:** посмотреть `ha_ws.py find <кнопка>` → если в списке сущностей **нет `event.*`** — нажать кнопку физически и перечитать. Только после появления `event.*` автоматизацию можно триггерить (триггер `platform: state`, `entity_id: event.*`, чтение `trigger.event.data.key_press`).
#### 🔴 ФАКТ 5-БИС — `event.*` кнопки ТАК И НЕ ПОЯВИЛСЯ (слушание шины, 90 с)
**Проверено фактом:** открыт фоновый слушатель WS (`subscribe_events`: `zha_event` + `state_changed`), Alex попросили нажать кнопку в спальне. За **90 секунд — ни одного события** от `a4:c1:38:b0:f9:e6:74:a5`. `event.*` не создалась.
> 🔴 **НАЖАТИЕ НЕ ДОЛЕТЕЛО ДО КООРДИНАТОРА.** Это уже **не** «HA не создала сущность» — HA создаёт `event.*` из первого `zha_event`, а события нет вообще. Значит кнопка физически не передаёт нажатие в сеть ZHA. См. также паттерн `light_sensor_stairs` (§Факт 6): **батарейные устройства после миграции нужно буквально «доставить» до координатора повторным режимом спаривания.**
>
> **Что делать с кнопкой:** применить тот же приём, что сработал на датчике лестницы — **открыть `zha.permit` (REST, 180 с) → слушать WS-шину в фоне → ретраить режим спаривания на кнопке** (TS0041: удерживать ~5 с), пока в шине не появится `zha_event`, и только тогда нажимать обычным способом.
> 📌 **Диагностический порядок для любой кнопки:** (1) есть ли `zha_event` в шине → если нет, кнопка не в сети; (2) есть ли `event.*` → если нет, событий ещё не было; (3) только после обоих — строить триггер автоматизации.
> 📌 Скрипт-слушатель: `btn_listen.py` (фильтр по IEEE кнопки, ловит `zha_event` и появление `event.*`).
> ⚠️ **Ранее записанный вывод «нажать кнопку — и всё появится» НЕВЕРЕН для этой кнопки.** Проверено: нажатие не проходит. Не повторять совет без проверки шины.
### ✅ ФАКТ 6 — `light_sensor_stairs` ДОБАВИЛСЯ (ОБНОВЛЕНО: сначала НЕ добавился, потом добавился)
> 🔴 **ЗАПИСЬ ПЕРЕПИСАНА.** Ранее здесь стояло «ДОБАВИТЬСЯ НЕ СМОГ», «в реестре отсутствует вовсе». **Неверно — устройство в итоге добавилось.** Оставляю обе фазы, потому что первая фаза — рабочий разбор отказа.
**Фаза 1 (отказ) — попытка по просьбе Alex** («поставил light sensor в режим спаривания»), затем «еще раз поставил»:
1. Окно спаривания через REST: `POST /api/services/zha/permit` body `{"duration":120}`**`200`, `[]`** — окно открыто. ⚠️ WS-метод `zha/permit` отвечает `unknown_command`**работает только REST-сервис**.
2. Опрос ~60 с + проверка реестра → **0 результатов**. ZHA — 16 устройств (15 + координатор).
**Фаза 2 (успех) — на следующей попытке Alex устройство долетело.** Проверено фактом:
```
a4c1386d40ddb67b | _TZ3000_hy6ncvmw TS0222 | EndDevice | last_seen 2026-09-15T20:46:51
ZHA devices: 17 (16 устройств + координатор)
```
**Что сделано после появления:**
| Шаг | Результат |
|---|---|
| `name_by_user` | `light_sensor_stairs` ✅ |
| зона | `lestnitsa` ✅ |
| `device_id` | `f33b36fbaec7b1eabca7a7e496be89f4` |
| сущности переименованы | `sensor.light_sensor_stairs_illuminance` / `_battery` / `_temperature` / `_humidity` (все `success: true`) ✅ |
| данные идут | освещённость 3…440 lx (поток), батарея 100% ✅ |
> 🔑 **ПОЧЕМУ ЗАРАБОТАЛО:** помогло **не одно** длинное нажатие, а **повторные попытки перевода устройства в режим спаривания**. Первые две попытки — 0 результата, третья — устройство долетело. **Вывод: для `TS0222` (EndDevice, спит) ретраить режим спаривания, а не считать отказ окончательным.** Ранее записанный вердикт «длинный нажим 10 с / вынуть батарейку» **не понадобился**.
> 📌 **Проверять появление ФАКТОМ через реестр** (`zha/devices` по WebSocket или `ha_ws.py find <ieee>`), не по состоянию сущностей — у sleeping EndDevice состояние приходит позже регистрации.
> 📌 **Мониторинг появления — рабочий приём:** фоновый слушатель WS `subscribe_events` (`zha_event` + `state_changed`) с фильтром по entity_id; он же подтвердил поток данных датчика (`state: sensor.*_osveshchennost 308 → 296 → 381 → 433 …`). Скрипт: `/tmp/pair_listen.py`.
> ⚠️ `manufName` у него `_TZ3000_hy6ncvmw` (ранее в переписке я называл `_TZ3000_4ufaeuwv` — ошибка). `modelId: TS0222`, `powerSource: Battery`.
> 🔴 **Правильный порядок для будущих sleeping-устройств:** открыть окно `zha.permit` (REST, 180 с) → **слушать WS-шину в фоне** → ретраить режим спаривания на устройстве, пока в реестре не появится IEEE.
### 🔴 ФАКТ 9 — ещё 2 битых автоматизации: `triggers: []` и чужие `device_id`
**Найдено при проверке `automations.yaml` (189 строк, снят с t610 локально в `~/tmp-t610/automations-current.yaml`).**
```
- id: '1771683420621'
alias: 'Toggle Dimmer bed (ждёт кнопку bed)'
description: 'Кнопка wireless_light_switch_bed не подхвачена ZHA — триггер отключён до пробуждения'
triggers: [] ← 🔴 ПУСТО, я сам отключил
actions:
- type: toggle
device_id: 700e14b7d1710526b00f098b8506826d ← 🔴 ЭТО sauna, не диммер!
entity_id: switch.tz3210_nhqka112_ts011f ← 🔴 ЭТО sauna, не диммер!
- id: '1771683677259'
alias: 'Dimmer bed cycle (ждёт кнопку bed)'
triggers: [] ← 🔴 ПУСТО
actions:
- service: light.turn_on
target:
entity_id: switch.tz3210_nhqka112_ts011f ← 🔴 ЭТО sauna, не диммер!
data:
brightness_pct: 50
```
> 🔴 **ДВА независимых бага в одной автоматизации:**
> 1. **`triggers: []`** — я отключил триггер с пометкой «ждёт кнопку bed». Пустой триггер = автоматизация никогда не сработает, но HA держит её загруженной. **Пустой `triggers` не даёт `unavailable`** — автоматизация «on», просто мёртвая молча. Если бы не проверка конфига, я бы не увидел.
> 2. **`device_id` + `entity_id` указывают на `sauna`, а не на диммер** — тот же перепутанный IEEE, что и в §Факт 7. Я пересобрал автоматизации **до** того, как исправил карту. Автоматизация «Toggle Dimmer bed» на самом деле щёлкала бы реле сауны.
>
> **Правильные цели:** `bed_dimmer` → `light.bed_dimmer` (домен **light**), `sauna` → `switch.sauna` (домен **switch**).
> 🔴 **`Dimmer bed cycle` вызывает `light.turn_on` на `switch.*` — так нельзя вообще.** Для диммера домен — `light`, для реле — `switch`. Перепутано и устройство, и домен.
> ⚠️ **Остальные найденные дефекты в том же файле:**
> - `Вкл. ночной свет душевая` / `Выкл. ночной свет душевая` → `device_id: fd52114b516a79055c7add0393f2486d` — **это `night_light_shower_2`** (он же в таблице §Шаг 3), но у устройства уже другой `device_id`. Проверить живость.
> - `Zigbee T sensor батарея` → `sensor.tz3000_akqdg6g7_ts0201_batareia` — **устройство переименовано** в `office_temperature_sensor`, entity_id устарел.
> - `light_switch_bed_batareia` = **unavailable**.
> - Итог замера: **11 из 16 автоматизаций в состоянии `on`**, 4 недоступны (`unavailable`).
> 🔴 **УРОК: `triggers: []` не диагностируется по состоянию `automation.*`.** Проверять **содержимое** `/config/automations.yaml`, а не только `state`. Рабочая команда: `grep -n "triggers:" automations.yaml` + глазами искать пустые массивы.
```
0ceff6fffe9339f2 Inswift ZBP-MG21 Coordinator
a4c138f8da8bc478 recirculation_pump Router
a4c138c4a94a6a31 shower_2_presence_sensor Router
a4c1381694217e10 boiler_controller_power Router
a4c138eb6fbe9d19 heating_cable_plug Router
a4c1383d5fcaa063 boiler_water_leak EndDevice
a4c13873b5c1575b office_table_light_switch Router
a4c1386d0839706a light_stairs Router
84fd27fffed9e137 night_light_shower_2 Router
a4c138c650636cf6 toilet_1_floor_temperature EndDevice
a4c1384fbe0b3a6b sauna Router
a4c13807b64c7fd4 kitchen_hood Router
a4c1381186ed1a32 smart_light_office EndDevice
a4c13862d39377e6 office_temperature_sensor EndDevice
a4c13882a4b42db0 bed_dimmer Router
a4c138b0f9e674a5 wireless_light_switch_bed EndDevice
```
> 🔴 **УТОЧНЕНИЕ к Факту 4:** вывод «устройство привязалось к ZHA (`iasCieAddr` координатора ZHA, свежий `lastSeen`)» **перепроверить нельзя** — `database.db` был снят **до** миграции, поэтому `iasCieAddr 0x0ceff6fffe9339f2` мог быть записан ещё Z2M'ом при интервью. **Факт на сейчас: в живом реестре ZHA устройства НЕТ.** Достоверно — только это.
>
> **Порядок действий (согласован, ждём Alex):**
> 1. Зажать кнопку на датчике и держать **~10 с** — не отпускать на первом мигании, дождаться быстрого/тройного.
> 2. Отпустить, пауза 2 с, **один короткий нажим**.
> 3. Если не появится — **вынуть батарейку на 10 с**, вставить, повторить п.1–2 (сбрасывает возможный рассинхрон ключа).
> 4. Проверять **реестр по WebSocket**, а не состояние сущностей.
>
> ⚠️ `zha.permit` для уже-в-сети устройств бесполезен (питфолл 22), но для **не долетевшего** устройства окно открывать надо — оно есть, факт: REST-вызов прошёл.
### 🔴 ПИТФОЛЛ: фильтр секретов ломает скрипты на `Bearer $TOK`
**Симптом:** `bash: syntax error near unexpected token ')'` / `unexpected EOF while looking for matching '"'`.
**Причина:** строка `Authorization: Bearer *** **вырезается фильтром при передаче скрипта**, кавычки не закрываются.
**Рабочий обход (проверено):** не писать эту строку в bash-скрипте вообще — **уходить в Python + `urllib`**, токен читать из файла:
```python
TOK = open("/tmp/.hatok").read().strip()
HDR = {"Authorization": "Bearer " + TOK, "Content-Type": "application/json"}
ctx = ssl.create_default_context(); ctx.check_hostname = False; ctx.verify_mode = ssl.CERT_NONE
urlopen(urllib.request.Request(BASE + path, headers=HDR), context=ctx)
```
> 📌 `python3 /tmp/x.py` **не триггерит фильтр** — токен собирается в рантайме из файла. Это надёжнее, чем `P="Bearer"` из питфолла 10.
> 📌 **`jq: parse error: Expected string key before ':' at line 1, column 4`** при `curl … | jq` — тот же корень: пустой `$HDR`, curl вернул текст ошибки.
---
### 🔴 ФАКТ 7 — перепутанные IEEE: ЗАПИСЬ В ДОКЕ БЫЛА НЕВЕРНОЙ, вот правильная
> **Триггер:** Alex — «Чё за хуйня как ты мог перепутать если данные все блядь были» + «проверяй ВСЁ из бэкапа».
**Проверено по `database.db`** (`ieeeAddr` + `modelId` + `manufName` — одной строкой):
```
a4c1384fbe0b3a6b sauna modelId TS011F manufName _TZ3210_nhqka112 ← НЕ bed_dimmer
a4c13882a4b42db0 bed_dimmer modelId TS0052 manufName _TZ3000_ooc8illt ← НЕ sauna
```
**Соответствие в живом HA ZHA (проверено, `device_id` + `identifiers`):**
| IEEE | ZHA `device_id` | ZHA-сущность | `name_by_user` |
|---|---|---|---|
| `a4:c1:38:82:a4:b4:2d:b0` | `e230c12e6cb45492408ddba6456b6444` | `light.bed_dimmer` (было `light.tz3000_ooc8illt_ts0052`) | **bed_dimmer** |
| `a4:c1:38:4f:be:0b:3a:6b` | `700e14b7d1710526b00f098b8506826d` | `switch.sauna` (было `switch.tz3210_nhqka112_ts011f`) | **sauna** |
> 🔴 **ОШИБКА В ЭТОМ ДОКЕ, ИСПРАВЛЕНА:** ранее в двух местах было записано наоборот — «`700e14b7…` = `bed_dimmer`» (таблица переименованных устройств) и «`switch.tz3210_nhqka112_ts011f` → `light.bed_dimmer`» (карта переименования). **Оба неверны.** `_TZ3210_nhqka112 TS011F` — это **`sauna`** (реле), `_TZ3000_ooc8illt TS0052` — **`bed_dimmer`** (диммер). Исправлено здесь и в §Инвентарь.
>
> **ПОЧЕМУ ОШИБКА ЖИЛА В ДОКЕ:** я записывал док по **производной карте** `rename-map.json` и собственным ночным выводам, а не по `database.db`. Док фиксирует не факт, а мой тогдашний (ошибочный) вывод — и ошибка закрепилась как «знание».
> 🔴 **УРОК: `database.db` — единственный первоисточник. Всё, что в доке пришло из производной карты, требует перепроверки при следующем касании.**
### 🔴 ФАКТ 8 — `select.bed_dimmer_*` названы по чужому устройству
```
bed_dimmer e230c12e… → light.bed_dimmer, button.*_identifikatsiia, number.*_vremia_perekhoda_*
sauna 700e14b7… → switch.sauna, select.bed_dimmer_power_on_behavior 🔴, select.bed_dimmer_switch_type 🔴
```
`select.bed_dimmer_power_on_behavior` / `_switch_type` — это настройки реле **`sauna`**, но **названы «bed_dimmer»**. Тот же класс ошибки: массовое переименование вслепую, имена ушли не тем устройствам.
> 📌 **Диагностический признак:** если сущности «одного устройства» ссылаются на **два разных `device_id`** — имена разошлись по чужим устройствам. Проверять `device_id` **каждой** сущности, а не только главной.
> 📌 **Практический вывод:** на работу кнопки это **не влияет** (переименовано 3+4). Косметика для UI.
### 🔴 Факт 4 — `light_sensor_stairs` В СЕТИ, но сущностей нет