Companion hardware to an HA OS install that supports GPIO sensors and Celluar backup

This post covers how I shifted capabilities off my HA controller hardware so it could run HA OS. The solution works but doubled power required to maintain my alarm system during a power outage. I believe these capabilities are core capabilities that should be supported in HA OS. Hopefully documenting things will open the door for HA OS reconsideration. If not maybe they’ll just be helpful to someone, myself include should I have to rebuild things.

Update: I’ve currently have an alternative implantation that moves GPIO monitoring over to an esp and the routing over to an OpenWrt router.

Here’s what the part of my HA implementation related to this post now looks like:

You years I’ve been running the an HA supervised install. The driver for this was to have full access to the controller hardware and have the ability to implement more complex networking. The hardware that was of interest were the GPIO pins on the Odroid N2+ HA controller. I utilized the GPIO pins to interface with wired contact sensors that came with the house. Wired contact sensors are significantly better than the wireless alternatives. With control of the networking, I was able to connected to both my wired internet provider and utilize cellular to provide HA an backup route to the internet. The alternative route stays up should I lose power. Utilizing Nabu Casa, you can still reach your smart home alarm features remotely during a power outage. These features can’t be implemented on HA OS today.

I wanted to migrate over to HA OS because we plan to sell our house at some point. Most people recommend against including your HA smart house implementation in the sale. Not me, I plan on giving the buyer the option to take over all smart house features in as is condition. That said, I’ve been spending time trying to make things in the house as easy as possible to support. While I was fine with my supervised install, I believe it requires more knowledge than using HA OS. I believe HA OS will be easier for someone to takeover.

I still want to have the contact sensor and redundant internet connections while I live in the house. Once we sell the house, I want to make it easy for the new home owner to use or remove features, or completely disable the smart house if they desire. My HA controller is now running HA OS. My companion system is using a Rasberry pi 4 with Rasberry pi OS handling the GPIO integration and networking.

My new implementation carries over the capabilities described in these post:

From the requirements mentioned in that second post above, I no longer utilize a 24/7 3rd monitoring service. I’ve moved over to using frigate for camera processing. Frigate and other applications that are CPU intensive run on a larger docker/NAS server that is not on battery backup. This architecture allows the home alarm part of my smart house to ride through power failures and ISP outages.

Added Hardware

Setting up the networking
I run the Rasberry in headless mode, using the serial console port to access the pi command line interface. The Pi’s Physical network connector is hardwired to the IOT network. The USB network adapter is connected from the pi to the HA controller network interface. I used rasp-config to make sure the the localisation values for locale, timezone and WLAN Country were set appropriately for my location. I use it to change the hostname and enable ssh and the serial port. I made sure all packages on the pi were up to date with:

sudo apt update
sudo apt upgrade

I don’t utilize ipv6 so I disabled it via creating the file /etc/sysctl.d/94-ipv6Disable.conf holding the line:

net.ipv6.conf.all.disable_ipv6 = 1

This can be loaded with “sudo sysctl -p /etc/sysctl.d/94-ipv6Disable.conf” or with a reboot. You can verify it’s being set with: sysctl -a |grep disable_ipv6.

Since I’m not using the integrated WiFi adaptors , I disabled it by adding the following line to the end of the /boot/firmware/config.txt file.

dtoverlay=disable-wifi

A reboot is required for this to take effect. It’s best to do this before you add the WiFi adapter and build the bridge described below. I utilize syslog on all my machines so I install it via:

sudo apt install syslog-ng.

I typically monitor the syslog in real time as I make changes. At this point as I was building the system, syslog was useful to verify when I plug in the wireless adapter that it is recognized as such.

A network bridge is created between the two Network adapters and the WiFi adapter. Implementing a bridge gives the pi, HA and the cell phone direct connect access to the IOT network. That is, they are all on the same unified network segment as the IOT network falling under the same network address block. If the pi were acting only as a routing device, between HA and the IOT network, then HA’s device discovery would fail.

