Files
obsidian-vault/family/how-to/zont-modbus-bridge-udev-race-protection.md
T

73 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
status: implemented
tags:
- family
- homeautomation
- zont
- modbus
title: Защита modbus-bridge от гонки с udev (ZONT датчики)
updated: '2026-08-25'
---
# Защита modbus-bridge/mbusd от гонки с udev (ZONT датчики)
> Статус: **внедрено** (2026-08-25, шаги 13). Датчики в 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` ретраит в ДВУХ случаях:
1. Процесс контейнера **стартовал и завершился** с ненулевым кодом → демон ретраит с backoff.
2. **Перезапуск 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с), затем запускает контейнеры:
```bash
#!/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