114 KiB
title, status, tags, created, updated, related
| title | status | tags | created | updated | related | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| t610 — развёртывание через HA-аддоны | in-progress |
|
2026-09-13 | 2026-09-14 |
|
t610 — развёртывание через HA-аддоны
Статус (2026-09-14, поздняя сессия): Этап 1 ✅. Этап 2 ✅ ПОЛНОСТЬЮ. Этап 3 ✅ ЗАКРЫТ. z2m = 15 устройств, реестр HA = 332 сущности, hex = 0. Добавлена розетка
boiler_controller_power(0xa4c1381694217e10, TS011F, Котельная) — питание контроллеров котлов; 13 её сущностей переименованы из hex. Автоматизации: 13/16unavailable→ 0 (15on+ 1off). Причины были две, обе устранены: ①device_id(9 шт., 20 вхождений) перемаплены поidentifiers; ② hex-entity_idвautomations.yaml(light.0xa4c13882a4b42db0→light.bed_dimmer;switch.0xa4c13873b5c1575bоказался артефактом regex — в файле уже_l1/_l2). Файл залит, HA перезапущен. HTTP-варнинг устранён: блокhttp:удалён изconfiguration.yaml, настройки перенесены в.storage/http(UI → Network). modbus.host исправлен:127.0.0.1→192.168.2.176(mbusd в отдельном контейнере —127.0.0.1изнутри HA его не видел). modbus-bridge: HTTP 404 → 200. Опрашивал HA по hex-entity_id; правилсяmodbus_ha_bridge.py+data/config.template.tmpl+ обязательный rebuild аддона. ⚠️ ЕДИНСТВЕННЫЙ ОСТАВШИЙСЯ БЛОКЕР (физика, не конфиг): 32 заслонки вентиляцииunavailable. mbusd работает (TCP отвечает), но шина не отвечает — exception 0x0B (GATEWAY TARGET DEVICE FAILED TO RESPOND). Вывод: CH340 #2 воткнут в USB, но линии A/B вентиляционной шины к нему не подключены / шина обесточена. За Alex. ⚠️unknownпосле рестарта HA — ПРОВЕРЕНО ЭКСПЕРИМЕНТОМ 2026-09-14, воспроизводится. Реле/кнопки слетают вunknownпри каждой перезагрузке HA;retain: true+cache_state*в z2m стоят, но не помогают. Практический эффект: первое нажатие кнопки после рестарта не срабатывает. Открытый фикс: убратьnot_from: [unknown]из триггеров (не применён). См. §«ДОБАВЛЕНО В КОНЦЕ СЕССИИ» ③‑бис. ✅ ЗОНЫ ВОССТАНОВЛЕНЫ (18 устройств): при переносеarea_idтеряются так же, какdevice_id(устройства ре-регистрируются) → все 14 zigbee были без зон. Проставлены по эталону с TrueNAS по zigbee-адресу. См. §«ДОБАВЛЕНО В КОНЦЕ СЕССИИ» ①. ✅ office-переключатель управляет светом: устранены hex-entity_idв триггерах автоматизаций (switch.0xa4c13873b5c1575b_l1/l2→ человеческие) + реле выведены изunknownфизическим нажатием. Цепочкаlight → switch_as_x → z2m → релепроверена. См. §«ДОБАВЛЕНО В КОНЦЕ СЕССИИ» ②③. Сервисы: 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 автоматический.
Как прописывать путь в конфиге сервиса:
# 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)
Что сделано:
- Бэкап с TrueNAS → Mac
~/tmp-t610/z2m-backup-20260914/(database.db,configuration.yaml,state.json,coordinator_backup.json). Источник на TrueNAS:/mnt/RED_2TB/docker/zigbee2mqtt/. - Установлен аддон
45df7312_zigbee2mqttv2.14.1-1 (community repo). Манифест содержитuart: true→ доступ ко всем serial,devices:не нужен. - Mosquitto: добавлен логин
zont(тот же пароль, что на TrueNAS) через Supervisor API →POST /addons/core_mosquitto/options→ha apps restart core_mosquitto. Нужен, чтобы HA-интеграция и ZONT продолжили работать по старым креденшелам. - Опции z2m (Supervisor API
POST /addons/45df7312_zigbee2mqtt/options):
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>" }
- База перенесена 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). 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
- Advanced Mode — не понадобился для CLI (всё сделано через
ha apps), понадобится позже для local add-ons - Mosquitto broker (
core_mosquittov7.1.1) — установлен,started, порты 1883 (MQTT) + 1884 (WS) открыты, discovery отправлен в HA автоматически - Node-RED (
a0d7b954_noderedv22.0.6) — установлен,started, порт 1880 открыт, уже подключился к HA (Connected to http://supervisor/core) - Samba share (
core_samba) — установлен, ноstopped: требует задатьpassword(по умолчаниюnull) → логинhomeassistant. Задать в UI: Settings → Apps → Samba → Configuration - File editor (
core_configurator) — установлен,started - Репозиторий Zigbee2MQTT добавлен:
ha store add https://github.com/zigbee2mqtt/hassio-zigbee2mqtt→ появился какHome Assistant App: Zigbee2MQTT(slug45df7312) - ✅ 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-аддон):
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
- Alex втыкает 3 USB в t610 — ВЫПОЛНЕНО 2026-09-14. Порты зафиксированы: CH340 #1 → USB1 порт 3, CH340 #2 → USB1 порт 4, Zigbee → USB3 порт 1. Устройства из портов не вынимать!
- Пути определены (
ls /dev/serial/by-id/,by-path, sysfs) — подробная карта: family/how-to/t610-access §USB - Карта составлена: ttyUSB0 = CH340 #1 (ZONT), ttyUSB1 = CH340 #2 (Vent), ttyACM0 = Zigbee
- СПОСОБ ПРИВЯЗКИ РЕШЁН 2026-09-14 — привязка по
by-path, никаких udev-алиасов. Механизм: флагuart: trueв манифесте аддона даёт доступ ко всем serial включая/dev/serial/by-path/(проверено на живом t610:core_sshuart:true видит все by-path; z2m тоже uart:true).devices:прописывать не надо. Подробности: family/how-to/t610-access §USB. Блокер снят. - ✅ z2m-аддон УСТАНОВЛЕН И РАБОТАЕТ (2026-09-14) — аддон
45df7312_zigbee2mqttv2.14.1-1, serial по by-id, база перенесена 1:1, 16 устройств на месте, переспаривание не потребовалось. Подробности — §«z2m на t610 (ВЫПОЛНЕНО)» выше. - ✅ mbusd local add-on СОБРАН И РАБОТАЕТ (2026-09-14) — slug
local_mbusd, порт 502 открыт (провереноncс Mac), устройство by-path CH340 #2 (порт 4). Подробности — §«Local add-ons mbusd / modbus-bridge» ниже. - ✅ 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 нет.
Причины (по порядку):
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.- 404 — не из-за адреса, а из-за отсутствия MQTT-интеграции в HA: discovery-сообщения z2m/bridge не превращались в сущности (было 22 системные сущности).
- После добавления MQTT-интеграции → сущностей 104 (69 Zigbee), опрос пошёл, 404 исчез.
Рецепт добавления MQTT-интеграции (Config Entry Flow API):
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_controladdc. - ✅ Порт 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), экспортит envHA_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.yamlcbuild_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. Фикс: в DockerfileENTRYPOINT []+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_statelovelace.home_plan(+.bak,.bak2),lovelace_dashboards,lovelace_resourcesperson,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на момент залива, позже исправлено на192.168.2.176; убрана строкаlocaltuya: debug; блокhttp:удалён 2026-09-14 — настройки уехали в.storage/http),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_entitieswww/: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, шаги 1–7):
- ✅ Бэкап
/configt610 →~/tmp-t610/backups/config-t610-20260914-115034.tar.gz - ✅ Бэкап TrueNAS →
~/tmp-t610/backups/truenas-ha-backup-20260913-215043.tar.gz(auth/http/auth_providerне читаются — root-only, и не нужны) - ✅
ha core stop(проверено: веб отдаёт000= лежит) - ✅ Залиты реестры
.storage(12 файлов, выборочно по списку) - ✅ Залиты конфиги +
www/(3 файла) - ✅
ha core check— ошибок нет;ha core start→ веб200 - ✅ Проверка: 410 сущностей в реестре, 11 зон, MQTT-интеграция на месте (
core.config_entriesне тронут) - ✅ ВЫПОЛНЕНО 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` |
| 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).
Следствия (отменяют прежнее опасение «всё пересоздастся»):
- ✅ Смена
friendly_nameв z2m НЕ меняетunique_id→ HA узнаёт сущность поunique_id, обновляет её на месте и сохраняет существующийentity_idиз реестра. Дубли не создаются. - ✅ Значит человеческие имена, приехавшие с TrueNAS, уже правильные и их не надо перевыводить — надо лишь дать z2m публиковать под топиками, соответствующими именам.
- ⚠️ Прежняя запись в доке «смена
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 '"'. Обход: собирать заголовок в файл без литерала рядом с переменной:
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: снести.
# бэкап базы перед удалением
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_idHA)» из §«КРИТИЧЕСКОЕ ОТКРЫТИЕ» выше. Расхождения (эталон — реальные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):
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 — их надо искать в трёх местах:
- z2m
/config/zigbee2mqtt/configuration.yaml→ секцияdevices:→friendly_name. - HA
core.device_registry→data.devices[].name(иname_by_user), связь черезidentifiers: [["mqtt","zigbee2mqtt_0x..."]]. - Дашборд
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. Автоматизации остались со старыми TrueNAS-овскими.
⚠️ Главный вывод: device_id НЕ переносятся между инстансами HA. entity_id и unique_id — переносятся; device_id — НЕТ. Автоматизации/скрипты, ссылающиеся на device_id (а это все device-trigger'ы в UI), ломаются.
✅ Полный маппинг — 9/9, собран 2026-09-14 (метод: по identifiers)
Метод (надёжный, воспроизводимый): взять TrueNAS-реестр core.device_registry (оттуда, где device_id из автоматизаций ЕСТЬ) → для каждого устройства вытащить identifiers (для zigbee = [[\"mqtt\",\"zigbee2mqtt_<ieee>\"]]) → найти на t610 устройство с тем же identifiers → его id и есть актуальный device_id.
| # | Устройство | device_id TrueNAS (в автоматизациях) |
device_id t610 (актуальный) |
Замен |
|---|---|---|---|---|
| 1 | night_light_shower_2 (84fd27fffed9e137) |
0c7a0eb6d60e852b447266da69a7785e |
4d6e55505ff7dbad13d2674cdcb18d5a |
2 |
| 2 | recirculation_pump (f8da8bc478) |
234686e6c83f7d19c9e10b2f0d1fcc59 |
16d2c6f64ec399e5261c89b35c1e75c6 |
2 |
| 3 | bed_dimmer (82a4b42db0) |
2862be34f5eaaa39b9d51084a1f921ee |
098a641cb1d30f08f1ae293e00d9885b |
1 |
| 4 | office_temperature_sensor (62d39377e6) |
52266a1b4a9d301f0da0dfa6f97c4ea2 |
bcf47eeae909877978bdaf6c705210f8 |
1 |
| 5 | wireless_light_switch_bed (b0f9e674a5) |
757e0e9b1e5771e0c700a9df852b0549 |
5cd5d9d2d289b5e470bbeaac0eb7905c |
3 |
| 6 | light_sensor_stairs (6d40ddb67b) |
7f102ad2e78960fff6ebc5f01c0bba93 |
1ea8bbc2612dde303e4279bc5fbad57a |
3 |
| 7 | shower_2_presence_sensor (c4a94a6a31) |
7f74e7077d7fa23e405f2c5e25f6fa17 |
4095e7c3b47b9dc9640cfb8c3aeff022 |
4 |
| 8 | light_stairs (6d0839706a) |
9d3f31b1b49c95433428afbb113d929b |
028b7d9f489c87bdc9e563473a1d61e8 |
2 |
| 9 | boiler_water_leak (3d5fcaa063) |
c42ce32c73731941884bcbf0c2b2d077 |
b9d384a51b780a7924ed9504eddec12e |
2 |
Итого: 9 device_id из автоматизаций (все 9 — zigbee), 20 вхождений. ⚠️ Прежняя оценка «6 UUID» была неполной — реальных уникальных device_id 9. В scripts.yaml device-ссылок 0 (проверено).
Как получить актуальные device_id (bash+jq на t610):
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.
⚠️ Получение TrueNAS-реестра: /mnt/RED_2TB/docker/ha/.storage/core.device_registry читается без sudo (права 644, owner root) — scp работает напрямую. sudo cat падает (a terminal is required to read the password) — sudo не нужен.
🔴 ВТОРАЯ ПОЛОМКА ТОГО ЖЕ КЛАССА: hex entity_id в automations.yaml (2 шт.)
⚠️ Тот же класс проблемы, что и device_id, её легко пропустить. При переименовании реестра (hex → человеческие entity_id) ссылки в automations.yaml не обновлялись → в автоматизациях остались старые hex-entity_id:
light.0xa4c13882a4b42db0→ должно бытьlight.bed_dimmer(в реестре уже человеческое).switch.0xa4c13873b5c1575b→ ⚠️ неоднозначно: у устройства теперь два каналаswitch.office_table_light_switch_l1/_l2(z2m разбил на каналы), а в автоматизации одна старая сущность. Требует разбора, какой канал использовался на TrueNAS (см. §«Осталось»).
Мораль: при переносе HA надо чистить и device_id, и hex-entity_id одновременно — иначе автоматизация «чинится» наполовину.
✅ План починки — ВЫПОЛНЕН 2026-09-14 (автоматизации 0 unavailable)
Файл: ~/tmp-t610/etap3-fix/automations.fixed.yaml — 20 замен device_id, 0 старых осталось, все 20 новых проверены по реестру t610. Бэкап на t610: /config/automations.yaml.bak-devid-20260914-124733.
Уточнение про switch.0xa4c13873b5c1575b (закрыт вопрос l1/l2): это был артефакт regex, а не реальная ссылка. В automations.yaml уже стояли правильные switch.0xa4c13873b5c1575b_l1 (авт. office_pass_switch_table) и switch.0xa4c13873b5c1575b_l2 (авт. office_pass_switch_main). Проверка grep -E 'switch\.0xa4c13873b5c1575b(?!_l)' → 0 совпадений. Чинить нечего.
Реально исправленный hex-entity_id — только один: light.0xa4c13882a4b42db0 → light.bed_dimmer (2 вхождения, автоматизация «Dimmer bed cycle»: и в state_attr(), и в target.entity_id).
Порядок (выполнен): ha core stop-эквивалент через ha core restart → залив automations.yaml → проверка API.
Результат (факт, 2026-09-14): automation.* — 16 сущностей: 15 on + 1 off (0 unavailable). Единственная off — automation.ventilation_automation_on: это нормальное состояние (вентиляция управляется через modbus-шину, а не по расписанию), идентично TrueNAS.
Важный побочный вывод: 12 entity_id внутри device-действий формата entity_id: <32-hex> — это реестровые id сущностей, а НЕ строки domain.name. Они совпали и менять их не пришлось, потому что при переименовании реестра через jq мы меняли только поле entity_id, а id оставался нетронутым (перенесён с TrueNAS). Проверено: 12/12 найдены в core.entity_registry.
🔴 ТРЕТЬЯ ПОЛОМКА ТОГО ЖЕ КЛАССА: hex-entity_id зашиты в код local add-on (modbus-bridge)
Симптом: modbus-bridge бесконечно логирует HA poll: sensor.0xa4c13862d39377e6_temperature HTTP 404.
Причина: hex-entity_id (sensor.0xa4c13862d39377e6_temperature, switch.0xa4c138f8da8bc478) зашиты в код аддона, а не в опции:
/addons/modbus-bridge/modbus_ha_bridge.py(строки 74, 82, 89 — встроенный дефолтDEFAULT_CONFIG)/addons/modbus-bridge/data/config.template.tmpl(строки 112, 125)
Правильные значения: sensor.office_temperature_sensor_temperature, switch.recirculation_pump.
⚠️ ГЛАВНЫЙ ПИТФОЛЛ: правки в data/*.tmpl НЕ применяются без rebuild. run.sh генерирует runtime /app/config.yml из /app/config.template.yml — копии внутри образа (Dockerfile: COPY data/config.template.tmpl /app/config.template.yml). Поэтому после правки исходников обязателен ha addons rebuild local_modbus-bridge (без него работает старая версия из образа — я на этом попался).
Проверка после rebuild: в логе HA poll -> sensor.office_temperature_sensor_temperature = 23.96 (200, без 404).
🔧 ПИТФОЛЛ: http: в configuration.yaml игнорируется после миграции
Симптом (варнинг в HA): YAML configuration is ignored after migration / The HTTP configuration in configuration.yaml has already been migrated and is now being ignored... This stops working in version 2027.2.0. → надо удалить блок http: и управлять через Settings → System → Network.
Что было: в configuration.yaml блок
http:
use_x_forwarded_for: true
trusted_proxies:
- 172.16.0.0/12
Но в .storage/http этих ключей НЕ было → простое удаление блока потеряло бы доверие к Caddy-прокси (HA отдаёт 400 на запросы через прокси — критично для Этапа 4).
Правильный фикс (выполнен):
- Бэкап
configuration.yaml→.bak-http-<ts>; бэкап.storage/http→.bak-<ts>. - Добавить в
.storage/http→data.stable(jq, локально):use_x_forwarded_for: true,trusted_proxies: ["172.16.0.0/12"]. Файл положить при остановленном HA (ha core stop), иначе HA перезапишет. - Удалить блок
http:изconfiguration.yaml, оставить комментарий-пояснение. ha core start→ HA сам выставляетdata.yaml_migration_done: true.
Проверка: jq '.data.stable | {server_port, use_x_forwarded_for, trusted_proxies}' /config/.storage/http → порт 80, настройки на месте; curl -o /dev/null -w '%{http_code}' http://192.168.2.176/ → 200.
📌 Общий принцип (для любых настроек, мигрированных в UI): прежде чем удалять YAML-блок, сверить, что все его ключи реально есть в
.storage/<domain>. Иначе настройка молча теряется.
🔴 ПИТФОЛЛ (КРИТИЧНЫЙ): modbus.host не может быть 127.0.0.1 — mbusd в отдельном контейнере
Симптом: 32 switch.*_damper (заслонки вентиляции) unavailable, 0 живых modbus-сенсоров, хотя local_mbusd = started и порт 502 на хосте открыт.
Причина: в configuration.yaml было modbus.host: 127.0.0.1. HA Core сидит в своём контейнере (172.30.32.1), а local_mbusd — в другом контейнере, пробросивший порт на хост. Для HA 127.0.0.1 = он сам → таймаут.
Фикс: host: 192.168.2.176 (IP хоста t610, порт 502 проброшен Docker'ом). Проверка: nc -z 192.168.2.176 502 → OK.
⚠️ Не путать: в логе mbusd
conn_open(): accepting connection from 172.30.32.1+ мгновенныйconn_close()= признак неверного адреса. Успешное подключение выглядит какconn_open(): accepting connection from 192.168.2.176и БЕЗ последующегоconn_close(HA держит коннект).
📡 ПИТФОЛЛ: диагностика modbus-шины через прямой TCP-запрос
Проверка «жива ли шина», не залезая в HA (скрипт ~/tmp-t610/etap3-fix/mbtest.sh):
# Modbus TCP: FC=03, UnitID=0b(11), Start=0000, Qty=0001
printf '\x00\x01\x00\x00\x00\x06\x0b\x03\x00\x00\x00\x01' > /tmp/mbreq.bin
nc -w 5 192.168.2.176 502 < /tmp/mbreq.bin | xxd
Расшифровка ответа:
| Ответ | Значение |
|---|---|
... 01 03 02 XXXX |
✅ нормальный ответ (FC=03, 2 байта данных) |
... 01 83 04 |
❌ SLAVE DEVICE FAILURE — устройство есть, но не ответило |
... 0b 83 0b |
❌ GATEWAY TARGET DEVICE FAILED TO RESPOND — mbusd передал, шина молчит (нет устройства/нет провода) |
Exception-код = байт FC с флагом
0x80; второй байт — код ошибки. Для заслонок вентиляции slave = 11 (configuration.yaml, секцияmodbus).
⏸️ ИТОГ: заслонки вентиляции — АППАРАТНЫЙ блокер (за Alex)
mbusd-стек исправен полностью: TCP отвечает, serial открыт (/dev/serial/by-path/pci-0000:00:12.0-usb-0:4:1.0-port0), HA-коннект с 192.168.2.176 держится. Но на запрос к slave 11 шина отдаёт exception 0x0B — устройство не отвечает.
Диагноз: CH340 #2 воткнут в USB-порт t610, но линии A/B вентиляционной шины к нему не подключены (или шина обесточена).
Это ровно тот блокер, о котором Alex предупреждал в начале сессии («проверь USB основной шины, дальше подключу ZONT»). Никакие конфиги тут не помогут — нужна физика. Заслонки оживут сами, как только шина будет подключена. Адреса записаны:
/dev/serial/by-path/pci-0000:00:12.0-usb-0:4:1.0-port0 (ttyUSB1, CH340 #2) = ВЕНТИЛЯЦИЯ (slave 11)
/dev/serial/by-path/pci-0000:00:12.0-usb-0:3:1.0-port0 (ttyUSB0, CH340 #1) = ZONT
⚠️ Мораль для будущих переносов HA: либо переносить core.config_entries целиком вместе с реестрами (тогда device_id согласуются), либо после переноса обязательно перемапить device_id в automations.yaml/scripts.yaml по identifiers, и заодно проверить hex-ссылки entity_id. Мы выбрали не переносить 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).
Порядок (выполнен):
- ✅ Заменить
devices:в/config/zigbee2mqtt/configuration.yaml(friendly_name = человеческие) →ha apps restart 45df7312_zigbee2mqtt. Проверка: z2m публикует вzigbee2mqtt/<human_name>,bridge/devicesпоказывает человеческие имена. - ✅
ha core stop→ переименоватьentity_idвcore.entity_registry(regex<domain>.<hex>[_suffix]→<domain>.<friendly>[_suffix]) →ha core start.
Команда переименования (jq, т.к. python3 в аддоне НЕТ):
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 всё оживёт.
🔌 Новое устройство: boiler_controller_power — питание контроллеров котлов (2026-09-14)
Задача Alex: добавить Zigbee-розетку в котельную как питание для контроллеров котлов.
| Параметр | Значение |
|---|---|
friendly_name |
boiler_controller_power |
| IEEE | 0xa4c1381694217e10 |
| Модель | TS011F, manufName = _TZ3000_gjnozsaz (Tuya Smart Plug с измерениями P/V/I/E) |
| Тип | Router, Mains (single phase) — усиливает mesh в котельной |
| Зона | Котельная (kotelnaia) |
| device_id | dab3c111a46c9c441e2c90fdfe35a702 |
| Сущности | 13, все с человеческими entity_id |
| Состояние | switch.boiler_controller_power = off, voltage = 218 |
Процедура (выполнена, рабочий рецепт):
- permit_join через MQTT:
mosquitto_pub -t zigbee2mqtt/bridge/request/permit_join -m '{"value":true,"time":250}'. ⚠️ Питфолл: лимит окна — 254 секунды."time":300→error: Cannot permit join for more than 254 seconds. Ставить ≤250. - Устройство присоединилось само → появилось в
bridge/devicesпод hex-именем0xa4c1381694217e10. - Переименование в z2m (до того как HA создаст сущности!):
mosquitto_pub -t zigbee2mqtt/bridge/request/device/rename -m '{"from":"0xa4c1381694217e10","to":"boiler_controller_power"}' - ⚠️ HA всё равно создал сущности по hex-имени (успел между join и rename) → понадобился второй фикс: переименование
entity_idвcore.entity_registry(HA stop → jq → HA start). - Зона ставится в
core.device_registry(area_id), НЕ в entity_registry. Устройство найдено поidentifiers=[["mqtt","zigbee2mqtt_0xa4c1381694217e10"]]→area_id = "kotelnaia".
Явный маппинг (13 hex → человеческие):
# jq-фильтр: replace по каждому суффиксу
switch.0xa4c1381694217e10 -> switch.boiler_controller_power
switch.…_child_lock -> switch.boiler_controller_power_child_lock
number.…_countdown -> number.boiler_controller_power_countdown
select.…_power_outage_memory -> select.boiler_controller_power_power_outage_memory
select.…_switch_type_button -> select.boiler_controller_power_switch_type_button
select.…_indicator_mode -> select.boiler_controller_power_indicator_mode
sensor.…_power / _current / _voltage / _energy / _linkquality
button.…_identify -> button.boiler_controller_power_identify
update.0xa4c1381694217e10 -> update.boiler_controller_power
Скрипты: ~/tmp-t610/etap3-fix/{permit_join.sh,z2m_devices.sh,rename_plug.sh,rename_plug_ids.jq,set_area.jq,check_plug.sh}.
⚠️ ВЫВОД (обобщение питфолла): bridge/request/device/rename в z2m не спасает — HA успевает создать сущности под hex-именем. Порядок «сначала rename в z2m, потом join» невозможен → после каждого нового устройства всегда проверять core.entity_registry на hex и переименовывать через jq.
📍 СОСТОЯНИЕ НА КОНЕЦ СЕССИИ 2026-09-14 (поздняя) — для следующей сессии
Факты (проверено API): HA http://192.168.2.176 → 200; z2m started, 15 устройств; реестр 332 сущности, hex = 0; light.* (5 шт.) работают; MQTT-интеграция на месте; switch_as_x (4) восстановлены; автоматизации 16 шт.: 15 on + 1 off (0 unavailable); HTTP-варнинг устранён; modbus.host = 192.168.2.176; modbus-bridge опрос работает (без 404).
Счётчики живого API: 253 сущности; unavailable 44 (из них 32 — заслонки вентиляции, аппаратный блокер); unknown 69.
Живые zigbee-датчики (проверено): sensor.office_temperature_sensor_temperature = 23.96, sensor.recirculation_pump_voltage = 221, sensor.light_sensor_stairs_illuminance = 556, sensor.heating_cable_plug_voltage = 222, sensor.boiler_controller_power_voltage = 218.
✅ Добавлено в конце сессии: Zigbee-розетка boiler_controller_power (0xa4c1381694217e10, TS011F, зона Котельная) — питание контроллеров котлов. Итого 15 устройств в z2m, 332 сущности в реестре. См. §«Новое устройство: boiler_controller_power».
✅ Этап 3 ЗАКРЫТ. Всё, что осталось — вне конфигов:
⏸️ 1. ГЛАВНОЕ: заслонки вентиляции (32 switch.*_damper unavailable) — АППАРАТНЫЙ блокер, за Alex. Подключить линии A/B вентиляционной шины к CH340 #2 (by-path ...0:4:1.0-port0, slave 11) или проверить питание шины. После подключения заслонки оживут сами — конфиг уже верный. См. §«ИТОГ: заслонки вентиляции».
Далее (не блокеры):
sensor.*_summary— добавить|default(0)в template-сенсорыconfiguration.yaml(косметика; ошибкиround got invalid input 'unknown'дляkids_*/bedroom_*— уйдут сами, когда sniffer вентиляции пришлёт данные).switch.sauna=unknown— розетка физически отключена (lastSeen8+ ч), не баг.- Камера (§8 родительского плана).
- Этап 4: Caddy upstream → t610, GPON-редирект → t610, отключить TrueNAS.
Ключевые пути/скрипты сессии: ~/tmp-t610/ — stage3/out/, backups/, ha_token.txt. Этап 3 правки: ~/tmp-t610/etap3-fix/ — automations.fixed.yaml, devid_mapping.json, truenas.device_registry, core.device_registry, core.entity_registry, scripts.yaml, http.new.json, mb_bridge.py, config.template.tmpl, mbtest.sh, check_dampers2.sh, final_check.sh, restart_ha.sh, run_check.sh, token.env, q_dampers.jq, q_sensors.jq. На t610: /config/automations.yaml.bak-devid-*, /config/configuration.yaml.bak-http-*, /config/.storage/http.bak-*, /addons/modbus-bridge/*.bak-hex-*.
⚠️ Питфолл сессии (важный для будущих сессий): Alex устал апрувать запуск python-скриптов (execute_code и /usr/bin/python3 -c) — ТРЕБУЕТ bash+jq/curl. Пользоваться shell-скриптами, python только когда без него никак (и предупреждать).
🧩 ДОБАВЛЕНО В КОНЦЕ СЕССИИ 2026-09-14 — ЗОНЫ и office-переключатель
Три отдельных дефекта, найденных Alex'ом после «всё готово». Все устранены.
① Зоны (area_id) потерялись при ре-регистрации устройств — ГЛАВНЫЙ питфолл
Симптом (Alex): «на всех устройствах зоны верно поставлены? Чето в ui кажется что не все девайсы имеют зону».
Факт: 14 из 14 zigbee-устройств были БЕЗ зоны (area_id = null). Зона была только у только что добавленной boiler_controller_power (её я прописал руками).
Причина — ТРЕТИЙ слой той же болезни, что device_id: при переносе .storage я скопировал core.area_registry (11 зон созданы), но area_id живёт в core.device_registry. Zigbee-устройства при подключении к локальной MQTT-интеграции зарегистрировались заново → новые записи устройств пришли без area_id. Зоны (как сущности реестра зон) остались, а привязка устройство→зона — нет.
🔑 Обобщение (важно для будущих миграций): при переносе HA между инстансами теряются все инстанс-локальные привязки, а не только
device_id:
device_id— новый у каждого устройства;area_id(зона устройства) — теряется, если устройство ре-регистрируется;entity_id(вentity_registry) — сохраняется поunique_id, но ссылки на него в автоматизациях/дашбордах — нет. Переносится только то, что задано явнымиidв реестрах (area_registry,floor_registry).
Лечение (выполнено): эталон зон взят с TrueNAS (/mnt/RED_2TB/docker/ha/.storage/core.device_registry) — там 17 устройств с зонами. Маппинг построен по zigbee-адресу (identifiers[0][1] = zigbee2mqtt_<ieee>), проставлен через jq при остановленном HA.
Итоговые зоны (18 устройств):
| Зона | Устройства |
|---|---|
Котельная kotelnaia |
boiler_controller_power, boiler_water_leak, heating_cable_plug, recirculation_pump |
Кабинет kabinet |
smart_light_office, office_table_light_switch, office_temperature_sensor |
Спальня bedroom |
bed_dimmer, wireless_light_switch_bed, Bedroom Sensor (modbus) |
Душевая dushevaia |
night_light_shower_2, shower_2_presence_sensor |
Лестница lestnitsa |
light_stairs, light_sensor_stairs |
Кухня kitchen |
kitchen_hood |
Туалет tualet |
sauna |
Гостиная living_room |
Dining Sensor (modbus) |
Детская detskaia |
Kids Sensor (modbus) |
ℹ️
office_temperature_sensorна TrueNAS зоны не имел → поставленkabinetпо расположению.heating_cable_plugзаменил Wi-Fi-розеткуlocal_bf8821e863abe84816qmbo(былаkotelnaia) → унаследовал зону.
Скрипт: ~/tmp-t610/etap3-fix/set_all_areas.jq (jq-фильтр map по identifiers[0][1]). Применение: jq -f set_all_areas.jq core.device_registry > … → HA stop → scp → HA start.
② Office table switch не управлял светом — ДВЕ причины
Симптом (Alex): «office table switch не управляет светом в кабинете».
Причина A — hex-entity_id в ТРИГГЕРАХ автоматизаций. Триггеры office_pass_switch_table/_main ссылались на hex:
entity_id: switch.0xa4c13873b5c1575b_l1 # ← в реестре уже switch.office_table_light_switch_l1
При переименовании реестра я поправил entity_id в actions и device-триггерах (platform: state с device_id), но НЕ в обычных platform: state-триггерах. HA загрузил автоматизацию, но подписался на несуществующую сущность → кнопка не срабатывала.
🔑 Правило проверки: после переименования
entity_idгрепать весьautomations.yaml+scripts.yamlна[a-z_]+\.0x[0-9a-f]{16}— не толькоdevice_id, не только actions. Найдено ровно 2 (строки 46, 60).
Причина B — unknown у реле из-за пассивной публикации z2m (см. ③). Триггер имел not_from: [unavailable, unknown] → пока состояние unknown, он не сработает по определению.
Проверка на живом (рабочий рецепт):
# слушаем топики, Alex физически нажимает кнопки
ssh root@192.168.2.176 'timeout 60 mosquitto_sub -h core-mosquitto -u zont -P "…" \
-t "zigbee2mqtt/office_table_light_switch/#" -t "zigbee2mqtt/smart_light_office/#" -v'
# → state_l1/state_l2 (office_table_light_switch идут как state_l1/l2)
# → state_left/state_right (smart_light_office)
# управление светом через HA (проверка цепочки light → switch_as_x → z2m → реле)
curl -s -X POST -K curl.auth -H "Content-Type: application/json" \
http://192.168.2.176/api/services/light/turn_on -d '{"entity_id":"light.smart_light_office_left"}'
Результат: light.smart_light_office_left off→on→off, switch.smart_light_office_left off→on→off — цепочка работает целиком.
ℹ️ Разные устройства публикуют разные имена полей:
office_table_light_switch(TS0002) →state_l1/state_l2;smart_light_office(TS0012) →state_left/state_right. Discovery z2m генерирует корректныйvalue_templateпод каждое — трогать не нужно.
③ z2m НЕ публикует состояние пассивно → реле «залипают» в unknown
Ключевое открытие сессии. После перезапуска HA все switch.* (реле) были unknown, при этом устройства живы (lastSeen в секундах).
Причина: z2m публикует payload только при получении данных от устройства. Питаемые реле не отчитываются сами по себе — ждут события (нажатия) или запроса.
Лечение (практическое): после перезапуска физически нажать кнопки на реле — сеть «прогревается», все unknown уходят. Проверено: switch.office_table_light_switch_l1/l2 стали on, switch.smart_light_office_left/right — off.
③‑бис ✅ ПРОВЕРЕНО на перезагрузке (2026-09-14): unknown ВОЗВРАЩАЕТСЯ, retain не спасает
Проведён эксперимент (не гипотеза): зафиксировано состояние → homeassistant.restart через API → состояние снято снова.
| Сущность | До рестарта | После рестарта |
|---|---|---|
switch.office_table_light_switch_l1/l2 |
on |
unknown |
switch.smart_light_office_left/right |
off |
unknown |
switch.heating_cable_plug |
off |
unknown |
switch.boiler_controller_power |
off |
unknown |
switch.kitchen_hood_l1/l2/l3, switch.light_stairs_l1/l2 |
unknown |
unknown |
Вывод: всё, что было on/off, после перезагрузки слетает в unknown. Поведение воспроизводимо.
Что НЕ помогло (проверено на живом): в z2m стоят все три штатных механизма —
retain: true (подтверждено дважды: bridge/request/options → {"data":{"restart_required":false},"status":"ok"}),
cache_state: true, cache_state_persistent: true, cache_state_send_on_startup: true —
но retained-сообщения на топиках устройств фактически не появляются, состояния при старте не переопубликовываются.
Контроль: zigbee2mqtt/bridge/state retained есть (прилетает мгновенно при свежей подписке) → брокер retained умеет, дело не в нём.
🔬 Питфолл диагностики retained: флаг
-R(retained-only) уmosquitto_subв аддоне работает НЕ как ожидается — с ним вывод пустой даже там, где retained есть. Надёжный способ: подписаться и смотреть с timestamp, что прилетает СРАЗУ при подписке (retained приходит мгновенно, живой трафик — только по событию):timeout 4 mosquitto_sub -h 192.168.2.176 -u zont -P "$P" -t 'zigbee2mqtt/bridge/state' -v \ | while IFS= read -r l; do echo "$(date +%H:%M:%S.%N | cut -c1-12) | $l"; done
Практическое следствие: триггер platform: state с not_from: [unavailable, unknown] не сработает на первое нажатие после рестарта (unknown блокирует) — нужно второе.
Фикс (точечный, не зависит от z2m): убрать not_from: [unknown] из триггеров кнопок в automations.yaml.
⚠️ На момент записи фикс НЕ применён — ожидает решения Alex (альтернатива: копать, почему cache_state_send_on_startup не отрабатывает — без гарантии).
ℹ️ Датчики (t°/освещённость/радар) выходят из
unknownсами за секунды-минуты — страдают только реле и кнопки. ℹ️ Проверка живости узла без нажатия —get-запрос:mosquitto_pub … -t 'zigbee2mqtt/<name>/get' -m '{"state_l1":""}'→ устройство отвечает текущим состоянием.
🔑 Диагностический приём: чтобы понять, жив ли узел, смотреть
lastSeenвdatabase.db(/config/zigbee2mqtt/database.db, JSON-lines, читать построчно — это НЕ единый JSON!):while IFS= read -r line; do echo "$line" | jq -r 'select(.type=="EndDevice" or .type=="Router") | "\(.ieeeAddr)\t\(.lastSeen // "нет")"' done < db.json
lastSeenобновляется по любым пакетам → зелёный флаг живости, даже еслиstateв HA =unknown.
Итог по всем трём: light.smart_light_office_left/right, switch.*_office_table_light_switch_l1/l2, switch.smart_light_office_left/right — все корректны, цепочка управления проверена. Зоны проставлены (18 устройств). Розетка котельной видна (её не было в UI именно из-за area_id = null).
ℹ️ После правок реестров обновить страницу в браузере (Ctrl+Shift+R) — UI держит кэш и может не показать новые зоны сразу.
Этап 4 — проверка и отключение TrueNAS
- Чек-лист из родительского плана §6
- Caddy upstream → t610; GPON-редирект → t610
- Остановить + отключить автозапуск на 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 управляет зависимостями и пробросом устройств. Это была самая опасная часть старого плана.
Открытые вопросы
- ✅ РЕШЕНО 2026-09-14 — способ привязки CH340 в аддонах: привязка по
/dev/serial/by-path/...; механизм Supervisor — флагuart: trueв манифесте аддона (доступ ко всем serial автоматически,devices:не нужен). Проверено на живом t610. Детали: family/how-to/t610-access §USB. - ✅ РЕШЕНО 2026-09-14 — куда переносить данные z2m:
data_pathаддона =/config/zigbee2mqtt(внутри HA-конфига), НЕ/addon_configs/. Туда залитыdatabase.dbиconfiguration.yaml. - ✅ Проверено 2026-09-14 — совместимость community-repo z2m с HA OS 18.2 / Core 2026.9.2: работает (v2.14.1-1, координатор EmberZNet 7.4.5, 17 устройств).
- ✅ РЕШЕНО 2026-09-14 —
uart: trueдля local add-ons: подтверждено на mbusd/modbus-bridge — в их манифестахuart: true, by-path виден, устройства открываются (mbusd порт 502, bridge sniffer на шине ZONT). Тот же механизм, что у z2m и core_ssh. - ✅ РЕШЕНО 2026-09-14 — modbus-bridge
ha_token/mqtt_password: вписаны, MQTT + HA-опрос работают. Ключевой момент —ha.url=http://192.168.2.176:80(неsupervisor/core), + в HA добавлена MQTT-интеграция. Этап 2 закрыт полностью. - ✅ РЕШЕНО 2026-09-14 —
custom_componentsне переносим. HACS (репо пусто) иtuya_local(нет config entry) не нужны;localtuyaобслуживал единственную Tuya-розетку, которую Alex заменил на Zigbee → тоже снят. - ✅ РЕШЕНО 2026-09-14 — история БД не переносится (новая с нуля) и реестры
.storage— замена (вариант B). - ✅ ВЫПОЛНЕНО 2026-09-14 — Zigbee-розетка NEO NAS-WR01B (
0xa4c138eb6fbe9d19) добавлена через permit_join (MQTT). z2m = 16 устройств (после удаления мёртвого). - ✅ ВЫПОЛНЕНО 2026-09-14 — Этап 3 (перенос конфига): бэкапы сделаны, HA остановлен, залиты 12 файлов
.storage+ 5 конфигов +www/, HA запущен (248 сущностей, 11 зон, MQTT-интеграция цела, ошибок нет).modbus.host→127.0.0.1,localtuya: debugубран, дашборд поправлен. - ✅ РЕШЕНО 2026-09-14 —
Mini Smart Switch 1удалён из z2m (force: true). Мёртвое:lastSeen2026-01-26,unavailable, нет зоны, нигде не используется. - ✅ УТОЧНЕНО 2026-09-14 — механизм связи сущностей: HA связывает по
unique_id, НЕ поentity_id. Сменаfriendly_nameв z2m сохраняет человеческиеentity_id. Прежнее опасение «всё пересоздастся» снято. - ⏳ ОСТАЛОСЬ (последний шаг Этапа 3): прописать
friendly_nameв z2m по таблице из §«КРИТИЧЕСКОЕ ОТКРЫТИЕ» (16 устройств), перезапустить z2m, убедиться, чтоunknown-сущности ожили (ожидаемо ~133 → минимум). Затем чистка hex-остатков (58 шт.) в HA. - ✅ ВЫПОЛНЕНО 2026-09-14 (поздняя сессия) — автоматизации починены:
device_idперемаплены (9/9, 20 вхождений), hex-entity_idlight.0xa4c13882a4b42db0→light.bed_dimmer. Результат: 16 автоматизаций, 15on+ 1off, 0unavailable. Этап 3 закрыт. - ✅ УСТРАНЕНО 2026-09-14 — HTTP-варнинг: блок
http:удалён изconfiguration.yaml,trusted_proxies/use_x_forwarded_forперенесены в.storage/http. - ✅ ИСПРАВЛЕНО 2026-09-14 — modbus.host:
127.0.0.1→192.168.2.176. - ✅ ИСПРАВЛЕНО 2026-09-14 — modbus-bridge 404: hex-entity_id в коде аддона → человеческие +
ha addons rebuild. - ✅ ВЫПОЛНЕНО 2026-09-14 (поздняя сессия) — Zigbee-розетка
boiler_controller_powerдобавлена (0xa4c1381694217e10, TS011F, зона Котельная) как питание контроллеров котлов; 13 сущностей переименованы из hex. Итого z2m = 15 устройств, реестр = 332 сущности, hex = 0. - ⏸️ ГЛАВНЫЙ ОСТАВШИЙСЯ БЛОКЕР (аппаратный, за Alex): 32 заслонки вентиляции
unavailable— шина не отвечает (exception 0x0B). Подключить линии A/B к CH340 #2 (by-path ...0:4:1.0-port0, slave 11). Конфиг верный, оживут сами. - Камера (§8 родительского плана) — не аддон, разбираться отдельно
- ✅ ВЫПОЛНЕНО 2026-09-14 (конец сессии) — ЗОНЫ восстановлены у 18 устройств.
area_idтеряется при ре-регистрации устройств (какdevice_id) — все 14 zigbee были без зон. Проставлены по эталону с TrueNAS поidentifiers[0][1](zigbee2mqtt_<ieee>). Скрипт:~/tmp-t610/etap3-fix/set_all_areas.jq. - ✅ ИСПРАВЛЕНО 2026-09-14 (конец сессии) — office-переключатель: hex-
entity_idв триггерах автоматизаций (switch.0xa4c13873b5c1575b_l1/l2→switch.office_table_light_switch_l1/l2); реле выведены изunknownнажатием кнопок. Цепочка управления светом проверена на живом. - ✅ УСТАНОВЛЕНО 2026-09-14 (конец сессии) — z2m не публикует состояние пассивно: реле «залипают» в
unknownдо первого события. Живость проверять поlastSeenвdatabase.db(JSON-lines, читать построчно). - ✅ ПРОВЕРЕНО ЭКСПЕРИМЕНТОМ 2026-09-14 —
unknownвозвращается после рестарта HA. Зафиксировано состояние → рестарт → состояние снято: всёon/offслетело вunknown.retain: true+cache_state*в z2m стоят, но retained на топиках устройств фактически не публикуется (контроль:bridge/stateretained есть). Питфолл:mosquitto_sub -Rв аддоне врёт. См. §«ДОБАВЛЕНО В КОНЦЕ СЕССИИ» ③‑бис. - ⚠️ ОТКРЫТО (на решение Alex): убрать
not_from: [unknown]из триггеров кнопок вautomations.yaml— иначе первое нажатие после рестарта HA не срабатывает (unknownблокирует триггер). Альтернатива — копатьcache_state_send_on_startup. Фикс не применён. - ⚠️ Незакреплённое:
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