The WiFi adapter acts as an access point for the Cellular phone WiFi connection. The cell phone is also connected to the pi via USB, tethering it’s internet access. The phone I use runs android. You can not tell android what IP CIDR block to assign to the tethered network. Surprisingly when I first utilized a phone for celluar access a few years back, I had a case where the cell phone picked the same network block as the IOT network. This is a bigh problem if it happens. By connecting the cell phone wifi to the IOT network, you prevent the phone from assigning the same address space as the IOT network. A secondary advantage of this is that the phone will send all network traffic over the WiFi network when it’s available. So under normal operation I can ensure all traffic from my network goes out my main firewall. When my ISP internet access is having problems I can shutdown the pi’s access point and the Cell phone will shift to using the Celluar network until wifi access returns.

Steps to build the bridge:
This link provides details on setting up the bridge, including the WiFi hotspot . The commands I used from this document follow.

Create the bridge

sudo nmcli connection add type bridge con-name 'Bridge' ifname bridge0

Connect the on board nic to the bridge

sudo nmcli connection add type ethernet slave-type bridge con-name 'Ethernet0' ifname eth0 master bridge0

Connect the USB NIC adapter the bridge

sudo nmcli connection add type ethernet slave-type bridge con-name 'Ethernet1' ifname eth1 master bridge0

Create and connect the wifi hotspot to the bridge
Change YOUR_SID and YOUR_PASS_PHRASE as desired

sudo nmcli connection add con-name 'Hotspot' ifname wlan0 type wifi slave-type bridge master bridge0 wifi.mode ap wifi.ssid YOUR_SID wifi-sec.key-mgmt wpa-psk wifi-sec.proto rsn wifi-sec.pairwise ccmp wifi-sec.psk YOUR_PASS_PHRASE

I restrict the wifi to 5Ghz because I use zigbee devices and I don’t want to add any more noise to the 2.4Ghz wireless band.

sudo nmcli connection modify Hotspot 802-11-wireless.band a

Bring the bridge up

sudo nmcli connection up Bridge
sudo nmcli connection up Hotspot

With the above configuration and the pi connected inline between HA and your IOT network, HA should work like it was directly connected to the IOT network.

Routing HA’s external traffic through the pi
The next step is to route any external traffic from HA through the pi. To do this the first thing we need to do is enabling routing on the pi. You create the file /etc/sysctl.d/95-ipForward.conf containing this line:

net.ipv4.ip_forward = 1

This can be loaded with “sudo sysctl -p /etc/sysctl.d/ 95-ipForward.conf” or with a reboot.

I recommend a static ipv4 address on the pi Bridge. You can do this with a modification of the following command, the IP information needs to be appropriate for connecting to your IOT network:

sudo nmcli con modify "Bridge" ipv4.method manual ipv4.addresses 192.168.11.150/24 ipv4.gateway 192.168.11.2 ipv4.dns 192.168.11.2

In theory you could restart the bridge with the following command, however sometimes this command doesn’t seem to complete:

sudo nohup nmcli con down "Bridge" && nmcli con up "Bridge"

I’d recommend you do a reboot again and remember you’ll be sshing into the new IP addressed you just assigned.

On the HA system you should set a static IP address under Settings→System→Network→IPV4. The gateway address would be set to the IP address of the PI. I also set the DNS server address to an external DNS server address so that DNS works when you’re on the cellular network. I use the google dns server 8.8.8.8. After making these changes your HA system may not fully function right as we need to add some iptables rules on the PI to handle the traffic forwarding.

On the pi you have multiple options for enabling firewalling capabilities. I still use iptables, so on the pi I installed the iptables tools via:

sudo apt install iptables-persistent

The persistent version gives the system the ability to reload your firewall rules on reboot.
Loading some iptabes rules
The minimal configuration required is to set up maquerade for the cellular network network interfaces usb0 via the following:

sudo iptables -t nat -A POSTROUTING -o usb0 -j MASQUERADE

