Overview

This project is a DIY touchscreen panel to arm/disarm Home Assistant's alarm system. It's powered by a Raspberry Pi, 3.5" touchscreen display, a custom Python-based application, and MQTT.

The control panel in action

This guide walks you through the creation of the project and provides everything you need to create your own!

Home Assistant

Home Assistant is an amazing open-source home automation platform. Among its many features is the ability to implement your own home security alarm system. You can then use various sensors to determine if/when to trigger an alarm.

In my case, I have several Z-Wave door sensors on all of my exterior doors. If any door opens while the alarm is active, I receive instant push notifications on my phone and computers. Eventually I'll be expanding this to include motion sensors and a siren.

While this works fine, the only way to arm/disarm the device is through the web interface. The manual alarm unfortunately doesn't have a single API interface we can use to send arm/disarm commands while also receiving instant state changes from HA.

I therefore created the new Manual MQTT Alarm component which functions identically to the manual alarm, but also allows two-way communication over MQTT! With this component we can easily build our own remote keypad using any web-connected platform we can imagine. In my case, I chose to build a solution using a Raspberry Pi with a touchscreen.

Hardware

At a minimum, you'll need the following components:

Raspberry Pi*

Micro SD card

Micro USB cable for power

*I used a Pi Zero W for this project, but any Pi with wifi should work (even one using a USB wifi adapter).

Optional: The software also supports an optional screensaver mode where the screen blacks out after so much time. By adding a PIR motion sensor we can have the screen stay off until someone approaches the keypad, thus prolonging the life of the display. Simply connect the PIR sensor to the extra pins on the underside of the display - see the Motion Sensor section further down this page.

Preparing Home Assistant and MQTT

Home Assistant v0.50 adds the new alarm.manual_mqtt component we'll need to use. This relies on having the MQTT platform up-and-running, so make sure you do that first.

To add the alarm to Home Assistant, simply drop this into your file: configuration.yml

alarm_control_panel: platform: manual_mqtt state_topic: "home/alarm" command_topic: "home/alarm/set" name: Alarm

A full list of configuration options can be found on the alarm.manual_mqtt documentation page.

Preparing the Raspberry Pi

The PiTFT display requires special kernel drivers, configuration, and calibration. Adafruit does provide a nice guide and pre-baked OS image which includes these; however, this older image does not work properly with the Pi Zero W (wifi is completely broken).

In my case, I ended up installing the latest version of Raspbian Jessie Lite and followed these instructions to get the display working.

Note: You do not need an X desktop environment for this project as the software draws directly to the screen's frame buffer. If you follow the instructions in the previous link, simply skip over any section which references X11.

At this point, you should have a fully-functioning Linux CLI appearing on your TFT!

I forgot to take a photo of this step, so here's one from the Adafruit guide (http://bit.ly/2h4dPze)

To get the touch screen working with pygame, make sure you're using SDL 1.2. More information and details on how to do this can be found here: https://learn.adafruit.com/adafruit-pitft-28-inch-resistive-touchscreen-display-raspberry-pi/pitft-pygame-tips#ensure-you-are-running-sdl-1-dot-2

Now we can install the alarm panel software onto the Pi!

Software

The software that runs on the control panel can be found on GitHub: https://github.com/colinodell/mqtt-control-panel

To install it, use Git to clone the repository to some location - I chose /srv :

cd /srv git clone https://github.com/colinodell/mqtt-control-panel.git . pip install -r requirements.txt

You'll also need to configure the panel by copying the .env.dist example file to .env and editing the following settings:

PINS - A comma-separated list of 4-digit pins you'd like to use.

MQTT_HOST - The IP or hostname of the MQTT server

MQTT_USER - The username for MQTT

MQTT_PASS - The corresponding password for MQTT

You can now run the program:

python /srv/main.py

Lastly, if you'd like the alarm panel to start on boot, add something like this to your rc.local file (above the exit 0 line):

python /srv/main.py &

Optional Motion Sensor / Screensaver

