--- title: 'План: защита modbus-bridge от гонки с udev (ZONT датчики)' tags: - plan - family - homeautomation - zont - modbus updated: '2026-08-25' status: proposed --- # План: защита modbus-bridge/mbusd от гонки с udev (после рестарта TrueNAS) > Статус: **план на согласование** (2026-08-25), ничего не применено. > Задача: исключить повторение «485-датчики недоступные в ZONT» после перезагрузки TrueNAS. ## Контекст / причины - ZONT (192.168.0.10) — Modbus master на RS-485 шине `ttyZONT`. 485-датчики: Dining=1, Kids=2, Bedroom=3. - Контейнер `modbus-bridge` сниффит их и подставляет виртуальные slaves 101/102/103 → ZONT опрашивает как внешние датчики. - Если modbus-bridge не слушает шину → ZONT показывает датчики «недоступные». - Первопричина 2026-08-25: **гонка загрузки** — docker стартовал раньше udev, `/dev/ttyZONT` и `/dev/ttyVent` ещё не существовали → контейнеры упали на старте: `error gathering device information while adding custom device "/dev/ttyZONT": no such file or directory` (ExitCode 128/255, RestartCount=0). - `restart: unless-stopped` **не перезапускает** контейнер, упавший на этапе `docker start` (binding device fail) — отказ до старта процесса. ## Ключевое ограничение (почему задержка в entrypoint НЕ поможет в чистом виде) У modbus-bridge и mbusd устройство проброшено через `devices: /dev/ttyZONT:/dev/ttyUSB0` / `devices: /dev/ttyVent:/dev/ttyUSB0`. **Docker при `start` монтирует устройство ДО запуска процесса** — если `` не существует на _момент создания/старта контейнера_, контейнер вообще не стартует, и `sleep` внутри entrypoint/CMD никогда не выполнится. → Простой «sleep N в entrypoint» проблему НЕ решает. ## Почему контейнеры сами НЕ поднялись (RestartCount=0) — разбор `restart: unless-stopped`/`always` ретраит в ДВУХ случаях: 1. **Процесс контейнера стартовал и завершился** с ненулевым кодом → демон ретраит с backoff (RestartCount растёт). 2. **Перезапуск самого docker daemon** → демон пробует поднять `unless-stopped`/`always` контейнеры. Наш случай — ТРЕТИЙ, особый: контейнер **вообще не стартовал** — ошибка на этапе монтирования устройства: `error gathering device information while adding custom device "/dev/ttyZONT": no such file or directory`. - Нет процесса, который «завершился бы» — docker не смог примонтировать устройство, процесс не запущен вовсе. - Раз нет завершённого процесса, **restart policy не на что применять** → `RestartCount=0`, демон не ретраит. - После падения (13:24) демон НЕ перезапускался (docker.pid с 07:14) → второго триггера не было. Вывод: **отказ на этапе mount устройства НЕ перезапускается restart policy**. Авто-подъём при перезагрузке гарантирован только если устройства существуют на момент старта демона. Иначе — контейнеры молча остаются в exited до ручного `docker start`. ## Решение (рекомендуемое): POSTINIT init script с ожиданием + docker start Уже есть init script id=1 «Map ttyUSB» (POSTINIT), который копирует udev-правила и делает `udevadm trigger`. Он НЕ ждёт создания симлинков и не запускает докер-контейнеры. Добавить новый POSTINIT init script (COMMAND, when=POSTINIT, enabled=true), который: 1. Ждёт появления `/dev/ttyZONT` и `/dev/ttyVent` (poll до ~20 сек). 2. Как только оба есть — `docker start modbus-bridge mbusd`. 3. Если docker ещё не готов — также пробует переждать. Пример скрипта (положить в `/mnt/RED_2TB/system/start-modbus.sh`): ```bash #!/bin/bash # Ожидание tty-алиасов от udev (макс ~25 сек) for i in $(seq 1 25); do [ -e /dev/ttyZONT ] && [ -e /dev/ttyVent ] && break sleep 1 done sleep 2 # небольшая пауза на устойчивость udev docker start modbus-bridge mbusd 2>/dev/null ``` Команда в TrueNAS init: `bash /mnt/RED_2TB/system/start-modbus.sh` Timeout скрипта в TrueNAS: `30`. > Альтернатива (не рекомендуется): поменять `devices:` на прямой `/dev/ttyUSB1`/`/dev/ttyUSB0` — но номер ttyUSB может прыгать, алиасы для того и нужны. > Примечание: менять Dockerfile/entrypoint и/или `restart: always` здесь **недостаточно** — отказ на этапе mount устройства restart policy не обрабатывает. ## Шаги внедрения (после согласования) 1. Создать `/mnt/RED_2TB/system/start-modbus.sh` на TrueNAS (chmod +x). 2. Добавить init script через midclt: ```bash midclt call initshutdownscript.create '{"type":"COMMAND","command":"bash /mnt/RED_2TB/system/start-modbus.sh","when":"POSTINIT","enabled":true,"timeout":30,"comment":"Start modbus-bridge/mbusd after udev tty aliases"}' ``` 3. Проверить: `midclt call initshutdownscript.query` 4. Проверить после reboot: контейнеры Up, `ttyZONT`/`ttyVent` созданы, датчики в ZONT отвечают. ## Вердикт по исходному вопросу «добавить задержку в entrypoint» - Задержка внутри entrypoint/CMD для этих контейнеров **не выполняется** из-за device mount до старта процесса → этот путь отпадает. - Правильный эквивалент «задержки до готовности» — скрипт выше на уровне TrueNAS init (ожидание устройств, затем `docker start`). ## Связанные заметки - [[family/how-to/home-automation.md]] — карта slave ID, ZONT, датчики - [[family/how-to/truenas-infrastructure.md]] — docker, modbus-bridge, mbusd, udev rules, init scripts