The above is required because the cell phone is looking to tether a single device and not a full network.
*Add rules to limit flows that can enter the pi for routing
These rules restrict new flows coming in on the usb0 connector (cell phone tethered interface) to only DHCP messages:

sudo iptables -A INPUT -i usb0 -p udp -m udp --dport 68 -j ACCEPT
sudo iptables -A INPUT -i usb0 -p udp -m udp --dport 67 -j ACCEPT
sudo iptables -A INPUT -i usb0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

I want to make sure the only new flows coming into the pi via the bridge are ssh, icmp and HA controller packets:

sudo iptables -A INPUT -s IOT_NET_CIDR -i bridge0 -p tcp -m tcp --dport 22 -j ACCEPT
sudo iptables -A INPUT -s IP_OF_HA -i bridge0 -j ACCEPT
sudo iptables -A INPUT -p icmp -j ACCEPT
sudo iptables -A INPUT -i bridge0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

Above IOT_NET_CIRD and IP_OF_HA need to be match your network.

Setting the INPUT policy to DROP, ensures no other devices can utilize the pi as a routing device:

sudo iptables -P INPUT DROP

You’ll want to save the rules so they are applied at reboot

sudo iptables-save > /etc/iptables/rules.v4

Set metric values for routes
Verify what your current connection are via:

nmcli device

From that output, find the connection name for usb0. It’s normally ‘Wired connection 1’, but it could be something else. Set a metric value via:

sudo nmcli connection modify  'Wired connection 1'  ipv4.route-metric 150

Set the bridge metric to a lower value so it’s used as the normal default route

sudo nmcli connection modify  'Bridge'  ipv4.route-metric 100

For these to take effect the connections must be restarted:

sudo nmcli connection up 'Wired connection 1'
sudo nmcli connection up 'Bridge'

The usb0 connection will come back almost instantly, however the bridge is slow to go down and come back up.

You can now verify the routes have these newly assigned metrics via:

route -n

I have other networks available off my IOT firewall. One is a VPN that gives me external access to my HA system. As a result I have to add additional routes to make sure traffic can make it between the HA controller and other lan segments. I do this by simply editing the file /etc/NetworkManager/system-connections/Bridge.nmconnection and adding in the [ipv4] section a record for each route such as:

route1=192.168.10.0/24,192.168.11.2
route2=10.1.2.0/24,192.168.11.2

Above the CIRD blocks are the other networks that need access to HA and the individual IP address is the address of your router/firewall. Access to HA from these LAN segments will not work until you add specific routes.

Adding a script to control the internet routing.

The following script tracks the state of the internet and adjust the internet path to ensure HA communications can make it out of the house. The script is placed in the file /usr/local/bin/route-ctrl.py. IP_OF_HA, PORT_NUMBER_FOR_HA_GUI, MQTT_USER and MQTT_PASSSWORD need to be set correctly. This script assumes your running a MQTT server on HA.

#! /bin/python3
# Program looks to see if it can communicate with the internet, if it can't it takes
# wifi access point down, if it can access interent and wifi was previously taken
# down it brings it back up
import os
import subprocess
import time
import syslog
import socket
import sys
from datetime import datetime

HOST, PORT = "IP_OF_HA", PORT_NUMBER_FOR_HA_GUI
PASS="MQTT_PASSWORD"
USER="MQTT_USER"
connected = False

def ha_up():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((HOST, PORT))
        s.close()
        return True
    except socket.error:
        return False

def send_mqtt_msg( msg ):
    # only continue if mqtt broker is up
    done = 1
    while done != 0:
        #print("Sending message",msg)
        done = os.system( msg )
        if done != 0:
            time.sleep(5)


def move_to_cell_internet():
    # attempt to shutdown Hotspot so with metric change external traffic goes out celluar
    # really should verify these next two command work before declaring success
    response = os.system("nmcli connection modify 'Wired connection 1' ipv4.route-metric 50")
    response = os.system("nmcli connection up 'Wired connection 1'")

    response = os.system("nmcli connection down 'Hotspot'")
    if response == 0:
        os.system("conntrack --flush")

    return response


