How to: GPIO integration of old Alarm system contact sensors

This post goes over integrating hardwired contact sensors into a Home Assistant supervised instant running on the Armbian operating system on Odroid N2+ hardware. Available in the US here. NOTE: I no longer use Armbian, but this fully function Debian 11 distro. The distro has a built in command, menu-config, that provides for the supervised install of HA.

We bought our house years ago. The house had an existing minimal alarm system the previous owner had installed. Part of buying the house required us to take over the alarm system contract, which we did. We over paid for the alarm system and 3rd party monitoring for years. The system had hard wired contact sensors on the doors, a motion sensor and a glass break sensor. While the system provided my wife a small sense of comfort when we traveled, I always felt the system was a joke because of the limited features. There we’re multiple ways you could gain access to the house with no threat of detection.

About a year ago I discovered Home Assistant. I started playing around with it looking at different contact and motion detection sensors. I tried out Wyze and then switched over to the Aqara line of sensors. I’m very happy with the Aqara sensors. They are easy to integrate directly into Home Assistant with one of many Zigbee USB dongles. I utilize the HUSBZB-1. While the wireless sensors are easy to use, I really prefer the aesthetics of hidden hardwired sensors. That was the one thing our existing alarm system did right. They used hardwired sensors on all the doors.

The hardwired sensors are really just switches that are either open or closed, based on the position of the door. So power either flows or it doesn’t. The arm based board utilized as controllers for Home Assistant all come with a number of GPIO pins. In the simplest terms the GPIO pins can provide or receive a voltage and then report a change in that voltage. So if you use a GPIO pin that is providing voltage, connect it to the contact sensor and then the contact sensor back to a ground GPIO pin you have a complete circuit. The contact sensors in my house are Normally Open (NO) that means they are on, letting voltage flow when the door is closed. Normally Closed (NC) sensors would be off when the door is closed, stopping the flow of voltage. Regardless of your sensor type, NO or NC, the result is the same. Opening and closing the door changes the voltage measured at the GPIO pin. So wiring is easy you just need to find a GPIO pin that is providing voltage and wire it to ground with the sensor in line.

While there may be a way to do this utilizing the Home Assistant Operating System (HAOS), I don’t know that path. HAOS isolates the user from accessing the operating system. That’s fine if you’re just using items that come out of the box. It’s very limiting if you want to take full advantage of your hardware and operating system capabilities.

Most people seem to pick the Raspberry Pi 4 for their controller because of it’s cheap price, but I believe the Odroid N2+ is currently the best platform for Home Assistant. The N2+ provides about 2X CPU performance over the Raspberry Pi 4 for an additional $30. The N2+ also has the option to use eMMC storage instead of a micro SD card. The eMMC write speed comes in at 125MB/s, while a class 10 micro SD has a write speed of 10MB/s. There are faster micro SD card. The fastest I’ve seen has a write speed of 90MB/s. So eMMC is the way to go for performance. While you probably would not notice this in your operational system, the performance improvements are very visible when you’re working on your initial setup. Time is money and I know I’ve saved hundreds of dollars in time because I selected the N2+.

If you’re not going to go with HAOS then you need a operating system distribution for your hardware. At this point in time I recommend Armbian, primarily because the Armbian team looks to support multiple Arm boards. Having a common platform is great because you can try out different hardware if you like and the operating system configuration is exactly the same. You don’t have to figure out how to do something uniquely for each hardware platform. The current armbian release for the Odroid N2+ is here. I used the CLI version as there is no need for a DESKTOP with HA. The only issue with using this distribution for HA is that it’s one Debian version back from what HAOS uses. That said it has all the current version of software packages that HA utilzes so there is no operational issue with using the previous version of Debian with HA.

So the basic install process for the Armbian release is the same as installation of HAOS. That is, you grab the operating system image, decompress it and burn it on your storage media. Once you’ve installed the image you plug it into your system and boot the system. For the Armbian image you’ll have a couple of additional steps. You log into the default account “root” with the password “1234” . On first login you’re asked to change the password and set up the main account you’ll log into. While you could can just contine to log in as the root use it’s good security practice to set up a different account and to disable the root account. Once your logged into the command prompt you make sure the system is up to date

