Zigbee devices you don't want on your network

Want a stable mesh network? Running ZHA or Zigbee2MQTT as part of your home automation system? Here are some devices you should avoid running on your network.

Stability and performance issues?

  • Philips Hue A19 White and Color Ambiance (LCT001), released in ~2013
  • Philips Hue Table Lamp (LLC012), released in ~2013

The devices above will stop routing traffic and responding to commands, causing issues with your mesh network.

Pairing issues?

LinkTap GW-02, a wireless timer gateway leaves itself in Permanent Join mode and will reject join requests for any Zigbee device on your network. Sometimes, devices do not implement handling of rejected joins properly and will "give up."

Devices (re)-join Zigbee networks all the time to find a better parent route, so this will cause stability issues which are hard to diagnose.

ser2net and Zigbee coordinator USB dongle

Use ser2net on a Raspberry Pi if you would like to have your Zigbee coordinator in a central location, away from your Home Assistant machine. Can be especially useful if you have a PoE switch, and can use a PoE to MicroUSB adapter with Ethernet pass-through.


5678:raw:0:/dev/serial/by-id/usb-ITead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_$UUID-if00-port0:115200 NONE 1STOPBIT -XONXOFF NOBREAK

Home Assistant would then point at socket://x.x.x.x:5678 if using ZHA (Zigbee Home Automation) integration.

Network ACLs should be established to restrict access to ser2net to prevent abuse of the Zigbee controller.

DNS-based firewall rules on OpenWrt 22.03 using IP sets and fw4

I wanted to be able to use DNS-based firewall rules like on pfsense, opnsense and Sophos UTM for certain use cases. OpenWRT does not have this functionality built in. I came up with the following solution.

This allows you to list DNS names, for example in /etc/ipset-dns/dst_host_search_engines.list:


With a corresponding IP set entry in /etc/system/firewall:

config ipset
        option name 'dst_host_search_engines'
        option match 'dst_ip'
        option enabled '1'
        option timeout '0'

And an example firewall rule you could use with OpenWRT in /etc/config/firewall:

config rule
        option name 'Allow-Search-Engines'
        option family 'ipv4'
        list proto 'all'
        option ipset 'dst_host_search_engines'
        option family 'ipv4'
        option target 'ACCEPT'
        option src 'lan'

And the entirety of the script, which will query the hosts listed based on their IP address family, and set a timeout based on the TTL of the DNS entries.

/etc/ipset-dns.sh (don't forget to set executable bit):


for filename in /etc/ipset-dns/*.list; do
        ipset=$(basename $filename | cut -d '.' -f1)
        stdout=$(nft list set inet fw4 $ipset 2>&1)
        if [ $? -gt 0 ]; then
                echo $stdout | sed 's/^Error/Warning/'

        nft_type=$(echo $stdout | grep -oE 'type \w+' | awk '{ print $2 }')
        if [[ "$nft_type" == "ipv4_addr" ]]; then
        elif [[ "$nft_type" == "ipv6_addr" ]]; then
                echo "Warning: invalid type $nft_type for $ipset"

        dig $type -f $filename +noall +answer | while read _ ttl _ _ ip; do
                ttl=$(( ttl + 500 ))
                nft add element inet fw4 $ipset { ${ip} timeout ${ttl}s };

And the following crontab entry for the root user, in /etc/crontabs/root so that the script runs at boot and every 5 minutes (modify to suit, but make sure to update the 500 second addition on the TTL):

@reboot /etc/ipset-dns.sh
5 * * * * /etc/ipset-dns.sh

UEFI enabled libvirt virtual machines on Ubuntu

Required steps

  • Install the ovmf package
  • Restart libvirt-bin
  • Create /var/lib/libvirt/qemu/nvram to store NVRAM from a UEFI-enabled virtual machine (VM)

libvirt XML definition example for UEFI enabled VM

libvirt edit $VM_NAME and amend the XML definition.

    <type arch='x86_64' machine='pc-q35-2.11'>hvm</type>
    <loader readonly='yes' secure='no' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
    <nvram template='/usr/share/OVMF/OVMF_VARS.fd'/>
    <boot dev='hd'/>

WEMOS LOLIN32 ESP32 Lite pinout example for CJMCU-811

Low cost ESP32 development board such as WEMOS ESP32 LOLIN32 Lite paired with a CO2 / VOC sensor CJMCU-811. The WEMOS LOLIN32 development board does not have all the same GPIO as other similar ESP32 boards.


22 (GPIO22)SCL
19 (GPIO19)SDA
Pinout example for LOLIN32 paired with CJMCU-811

ESPHome example

  sda: GPIO15
  scl: GPIO2

  - platform: ccs811
      name: "CCS811 eCO2 Value"
      name: "CCS811 Total Volatile Organic Compound"
    address: 0x5A
    baseline: 0x9AB9
    update_interval: 60s