#!/bin/sh # # MQTT Bridge monitor daemon # Scans configured USB adapters/presets and updates UCI with live metadata. . /lib/functions.sh UCI_NAMESPACE="mqtt-bridge" LOGTAG="mqtt-bridge-monitor" SCAN_INTERVAL=10 COMMIT_NEEDED=0 log_msg() { logger -t "$LOGTAG" "$*" } find_usb_device() { local vendor="$1" local product="$2" local dev for dev in /sys/bus/usb/devices/*; do [ -f "$dev/idVendor" ] || continue [ -f "$dev/idProduct" ] || continue local idVendor idProduct idVendor="$(cat "$dev/idVendor" 2>/dev/null)" idProduct="$(cat "$dev/idProduct" 2>/dev/null)" [ "$idVendor" = "$vendor" ] || continue [ "$idProduct" = "$product" ] || continue echo "$dev" return 0 done return 1 } find_usb_tty() { local base="$1" local path node for path in "$base" "$base"/* "$base"/*/*; do [ -d "$path/tty" ] || continue for node in "$path"/tty/*; do [ -e "$node" ] || continue local tty tty="$(basename "$node")" [ -e "/dev/$tty" ] && { echo "/dev/$tty"; return 0; } done done return 1 } set_option_if_changed() { local section="$1" local key="$2" local value="$3" local current current="$(uci -q get ${UCI_NAMESPACE}.adapter.${section}.${key} 2>/dev/null)" [ "$current" = "$value" ] && return uci set ${UCI_NAMESPACE}.adapter.${section}.${key}="$value" COMMIT_NEEDED=1 } clear_option_if_needed() { local section="$1" local key="$2" local current current="$(uci -q get ${UCI_NAMESPACE}.adapter.${section}.${key} 2>/dev/null)" [ -z "$current" ] && return uci delete ${UCI_NAMESPACE}.adapter.${section}.${key} COMMIT_NEEDED=1 } update_adapter_section() { local section="$1" local enabled vendor product title preset config_get enabled "$section" enabled "1" config_get vendor "$section" vendor config_get product "$section" product config_get preset "$section" preset config_get title "$section" title if [ "$enabled" != "1" ]; then set_option_if_changed "$section" detected "0" set_option_if_changed "$section" health "disabled" return fi if [ -z "$vendor" ] || [ -z "$product" ]; then set_option_if_changed "$section" detected "0" set_option_if_changed "$section" health "unknown" return fi local dev_path dev_path="$(find_usb_device "$vendor" "$product")" || dev_path="" local prev_detected prev_detected="$(uci -q get ${UCI_NAMESPACE}.adapter.${section}.detected 2>/dev/null)" if [ -n "$dev_path" ]; then local bus devnum port ts bus="$(cat "$dev_path/busnum" 2>/dev/null)" devnum="$(cat "$dev_path/devnum" 2>/dev/null)" port="$(find_usb_tty "$dev_path")" ts="$(date -Iseconds)" set_option_if_changed "$section" detected "1" set_option_if_changed "$section" health "online" [ -n "$bus" ] && set_option_if_changed "$section" bus "$bus" [ -n "$devnum" ] && set_option_if_changed "$section" device "$devnum" if [ -n "$port" ]; then set_option_if_changed "$section" port "$port" else clear_option_if_needed "$section" port fi set_option_if_changed "$section" last_seen "$ts" if [ "$prev_detected" != "1" ]; then log_msg "Adapter $section ($title) detected on bus $bus dev $devnum $port" fi else set_option_if_changed "$section" detected "0" set_option_if_changed "$section" health "missing" clear_option_if_needed "$section" port clear_option_if_needed "$section" bus clear_option_if_needed "$section" device if [ "$prev_detected" = "1" ]; then log_msg "Adapter $section ($title) disconnected" fi fi } scan_loop() { while true; do COMMIT_NEEDED=0 config_load "$UCI_NAMESPACE" local interval config_get interval monitor interval [ -n "$interval" ] && SCAN_INTERVAL="$interval" config_foreach update_adapter_section adapter if [ "$COMMIT_NEEDED" -eq 1 ]; then uci commit "$UCI_NAMESPACE" fi sleep "$SCAN_INTERVAL" done } scan_loop