def move_to_isp_internet():
    # attempt to bring HotSpot back up
    response = os.system("nmcli connection up 'Hotspot'")
    if response == 0:
        #Hot spot is up so go ahead and change metric so traffic no longer goes out the cell phone tethered connection
        # really should verify these next two command work before declaring success
        os.system("nmcli connection modify 'Wired connection 1' ipv4.route-metric 150")
        os.system("nmcli connection up 'Wired connection 1'")
        # wait a little bit and then flush existing iptables flows so things will shift back to IPS connection on eth0
        time.sleep(.25)
        os.system("conntrack --flush")
    return response


# wait for HA to come up before continuing 
while not ha_up():
    syslog.syslog(syslog.LOG_INFO,"Waiting on HA to come up")
    time.sleep(10)


syslog.syslog(syslog.LOG_INFO,"HA is up and running")

internet_test_addr = "8.8.8.8" 
full_ping_delay = 5 
ping_delay = full_ping_delay
refreshTime = 0

# set so we start WiFi if the internet is up
house_internet_up = True
going_down = False

#Delay a couple seconds for things to come up
time.sleep(2)
syslog.syslog(syslog.LOG_INFO, 'Network Watcher up using target ' + internet_test_addr )

# Let HA know we currently have Hotspot up so using IPS internet
send_mqtt_msg("mosquitto_pub -u USER -P "+ PASS + " -h "+ HOST +" -t home-assistant/wifi -m "+ '{\\"state\\":\\"ON\\"}')

# just loop forever
while True:
    # check to see if we can ping out ISP internet to test address
    response = os.system("ping -I bridge0 -c 1 " + internet_test_addr + "> /dev/null")
    # good ping so internet is up
    #print( "Ping Response: ", response )
    if response == 0:
        #print( 'Good response to ping' )
        # if internet was down then bring wifi back up
        if not house_internet_up:
            #print( 'Good ping ' + internet_test_addr +  ' Bringing Hotspot Up')
            syslog.syslog(syslog.LOG_INFO, 'Good ping ' + internet_test_addr +  ' so enable Hotspot so if traffic flows to cell phone it will still go out ISP internet')

            response = move_to_isp_internet()

            if response == 0:
        # successful traffic shift
                house_internet_up = True

                # Up date HA sensor indicating we're now on ISP internet access
                send_mqtt_msg("mosquitto_pub -u USER -P "+ PASS + " -h "+ HOST +" -t home-assistant/wifi -m "+ '{\\"state\\":\\"ON\\"}')
                refreshTime = 0

                syslog.syslog(syslog.LOG_INFO,"Hostsport successfully activated");
                going_down = False
                ping_delay = full_ping_delay
            else:
        # failed traffic shift, so we'll try again next time
                syslog.syslog(syslog.LOG_INFO,"Hotsport did not activated");

    # second ping fails so if internet up then take it down
    elif going_down:
        if house_internet_up:
            #print('Cant ping ' + internet_test_addr +  ' Shutting down HA WiFi')
            syslog.syslog(syslog.LOG_INFO, 'Cant ping ' + internet_test_addr +  ' Shutting down Hotsport so traffic flows out cellular network')
            #os.system("rfkill block wlan")
            response = move_to_cell_internet()
            if response == 0:
                syslog.syslog(syslog.LOG_INFO,"Hotsport turned off show phone will send traffic out celluar network");
                # Up date HA sensor indicating we're now on cellular backup internet access
                send_mqtt_msg("mosquitto_pub -u USER -P "+ PASS + " -h "+ HOST +" -t home-assistant/wifi -m "+ '{\\"state\\":\\"OFF\\"}')
                refreshTime = 0

                house_internet_up = False
                ping_delay = full_ping_delay
            else:
                syslog.syslog(syslog.LOG_INFO,"Hotsport did not turn off so will try again next time");

    # failed first ping of internet test address so set to try second ping
    else:
        syslog.syslog(syslog.LOG_INFO,  "First ping failed, look for second error before routing external traffic out celluar network")
        #print "First ping failed, look for second error before taking internet down "
        going_down = True
        ping_delay = 5

    refreshTime = refreshTime + ping_delay

    # refress HA sensor state about ever 60 seconds 
    if refreshTime >= 60:
        refreshTime = 0
        if house_internet_up:
            send_mqtt_msg("mosquitto_pub -u USER -P "+ PASS + " -h "+ HOST +" -t home-assistant/wifi -m "+ '{\\"state\\":\\"ON\\"}')
        else:
            send_mqtt_msg("mosquitto_pub -u USER -P "+ PASS + " -h "+ HOST +" -t home-assistant/wifi -m "+ '{\\"state\\":\\"OFF\\"}')

    time.sleep(ping_delay)

