Forwarding of serial and USB ports over the network to openHAB

How I automated some usbip restarts after the connection between host and client was broken and re-established.

On the host (Pi 0 in my case):

sudo -s

#Identify your USB device. 0a12:0001 in my case.
lsusb

# Install usbip and setup the kernel module to load at startup
apt-get install usbip
modprobe usbip_host
echo 'usbip_host' >> /etc/modules

# Create a systemd service
nano /lib/systemd/system/usbipd.service

[Unit]
Description=usbip host daemon
After=network.target

[Service]
Type=forking
ExecStart=/usr/sbin/usbipd -D
ExecStartPost=/bin/sh -c "/usr/sbin/usbip bind --$(/usr/sbin/usbip list -p -l | grep '#usbid=0a12:0001#' | cut '-d#' -f1)"
ExecStop=/bin/sh -c "/usr/sbin/usbip unbind --$(/usr/sbin/usbip list -p -l | grep '#usbid=0a12:0001#' | cut '-d#' -f1); killall usbipd"

[Install]
WantedBy=multi-user.target

Enable and start it.

On the client (openHAB server):

# Create a separate service file for every shared USB device. Adjust IP. And if you have more then 2 clients: port=00, the Before= and After=.
sudo nano /lib/systemd/system/usbip.service

[Unit]
Description=USBIP Pi 0 Slaapkamer client
After=network.target
Before=usbip1.service
StartLimitIntervalSec=0

[Service]
Restart=always
RestartSec=30
#Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh -c "/usr/sbin/usbip attach -r 10.0.2.106 -b $(/usr/sbin/usbip list -r 10.0.2.106 | grep '0a12:0001' | cut -d: -f1)"
#ExecStop=/bin/sh -c "/usr/sbin/usbip detach --port=$(/usr/sbin/usbip port | grep '<Port in Use>' | sed -E 's/^Port ([0-9][0-9]).*/\1/')"
ExecStop=/bin/sh -c "/usr/sbin/usbip detach --port=00"

[Install]
WantedBy=multi-user.target

For reference, my second service file:

[Unit]
Description=USBIP Spin client
After=network.target usbip.service
StartLimitIntervalSec=0

[Service]
Restart=always
RestartSec=30
#Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh -c "/usr/sbin/usbip attach -r 10.0.1.1 -b $(/usr/sbin/usbip list -r 10.0.1.1 | grep '0a12:0001' | cut -d: -f1)"
#ExecStop=/bin/sh -c "/usr/sbin/usbip detach --port=$(/usr/sbin/usbip port | grep '<Port in Use>' | sed -E 's/^Port ([0-9][0-9]).*/\1/')"
ExecStop=/bin/sh -c "/usr/sbin/usbip detach --port=01"

[Install]
WantedBy=multi-user.target

Enable and start it.

items:

Switch Restart_BT_Pi0Slaapkamer "BT Pi Zero Slaapkamer opnieuw opstarten"   <network>                         { channel="exec:command:7b7959d5:run" }
Switch Restart_BT_Spin "BT Spin opnieuw opstarten"                          <network>                         { channel="exec:command:9c9a59d6:run" }
Switch Pi0slaapkamer "Pi Zero Slaapkamer"                                   <network> (gslaapkamer, gPis)     { channel="network:pingdevice:ca0875b9:online" }

rules:

var Timer SpinBTtimer = null
var Timer Pi0BTtimer = null

rule "Reboot local Spin BT service"
when
    Item Spin changed to ON
then
    logInfo("Spin BT restart Function", "1. Spin = " + Spin.state.toString)
    logInfo("Spin BT restart Function", "1. Restart_BT_Spin = " + Restart_BT_Spin.state.toString)
    if (SpinBTtimer === null) {
        SpinBTtimer = createTimer(now.plusSeconds(20), [ |
            logInfo("Spin BT restart Function", "2. Spin = " + Spin.state.toString)
            logInfo("Spin BT restart Function", "2. Restart_BT_Spin = " + Restart_BT_Spin.state.toString)
            Restart_BT_Spin.sendCommand(ON)
            logInfo("Spin BT restart Function", "3. Spin = " + Spin.state.toString)
            logInfo("Spin BT restart Function", "3. Restart_BT_Spin = " + Restart_BT_Spin.state.toString)
            SpinBTtimer = null // cancel the timer
        ])
    }
end

rule "Reboot local Pi 0 BT service"
when
    Item Pi0slaapkamer changed to ON
then
    logInfo("Pi 0 sk BT restart Function", "1. Pi 0 sk = " + Pi0slaapkamer.state.toString)
    logInfo("Pi 0 sk BT restart Function", "1. Restart_BT_Pi 0 sk = " + Restart_BT_Pi0Slaapkamer.state.toString)
    if (Pi0BTtimer === null) {
        Pi0BTtimer = createTimer(now.plusSeconds(20), [ |
            logInfo("Pi 0 sk BT restart Function", "2. Pi 0 sk = " + Pi0slaapkamer.state.toString)
            logInfo("Pi 0 sk BT restart Function", "2. Restart_BT_Pi 0 sk = " + Restart_BT_Pi0Slaapkamer.state.toString)
            Restart_BT_Pi0Slaapkamer.sendCommand(ON)
            logInfo("Pi 0 sk BT restart Function", "3. Pi 0 sk = " + Pi0slaapkamer.state.toString)
            logInfo("Pi 0 sk BT restart Function", "3. Restart_BT_Pi 0 sk = " + Restart_BT_Pi0Slaapkamer.state.toString)
            Pi0BTtimer = null // cancel the timer
        ])
    }
end

Furthermore you need the exec binding installed. Create a thing for every USB device with the command:

sudo /bin/systemctl restart usbip.service

I did this in paperUI, but you can also do it in .things file. Make sure your openHAB user has permission to execute sudo. See this topic.

Maybe a little complex, but it works. Only issue with this approach is that when the host stays online, but for some reason the USB device gets disconnected and reconnected, it will not be detected, thus rebooted. But this rarely happens in my use case (wifi signal lost, or host turned off/on).

Feedback is welcome! Especially if I can simplify this process!

2 Likes