To maximize the lifetime of the display, a PIR motion sensor can be used to automatically turn the display off when nobody is around. The PiTFT display conveniently exposes GPIO pins on its underside, so simply make the following connections:

VDC to 5v

GND to ground

OUT to any unused GPIO (such as pin 23)

Location of the extra pins. These use the same 20-pin layout as the first-gen Pis

Make sure to add the following line to your .env file so the control panel knows about your sensor - replace 23 with whichever GPIO pin you chose to use:

PIR_GPIO_PIN=23

(If your control panel is already running then you'll need to restart it after making this change.)

Usage

The display should automatically connect to MQTT once the application starts.

Photo taken with a potato - sorry for the poor quality!

Whenever the state of the alarm is changed in Home Assistant, it'll automatically push that new state via MQTT to the display in real time.

To change the alarm state via the alarm panel, you must first input a valid PIN code by pressing the corresponding numeric keys. If you accidentally press the wrong button, just tap on the masked input, the # key, or the * key to clear your input.

Entering a valid PIN will unlock the buttons to change the state:

Disarm

Arm Home

Arm Away

Pressing any of these will send a command via MQTT to Home Assistant to make that corresponding change.

Under the Hood - Creating the UI and Application

Designing the UI was fairly straight-forward. Using Photoshop, I created a new 480x320 workspace and divided it into a grid of equal units to ensure the buttons were properly sized and aligned:

Each button and its different states were then extracted to PNG.

The Python application uses a custom UI library I created on top of PyGame. Everything (except for the status text) is rendered as a "button" with multiple states:

PIN input (1-9, *, 0, and #):

Default

Pressed

Action buttons (disarm, arm home, arm away):

Default (disabled)

Active (the current state of the alarm system)

Available (enabled - can be chosen once a correct PIN is entered)

Even the box showing the current masked PIN is drawn as a "button" with states:

Default (no input entered)

1 number entered

2 numbers entered

3 numbers entered

4 numbers entered, PIN is valid

4 numbers entered, PIN is incorrect

Each button state has its own image - we simply keep track of the current state and flip between the images as needed.

The application itself runs a simple event loop - on each iteration, we check for screen touches or incoming state changes via MQTT. The UI state is also redrawn as needed. To keep the CPU from running at 100% and generating excessive heat, we also sleep for a very brief period.

The action buttons become unlocked once a correct PIN is entered. When an unlocked action button is pressed we immediately fire a command to Home Assistant via MQTT to change the state of the alarm accordingly.

Enclosure

Every DIY project needs an enclosure, so I took a stab at designing a custom 3D-printed case to house my control panel and PIR sensor:

It's not the most beautiful case, some of the internal measurements aren't 100% perfect, and there are some minor issues:

There's a slight gap between the back of the Pi and the rear of the enclosure - ideally I'd like them to sit flush. This was fixed with hot glue.

The support pillars could be stronger.

The thickness of the front plate is slightly shorter than the TFT display, causing it to stick out by ~1mm.

There are no extra ventilation holes (heat hasn't been an issue yet though).

The design is extremely basic (I'm not a designer).

For these reasons I may redesign the case in the future, but for now it's working well enough for my needs :)

The measurements of the display and PIR sensor were perfect, so those fit nice and snug into the front of the enclosure. Once installed, I used a decent amount of hot glue to keep the PCBs attached to the inside of the front face.

Display, Pi, and PIR sensor mounted onto the face plate just before adding hot glue.

For the rear, I simply threaded a micro USB cable through the hole, plugged that into the Pi, and snapped the front and rear pieces together. The hot glue I added before was still warm, so it helped bond the front and rear pieces together.

Attaching the front face plate to the rear box.

I then mounted it on the wall using Command Large Picture Hanging Strips (the ones with velcro-like material). I could've made holes in the case and used screws, but I wanted something less permanent in case I decide to make improvements later.

Summary

I'm very pleased with how this turned out. There are certainly some areas for improvement, but overall it works extremely well for my needs.

Let me know if you build your own - I'd love to see it! Also, because the software is open-source, please feel free to contribute any bug fixes or enhancements :)

Happy Automation!