RPi as Z-Wave/ZigBee-over-IP server for Hass

Can you recommend which?

Hey guys, thanks to @luma for this idea. Whilst this was not successful with my Aeotec Z-Stick it got me thinking about this idea and lead me to find the following discussion on the OpenHAB forums which worked perfectly for my Z-Stick connected to a RPi and my Ubuntu 16.04 virtual server running HASS on a Windows 2008 Server R2 Host.

2 Likes

He Guys, I am trying to install this on Hassbian with the latest version of Home Assistant 0.68.1 and Python 3.6, but I am getting an error:
Setting up python-distlib (0.2.4-1) …
Traceback (most recent call last):
File “/usr/bin/pycompile”, line 35, in
from debpython.version import SUPPORTED, debsorted, vrepr,
File “/usr/share/python/debpython/version.py”, line 24, in
from ConfigParser import SafeConfigParser
ImportError: No module named ‘ConfigParser’
dpkg: error processing package python-distlib (–configure):
subprocess installed post-installation script returned error exit status 1
Setting up python-ndg-httpsclient (0.4.2-1) …
Traceback (most recent call last):
File “/usr/bin/pycompile”, line 35, in
from debpython.version import SUPPORTED, debsorted, vrepr,
File “/usr/share/python/debpython/version.py”, line 24, in
from ConfigParser import SafeConfigParser
ImportError: No module named ‘ConfigParser’
dpkg: error processing package python-ndg-httpsclient (–configure):
subprocess installed post-installation script returned error exit status 1
Errors were encountered while processing:
python-distlib
python-ndg-httpsclient
E: Sub-process /usr/bin/dpkg returned an error code (1)

I believe that the problem could be the Python version that I am running? Any help is highly appreciated!

If you can run/build your docker image - this one has socat built-in.

If you don’t want to use docker, just take some inspiration from the scripts in the /runwatch/ folder - they monitor socat and home assistant and restart where needed - but you’ll need to modify the start/stop/check commands probably…

Also, on the server/pi with the zwave stick, don’t forget to map the stick to a fixed /dev/ like

then modify

RUN+=\"/bin/x-hass-restart-zwave-replug\