brian@HAbridge:~ $ 

The following goes in /etc/systemd/system/watchpins_mqtt.service to start the above script on boot.

[Unit]
Description=Watch GPIO pins and report to HA via MQTT
After=network.target

[Service]
Type=simple
#User=
#Group=
#ExecStart=/usr/local/bin/dufs  -p 443  -a mybackup:GetYourData@/:rw  --allow-delete --allow-search --allow-archive --log-file /var/log/dufs.log --tls-key=/etc/ssl/private/dufs-selfsigned.key --tls-cert=/etc/ssl/certs/dufs-selfsigned.crt  /home/mybackup
ExecStart=/usr/local/bin/watchpins_mqtt.bash
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target

Once this file is in place you need to enable it so it starts on reboot:

systemctl enable watchpins_mqtt

defining the sensor for HA
On HA I have binary_sensors that report the state of the doors. There is probably a different way to do this now, but when I first start using this years ago I had to added the following information in the homeassistant/configuration.yaml to create the mqtt binary_sensor:

mqtt:                                                                  
  binary_sensor:                                                                                      
    - name: "wifi_status"                                        
      device_class: connectivity                                    
      state_topic: "home-assistant/wifi"                 
      qos: 0                                                    
      value_template: "{{ value_json.state }}"                      
      unique_id: wifi_status_bsensor                                                            

I hit the character limit for a post so the GPIO information in next post.

Setting up GPIO pin sensors
The GPIO pins on the PI are pretty easy to get working with contact sensors. You wire one end of the contact sensor to the 3.3v pin (one pin can be strapped to multiple contact sensors). You connect the other end of the contact sensor to one of the GPIO input pins. The command “gpioinfo” displays the list of gpiochips and their GPIO line numbers. This information with a Raspberry pi pinout diagram will let you map the GPIOXX to a physical pin.

It’s recommended that you add a resistor at the end of the wire just prior to it connecting to the input GPIO pin. The resistor value should be between 1K ohms and 10k ohms. This provides protection for the GPIO pin should a spike on the 3.3v line happen. The resistor acts to control the maximum current flow.

Most contact sensors break the circuit when the magnet is pulled away from the contact. However some do the opposite. While most of the input pins work, you need to test the pins you select to verify they provide the desired output. You can use gpioget to read the output.

gpioget --numeric -c 0 17 18 22 23 27

You can read one or more pins at once. This example reports the value from 5 GPIOXX lines. The numbers are not pin numbers, they are GPIO line numbers. The 0 indicates we’re reading from gpiochip0, which happen to have all of the GPIO input pins. The -c limits the output to either 1 or 0. The 5 GPIO lines in this example are connect to 5 door contact sensors. The output value when all doors are closed reads as:

1 1 1 1 1

I utilize the following bash script to read the state of the 5 doors and then report this information via MQTT to HA. The script is stored in the file /usr/local/bin/watchpins_mqtt.bash. The five variables at the top of the script need to be updated with the correct values.

#!/bin/bash