sudo apt-get update
sudo apt-get upgrade

Reboot the system just in case there was an operating system update

sudo shutdown -r now

Log back in to the command line and install docker:

sudo bash
apt-get install ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
 "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg]\
 https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install docker-ce docker-ce-cli containerd.io

Install and enable apparmor

apt install apparmor
echo "extraargs=apparmor=1 security=apparmor" >> /boot/armbianEnv.txt
update-initramfs -u
shutdown -r now

Log back in and add the last few packages required by

sudo bash
apt install  jq libglib2.0-bin
apt install udisks2

I’m pretty sure that previous line installing udisk2 didn’t work for me so I had to do this to get udisk2 installed:

apt --fix-broken install
apt install udisks2

Install HA os-agent:

wget \
https://github.com/home-assistant/os-agent/releases/download/1.2.2/os-agent_1.2.2_linux_aarch64.deb
dpkg -i os-agent_1.2.2_linux_aarch64.deb

Install HA supervised, make sure you select the odroid-n2 hardware during these steps when asked:

wget https://github.com/home-assistant/supervised-installer/releases/latest/download/homeassistant-supervised.deb
dpkg -i homeassistant-supervised.deb
shutdown -r now

At this point you should be able to access you’re home-assistant GUI. If you have a previous install that you did a backup of you can now create a HA account, login and reinstall the backup.

The last thing we need to do is install the packages that support GPIO pin access:

sudo bash
apt-get install gpiod python3-libgpiod

You need to add a file that make the pins available to all users:

echo 'KERNEL=="gpiochip0", MODE="0666"' > /etc/udev/rules.d/99-perm.rules
echo 'KERNEL=="gpiochip1", MODE="0666"' > /etc/udev/rules.d/99-perm.rules
shutdown -r now

At this point you just need to pick your pins and wire things up. Here is a picture
of the GPIO pins and their associated pin numbers.

The GPIO software make the pins available using a different set of numbers. As
such you need to do the translation to make these pins available in any software that reads the state of the pins.

The following is the mapping for the pins with an indication of the voltage on the pins. I used pins that had a positive voltage because I then connected them to ground. Pins 29, 31 and 33 are underlined as they are the three used in the bash script below:

62 = 7   -
63 = 27 +
64 = 28 +
65 = 16 +
66 = 18 +
67 = 22 +
69 = 13 +
70 = 33 +
71 = 35 -
72 = 15 +
73 = 19 +
74 = 21 +
75 = 24 +
76 = 23  +
77 = 8  ?
78 = 10  ?
79 = 29 +
80 = 31 +
81 = 12 +
82 = 3  +
83 = 5  +
84 = 36 -

You can check this mapping using the command:

gpioinfo periphs-banks

For monitoring and integrating this into Home Assistant were going to use a bash script. The script uses netcat as a way to verify Home Assistant is up before it starts sending messages to HA. It uses the mosquitto client to interface with the mosquitto broker that comes with home assistant. So we have to install two final packages

apt-get install netcat mosquitto-clients

You need to create the file watchpins_mqtt.bash. I recommend that you create it in the default home assistant directory structure so it’ll be include in any backup you do of home assistant from within home assistant. Create a directory in the home assistant directory structure:

mkdir /usr/share/hassio/homeassistant/os-support-apps/

Then use nano or vi to create the file watchpins_mqtt.bash in the os-support-apps directory with this content. Make sure to replace and with the user name and password you establish within your HA mosquitto broker:

#!/bin/bash
# you need to update <USER> and <PASS WORD>  below with the user and password for you mqtt server
# wait for HA to come up by checking web port before sending any messages
notdone=1
while [ $notdone -eq 1 ]; do 
  netcat -w 3 -z localhost 8123
  if [ $? -eq 0 ]; then
    echo port open
    notdone=0
  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 WORD>  -h 127.0.0.1 -t home-assistant/contact/front_door/availability -m online
