diff --git a/family/tech/zigbee-t610-z2m-i-zha.md b/family/tech/zigbee-t610-z2m-i-zha.md index 8c9b3c96..7925778d 100644 --- a/family/tech/zigbee-t610-z2m-i-zha.md +++ b/family/tech/zigbee-t610-z2m-i-zha.md @@ -1,10 +1,10 @@ --- title: "Zigbee на t610 — переезд Z2M → ZHA (выполнен, 2026-09-15)" created: '2026-09-15' -updated: '2026-09-15 (ночь-14: ✅ МИГРАЦИЯ ВЫПОЛНЕНА — мусор удалён, сущности + устройства переименованы, зоны восстановлены, 12/16 автоматизаций живых)' +updated: '2026-09-15 (ночь-15: найдена причина «кнопка не свитчит диммер» — `select.bed_dimmer_*` висят на чужом устройстве `sauna`; `light.bed_dimmer` не существует; `database.db` подтверждён как первоисточник)' type: tech namespace: family -status: 🟢 ПЕРЕЕЗД ВЫПОЛНЕН — ZHA работает, 13 устройств приняты автоматически, мусор Z2M удалён, сущности + устройства + зоны переименованы/восстановлены, 12/16 автоматизаций починены. Осталось: разбудить light_sensor_stairs + wireless_light_switch_bed (4 автоматизации ждут). +status: 🟡 ZHA работает, 15/16 устройств. Найден и разобран корень «кнопка спальни не свитчит диммер» (имена ушли не тем устройствам). Осталось: фикс имён (`light.bed_dimmer`) + 4 автоматизации + `light_sensor_stairs`. tags: - t610 - haos @@ -23,14 +23,16 @@ related: # Zigbee на t610 — переезд Z2M → ZHA (история + рабочий рецепт) -> 🚦 **СОСТОЯНИЕ НА 2026-09-15 (ночь-14) — ПЕРЕЕЗД ВЫПОЛНЕН:** +> 🚦 **СОСТОЯНИЕ НА 2026-09-15 (ночь-15) — ZHA РАБОТАЕТ, ИДЁТ ДОЧИСТКА ИМЁН:** > - ✅ **Три слоя мусора удалены:** 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`. -> - ⏳ **Осталось:** 4 автоматизации ждут 2 спящих батарейных (`light_sensor_stairs`, `wireless_light_switch_bed`). +> - 🔴 **НОЧЬ-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 батарейных. > - ⚠️ Z2M **остановлен**, не удалён. Данные целы в `/config/zigbee2mqtt/`. > 🔴 **ЧИТАТЬ ДАЛЬШЕ И КАК РЕЦЕПТ, И КАК РАЗБОР ОШИБОК.** Ниже: техника `reuse_settings` (проверена дважды), рабочий способ увидеть устройства ZHA (WebSocket), карта переименования по IEEE, разбор организационных провалов. @@ -300,7 +302,7 @@ ZHA их обнаруживает (уже в сети) — заново спар 5. ✅ **ВЫПОЛНЕНО ФАКТОМ — устройства приняты ZHA САМИ.** 12 сразу, `office_temperature_sensor` — позже, когда проснулся. **Итого 13 из 16.** Без «Add device» и без `zha.permit`. 6. ⬜ **ОСТАЛОСЬ — разбудить 2 не отозвавшихся** (`light_sensor_stairs`, `wireless_light_switch_bed`). Кнопкой на устройстве, **НЕ перепаривание**. > 📌 `office_temperature_sensor` — ✅ РАЗБУЖЕН И ПОДХВАЧЕН (ночь-14), переименован, зона `kabinet`. - > 📌 `sauna` (`0xa4c13882a4b42db0`) — в ZHA **так и не появилась**. Числилась Router'ом, но не вернулась; отдельная задача. + > ✅ **УТОЧНЕНО ночью-15:** `sauna` в ZHA **ЕСТЬ** — `device_id 700e14b7d1710526b00f098b8506826d`, `zha:a4:c1:38:4f:be:0b:3a:6b`, `name_by_user=sauna`, зона `kotelnaia`, сущность `switch.tz3210_nhqka112_ts011f`. Ранее записанное «не вернулась» — **неверно**. ⚠️ Но именно на неё ошибочно повешены `select.bed_dimmer_*` (см. §НОЧЬ-15). 7. ✅ **ВЫПОЛНЕНО (ночь-14) — переименование и починка ссылок.** Мусор удалён (127 сущностей + 18 устройств), 42 сущности + 13 устройств переименованы, 13 зон восстановлены, 12/16 автоматизаций пересобраны. См. §РЕЗУЛЬТАТ МИГРАЦИИ выше. > 🔴 **ИСПРАВЛЕНО ночью-13:** прежде здесь стояло «шаги 5-7 — только в UI, за клавиатурой, агентом нельзя». **Отменено.** Агент снял реестры через WebSocket, построил карту по IEEE и может выполнить переименование (`rename.py --apply`). Руками нужны **только батарейные** — физически нажать кнопку. @@ -787,14 +789,14 @@ unavailable: 8 — и НИ ОДНА не Zigbee: | `0xa4c13873b5c1575b` | office_table_light_switch | TS0002 | Router | | `0xa4c13807b64c7fd4` | kitchen_hood | TS0003 | Router | | `0xa4c1386d0839706a` | light_stairs | TS0002 | Router | -| `0xa4c138eb6fbe9d19` | sauna | TS011F | Router | +| `0xa4c138eb6fbe9d19` | **sauna** (в ZHA ✅ есть, `switch.tz3210_nhqka112_ts011f`) | TS011F | Router | | `0xa4c138b0f9e674a5` | wireless_light_switch_bed | TS0041 | EndDevice (батарея) | -| `0xa4c13882a4b42db0` | bed_dimmer | TS0052 | Router | -| `0xa4c138c4a94a6a31` | shower_2_presence_sensor | TS0601 | Router (mmWave) | -| `0xa4c1381694217e10` | boiler_water_leak | TS011F | Router | -| `0xa4c1383d5fcaa063` | (heating_cable_plug) | TS0207 | EndDevice | -| `0xa4c138c650636cf6` | (boiler_controller_power) | TS0201 | EndDevice | -| `0xa4c1384fbe0b3a6b` | heating_cable_plug | TS011F | Router | +| `0xa4c13882a4b42db0` | **bed_dimmer** (в ZHA ✅ есть, `light.tz3000_ooc8illt_ts0052`) | TS0052 | Router | +| `0xa4c138c4a94a6a31` | shower_2_presence_sensor (TS0601 = mmWave присутствие ✅) | TS0601 | Router (mmWave) | +| `0xa4c1381694217e10` | boiler_controller_power | TS011F | Router | +| `0xa4c1383d5fcaa063` | boiler_water_leak | TS0207 | EndDevice | +| `0xa4c138c650636cf6` | toilet_1_floor_temperature | TS0201 | EndDevice | +| `0xa4c1386d40ddb67b` | light_sensor_stairs (`_TZ3000_hy6ncvmw`, в сети ZHA ✅, сущностей нет) | TS0222 | EndDevice (батарея) | > Координатор: `0x0ceff6fffe9339f2`, `coordinator_ieee` `f23993fefff6ef0c`, imanufId 4169, ember/EZSP v13 (firmware 7.4.5 GA). @@ -881,6 +883,115 @@ state.json MD5 20bfb775cbab002e59d1be31a15db9e6 31. 🔴 **Автоматизации ссылаются на `device_id` + `entity_id`-UUID, а НЕ на `entity_id`.** Удаление устройств Z2M **убивает все 16 автоматизаций**, даже если сущности переименованы обратно. Проверять `config/device_registry/list` — если `device_id` из автоматизации в списке нет, триггер мёртв. Правка — только пересборка привязок по новым `device_id`. 32. 🔴 **Зоны (Areas) НЕ удаляются вместе с устройствами, но и НЕ восстанавливаются автоматически.** Отдельный реестр `area_registry` (11 зон уцелели). Пересозданные ZHA-устройства получают `area_id: null`. **После любой миграции зоны проставлять заново:** `config/device_registry/update` + поле **`area_id`** (= `slug` зоны, не отображаемое имя). 33. ⚠️ **Два устройства могут иметь ОДИНАКОВОЕ техническое имя.** `office_table_light_switch` и `light_stairs` — оба `_TZ3000_5gey1ohx TS0002`, различаются только по IEEE. В UI выглядят идентично; при массовых правках ключ — `device_id`, не имя. +34. 🔴 **`database.db` (Z2M) — ПОСТРОЧНЫЙ JSON LINES, не цельный JSON.** `jq '.devices[]'` даёт пустоту. Читать построчно: `json.loads` на каждую строку (см. §НОЧЬ-15). +35. 🔴 **ПЕРВОИСТОЧНИК — `database.db` / `configuration.yaml`, НЕ производные карты.** `rename-map.json`, `autofix-map.json`, `device-rename.json` — снимки, сделанные агентом; в них **мои же ошибки** (так перепутались `sauna` ↔ `bed_dimmer`). Сверять КАЖДЫЙ IEEE по `database.db` (`ieeeAddr` + `modelId` + `manufName` в одной строке). +36. 🔴 **Сущность может висеть на ЧУЖОМ `device_id`.** `select.bed_dimmer_power_on_behavior` / `select.bed_dimmer_switch_type` оказались на устройстве `sauna` (`700e14b7…`), а не на `bed_dimmer` (`e230c12e…`). **Проверка: если `entity_id` одного устройства ссылается на другой `device_id` — имена разошлись.** Тот же корень, что перепутанные IEEE: массовое переименование вслепую. +37. 🔴 **`select.*` / `number.*` (настройки) ZHA создаёт отдельно от `light.*`/`switch.*`** — при переименовании главной сущности настройки **остаются с техническим или чужим именем**. Проверять их отдельно. +38. 🔴 **Устройство может БЫТЬ в сети ZHA и не иметь ни одной сущности.** `light_sensor_stairs`: `iasCieAddr` = IEEE координатора ZHA, `lastSeen` свежий — значит **привязалось**, но сущностей нет (EndDevice спит, значение не менялось). **Проверять реестр по WebSocket, а не состояние сущностей** — иначе ложный вывод «не подхватился». +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.) + +--- + +## 🔴 НОЧЬ-15: разбор «кнопка не свитчит диммер» + два факта из бэкапа + +> **Триггер:** Alex — «Кнопка в спальне не свитчит диммер в спальне», плюс сомнение в модели датчика присутствия: «ты уверен что это `_TZE204_qasjif9e` — датчик присутствия??» и требование «проверяй ВСЁ из бэкапа». + +### ✅ Факт 1 — датчик присутствия определён верно + +Из Z2M-бэкапа (`~/tmp-t610/z2m-backup-20260915/database.db`), запись по строке: + +``` +0xa4c138c4a94a6a31 modelId: TS0601 manufName: _TZE204_qasjif9e +``` + +**`TS0601` / `_TZE204_qasjif9e` — это действительно mmWave-датчик присутствия** (Tuya-модуль, присутствие + illuminance + target distance + radar sensitivity). В ZHA устройство: `name_by_user=shower_2_presence_sensor`, `area=dushevaia`, `device_id=c9d62c9d04a231c4642c705088633121`. Сверено по `modelId`, а не по имени. **Ошибки нет.** + +### ✅ Факт 2 — источник истины: `database.db`, а не промежуточные карты + +> 🔴 **ПОЧЕМУ Я ПЕРЕПУТАЛ `sauna` ↔ `bed_dimmer` (ночь-14) — точная причина, найденная сейчас:** +> +> Я взял `~/tmp-t610/rename-map.json` — **производный файл, собранный мной же по кускам**. А `database.db` содержит **`ieeeAddr` + `modelId` + `manufName` + `nwkAddr` + `powerSource` одной строкой**, свериться можно было за одну команду. +> +> **УРОК: `database.db` — первоисточник. `rename-map.json`/`autofix-map.json`/`device-rename.json` — производные, они стареют и содержат мои же ошибки. Сверять ВСЕГДА по `database.db` или `/config/zigbee2mqtt/configuration.yaml`.** + +Рабочий разбор `database.db` (это **JSON-строки по строке на устройство**, не единый JSON): + +```bash +jq -r '.devices[]?...' database.db # ❌ НЕ работает — это не цельный JSON +``` + +```python +# ✅ правильно: файл — построчный JSON Lines +import json +recs = [] +for line in open("database.db", encoding="utf-8", errors="replace").read().splitlines(): + line = line.strip() + if line: + try: recs.append(json.loads(line)) + except Exception: pass +``` + +### 🔴 Факт 3 — почему кнопка спальни не свитчит диммер (корень найден) + +**Проверено фактом** (`config/device_registry/list` + `config/entity_registry/list` по WebSocket): + +``` +bed_dimmer device_id e230c12e6cb45492408ddba6456b6444 zha:a4:c1:38:82:a4:b4:2d:b0 + light.tz3000_ooc8illt_ts0052 ← ЕСТЬ, живой + button.tz3000_ooc8illt_ts0052_identifikatsiia + number.tz3000_ooc8illt_ts0052_vremia_perekhoda_mezhdu_vkliucheniem_i_vykliucheniem + sensor.*_rssi, sensor.*_lqi, update.* + +sauna device_id 700e14b7d1710526b00f098b8506826d zha:a4:c1:38:4f:be:0b:3a:6b + switch.tz3210_nhqka112_ts011f ← ЕСТЬ, живой + select.bed_dimmer_power_on_behavior ← 🔴 ИМЯ ОТ ДРУГОГО УСТРОЙСТВА + select.bed_dimmer_switch_type ← 🔴 ИМЯ ОТ ДРУГОГО УСТРОЙСТВА +``` + +> 🔴 **Новый класс ошибки, тот же корень:** `select.bed_dimmer_*` — это настройки реле **`sauna`**, но они названы «bed_dimmer». При ночном переименовании имена ушли **не тем устройствам**. **Ровно тот же класс, что перепутанные IEEE: правки по производной карте вслепую.** +> +> **Причина, почему кнопка не работает:** кнопка не рулит светом напрямую — она шлёт событие, автоматизация ловит его и зовёт сущность. Автоматизация ищет `light.bed_dimmer`, которого **не существует** (ZHA-имя с русской транслитерацией — `light.tz3000_ooc8illt_ts0052`). Событие кнопки уходит в пустоту. + +**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, не выполнен) + +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` фактом. + +> ⚠️ **Проверять после каждого шага чтением реестра обратно** — HA на `config/entity_registry/update` может ответить успехом, не применив значение. + +### 🔴 Факт 4 — `light_sensor_stairs` В СЕТИ, но сущностей нет + +Из `database.db`: + +``` +ieeeAddr: 0xa4c1386d40ddb67b modelId: TS0222 manufName: _TZ3000_hy6ncvmw +type: EndDevice powerSource: Battery +interviewCompleted: true interviewState: SUCCESSFUL +lastSeen: 1789478661136 ← 2026-09-15 ~21:24, ПОСЛЕ миграции +iasCieAddr: 0x0ceff6fffe9339f2 ← IEEE координатора ZHA (не Z2M!) +``` + +> ✅ **Вывод отменён:** раньше было записано «не дошёл / не подхватился». **Неверно.** Устройство **вышло на связь уже при ZHA** (`iasCieAddr` координатора ZHA, свежий `lastSeen`), т.е. **привязалось к ZHA**. Сущностей нет, потому что: `zoneState: 1` (зона в норме) + `measuredValue: 0` — ZHA создаёт сенсор освещённости только по первому **изменённому** значению, а EndDevice спит. +> +> ⚠️ **`manufName` у него `_TZ3000_hy6ncvmw`** — ранее в переписке я называл `_TZ3000_4ufaeuwv`, это была ошибка. +> **Рекомендация:** длинное нажатие паринг-кнопки 3–5 с (не короткий тык) + поднести к свету, затем **проверить реестр фактом через WebSocket**, а не по состоянию сущностей. + +### 🔴 ПИТФОЛЛ: `ha_ws.py` требует `/tmp/.hatok` + +Скрипт `~/tmp-t610/ha_ws.py` читает токен из `/tmp/.hatok` — файл **не переживает перезагрузку/очистку `/tmp`** (`FileNotFoundError`). Восстановление: + +```bash +cd ~/tmp-t610 && grep -o 'eyJ[A-Za-z0-9._-]*' ha_token.txt | head -1 > /tmp/.hatok +``` + +> 📌 `ha_ws.py ` — рабочий инструмент поиска `device_id`/`entity_id` по подстроке через WebSocket. Найти, что висит на устройстве: `python3 ha_ws.py find `. +> 📌 **Один `device_id` — одно устройство.** Если сущности одного устройства ссылаются на два разных `device_id` — это верный признак, что имена разошлись по чужим устройствам (как `select.bed_dimmer_*`). ---