diff --git a/ansible/provision_iot.yaml b/ansible/provision_iot.yaml index 368e92970..529b960c4 100644 --- a/ansible/provision_iot.yaml +++ b/ansible/provision_iot.yaml @@ -9,5 +9,6 @@ - role: apt - role: udev - role: ser2net + - role: usb-watchdog - role: wmbusmeters - role: readonly diff --git a/ansible/roles/udev/tasks/main.yaml b/ansible/roles/udev/tasks/main.yaml index 619ea9789..65b5abf25 100644 --- a/ansible/roles/udev/tasks/main.yaml +++ b/ansible/roles/udev/tasks/main.yaml @@ -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 diff --git a/ansible/roles/usb-watchdog/handlers/main.yaml b/ansible/roles/usb-watchdog/handlers/main.yaml new file mode 100644 index 000000000..61cca3447 --- /dev/null +++ b/ansible/roles/usb-watchdog/handlers/main.yaml @@ -0,0 +1,4 @@ +--- +- name: reload systemd + ansible.builtin.systemd: + daemon_reload: true diff --git a/ansible/roles/usb-watchdog/tasks/main.yaml b/ansible/roles/usb-watchdog/tasks/main.yaml new file mode 100644 index 000000000..523747986 --- /dev/null +++ b/ansible/roles/usb-watchdog/tasks/main.yaml @@ -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 diff --git a/ansible/roles/usb-watchdog/templates/usb-watchdog.sh.j2 b/ansible/roles/usb-watchdog/templates/usb-watchdog.sh.j2 new file mode 100644 index 000000000..e169983f4 --- /dev/null +++ b/ansible/roles/usb-watchdog/templates/usb-watchdog.sh.j2 @@ -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 diff --git a/ansible/roles/wmbusmeters/tasks/main.yaml b/ansible/roles/wmbusmeters/tasks/main.yaml index 8dce69973..2c34631b3 100644 --- a/ansible/roles/wmbusmeters/tasks/main.yaml +++ b/ansible/roles/wmbusmeters/tasks/main.yaml @@ -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 }}"