mosquitto_pub -u <USER> -P <PASS WORD> -h 127.0.0.1 -t home-assistant/contact/back_door/availability -m online
mosquitto_pub -u <USER> -P <PASS WORD> -h 127.0.0.1 -t home-assistant/contact/basement_door/availability -m online
mosquitto_pub -u <USER> -P <PASS WORD> -h 127.0.0.1 -t home-assistant/contact/front_door -m '{"state":"OFF"}'
mosquitto_pub -u <USER> -P <PASS WORD> -h 127.0.0.1 -t home-assistant/contact/back_door -m '{"state":"OFF"}'
mosquitto_pub -u <USER> -P <PASS WORD> -h 127.0.0.1 -t home-assistant/contact/basement_door -m '{"state":"OFF"}'

# keep track of current sensor state, assume everything is closed
declare -g curfd="0"
declare -g curbkd="0"
declare -g curbsd="0"
#echo curfd = $curfd, curbd = $curbkd, curbsd = $curbsd
#Loop forever
while true 
do
   # Read in gpio pin values for three doors
   while read fd bkd bsd; do 
     #echo fd = $fd curfd = $curfd bkd = $bkd curbkd = $curbkd bsd = $bsd curbsd = $curbsd
     # report any change in state of doors
     if [ $curfd != $fd ];then
       if [ $fd = 1 ];then
	 echo "`date` Sending front_door open "
         mosquitto_pub -u <USER> -P <PASS WORD> -h 127.0.0.1 -t home-assistant/contact/front_door -m '{"state":"ON"}'
       else
	 echo "`date` Sending front_door closed"
         mosquitto_pub -u <USER> -P <PASS WORD> -h 127.0.0.1 -t home-assistant/contact/front_door -m '{"state":"OFF"}'
       fi
       curfd=$fd
     fi
     if [ $curbkd != $bkd ];then
       if [ $bkd = 1 ];then
	 echo "`date` Sending back_door open"
         mosquitto_pub -u <USER> -P <PASS WORD> -h 127.0.0.1 -t home-assistant/contact/back_door -m '{"state":"ON"}'
       else
	 echo "`date` Sending back_door closed"
         mosquitto_pub -u <USER> -P <PASS WORD> -h 127.0.0.1 -t home-assistant/contact/back_door -m '{"state":"OFF"}'
       fi
       curbkd=$bkd
     fi
     if [ $curbsd != $bsd ];then
       if [ $bsd = 1 ];then
	 echo "`date` Sending basement_door open"
         mosquitto_pub -u <USER> -P <PASS WORD> -h 127.0.0.1 -t home-assistant/contact/basement_door -m '{"state":"ON"}'
       else
	 echo "`date` Sending basement_door closed"
         mosquitto_pub -u <USER> -P <PASS WORD> -h 127.0.0.1 -t home-assistant/contact/basement_door -m '{"state":"OFF"}'
       fi
       curbsd=$bsd
     fi
   done <<<$(gpioget gpiochip0 79 80 70)
   #Only check state every half second
   sleep .5
done

This script currently handles 3 hardwired contact sensors. Adding more sensors requires you adding them to the “while read…” and “done <<< lines…” and then doing a little cutting and pasting, but it should be pretty straight forward. The script has fd (front door), bk (back door) and bsd (basement door).

To start the script on reboot you can add the following line, just above the exit 0 line, in the file /etc/rc.local:

/usr/share/hassio/homeassistant/os-support-apps/watchpins/watchpins_mqtt.bash > /dev/null &

The script looks to talk with the mosquitto broker that you can install as an add on directly in HA. Setting up the add on also requires you to do a basic configuration for MQTT under integrations. When you set up the Mosquitto broker should have a configuration that looks something like this, with the username and password you want to use. You update the bash script above with the same username and password.

logins:
  - username: USERNAME
    password: PASSWORD
customize:
  active: false
  folder: mosquitto
certfile: fullchain.pem
keyfile: privkey.pem
require_certificate: false

The last step is to actually create the binary sensor in your home assistant configuration.yaml. So use either nano or vi to edit /usr/share/hassio/homeassistant/configuration.yaml and add this:

