Sometimes you want to use a USB serial device at a different location of where it is “plugged in”. With two tools (ser2net and socat) this is quite easy to do.
Within my home I make use of Home automation. I combine a few technologies to make it all work, among them Z-Wave and Zigbee. I started with Z-Wave and for that I used a Vera, a (now) quite old device which basically is an appliance running Linux.
Through time I’ve started to use Zigbee devices as well and for that I’m using zigbee2mqtt, a neat piece of software which pushes zigbee messages towards an mqtt server.
Zigbee2mqtt uses an USB adapter to connect to the Zigbee network. This USB adapter is basically a serial device and becomes the coordinator of the Zigbee mesh network.
As the Raspberry Pi on which I am running zigbee2mqtt is not in the best location for the adapter and the Vera already was, I decided to try to make it work via the Vera.
Browsing through the Linux installation at the Vera I discovered it contained the ser2net command. This is a little daemon which is capable of sending serial port traffic over a network connection. So that would be my starting point.
After initial testing I discovered the Vera had the nasty habit of re-initializing most of the system and killing ser2net whenever something in the system changed. (Vera uses ser2net itself as well)
So I wrote a little script with an endless loop which would restart the ser2net command if it was not running anymore. The script itself is started as a “respawn” via the inittab, so it’s always running.
#!/bin/sh # # Starts and restarts ser2net while [ true ] ; do ps ax|grep ser2net|grep -q ACM if [ $? == 1 ]; then /usr/sbin/ser2net -C '4096:raw:0:/dev/ttyACM0:38400 NONE 1STOPBIT 8DATABITS' else echo "Sleeping..." fi sleep 29 done
Ser2net is being instructed to open device /dev/ttyACM0 and listen on port 4096 for any connections towards the device. The communication is “raw”, which means everything that comes in is send as-is to the device.
The above script would work on any Linux device, not just the Vera.
So, the “listening” side of things has been set-up. Next up, the host on which zigbee2mqtt runs.
Again it’s very easy. By using socat to connect to the Vera device on which ser2net is listening we can create a “local” serial port. And by putting it in a Systemd configuration everything will be set-up together with the running of zigbee2mqtt.
[Unit] Description=SOCat to control Zigbee sniffer [Service] ExecStart=/usr/bin/socat pty,link=/dev/ttyRemote,raw,user=root,group=dialout,mode=777 tcp:192.168.1.1:4096 ExecStartPost=service zigbee2mqtt restart StandardOutput=null Restart=always RestartSec=30s [Install] WantedBy=multi-user.target
The configuration for socat is quite easy. It’s being told to create a pseudo terminal (pty) and link it to /dev/ttyRemote. Communication is raw and it sets the ownership to something you would expect with a tty. Finally the host to connect to is 192.168.1.1 port 4096
Systemd will make sure socat stays running and restarts zigbee2mqtt whenever it is started or restarted.