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

98 KiB
Raw Blame History

title, status, tags, created, updated, related
title status tags created updated related
t610 — развёртывание через HA-аддоны in-progress
family
plan
homeautomation
t610
haos
addons
2026-09-13 2026-09-14
family/plans/home-automation-migration-t610
family/how-to/home-automation

t610 — развёртывание через HA-аддоны

Статус (2026-09-14, поздняя сессия): Этап 1 . Этап 2 ПОЛНОСТЬЮ. Этап 3 ЗАКРЫТ. z2m = 15 устройств, реестр HA = 332 сущности, hex = 0. Добавлена розетка boiler_controller_power (0xa4c1381694217e10, TS011F, Котельная) — питание контроллеров котлов; 13 её сущностей переименованы из hex. Автоматизации: 13/16 unavailable → 0 (15 on + 1 off). Причины были две, обе устранены: ① device_id (9 шт., 20 вхождений) перемаплены по identifiers; ② hex-entity_id в automations.yaml (light.0xa4c13882a4b42db0light.bed_dimmer; switch.0xa4c13873b5c1575b оказался артефактом regex — в файле уже _l1/_l2). Файл залит, HA перезапущен. HTTP-варнинг устранён: блок http: удалён из configuration.yaml, настройки перенесены в .storage/http (UI → Network). modbus.host исправлен: 127.0.0.1192.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. Сервисы: 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)

