feat: add usb watchdog to rpi running zwave stick

This commit is contained in:
Peter Ahinko 2026-04-09 23:19:05 +02:00
parent 616f2b361b
commit 0f56d3f444
No known key found for this signature in database
GPG key ID: A49FDC84B6AD510B
6 changed files with 156 additions and 3 deletions

View file

@ -9,5 +9,6 @@
- role: apt
- role: udev
- role: ser2net
- role: usb-watchdog
- role: wmbusmeters
- role: readonly

View file

@ -6,10 +6,10 @@
# Creates consistent device symlinks regardless of USB port
# IMST iU891A-XL USB stick (Cypress chipset)
SUBSYSTEM=="tty", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="0003", ATTRS{manufacturer}=="IMST", SYMLINK+="wmbus_stick", GROUP="dialout", MODE="0664"
SUBSYSTEM=="tty", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="0003", ATTRS{manufacturer}=="IMST", SYMLINK+="wmbus_stick", GROUP="dialout", MODE="0664", TAG+="systemd", ENV{SYSTEMD_WANTS}+="wmbusmeters-restart.service"
# Aeotec Z-Wave USB Stick Gen7 (Silicon Labs CP2102N chipset)
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{manufacturer}=="Silicon Labs", SYMLINK+="zwave_stick", GROUP="dialout", MODE="0664"
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{manufacturer}=="Silicon Labs", SYMLINK+="zwave_stick", GROUP="dialout", MODE="0664", TAG+="systemd", ENV{SYSTEMD_WANTS}+="ser2net-restart.service"
dest: /etc/udev/rules.d/99-usbdevices.rules
owner: root
group: root
@ -18,3 +18,37 @@
notify:
- reload udev
- trigger udev
- name: Create ser2net restart service for udev trigger
copy:
content: |
[Unit]
Description=Restart ser2net after Z-Wave stick reconnect
[Service]
Type=oneshot
ExecStartPre=/bin/sleep 2
ExecStart=/bin/systemctl restart ser2net
dest: /etc/systemd/system/ser2net-restart.service
owner: root
group: root
mode: "0644"
become: yes
notify: reload udev
- name: Create wmbusmeters restart service for udev trigger
copy:
content: |
[Unit]
Description=Restart wmbusmeters after W-MBus stick reconnect
[Service]
Type=oneshot
ExecStartPre=/bin/sleep 2
ExecStart=/bin/systemctl restart wmbusmeters
dest: /etc/systemd/system/wmbusmeters-restart.service
owner: root
group: root
mode: "0644"
become: yes
notify: reload udev

View file

@ -0,0 +1,4 @@
---
- name: reload systemd
ansible.builtin.systemd:
daemon_reload: true

View file

@ -0,0 +1,49 @@
---
- name: Install usb-watchdog script
ansible.builtin.template:
src: templates/usb-watchdog.sh.j2
dest: /usr/local/bin/usb-watchdog
owner: root
group: root
mode: "0755"
- name: Install usb-watchdog service
ansible.builtin.copy:
content: |
[Unit]
Description=USB stick watchdog (Z-Wave and W-MBus)
After=local-fs.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/usb-watchdog
dest: /etc/systemd/system/usb-watchdog.service
owner: root
group: root
mode: "0644"
notify: reload systemd
- name: Install usb-watchdog timer
ansible.builtin.copy:
content: |
[Unit]
Description=Run USB stick watchdog every 30s
[Timer]
OnBootSec=30
OnUnitActiveSec=30
[Install]
WantedBy=timers.target
dest: /etc/systemd/system/usb-watchdog.timer
owner: root
group: root
mode: "0644"
notify: reload systemd
- name: Enable usb-watchdog timer
ansible.builtin.systemd:
name: usb-watchdog.timer
enabled: true
state: started
daemon_reload: true

View file

@ -0,0 +1,59 @@
#!/bin/bash
# USB stick watchdog for Z-Wave and Wireless M-Bus dongles
# Recovery: USB reset, then reboot if device was previously working this boot.
ALIVE_DIR="/tmp/usb-watchdog"
mkdir -p "$ALIVE_DIR"
check_device() {
local name="$1"
local device="$2"
local vendor="$3"
local product="$4"
local service="$5"
local alive_flag="$ALIVE_DIR/$name"
if [ -e "$device" ]; then
touch "$alive_flag"
return 0
fi
logger -t usb-watchdog "$name: $device not found, attempting USB reset"
# Try USB unbind/rebind
for usbdev in /sys/bus/usb/devices/*/idVendor; do
dir=$(dirname "$usbdev")
if [ "$(cat "$dir/idVendor" 2>/dev/null)" = "$vendor" ] && \
[ "$(cat "$dir/idProduct" 2>/dev/null)" = "$product" ]; then
devname=$(basename "$dir")
echo "$devname" > /sys/bus/usb/drivers/usb/unbind 2>/dev/null
sleep 2
echo "$devname" > /sys/bus/usb/drivers/usb/bind 2>/dev/null
sleep 3
break
fi
done
if [ -e "$device" ]; then
logger -t usb-watchdog "$name: recovered after USB reset"
touch "$alive_flag"
systemctl restart "$service"
return 0
fi
# Only reboot if device was working before
if [ ! -f "$alive_flag" ]; then
logger -t usb-watchdog "$name: never seen since boot, not rebooting (manual intervention required)"
return 1
fi
logger -t usb-watchdog "$name: was working but not recovered, rebooting"
reboot
}
needs_reboot=0
check_device "zwave" "/dev/zwave_stick" "10c4" "ea60" "ser2net" || needs_reboot=1
check_device "wmbus" "/dev/wmbus_stick" "04b4" "0003" "wmbusmeters" || needs_reboot=1
exit $needs_reboot

View file

@ -67,10 +67,16 @@
recurse: yes
become: yes
- name: Configure wmbusmeters
ansible.builtin.command:
cmd: ./configure
chdir: "{{ wmbusmeters_home }}/wmbusmeters-src"
become: yes
- name: Build wmbusmeters
make:
chdir: "{{ wmbusmeters_home }}/wmbusmeters-src"
jobs: "{{ ansible_processor_cores }}"
jobs: "{{ ansible_facts['processor_cores'] }}"
become: yes
environment:
HOME: "{{ wmbusmeters_home }}"