Files
obsidian-vault/family/how-to/t610-access.md
T

29 KiB
Raw Blame History

HP t610 — хост домашней автоматизации (HA OS)

Хост, на который переносится домашняя автоматизация с TrueNAS. План переноса: family/plans/home-automation-migration-t610 Развёртывание сервисов: family/plans/t610-addons-deployment

Состояние на 2026-09-14 (Этап 2 закрыт, Этап 3 в работе): z2m (16 устройств), mbusd (порт 502), modbus-bridge (MQTT + HA-опрос) — все развёрнуты аддонами и работают. В HA добавлена MQTT-интеграция (её не было → z2m/bridge не создавали сущности; стало 104 сущности, 69 Zigbee). Этап 3 — перенос HA-конфига с TrueNAS (разведка выполнена, решения приняты, ждём ответа Alex по HACS / схеме Zigbee-имён).

Основное

Параметр Значение
Железо HP t610 (AMD T56N 2×@1.65 ГГц, 4 ГБ DDR3, HDD WD2500BEVT 250 ГБ)
ОС Home Assistant OS 18.2 (generic-x86-64)
HA Core 2026.9.2
Supervisor 2026.09.0
IP 192.168.2.176 (DHCP-имя homeassistant, MAC 9c:8e:99:ef:3f:c5)
Web UI http://192.168.2.176⚠️ порт 80, не 8123!
SSH ssh -i ~/.ssh/id_rsa root@192.168.2.176 (через аддон Terminal & SSH)
Сеть 192.168.2.0/24, статический IP пока не закреплён на роутере

⚠️ HA слушает порт 80, а не 8123. Порт 8123 на t610 закрыт. Веб-морда открывается по http://192.168.2.176 без указания порта. Проверено 2026-09-13 (curl вернул HTTP 200 и страницу Home Assistant).

📌 Первая установка HA OS ставит HA «с нуля» — конфиги переносятся вручную (см. план миграции §5.6), НЕ через бэкап-снапшот.

Подключение

# HA UI (порт 80!)
http://192.168.2.176

# SSH — только после установки аддона Terminal & SSH (core_ssh)
ssh -i ~/.ssh/id_rsa root@192.168.2.176

Важно про SSH: в HA OS SSH выключен по умолчанию — порты 22 и 22222 дают Connection refused. Включается только через аддон core_ssh (Terminal & SSH): Settings → Apps → Terminal & SSH → Install → положить свой публичный ключ в authorized_keys → Start. Пароля root для SSH не существует — вход только по ключу.

⚠️ Порт 22222 (debug SSH) на t610 закрыт — debug-доступ не включён. Рабочий путь — аддон.

Хостовый SSH (debug-SSH 22222) — как и зачем

Порт 22222 даёт root-шелл самого хоста HA OS (не контейнера) — там есть /etc/udev/rules.d, udevadm, systemd. Это аналог того доступа, что был на TrueNAS.

Но включить его по сети НЕЛЬЗЯ (проверено 2026-09-14):

  • ha host — ssh-команд нет (только reboot/shutdown/disks/options/logs)
  • Supervisor API /host/services/ssh403 Forbidden (роль аддона core_ssh = manager, нужен admin)
  • ha os import — только импорт конфигов с флешки

Единственный штатный способ: флешка (FAT32, метка тома CONFIG) с файлом authorized_keys (публичный ключ) в корне → воткнуть в t610 → перезагрузка/ожидание → порт 22222 открывается.

📌 На практике хостовый SSH на t610 не нужен: задача алиасов serial решается штатным механизмом Supervisor — флагом uart: true (см. §USB → «РЕШЕНИЕ»). Хостовый шелл потребовался бы только для кастомных udev-правил, а они не требуются.

Ограничения SSH-аддона (что доступно из шелла)

Внутри аддона core_ssh НЕТ docker CLI и НЕТ python3.

Есть: bash, curl, jq, ha (HA CLI), ssh, ls, cat.