to point to a script that restart socat (or just do something like this in the script :

kill -9 $( pregp socat)
socat <params...>

Additionally if you know how to setup ssh keys, you can run a command to restart ser2net on the home assistant server (which will also trigger a home assistant restart).

This way if any part of the chain is broken, the rest will restart/reconnect…

Just wanted to share my setup which uses socat on both sides. I have a RPi with a Aeotec Z-Stick 5, and I’m running Home Assistant in a VM.

The Aeotec z-stick device was exposed as a serial device, so I felt doing usbip to be overkill, so I found the solution where someone used socat on server side and ser2net on the client to be more appropriate. While poking around, I found out that socat can be used on the client side as well, symmetry ftw!

Server Side

I’m running raspbian on a RPi. I use a dedicated user named hass which is added to group dialout to allow access to the device (or you can use root).

[Unit]
Description=Z-Wave Remote Server
After=network-online.target

[Service]
Type=simple
User=hass
ExecStart=/usr/bin/socat tcp-l:59595,reuseaddr,keepalive,nodelay file:/dev/ttyACM0,nonblock,raw
Restart=always
StartLimitIntervalSec=0
StartLimitBurst=0

[Install]
WantedBy=multi-user.target

Client Side

I have this running on the VM with home assistant. I’m also running it as hass, because my home assistant also runs under user hass, otherwise you will have a permission issue on the device.

[Unit]
Description=Z-Wave Remote Client
After=network-online.target

[Service]
Type=simple
User=hass
ExecStart=/usr/bin/socat pty,link=/var/lib/zwave/remotezwave,ignoreof,echo=0 tcp:RIPHOSTNAME:59595,forever
Restart=always
StartLimitIntervalSec=0
StartLimitBurst=0

[Install]
WantedBy=multi-user.target

Cheers.

EDIT: Okay, so the forever option was just for the initial connection, it wasn’t actually reconnecting. Anyways, relying on the systemd restart mechanism was a lot more reliable, plus I was able to use the journald logs to figure out when things go wrong (ie. client/server disconnected).

11 Likes

Excellent guide. I really think socat is a better solution for Z-Wave/ZigBee and I probably should move my environment over to that config. Thanks for sharing!

Could you do an example for us linux newbies ? :slight_smile:

2 Likes

Is there anything else to setup for the usbip? I have it all configured, the ports connect, dev on the HA machine has the correct USB ports listed… and it cant find anything. It seems so simple but it just wont connect.

I gave-up on the usbip method and went the ser2net and socat route.

Unfortunately none of this will work if you run HA in docker.

I am using usbip on my docker host running debian, works fine for me.
The virtual usb port is exposed on the docker host, and mapped into the docker container as usual.

Edit: The one problem I have with this setup is that a reboot of the docker host messes up the usbip server running on my rpi, it seems to be somewhat fragile when loosing connection unexpectedly. Fully stable when both machines are up and running though.
Are socat/ser2net better att handling dropped connections and machines rebooting?

Would this go into socatd.service on the Raspberry and on the server that runs HASS?

Example please with 2 usb sticks.
I have problem with my second usb device. first one is aeotec z-stick usb wich is running shared on a pi to my ha (VM). tried to do the same on the pi with my conbee stick but can’t get the configuration running.

@luma, I’ve got my Zwave stick working right now. But can you please explain how to add a second usb device?
I tried to edit usbipd.service to this:

[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=0658:0200#' | cut '-d#' -f1)"
ExecStop=/bin/sh -c "/usr/sbin/usbip unbind --$(/usr/sbin/usbip list -p -l | grep '#usbid=10658:0200#' | cut '-d#' -f1`); killall usbipd"

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

[Install]
WantedBy=multi-user.target

But then the service is not able to start. I get this error:
Failed to start usbipd.service: Unit usbipd.service is not loaded properly: Invalid argument.

Edit:
I think I solved my own question:

[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=0451:16a8#' | cut '-d#' -f1)"
ExecStartPost=/bin/sh -c "/usr/sbin/usbip bind --$(/usr/sbin/usbip list -p -l | grep '#usbid=0658:0200#' | cut '-d#' -f1)"
ExecStartPost=/bin/sh -c "/usr/sbin/usbip bind --$(/usr/sbin/usbip list -p -l | grep '#usbid=1a86:7523#' | cut '-d#' -f1)"
ExecStop=/bin/sh -c "/usr/sbin/usbip unbind --$(/usr/sbin/usbip list -p -l | grep '#usbid=0451:16a8#' | cut '-d#' -f1`); killall usbipd"
ExecStop=/bin/sh -c "/usr/sbin/usbip unbind --$(/usr/sbin/usbip list -p -l | grep '#usbid=0658:0200#' | cut '-d#' -f1`); killall usbipd"
ExecStop=/bin/sh -c "/usr/sbin/usbip unbind --$(/usr/sbin/usbip list -p -l | grep '#usbid=1a86:7523#' | cut '-d#' -f1`); killall usbipd"

[Install]
WantedBy=multi-user.target

And for the client part:

[Unit]
Description=usbip client
After=network.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh -c "/usr/lib/linux-tools/$(uname -r)/usbip attach -r 192.168.1.208 -b $(/usr/lib/linux-tools/$(uname -r)/usbip list -r 192.168.1.208 | grep '0451:16a8' | cut -d: -f1)"
ExecStart=/bin/sh -c "/usr/lib/linux-tools/$(uname -r)/usbip attach -r 192.168.1.208 -b $(/usr/lib/linux-tools/$(uname -r)/usbip list -r 192.168.1.208 | grep '0658:0200' | cut -d: -f1)"
ExecStart=/bin/sh -c "/usr/lib/linux-tools/$(uname -r)/usbip attach -r 192.168.1.208 -b $(/usr/lib/linux-tools/$(uname -r)/usbip list -r 192.168.1.208 | grep '1a86:7523' | cut -d: -f1)"
ExecStop=/bin/sh -c "/usr/lib/linux-tools/$(uname -r)/usbip detach --port=$(/usr/lib/linux-tools/$(uname -r)/usbip port | grep '<Port in Use>' | sed -E 's/^Port ([0-9][0-9]).*/\\1/')"

[Install]
WantedBy=multi-user.target
2 Likes

Has someone found a reliable solution using ser2net/socat and hassio without a custom docker image?

1 Like

I was only able to get usbip working, but it is working well so far.

I did have to modify the service files above to use network-online.target because the service was starting too soon and not connecting on boot.

1 Like

does it reconnect automatically after rebooting the server or client?

Thanks for the write up I’m also interested in getting this up a running. I have zwave issues,
What files are you showing in your example and where are they located please

Looks like what I have been looking for. I read through this thread and seem lost. Assuming i have a spare pi, a working instannce of HASSIO a aeon zwave stick, what’s the best way to do this?

For now my hassio runs on a laptop, but would like to get it into a hyper-v, and that doesn’t allow me to pass the usb over. I’m so basic when it comes to linux.