HA_ADDR="IP_OF_HA"
MQTT_ADDR="IP_MQTT_SRV"
HA_PORT="HA_GUI_PORT"
USER="MQTT_USER"
PASS="MQTT_PASSWORD"

# wait for HA to come up by checking web port before sending any messages
notdone=1
# set to skip check for HA being available
while [ $notdone -eq 1 ]; do 
  netcat -w 3 -z $HA_ADDR $HA_PORT
  if [ $? -eq 0 ]; then
    echo port open
    notdone=0
    break
  else
    echo port closed
  fi
  sleep 10
done
# give a little time to make sure things are really up
#sleep 20

#post fact senosrs are available and in a closed state
mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/front_door/availability -m online
mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/back_door/availability -m online
mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/basement_door/availability -m online
mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/garage_door_l/availability -m online
mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/garage_door_r/availability -m online
mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/front_door -m '{"state":"OFF"}'
mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/back_door -m '{"state":"OFF"}'
mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/basement_door -m '{"state":"OFF"}'
mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/garage_door_l -m '{"state":"OFF"}'
mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/garage_door_r -m '{"state":"OFF"}'

# keep track of current sensor state, assume everything is closed
declare -g curfd="2"
declare -g curbkd="2"
declare -g curbsd="2"
declare -g curgdl="2"
declare -g curgdr="2"
declare -g lastcnt=0

#echo curfd = $curfd, curbd = $curbkd, curbsd = $curbsd
#Loop forever
while true 
do
   if [ $lastcnt -gt 600 ];then
     #echo Reporting available
     mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/front_door/availability -m online
     mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/back_door/availability -m online
     mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/basement_door/availability -m online
     mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/garage_door_l/availability -m online
     mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/garage_door_r/availability -m online
     # set current state so will force reporting of previous state
     curfd=2
     curbkd=2
     curbsd=2
     curgdl=2
     curgdr=2
     lastcnt=0
   fi
   # Read in gpio pin values for three doors
   while read fd bkd bsd gdl gdr; do 
     #echo fd = $fd curfd = $curfd bkd = $bkd curbkd = $curbkd bsd = $bsd curbsd = $curbsd
     #echo gdl = $gdl curgdl = $curgdl gdr = $gdr curgdr = $curgdr
     # report any change in state of doors
     if [ $curfd != $fd ];then
       if [ $fd = 0 ];then
	 echo "`date` Sending front_door open "
         mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/front_door -m '{"state":"ON"}'
       else
	 echo "`date` Sending front_door closed"
         mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/front_door -m '{"state":"OFF"}'
       fi
       curfd=$fd
     fi
     if [ $curbkd != $bkd ];then
       if [ $bkd = 0 ];then
	 echo "`date` Sending back_door open"
         mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/back_door -m '{"state":"ON"}'
       else
	 echo "`date` Sending back_door closed"
         mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/back_door -m '{"state":"OFF"}'
       fi
       curbkd=$bkd
     fi
     if [ $curbsd != $bsd ];then
       if [ $bsd = 0 ];then
	 echo "`date` Sending basement_door open"
         mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/basement_door -m '{"state":"ON"}'
       else
	 echo "`date` Sending basement_door closed"
         mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/basement_door -m '{"state":"OFF"}'
       fi
       curbsd=$bsd
     fi

     if [ $curgdl != $gdl ];then
       if [ $gdl = 0 ];then
	 echo "`date` Sending garage_door_l open"
         mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/garage_door_l -m '{"state":"ON"}'
       else
	 echo "`date` Sending garage_door_l closed"
         mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/garage_door_l -m '{"state":"OFF"}'
       fi
       curgdl=$gdl
     fi

     if [ $curgdr != $gdr ];then
       if [ $gdr = 0 ];then
	 echo "`date` Sending garage_door_r open"
         mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/garage_door_r -m '{"state":"ON"}'
       else
	 echo "`date` Sending garage_door_r closed"
         mosquitto_pub -u $USER -P $PASS -h $MQTT_ADDR -t home-assistant/contact/garage_door_r -m '{"state":"OFF"}'
       fi
       curgdr=$gdr
     fi
   #done <<<$(gpioget gpiochip0 80 70 79 76 63)
   done <<<$(gpioget --numeric -c 0 17 18 22 23 27)
   #Only check state every half second
   sleep .5
   ((lastcnt=lastcnt+1))
