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

This commit is contained in:
Alexey Martemyanov
2026-09-15 21:09:17 +06:00
parent 43d7857991
commit bada739d27
+99 -10
View File
@@ -1,10 +1,10 @@
---
title: "Zigbee на t610 — переезд Z2M → ZHA (выполнен, 2026-09-15)"
created: '2026-09-15'
updated: '2026-09-15 (ночь-16: 🔴🔴 НАЙДЕН НАСТОЯЩИЙ КОРЕНЬ «кнопка не свитчит» — `_TZ3000_kccru4oi` в `input` НЕ ИМЕЕТ кластера `OnOff 0x0006` (он в `output`), `exposes_features: []` → ZHA из неё `event.*` не сделает НИКОГДА, нажатия и `permit` бесполезны (см. §Факт 5-тер). Исправленный `automations-fixed.yaml` собран, НЕ залит. `light_sensor_stairs` добавлен, `light.bed_dimmer`/`switch.sauna` переименованы)'
updated: '2026-09-15 (ночь-17: 🟢🟢 ПЕРЕЛОМ — КНОПКА СПАЛЬНИ РАБОТАЕТ. Прежний вывод «`event.*` не появится НИКОГДА» ОТМЕНЁН: `zha/devices/reconfigure` перечитал quirk, и кнопка начала слать `zha_event` (`command=remote_button_short_press`, `cluster_id=6`). `automations-fixed.yaml` ЗАЛИТ на t610, `Toggle Dimmer bed` + `Dimmer bed cycle` стали `on`. Bind кнопка→диммер и кнопка→координатор выполнен. Создана Zigbee-группа `bed` (group_id 2) с диммером внутри. 4 «мёртвых» автоматизации оказались ПРИЗРАКАМИ реестра — тела нет, только записи в `core.entity_registry`/`core.restore_state`)'
type: tech
namespace: family
status: 🟢 ZHA работает, 16/16 устройств. Имена `light.bed_dimmer`/`switch.sauna` исправлены, сущности датчика лестницы переименованы. 🔴 Кнопка спальни `_TZ3000_kccru4oi` в ZHA неработоспособна по железу (нет `input: 0x0006`) — нужна группа+bind или замена кнопки. Осталось: путь кнопка→диммер, заливка `automations-fixed.yaml`, 4 кривых автоматизации, косметика `select.bed_dimmer_*`.
status: 🟢 ZHA работает, 17 устройств. Кнопка спальни шлёт события, автоматизации диммера `on` и залиты. Bind + группа `bed` созданы. 🔴 Осталось: удалить 4 сироты-автоматизации (призраки, тела нет) и, при желании, пересоздать 2 сценария подсветки лестницы на новом датчике.
tags:
- t610
- haos
@@ -23,16 +23,35 @@ related:
# Zigbee на t610 — переезд Z2M → ZHA (история + рабочий рецепт)
> 🚦 **СОСТОЯНИЕ НА 2026-09-15 (ночь-16, ПОСЛЕ РАЗБОРА КНОПКИ) — ZHA РАБОТАЕТ, 16/16 УСТРОЙСТВ:**
> 🚦 **СОСТОЯНИЕ НА 2026-09-15 (ночь-17) — ZHA РАБОТАЕТ, КНОПКА СПАЛЬНИ РАБОТАЕТ:**
```
a4c1386d40ddb67b light_sensor_stairs EndDevice last_seen 20:46:51 ← ✅ ДОБАВИЛСЯ
ZHA devices: 17 (16 + координатор)
```
> - 🟢🟢 **КНОПКА СПАЛЬНИ ЗАРАБОТАЛА — ГЛАВНЫЙ ПЕРЕЛОМ НОЧИ-17.** Прежний вывод «`event.*` не создастся НИКОГДА» (§Факт 5-тер) **ОТМЕНЁН ФАКТОМ.** `{"type":"zha/devices/reconfigure","ieee":"a4:c1:38:b0:f9:e6:74:a5"}` → quirk перечитался → кнопка начала слать события:
> ```
> ZHA_EVENT: device_ieee a4:c1:38:b0:f9:e6:74:a5
> command: "remote_button_short_press" ← короткое нажатие РАБОТАЕТ
> cluster_id: 6, endpoint_id: 1
> ZHA_EVENT: command: "press_type", args: [0], params: {"press_type": 0}
> ```
> **ВЫВОД: дамп кластеров (§5-тер) показывает СОСТОЯНИЕ ДО reconfigure. `reconfigure` пересобирает устройство и может оживить кнопку. Сначала reconfigure, и только если он не помог — делать выводы.** См. §Факт 5-кватер.
> - ✅ **`automations-fixed.yaml` ЗАЛИТ на t610** (`scp` rc=0, 5065 б, бэкап `/config/automations.yaml.bak-dimmer-fix`). После `POST /api/services/automation/reload` → **`Toggle Dimmer bed` и `Dimmer bed cycle` = `on`**. Действия теперь на `light.bed_dimmer` (было — реле САУНЫ `switch.tz3210_nhqka112_ts011f`). См. §Факт 9-бис (ОБНОВЛЁН).
> - ✅ **Bind выполнен дважды:** `zha/devices/bind` `source_ieee=кнопка` → `target_ieee=диммер` (**success: true**) и → `target_ieee=координатор` (**success: true**). Формат команды: поля **`source_ieee`/`target_ieee`**, НИКАКИХ `cluster_id`/`endpoint_id` (те дают `invalid_format`).
> - ✅ **Создана Zigbee-группа `bed` (group_id 2)**, диммер внутри (`zha/group/members/add`, endpoint 1). Команда создания — `{"type":"zha/group/add","group_name":"bed"}` (⚠️ ключ именно `group_name`, не `name`).
> - 🔵 **4 «мёртвых» автоматизации — ПРИЗРАКИ РЕЕСТРА, не поломка кода.** Их нет в `automations.yaml` (там 12 блоков) и нет в `/api/config/automation/config/<id>` (**404**). Остались только записи в `core.entity_registry` + `core.restore_state`. Тела нет → HA корректно показывает `unavailable`. Лечение: удалить сирот из реестра. См. §Факт 10.
> - ✅ **`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.*` кнопки спальни НЕ ПОЯВИТСЯ НИКОГДА — НАЙДЕНА НАСТОЯЩАЯ ПРИЧИНА.** Не «нажатие не долетело» (прежняя гипотеза, §5-бис — **отменена**). Дамп кластеров: у `_TZ3000_kccru4oi` кластер `OnOff 0x0006` лежит в **`output`**, а `input` содержит только `Basic`/`Power`/`TuyaZBE000`. `exposes_features: []`. ZHA строит сущности только из `input` → **`zha_event` не рождается, `event.*` не создастся ни при каких нажатиях и окнах спаривания.** Это архитектурная несовместимость конкретного `manufacturerName`. См. §Факт 5-тер (3 варианта решения).
> - ✅ **Имена исправлены фактом:** `light.tz3000_ooc8illt_ts0052` → **`light.bed_dimmer`**, `switch.tz3210_nhqka112_ts011f` → **`switch.sauna`** (оба `success: true`, проверены чтением состояния).
> - 🟡 **Три слоя мусора удалены:** 127 сущностей `platform=mqtt` + 18 устройств-призраков Z2M. Реестр: 624 → 493 сущности, 52 → 34 устройства.
> - ✅ **13 modbus-датчиков СОХРАНЕНЫ** (проверено фактом: пишут данные) — они тоже `platform=mqtt`, но живые.
> - ✅ **13/13 устройств переименованы** — в UI больше нет `_TZ3000_5gey1ohx TS0002`; **13 устройств получили ЗОНЫ обратно** + `light_sensor_stairs` → `lestnitsa`.
> - ⏳ **Осталось:** удалить 4 сироты-автоматизации (§Факт 10); при желании — пересоздать 2 сценария подсветки лестницы на `sensor.light_sensor_stairs_illuminance`; косметика `select.bed_dimmer_*` (висят на `sauna`).
> - ⚠️ Z2M **остановлен**, не удалён. Данные целы в `/config/zigbee2mqtt/`.
> - 📌 **ИСТОРИЧЕСКОЕ (ночь-16, ОТМЕНЕНО ночью-17):** «`event.*` кнопки спальни НЕ ПОЯВИТСЯ НИКОГДА» — **неверно**. Дамп кластеров показывал `OnOff` в `output` и `exposes_features: []`, из чего был сделан вывод об архитектурной несовместимости. **`reconfigure` этот вывод опрокинул — кнопка шлёт `zha_event`.** Ошибка была в том, что дамп снят ДО reconfigure. См. §Факт 5-кватер.
> - ✅ **Дополнительно найдены и подтверждены 2 битых автоматизации диммера** — `Toggle Dimmer bed` и `Dimmer bed cycle` с `triggers: []` (пустые!) и действиями на реле САУНЫ. **Обе ИСПРАВЛЕНЫ и залиты (ночь-17).** См. §Факт 9.
> - 🟡 **Три слоя мусора удалены:** 127 сущностей `platform=mqtt` + 18 устройств-призраков Z2M. Реестр: 624 → 493 сущности, 52 → 34 устройства.
> - ✅ **13 modbus-датчиков СОХРАНЕНЫ** (проверено фактом: пишут данные) — они тоже `platform=mqtt`, но живые.
> - ✅ **51 операция переименования сущностей:** 42 выполнены, 8 отбиты (`light`→`switch` запрещён HA), 1 пропущена.
@@ -1128,9 +1147,12 @@ a4c138b0f9e674a5 wireless_light_switch_bed EndDevice
> 4. После появления — `config/device_registry/update` → `name_by_user` + `area_id`, затем переименовать сущности.
>
> ⚠️ `zha.permit` для уже-в-сети устройств бесполезен (питфолл 22), но для **не долетевшего** устройства окно открывать надо — оно есть, факт: REST-вызов прошёл.
> 🔴 **ОГРАНИЧЕНИЕ, ВЫЯСНЕННОЕ ночью-16:** этот рецепт работает **только для sleeping EndDevice, которые ДЕЛЯТСЯ атрибутами** (`light_sensor_stairs`/TS0222). Для устройств-«передатчиков команд» (`_TZ3000_kccru4oi`/TS0041, у которых `OnOff` в `output`) он **не работает вообще** — см. §Факт 5-тер. **Перед ретраем спаривания снять дамп кластеров.**
> 🔴 **ОГРАНИЧЕНИЕ (ночь-16, ОТМЕНЕНО ночью-17):** записанное здесь «рецепт не работает для `_TZ3000_kccru4oi`/TS0041» — **неверно**, см. §Факт 5-кватер. Кнопка ожила через `reconfigure` и шлёт `zha_event`. **Правильный порядок: сначала `reconfigure`, потом выводы.**
### 🔴🔴 ФАКТ 5-ТЕР — НАСТОЯЩИЙ КОРЕНЬ НАЙДЕН: `_TZ3000_kccru4oi` — НЕ КНОПКА для ZHA (проверено дампом кластеров)
### 🔴🔴 ФАКТ 5-ТЕР — ⛔ ОТМЕНЁН §5-КВАТЕР (ночь-17): вывод «НЕ КНОПКА для ZHA» БЫЛ НЕВЕРЕН
> ⛔⛔ **ЭТОТ РАЗДЕЛ ОТМЕНЁН. НИЖЕ — ОШИБОЧНЫЙ ВЫВОД, ОСТАВЛЕН КАК ИСТОРИЯ.** Правильный ответ — в §Факт 5-кватер: **одна команда `zha/devices/reconfigure` оживила кнопку**, она шлёт `zha_event` (`command: remote_button_short_press`). Кнопку **НЕ надо менять и НЕ надо обходить группой** — штатные автоматизации работают.
> 🔑 **ЦЕННОСТЬ ЭТОГО РАЗДЕЛА — как разбор ошибки:** дамп кластеров (`OnOff` в `output`, `exposes_features: []`) был снят **до** `reconfigure` и принят за приговор. **Дамп показывает состояние на момент съёмки, а не возможности устройства.** Читать дальше — только как пример неверного рассуждения.
> **Триггер:** Alex — «Чё блядь опять за хуйня» после §Факт 5-бис. Вместо повторного слушания шины — прямой дамп устройства и его кластеров через ZHA WebSocket.
@@ -1182,7 +1204,69 @@ endpoint 1:
> 3. Если `0x0006` в `out` И `exposes_features: []` → **кнопка не будет работать в ZHA. Не тратить время на нажатия и `permit`.**
> 📌 Дамп раскрывает всё это **сразу**, без ожидания событий на шине. **Слушание шины (§5-бис) — тупиковый путь для этого класса устройств; дамп кластеров — правильный первый шаг.**
### 🔴 ФАКТ 9-БИС — автоматизации диммера: исправленный файл собран, НА t610 НЕ ЗАЛИТ
### 🟢🟢 ФАКТ 5-КВАТЕР — ОТМЕНА §5-ТЕР: `reconfigure` ОЖИВИЛ КНОПКУ, событий ЕСТЬ
**Факт 5-тер («`event.*` не появится НИКОГДА», архитектурная несовместимость) ОТМЕНЁН.** Что произошло по шагам:
1. Запущена команда (принята, `zha_channel_cfg_done`):
```python
{"type": "zha/devices/reconfigure", "ieee": "a4:c1:38:b0:f9:e6:74:a5"}
```
2. Alex нажал кнопку — **прилетели события**:
```
ZHA_EVENT: {"device_ieee": "a4:c1:38:b0:f9:e6:74:a5",
"device_id": "da6c759f9046046c4ef60467175ccbbe",
"unique_id": "a4:c1:38:b0:f9:e6:74:a5:1:0x0006",
"endpoint_id": 1, "cluster_id": 6,
"command": "remote_button_short_press", "args": [], "params": {}}
ZHA_EVENT: {"command": "press_type", "args": [0], "params": {"press_type": 0}}
```
> 🔑 **ГЛАВНЫЙ УРОК: дамп кластеров показывает СОСТОЯНИЕ УСТРОЙСТВА НА МОМЕНТ СЪЁМКИ, а не его возможности.** После `reconfigure` quirk перечитывается и устройство может начать отдавать то, чего в старом дампе не было. **Порядок правильной диагностики кнопки: (1) `reconfigure`, (2) подписка на `zha_event` + физическое нажатие, (3) и ТОЛЬКО если пусто — вывод о несовместимости.**
> ⛔ **НЕ делать вывод «кнопка несовместима» по одному дампу кластеров.** Это была ошибка ночи-16: `OnOff` в `output` + `exposes_features: []` были приняты за приговор, хотя лечились одной командой `reconfigure`.
> 📌 Формат события для триггера автоматизации: `type: remote_button_short_press`, `subtype: button_1`, `domain: zha`, `device_id: da6c759f9046046c4ef60467175ccbbe`. Long press — `remote_button_long_press`.
### 🔑 ZHA WebSocket API — рабочие команды, найденные фактом (ночь-17)
| Задача | Команда | Результат |
|---|---|---|
| Кластеры устройства | `{"type":"zha/devices/clusters","ieee":"<с двоеточиями>"}` | список `in`/`out` |
| Дамп устройства | `{"type":"zha/devices"}` | quirk, signature, entities, lqi, rssi |
| **Перечитать устройство** | `{"type":"zha/devices/reconfigure","ieee":"<с двоеточиями>"}` | событие `zha_channel_cfg_done` |
| Bind устройства к устройству | `{"type":"zha/devices/bind","source_ieee":"<hex>","target_ieee":"<hex>"}` | `success: true` |
| Список групп | `{"type":"zha/groups"}` | `[{name, group_id, members}]` |
| Создать группу | `{"type":"zha/group/add","group_name":"bed"}` | `{name, group_id: 2}` |
| Добавить в группу | `{"type":"zha/group/members/add","group_id":2,"members":[{"ieee":"<hex>","endpoint_id":1}]}` | `success: true` |
> 🔴 **ПИТФОЛЛ: ключ группы — `group_name`, НЕ `name`.** С `name` → `invalid_format: not a valid option at 'name' … required key not provided at 'group_name'`.
> 🔴 **ПИТФОЛЛ: у `zha/devices/bind` НЕТ полей `cluster_id`/`endpoint_id`/`ieee`/`src_ieee`.** Только **`source_ieee` + `target_ieee`**, оба — hex-строки. Иначе `invalid_format` с подсказкой `did you mean 'source_ieee' or 'target_ieee'?`.
> 🔴 **НЕсуществующие команды** (дают `unknown_command`): `zha/permit` (WS) → использовать сервис `zha.permit`; `zha/devices/reinterview`; `zha/devices/reconfigure_device`; `zha/group/list`; `zha/group/add_member`.
> ✅ **`zha.permit` только через сервис:** `POST /api/services/zha/permit` с `{"duration":240}` → HTTP 200.
### 🔵 ФАКТ 10 — 4 «мёртвых» автоматизации = ПРИЗРАКИ РЕЕСТРА (тела нет)
**Симптом:** 4 автоматизации в `/api/states` висят `unavailable`, `last_triggered: None`:
```
Светло: выкл.подсветку лестницы id 1771466806839
Темно: вкл.подсветку лестницы id 1771466955010
Датчик освещенности лестница батарея id 1773459513601
Light switch bed батарея id 1773459606336
```
**Диагностика фактом (порядок, который сразу даёт ответ):**
1. **`grep -c 'id:' /config/automations.yaml`** → 12. В файле этих 4 **нет вообще**.
2. **`GET /api/config/automation/config/<numeric-id>`** → **404 Not Found** для всех четырёх. **Тела автоматизации не существует.**
3. **`grep -o '<id>' /config/.storage/*`** → найдены **только** в `core.entity_registry` и `core.restore_state`.
> 🔑 **Вывод: это сироты — записи реестра без тела.** Появились как остаток от удаления 127 мёртвых Z2M-сущностей: тело автоматизации удалилось, запись в `core.entity_registry` осталась. **HA показывает `unavailable` корректно** — нечего запускать.
> ⛔ **Это НЕ «битый YAML» и НЕ «потерянный конфиг».** Не искать ошибку в `automations.yaml` — их там нет.
> ⚠️ **Сироты бывают двух видов:** (а) `triggers: []` + тело в YAML (лечится правкой YAML — так было с `Toggle Dimmer bed`, §Факт 9); (б) тела нет вовсе, только реестр (лечится удалением записи). **Различать проверкой `/api/config/automation/config/<id>` → 200 vs 404.**
> 📌 **Проверка «сколько автоматизаций реально живых»:** сравнивать число блоков в `automations.yaml` с числом сущностей `automation.*` в `/api/states`. Расхождение = сироты. Здесь: 12 блоков vs 16 сущностей = 4 сироты.
> 📌 `unavailable` сам по себе НЕ значит «сломан код». Сначала **404 по config API** — если 404, чинить нечего, только удалять запись.
### 🔴 ФАКТ 9-БИС — автоматизации диммера: ✅ ИСПРАВЛЕНО И ЗАЛИТО (ночь-17)
**Собран `/Users/admin/tmp-t610/automations-fixed.yaml`** (источник — снятый с t610 `automations-current.yaml`, 189 строк). Содержимое правки:
@@ -1214,8 +1298,13 @@ endpoint 1:
То же для `Dimmer bed cycle` (`long_press``light.turn_on brightness_pct: 50` на `light.bed_dimmer`).
> 🔴 **ПОЧЕМУ НЕ ЗАЛИТ: триггер `remote_button_short_press` на этой кнопке НЕ СРАБОТАЕТ** (§Факт 5-тер — нет `input: 0x0006`, нет `event.*`). Заливать файл с заведомо мёртвым триггером — бессмысленно. **Сначала дать кнопке путь к диммеру (вариант 1: группа + bind), потом заливать.**
> 📌 **Действия (actions) в этом файле исправлены правильно и нужны независимо от судьбы кнопки** — их можно залить, если решено оставить автоматизации без триггера. Решение за Alex.
> **ОБНОВЛЕНО ночью-17: ФАЙЛ ЗАЛИТ.** `scp /Users/admin/tmp-t610/automations-fixed.yaml root@192.168.2.176:/config/automations.yaml` → **rc=0**, размер подтверждён (`wc -c` → 5065). Бэкап на хосте: `/config/automations.yaml.bak-dimmer-fix`. После `POST /api/services/automation/reload` (**HTTP 200**) обе автоматизации стали **`on`** — факт из `/api/states`:
> ```
> on | Toggle Dimmer bed
> on | Dimmer bed cycle
> ```
> 🔑 **Прежний довод «не заливать, триггер всё равно мёртв» ОКАЗАЛСЯ НЕВЕРНЫМ** — кнопка после reconfigure **шлёт `remote_button_short_press`** (§Факт 5-кватер), так что триггер рабочий. **Урок: не откладывать заливку исправленных `actions` из-за сомнений в `triggers` — проверять `triggers` фактом (reconfigure + слушание шины), а не выводом из дампа.**
> 📌 **Действия (actions) в этом файле исправлены правильно** — `light.bed_dimmer` вместо реле сауны.
**Сверенные ID (проверено фактом через `config/device_registry/list`):**