Что сделано:

  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 v2.14.1-1 (community repo). Манифест содержит uart: true → доступ ко всем serial, devices: не нужен.
  3. Mosquitto: добавлен логин zont (тот же пароль, что на TrueNAS) через Supervisor API → POST /addons/core_mosquitto/optionsha apps restart core_mosquitto. Нужен, чтобы HA-интеграция и ZONT продолжили работать по старым креденшелам.
  4. Опции 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: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).
  2. 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. Advanced Mode — не понадобился для CLI (всё сделано через ha apps), понадобится позже для local add-ons
  2. Mosquitto broker (core_mosquitto v7.1.1) — установлен, started, порты 1883 (MQTT) + 1884 (WS) открыты, discovery отправлен в HA автоматически
  3. 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. File editor (core_configurator) — установлен, started
  6. Репозиторий Zigbee2MQTT добавлен: ha store add https://github.com/zigbee2mqtt/hassio-zigbee2mqtt → появился как Home Assistant App: Zigbee2MQTT (slug 45df7312)
  7. 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

  1. Alex втыкает 3 USB в t610 — ВЫПОЛНЕНО 2026-09-14. Порты зафиксированы: CH340 #1 → USB1 порт 3, CH340 #2 → USB1 порт 4, Zigbee → USB3 порт 1. Устройства из портов не вынимать!
  2. Пути определены (ls /dev/serial/by-id/, by-path, sysfs) — подробная карта: family/how-to/t610-access §USB
  3. Карта составлена: ttyUSB0 = CH340 #1 (ZONT), ttyUSB1 = CH340 #2 (Vent), ttyACM0 = Zigbee
  4. СПОСОБ ПРИВЯЗКИ РЕШЁН 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. Блокер снят.
  5. z2m-аддон УСТАНОВЛЕН И РАБОТАЕТ (2026-09-14) — аддон 45df7312_zigbee2mqtt v2.14.1-1, serial по by-id, база перенесена 1:1, 16 устройств на месте, переспаривание не потребовалось. Подробности — §«z2m на t610 (ВЫПОЛНЕНО)» выше.
  6. mbusd local add-on СОБРАН И РАБОТАЕТ (2026-09-14) — slug local_mbusd, порт 502 открыт (проверено nc с Mac), устройство by-path CH340 #2 (порт 4). Подробности — §«Local add-ons mbusd / modbus-bridge» ниже.
  7. 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:80200.
  2. 404 — не из-за адреса, а из-за отсутствия MQTT-интеграции в HA: discovery-сообщения z2m/bridge не превращались в сущности (было 22 системные сущности).
  3. После добавления 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 mqttmqtt. Скрипт: ~/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.urlhttp://192.168.2.176:80, mqtt.brokercore-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.shcan't read config file /etc/mbusd.conf. Фикс: в Dockerfile ENTRYPOINT [] + CMD ["/bin/bash","/run.sh"].
  • После правки Dockerfile/манифеста нужен ha apps uninstall <slug>ha store reloadha apps install (обновление образа не подхватывается само).
  • Пакета mbusd в репозиториях Alpine НЕТ (apk add mbusdno 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: mqtt142, из них 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.host127.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_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_kabelswitch.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`
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 '"'. Обход: собирать заголовок в файл без литерала рядом с переменной:

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). Правило: писать скрипт файломscpbash /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.yaml16 устройств (было 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_pumpnasos_obratki, stairs_light_sensorlight_sensor_stairs, office_smart_lightsmart_light_office, stairs_smart_lightlight_stairs, bed_wireless_light_switchwireless_light_switch_bed, shower_night_lightnight_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 — артефакт переноса, а не исходное состояние.

Итоговая таблица (латиница, исправлены опечатки вроде Presensepresence):

# 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.dbfile 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_registrydata.devices[].namename_by_user), связь через identifiers: [["mqtt","zigbee2mqtt_0x..."]].
  3. Дашборд lovelace.home_planentity в 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_idcore.device_registryidentifiers → 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_kabelswitch.heating_cable_plug — СДЕЛАНО (в staged-файле, скрипт fix_dashboard.py)
  • binary_sensor.0xa4c1383d5fcaa063_water_leakbinary_sensor.boiler_water_leak_water_leak — СДЕЛАНО (автоматически переименованием реестра)
  • switch.0xa4c138f8da8bc478switch.recirculation_pump — СДЕЛАНО (то же)
  • light.0xa4c13882a4b42db0light.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_entriesha 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.0xa4c13882a4b42db0light.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). Единственная offautomation.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).

Правильный фикс (выполнен):

  1. Бэкап configuration.yaml.bak-http-<ts>; бэкап .storage/http.bak-<ts>.
  2. Добавить в .storage/httpdata.stable (jq, локально): use_x_forwarded_for: true, trusted_proxies: ["172.16.0.0/12"]. Файл положить при остановленном HA (ha core stop), иначе HA перезапишет.
  3. Удалить блок http: из configuration.yaml, оставить комментарий-пояснение.
  4. 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).

Порядок (выполнен):

  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 в аддоне НЕТ):

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.dblastSeen в мс.

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

Процедура (выполнена, рабочий рецепт):

  1. permit_join через MQTT: mosquitto_pub -t zigbee2mqtt/bridge/request/permit_join -m '{"value":true,"time":250}'. ⚠️ Питфолл: лимит окна — 254 секунды. "time":300error: Cannot permit join for more than 254 seconds. Ставить ≤250.
  2. Устройство присоединилось само → появилось в bridge/devices под hex-именем 0xa4c1381694217e10.
  3. Переименование в z2m (до того как HA создаст сущности!): mosquitto_pub -t zigbee2mqtt/bridge/request/device/rename -m '{"from":"0xa4c1381694217e10","to":"boiler_controller_power"}'
  4. ⚠️ HA всё равно создал сущности по hex-имени (успел между join и rename) → понадобился второй фикс: переименование entity_id в core.entity_registry (HA stop → jq → HA start).
  5. Зона ставится в 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) или проверить питание шины. После подключения заслонки оживут сами — конфиг уже верный. См. §«ИТОГ: заслонки вентиляции».

Далее (не блокеры):

  1. sensor.*_summary — добавить |default(0) в template-сенсоры configuration.yaml (косметика; ошибки round got invalid input 'unknown' для kids_*/bedroom_* — уйдут сами, когда sniffer вентиляции пришлёт данные).
  2. switch.sauna = unknown — розетка физически отключена (lastSeen 8+ ч), не баг.
  3. Камера (§8 родительского плана).
  4. Этап 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 только когда без него никак (и предупреждать).

Этап 4 — проверка и отключение TrueNAS

  1. Чек-лист из родительского плана §6
  2. Caddy upstream → t610; GPON-редирект → t610
  3. Остановить + отключить автозапуск на 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.host127.0.0.1, localtuya: debug убран, дашборд поправлен.
  • РЕШЕНО 2026-09-14 — Mini Smart Switch 1 удалён из z2m (force: true). Мёртвое: lastSeen 2026-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_id light.0xa4c13882a4b42db0light.bed_dimmer. Результат: 16 автоматизаций, 15 on + 1 off, 0 unavailable. Этап 3 закрыт.
  • УСТРАНЕНО 2026-09-14 — HTTP-варнинг: блок http: удалён из configuration.yaml, trusted_proxies/use_x_forwarded_for перенесены в .storage/http.
  • ИСПРАВЛЕНО 2026-09-14 — modbus.host: 127.0.0.1192.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 родительского плана) — не аддон, разбираться отдельно
  • ⚠️ Незакреплённое: sensor.0xa4c138f8da8bc478_voltage/energy/power/current (11 hex-сущностей розетки Насос обратки) — проживут ли под новым friendly_name или создадутся дубли; проверить после шага 8.

Связанные заметки