Files
obsidian-vault/family/tech/zigbee-t610-z2m-i-zha.md
T

240 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "Zigbee на t610 — Z2M сейчас, перенос в ZHA (разбор 2026-09-15)"
created: '2026-09-15'
updated: '2026-09-15 (ночь-8: разбор переноса Z2M → ZHA; главный факт — coordinator_backup.json у ember-адаптера ВСЕГДА пуст, устройства живут в database.db)'
type: tech
namespace: family
status: research — перенос НЕ выполнен, Z2M работает
tags:
- t610
- haos
- home-assistant
- zigbee
- zigbee2mqtt
- zha
- ember
- ezsp
- migration
related:
- '[[family/how-to/home-automation]]'
- '[[family/how-to/ha-automations]]'
- '[[family/plans/t610-backup-to-truenas]]'
---
# Zigbee на t610 — Z2M / перенос в ZHA
> ❓ **Вопрос Alex (2026-09-15):** «HA штатно поддерживает Zigbee без Z2M? Что нужно, чтобы перенести всё в HA **без заново спаривания**?»
## Короткий ответ
**Да, HA поддерживает Zigbee штатно — интеграция ZHA, встроена в HA core, ничего ставить не надо. Стик тот же (`/dev/ttyACM0`).**
**НО перенос «без спаривания» через `coordinator_backup.json` у тебя НЕ сработает** — этот файл у ember/EZSP-адаптера **всегда пуст** (`"devices": []`). Это **не поломка** и **не устаревший файл**: так работает ember у Zigbee2MQTT.
---
## 🔴 ГЛАВНЫЙ ФАКТ этой сессии: `coordinator_backup.json` пуст — и это норма
**Проверено фактом (2026-09-15):** запросил у Z2M свежий backup через MQTT (`bridge/request/backup`) — Z2M сгенерировал его **заново, в эту секунду**, и там всё равно:
```json
{
"metadata": { "format": "zigpy/open-coordinator-backup", "version": 1,
"source": "zigbee-herdsman@10.9.2",
"internal": { "ezspVersion": 13 } },
"coordinator_ieee": "f23993fefff6ef0c",
"pan_id": "8ea1",
"extended_pan_id": "0d678f5d9d2718a4",
"network_key": { "key": "f9571f4d9b9d9bbfba585d45332e2230", ... },
"channel": 11,
"devices": [] 🔴 ПУСТО, хотя 16 устройств работают
}
```
**Вывод:** файл содержит только **параметры сети** (ключ, PAN, EPID, канал), но **не список устройств**. `jq '.devices | length'``0`.
**Почему так:** Z2M пишет в этот массив только **детей координатора** и устройства с APS-ключами, которыми поделился координатор. У Tuya-сетей, где почти всё висит на роутерах `TS011F`/`TS0002`, массив остаётся пустым.
> ⛔ **НЕ искать «поломку» в пустом `devices: []`** — это ожидаемое поведение ember. Заново запрашивать backup по MQTT бессмысленно, результат тот же.
> ⛔ **НЕ пытаться «дописать» устройства в этот файл руками** — `link_key` каждого устройства неизвестен, координатор новый трафик не расшифрует.
---
## Что реально есть на t610 (инвентарь 2026-09-15)
```
/config/zigbee2mqtt/
├── configuration.yaml 1650 б — serial.port, adapter: ember, network_key, pan_id, 16 friendly_name
├── coordinator_backup.json 782 б — ТОЛЬКО сеть, devices: [] (см. выше)
├── database.db 24931 б — 🔑 ВСЕ 17 записей: 1 Coordinator + 16 устройств
├── state.json 2164 б — текущие значения (temperature, state, battery…)
└── log/ — рантайм-логи Z2M
```
**`database.db`** — это Z2M-SQLite (построчный JSON, по строке на устройство). Содержит `ieeeAddr`, `nwkAddr`, `manufId`, `manufName`, `modelId`, `endpoints`, `binds`, `configuredReportings`, `lastSeen`.
> 🔴 **`link_key` / `apsKey` в `database.db` НЕТ ВООБЩЕ** — проверено: `grep -c 'link_key\|linkKey\|apsKey'` → 0, ни одной 32-символьной hex-строки. Ключи лежат **только в NVRAM стика**.
> ⚠️ **ZHA не читает `database.db`** — формат Z2M-овский (SQLite + JSON-строки), у ZHA свой `zigbee.db`.
**Адаптер по логу Z2M:**
```
zh:ember: Adapter version info: {"ezsp":13,"revision":"7.4.5 [GA]","major":7,"minor":4,"patch":5}
zh:ember: [STACK STATUS] Network up.
zh:ember: [INIT TC] Adapter network matches config. ← стик держит сеть САМ
```
> 🔑 **Стик хранит сеть в собственной NVRAM** (`Network up`, `network matches config`) — вот на чём держится перенос без перепаривания, **а не на файле**.
### Интерфейс Z2M и MQTT
| Что | Значение |
|---|---|
| Веб-фронтенд Z2M | порт **8099**, `frontend.enabled: true` — ⚠️ снаружи (с Mac) **не отвечает** (`http=000`), слушает только внутри docker-сети |
| MQTT-брокер | `core-mosquitto:1883` — ✅ **работает из SSH-аддона по DNS-имени** |
| MQTT-брокер `localhost:1883` | ❌ **НЕ работает** из SSH-аддона (`Bad file descriptor`, `nc` порт не видит) |
| Учётка MQTT | `zont` / `mqtt1z3$` |
> 🔴 **ПИТФОЛЛ: `mosquitto_sub -h localhost` из SSH-аддона падает с `Error: Bad file descriptor`.** Причина — аддон не видит порт 1883 на loopback. **Фикс: указывать `-h core-mosquitto`** (DNS-имя контейнера). Заработало сразу.
> 📌 `mosquitto_sub`/`mosquitto_pub`/`nc` в SSH-аддоне **есть** в `/usr/bin/`.
---
## Запрос полного backup у Z2M (рабочий рецепт)
Z2M отдаёт backup **через MQTT**, не через файл:
```bash
#!/bin/bash
MQTT_PASS='mqtt1z3$'
BROKER='core-mosquitto' # 🔴 НЕ localhost
OUT=/tmp/z2m_full_backup.json
mosquitto_sub -h "$BROKER" -p 1883 -u zont -P "$MQTT_PASS" \
-t 'zigbee2mqtt/bridge/response/backup' -C 1 -W 25 > $OUT &
SUB_PID=$!
sleep 3
mosquitto_pub -h "$BROKER" -p 1883 -u zont -P "$MQTT_PASS" \
-t 'zigbee2mqtt/bridge/request/backup' -m ''
wait $SUB_PID
jq -r '.data.zip' $OUT | base64 -d > /tmp/z2m_backup.zip
mkdir -p /tmp/z2m_unpack && cd /tmp/z2m_unpack && unzip -o /tmp/z2m_backup.zip
```
**Результат:** `{"data":{"zip":"UEsDBBQ..."},"status":"ok"}` — ZIP, ~5.1 КБ, внутри 4 файла:
`configuration.yaml`, `coordinator_backup.json`, `database.db`, `state.json`.
⚠️ **Ответ приходит base64-строкой внутри JSON**, а не файлом. Декодировать `base64 -d`.
⚠️ Длинный ответ прилетает в MQTT **одним сообщением**`-C 1` (одно сообщение) хватает, но `-W` ставить ≥20 с.
---
## Как перенос «без спаривания» работает НА САМОМ ДЕЛЕ
Не через файл. Через **NVRAM стика**:
```
Z2M держит сеть (PAN 8ea1, канал 11, network_key f957…2230) в NVRAM стика Inswift ZBP-MG21
│ останавливаем Z2M (стик освобождается)
ZHA стартует на ТОМ ЖЕ стике
│ читает NVRAM → сеть та же: ключ тот же, PAN тот же, канал тот же
устройства видят «своего» координатора и продолжают отчитываться
ZHA их обнаруживает (уже в сети) — заново спаривать НЕ нужно
```
**Порядок (если решимся):**
1. **Полный snapshot HA** — обязательно, до всего.
2. Скачать `coordinator_backup.json` (ключ/PAN/канал) + `database.db` (инвентарь) — на случай отката.
3. **Остановить Z2M** (`stop`, не удалять) — стик освободить.
4. HA → Настройки → Устройства → **Добавить интеграцию → ZHA** → порт
`/dev/serial/by-id/usb-Inswift_Zigbee_ZBP-MG21_535A000001-if00` → тип **EZSP/ember**.
5. При запросе — восстановить `coordinator_backup.json` (ZHA возьмёт параметры сети).
6. ZHA поднимает сеть. Устройства уже в ней — идут сами. **Батарейные (`EndDevice`) спят** — их надо разбудить кнопкой, но это **не перепаривание**.
7. Переназначить `modbus-bridge` (он завязан на `switch.0xa4c138f8da8bc478`).
---
## 🔴 Что ЛОМАЕТСЯ при переезде (честно)
| # | Что | Масштаб |
|---|---|---|
| 1 | **Friendly names (16)** | `zigbee.db` у ZHA пуст — имена не переносятся, задавать заново |
| 2 | **Все автоматизации с `switch.0xa4c138f8da8bc478` и подобными** | `entity_id` в ZHA будут другие → переписать все ссылки |
| 3 | **`modbus-bridge`** | жёстко завязан на Zigbee-сущность `switch.0xa4c138f8da8bc478` (relay slave 104) — сломается |
**Почему Z2M сейчас остаётся (решение 2026-09-15):**
- 16 устройств уже спарены и работают (проверено: 19 сущностей online, `presence`, `illuminance`, `state` живые)
- `modbus-bridge` висит на Z2M-сущность — переезд немедленно ломает мост на ZONT
- ZHA и Z2M **не уживаются на одном стике** — второго нет
- Выигрыш от переезда = 0. HA «штатно поддерживает Zigbee» — правда, но у Alex не «поставить интеграцию», а «перенести построенную сеть + переписать автоматизации»
> 📌 Формулировка для будущего: **вопрос не в возможностях ZHA, а в том, что сеть уже построена и завязана на неё.**
---
## Инвентарь Zigbee-сети (16 устройств, 2026-09-15)
| IEEE | friendly_name | modelId | тип |
|---|---|---|---|
| `0xa4c13862d39377e6` | office_temperature_sensor | TS0201 | EndDevice (батарея) |
| `0xa4c138f8da8bc478` | **recirculation_pump** | TS011F | Router — 🔴 **на нём висит `modbus-bridge`** |
| `0x84fd27fffed9e137` | night_light_shower_2 | TS0001 | Router |
| `0xa4c1386d40ddb67b` | light_sensor_stairs | TS0222 | EndDevice (батарея) |
| `0xa4c1381186ed1a32` | smart_light_office | TS0012 | EndDevice |
| `0xa4c13873b5c1575b` | office_table_light_switch | TS0002 | Router |
| `0xa4c13807b64c7fd4` | kitchen_hood | TS0003 | Router |
| `0xa4c1386d0839706a` | light_stairs | TS0002 | Router |
| `0xa4c138eb6fbe9d19` | sauna | 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 |
> Координатор: `0x0ceff6fffe9339f2`, `coordinator_ieee` `f23993fefff6ef0c`, imanufId 4169, ember/EZSP v13 (firmware 7.4.5 GA).
---
## Бэкапы (сделано в этой сессии)
`/Users/admin/tmp-t610/z2m-backup-20260915/` — md5 проверены, файлы идентичны хостовым:
```
configuration.yaml MD5 ac2e35502237d6a7ce759b407063a2c8
coordinator_backup.json MD5 5c29cf397a919ebcd02f2332916dee97
database.db MD5 3292d64bf1455d4b3d50a93c0950d0b4
state.json MD5 20bfb775cbab002e59d1be31a15db9e6
```
Скрипты на Mac (`~/tmp-t610/`): `z2m-backup-request.sh` (первая версия, `localhost` — падает), `z2m-backup-request2.sh` (`core-mosquitto` — работает), `z2m-get-backup.sh` (полный цикл + распаковка), `z2m-check-adapter.sh` (диагностика адаптера).
> ⚠️ **Правило:** скрипты писать на Mac → `scp` → выполнить. Не инлайнить `mosquitto_sub` с паролем в одну ssh-строку — `$` в пароле `mqtt1z3$` ломается в двойных кавычках.
---
## Питфоллы (найдены в этой сессии)
1. 🔴 **`coordinator_backup.json` пуст у ember — это НОРМА, не поломка.** Не искать проблему, не «дописывать» устройства.
2. 🔴 **`mosquitto_sub -h localhost` из SSH-аддона → `Bad file descriptor`.** Использовать `-h core-mosquitto`.
3. ⚠️ **Z2M-фронтенд на :8099 снаружи (с Mac) недоступен** (`http=000`) — слушает внутри docker-сети. Не считать это поломкой.
4. ⚠️ **`link_key`/APS-ключей нет ни в `database.db`, ни в backup-файле** — только NVRAM стика. Поэтому «переписать файл руками» не выход.
5. ⚠️ **ZHA не читает `database.db`** — форматы несовместимы (`zigbee.db` vs `database.db`).
6. ⚠️ **ZHA и Z2M на одном стике не уживаются** — второго стика нет, значит переезд = полная замена, не параллельная работа.
7. 📌 Эндпоинт опций аддона — `GET /addons/<slug>/info` (`.data.options`), НЕ `/options` (405). Токен: `T=$(cat /run/s6/container_environment/HASSIO_TOKEN)`.
---
## Связанные заметки
- [[family/how-to/home-automation]] — топология, аддоны t610, первопричина RCU stall
- [[family/how-to/ha-automations]] — 16 автоматизаций (часть завязана на Zigbee-сущности)
- [[family/plans/t610-backup-to-truenas]] — автобэкап `/config/zigbee2mqtt/` (попадает в архив)
- [[family/tech/local-ustreamer-addon]] — камера на том же хосте