done

This script is stated via the service file /etc/systemd/system/watchpins_mqtt.service:

[Unit]
Description=Watch GPIO pins and report to HA via MQTT
After=network.target

[Service]
Type=simple
#User=
#Group=
ExecStart=/usr/local/bin/watchpins_mqtt.bash
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target

You enable the script to start at boot with “sudo systemctl enable watchpins_mqtt”.

Like above, I also created binary_sensors for each door in the homeassistant/configuration.yaml. They are added in the mqtt section below the wifi_status sensor

mqtt:                                                       
  binary_sensor:  
    - name: "wifi_status"                                       
      device_class: connectivity                                    
      state_topic: "home-assistant/wifi"                 
      qos: 0                                                    
      value_template: "{{ value_json.state }}"                      
      unique_id: wifi_status_bsensor            

    - name: "front_door_bsensor"                                                 
      device_class: door                                               
      state_topic: "home-assistant/contact/front_door"                 
      payload_on: "ON"                                                           
      availability:                                                    
        - topic: "home-assistant/contact/front_door/availability"
          payload_available: "online"                 
          payload_not_available: "offline"
      qos: 0                             
      value_template: "{{ value_json.state }}"                   
      unique_id: 98F4ABD0B919A0                       
                                          
    - name: "back_door_bsensor"
      device_class: door                                         
      state_topic: "home-assistant/contact/back_door"
      payload_on: "ON"                       
      availability:                                              
        - topic: "home-assistant/contact/back_door/availability"
          payload_available: "online"                
          payload_not_available: "offline"
      qos: 0                                  
      value_template: "{{ value_json.state }}"                  
      #unique_id: 98F4ABD0B919A1                     
      unique_id: back_door_bsensor        
                        
    - name: "basement_door_bsensor"                                    
      device_class: door                                    
      state_topic: "home-assistant/contact/basement_door"              
      payload_on: "ON"                                                           
      availability:                                                    
        - topic: "home-assistant/contact/basement_door/availability"   
          payload_available: "online"                                            
          payload_not_available: "offline"                             
      qos: 0                                                     
      value_template: "{{ value_json.state }}"                      
      unique_id: 98F4ABD0B919A2                          
                                          
    - name: "garage_door_left"                                   
      device_class: door                                            
      state_topic: "home-assistant/contact/garage_door_l"
      payload_on: "ON"                    
      availability:                                              
        - topic: "home-assistant/contact/garage_door_l/availability"
          payload_available: "online"                    
          payload_not_available: "offline"                       
      qos: 0                                                    
      value_template: "{{ value_json.state }}"                      
      unique_id: 98F4ABD0B919A3     

    - name: "garage_door_right"                                  
      device_class: door                                            
      state_topic: "home-assistant/contact/garage_door_r"
      payload_on: "ON"                    
      availability:                                              
        - topic: "home-assistant/contact/garage_door_r/availability"
          payload_available: "online"                    
          payload_not_available: "offline"
      qos: 0                                                     
      value_template: "{{ value_json.state }}"                      
      unique_id: 98F4ABD0B919A4             

A lot of hoops to access the GPIO pins. I have a suggestion that is easier and well documented. You outboard your GPIO to an Arduino: 8ADC/DIO pins,11DIO pins, IIC support (uses 2 pins), SPI support (uses 5 pins)

MySensors with the MySensors Integration. Once the integration is installed and the Arduino is programmed with the serial gateway, you would write the code to control your sensor/actuator.

Most applications have satellite Arduino device controller that communicate to with the gateway via a [nRF24] radio. The radio isn’t necessary if you use the I/O of the gateway.

Included is HA Auto discovery of devices.

