So, one of the most difficult things about Home Assistant is that it often must use usb devices to communicate to the external world. Well, this post outlines one way to get Home Assistant setup as a usbip client. Then, it is possible to make home assistant a truly portable and contanered application.
Things To Consider
So, first this is a unsecure protocol it is raw usb over ip. Therefor, if this is sent outside of a LAN type network the data can be inspected. So, If it is planned to be used in a remote connection approach then I would wrap that within some sort of VPN and VLAN configuration. Technically, I would recommend running all of this in its own VLAN and maybe even limiting the access of outbound traffic to HTTP and HTTPS so that the docker images can be received. Anyway, that is beyond the scope of this post. I just wanted to remind everyone that this is not secure and security should be considered with this especially with so many IOT items that may be used with HomeAssistant.
Step 1 – Configure a usbip server
First, we have to have a Debian instance running and attached to a usb device. Raspberry Pi is a good candidate for this option. Especially, if running with a wifi adapter. Then, it is possible to setup the usb dongle in the most central location. Thus, optimizing for use and access to associated devices.
1.a – Install usbip and usbutils
sudo apt install -y usbip usbutils
sudo usbipd -D
sudo modprobe usbip_host
sudo echo "usbip_host" | sudo tee -a /etc/modules
sudo usbip list -lp
This should output:
- busid 2-1 (10c4:ea60)
Silicon Labs : CP210x UART Bridge (10c4:ea60)
- busid 2-2 (10c4:ea60)
Silicon Labs : CP210x UART Bridge (10c4:ea60)
1.b – Create usbip Host Service
So, it appears usbip is installed so now it is time to go ahead and create the needed service on the host server. Its job is simple. It will loop through all of the usb devices attached to this device and bind them. Please note: this may cause problems if it is desired to limit the devices served. I will address that in the next update to this code. Thank you for your patients this entire process is complex. I think I will write simple node.js server and client that will update the list and eventually be run as the services on the host and client to keep desired devices in sync. That is what I would like to do anyway then a simple UI where you add the devices to be served. Vola! Then they are available on the associated client. Even to the point where you can specify what client gets what usb device. Wouldn’t that be cool! Someday, I will write it.
For now, here is the simplified service.
Switch to sudo -i for simplicity for now
sudo -i
Create the service file
nano /etc/systemd/system/usbiphost.service
Put the following text in the file.
[Unit]
Description=usbip host daemon
After=network.target
[Service]
Type=forking
ExecStart=/usr/sbin/usbipd -D
ExecStartPost=/bin/sh -c "/lib/systemd/system/usbipdup.sh"
ExecStop=/bin/sh -c "/lib/systemd/system/usbipddwn.sh"
[Install]
WantedBy=multi-user.target
Create the Up Script mentioned in the service.
nano /lib/systemd/system/usbipdup.sh
Paste the following text in it
#!/bin/bash
for i in `usbip list -lp | grep 'busid' | cut '-d ' -f4`; do
usbip bind -b "$i";
done
Create the Down Script as mention in the service.
nano /lib/systemd/system/usbipddwn.sh
Place the following test in it.
#!/bin/bash
for i in `usbip list -lp | grep 'busid' | cut '-d ' -f4`; do
usbip unbind -b "$i";
done
Do a chmod on the shell scripts that were created.
chmod +x /lib/systemd/system/usbipdup.sh
chmod +x /lib/systemd/system/usbipddwn.sh
Now, setup the service. Oh, for now I would recommend running via ssh and not having any usb mouse device plugged in. Otherwise it will be taken over and you will lose the ability to use keyboard and mouse. This is because it is currently designed to take over everything that usbip list -lp can find. Once the service is up and running you can plug your mouse back in!.
systemctl enable usbiphost.service
service usbiphost start
If any problems arise use journalctl -xeu usbiphost.service to help troubleshoot.
journalctl -xeu usbiphost.service
If you have to make changes to the shell scripts or the service run systemctl daemon-reload to resync everything
systemctl daemon-reload
Step 2 – Configure a usbip client in home assistant pod.
sudo apt install -y usbip usbutils
sudo modprobe vhci-hcd
sudo echo "vhci-hcd" | sudo tee -a /etc/modules
sudo usbip attach -r 192.168.1.172 -d 3-1
lsusb
Bus 002 Device 002: ID 10c4:ea60 Silicon Labs CP210x UART Bridge
Step 3a – Make USBIP Run as a Service on server and in Home Assistant Pod.
Final step, At least for this first rendition is to make services for both home assistant pod and usbip server. This way they will auto start on reboot. Now, I have not got this 100 percent yet; however, I wanted to share what I do have working and then as I finalize my setup I will add the other elements to this post.
Below, is the /etc/systemd/system/usbipclient.service
nano /etc/systemd/system/usbipclient.service
[Unit]
Description=usbip client daemon
After=network.target
[Service]
Type=forking
ExecStart=/usr/sbin/usbipd -D
ExecStartPost=/bin/sh -c "/lib/systemd/system/usbipdup.sh"
ExecStop=/bin/sh -c "/lib/systemd/system/usbipddwn.sh"
[Install]
WantedBy=multi-user.target
This is the /lib/systemd/system/usbipdup.sh
script so open a text file with a editor such as nano.
nano /lib/systemd/system/usbipdup.sh
Paste in the following code.
#!/bin/bash
for i in `/usr/sbin/usbip list -r 192.168.1.129 -l | grep ':' | cut '-d:' -f1`; do
/usr/sbin/usbip attach -r 192.168.1.129 -d "$i";
echo "Attaching Port: $i"
done
This is the /lib/systemd/system/usbipddwn.sh
nano /lib/systemd/system/usbipddwn.sh
#!/bin/bash
for i in `/usr/sbin/usbip port | grep 'Port' | cut '-d:' -f1 | cut '-d ' -f2`; do
/usr/sbin/usbip detach -p "$i";
done
Now fix permissions and enable the service.
chmod +x /lib/systemd/system/usbipdup.sh
chmod +x /lib/systemd/system/usbipddwn.sh
Oh, and here is how to check the status of the service
journalctl -xeu usbipclient.service
Sometimes it is needed to resync the script to the systemctl daemon
systemctl daemon-reload
So now enable and test start and stop of the service
systemctl enable usbipclient.service
service usbipclient stop
service usbipclient start
other client commands
sudo usbip list -r 192.168.1.172
Exportable USB devices
======================
- 192.168.1.172
3-1: Silicon Labs : CP210x UART Bridge (10c4:ea60)
: /sys/devices/pci0000:00/0000:00:1d.0/usb3/3-1
: (Defined at Interface level) (00/00/00)
: 0 - Vendor Specific Class / unknown subclass / unknown protocol (ff/00/00)
sudo usbip port
Imported USB devices
====================
Port 00: <Port in Use> at Full Speed(12Mbps)
Silicon Labs : CP210x UART Bridge (10c4:ea60)
2-1 -> usbip://192.168.1.172:3240/3-1
-> remote bus/dev 003/002
sudo usbip detach -p 00
usbip: info: Port 0 is now detached!
Step 3b – Make Work With Debian 12 Supervisor HomeAssistant
See Common Errors Typically occurs because usbipd -D was not ran on server and so client cannot create a tcp port. Typically, occurs when client is already ported in device from server. I found a windows version today. I have not tried it, but I will. I think I want to resurrect this process for my current home assistant. So, this would be a good time to test this out. I will follow up with more info in the near future. This is my next Home Assistant improvement! I am sick of having it running on one specific proxmox server. This is defeating my proxmox setup as I cannot move HA (Home Assistant) where I want it. So, I will try windows as a server in the effort to test usbip out!tcp connect
debian@usbip-2:~$ sudo usbip attach -r 192.168.1.172 -d 3-1
usbip: error: tcp connectDevice busy (exported)
debian@usbip-2:~$ sudo usbip attach -r 192.168.1.172 -d 3-1
usbip: error: Attach Request for 3-1 failed - Device busy (exported)
Windows Version