[2026-09-14] eagle: family/how-to/home-automation.md family/how-to/truenas-infrastructure.md family/how-to/zont-modbus-bridge-udev-race-protection.md family/plans/t610-home-automation.md

This commit is contained in:
Alexey Martemyanov
2026-09-14 20:54:43 +06:00
parent 2f88ba48b9
commit 80b172d9e4
4 changed files with 74 additions and 39 deletions
+2
View File
@@ -30,6 +30,8 @@ related:
>
> **✅ ZONT MQTT — ПЕРЕНАПРАВЛЕН 2026-09-14:** на роутере `192.168.2.2` (OpenWrt) DNAT-правила `redirect[0]` (name `MQTT`) и `rule[3]` (name `allow-1883`) переключены `dest_ip` `192.168.2.197` → **`192.168.2.176`**. ZONT теперь пишет в mosquitto-**аддон на t610** (живой поток `modbus/sensors/kids/*`, `bedroom/*`). В настройках ZONT ничего не менялось — адрес `mqtt://zont:…@192.168.0.10:1883` остался тот же (`192.168.0.10` = wan-интерфейс самого роутера `192.168.2.2`). Бэкап правил: `/root/firewall.bak-20260914-092555`. Детали и откат — [[family/plans/t610-home-automation]] §5-кватер-Д. Также `/etc/config/dhcp`: `list address '/mallexxx.duckdns.org/192.168.0.10'` — внутренний DNS-пин для ZONT-сети.
>
> **⛔ ДЕКОМИССИЯ TrueNAS-СТЕКА (2026-09-14, ночь):** старый стек автоматизации на TrueNAS **погашен** — `homeassistant`, `mbusd`, `mosquitto`, `nodered`, `zigbee2mqtt`, `modbus-bridge`, `ser2net` (`docker stop` + `--restart=no`, **НЕ удалены**). Контейнеров на TrueNAS в этой схеме **больше нет** — весь домашний контур живёт на **t610** (`192.168.2.176`). USB-адаптеры CH340 физически на t610 → на TrueNAS узлов `/dev/ttyVent`/`/dev/ttyZONT` не существует. Полный разбор — [[family/plans/t610-home-automation]] §5-кватер-Л, канон-блок — [[family/how-to/truenas-infrastructure]].
>
> **🔌 ZONT 485 сидит на гнезде 4** (`/dev/serial/by-path/pci-0000:00:12.0-usb-0:4:1.0-port0`), вентиляция — гнездо 3. `modbus-bridge` (аддон на t610) сниффит ZONT-шину и публикует в MQTT топики `modbus/sensors/<комната>/<параметр>`. **Публикуются `kids`, `bedroom` И `dining`.**
>
> **✅ `dining/*` — ПОЧИНЕН 2026-09-14 (коммит `3748feb`).** Настоящая причина: **баг сборки RTU-кадров в `modbus_ha_bridge.py`** — ответы рвались (`ser.read(ser.in_waiting or 1)` + короткий таймаут), байты-сироты копились в голове буфера → сдвиг выравнивания → **19-байтный** кадр гостиной не сходился по CRC и молча отбрасывался (12-байтные `kids`/`bedroom` проскакивали). Фикс по канону libmodbus/pymodbus: **T3.5-разграничение** (пауза ≥ 3.5 символа = конец кадра; при 9600 бод = 4.01 мс) + **сброс битого буфера** (`buf = b""`, аналог `resetFrame`). Итог: 7/7 полей `dining` публикуются, `unavailable` 10→8. Диагностика `MODBUS_DEBUG_RAW` снята.
+56 -28
View File
@@ -4,7 +4,7 @@
>
> **2026-09-14 (вечер-2, обновлено вечер-13) — Caddy ПЕРЕКЛЮЧЁН, Node-RED ПЕРЕНЕСЁН:**
> - **Caddy НЕ переносился и не будет:** 17 из 20 доменов `*.mallexxx.duckdns.org` — сервисы самого TrueNAS (immich, gitea, jellyfin, radarr, webdav, transmission, portainer…). Перенос Caddy на t610 положил бы их при падении t610. **✅ ПРАВКА ЗАВЕРШЕНА (факт-проверка 2026-09-14 вечер-13):** в `Caddyfile` остался **ОДИН** upstream на t610 — `mallexxx.duckdns.org` → `192.168.2.176:80` (HA, HTTP 200 ✅). **УБРАНЫ совсем:** `cam.mallexxx.duckdns.org` (камера на t610 по RTSP — домен не нужен) и `nodered.mallexxx.duckdns.org` (Node-RED — через ingress HA, решение Alex «оставляем так»). Caddyfile: `/mnt/RED_2TB/docker/caddy/Caddyfile` (root-owned — агент только стейджит в `/tmp/`, подменяет Alex), бэкап `Caddyfile.bak-20260914`. Порты контейнера: `8088:80`, `8443:443`; DNAT на роутере `192.168.2.2`: `wan:80→192.168.2.197:8088`, `wan:443→192.168.2.197:8443`.
> - **Node-RED flows перенесены на t610** (`/addon_configs/a0d7b954_nodered/flows.json`, 68 узлов, узел `server` → `addon: true`). **Наружу НЕ выпущен** (порт-маппинг при `host_network: true` глушится, снимается только в UI) — доступ через ingress HA. Node-RED в докере TrueNAS (`/mnt/RED_2TB/docker/nodered/`, порт `1880:1880`) **продолжает работать** как источник/откат.
> - **Node-RED flows перенесены на t610** (`/addon_configs/a0d7b954_nodered/flows.json`, 68 узлов, узел `server` → `addon: true`). **Наружу НЕ выпущен** (порт-маппинг при `host_network: true` глушится, снимается только в UI) — доступ через ingress HA. Node-RED в докере TrueNAS (`/mnt/RED_2TB/docker/nodered/`) **✅ ПОГАШЕН 2026-09-14** (`stop` + `--restart=no`; папка цела, откат = `docker start nodered` + `--restart=unless-stopped`).
> - **🔴 Важно про доступ к HA извне:** `/config/.storage/http` на t610 требовал `trusted_proxies += 192.168.2.197/32`, иначе Caddy с другого хоста даёт **400** (HA `use_x_forwarded_for: true`). Обобщение: **IP любого внешнего reverse-proxy обязан быть в `trusted_proxies`.**
> **2026-09-14 (вечер-3) — ZONT MQTT ПЕРЕНАПРАВЛЕН НА t610:**
> - DNAT на роутере `192.168.2.2`: `firewall.@redirect[0]` (name `MQTT`) и `firewall.@rule[3]` (name `allow-1883`) — `dest_ip` `192.168.2.197` → **`192.168.2.176`**. `uci commit firewall` + `/etc/init.d/firewall reload`. Бэкап: `/root/firewall.bak-20260914-092555`.
@@ -25,13 +25,11 @@
> ## ✅ СТАТУС на 2026-08-25: пул ONLINE, docker поднят, почти все контейнеры Up
> **Пул RED_2TB пересоздан (2026-08-21) и работает:** `zpool status` ONLINE, rsync возврата данных завершён, `/mnt/RED_2TB/` смонтирован.
> **Docker: ПОДНЯТ на 2026-08-25.** Почти все контейнеры Up (zigbee2mqtt, webdav, vless-proxy, homeassistant, caddy, transmission, syncthing, mosquitto, nodered, immich*, gitea, filebrowser, portainer*, hermes-taiga и др.). ✅ **cups-splix поднят 2026-08-26** — образ собран заново (`docker build -t cups-splix .`), контейнер запущен `docker compose up -d`, порт 631 открыт, принтер `Samsung_CLX-216x_Series` активен (USB `04e8:3425`). Причина былого падения: образ локальный, потерян при восстановлении пула (`.ix-apps` не переносился), вручную не пересобирали. Рецепт — ниже, раздел «Печать / cups-splix». Ещё не подняты (проверить при надобности): inpxer/inpx-web/arr/ser2net.
> **⚠️ Известная проблема modbus-bridge/mbusd — гонка с udev при рестарте TrueNAS:**
> - После перезагрузки docker стартует раньше udev, поэтому `/dev/ttyZONT` и `/dev/ttyVent` на момент старта контейнеров ещё не существуют.
> - Контейнеры с `devices: /dev/ttyZONT:...` падают на `start` с `error gathering device information while adding custom device "/dev/ttyZONT": no such file or directory` (ExitCode 128/255, RestartCount=0).
> - `restart: unless-stopped` НЕ перезапускает такой контейнер (отказ до старта процесса).
> - Следствие: modbus-bridge не отвечает на шине → 485-датчики в ZONT отображаются **«недоступные»**.
> - Ручной фикс: `docker start modbus-bridge mbusd` (после готовности tty-симлинков).
> - Защита от рецидива (план, НЕ внедрён — ждёт OK Alex): `family/how-to/zont-modbus-bridge-udev-race-protection.md` — POSTINIT init script с ожиданием симлинков + `docker start`.
> **⚠️ ИСТОРИЧЕСКАЯ проблема modbus-bridge/mbusd — гонка с udev при рестарте TrueNAS (❌ БОЛЬШЕ НЕАКТУАЛЬНА):**
> - ~~После перезагрузки docker стартует раньше udev, поэтому `/dev/ttyZONT` и `/dev/ttyVent` на момент старта контейнеров ещё не существуют.~~
> - **✅ НЕАКТУАЛЬНО с 2026-09-14:** USB-адаптеры (CH340 ZONT/вентиляция) **физически перенесены на t610** → на TrueNAS узлов `/dev/ttyZONT` / `/dev/ttyVent` **нет вообще**, а сами контейнеры `mbusd`, `modbus-bridge`, `ser2net` **погашены** (`stop` + `--restart=no`). Проверка: `ls /dev/ttyUSB*` → пусто; `/sys/bus/usb/devices` содержит только принтер Samsung `04e8:3425` (**`lsusb` на TrueNAS не установлен** — использовать `/sys/bus/usb/devices`).
> - **Актуальная гонка udev живёт на t610** — см. [[family/how-to/zont-modbus-bridge-udev-race-protection]].
> - ⚠️ **Историческая справка (если когда-нибудь откатывать):** `restart: unless-stopped` НЕ перезапускает контейнер, упавший на `start` из-за отсутствующего device-узла (отказ до старта процесса, ExitCode 128/255, RestartCount=0); лечилось ручным `docker start modbus-bridge mbusd` после готовности симлинков.
> **⚠️ ДРУГОЕ (открытое):** пул `DEST` (IronWolf) на 2026-08-24 `DEGRADED` — разобраться, почему (отвалился mirror-член). TimeMachine (~277G) не возвращён (бэкапы macOS, вероятно не нужен — решение Alex не подтверждено). SSH с Mac по 192.168.2.197 нестабилен — использовать `mallexxx.duckdns.org`.
> ## 🔒 ИСТОРИЯ: статус до восстановления (2026-08-24)
@@ -173,21 +171,50 @@ docker compose up -d
**✅ Есть `docker-compose.yml` (поднимаются `docker compose -f ... up -d`)** — 22 шт:
arr, caddy, cups, filebrowser, gitea, hermes, immich, inpx-web, inpxer, library, mbusd, mosquitto, nodered, portainer-mcp, portainer, rclone, ser2net, syncthing, transmission, vless-proxy, watchtower, **xray-admin (3x-ui, добавлен 2026-09-01)**
> 🔴 **ВАЖНО (2026-09-14):** `mbusd`, `mosquitto`, `nodered`, `ser2net` **погашены** — поднимать их обратно **НЕ НАДО** (переехали на t610). Остальные — активны.
**⚠️ НЕТ compose-файла — только конфиг (восстанавливать вручную, параметры из доки ниже):**
- **ha** — Home Assistant: `/mnt/RED_2TB/docker/ha/` (automations.yaml). Образ `ghcr.io/home-assistant/home-assistant:stable`, порт `8123`, volume `/mnt/RED_2TB/docker/ha``/config`.
- **webdav** — `/mnt/RED_2TB/docker/webdav/` (config.yml). Образ `hacdias/webdav:latest`, домен webdav.mallexxx.duckdns.org.
- **modbus-bridge** — `/mnt/RED_2TB/docker/modbus-bridge/` (config.yml + modbus_ha_bridge.py). Образ `modbus-bridge` (локальная сборка из репо `HA-ZONT-Modbus`). Volumes: config.yml → `/app/config.yml` (ro), modbus_ha_bridge.py → `/app/modbus_ha_bridge.py` (ro).
- **zigbee2mqtt** — `/mnt/RED_2TB/docker/zigbee2mqtt/` (configuration.yaml). Образ `koenkk/zigbee2mqtt:latest`, работает через mosquitto.
- **homeassistant** — в доке упомянут как отдельный контейнер (порт 8123, volume → /config); папка `docker/homeassistant/` есть, но название контейнера в таблице `homeassistant`, а папка конфига HA фактически `ha/`. При восстановлении сверить, какой реально используется.
- ~~**ha** — Home Assistant: `/mnt/RED_2TB/docker/ha/` (automations.yaml)~~ → 🔴 **ПОГАШЕН 2026-09-14.** Папка **сохранена как ЭТАЛОН конфига** (`configuration.yaml`, modbus-блок построчно идентичен t610, 32 заслонки) — **не удалять**.
- **webdav** — `/mnt/RED_2TB/docker/webdav/` (config.yml). Образ `hacdias/webdav:latest`, домен webdav.mallexxx.duckdns.org. ✅ активен (compose на самом деле есть, см. строку выше).
- ~~**modbus-bridge** — `/mnt/RED_2TB/docker/modbus-bridge/`~~ → 🔴 **ПОГАШЕН 2026-09-14** (`Exited (0)` с 14.09 01:59 — узел `/dev/ttyZONT` исчез). Папка цела.
- ~~**zigbee2mqtt** — `/mnt/RED_2TB/docker/zigbee2mqtt/`~~ → 🔴 **ПОГАШЕН 2026-09-14** (`Exited (2)` — координатор на t610).
- ~~**homeassistant** — папка `docker/homeassistant/`~~ → **ПУСТАЯ и не использовалась**; рабочая была `ha/` (см. выше).
### Порядок восстановления docker-стека (зависимости)
1. **docker engine:** `systemctl enable --now docker` (после создания data-root, см. шапку). Проверка: `docker info | grep -iE "Server Version|Docker Root Dir"`.
2. **Инфраструктура/сеть:** mosquitto (MQTT) → zigbee2mqtt (нужен mosquitto) → nodered (MQTT) caddy (прокси, тянет все домены) → vless-proxy (SOCKS5 для hermes).
2. **Инфраструктура/сеть:** ~~mosquitto (MQTT) → zigbee2mqtt (нужен mosquitto) → nodered (MQTT)~~ — 🔴 **все три ПОГАШЕНЫ 2026-09-14, на TrueNAS НЕ ВОССТАНАВЛИВАТЬ** (живут на t610). Остаётся: caddy (прокси, тянет все домены) → vless-proxy (SOCKS5 для hermes).
3. **Умный дом:****на TrueNAS БОЛЬШЕ НЕ ВОССТАНАВЛИВАТЬ** — переехало на t610 (см. «Декомиссия стека автоматизации»), **стек ПОГАШЕН 2026-09-14**. `mbusd` (Modbus TCP:502) → `modbus-bridge` (через mbusd) → `ha` (homeassistant, нужен caddy для домена) — **всё это теперь аддоны на `192.168.2.176`**.
4. **Медиа/хранилище:** transmission (нужен caddy) → arr (radarr/sonarr/prowlarr) → inpxer (books), inpx-web, library → rclone, syncthing, filebrowser, webdav, gitea. ⚠️ `inpxer`/`inpx-web`/`library` — на 2026-09-14 в циклическом краше (см. декомиссию).
4. **Медиа/хранилище:** transmission (нужен caddy) → arr (radarr/sonarr/prowlarr) → inpxer (books), inpx-web, library → rclone, syncthing, filebrowser, webdav, gitea. ⚠️ `inpxer`/`inpx-web` — на 2026-09-14 в циклическом краше (НЕ трогать по указанию Alex); `library` — погашен 2026-09-14 (см. декомиссию).
5. **Сервисы/свои:** hermes-taiga (нужен vless-proxy), portainer, portainer-mcp, watchtower, cups. ~~ser2net~~**погашен 2026-09-14** (конфликт порта 502 с mbusd).
6. **Проверка:** `docker ps`. HA: `docker exec homeassistant python -m homeassistant --script check_config --config /config`.
6. **Проверка:** `docker ps`. HA (если когда-нибудь поднимать обратно): `docker exec homeassistant python -m homeassistant --script check_config --config /config` — но 🔴 контейнер **погашен**, живая HA = аддон на t610 `192.168.2.176`.
### ⛔ Декомиссия стека автоматизации TrueNAS (2026-09-14) — КАНОН
**Погашено 7 контейнеров** (`docker stop` + `docker update --restart=no`, **НЕ удалены**):
`homeassistant`, `mbusd`, `mosquitto`, `nodered`, `zigbee2mqtt`, `modbus-bridge`, `ser2net`
- **Почему:** всё это работает на **t610** (HA OS, `192.168.2.176`) как HA-аддоны; на TrueNAS ресурсы дублировались впустую, а `mbusd`/`modbus-bridge`/`zigbee2mqtt` вообще были мертвы (USB-адаптеры переехали физически).
- **Папки `/mnt/RED_2TB/docker/*` ЦЕЛЫ.** Откат: `docker start <name>` + `docker update --restart=unless-stopped <name>`.
- **`rm` НЕ делали** — удаление отдельным шагом, не раньше чем через 2–3 дня стабильной работы.
- **Секрет:** `HA_TOKEN` лежит **открытым текстом** в `/mnt/RED_2TB/docker/modbus-bridge/docker-compose.yml``environment` (там же `MQTT_PASS: mqtt1z3$`) — кандидат на `.env` + ротацию. Папку **не трогать/не публиковать** до ротации.
- **Полный разбор** — §5-кватер-Л в [[family/plans/t610-home-automation]].
**⚠️ Минные поля, найденные при аудите (НЕ трогались, отдельное решение Alex):**
| Контейнер | Проблема |
|---|---|
| `library` ⛔ | ~~`Restarting` циклически, **`RestartCount=29752`**~~**✅ ПОГАШЕН 2026-09-14** (по команде Alex): `docker stop library` + `docker update --restart=no``state=exited`, `restart=no`. Caddy-домен `library.mallexxx.duckdns.org`**мёртв** (и был мёртв до гашения). **Не удалён**, папка цела. **Открыто:** почему падал (`image: library-app:latest` из `build: .` — локальная сборка; тот же паттерн, что утерянные `cups-splix`/камера при пересоздании пула) |
| `inpx-web` / `inpxer` | оба `Exited (1)`, `RestartCount=13`; `books.mallexxx.duckdns.org``:18080` (мёртвый `inpxer`). **По указанию Alex НЕ трогать** |
**Диагностические питфоллы TrueNAS (проверено 2026-09-14):**
- ⚠️ **`curl http://192.168.2.176:8123``HTTP 000` — ЭТО НОРМА.** HA на t610 живёт **за Caddy**; её `:8123` закрыт, доступ = `:80` / `mallexxx.duckdns.org`. Не принимать за поломку.
- **`lsusb` на TrueNAS НЕ установлен** → USB-устройства смотреть через `/sys/bus/usb/devices/` (`product`, `manufacturer`, `idVendor`/`idProduct`).
- **`midclt call app.query``[]`** (TrueNAS Apps не используются), `/mnt/.ix-apps/app_configs` пуст. Всё — **per-service compose из своей папки**, Portainer stacks **не используются**.
- **`sudo` на TrueNAS требует пароль** (passwordless нет) — root-операции только через root-SSH/Shell.
- Кто чем управляется: `docker inspect <name> --format '{{index .Config.Labels "com.docker.compose.project.config_files"}}'`.
### Transmission — детали
- **Config:** `/mnt/RED_2TB/docker/transmission/` (монтируется как `/config`; внутри `/config/docker-compose.yml`)
@@ -528,16 +555,16 @@ git -C /mnt/RED_2TB/storage/git/obsidian-vault.git log --oneline -10
| Контейнер | Состояние | Причина | Решение |
|---|---|---|---|
| `homeassistant` | Up 5 дн | холостой — `modbus.host=192.168.2.197`, шины там нет | ⛔ гасить |
| `mbusd` | Up (ложно), 14:42 `can't open /dev/ttyUSB0` | `/dev/ttyVent` не существует (USB уехал) | ⛔ гасить |
| `mosquitto` | Up 3 нед | ZONT переключён на `.176` (DNAT) | ⛔ гасить |
| `nodered` | Up (healthy) | flows перенесены на t610 (68 узлов) | ⛔ гасить *(решение Alex: сразу или страховка 2 дня — открыто)* |
| `zigbee2mqtt` | Exited (2) **14.09 01:59** | `Adapter disconnected` — координатор на t610 | ⛔ останавливать (уже мёртв) |
| `modbus-bridge` | Exited (0) **14.09 01:59** | `/dev/ttyZONT` исчез | ⛔ останавливать (уже мёртв) |
| **`caddy`** | Up | **17 доменов TrueNAS + `mallexxx.*` → t610** | 🔴 **НЕ ТРОГАТЬ** |
| `ser2net` | `Created` (никогда не стартовал) | конфликт 502 с mbusd | отдельное решение |
| `library` | **Restarting, restart=29745** | 🔴 циклический краш, при этом Caddy ссылается (`library:8080`) | 🔴 отдельная задача |
| `inpx-web`, `inpxer` | Exited (1), 13 рестартов, 3 нед | циклический краш | 🔴 отдельная задача |
| `homeassistant` | Up 5 дн | холостой — `modbus.host=192.168.2.197`, шины там нет | **ПОГАШЕН 2026-09-14** |
| `mbusd` | Up (ложно), 14:42 `can't open /dev/ttyUSB0` | `/dev/ttyVent` не существует (USB уехал) | **ПОГАШЕН 2026-09-14** |
| `mosquitto` | Up 3 нед | ZONT переключён на `.176` (DNAT) | **ПОГАШЕН 2026-09-14** |
| `nodered` | Up (healthy) | flows перенесены на t610 (68 узлов) | **ПОГАШЕН 2026-09-14** (решение Alex: «Гасим nodered») |
| `zigbee2mqtt` | Exited (2) **14.09 01:59** | `Adapter disconnected` — координатор на t610 | `restart=no` 2026-09-14 |
| `modbus-bridge` | Exited (0) **14.09 01:59** | `/dev/ttyZONT` исчез | `restart=no` 2026-09-14 |
| **`caddy`** | Up | **17 доменов TrueNAS + `mallexxx.*` → t610** | 🔴 **НЕ ТРОГАТЬ** (не тронут) |
| `ser2net` | `Created` (никогда не стартовал) | конфликт 502 с mbusd | **ПОГАШЕН 2026-09-14** (по команде Alex) |
| `library` | ~~Restarting, restart=29752~~ | 🔴 циклический краш, Caddy ссылается (`library:8080`) | **ПОГАШЕН 2026-09-14** (по команде Alex); причина краша открыта |
| `inpx-web`, `inpxer` | Exited (1), 13 рестартов, 3 нед | циклический краш | 🔴 **НЕ ТРОГАТЬ** (указание Alex) |
**Ключевой факт-маркер переезда:** `zigbee2mqtt` и `modbus-bridge` **оба** легли в **2026-09-14T01:59** — синхронно, в момент физического переноса USB-адаптеров. Это доказательство, что дубль перестал работать сам, а не «сломался от чего-то».
@@ -557,8 +584,9 @@ curl -s -o /dev/null -w '%{http_code}\n' https://mallexxx.duckdns.org # ожи
**Правила этого шага:**
-**НЕ** `docker rm`, ❌ не удалять `/mnt/RED_2TB/docker/<app>/` — сначала «погасить», откат = `docker start` + вернуть `restart: unless-stopped`.
-**Caddy не гасить и не переносить** — 17 из 20 доменов это сервисы TrueNAS.
-`library`/`inpx-*`**отдельным решением**, не в этом заходе (там своя авария, не связанная с миграцией).
- ⚠️ Порт 502: `mbusd` и `ser2net` **не поднимать одновременно**.
-`inpx-*`**не трогать** (указание Alex). `library`**погашен отдельной командой Alex** (2026-09-14), причина краша не выяснена.
- ⚠️ Порт 502: `mbusd` и `ser2net` **не поднимать одновременно** (оба погашены).
- **✅ Факт выполнения 2026-09-14:** погашено 9 контейнеров (7 автоматизации + `ser2net` + `library`). Проверено: 502/1883/8123/1880 на TrueNAS свободны, `mallexxx.duckdns.org` = 200, MQTT на `.176` живой, RTSP `:8554` OPEN.
---
@@ -1,16 +1,21 @@
---
status: implemented
status: obsolete
tags:
- family
- homeautomation
- zont
- modbus
title: Защита modbus-bridge от гонки с udev (ZONT датчики)
updated: '2026-08-25'
updated: '2026-09-14'
---
# Защита modbus-bridge/mbusd от гонки с udev (ZONT датчики)
> Статус: **внедрено** (2026-08-25, шаги 13). Датчики в ZONT снова отвечают, скрипт и init script на месте.
> 🔴 **ДОКУМЕНТ УСТАРЕЛ (2026-09-14).** Речь идёт о контейнерах **на TrueNAS** — `modbus-bridge` и `mbusd`. Они **погашены** (`docker stop` + `--restart=no`) вместе со всем стеком автоматизации; USB-адаптеры физически переехали на **t610**, где узлов `/dev/ttyZONT`/`/dev/ttyVent` на TrueNAS больше не существует. **Проблема неактуальна.**
> На **t610** гонка udev решается иначе: Supervisor (HA OS) сам ждёт устройство перед стартом аддона — отдельный init-скрипт не нужен.
> История/контекст декомиссии: [[family/plans/t610-home-automation]] §5-кватер-Л, канон-блок — [[family/how-to/truenas-infrastructure]].
> ⚠️ Документ **оставлен как историческая справка** (пригодится, если когда-нибудь откатывать TrueNAS-стек).
>
> ~~Статус: **внедрено** (2026-08-25, шаги 13). Датчики в ZONT снова отвечают, скрипт и init script на месте.~~
## Проблема
ZONT (192.168.0.10) — Modbus master на RS-485 шине `ttyZONT`. 485-датчики: Dining=1, Kids=2, Bedroom=3.
+8 -8
View File
@@ -1977,7 +1977,7 @@ curl -s -X POST -H "$HDR" -H "Content-Type: application/json" \
| ~~5-арх~~ | ~~«Перенести Caddy на OpenWrt/t610»~~**❌ ОТВЕРГНУТО (§5-кватер-Б):** на OpenWrt 80/443 заняты `uhttpd`; у Caddy 17 доменов TrueNAS → при переносе падение t610 положит все медиасервисы. **Caddy остаётся на TrueNAS.** | — |
| ~~6~~ | ~~Остановить + отключить автозапуск сервисов на TrueNAS (не удалять — откат). **✅ РАЗБЛОКИРОВАНО 2026-09-14:** условие снято — п. **5-мк СДЕЛАН** (ZONT MQTT → t610). **Гасим ТОЛЬКО стек автоматизации:** `homeassistant` (8123), `mbusd` (502), `mosquitto` (1883), `nodered` (1880), + `zigbee2mqtt`/`modbus-bridge` если есть. **🔴 Caddy НЕ ГАСИТЬ и не переносить** — он не в списке, он рабочий элемент (17 доменов TrueNAS + `mallexxx.*` → t610) | **🔄 АУДИТ ПРОВЕДЁН 2026-09-14 (см. §5-кватер-Л).** Факты: `zigbee2mqtt` (Exited 2) и `modbus-bridge` (Exited 0) легли **синхронно 14.09 01:59** — сами, при переносе USB на t610; `mbusd` формально `Up` но спамит `can't open /dev/ttyUSB0` (адаптеров на TrueNAS НЕТ — в `/sys/bus/usb` только принтер Samsung `04e8:3425`); `homeassistant` Up, но `modbus.host=.197` → холостой. **Гасить (stop + `--restart=no`, НЕ `rm`):** `homeassistant`, `mbusd`, `mosquitto`, `nodered`, `zigbee2mqtt`, `modbus-bridge`. **Caddy НЕ трогать.** Побочная находка: `HA_TOKEN` открытым текстом в compose `modbus-bridge`. **Ждёт решения Alex:** `nodered` сразу или страховка 2 дня | **✅✅ ВЫПОЛНЕНО 2026-09-14 (ночная сессия).** Alex: «Гасим nodered» + «ser2net тоже гасить» + «inpxer не трогай». **Погашено 7 контейнеров** (`docker stop` + `docker update --restart=no`, **НЕ `rm`**, папки `docker/*` целы): `homeassistant`, `mbusd`, `mosquitto`, `nodered`, `zigbee2mqtt`, `modbus-bridge`, **`ser2net`**. Все → `restart=no` / `exited`. **Проверено:** порты 502/1883/8123/1880 на TrueNAS **свободны**; `mallexxx.duckdns.org` **HTTP 200**; MQTT `modbus/#` на t610 живой (`23.11`/`25.04`); RTSP камеры `:8554` OPEN; `.197:502` CLOSED. **Caddy НЕ тронут.** `inpxer` / `inpx-web` / `library` по указанию Alex **НЕ трогались**. Полный разбор — **§5-кватер-Л** |
| ~~7~~ | ~~Static IP для t610 на роутере (сейчас DHCP)~~**✅ ВЫПОЛНЕНО 2026-09-14 (вечер-8, §5-кватер-И-1):** `dhcp.@host[1]` = `t610` / MAC `9c:8e:99:ef:3f:c5` / `192.168.2.176`, бэкап `/root/dhcp.bak-20260914-104152` | ✅ закрыто |
| 8 | Бэкап конфигов t610 → Mac + TrueNAS + git (Gitea `git.mallexxx.duckdns.org`). **📌 Добавить в бэкап:** `/config/.storage/http` (фикс `trusted_proxies`), сам `Caddyfile`, `/config/go2rtc.yaml` (камера + поворот `#rotate=90`), `/config/automations.yaml`, а также `data/config.template.tmpl` аддона `modbus-bridge` (там живёт маппинг реле котла) | ** СДЕЛАНА ЧАСТЬ 1/3 (2026-09-14):** git-синк в Gitea (`~/Automation/HA-ZONT-Modbus`, коммит `9d31118`, 4 файла: `configuration.yaml`, `automations.yaml`, `go2rtc.yaml`, `config.yml`). **✅ ЧАСТЬ 2/3 — АВТОБЭКАП НА TRUENAS РАБОТАЕТ** (см. §5-кватер-К). Осталась часть 3/3: копия на Mac. **⚠️ Caddyfile в автобэкап НЕ входит** — он на TrueNAS, не на t610 (учесть отдельно) |
| ~~8~~ | ~~Бэкап конфигов t610 → Mac + TrueNAS + git (Gitea `git.mallexxx.duckdns.org`). **📌 Добавить в бэкап:** `/config/.storage/http` (фикс `trusted_proxies`), сам `Caddyfile`, `/config/go2rtc.yaml` (камера + поворот `#rotate=90`), `/config/automations.yaml`, а также `data/config.template.tmpl` аддона `modbus-bridge` (там живёт маппинг реле котла)~~ **✅ ЗАКРЫТО ПОЛНОСТЬЮ (2026-09-14, ночная сессия): все 3/3 части сделаны.** ① **git-синк** в Gitea (`~/Automation/HA-ZONT-Modbus`, коммит `9d31118`, 4 файла: `configuration.yaml`, `automations.yaml`, `go2rtc.yaml`, `config.yml`); ② **автобэкап на TrueNAS** — крон юзером `nas` 03:30 ежедневно, ротация 14 (`[[family/plans/t610-backup-to-truenas]]`); ③ **копия на Mac** — ✅ **СДЕЛАНА (подтверждено Alex 2026-09-14)**. **⚠️ Caddyfile в автобэкап НЕ входит** — он на TrueNAS, не на t610 (учесть отдельно) | ✅ закрыто |
| ~~9~~ | ~~**Zigbee-реле котла → modbus-bridge**~~**✅✅ ВЫПОЛНЕНО + ПОДТВЕРЖДЕНО ALEX 2026-09-14 (вечер-13, §5-кватер-И-7):** `switch.boiler_controller_power` = **`slave 104, рег. 1`** (bidirectional). Бэкап `.bak-relay-20260914-200827` | ✅ закрыто |
**✅ Закрыто в этой сессии (2026-09-14, поздняя):**
@@ -1996,7 +1996,7 @@ curl -s -X POST -H "$HDR" -H "Content-Type: application/json" \
- **📹 Поворот камеры 90°** — `#rotate=90` в `/config/go2rtc.yaml` (нативный параметр go2rtc, работает при транскодинге). Поток стал `480x640`, кадр проверен, CPU `load 0.20`. **Alex: «Все хорошо, в ту»** — направление подтверждено. Канон — §5-кватер-И-6 (КАНОН-2). Бэкап `/config/go2rtc.yaml.bak-rotate-20260914-202817`, скрипт `~/tmp-t610/relay/patch_rotate.py`.
- **📹 B3 / Этап 4 закрыт** — факт-проверка роутера: `firewall.@redirect[0]` (MQTT) и `@rule[3]` `dest_ip=192.168.2.176` (ZONT MQTT → t610). Отдельного «GPON-роутера» нет.
- **📹 Caddy ПЕРЕСТРОЕН** — из `Caddyfile` убраны `cam.*` (камера на t610 по RTSP) и `nodered.*` (ingress HA); на t610 ведёт **только** `mallexxx.duckdns.org``192.168.2.176:80`. Обновлён [[family/how-to/truenas-infrastructure]].
- **⚠️ ОСТАЛОСЬ 1 пункт:** ① **п.8** — бэкап конфигов t610 (A3) → **✅ ЗАКРЫТ по факту 2026-09-14 (v4, см. [[family/plans/t610-backup-to-truenas]]):** git-синк (`9d31118`) + автобэкап на TrueNAS работает (датасет `backup/t610` `nas:nas`, SMB-шара `t610` id=3, pull-ключ в `backup/t610/.ssh/`, скрипт v4, крон id=3 `nas` 03:30, архив ~6 МБ / 162 файла → rclone → Mail.ru). **Хвост:** копия на Mac (часть 3/3) + `Caddyfile` (живёт на TrueNAS, не в t610-бэкапе); ② **п.6** — погасить на TrueNAS стек автоматизации (`homeassistant`/`mbusd`/`mosquitto`/`nodered`) — **РАЗБЛОКИРОВАН** (5-мк закрыт), **Caddy не гасить**. Хвост: ротация токена из remote `nolvu-landing`; в роутере `redirect[1]` HA `8123``.197` помечен `enabled='0'` — мёртвый, можно удалить.
- **✅✅ ОСТАЛОСЬ 0 пунктов (2026-09-14, ночь):** ① **п.8** — бэкап конфигов t610 (A3) → **✅ ЗАКРЫТ ПОЛНОСТЬЮ 3/3:** git-синк (`9d31118`) + автобэкап на TrueNAS (крон `nas` 03:30, ротация 14 → rclone → Mail.ru) + **копия на Mac (часть 3/3 сделана, подтверждено Alex 2026-09-14)**. См. [[family/plans/t610-backup-to-truenas]]. **Хвост:** `Caddyfile` в t610-бэкап не входит (он на TrueNAS — учесть отдельно); ② **п.6** — погасить на TrueNAS стек автоматизации → **✅ ВЫПОЛНЕНО 2026-09-14 (ночь), §5-кватер-Л:** погашено 7 контейнеров (`homeassistant`/`mbusd`/`mosquitto`/`nodered`/`zigbee2mqtt`/`modbus-bridge`/`ser2net`) + `library` по команде Alex, **Caddy не тронут**. **Остаток хвостов:** ротация токена из remote `nolvu-landing`; в роутере `redirect[1]` HA `8123``.197` помечен `enabled='0'` — мёртвый, можно удалить; `inpx-web`/`inpxer` в циклическом краше (не трогать).
- **✅ Синк конфигов в git (2026-09-14, ночь):** репозиторий `~/Automation/HA-ZONT-Modbus` → Gitea `git_admin/HA-ZONT-Modbus`, коммит **`9d31118`** (запушен, remote SHA = local). Синкнуто фактически изменившееся: `configuration.yaml` (http-блок → `.storage/http`; `modbus.host` `.197``.176`), `automations.yaml` (`device_id` перегенерированы, `light.0xa4c13882a4b42db0``light.bed_dimmer`, +`illuminance`, +`is_occupied`), **новый** `homeassistant/go2rtc.yaml`, `config.yml` (+реле котла slave 104/рег 1). `modbus_ha_bridge.py` и `scripts.yaml` — уже совпадали по sha256. **Паттерн: сначала sha256 прод↔репо, потом тянуть только diff.**
**✅ Закрыто / установлено в этой сессии (2026-09-14, позднейшая, Modbus-диагностика):**
@@ -2299,7 +2299,7 @@ curl -o /dev/null -w "%{http_code} %{content_type}\n" "http://192.168.2.176:8090
`/config/configuration.yaml.bak-cam-20260914-180801` (до блока), `.bak-camdev-20260914-181945`, `.bak-camdev2-*` (перед сменой input).
### 🧹 Осталось убрать
- `/config/go2rtc.yaml`**создан по ошибке, HA его не читает.** Удалить (спросить Alex).
- ~~`/config/go2rtc.yaml` — **создан по ошибке, HA его не читает.** Удалить (спросить Alex).~~**❌ ОТМЕНЕНО (2026-09-14, вечер-13, подтверждено фактом ночной сессией): файл УДАЛЯТЬ НЕЛЬЗЯ.** Он **нужен аддону `a889bffc_go2rtc-hardware`** (AlexxIT) — тот читает именно `/config/go2rtc.yaml`. Факт-проверка: файл существует, **1333 б, `-rw------- root:root`, mtime 20:28**, внутри финальный конфиг камеры (`usb_camera_h264: ffmpeg:device?video=/dev/video0&input_format=mjpeg&video_size=640x480#video=h264#rotate=90`). Прежняя пометка «создан по ошибке, HA его не читает» верна **только для встроенного go2rtc HA Core** (тот генерирует свой `/tmp/go2rtc_XXXX.yaml` и `/config/`-файл игнорирует). **Актуальный канон — §5-кватер-И-6 (КАНОН-2).**
### 🔑 HA Long-Lived Access Token (t610)
Выдан Alex'ом 2026-09-14. Хранится: `~/tmp-t610/ha_token.txt` (локально), этот док.
@@ -2885,11 +2885,11 @@ ssh root@192.168.2.176 'ha apps rebuild local_modbus-bridge && ha apps restart l
**Новые питфоллы (см. §5-кватер-И-3/И-5):** HA на t610 слушает **порт 80** (не 8123) — все REST-вызовы туда; из SSH-аддона Core недоступен (сетевая изоляция) → API вызывать с Mac; обход маскировщика — токен в файл + `read -r` (не `$(...)`) + заголовок из кусков; `pip install websocket-client` нужен **без** `--user` (venv).
**Осталось:** удалить `/config/go2rtc.yaml` (ждёт команды); снять устаревшую строку `cam.*` из `truenas-infrastructure.md`.
**Осталось:** ~~удалить `/config/go2rtc.yaml` (ждёт команды)~~**❌ ОТМЕНЕНО (вечер-13, подтверждено фактом): файл НЕ удалять, он нужен аддону `go2rtc-hardware`.** Строка `cam.*` из `truenas-infrastructure.md` — ✅ снята.
### 2026-09-14 (вечер-9-продолжение): unique_id, зона котельной, `Resource busy`
Разбор вопроса Alex «это штатный и единственный способ добавить usb камеру?». **Проверено по первоисточникам:** у `camera.ffmpeg` **нет** поля `unique_id` (только `input`/`name`/`extra_arguments`) → сущность не попадает в `entity_registry`**зону (`kotelnaia`) назначить нельзя** (`Entity not found`). Это **штатное ограничение**, а не дефект (офиц. FAQ HA: «This is not an error»). Generic Camera отвергает все локальные входы (`/dev/video0`, `ffmpeg:`, `v4l2:`, `file://``relative_url`). **Итог: для USB-вебки штатный путь ОДИН — `camera: platform: ffmpeg`.** ⚠️ **ЭТОТ ВЫВОД ❌ ОПРОВЕРГНУТ вечер-11** — верен был лишь в рамках «Core сам открывает устройство». Схема «внешний MJPEG-сервис + Generic Camera по URL» даёт и `unique_id`, и зону (см. запись вечер-11 выше). Также пойман и устранён новый питфолл: пробы Generic Camera держали `/dev/video0``Resource busy` → камера 500; лечение `ha core restart`. Полный разбор — **§5-кватер-И-5** и «Питфоллы» в §5-кватер-И-3.
**Осталось (ждёт Alex) — ✅ ОБА ВОПРОСА ЗАКРЫТЫ вечер-11:** камера **переименована** в «Камера котельной» и **получила зону** `kotelnaia` (через Generic Camera, а не переименованием); лишний `/config/go2rtc.yaml`**всё ещё на месте**, ждёт команды на удаление.
**Осталось (ждёт Alex) — ✅ ЗАКРЫТО:** камера **переименована** в «Камера котельной» и **получила зону** `kotelnaia` (через Generic Camera, а не переименованием); ~~лишний `/config/go2rtc.yaml` — **всё ещё на месте**, ждёт команды на удаление~~**❌ ОТМЕНЕНО (вечер-13, подтверждено фактом): файл НЕ лишний — он нужен аддону `a889bffc_go2rtc-hardware` и содержит боевой конфиг камеры с `#rotate=90`. Удаление сломало бы камеру.**
### 2026-09-14 (вечер-9): USB-камера заведена в HA — ⚠️ схема ПОЗЖЕ ЗАМЕНЕНА (вечер-11)
**Итог того момента:** камера работала через `camera: platform: ffmpeg` + `input: /dev/video0` в `configuration.yaml``camera.usb_camera`, кадр JPEG 640×480. Опровергнуты 5 путей (go2rtc-файл, go2rtc-интеграция, Generic Camera, `usb_camera`, by-id-путь).
@@ -3383,7 +3383,7 @@ docker update --restart=no <те же 7>
- 🔴 **`rm` НЕ делали.** Папки `/mnt/RED_2TB/docker/{ha,mbusd,mosquitto,nodered,zigbee2mqtt,modbus-bridge,ser2net}/` **целы** — откат = `docker start` + `docker update --restart=unless-stopped`.
- 🔴 **Caddy НЕ тронут** (17 доменов TrueNAS + `mallexxx.*` → t610).
- **`inpxer` / `inpx-web` / `library` — НЕ трогались** (Alex: «inpxer не трогай»).
- **`inpxer` / `inpx-web` — НЕ трогались** (Alex: «inpxer не трогай»). **`library` — погашен ПОЗЖЕ, отдельной командой Alex** (см. Л-4 п.1), в первую волну 7 контейнеров не входил.
### Л-3. Верификация (после гашения)
@@ -3400,7 +3400,7 @@ docker update --restart=no <те же 7>
### Л-4. ⚠️ Найденные минные поля (НЕ трогались — отдельное решение Alex)
1. 🔴 **`library` рестартует циклически — `RestartCount=29745`.** Caddy на него ссылается (`library.mallexxx.duckdns.org → library:8080`, basic_auth `books-admin`) → **домен сейчас мёртв**. Создан 24.08 09:11, падает непрерывно.
1. **`library` — ПОГАШЕН 2026-09-14 (по команде Alex).** Был в циклическом краше: `RestartCount=29752`, `state=restarting`, `restart=unless-stopped`. Caddy на него ссылается (`library.mallexxx.duckdns.org → library:8080`, basic_auth `books-admin`) → **домен сейчас мёртв** (и был мёртв до гашения). Сделано: `docker stop library` + `docker update --restart=no``state=exited`, `restart=no`. **Не удалён**, папка `/mnt/RED_2TB/docker/library/` цела. **Открыто:** почему падал (образ `library-app:latest` из `build: .` — локальная сборка, тот же паттерн, что утраченный `cups-splix`/камера при пересоздании пула) — копать при отдельной задаче.
2. 🔴 **Конфликт порта 502 (устранён гашением).** До гашения: `mbusd` и `ser2net` **оба** мапили `0.0.0.0:502`, **оба** просили `/dev/ttyVent:/dev/ttyUSB0`. `ser2net` в `Created` → при старте **порт был бы занят**. Теперь оба `restart=no`, конфликт снят.
3. 🔴 **`inpx-web` (порт 18081) и `inpxer` (порт 18080) — оба `Exited (1)`, `RestartCount=13`.** Caddy: `books.mallexxx.duckdns.org → 192.168.2.197:18080`**ведёт в мёртвый `inpxer`**. По указанию Alex **не трогались**.
4. ⚠️ **Секрет открытым текстом:** `HA_TOKEN` (long-lived HA, `eyJhbG...wkME`) прямо в `/mnt/RED_2TB/docker/modbus-bridge/docker-compose.yml``environment`. Кандидат на вынос в `.env` + ротацию. Также `MQTT_PASS: mqtt1z3$` там же.
@@ -3409,6 +3409,6 @@ docker update --restart=no <те же 7>
- [ ] Откат при необходимости: `docker start <name>` + `docker update --restart=unless-stopped <name>`
- [ ] **Удаление** — отдельным шагом, не раньше чем через 2–3 дня стабильной работы (Alex: сначала «остановить, не удалять»)
- [ ] Разобраться с `library` / `inpx-web` / `inpxer` (минные поля Л-4)
- [ ] Разобраться с `inpx-web` / `inpxer` (минное поле Л-4 п.3; `library` уже погашен)
- [ ] Вынести `HA_TOKEN` из compose в `.env` + ротация
- [ ] Ротация токена из remote `nolvu-landing` (хвост п.3-гт)