Files
obsidian-vault/family/plans/t610-addons-deployment.md
T

727 lines
78 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: t610 — развёртывание через HA-аддоны
status: in-progress
tags:
- family
- plan
- homeautomation
- t610
- haos
- addons
created: '2026-09-13'
updated: '2026-09-14'
related:
- '[[family/plans/home-automation-migration-t610]]'
- '[[family/how-to/home-automation]]'
---
# t610 — развёртывание через HA-аддоны
> **Статус (2026-09-14): Этап 1 ✅. Этап 2 ✅ ПОЛНОСТЬЮ. Этап 3 ✅ ОСНОВНОЕ ВЫПОЛНЕНО — реестры и конфиг перенесены, БД с нуля, `localtuya`/HACS сняты, z2m приведён к **14 живым** устройствам (удалены 3 мёртвых), все `entity_id` в HA переименованы в человеческие (**hex = 0**), `friendly_name` в z2m — латиница snake_case, `switch_as_x` восстановлены (виртуальные `light.*` работают), дашборд поправлен.**
> ⚠️ **ОСТАЛОСЬ ПОЧИНИТЬ (блокер): 13 из 16 автоматизаций `unavailable` — ссылаются на `device_id` с TrueNAS, которых нет на t610.** Маппинг собран, см. §«ПИТФОЛЛ: device_id ломаются при переносе реестра». Далее: `sensor.*_summary` template-ошибки (`default(0)`), Этап 4.
> Сервисы: z2m (14), mbusd (502), modbus-bridge (MQTT + HA-опрос), MQTT-интеграция в HA.
> Родительский план: [[family/plans/home-automation-migration-t610]] (Шаг 3 в нём заменяется на этот документ).
> Доступ к хосту, CLI и питфоллы: [[family/how-to/t610-access]].
## Ключевые решения (кратко, для быстрого входа в контекст)
| Решение | Что выбрано | Почему |
|---------|-------------|--------|
| Формат развёртывания сервисов | **HA-аддоны** (не docker-compose) | из SSH-аддона host docker не виден; аддоны штатны и снимают udev-гонку |
| Источник z2m | **community-repo** `zigbee2mqtt/hassio-zigbee2mqtt` | в официальном сторе z2m нет |
| mbusd / modbus-bridge | **local add-ons** (`/addons/...`) | кастомный код, в сторе нет |
| Привязка CH340 (2 одинаковых адаптера) | **`/dev/serial/by-path/...`** | by-id у обоих идентичен (нет серийников) |
| Как аддон видит serial | **флаг `uart: true`** в манифесте аддона | даёт доступ ко всем serial (by-id + by-path) автоматически; `devices:` не нужен |
| udev-алиасы `ttyZONT`/`ttyVent` | **отменены** | на HA OS невозможны (SSH-аддон = Alpine-контейнер); by-path функционально эквивалентен |
| Доступ к хостовому шеллу | **не нужен** | debug-SSH 22222 включается только флешкой; всё делается через Supervisor API |
## Контекст: почему аддоны, а не docker-compose 1:1
Изначально в родительском плане (Шаг 3, Вариант B) предполагалось перенести `docker-compose.yml` с TrueNAS 1:1.
При проверке живого t610 выяснилось:
- HA OS 18.2 внутри использует **host docker 29.6.2** (overlayfs, journald) — docker есть, `ha docker info` подтверждает.
- Но **из SSH-аддона docker CLI не виден** — аддон живёт в своём контейнере. Доступ к host docker только через Supervisor (`ha docker`) или через Portainer-аддон.
- Поэтому штатный и наименее хрупкий путь — **аддоны**.
**Решение Alex (2026-09-13): «Делай всё аддонами».**
## Состав аддонов
| Сервис | Slug | Источник | Статус |
|--------|------|----------|--------|
| Mosquitto broker (MQTT) | `core_mosquitto` | Official (core) | ✅ установлен, `started` (1883/1884) |
| Node-RED | `a0d7b954_nodered` | Community | ✅ установлен, `started` (1880) |
| Advanced SSH & Web Terminal | `a0d7b954_ssh` | Community | ✅ есть в сторе (запасной путь) |
| Terminal & SSH | `core_ssh` | Official | ✅ **установлен и работает** |
| Samba share (для доступа к файлам) | `core_samba` | Official | ⏸️ установлен, `stopped` (нужен `password`) |
| File editor | `core_configurator` | Official | ✅ установлен, `started` |
| **Zigbee2MQTT** | `45df7312_zigbee2mqtt` | Community repo | ✅ **установлен, работает — 16 устройств** |
| **mbusd** | `local_mbusd` | Local add-on (`/addons/mbusd`) | ✅ **установлен, работает — порт 502** |
| **modbus-bridge** | `local_modbus-bridge` | Local add-on (`/addons/modbus-bridge`) | ✅ **установлен, работает — MQTT + HA-опрос** |
| **MQTT-интеграция в HA** | `mqtt` | Config entry | ✅ **добавлена 2026-09-14** (была ОТСУТСТВОВАЛА → 22 сущности; стало 104, 69 Zigbee) |
### Про Zigbee2MQTT
В официальном сторе z2m нет (есть только deCONZ `core_deconz` и `core_silabs_multiprotocol`).
Варианты:
- **A. Community-репозиторий z2m** — у сообщества есть репо (`https://github.com/zigbee2mqtt/hassio-zigbee2mqtt`), добавляется как app repository, дальше штатная установка.
- **B. Local add-on** — свой Dockerfile в `/addons/zigbee2mqtt`.
**Решение: A (community repo)** — меньше ручной работы, поддерживается сообществом, обновления через UI. ✅ Реализовано 2026-09-14.
### Про mbusd и modbus-bridge
В сторе нет и быть не может (кастомный код). Только **local add-ons**:
```
/addons/mbusd/ → Dockerfile + config
/addons/modbus-bridge/ → Dockerfile + modbus_ha_bridge.py + config.yml
```
Local add-ons требуют **Advanced Mode** в профиле HA (Settings → Apps появляются только с ним) + репозиторий «Local apps» уже подключён (проверено: `addons_repositories` содержит `Local apps`).
## ✅ USB-устройства подключены (2026-09-14) — блокер снят
**Все 3 устройства воткнуты и видны** (карта by-id/by-path: [[family/how-to/t610-access]] §USB).
```
/dev/ttyUSB0 → CH340 #1 by-path: pci-0000:00:12.0-usb-0:3:1.0-port0 (порт 3) → ZONT / modbus-bridge
/dev/ttyUSB1 → CH340 #2 by-path: pci-0000:00:12.0-usb-0:4:1.0-port0 (порт 4) → Vent / mbusd
/dev/ttyACM0 → Zigbee Inswift ZBP-MG21 by-id: usb-Inswift_Zigbee_ZBP-MG21_535A000001-if00
```
⚠️ **Два CH340 неразличимы по by-id** (у обоих `1a86:7523`, serial отсутствует) → привязка только по **by-path / адресу шины**.
### 🔑 РЕШЕНИЕ: привязка по `by-path` вместо udev-алиасов
Проверено на живом t610 (2026-09-14): **udev-алиасы (`ttyZONT`/`ttyVent`) на HA OS не нужны и сделать их «как на TrueNAS» нельзя** — SSH-аддон это Alpine-контейнер, у него нет `/etc/udev/rules.d` и нет `udevadm`. Хостовый доступ = только debug-SSH 22222, который на t610 выключен и включается лишь флешкой с ключом в разделе `CONFIG` (по сети — никак: `ha host` без ssh-команд, Supervisor API `/host/services/ssh` → 403, роль аддона `manager`).
**Рабочая схема — штатный механизм Supervisor: `uart: true`.**
- В `config.yaml` (или `config.json`) аддона флаг **`uart: true`** даёт контейнеру доступ ко **всем** serial-устройствам хоста — вместе с симлинками `/dev/serial/by-id/` **и** `/dev/serial/by-path/`.
- Подтверждено: `core_ssh` имеет `uart: true` → из него виден весь `/dev/serial/by-path/`. z2m-аддон тоже имеет `uart: true`.
- **`devices:` в конфиг аддона прописывать НЕ надо** — при `uart: true` проброс serial автоматический.
**Как прописывать путь в конфиге сервиса:**
```yaml
# zigbee2mqtt (Settings → Apps → Zigbee2MQTT → Configuration → serial)
serial:
adapter: ember
port: /dev/serial/by-path/pci-0000:04:00.0-usb-0:1:1.0 # Zigbee — by-id тоже ок (уникальный серийник)
```
Для mbusd / modbus-bridge (local add-ons) — в их `config.yaml`/опциях указывать **by-path**:
```
ZONT → /dev/serial/by-path/pci-0000:00:12.0-usb-0:3:1.0-port0
Vent → /dev/serial/by-path/pci-0000:00:12.0-usb-0:4:1.0-port0
```
Это **функциональный аналог** udev-алиасов с TrueNAS: имя не «прыгает» при перезагрузке, привязка к физическому порту. Разница только в том, что вместо `ttyZONT` пишется полный by-path.
> ⚠️ **by-path привязан к физическому порту.** CH340 #1 обязан остаться в порту 3, CH340 #2 — в порту 4. Если поменять — пути поедут. Порты зафиксированы (проверено).
### ✅ z2m на t610 — ВЫПОЛНЕНО (2026-09-14)
**Что сделано:**
1. **Бэкап с TrueNAS** → Mac `~/tmp-t610/z2m-backup-20260914/` (`database.db`, `configuration.yaml`, `state.json`, `coordinator_backup.json`). Источник на TrueNAS: `/mnt/RED_2TB/docker/zigbee2mqtt/`.
2. Установлен аддон `45df7312_zigbee2mqtt` v**2.14.1-1** (community repo). Манифест содержит **`uart: true`** → доступ ко всем serial, `devices:` не нужен.
3. **Mosquitto**: добавлен логин `zont` (тот же пароль, что на TrueNAS) через Supervisor API → `POST /addons/core_mosquitto/options``ha apps restart core_mosquitto`. Нужен, чтобы HA-интеграция и ZONT продолжили работать по старым креденшелам.
4. **Опции z2m** (Supervisor API `POST /addons/45df7312_zigbee2mqtt/options`):
```json
serial: { "port": "/dev/serial/by-id/usb-Inswift_Zigbee_ZBP-MG21_535A000001-if00",
"adapter": "ember", "baudrate": 115200, "rtscts": false }
mqtt: { "server": "mqtt://core-mosquitto:1883", "user": "zont", "password": "<как на TrueNAS>" }
```
5. **База перенесена 1:1.** ⚠️ `data_path` аддона = **`/config/zigbee2mqtt`** — внутри HA-конфига, НЕ `/addon_configs/...`. Создана `/config/zigbee2mqtt/`, залиты `database.db` + `configuration.yaml` (тот же `network_key`/`pan_id`/`ext_pan_id`/`channel: 11`, но serial → by-id, MQTT → core-mosquitto).
6. `ha apps start 45df7312_zigbee2mqtt`**работает.**
**Лог подтверждает успех** (`/config/zigbee2mqtt/log/<ts>/log.log`):
```
zh:ember: [INIT TC] Adapter network matches config.
z2m: Coordinator firmware: EmberZNet 7.4.5 [GA], EZSP 13
z2m: Currently 16 devices are joined.
z2m: Connected to MQTT server
```
**16 устройств на месте, переспаривание НЕ потребовалось.** (Tuya: модули реле, диммеры, розетки, датчики t°/влажности, протечки, радар присутствия, светильник.)
**Питфоллы z2m-переноса:**
- **Пароль MQTT содержит `$`** (`mqtt1z3$`) → при передаче через `sed`/интерполяцию в шелле ломается экранирование, скрипт падает с `unmatched '|'`. Надёжный путь: файл `configuration.yaml` готовить **локально**, заливать копированием файла, значения с `$` не подставлять в bash-строки. Для Supervisor API — JSON собирать через `jq`, а не конкатенацией.
- Supervisor API требует **полный** набор опций (схема валидирует все ключи) — брать текущие и менять нужное.
- Пароль в выводе `ha`/API маскируется как `***` — это нормально, значение применяется.
- `uart: true` = автоматический проброс всех serial (by-id + by-path). `devices:` в конфиг аддона прописывать не надо.
- В SSH-аддоне **нет python3**, и он неустойчив к сложному экранированию строк — готовые конфиги заливать файлом, а не генерировать на хосте.
## План по шагам
### Этап 1 — базовые аддона (не требуют USB) — ✅ ВЫПОЛНЕНО 2026-09-13
1. [x] Advanced Mode — не понадобился для CLI (всё сделано через `ha apps`), понадобится позже для local add-ons
2. [x] **Mosquitto broker** (`core_mosquitto` v7.1.1) — установлен, `started`, порты **1883** (MQTT) + **1884** (WS) открыты, discovery отправлен в HA автоматически
3. [x] **Node-RED** (`a0d7b954_nodered` v22.0.6) — установлен, `started`, порт **1880** открыт, **уже подключился к HA** (`Connected to http://supervisor/core`)
4. [ ] **Samba share** (`core_samba`) — установлен, но `stopped`: требует задать `password` (по умолчанию `null`) → логин `homeassistant`. Задать в UI: Settings → Apps → Samba → Configuration
5. [x] **File editor** (`core_configurator`) — установлен, `started`
6. [x] Репозиторий Zigbee2MQTT добавлен: `ha store add https://github.com/zigbee2mqtt/hassio-zigbee2mqtt` → появился как `Home Assistant App: Zigbee2MQTT` (slug `45df7312`)
7. [x] ✅ **HA MQTT-интеграция на `core-mosquitto` — ДОБАВЛЕНА 2026-09-14** (её не было → z2m/bridge не создавали сущности). Сущностей: 22 → **104** (69 Zigbee). Рецепт — §«HA MQTT-интеграция» ниже.
**Питфоллы, выявленные при установке:**
- **`ha apps` НЕ имеет команды для изменения опций** (только install/start/stop/restart/logs/info/update/uninstall). Настройка опций — только через **UI** или **Supervisor API** (`POST http://supervisor/addons/<slug>/options`).
- **Node-RED по умолчанию `ssl: true`** → падает при старте без сертификата (`init-nginx: command exited 1`, `state: error`). Фикс: `ssl: false` через API (см. ниже).
- API требует **полный** набор опций (схема валидирует все ключи) — нельзя послать только `{"ssl": false}`, будет `Missing option 'certfile'`. Надо взять текущие опции и поменять нужное.
- **В SSH-аддоне нет python3** (только bash/curl/jq/`ha`). Скрипты для t610 писать на bash+jq.
- `ha store add <url>` (не `ha store repositories add`).
**Рабочий рецепт смены опций аддона (bash+jq через SSH-аддон):**
```bash
SLUG="a0d7b954_nodered"
API="http://supervisor/addons/${SLUG}"
AUTH=*** Bearer ${SUPERVISOR_TOKEN}"
curl -s -H "${AUTH}" "${API}/info" | jq '.data.options | .ssl = false' > /tmp/o.json
jq -n --slurpfile o /tmp/o.json '{options: $o[0]}' > /tmp/post.json
curl -s -X POST -H "${AUTH}" -H "Content-Type: application/json" -d @/tmp/post.json "${API}/options"
ha apps restart "$SLUG"
```
> ⚠️ Если строка `AUTH=` выглядит искажённой — это артефакт маскировки секретов при записи доки. В живом скрипте: `AUTH=*** Bearer ${SUPERVISOR_TOKEN}"`. Рабочие скрипты лежат на Mac в `~/tmp-t610/*.sh`.
Скрипты лежат локально: `~/tmp-t610/nr_set_ssl.sh`.
### Этап 2 — USB-устройства — ✅ ВЫПОЛНЕНО 2026-09-14
8. [x] Alex втыкает 3 USB в t610 — **ВЫПОЛНЕНО 2026-09-14**. Порты зафиксированы: CH340 #1 → USB1 порт 3, CH340 #2 → USB1 порт 4, Zigbee → USB3 порт 1. **Устройства из портов не вынимать!**
9. [x] Пути определены (`ls /dev/serial/by-id/`, `by-path`, sysfs) — подробная карта: [[family/how-to/t610-access]] §USB
10. [x] Карта составлена: ttyUSB0 = CH340 #1 (ZONT), ttyUSB1 = CH340 #2 (Vent), ttyACM0 = Zigbee
11. [x] **СПОСОБ ПРИВЯЗКИ РЕШЁН 2026-09-14** — привязка по **`by-path`**, никаких udev-алиасов. Механизм: флаг `uart: true` в манифесте аддона даёт доступ ко **всем** serial включая `/dev/serial/by-path/` (проверено на живом t610: `core_ssh` uart:true видит все by-path; z2m тоже uart:true). `devices:` прописывать не надо. Подробности: [[family/how-to/t610-access]] §USB. **Блокер снят.**
12. [x] ✅ **z2m-аддон УСТАНОВЛЕН И РАБОТАЕТ (2026-09-14)** — аддон `45df7312_zigbee2mqtt` v2.14.1-1, serial по by-id, база перенесена 1:1, **16 устройств на месте, переспаривание не потребовалось.** Подробности — §«z2m на t610 (ВЫПОЛНЕНО)» выше.
13. [x] ✅ **mbusd local add-on СОБРАН И РАБОТАЕТ (2026-09-14)** — slug `local_mbusd`, порт **502 открыт** (проверено `nc` с Mac), устройство by-path CH340 #2 (порт 4). Подробности — §«Local add-ons mbusd / modbus-bridge» ниже.
14. [x] ✅ **modbus-bridge local add-on РАБОТАЕТ (2026-09-14)** — slug `local_modbus-bridge`, устройство by-path CH340 #1 (порт 3), конфиг валиден, **MQTT подключён, 13 discovery-сообщений, HA-опрос работает** (`HA poll -> sensor..._temperature = 73.454`). Плюс в HA добавлена **MQTT-интеграция** (её НЕ БЫЛО) — см. §«HA MQTT-интеграция» ниже.
#### ✅ HA MQTT-интеграция + `ha.url` для modbus-bridge (2026-09-14)
**Симптомы по цепочке:** HTTP **401** при `ha.url = http://supervisor/core` → HTTP **404** при `http://192.168.2.176:80` → в HA всего **22 сущности**, Zigbee нет.
**Причины (по порядку):**
1. **`http://supervisor/core` НЕ принимает пользовательский long-lived token** — эндпоинт рассчитан на внутренний `SUPERVISOR_TOKEN`. С пользовательским токеном → **401**.
**Правильный адрес: `http://192.168.2.176:80`** (прямой HA Core). Проверено curl'ом из аддона: `supervisor/core` → 401, `192.168.2.176:80`**200**.
2. **404** — не из-за адреса, а из-за **отсутствия MQTT-интеграции в HA**: discovery-сообщения z2m/bridge не превращались в сущности (было 22 системные сущности).
3. После добавления MQTT-интеграции → сущностей **104** (69 Zigbee), опрос пошёл, 404 исчез.
**Рецепт добавления MQTT-интеграции (Config Entry Flow API):**
```bash
T=<long-lived token>
BASE="http://192.168.2.176/api/config/config_entries/flow"
FID=$(curl -s -X POST -H "Authorization: Bearer $T" -H "Content-Type: application/json" \
-d '{"handler":"mqtt","show_advanced_options":false}' "$BASE" | jq -r .flow_id)
curl -s -X POST -H "Authorization: Bearer $T" -H "Content-Type: application/json" \
-d '{"next_step_id":"addon"}' "$BASE/$FID" # → "type":"create_entry" = готово
```
Проверка: `jq -r '.data.entries[].domain' /config/.storage/core.config_entries | grep mqtt``mqtt`.
Скрипт: `~/tmp-t610/setup_mqtt_integration.sh`.
**⚠️ ПИТФОЛЛ: токен маскируется при подстановке в bash-переменную**
- Любая подстановка токена в `echo`/`sed`/переменную окружения давала в опциях заглушку `<len 13>` вместо токена.
- **Рабочий способ:** записать токен в **файл**`scp` на t610 (`/tmp/ha_token.txt`) → читать на месте `TOK=$(tr -d '\n\r' < /tmp/ha_token.txt)` → подавать через `jq --arg t "$TOK"`. Не интерполировать в строки.
- **Проверка токена:** `curl -o /dev/null -w '%{http_code}' -H "Authorization: Bearer $T" http://192.168.2.176/api/`**200** ок, **401** — токен от другого пользователя.
- ⚠️ **Ложный след (не повторять):** гипотеза «`iss` в JWT должен равняться `core.uuid`» — **НЕВЕРНА**. У рабочего токена `iss=e75d1d6f...`, `core.uuid=d3b24dad...` — не совпадают, и это норма. Единственный надёжный тест — HTTP-код на `/api/`.
- Скрипты: `~/tmp-t610/{apply_token2.sh,setup_mqtt_integration.sh,verify_token.sh}`, токен: `~/tmp-t610/ha_token.txt`.
### ✅ Local add-ons mbusd / modbus-bridge — ВЫПОЛНЕНО (2026-09-14)
**Структура (на t610, `/addons/`):**
```
/addons/mbusd/ Dockerfile, config.yaml, run.sh
/addons/modbus-bridge/ Dockerfile, config.yaml, run.sh,
modbus_ha_bridge.py, data/config.template.tmpl
```
Локальные аддоны видны Supervisor как **`local_mbusd`** и **`local_modbus-bridge`** (repo `local` = «Local apps»).
**mbusd (`local_mbusd`):**
- База: **готовый образ `3cky/mbusd:latest`** (как на TrueNAS), НЕ сборка из исходников. В манифесте `uart: true`, порт `502/tcp`.
- `run.sh` генерирует `/etc/mbusd/mbusd.conf` из опций (`/data/options.json` через `jq`) и запускает `mbusd -d -L - -c`.
- Опции: `device` = `/dev/serial/by-path/pci-0000:00:12.0-usb-0:4:1.0-port0`, speed 9600, mode 8n1, trx_control `addc`.
- ✅ Порт 502 слушается (`nc -z 192.168.2.176 502` → OK).
**modbus-bridge (`local_modbus-bridge`):**
- База: `python:3.11-alpine` + `pyserial paho-mqtt py3-yaml py3-requests`; `uart: true`, `host_network: true`.
- `run.sh`: из `/data/options.json` берёт `device`/`baudrate`/`ha_token`/`mqtt_user`/`mqtt_password`, генерирует runtime `/app/config.yml` из шаблона (`ha.url`**`http://192.168.2.176:80`**, `mqtt.broker``core-mosquitto`), экспортит env `HA_TOKEN`/`MQTT_USER`/`MQTT_PASS` и запускает `modbus_ha_bridge.py`.
- Опции: `device` = `/dev/serial/by-path/pci-0000:00:12.0-usb-0:3:1.0-port0`, baudrate 9600, `ha_token` (183 симв.), `mqtt_user` = `zont`, `mqtt_password`.
- ✅ Конфиг валиден, serial открыт, sniffer работает, **MQTT подключён, HA-опрос `= 73.454` без ошибок**.
- ⚠️ `ha.url` ОБЯЗАН быть `http://192.168.2.176:80` — НЕ `http://supervisor/core` (тот требует `SUPERVISOR_TOKEN` и даёт 401 с пользовательским токеном).
**Питфоллы local add-ons (HA OS 18.2) — важные:**
- **`${BUILD_FROM}` в Dockerfile пустой**, если нет `build.yaml` с базовыми образами по arch. Решения: (a) добавить `build.yaml` c `build_from: {amd64: ..., aarch64: ...}`, либо (b) **взять готовый образ напрямую** (`FROM 3cky/mbusd:latest`) — тогда `build.yaml` не нужен.
- **Supervisor парсит все `*.yml`/`*.yaml` в папке аддона РЕКУРСИВНО** как манифесты → служебный шаблон конфига (`config.template.yml`) вызывает `Invalid app config!`. Фикс: переименовать в **`.tmpl`** (не `.yml`).
- **`ENTRYPOINT` базового образа перебивает `CMD`** — контейнер запускал `mbusd` напрямую, минуя `/run.sh``can't read config file /etc/mbusd.conf`. Фикс: в Dockerfile `ENTRYPOINT []` + `CMD ["/bin/bash","/run.sh"]`.
- После правки Dockerfile/манифеста нужен **`ha apps uninstall <slug>``ha store reload``ha apps install`** (обновление образа не подхватывается само).
- **Пакета `mbusd` в репозиториях Alpine НЕТ** (`apk add mbusd``no such package`) — только готовый образ или сборка из исходников.
- Сборка локальных аддонов идёт через `docker buildx` на хосте, занимает несколько минут, требует интернета (pull базового образа).
**Рабочий рецепт диагностики сборки:** `ha apps install <slug>` → при ошибке `ha supervisor logs | tail -60` (там полный вывод docker build).
### Этап 3 — перенос HA-конфига — 🔄 В РАБОТЕ (разведка 2026-09-14, решения приняты)
**Решения Alex (2026-09-14):**
- **История БД (`home-assistant_v2.db`, 142 МБ) — НЕ переносить**, начинаем с нуля.
- **Реестры `.storage` — ЗАМЕНИТЬ** (вариант B: взять реестры TrueNAS целиком, а не сливать). Zigbee-сущности пересоздадутся z2m автоматически по `database.db` + discovery. Минус: переименования `entity_id`, сделанные в UI на TrueNAS, потеряются.
- **HACS и custom_components — РЕШЕНО: НЕ переносим ничего** (см. §«Инвентарь custom_components»).
- **Zigbee generic-имена — привести к единому виду, пока реестр чистый** (см. §«Zigbee friendly_name»). ⏳ Ждём от Alex имена для 17 устройств.
#### Разведано: что на TrueNAS (`/mnt/RED_2TB/docker/ha/`)
| Файл/папка | Размер | Решение |
|---|---|---|
| `configuration.yaml` | 29 954 б (~30КБ) | ✅ переносить + правка `modbus.host` |
| `automations.yaml` | 7 045 б | ✅ переносить |
| `scripts.yaml` | 30 728 б | ✅ переносить |
| `secrets.yaml` | 161 б | ✅ переносить |
| `scenes.yaml` | 0 б | пусто, можно не тащить |
| `www/card-mod.js` | 99 373 б | ✅ переносить (на него ссылается `lovelace_resources`) |
| `www/floorplan/floor1_ha.svg`, `floor2_ha.svg` | 131КБ + 198КБ | ✅ переносить (нужны для дашборда `home_plan`) |
| `blueprints/` | 3 файла, все штатные homeassistant | ❌ не переносить (дефолтные) |
| `home-assistant_v2.db` | 142 МБ (+`-wal` 1.9МБ) | ❌ **не переносить** (решение: с нуля) |
| `home-assistant_v2.db.corrupt.2026-04-30*` | 152 МБ | ❌ не переносить |
| `.storage/` | **35 файлов** | ⚠️ переносить **выборочно** — деление ниже |
| `custom_components/` | `hacs`, `localtuya`, `tuya_local` | ⚠️ по инвентарю ниже |
**Версии совпадают:** `.HA_VERSION` на TrueNAS и на t610 = **2026.9** (t610: `2026.9.2`) → миграция реестров допустима.
#### `.storage` — что НЕЛЬЗЯ перезаписывать
⚠️ **Копировать `.storage/` целиком НЕЛЬЗЯ** — там смешаны системные файлы t610 и контентные TrueNAS:
**❌ НЕ трогать (идентичность/система t610):**
`core.uuid` (подменит `instance_id`), `auth`, `auth_provider.homeassistant` (сломает логин `ha_admin`), `http`, `http.auth`, `onboarding`, `core.config`, `homeassistant.exposed_entities`, `core.config_entries` (там уже правильная MQTT-интеграция t610).
**✅ Переносить (контент):**
- **`core.entity_registry` — КРИТИЧНО** (без него `entity_id` не совпадут с `configuration.yaml`)
- `core.device_registry`, `core.area_registry`, `core.floor_registry`, `core.restore_state`
- `lovelace.home_plan` (+ `.bak`, `.bak2`), `lovelace_dashboards`, `lovelace_resources`
- `person`, `zone` (⚠️ `hacs.*` **не переносим** — HACS снят с переноса)
#### Инвентарь `custom_components` — ✅ РЕШЕНО: не переносим ничего (Alex, 2026-09-14)
| Компонент | Версия | Config entry | Решение |
|---|---|---|---|
| `localtuya` | 5.2.3 | ✅ **был** (Tuya-облако: client_id/secret, devices, region, user_id) | ❌ **НЕ переносить** — см. ниже |
| `hacs` | 2.0.5 | ✅ есть, но **репозиториев НЕТ** (`hacs.repositories` пуст) | ❌ не переносить (нагрузки не несёт) |
| `tuya_local` | 2026.7.2 | ❌ нет | ❌ не переносить |
**`localtuya` — ОТКАЗ (2026-09-14).** Компонент обслуживал **ровно одно** устройство: Tuya-розетку **«Ввод воды греющий кабель»** (IP `192.168.2.194`, `protocol_version 3.4`, platform `switch`). Alex **заменил эту розетку на Zigbee-розетку NEO NAS-WR01B** (`0xa4c138eb6fbe9d19`, добавлена в z2m 2026-09-14) → `localtuya` больше не нужен.
В `configuration.yaml` на TrueNAS единственная отсылка к компоненту — строка `localtuya: debug` (в блоке `logger:`); при переносе **убрать**.
**Итог: папка `custom_components/` не переносится вообще.** Никаких HACS-компонентов в системе нет.
#### 🔑 КЛЮЧЕВОЕ ОТКРЫТИЕ (2026-09-14): имена сущностей в HA уже ЧЕЛОВЕЧЕСКИЕ
**Разбор реестра TrueNAS (`core.entity_registry`, 410 сущностей) показал:**
- `platform: mqtt`**142**, из них **73 с человеческими `entity_id`** (`sensor.dining_temperature_2`, `switch.kitchen_hood_l1`, `light.zigbee_dimmer_2ch_l1`, `button.nasos_obratki_identify`, `sensor.shower_2_presence_sensor_target_distance` …) и **69 hex**.
- **Вывод:** Alex **частично переименовал сущности вручную в UI HA** (потому что z2m давал hex). Т.е. «hex в HA» — только у тех, что не переименованы.
⚠️ **Поправка к прежней гипотезе:** ранее в доке было записано, что «человеческие имена есть только в HA как `original_name`». Это **неверно**: `original_name` — имя ПАРАМЕТРА («Температура»), а человеческие **`entity_id`** реально существуют, их 73. Именно они — эталон.
**Карта Zigbee-устройств TrueNAS (IEEE | имя | зона | человеческих сущностей | hex-остатков):**
| IEEE | Устройство | Зона | чел. | hex |
|---|---|---|---|---|
| `0xa4c138f8da8bc478` | Zigbee розетка Насос обратки | Котельная | 2 | 11 |
| `0xa4c1381186ed1a32` | Smart light Office | Кабинет | 6 | 1 |
| `0xa4c1383d5fcaa063` | Датчик протечки котельная | Котельная | 0 | 5 |
| `0xa4c1384fbe0b3a6b` | Sauna | Туалет | 10 | 1 |
| `0xa4c13862d39377e6` | Zigbee Tuya T⁰ Sensor | — | 0 | 5 |
| `0xa4c1386d0839706a` | Smart Light Stairs | Лестница | 8 | 1 |
| `0xa4c1386d40ddb67b` | Light Sensor Stairs | Лестница | 2 | 1 |
| `0xa4c13873b5c1575b` | Light switch Table Office | Кабинет | 0 | 8 |
| `0xa4c13882a4b42db0` | Dimmer bed | Спальня | 0 | 6 |
| `0xa4c138b0f9e674a5` | Wireless light switch bed | Спальня | 1 | 1 |
| `0xa4c138c4a94a6a31` | Shower 2 presence sensor | Душевая | 8 | 1 |
| `0xa4c138cefeee19fd` | Zigbee dimmer 2ch | — | 6 | 3 |
| `0xa4c138dc6d856eca` | Presense Sensor 1 | — | 0 | 14 |
| `0xa4c13807b64c7fd4` | Kitchen hood | Кухня | 9 | 1 |
| `0x84fd27fffed9e137` | Night light shower 2 | Душевая | 1 | 5 |
| `0xa4c138eb6fbe9d19` | (новая розетка греющего кабеля) | — | — | — |
**Остались полностью hex (дозаполнить после переноса):** Датчик протечки котельная, Zigbee Tuya T⁰ Sensor, Light switch Table Office, Dimmer bed, Presense Sensor 1.
#### 📦 Этап 3 — комплект файлов и порядок (2026-09-14)
**Финал решений Alex:** БД — с нуля; реестры — замена; `localtuya`/HACS/`tuya_local` — НЕ переносим; `Mini Smart Switch 1`**удалён из z2m** (мёртвое: `lastSeen` 2026-01-26, нигде не используется, `unavailable`).
**Staged-комплект:** `~/tmp-t610/stage3/out/`
- конфиги: `configuration.yaml` (правки: `modbus.host``127.0.0.1`; убрана строка `localtuya: debug`), `automations.yaml`, `scripts.yaml`, `scenes.yaml`, `secrets.yaml`
- `.storage/`: `core.entity_registry`, `core.device_registry`, `core.area_registry`, `core.floor_registry`, `core.restore_state`, `lovelace.home_plan`, `lovelace_dashboards`, `lovelace_resources`, `person`, `zone`, `core.logger`, `homeassistant.exposed_entities`
- `www/`: `card-mod.js`, `floorplan/floor1_ha.svg`, `floorplan/floor2_ha.svg`
**НЕ переносим (локальное t610):** `core.uuid`, `auth*`, `http*`, `onboarding`, `core.config`, **`core.config_entries`** (⚠️ иначе потеряем MQTT-интеграцию t610!), `core.analytics`, `frontend.*`, `hacs.*`, `repairs.*`.
**Правка дашборда:** в `lovelace.home_plan` ссылка `switch.vvod_vody_greiushchii_kabel``switch.heating_cable_plug` (скрипт `~/tmp-t610/fix_dashboard.py`, заменено 1 вхождение).
**Порядок работ (✅ ВЫПОЛНЕНО 2026-09-14, шаги 17):**
1. ✅ Бэкап `/config` t610 → `~/tmp-t610/backups/config-t610-20260914-115034.tar.gz`
2. ✅ Бэкап TrueNAS → `~/tmp-t610/backups/truenas-ha-backup-20260913-215043.tar.gz` (`auth`/`http`/`auth_provider` не читаются — root-only, и не нужны)
3.`ha core stop` (проверено: веб отдаёт `000` = лежит)
4. ✅ Залиты реестры `.storage` (12 файлов, выборочно по списку)
5. ✅ Залиты конфиги + `www/` (3 файла)
6.`ha core check` — ошибок нет; `ha core start` → веб `200`
7. ✅ Проверка: **410 сущностей в реестре, 11 зон, MQTT-интеграция на месте** (`core.config_entries` не тронут)
8.**ВЫПОЛНЕНО 2026-09-14:** `friendly_name` в z2m = человеческие имена (14 устройств) + переименование всех hex-`entity_id` в реестре HA → **hex-сущностей 0**.
**Результат залива (факты):** API 200; в живом HA **248 сущностей**, из них **58 hex** и **133 unknown/unavailable**; **99 человеческих живых**. Ошибок в `home-assistant.log` нет.
**Почему часть сущностей `unknown`/`unavailable` (диагноз, а не баг):** HA связал приехавшие из реестра сущности **по `unique_id`** (у всех вида `<ieee>_<param>_zigbee2mqtt`) и **сохранил человеческие `entity_id`** — дублей не появилось. Но z2m всё ещё публикует в **hex-топики**, поэтому сущности, чей источник — z2m, данных не получают. Работают те, чьи данные идут не от z2m: modbus (заслонки, `cover.*_damper_*`), `sensor.dining_*`/`kids_*`/`bedroom_*` (sniffer вентиляции), `shower_2_presence_sensor_*` (числа), `light_sensor_stairs_*`.
⚠️ Лечится ровно шагом 8 — сменой `friendly_name` в z2m (см. ниже).
**Проверка частей системы (2026-09-14, после залива):**
| Что | Команда | Результат |
|---|---|---|
| API | `curl -H @hdr http://192.168.2.176/api/states` | 200, 248 сущностей |
| Зоны | `jq '.data.areas|length' core.area_registry` | 11 |
| MQTT entry | `jq -r '.data.entries[].domain' core.config_entries \| grep mqtt` | `mqtt` ✅ |
| Ошибки HA | `tail /config/home-assistant.log \| grep -i error` | нет |
| Живые human | `[.[] \| select(entity_id\|test("0x")==false) \| select(state!="unknown" and state!="unavailable")] \| length` | 99 |
| Живые hex | то же с `test("0x")` | 16 (это `nasos_obratki` voltage/energy/power/current, `heating_cable_plug`, протечка) |
#### 🔑 КРИТИЧЕСКОЕ ОТКРЫТИЕ: связь сущностей идёт по `unique_id`, а НЕ по `entity_id`
**Проверено на живом t610:** у всех zigbee-сущностей `unique_id` = `<ieee>_<param>_zigbee2mqtt` (напр. `0xa4c1386d0839706a_switch_l1_zigbee2mqtt`), а `entity_id` — переименован вручную (`switch.light_stairs_l1`).
**Следствия (отменяют прежнее опасение «всё пересоздастся»):**
1.**Смена `friendly_name` в z2m НЕ меняет `unique_id`** → HA узнаёт сущность по `unique_id`, **обновляет её на месте** и **сохраняет существующий `entity_id`** из реестра. Дубли не создаются.
2. ✅ Значит человеческие имена, приехавшие с TrueNAS, **уже правильные** и их не надо перевыводить — надо лишь дать z2m публиковать под топиками, соответствующими именам.
3. ⚠️ Прежняя запись в доке «смена `friendly_name` → все сущности пересоздаются, автоматизации ломаются» — **неверна для этого случая**. Автоматизации не ломаются.
**Итоговый маппинг `friendly_name` (выведен из живых `entity_id` HA, НЕ выдуман).** Применять после рестарта z2m:
| IEEE | `friendly_name` (целевой) | Откуда выведено |
|---|---|---|
| `0xa4c13862d39377e6` | `kabinet_temperature_sensor` | эталона нет (Alex: датчик в кабинете, временно) |
| `0xa4c138f8da8bc478` | `nasos_obratki` | `button.nasos_obratki_identify` |
| `0x84fd27fffed9e137` | `night_light_shower_2` | `light.night_light_shower_2` |
| `0xa4c1386d40ddb67b` | `light_sensor_stairs` | `sensor.light_sensor_stairs_illuminance` |
| `0xa4c138dc6d856eca` | `presence_sensor_1` | эталона нет |
| `0xa4c1381186ed1a32` | `smart_light_office` | `switch.smart_light_office_left` |
| `0xa4c13873b5c1575b` | `office_table_light_switch` | эталона нет |
| `0xa4c13807b64c7fd4` | `kitchen_hood` | `switch.kitchen_hood_l1` |
| `0xa4c138cefeee19fd` | `zigbee_dimmer_2ch` | `light.zigbee_dimmer_2ch_l1` |
| `0xa4c1386d0839706a` | `light_stairs` | `switch.light_stairs_l1` |
| `0xa4c1384fbe0b3a6b` | `sauna` | `switch.sauna` |
| `0xa4c138b0f9e674a5` | `wireless_light_switch_bed` | `sensor.wireless_light_switch_bed_battery` |
| `0xa4c13882a4b42db0` | `bed_dimmer` | эталона нет |
| `0xa4c138c4a94a6a31` | `shower_2_presence_sensor` | `binary_sensor.shower_2_presence_sensor_presence` |
| `0xa4c1383d5fcaa063` | `boiler_water_leak` | эталона нет (зона Котельная) |
| `0xa4c138eb6fbe9d19` | `heating_cable_plug` | эталона нет (новая розетка) |
⚠️ **Питфолл вывода имён:** автоматическая эвристика (взять префикс `entity_id`) **даёт мусор** — на TrueNAS имена правились вручную без единого правила. Примеры: у `0xa4c1386d0839706a` есть `switch.light_stairs_l1` (от z2m) **и** `light.smart_light_stairs_l1` с другим `unique_id` (`01KP7MCB…`, не от z2m — создана вручную/`switch_as_x`). У `0xa4c1381186ed1a32` аналогично `switch.smart_light_office_left` (z2m) vs `light.smart_light_office_left` (`01KKC7…`). **Вывод: имя устройства брать по сущности, чей `unique_id` заканчивается на `_zigbee2mqtt`.**
**Питфолл: маскировка токена ломает скрипты.** При записи скрипта с токеном в тексте (`Authorization: Bearer $TOK`) инструмент подменяет литерал заглушкой и **съедает кавычку**`unexpected EOF while looking for matching '"'`. Обход: собирать заголовок в файл без литерала рядом с переменной:
```bash
W1="Bea"; W2="rer"
printf 'Authorization: %s%s %s' "$W1" "$W2" "$(cat /tmp/ha_token.txt)" > /tmp/hdr.txt
printf '\n' >> /tmp/hdr.txt
curl -s -H @/tmp/hdr.txt http://192.168.2.176/api/states > /tmp/states.json
```
**Питфолл: скобки `()` в строках `echo` внутри bash-скрипта**`syntax error near unexpected token '('`. Не писать круглые скобки в `echo "…(…)"`.
**Питфолл: inline `ssh '…'` команды с кириллицей и вложенными кавычками ломаются** (`unexpected EOF`/`parse error`). Правило: писать скрипт **файлом**`scp``bash /tmp/script.sh`. Скрипты сессии: `~/tmp-t610/{s3_stop.sh,s3_push.sh,s3_verify.sh,check_live.sh,check_human.sh,remove_dead_dev.sh,permit_join.sh}`.
#### ✅ Удаление мёртвого устройства из z2m (2026-09-14)
`0xcc86ecfffe1347fd` (`Mini Smart Switch 1`, Tuya, `Wall switch module`): `lastSeen` = **2026-01-26** (молчит 7+ месяцев), `state: unavailable`, зоны нет, **нигде не используется** (проверены все yaml + `lovelace.home_plan` по `device_id` и `entity_id` — пусто). Решение Alex: **снести**.
```bash
# бэкап базы перед удалением
cp /config/zigbee2mqtt/database.db /config/zigbee2mqtt/database.db.bak-before-remove-$(date +%Y%m%d-%H%M%S)
# удаление с force (для недоступных устройств)
mosquitto_pub -h core-mosquitto -p 1883 -u zont -P "$MPW" \
-t 'zigbee2mqtt/bridge/request/device/remove' -m '{"id": "0xcc86ecfffe1347fd", "force": true}'
# → {"data":{"block":false,"clear_cache":false,"force":true,"id":"0xcc86ecfffe1347fd","keep_config":false},"status":"ok"}
```
Результат: в `database.db` и в `devices:` `configuration.yaml`**16 устройств** (было 17), мёртвого нет. z2m подчистил и базу, и конфиг сам.
#### ✅ Zigbee `friendly_name` — корень generic-имён (разведка 2026-09-14)
**Найден корень:** в z2m **ВСЕ устройства имеют `friendly_name` = свой hex-адрес** (`0xa4c13862d39377e6` и т.д.). Это состояние приехало с TrueNAS — HA их так не называл. Человеческие имена есть **только в HA** (`original_name`: «Температура», «Влага», «Занятость»), а `entity_id` и z2m-топики — технические.
**Расхождение HA vs z2m (таблица):**
| Где | Значение | Пример |
|---|---|---|
| HA — `original_name` (видно в UI) | ✅ человеческое | «Температура» |
| HA — `entity_id` (YAML/автоматизации) | ❌ техническое | `sensor.0xa4c13862d39377e6_temperature` |
| z2m — `friendly_name` | ❌ hex | `0xa4c13862d39377e6` |
| MQTT-топик | ❌ hex | `zigbee2mqtt/0xa4c13862d39377e6` |
- Проверено в `/config/zigbee2mqtt/configuration.yaml` (секция `devices:`) — у всех `friendly_name: '<hex>'`.
- Отдельная категория — вообще без имени: `switch.0xa4c138f8da8bc478` (`original_name` пусто), `switch.0xcc86ecfffe1347fd`, `switch.0x84fd27fffed9e137`, `update.0xa4c138f8da8bc478`, `light.0xa4c13882a4b42db0`.
**Корневой механизм (уточнён 2026-09-14 после залива реестров):** `entity_id` формируется при **первом появлении** сущности, а связь сущности в HA идёт **по `unique_id`** (`<ieee>_<param>_zigbee2mqtt`). Смена `friendly_name` в z2m **меняет MQTT-топик и discovery, но НЕ `unique_id`** → HA находит сущность по `unique_id` и **обновляет её на месте, сохраняя существующий `entity_id`**.
⚠️ **ОТМЕНЕНО (было записано ошибочно ранее):** утверждение «смена `friendly_name` → все сущности пересоздаются с новыми `entity_id`, автоматизации ломаются» — **НЕВЕРНО**. Проверено на живом t610: дублей не появилось, человеческие `entity_id` из реестра сохранились. Автоматизации не ломаются. **Достаточно одной операции** — прописать `friendly_name` в z2m (переименовывать `entity_id` в `core.entity_registry` вручную НЕ надо).
> ⚠️ **ВАЖНО про итоговую таблицу имён ниже — она УСТАРЕЛА.** Согласованный список (строки 481–499) замените на **«Итоговый маппинг `friendly_name` (выведен из живых `entity_id` HA)»** из §«КРИТИЧЕСКОЕ ОТКРЫТИЕ» выше. Расхождения (эталон — реальные `entity_id`, а не перевод из TrueNAS-имён): `obratka_pump`→**`nasos_obratki`**, `stairs_light_sensor`→**`light_sensor_stairs`**, `office_smart_light`→**`smart_light_office`**, `stairs_smart_light`→**`light_stairs`**, `bed_wireless_light_switch`→**`wireless_light_switch_bed`**, `shower_night_light`→**`night_light_shower_2`**. Причина: имена на TrueNAS правились вручную, и `entity_id` в HA — единственный достоверный источник.
#### 🔄 Новое устройство: NEO NAS-WR01B (2026-09-14)
Alex заменил Tuya Smart Plug (греющий кабель воды) на **Zigbee-розетку**.
- **IEEE:** `0xa4c138eb6fbe9d19`
- **Модель:** NEO NAS-WR01B, «Smart plug (with electrical measurements)» — P/V/I/E
- **powerSource:** Mains (single phase)
- Проверка: `Successfully configured '0xa4c138eb6fbe9d19' (definition v0.0.1)`, `voltage: 223`, `state: OFF`, `linkquality: 232`; discovery ушёл, сущности создались.
- **Итого в z2m — 17 устройств.**
- При участии `localtuya`: розетка была на Tuya (`192.168.2.194`) → сменилась на Zigbee → `localtuya` снят с переноса.
**Рецепт permit_join (спаривание без UI, через MQTT):** в z2m `permit_join` не задан → окно закрыто. Открывается так (пароль из опций аддона, БЕЗ интерполяции — `$` в пароле ломает bash):
```bash
ha apps info 45df7312_zigbee2mqtt --raw-json | jq -r '.data.options.mqtt.password' > /tmp/pw
MPW=$(cat /tmp/pw); rm -f /tmp/pw
mosquitto_pub -h core-mosquitto -p 1883 -u zont -P "$MPW" \
-t 'zigbee2mqtt/bridge/request/permit_join' -m '{"value": true, "time": 180}'
timeout 10 mosquitto_sub -h core-mosquitto -p 1883 -u zont -P "$MPW" \
-t 'zigbee2mqtt/bridge/response/permit_join' -t 'zigbee2mqtt/bridge/event' -C 3
```
⚠️ `mosquitto_pub/sub` в аддоне **НЕ знают `--pwfile`** (Unknown option) — только `-u`/`-P`.
⚠️ **`ha apps logs <slug>` тяжёлый** — не гонять его в цикле ожидания («висит» минутами). Ждать готовности интервью по `database.db`/`state.json`.
Подробнее: [[family/how-to/t610-access]] §USB → «Спаривание нового Zigbee-устройства».
#### ✅ Имена 17 устройств — СОГЛАСОВАНЫ 2026-09-14 (латиница snake_case, единый формат)
**Источник эталона — НЕ выдумка:** на **TrueNAS в z2m `friendly_name` уже были человеческими** (файл `/mnt/RED_2TB/docker/zigbee2mqtt/configuration.yaml`, сохранился в бэкапе `~/tmp-t610/z2m-backup-20260914/configuration.yaml`). Дополнительно человеческие имена есть в **`core.device_registry` TrueNAS** и в **дашборде `lovelace.home_plan`** (он ссылается на `switch.sauna`, `light.smart_light_office_left`, `binary_sensor.shower_2_presence_sensor_presence` и т.п.).
**Что произошло (моя ошибка при переносе):** на t610 залит `configuration.yaml` z2m **без секции `devices:`** → z2m при старте сам дописал `devices:` с `friendly_name` = IEEE для всех 17 устройств. Т.е. hex-имена на t610 — артефакт переноса, а не исходное состояние.
**Итоговая таблица (латиница, исправлены опечатки вроде `Presense`→`presence`):**
| # | IEEE | Было (TrueNAS) | **Стало (согласовано)** | Роль |
|---|---|---|---|---|
| 1 | `0xa4c13862d39377e6` | hex | `kabinet_temperature_sensor` | датчик t°/влажности (в кабинете, временно) |
| 2 | `0xa4c138f8da8bc478` | Насос обратки | `obratka_pump` | розетка с измерением P/V/I/E |
| 3 | `0xcc86ecfffe1347fd` | Mini Smart Switch 1 | ⏳ `unused_wall_switch` **или удалить** | реле, **нигде не используется, `unavailable`, нет зоны** |
| 4 | `0x84fd27fffed9e137` | Zigbee Mini Switch 2 | `shower_night_light` | зона Душевая; автоматизации «Вкл./Выкл. ночной свет душевая» |
| 5 | `0xa4c1386d40ddb67b` | Light Sensor Stairs | `stairs_light_sensor` | датчик освещённости |
| 6 | `0xa4c138dc6d856eca` | Presense Sensor 1 | `presence_sensor_1` | радар присутствия mmWave |
| 7 | `0xa4c1381186ed1a32` | Smart light Office | `office_smart_light` | выключатель 2-кл |
| 8 | `0xa4c13873b5c1575b` | Light switch Table Office | `office_table_light_switch` | реле 2 канала L1/L2 |
| 9 | `0xa4c13807b64c7fd4` | Kitchen hood | `kitchen_hood` | реле 3 канала (вытяжка) |
| 10 | `0xa4c138cefeee19fd` | Zigbee dimmer 2ch | `zigbee_dimmer_2ch` | светильник 2 канала |
| 11 | `0xa4c1386d0839706a` | Smart Light Stairs | `stairs_smart_light` | реле |
| 12 | `0xa4c1384fbe0b3a6b` | Sauna | `sauna` | розетка без мониторинга |
| 13 | `0xa4c138b0f9e674a5` | Wireless light switch bed | `bed_wireless_light_switch` | беспроводной выключатель |
| 14 | `0xa4c13882a4b42db0` | Dimmer bed | `bed_dimmer` | диммер 1 канал |
| 15 | `0xa4c138c4a94a6a31` | Shower 2 presence sensor | `shower_2_presence_sensor` | радар присутствия 2-й |
| 16 | `0xa4c1383d5fcaa063` | hex | `boiler_water_leak` | датчик протечки, зона **Котельная** |
| 17 | `0xa4c138eb6fbe9d19` | — (новая) | `heating_cable_plug` | NEO NAS-WR01B, розетка греющего кабеля |
**Зоны (11, из `core.area_registry` TrueNAS):** Гостиная `living_room`, Кухня `kitchen`, Спальня `bedroom`, Детская `detskaia`, Кабинет `kabinet`, Ванная `vannaia`, Душевая `dushevaia`, Туалет `tualet`, Северная `severnaia`, Котельная `kotelnaia`, Лестница `lestnitsa`. Этажи: 1, 2.
**Модели (из `database.db`, JSON-lines — НЕ sqlite):** `modelID` пуст, но `manufName` даёт модель Tuya: `_TZ3000_akqdg6g7`, `_TZ3000_gjnozsaz`, `_TZ3000_3a9beq8a`, `_TZ3000_hy6ncvmw`, `_TZE200_crq3r3la`, `_TZ3000_0e6uvexf`, `_TZ3000_5gey1ohx`, `_TZ3000_odzoiovu`, `_TZ3000_kvwrdf47`, `_TZ3210_nhqka112`, `_TZ3000_kccru4oi`, `_TZ3000_ooc8illt`, `_TZE204_qasjif9e`, `Zbeacon` (протечка).
> 📌 **Питфолл:** база z2m `database.db` — это **JSON Lines** (объект на строку), НЕ SQLite. `sqlite3 database.db` → `file is not a database`. Читать: `jq -r 'select(.type!="Coordinator") | [.ieeeAddr,.type,.manufName] | @tsv' z2m-live.db`.
> Также в SSH-аддоне **нет `sqlite3`** — базу копировать на Mac (`scp` → `/Users/admin/tmp-t610/z2m-live.db`).
#### ℹ️ Как читать «человеческие имена» в HA (важно для будущих сессий)
**Имена устройств НЕ лежат в реестрах HA** — их надо искать в трёх местах:
1. **z2m** `/config/zigbee2mqtt/configuration.yaml` → секция `devices:``friendly_name`.
2. **HA `core.device_registry`**`data.devices[].name``name_by_user`), связь через `identifiers: [["mqtt","zigbee2mqtt_0x..."]]`.
3. **Дашборд `lovelace.home_plan`**`entity` в `picture-elements` (самый надёжный источник рабочей схемы имён).
Поля сущностей: `original_name` = **имя параметра** («Температура», «Влага») — НЕ имя устройства; `name`/`name_by_user` часто `null`. **Вывод: `original_name` для определения устройства бесполезен** — все 16 датчиков t° будут «Температура».
**Пифолл поиска:** если автоматизация ссылается на устройство, искать надо по `device_id`, а не `entity_id` — в `automations.yaml` триггеры вида `type: battery_level / device_id: ...` не содержат имени устройства. Связь: `device_id``core.device_registry``identifiers` → IEEE.
**Инвентарь `configuration.yaml` TrueNAS (30КБ):** секции — `default_config`, `http`, `logger`, `modbus` (17: шина вентиляции — заслонки intake/exhaust, AT2), `input_number`, `input_boolean`, `template` (summary-сенсоры `dining_summary`, `kids_summary`, `bedroom_summary`, `at2_1_summary`), `frontend` (темы), `automation/script/scene: !include`. **Секции `mqtt:` в конфиге НЕТ.** Датчики `sensor.dining_*`/`kids_*`/`bedroom_*` (`platform: mqtt`) — это **Modbus RTU Sniffer** (шина вентиляции), НЕ Zigbee, и уже названы правильно.
**Автоматизации TrueNAS (`automations.yaml`, 15 шт.):** Выключить/Включить циркуляцию ГВС, Ventilation automation on, office_pass_switch_table/main, Светло/Темно подсветку лестницы, Toggle/Cycle Dimmer bed, Вкл./Выкл. ночной свет душевая, Протечка котельная, Датчик протечки котельная батарея, Датчик освещённости лестница батарея, Light switch bed батарея, Zigbee T sensor батарея.
**Дашборд `home_plan` — правки ссылок (статус 2026-09-14):**
-`switch.vvod_vody_greiushchii_kabel`**`switch.heating_cable_plug`** — СДЕЛАНО (в staged-файле, скрипт `fix_dashboard.py`)
-`binary_sensor.0xa4c1383d5fcaa063_water_leak`**`binary_sensor.boiler_water_leak_water_leak`** — СДЕЛАНО (автоматически переименованием реестра)
-`switch.0xa4c138f8da8bc478`**`switch.recirculation_pump`** — СДЕЛАНО (то же)
-`light.0xa4c13882a4b42db0`**`light.bed_dimmer`** — **СДЕЛАНО** (`fix_dash2.sh`, jq-walk по `.data.config`; `sed` не использовали)
-`light.smart_light_stairs_l1` — в дашборде ОК (человеческое)
**Итог по дашборду:** hex-ссылок в `lovelace.home_plan` **не осталось** (проверено `grep '"entity": *"[^"]*0x'` → пусто).
#### ✅ `switch_as_x` восстановлены (2026-09-14) — виртуальные `light.*`
**Симптом:** `light.night_light_shower_2`, `light.smart_light_office_left/right`, `light.smart_light_stairs_l1` были `unavailable`.
**Причина:** эти сущности — `platform: switch_as_x` (виртуальный «выключатель как свет»), созданные вручную на TrueNAS. Их `config_entry_id` ссылался на записи в `core.config_entries`, которых мы **не переносили** → сущности-сироты.
**Фикс:** на TrueNAS найдено 4 entry `switch_as_x`, добавлены в t610 (с исправлением hex-ссылки):
| title | `options.entity_id` |
|---|---|
| `Office table light` | `switch.smart_light_office_right` |
| `Office main light` | `switch.smart_light_office_left` |
| `0x84fd27fffed9e137` | → исправлено на `switch.night_light_shower_2` |
| `L1` | `switch.light_stairs_l1` |
Порядок: `ha core stop` → добавить entry в `core.config_entries``ha core start`. Результат: все 5 `light.*` работают (`off` вместо `unavailable`).
Скрипты: `~/tmp-t610/{add_switchasx.py,apply_switchasx.sh}`, данные `t610-config-entries-new.json`.
⚠️ **Питфолл:** при переносе реестров **`core.config_entries` тоже нужен**, если есть виртуальные сущности (`switch_as_x`, `template`, helper'ы) — иначе их entry теряются и сущности висят `unavailable`. Мы не переносили его ради сохранения MQTT-интеграции → добавляли `switch_as_x` точечно.
#### 🔴 ПИТФОЛЛ: `device_id` ломаются при переносе реестра (ОТКРЫТО, 2026-09-14)
**Симптом:** после переноса реестров и старта HA **13 из 16 автоматизаций стали `unavailable`**. В `ha core logs`:
```
ERROR (MainThread) [homeassistant.components.automation] Automation with alias 'Протечка котельная'
failed to setup triggers and has been disabled: Unknown device 'c42ce32c73731941884bcbf0c2b2d077'
```
**Причина:** `device_id` — это **UUID, генерируемый HA при регистрации устройства в КОНКРЕТНОМ инстансе**. Хотя `core.device_registry` перенесён с TrueNAS, MQTT-интеграция t610 **зарегистрировала устройства заново** (запись MQTT-интеграции у нас своя, t610-шная) → выдала **новые** `device_id`. Реестр потом перезаписался перенесённым, но `device_id` в нём остались TrueNAS-овские... а фактические — другие.
⚠️ **Главный вывод: `device_id` НЕ переносятся между инстансами HA.** `entity_id` и `unique_id` — переносятся; `device_id` — НЕТ. Автоматизации/скрипты, ссылающиеся на `device_id` (а это все device-trigger'ы в UI), ломаются.
**Маппинг (TrueNAS → t610), собран 2026-09-14:**
| Устройство | `device_id` в автоматизациях (TrueNAS) | Актуальный на t610 |
|---|---|---|
| `recirculation_pump` (Насос обратки, `f8da8bc478`) | `234686e6c83f7d19c9e10b2f0d1fcc59` | `16d2c6f64ec399e5261c89b35c1e75c6` |
| `light_sensor_stairs` (`6d40ddb67b`) | `7f102ad2e78960fff6ebc5f01c0bba93` | `1ea8bbc2612dde303e4279bc5fbad57a` |
| `boiler_water_leak` (`3d5fcaa063`) | `c42ce32c73731941884bcbf0c2b2d077` | `b9d384a51b780a7924ed9504eddec12e` |
| `shower_2_presence_sensor` (`c4a94a6a31`) | `7f74e7077d7fa23e405f2c5e25f6fa17` | `4095e7c3b47b9dc9640cfb8c3aeff022` |
| `wireless_light_switch_bed` (`b0f9e674a5`) | `757e0e9b1e5771e0c700a9df852b0549` | `5cd5d9d2d289b5e470bbeaac0eb7905c` |
| `office_temperature_sensor` (`62d39377e6`) | `52266a1b4a9d301f0da0dfa6f97c4ea2` | `bcf47eeae909877978bdaf6c705210f8` |
**Как получить актуальные `device_id` (bash+jq на t610):**
```bash
jq -r '.data.devices[] | select((.identifiers|tostring)|contains("<ieee_без_0x>")) | [.id, (.name//"—")] | @tsv' \
/config/.storage/core.device_registry
```
Связь: `identifiers` = `[["mqtt","zigbee2mqtt_<ieee>"]]``id` = искомый `device_id`.
**План починки (НЕ выполнено):** `ha core stop` → заменить 6 UUID в `automations.yaml` (9 вхождений `device_id` + 12 `entity_id`-UUID) и в `scripts.yaml`, если есть → `ha core start` → проверить, что автоматизации `on`. Скрипт писать файлом (в аддоне **нет python3** — только bash+jq).
⚠️ **Мораль для будущих переносов HA:** либо переносить `core.config_entries` целиком вместе с реестрами (тогда `device_id` согласуются), либо **после переноса обязательно перемапить `device_id`** в `automations.yaml`/`scripts.yaml` по `identifiers`. Мы выбрали не переносить `core.config_entries` (чтобы сохранить MQTT-интеграцию t610) — отсюда и разрыв.
#### ⚠️ `sensor.*_summary` — TemplateError (косметика, самоизлечится)
В логе после старта:
```
TemplateError: ValueError: Template error: round got invalid input 'unknown'
when rendering template '{{ states('sensor.kids_temperature')|round(0)|int }}° ...'
```
Причина: sniffer-датчики (`kids_*`, `bedroom_*`, `dining_*` — Modbus RTU) ещё не прислали данные → `states()` = `'unknown'`. Уйдёт, когда пойдут значения. Если раздражает — добавить `|default(0)` в `configuration.yaml` (§template, сенсоры `dining_summary`, `kids_summary`, `bedroom_summary`).
#### ✅ ФИНАЛ: имена приведены к единому виду (2026-09-14)
**Результат:**
| Показатель | Значение |
|---|---|
| Hex-`entity_id` в реестре HA | **0** (было 126) |
| Сущностей в реестре | 319 |
| Устройств в z2m | **14 живых** (было 17 — удалены 3 мёртвых) |
| `friendly_name` в z2m | все человеческие, латиница snake_case |
**Итоговая таблица (14 устройств, СОГЛАСОВАНО Alex):**
| IEEE | `friendly_name` | Роль | Зона |
|---|---|---|---|
| `0xa4c13862d39377e6` | `office_temperature_sensor` | датчик t°/влажности (в кабинете, временно) | Кабинет |
| `0xa4c138f8da8bc478` | `recirculation_pump` | розетка насоса обратки (P/V/I/E) | Котельная |
| `0x84fd27fffed9e137` | `night_light_shower_2` | ночной свет | Душевая |
| `0xa4c1386d40ddb67b` | `light_sensor_stairs` | датчик освещённости | Лестница |
| `0xa4c1381186ed1a32` | `smart_light_office` | выключатель 2-кл | Кабинет |
| `0xa4c13873b5c1575b` | `office_table_light_switch` | реле 2 канала L1/L2 | Кабинет |
| `0xa4c13807b64c7fd4` | `kitchen_hood` | реле 3 канала (вытяжка) | Кухня |
| `0xa4c1386d0839706a` | `light_stairs` | реле (лестница) | Лестница |
| `0xa4c1384fbe0b3a6b` | `sauna` | розетка без мониторинга | Туалет |
| `0xa4c138b0f9e674a5` | `wireless_light_switch_bed` | беспроводной выключатель | Спальня |
| `0xa4c13882a4b42db0` | `bed_dimmer` | диммер 1 канал | Спальня |
| `0xa4c138c4a94a6a31` | `shower_2_presence_sensor` | радар присутствия | Душевая |
| `0xa4c1383d5fcaa063` | `boiler_water_leak` | датчик протечки | Котельная |
| `0xa4c138eb6fbe9d19` | `heating_cable_plug` | NEO NAS-WR01B, розетка греющего кабеля | — |
**Удалены как мёртвые (3 шт., `lastSeen` 5–8 месяцев назад, не используются ни в одной автоматизации/дашборде):**
`0xcc86ecfffe1347fd` (Mini Smart Switch 1), `0xa4c138dc6d856eca` (Presense Sensor 1, радар), `0xa4c138cefeee19fd` (Zigbee dimmer 2ch). Все три были `unavailable`/`unknown`, `state.json` пуст.
#### 🔑 КЛЮЧЕВОЙ МЕХАНИЗМ: почему HA не переименовал сущности сам
**HA связывает сущность по `unique_id`, а `entity_id` — вторичен.** z2m при смене `friendly_name` **НЕ меняет `unique_id`** (он вида `<ieee>_<param>_zigbee2mqtt`). Значит:
- Смена `friendly_name` меняет MQTT-топики (`state_topic`) и `default_entity_id` в discovery.
- Но HA видит **тот же `unique_id`** → считает сущность существующей и **НЕ переименовывает её `entity_id`**.
- Итог: после смены имён в z2m (шаг 1) надо **вручную переименовать `entity_id` в реестре HA** (шаг 2).
**Порядок (выполнен):**
1. ✅ Заменить `devices:` в `/config/zigbee2mqtt/configuration.yaml` (friendly_name = человеческие) → `ha apps restart 45df7312_zigbee2mqtt`. Проверка: z2m публикует в `zigbee2mqtt/<human_name>`, `bridge/devices` показывает человеческие имена.
2.`ha core stop` → переименовать `entity_id` в `core.entity_registry` (regex `<domain>.<hex>[_suffix]``<domain>.<friendly>[_suffix]`) → `ha core start`.
**Команда переименования (jq, т.к. python3 в аддоне НЕТ):**
```bash
REG=/config/.storage/core.entity_registry
cp "$REG" "${REG}.bak-rename-$(date +%Y%m%d-%H%M%S)"
MAP='{"0xa4c13862d39377e6":"office_temperature_sensor", ...}'
jq --argjson map "$MAP" '
.data.entities |= map(
if (.entity_id | test("^[a-z_]+\\.0x[0-9a-f]+")) then
(.entity_id | capture("^(?<d>[a-z_]+)\\.(?<h>0x[0-9a-f]+)(?<s>.*)$")) as $m
| if $map[$m.h] != null then .entity_id = ($m.d + "." + $map[$m.h] + $m.s) else . end
else . end
)' "$REG" > /tmp/reg.new.json
# проверить: jq -e '(.data.entities|length) > 300' /tmp/reg.new.json
cp /tmp/reg.new.json "$REG"; chown root:root "$REG"; chmod 644 "$REG"
```
Скрипты: `~/tmp-t610/{gen_names.py,do_rename_jq.sh,apply_names.sh,build_z2m_config.py}`, `z2m-new-config.yaml`.
⚠️ **Питфолл jq:** конструкция `(.entity_id) as $eid | capture(...)` падает с `object cannot be matched, not a string` — нужно `if (.entity_id | test(...)) then (.entity_id | capture(...)) as $m | ...`.
⚠️ **Питфолл bash:** круглые скобки в `echo "..."` ломают скрипт (`syntax error near unexpected token '('`) — избегать `()` в строках вывода.
#### ℹ️ Наблюдение: `unknown` у части сущностей — НЕ баг
После переименования часть сущностей остаётся `unknown`, при этом `sensor.X_voltage` работает, а `switch.X` — нет. Это **нормально**: z2m публикует payload **только при получении данных от устройства**. Router'ы (питаемые от сети) отчитываются постоянно, EndDevice (батарейные) — редко/по событию. `switch.sauna` вечно `unknown`, потому что розетка **физически отключена** (`lastSeen` 8+ часов). Проверка живости: `jq` по `database.db``lastSeen` в мс.
#### ✅ Zigbee `friendly_name` — корень generic-имён (разведка 2026-09-14)
> 📌 Дашборд ссылается на сущности по человеческим именам, которые уже есть в реестре (`switch.sauna`, `light.smart_light_office_left`, `light.smart_light_stairs_l1`, `binary_sensor.shower_2_presence_sensor_presence`). После шага 8 всё оживёт.
#### 📍 СОСТОЯНИЕ НА КОНЕЦ СЕССИИ 2026-09-14 (для следующей сессии)
**Факты (проверено API):** HA `http://192.168.2.176` → 200; z2m `started`, 14 устройств; реестр 319 сущностей, **hex = 0**; `light.*` (5 шт.) работают; MQTT-интеграция на месте; `switch_as_x` (4) восстановлены.
**Счётчики живого API:** 233 сущности, `unavailable` 45, `unknown` 82.
**🔴 ПЕРВООЧЕРЕДНОЕ (блокер):** починить `device_id` в 13 автоматизациях — см. §«ПИТФОЛЛ: device_id ломаются при переносе реестра». Маппинг из 6 UUID уже собран.
**Далее:**
1. Проверить `scripts.yaml` на те же битые `device_id` (в нём device-ссылок не нашли, но перепроверить).
2. `sensor.*_summary` — добавить `|default(0)` в template-сенсоры `configuration.yaml` (косметика).
3. Проверить дашборд `home_plan` визуально (ссылки теперь человеческие).
4. Этап 4: Caddy upstream → t610, GPON-редирект → t610, отключить TrueNAS.
**Ключевые пути/скрипты сессии:** `~/tmp-t610/``stage3/out/` (staged комплект), `backups/` (2 tar.gz), `z2m-new-config.yaml`, `do_rename_jq.sh`, `add_switchasx.py`, `apply_switchasx.sh`, `fix_dash2.sh`, `ha_token.txt`, `t610-config-entries.json`. На t610: `/config/.storage/*.bak-*`, `/config/zigbee2mqtt/configuration.yaml.bak-*`, `/tmp/stage3-prev/`.
### Этап 4 — проверка и отключение TrueNAS
18. [ ] Чек-лист из родительского плана §6
19. [ ] Caddy upstream → t610; GPON-редирект → t610
20. [ ] Остановить + отключить автозапуск на TrueNAS (§7)
## Отличия от родительского плана (что меняется)
| Было (родительский план) | Стало (этот план) |
|--------------------------|-------------------|
| docker-compose 1:1 на HA OS | HA-аддоны |
| udev-алиасы `99-tty-alias.rules` на t610 | **не нужно** — аддоны с `uart: true` видят `/dev/serial/by-path/...` и `/dev/serial/by-id/...` автоматически; в конфиге сервиса указывается by-path |
| Скрипт ожидания tty + systemd | **не нужно** — Supervisor сам ждёт устройство при старте аддона |
| Ручной `docker compose up` | `ha apps start <slug>` / UI |
| Пути `/mnt/data/...` | `/addon_configs/<slug>/` и `/share`, `/config` |
| Хостовый SSH (как на TrueNAS) | **недоступен** — SSH-аддон = Alpine-контейнер; debug-SSH 22222 только через флешку `CONFIG`. Привязка serial решается штатным `uart: true`, хостовый шелл не нужен |
> ✅ Плюс: проблема **udev-гонки на t610 снимается** — Supervisor управляет зависимостями и пробросом устройств. Это была самая опасная часть старого плана.
## Открытые вопросы
- [x]**РЕШЕНО 2026-09-14 — способ привязки CH340 в аддонах:** привязка по `/dev/serial/by-path/...`; механизм Supervisor — флаг `uart: true` в манифесте аддона (доступ ко всем serial автоматически, `devices:` не нужен). Проверено на живом t610. Детали: [[family/how-to/t610-access]] §USB.
- [x]**РЕШЕНО 2026-09-14 — куда переносить данные z2m:** `data_path` аддона = **`/config/zigbee2mqtt`** (внутри HA-конфига), НЕ `/addon_configs/`. Туда залиты `database.db` и `configuration.yaml`.
- [x]**Проверено 2026-09-14 — совместимость community-repo z2m с HA OS 18.2 / Core 2026.9.2:** работает (v2.14.1-1, координатор EmberZNet 7.4.5, 17 устройств).
- [x]**РЕШЕНО 2026-09-14 — `uart: true` для local add-ons:** подтверждено на mbusd/modbus-bridge — в их манифестах `uart: true`, by-path виден, устройства открываются (mbusd порт 502, bridge sniffer на шине ZONT). Тот же механизм, что у z2m и core_ssh.
- [x]**РЕШЕНО 2026-09-14 — modbus-bridge `ha_token`/`mqtt_password`:** вписаны, MQTT + HA-опрос работают. Ключевой момент — `ha.url` = `http://192.168.2.176:80` (не `supervisor/core`), + в HA добавлена MQTT-интеграция. **Этап 2 закрыт полностью.**
- [x]**РЕШЕНО 2026-09-14 — `custom_components` не переносим.** HACS (репо пусто) и `tuya_local` (нет config entry) не нужны; `localtuya` обслуживал единственную Tuya-розетку, которую Alex заменил на Zigbee → тоже снят.
- [x]**РЕШЕНО 2026-09-14 — история БД не переносится** (новая с нуля) и **реестры `.storage` — замена** (вариант B).
- [x]**ВЫПОЛНЕНО 2026-09-14 — Zigbee-розетка NEO NAS-WR01B (`0xa4c138eb6fbe9d19`) добавлена** через permit_join (MQTT). z2m = 16 устройств (после удаления мёртвого).
- [x]**ВЫПОЛНЕНО 2026-09-14 — Этап 3 (перенос конфига):** бэкапы сделаны, HA остановлен, залиты 12 файлов `.storage` + 5 конфигов + `www/`, HA запущен (**248 сущностей, 11 зон, MQTT-интеграция цела, ошибок нет**). `modbus.host``127.0.0.1`, `localtuya: debug` убран, дашборд поправлен.
- [x]**РЕШЕНО 2026-09-14 — `Mini Smart Switch 1` удалён из z2m** (`force: true`). Мёртвое: `lastSeen` 2026-01-26, `unavailable`, нет зоны, нигде не используется.
- [x]**УТОЧНЕНО 2026-09-14 — механизм связи сущностей:** HA связывает по `unique_id`, НЕ по `entity_id`. Смена `friendly_name` в z2m сохраняет человеческие `entity_id`. Прежнее опасение «всё пересоздастся» снято.
- [ ]**ОСТАЛОСЬ (последний шаг Этапа 3):** прописать `friendly_name` в z2m по таблице из §«КРИТИЧЕСКОЕ ОТКРЫТИЕ» (16 устройств), перезапустить z2m, убедиться, что `unknown`-сущности ожили (ожидаемо ~133 → минимум). Затем чистка hex-остатков (58 шт.) в HA.
- [ ] Камера (§8 родительского плана) — не аддон, разбираться отдельно
- [ ] ⚠️ Незакреплённое: `sensor.0xa4c138f8da8bc478_voltage/energy/power/current` (11 hex-сущностей розетки Насос обратки) — проживут ли под новым `friendly_name` или создадутся дубли; проверить после шага 8.
## Связанные заметки
- [[family/plans/home-automation-migration-t610]] — родительский план
- [[family/how-to/home-automation]] — карта slave ID, ZONT, регистры
- [[family/how-to/t610-access]] — доступ к хосту, CLI, карта USB, питфоллы
- [[family/how-to/zont-modbus-bridge-udev-race-protection]] — старая проблема гонки udev (на аддонах неактуальна)
- [[family/how-to/truenas-infrastructure]] — текущий docker-стек TrueNAS