Zigbee to MQTT evaluation - Step 1

Today is the day when I get to try Zigbee2MQTT project. The goal is to be able to push a button and being able to print something at the terminal as a response.

I bought the following hardware:

First I am installing a Virtual Machine with ARCH linux on it. That will be a separate blog post on how I do that. I booted up an arch install media and ran the following script to install the base operating system.

Once that was done, I rebooted the VM and started to install the required packages.

Some utilities are needed

pacman -S bash-completion vim usbutils
pacman -S mosquitto
systemctl enable mosquitto.service
systemctl start mosquitto.service

Now let's install zigbee2mqtt

pacman -S zigbee2mqtt
systemctl enable zigbee2mqtt.service
systemctl start zigbee2mqtt.service

Now I plugged in the USB device into my host machine, and it was showing up as:

lsusb
Bus 001 Device 008: ID 10c4:ea60 Silicon Labs CP210x UART Bridge

And I am forwarding that to the Guest using virt-manager.

Then looked into the VM to see if it turns up, and it did. I looked at dmesg to see what the name of the device is:

[  917.776577] usbcore: registered new interface driver cp210x
[  917.776593] usbserial: USB Serial support registered for cp210x
[  917.776615] cp210x 1-4:1.0: cp210x converter detected
[  917.778762] usb 1-4: cp210x converter now attached to ttyUSB0

Then I configured it in zigbee2mqtt's configuration file.

But I found that zigbee2mqtt was unable to talk to the device:

journalctl -u zigbee2mqtt.service -f
Error: Failed to connect to the adapter (Error: SRSP - SYS - ping after 6000ms)

So let us check permissions. I first need to understand who runs this process:

# systemctl cat zigbee2mqtt.service  | grep User
User=zigbee2mqtt
# ls -la /dev/ttyUSB0 
crw-rw---- 1 root uucp 188, 0 Nov  1 21:05 /dev/ttyUSB0
# usermod -a -G uucp zigbee2mqtt

Let's see if it does the trick. It still was failing with the same error.

So I plugged in the device to the network, and tried connecting it via TCP:

serial:
  port: tcp://192.168.0.220:6638
Nov 01 21:35:35 home01 node[1395]: [2024-11-01 21:35:35] info:         z2m: Zigbee2MQTT started!

Once that was done, I pulled out the battery insulation sheet from the button, and it was automatically detected.

Zigbee2mqtt added this device to the configuration, and I was able to give it a friendly name.

When I pushed the button, I was able to see the logs in the virtual machine.

Now it is pushing messages into this topic:

Nov 01 21:49:32 home01 node[1501]: [2024-11-01 21:49:32] info:         z2m:mqtt: MQTT publish: topic 'zigbee2mqtt/button-0', payload '{"action":"single","battery":100,"linkquality":163,"update":{"installed_version":8704,"latest_version":8704,"state":"idle"},"update_available":false,"voltage":3100}'

All is left for me to write some python code that will do something in response.

But before that, let us restart the VM and see it coming back again.

It came back without issues.

Now let's go python:

sudo pacman -S python
python -m venv .venv
. .venv/bin/activate
pip install paho-mqtt
(.venv) [matelakat@home01 ~]$ cat listen.py 
import paho.mqtt.client as mqtt
import json

# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, reason_code, properties):
    print(f"Connected with result code {reason_code}")
    # Subscribing in on_connect() means that if we lose the connection and
    # reconnect then subscriptions will be renewed.
    client.subscribe("zigbee2mqtt/button-0")

# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    data = json.loads(msg.payload.decode())

    print(msg.topic)
    print(data["action"])

mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
mqttc.on_connect = on_connect
mqttc.on_message = on_message

mqttc.connect("localhost", 1883, 60)

# Blocking call that processes network traffic, dispatches callbacks and
# handles reconnecting.
# Other loop*() functions are available that give a threaded interface and a
# manual interface.
mqttc.loop_forever()

And then

(.venv) [matelakat@home01 ~]$ python listen.py 
Connected with result code Success
zigbee2mqtt/button-0
single
zigbee2mqtt/button-0
double
zigbee2mqtt/button-0
long