binary_sensor:
  - platform: mqtt
    name: "front_door_mqtt"
    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
    device_class: door
    value_template: "{{ value_json.state }}"

  - platform: mqtt
    name: "back_door_mqtt"
    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
    device_class: door
    value_template: "{{ value_json.state }}"

  - platform: mqtt
    name: "basement_door_mqtt"
    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
    device_class: door
    value_template: "{{ value_json.state }}"

If you only only have one or two sensor then just add entries to configuration.yaml for one or two entries. You need to restart home assistant which you can do via:

ha core restart

You should now see the binary senors as new entities in home assistant.
Hopefully this is helpful.

2 Likes

@bkprath, Very well written article. I too have searched for simplistic methods of utilizing the hard wire contacts. I wanted to side step with a very inexpensive method using Z-Wave. At first all my z-wave was integrated by ADT Pulse, but honestly, the system was limited and could not handle it. Then I jumped on board with Wink and Wink II. It worked really well until the held the system hostage demanding a monthly fee subscription. I am now with SmartThings. First, I must say that it is a great platform that can integrate Every z-wave device I have come across… The beautiful thing is there is a direct integration into HA! So… Price went up (I originally paid 67.54 :slight_smile: ) the device…
My difficulty was that on one offered a simple method to convert wired to wireless (And you post looks very detailed, but complicated. I used a Ecolink Z-Wave Amazon Link Documentation is weak, but the exciting part is there is a set of terminals inside. They run in parallel with the tilt sensor, so you mount the device upside down and now it reports open/closed back to HA. My other advice to someone in the engineering phase of conversion… Remember that you can connect wired contacts in series to save on devices… .i.e. my outdoor garage (Workshop) has two doors, I put them in series and called it shop. Not bad for a $12.91 conversion :slight_smile:

This is outstanding, thank you! I do have a question, doesn’t your Supervised install show as either unhealthy or unsupported since iot is not purely Debian? Does Debian run on Odroid N2?

As long as you start with a clean Debian Bullseye build it will show as healthy. I run my system on the odroid N2+ with 4G of ram and 32G ssd. Based on performance and cost of the N2+, I’ve, yet to see a better option for running HA. There’s a group that does debian for ARM that is my choice for the bullseye OS. The guy that runs the thing is very responsive and helpful. I contributed an HA install script into his menu-config tool. Here’s a post for that install using the distro. The only challenge with the approach is you have to build the initial image file running scripts on a linux (bullyseye) system. I use an X86 VM and with cross compiling capabilities to generate my image files. Some people don’t have the background or a build system around to generate the image. The guy that runs the site is always willing to post an image file. I’d also be willing to make an image file available if needed. When I originally made this GPIO post I was using Armbian, however because HA complained about it not being a clean debian build I shifted to the other approach. I’ve been running on this distro for a couple of years now and have been very satisfied.

I know, it quite a long time, but I want ask, how to get working GPIO on the odroid n2+. For my project I need working RX/TX (UART) communication, but OS which I tested doesn’t work with Odroid’s GPIO. Thanks for help

Did you use the distro provided here? This is the one I use and the GIO stuff works. I also use RX/TX as console port so I can access the device. From the site you actually have to build your own image file. They have a discord channel where you can get assistance. If need be people on the channel will post an image for you.

Ok, nice to see that there is any distro where gpio on the odroid is working. Quite complicated for me as amateur is to make a image file :frowning:

OK, I have a distro from your link, but now how to get a RX/TX working ?

Just to make sure we’re talking about the same thing, when you say RX/TX, you’re talking about the 4 pin UART on the opposite side as the 40 pin GPIO header, correct? Those UART pins, which include TX/RX pins are identified as the kernel as /dev/ttyAML0.

The next question would be what do you want to do with the pins? By default, based on the /boot/extlinux/extlinux.conf file, those pins are currently set to have a system console connected to them. This is result of this “console=ttyAML0,115200n8 console=both” on the append line in that file. If you want to use those pins for something else you would need to disable the system console from that port.

my idea was use rx/tx directly on thepin GPIO (pin8 and 10) :

which is I think identified as AML1

but if AML0 is working, I can also use this. How to modify a extlinux.conf file please to disable a system console?

thanks

I saw on the discord channel they got you set up to enable the GIOP pins as a UART. So I assume you’re good. But if you do want to remove ttyAML0 you edit the line I mentioned. You will see it actually has three console values being set. Leave the one I didn’t mention and remove “console=ttyAML0,115200n8 console=both”. I’m pretty sure that will do it for you after a reboot. You could then use something like the stty command to display or set the serial port parameters if need be as discussed here.

On the discord channel we “maybe” enabled UART_EE_A, so in the device list I can see a ttyAML0 and ttyAML1. But ttyAML1 isn’t accepted by the software, because I think isn’t correctly defined as serial port. Maybe I must insert any definition of AML1 into extlinux.conf. But not sure what’s correct definition. Second strange thing is, that on the link which you sent in the last post is always ttyS0 or ttyS1, but this I don’t have.

The device name is determine by the hardware and then associated driver. The fact that it is ttyAML vs ttyS shouldn’t matter. That would seem to be a problem with the software you are using. If the software expects it to be named ttyS0 you could try make a hard link using

ln /dev/ttyAML0 /dev/ttyS0

This then give you a device named /dev/ttyS0 that is really just /dev/AML0

Alternatively you could link /dev/ttyS0 name to the other serial device you enabled with the overlay.

so I opened a extlinux.conf :

label default
	kernel ../Image
	initrd ../uInitrd
	fdtdir ../amlogic/
	fdt ../amlogic/meson-g12b-odroid-n2-plus.dtb
	fdtoverlays ../amlogic/overlays/meson-g12b-odroid-n2-uart0.dtbo
	append earlyprintk console=tty1 console=ttyAML0,115200n8 console=both rw root=PARTUUID=0407e572-01 rootwait rootfstype=ext4 fsck.repair=yes loglevel=1 net.ifnames=0 no_console_suspend clk_ignore_unused usb-storage.quirks=0x152d:0x0576:u init=/sbin/init

but rename to ttyS1 also doesn’t work :

HANDLER_CONFIGURATION_PENDING
{serialPort=The value of /dev/ttyS1 does not match the enabled options parameter. Allowed options are: [ParameterOption [value="/dev/ttyUSB1", label="/dev/ttyUSB1"], ParameterOption [value="/dev/ttyUSB0", label="/dev/ttyUSB0"], ParameterOption [value ="/dev/serial/by-id/usb-Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_0001-if00-port0", label="/dev/serial/by-id/usb-Silicon_Labs_CP2102_USB_to_UART_Bridge_Controller_0001-if00-port0"], ParameterOption [value="/dev/ serial/by-id/usb-1a86_USB2.0-Ser_-if00-port0", label="/dev/serial/by-id/usb-1a86_USB2.0-Ser_-if00-port0"]]}

question is, if inside extlinux.conf this ttyAML1 or ttyS1 must be configurated as serial port

Looks like it’s telling you it wants a USB serial device. You could try the ln command again but this time ln /dev/ttyUSB0 ti the AML device instead of ttyS0 and see if that works. If it doesn’t work then remove the ln created for USB0. You could also just get a USB serial port device like this one and see if that meets your needs.

I already have two USB devices :slight_smile: ttyUSB0 and ttyUSB1. So he wants this two and next serial device AML1 looks like doesn’t exist for him.

does

sudo dmesg |grep tty 

show your AML devices as serial devices. On my system I get these lines in the output showing serial devices

[    0.504726] ff803000.serial: ttyAML0 at MMIO 0xff803000 (irq = 14, base_baud = 1500000) is a meson_uart
[    0.506430] ffd24000.serial: ttyAML1 at MMIO 0xffd24000 (irq = 15, base_baud = 1500000) is a meson_uart

Assuming you get something simular, I don’t know why your software isn’t providing these as options for possible assignment. You should reach out to that community and ask them what is required to get a serial device to be available. Provide them with the dmesg output and see what insight they can provide. It may be that software only supports usb devices and not on board devices.

You might also want to switch over to HA for your home automation needs.

is it ok?

It shows that both ttyAML0 and ttyAML1 are serial devices, so I would question why they don’t work with the software you’re trying to use.