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.

/etc/ser2net.conf:

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:

google.com
www.google.com
yahoo.com
www.yahoo.com
bing.com
www.bing.com

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):

#!/bin/sh

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/'
                continue
        fi

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


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

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

MOES IR Control Tuya (SRW-001) flashing (ESPHome, etc)

The device MOES IR Control Hub, which uses Tuya ESP8266 is no longer vulnerable to the vulnerability that tuya-convert exploits. You will need to open the device to flash it.

They are currently shipped with an TYWE3S which is an ESP8266 (as of June, 2021). You can see the pin outs for the TYWE3S at the Tasmota site.

Use a thin utility knife to open, I would recommend starting at the USB port area. There are two tabs on either side, and a few spread throughout. Once you have the device open and have connections setup you are ready to flash.

How to flash?

  1. Tie GPI0 to GND to start flash mode (when RST or power on the device, you will know you are in flash mode because the blue status LED does not come on)
  2. RX, TX, GND to your USB TTL (remember RX and TX are reversed for the USB TTL side)
  3. GND on TYWE3S is connected to the same ground plane as the rest of the board (i.e. GND on your USB TTL)
  4. Then power up via MicroUSB
  5. Flash via esptool (rev 1ca08af instead of master due to Issue #635 in esptool)
  6. Unplug everything and power up normally, and configure ESPHome as you normally would.

deCONZ VNC access without full blown Xorg install

deCONZ / Phoscon-GW recommends a full blown Xorg install on a Raspberry Pi to access their GUI. deCONZ is a utility to work with Zigbee controller provided by Raspbee / Conbee. deCONZ GUI provides more advanced control of Zigbee devices, and has functionality that is not available via web interface/REST API.

No need to install a full blown UI if you want to run headless. These instructions are for Raspbian.

Make sure to disable and stop existing deconz services if enabled:

systemctl disable deconz
systemctl stop deconz

You may also have deconz-gui service if you have followed their install guide, so make sure to disable and stop this as well if applicable.

Install TigerVNC which we will use to provide headless VNC access to the GUI:

apt-get install tigervnc-standalone-server

You will create a new systemd service definition, which is outlined below .

/etc/systemd/system/deconz-vnc.service

[Unit]
Description=deCONZ: ZigBee gateway -- GUI/REST API VNC
Wants=deconz-init.service deconz-update.service

[Service]
User=1000
Environment="DISPLAY=:0"
ExecStartPre=/usr/bin/tigervncserver -geometry 1024x768 -useold -SecurityTypes None -localhost yes -noxstartup "$DISPLAY"
ExecStart=/usr/bin/deCONZ --http-port=80
Restart=on-failure
StartLimitIntervalSec=0
RestartSec=30
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_KILL CAP_SYS_BOOT CAP_SYS_TIME

[Install]
WantedBy=multi-user.target

Then reload systemd, enable and start the newly created service:

systemctl daemon-reload
systemctl enable deconz-vnc
systemctl start deconz-vnc

Once this is done you can setup a SSH port forward to localhost:5900 and access deCONZ GUI using your favourite VNC viewer.

Home Assistant sensors and CyberPower UPS via RMCARD205

RMCARD205 supplies metrics via SNMP for all supported CyberPower UPS. Who doesn't want to display power usage on their UPS via Home Assistant?

Lovelace card for CyberPower UPS

I created a "package" for CyberPower UPS RMCARD that exports data via SNMP. This assumes your default read-only community is named public.

packages/ups.yaml:

sensor:
  - platform: snmp
    scan_interval: 60
    name: ups_nompower
    host: x.x.x.x
    baseoid: 1.3.6.1.4.1.3808.1.1.1.4.2.5.0
    accept_errors: true
    unit_of_measurement: Watts
  - platform: snmp
    scan_interval: 60
    name: ups_nominv
    host: x.x.x.x
    baseoid: 1.3.6.1.4.1.3808.1.1.1.3.2.1.0
    accept_errors: true
    unit_of_measurement: Volts
    value_template: '{{((value | int) / 10) | int}}'
  - platform: snmp
    scan_interval: 60
    name: ups_itemp
    host: x.x.x.x
    baseoid: 1.3.6.1.4.1.3808.1.1.1.2.2.3.0
    accept_errors: true
    unit_of_measurement: "°C"
  - platform: snmp
    scan_interval: 60
    name: ups_timeleft
    host: x.x.x.x
    baseoid: 1.3.6.1.4.1.3808.1.1.1.2.2.4.0
    accept_errors: true
    unit_of_measurement: 'minutes'
    value_template: '{{((value | int) / 6000) | int}}'
  - platform: snmp
    scan_interval: 30
    name: ups_status
    host: x.x.x.x
    baseoid: 1.3.6.1.4.1.3808.1.1.1.4.1.1.0
    accept_errors: true
    value_template: >-
      {% set status = (value | int) %}
      {%- if status == 2 -%}
      Online
      {%- elif status ==  3 -%}
      On Battery
      {%- elif status ==  4 -%}
      On Boost
      {%- elif status ==  5 -%}
      On Sleep
      {%- elif status ==  6 -%}
      Off
      {%- elif status ==  7 -%}
      Rebooting
      {%- elif status ==  8 -%}
      On ECO
      {%- elif status ==  9 -%}
      On Bypass
      {%- elif status ==  10 -%}
      On Buck
      {%- elif status ==  11 -%}
      On Overload
      {%- else -%}
      Unknown
      {%- endif -%}
      
group:
  ups:
    name: UPS
    entities:
      - sensor.ups_status
      - sensor.ups_nompower
      - sensor.ups_nominv
      - sensor.ups_itemp
      - sensor.ups_timeleft

homeassistant:
  customize:
    sensor.ups_nompower:
      friendly_name: 'UPS Nominal Output Power'
      icon: mdi:flash
    sensor.ups_nominv:
      friendly_name: 'UPS Nominal Input Voltage'
      icon: mdi:flash
    sensor.ups_status:
      friendly_name: 'UPS Status'
      icon: mdi:information-outline
    sensor.ups_itemp:
      friendly_name: 'UPS Internal Temperature'
      icon: mdi:thermometer
    sensor.ups_timeleft:
      friendly_name: 'UPS Time Left'
      icon: mdi:clock-alert