Как управлять docker: только через Supervisor — ha docker info (сам docker на хосте есть, v29.6.2, overlayfs/journald), но из аддона он не виден, т.к. аддон живёт в своём контейнере. Полноценный docker-compose на HA OS — нештатный путь; сервисы ставим аддонами (см. family/plans/t610-addons-deployment).

Скрипты для t610 писать на bash + jq, не на python3.

HA CLI (ha) — полезные команды

ha info                      # общая информация
ha core info                 # состояние HA Core
ha supervisor info            # список аддонов и репозиториев
ha apps                       # список установленных аддонов + состояние
ha apps info <slug>           # детали аддона (в т.ч. options, схема)
ha apps install <slug>        # установить
ha apps start|stop|restart <slug>
ha apps logs <slug>           # логи аддона
ha store add <url>            # добавить репозиторий аддонов
ha hardware info              # железо + USB-устройства (tty, serial)
ha host info                  # диск, версия OS, features

⚠️ ha apps не умеет менять опции (нет команды options). Настройка — через UI или Supervisor API (см. ниже).

Диагностика USB/serial из аддона (udevadm НЕТ)

В SSH-аддоне нет udevadm (udevadm info вернёт пусто / command not found). Атрибуты USB-устройств читать напрямую из sysfs:

# все serial-симлинки (по id и по адресу шины)
ls -la /dev/serial/by-id/ /dev/serial/by-path/

# для конкретного tty — найти sysfs-путь и прочитать атрибуты
P=$(readlink -f /sys/class/tty/ttyUSB0/device)          # базовый sysfs-путь
for f in idVendor idProduct serial product manufacturer; do
  v=$(cat "${P%/*}/$f" 2>/dev/null); [ -n "$v" ] && echo "$f = $v"
done

# топология USB (какое устройство на каком контроллере/порту)
lsusb
lsusb -t

# быстрый срез всех tty + их sysfs
for d in ttyUSB0 ttyUSB1 ttyACM0; do echo "$d -> $(readlink -f /sys/class/tty/$d/device)"; done

📌 Питфолл: у двух CH340 (1a86:7523) поля serial/manufacturer пустые → их by-id совпадает. Различать только по by-path (адрес шины). Подробнее — §USB.

Смена опций аддона через Supervisor API

API доступен из аддона (SUPERVISOR_TOKEN уже в окружении):

SLUG="a0d7b954_nodered"
API="http://supervisor/addons/${SLUG}"
AUTH="Authorization: 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"

