5.0 KiB
status, tags, title, updated
| status | tags | title | updated | ||||
|---|---|---|---|---|---|---|---|
| implemented |
|
Защита modbus-bridge от гонки с udev (ZONT датчики) | 2026-08-25 |
Защита modbus-bridge/mbusd от гонки с udev (ZONT датчики)
Статус: внедрено (2026-08-25, шаги 1–3). Датчики в ZONT снова отвечают, скрипт и init script на месте.
Проблема
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): гонка загрузки TrueNAS — docker стартовал раньше udev, /dev/ttyZONT и /dev/ttyVent ещё не существовали → контейнеры modbus-bridge (Exit 128) и mbusd (Exit 255) упали на старте:
error gathering device information while adding custom device "/dev/ttyZONT": no such file or directory (RestartCount=0).
Фикс был: ручной docker start modbus-bridge mbusd.
Почему контейнеры сами НЕ поднялись (RestartCount=0)
restart: unless-stopped/always ретраит в ДВУХ случаях:
- Процесс контейнера стартовал и завершился с ненулевым кодом → демон ретраит с backoff.
- Перезапуск docker daemon → демон пробует поднять
unless-stopped/alwaysконтейнеры.
Наш случай — ТРЕТИЙ, особый: контейнер вообще не стартовал — ошибка на этапе монтирования устройства.
- Нет процесса, который «завершился бы» → restart policy не на что применять →
RestartCount=0, демон не ретраит. - После падения (13:24) демон не перезапускался → второго триггера не было. Вывод: отказ на этапе mount устройства НЕ перезапускается restart policy. Авто-подъём гарантирован только скриптом, ждущим устройства.
Ключевое ограничение (задержка в entrypoint НЕ помогает)
У обоих контейнеров устройство проброшено через devices: /dev/ttyZONT:/dev/ttyUSB0 / devices: /dev/ttyVent:/dev/ttyUSB0.
Docker при start монтирует устройство ДО запуска процесса — если <src> отсутствует на момент старта, контейнер вообще не стартует, и sleep внутри entrypoint/CMD не выполняется. Поэтому решение — на уровне init скрипта.
Внедрённое решение
1. Скрипт /mnt/RED_2TB/system/start-modbus.sh (root, -rw-r--r--)
Ожидает появления tty-алиасов от udev (до ~50с), затем запускает контейнеры:
#!/bin/bash
# Ждём tty-алиасы от udev (макс ~25с), затем стартуем modbus контейнеры.
for i in $(seq 1 50); do
[ -e /dev/ttyZONT ] && [ -e /dev/ttyVent ] && break
sleep 1
done
sleep 2
docker start modbus-bridge mbusd 2>/dev/null
2. Init script (TrueNAS, id=3)
- when: POSTINIT, type: COMMAND, timeout: 30, enabled: true
- command:
bash /mnt/RED_2TB/system/start-modbus.sh - comment:
Start modbus-bridge/mbusd after udev tty aliases
Порядок POSTINIT скриптов
| id | command | comment | enabled |
|---|---|---|---|
| 1 | cp .../99-tty-alias.rules /etc/udev/rules.d/ && udevadm control --reload-rules && udevadm trigger |
Map ttyUSB | ✅ |
| 2 | bash /mnt/RED_2TB/system/tunnel.sh & |
— | ✅ |
| 3 | bash /mnt/RED_2TB/system/start-modbus.sh |
Start modbus-bridge/mbusd after udev tty aliases | ✅ |
Проверка
/dev/ttyZONT→ttyUSB1(CH340),/dev/ttyVent→ttyUSB0— симлинки появляются после POSTINIT id=1.- После reboot:
docker ps— modbus-bridge и mbusd Up; датчики в ZONT отвечают. - Просмотр init scripts:
midclt call initshutdownscript.query - Откат:
midclt call initshutdownscript.delete <ID>+ удалить скрипт с диска.
Связанные заметки
- family/how-to/home-automation.md — карта slave ID, ZONT, датчики
- family/how-to/truenas-infrastructure.md — docker, modbus-bridge, mbusd, udev rules, init scripts