This is an example

I consider using ESPhome, but I’d still need to have wifi for the ESP to report to HA. Adding a wifi access point in the mix would utilize a similar amount of power to this solution and I wouldn’t have backup cellular to ensure the alarm is accessible during a power outage. If I were only trying to utilize GPIO pins and didn’t have power and 24x7 accessibility requirements I would have gone the ESPhome or Arduino route. I don’t think it would be easier, but it would be less power.

You might just choose some ESP with ethernet to replace the raspberry? Also ESPHome supports one(?) gsm modem directly (sim800l) but might be limited to message/calls (which actually might do the trick for alarming anyway). Other than that you might even utilize esp-now for direct node2node communication (remote esphome sensors to interact with the gsm capable ESPHome node). And obviously you can also give your esphome node a internet connection via your phone (easiest might just be an wifi hotspot) :signal_strength:

If the OS development team takes on adding multiple NIC I could then look to utilize an ESP with the ethernet interface for my GPIO pins. I added this feature request to see if I can get some love. If you’re interested in the request, check it out and up vote it.

Or just get a used $10 openwrt router which does the fallback internet routing for you?

https://openwrt.org/docs/guide-user/network/wan/simple_wan_failover?s[]=openwrt

1 Like

Where are you getting a $10 router capable of running openwrt as I’d buy one of those? In reality my setup does what openwrt would do, but restricting the dual route for use just by HA, and provides HA both bridge access to the IOT network, with routed access to the dual gateway. The approach I present minimizes the amount of hardware that has to be on an UPS.

If HA supported dual routing and allowed the addition of static routes, I could use my HA controller, for networking. I’d add a 5 port switch and an ESP with ethernet to handle the wired alarm contact sensors via the ESP GPIO. My Odroid N2+ pull under 3 watts on average, the 5 port switch and ESP would add 1 watt resulting in a system that used under 4 watts at normal load. The solution I currently have in places pulls 8.5 watts at normal load. The fewer the watts the smaller the battery for multi day operations without power.

I just need the development HA OS team to add something that should be relatively easy to do. It would be great if you could configure things via the gui, but I’d be fine configuring the networking in configuration.yaml if need be. So hopefully they’ll support my request.

Just started digging into this suggestion a little more. If I’m reading the docs for MySensor right I could plug an arduino board into one of the USB ports on my HA controller and directly access the sensor from HA. You have any suggestion on a good arduino board? Any idea if these would work?

Ebay good place to look for cheap second hand router for Openwrt. The openWRT forum has threads about cheap routers. I have bought several that cost less than 10 bucks each. Good for wifi access points or travel routers.
But if you want something a bit more beefier go for something like a flint2 but will cost closer to 50 bucks.

Interesting, the low cost boxes are older wifi routers. I actually have one of the models they were selling on ebay on the shelf. I might have to see if I can get Openert running on it. While the old linksys router I had runs OpenWrt well, it didn’t support usb tethering.

1 Like

So based on some of the comments in this thread I tried out 3 different approaches for handling GPIO pins that I documented here.

I moved the routing over to low cost, low power OpenWrt box. At this point my average power consumption is about 5 watts. So GPIO and OpenWrt average power consumption is about 2 Watts. If anyone is aware of a an alternative OpenWrt device that operates on average under 1.5 Watts, please let me know.

1 Like

Not sure about the latest and greatest models, but devices branded as travel routers (some times with included battery) should be more efficient than devices designed for stationary use. :battery:

Also some openwrt devices even expose some gpio’s (like the good old gl-inet mango) but the software support might be a little limited in openwrt depending on the peripherals you want to hook up. :satellite:

In general 1.5W doesn’t sound bad at all and depending on specs (gigabit Ethernet for example) and the load (devices actively transmitting data) I guess it is already on the lower side. :+1:

not really, you can use Ethernet with ESP’s.

Which might actually be more power/energy demanding compared to WIFI :zap:

…but less than running a Raspberry Pi.

1 Like