⚠️ ПРИМЕЧАНИЕ (2026-09-14): в некоторых скриптах этой доки переменная токена при записи через инструменты выглядит как AUTH="...***..." — это артефакт маскировки секретов, а не рабочий код. В живом скрипте должно быть AUTH="Authorization: Bearer ${SUPERVISOR_TOKEN}". Если строку с AUTH съело при редактировании — перезаписать файл целиком (см. ~/tmp-t610/*.sh на Mac, они рабочие).

⚠️ API требует полный набор опций — схема валидирует все ключи. Посылать только изменённое нельзя: вернёт Missing option '<key>'. Берём текущие опции и меняем нужное.

Long-lived token HA и обращение к API из аддонов (важно, 2026-09-14)

Как создать токен: http://192.168.2.176 → профиль (аватар) → SecurityLong-lived access tokensCreate token.

Проверка токена:

curl -s -o /dev/null -w '%{http_code}\n' -H "Authorization: Bearer <TOKEN>" http://192.168.2.176/api/
# 200 = рабочий, 401 = негодный

⚠️ ПИТФОЛЛ 1 — токен маскируется в bash. Если подставлять токен через переменную окружения / echo / sed, в итоговый JSON/опции попадает заглушка (наблюдалось <len 13> вместо реальных 183 символов). Рабочий способ: записать токен в файл → скопировать файлом на t610 → читать на месте:

TOK=$(tr -d '\n\r' < /tmp/ha_token.txt)
jq --arg t "$TOK" '.ha_token = $t' input.json > out.json

⚠️ ПИТФОЛЛ 2 — адрес для аддона. Внутри аддона http://supervisor/core требует внутренний SUPERVISOR_TOKEN, а пользовательский long-lived token там даёт 401. Для обращения к HA Core из аддона использовать прямой адрес:

http://192.168.2.176:80      ✅ работает с пользовательским токеном (200)
http://supervisor/core       ❌ 401 с пользовательским токеном

Это ровно то, что нужно modbus-bridge в его ha.url (см. family/plans/t610-addons-deployment).

host_network: true в манифесте аддона не обязателен для этого, но не мешает — 192.168.2.176 достижим и без него.

⚠️ ЛОЖНЫЙ СЛЕД (не повторять): гипотеза «iss в JWT должен совпадать с core.uuid HA» — НЕВЕРНА. У рабочего токена iss и core.uuid не совпадают (проверено: iss=e75d1d6f…, core.uuid=d3b24dad…), и это норма. Единственный надёжный критерий — HTTP-код на /api/.

Добавление интеграции MQTT в HA (Config Entry Flow API)

Если в HA нет MQTT-интеграции, discovery-сообщения z2m/bridge уходят в mosquitto и висят — сущности не создаются (симптом: 404 при обращении к сущности; в HA только системные ~22 сущности).

T="<long-lived token>"
BASE="http://192.168.2.176/api/config/config_entries/flow"
# 1) создать 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)
# 2) выбрать вариант "addon" (Mosquitto Mqtt Broker) — креды Supervisor подставит сам
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. Эффект: сущностей стало 104 (69 Zigbee) вместо 22. Скрипт: ~/tmp-t610/setup_mqtt_integration.sh.

Доступ к роутерам (диагностика сети t610)

t610 в сети 192.168.2.0/24. Роутеры для проверки:

Роутер Доступ Особенность
192.168.2.2 (OpenWrt, основной) SSH root, пароль 1316261 DHCP-аренды: cat /tmp/dhcp.leases
192.168.6.1 («Rasputin», OpenWrt aarch64) SSH root имеет eth0 192.168.2.157/24 → видит сеть 192.168.2.x

⚠️ ПИТФОЛЛ: nc на OpenWrt (busybox) НЕ поддерживает флаг -z. nc -z host port молча печатает usage и возвращает неверный результат → ложный вывод «порт закрыт». Для проверки портов с OpenWrt использовать curl -s -o /dev/null -w '%{http_code}' или wget. Проверка портов с Mac через nc -z работает нормально.

Диск и железо (проверено 2026-09-13, ha host info)

Параметр Значение
Диск WD2500BEVT (WD-WX31A60P2258), 228.5 ГБ
Занято 5 ГБ
Свободно 214.2 ГБ
Docker (host) 29.6.2, storage overlayfs, logging journald
OS haos:18.2, generic-x86-64, production

📌 Диск был взят из TrueNAS (бывший системный диск с Windows 7) — образ HA OS записан через dd с Mac. Подробности в family/plans/home-automation-migration-t610 Шаг 1.

USB-устройства (подключены 2026-09-14, карта зафиксирована)

Все 3 устройства физически подключены к t610 (проверено 2026-09-14).

Устройство by-id by-path (фиксированная привязка) tty Физический порт
CH340 #1 usb-1a86_USB_Serial-if00-port0 pci-0000:00:12.0-usb-0:3:1.0-port0 /dev/ttyUSB0 USB1 порт 3 (OHCI pci-0000:00:12.0)
CH340 #2 usb-1a86_USB_Serial-if00-port0 ⚠️ тот же pci-0000:00:12.0-usb-0:4:1.0-port0 /dev/ttyUSB1 USB1 порт 4
Zigbee Inswift ZBP-MG21 usb-Inswift_Zigbee_ZBP-MG21_535A000001-if00 pci-0000:04:00.0-usb-0:1:1.0 /dev/ttyACM0 USB3 порт 1 (xhci pci-0000:04:00.0)

Sysfs-пути:

ttyUSB0 → /sys/devices/pci0000:00/0000:00:12.0/usb1/1-3/1-3:1.0/ttyUSB0
ttyUSB1 → /sys/devices/pci0000:00/0000:00:12.0/usb1/1-4/1-4:1.0/ttyUSB1
ttyACM0 → /sys/devices/pci0000:00/0000:00:15.3/0000:04:00.0/usb3/3-1/3-1:1.0

⚠️ ГЛАВНЫЙ ПИТФОЛЛ: два CH340 неразличимы по by-id

Оба CH340 — 1a86:7523, serial = <none>, manufacturer = <none>, product = "USB Serial" (одинаковые). → by-id у обоих идентичен (usb-1a86_USB_Serial-if00-port0). Проброс по by-id в аддонах сломается — оба аддона получат одно и то же устройство.

Различать только по by-path (адрес шины) — ровно та же проблема, что была на TrueNAS, где алиасы ttyZONT/ttyVent делались udev-правилами по адресу шины (family/how-to/zont-modbus-bridge-udev-race-protection).

Zigbee-координатор — единственный из трёх, у кого есть уникальный серийник (535A000001), поэтому его by-id стабилен и проброс по by-id безопасен.

Различия by-path на t610 vs TrueNAS

  • TrueNAS: KERNELS=="?-1.5" / "?-1.6" (другая топология USB).
  • t610: путь pci-0000:00:12.0-usb-0:3 и ...-0:4порт 3 и порт 4 на одном OHCI-контроллере. Т.е. udev-правило на t610: KERNELS=="1-3" и KERNELS=="1-4".

🔑 РЕШЕНИЕ: привязка по by-path (udev-алиасы на HA OS не нужны)

Как на TrueNAS — нельзя. Там был хостовый шелл TrueNAS → /etc/udev/rules.d/99-tty-alias.rules. На t610 SSH-аддон = Alpine-контейнер: нет /etc/udev/rules.d, нет udevadm. Хостовый доступ = только debug-SSH 22222, но он выключен и включается только флешкой (authorized_keys в разделе с меткой CONFIG); по сети — никак:

  • ha host — ssh-команд нет
  • Supervisor API /host/services/ssh403 Forbidden (аддон core_ssh имеет роль manager, нужен admin)
  • ha os import — только импорт конфигов с флешки

Рабочая схема — штатный uart: true:

  • Флаг uart: true в манифесте аддона даёт контейнеру доступ ко всем serial-устройствам хоста, включая симлинки /dev/serial/by-id/ и /dev/serial/by-path/.
  • Проверено на живом t610: core_ssh имеет uart: true → его /dev/serial/by-path/ содержит все пути (таблица выше). z2m-аддон тоже uart: true.
  • devices: прописывать не нужно — проброс автоматический.

Что писать в конфигах сервисов:

Zigbee (z2m): serial.port = /dev/serial/by-id/usb-Inswift_Zigbee_ZBP-MG21_535A000001-if00  (или by-path pci-0000:04:00.0-usb-0:1:1.0)
ZONT (modbus-bridge):       /dev/serial/by-path/pci-0000:00:12.0-usb-0:3:1.0-port0   (CH340 #1, порт 3)
Вентиляция (mbusd):         /dev/serial/by-path/pci-0000:00:12.0-usb-0:4:1.0-port0   (CH340 #2, порт 4)

Функциональный аналог TrueNAS-алиасов: имя не «прыгает» при перезагрузке. Отличие — вместо ttyZONT пишется полный by-path.

⚠️ by-path привязан к физическому порту — CH340 #1 держать в порту 3, CH340 #2 в порту 4. Порты зафиксированы.

Плюс аддонов: старая проблема гонки udev (family/how-to/zont-modbus-bridge-udev-race-protection) на t610 неактуальна — Supervisor сам ждёт устройство при старте аддона, скрипты ожидания tty не нужны.

Установленные аддоны (обновлено 2026-09-14)

Аддон Slug Версия Состояние Порты
Terminal & SSH core_ssh 10.4.0 started 22
Mosquitto broker core_mosquitto 7.1.1 started 1883 (MQTT), 1884 (WS)
Node-RED a0d7b954_nodered 22.0.6 started 1880
File editor core_configurator started web UI
Zigbee2MQTT 45df7312_zigbee2mqtt 2.14.1-1 started (16 устройств) ingress 8099
mbusd local_mbusd 1.0.0 started 502 (Modbus TCP)
modbus-bridge local_modbus-bridge 1.0.0 started — MQTT + HA-опрос sniffer шины ZONT
Samba share core_samba ⏸️ stopped (нужен пароль)

Репозитории аддонов: официальный + Zigbee2MQTT (https://github.com/zigbee2mqtt/hassio-zigbee2mqtt) + Local apps.

Как собрать local add-on на HA OS (рецепт + питфоллы, 2026-09-14)

Local add-ons (/addons/<slug>/) нужны, когда сервиса нет в сторе и нет community-репо. Собраны так: mbusd (local_mbusd) и modbus-bridge (local_modbus-bridge). Готовые исходники лежат и на t610 (/addons/…), и локально на Mac (~/tmp-t610/addons/…).

Минимальная структура аддона:

/addons/<slug>/
  config.yaml     ← манифест Supervisor (name, version, slug, arch, options, schema, uart, …)
  Dockerfile
  run.sh          ← читает /data/options.json, готовит конфиг сервиса, exec сервиса
  build.yaml      ← ТОЛЬКО если базовый образ задаётся через ${BUILD_FROM} (см. питфолл 1)

Жизненный цикл:

ha store reload                  # Supervisor подхватывает /addons/*  → local_<slug> в сторе
ha apps install local_<slug>     # собирает образ (docker buildx) и ставит
ha apps start  local_<slug>
ha apps logs   local_<slug>
# при правке Dockerfile/манифеста:
ha apps uninstall local_<slug> && ha store reload && ha apps install local_<slug>

Настройка опций после установки — через UI или Supervisor API (POST http://supervisor/addons/<slug>/options, полный набор опций). Диагностика провала сборки: ha supervisor logs | tail -60 — там полный вывод docker build.

⚠️ Питфоллы (все ловились на живом t610):

  1. ${BUILD_FROM} пустойbase name (${BUILD_FROM}) should not be blank. Либо добавить build.yaml c build_from: {amd64: <image>, aarch64: <image>}, либо взять готовый образ напрямую (FROM 3cky/mbusd:latest) — тогда build.yaml не нужен.
  2. Supervisor рекурсивно парсит ВСЕ *.yml/*.yaml в папке аддона как манифесты → служебный шаблон конфига даёт Invalid app config! и ломает загрузку. Фикс: держать шаблон с расширением .tmpl (например data/config.template.tmpl), переименовывать в .yml только внутри контейнера при сборке.
  3. ENTRYPOINT базового образа перебивает CMD → контейнер запускал бинарь напрямую, минуя run.sh (mbusd: can't read config file /etc/mbusd.conf). Фикс: в Dockerfile явно ENTRYPOINT [] + CMD ["/bin/bash","/run.sh"].
  4. Пакета может не быть в репозиториях Alpine (apk add mbusdno such package) — тогда только готовый образ из Docker Hub или сборка из исходников.
  5. Сборка идёт через docker buildx на хосте, тянет базовый образ из интернета, занимает несколько минут.
  6. uart: true в манифесте обязателен для доступа к /dev/serial/by-path/… (иначе аддон не увидит CH340/Zigbee). Для modbus-bridge дополнительно host_network: true.
  7. В HA UI local add-ons требуют Advanced Mode в профиле (Settings → Apps).

📌 <slug> в URL аддона = local_<имя папки>. Опции из UI кладутся в /data/options.json внутри контейнера — читать через jq.

📌 z2m: data_path = /config/zigbee2mqtt (внутри HA-конфига, НЕ /addon_configs/). Там database.db, configuration.yaml, coordinator_backup.json, log/. Данные перенесены 1:1 с TrueNAS — подробности и питфоллы: family/plans/t610-addons-deployment §«z2m на t610 (ВЫПОЛНЕНО)».

📌 В HA 2026.x аддоны в UI называются Settings → Apps (не «Add-ons»). Пункта «Add-ons» в меню больше нет.

Работа с данными z2m на t610 (2026-09-14)

Файлы в /config/zigbee2mqtt/:

Файл Что это
database.db база z2m (устройства, endpoints, keys)
configuration.yaml конфиг z2m: network_key, pan_id, ext_pan_id, channel, serial, mqtt, секция devices: с friendly_name
coordinator_backup.json бэкап координатора
state.json runtime-состояние
log/<ts>/log.log логи запуска

⚠️ ПИТФОЛЛ: database.db — это НЕ SQLite, а JSON Lines (по одному JSON-объекту на строку, расширение .db обманчиво).

  • sqlite3 database.db "SELECT ..."Error: in prepare, file is not a database (26) — не тратить на это время.
  • Читать через jq построчно (каждый объект = устройство):
scp root@192.168.2.176:/config/zigbee2mqtt/database.db /Users/admin/tmp-t610/z2m-live.db
jq -r 'select(.type!="Coordinator") | [.ieeeAddr, .type, (.manufName // "-")] | @tsv' /Users/admin/tmp-t610/z2m-live.db
# .ieeeAddr, .type (EndDevice/Router/Coordinator), .manufName (модель Tuya, напр. _TZ3000_gjnozsaz)
  • В SSH-аддоне нет sqlite3 — базу копировать на Mac (scp) и разбирать там.

📌 modelID в database.db пустой (не заполнился при переносе базы 1:1), но manufName даёт модель Tuya — по ней определяется тип устройства.

⚠️ friendly_name устройств z2m = hex-адрес. Все 16 устройств в configuration.yaml → devices: имеют friendly_name: '0xa4c138...' — это состояние с TrueNAS. Отсюда технические entity_id в HA (sensor.0xa4c138..._temperature). Исправление — Этап 3, family/plans/t610-addons-deployment §«Zigbee friendly_name».

HA-конфиг: что где лежит (TrueNAS → t610, разведка 2026-09-14)

На TrueNAS конфиг HA: /mnt/RED_2TB/docker/ha/ (доступ: ssh truenas_admin@mallexxx.duckdns.org).

Состав (для переноса в Этапе 3):

  • configuration.yaml (~30 КБ), automations.yaml, scripts.yaml (~30 КБ), secrets.yaml
  • www/card-mod.js + floorplan/floor1_ha.svg, floor2_ha.svg
  • .storage/35 файлов, переносить выборочно ⚠️
  • custom_components/hacs (2.0.5, репо пусто), localtuya (5.2.3, используется), tuya_local (2026.7.2, не используется)
  • home-assistant_v2.db — 142 МБ, не переносится (решение: история с нуля)

⚠️ .storage/ НЕ копировать целиком — смешаны системные файлы t610 и контентные TrueNAS:

  • НЕ трогать: core.uuid (подменит instance_id), auth, auth_provider.homeassistant (сломает логин), http, http.auth, onboarding, core.config, core.config_entries
  • Переносить: core.entity_registry (критично!), core.device_registry, core.area_registry, core.floor_registry, core.restore_state, lovelace.home_plan, lovelace_dashboards, lovelace_resources, person, zone

Порядок критичен: сначала реестры, потом (после старта HA) правка friendly_name в z2m и entity_id в HA. Переименование до переноса реестров пропадёт — HA перезапишет реестр.

Полезные команды разведки конфига (из SSH-аддона на t610):

ls -la /config/                                          # состав HA-конфига
ls /config/.storage/ | wc -l                             # число файлов реестра
jq -r '.data.entries[].domain' /config/.storage/core.config_entries | sort | uniq -c   # какие интеграции подключены
jq -r '.data.entities | length' /config/.storage/core.entity_registry                  # число сущностей
cat /config/.HA_VERSION                                  # версия HA

На TrueNAS аналогично, путь /mnt/RED_2TB/docker/ha/ (читать под truenas_admin).

📌 Как узнать, используется ли интеграция: jq -r '.data.entries[].domain' core.config_entries — если домена нет, компонент не подключён (напр. tuya_local стоял в файлах, но config entry отсутствовал → не использовался).

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