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.
This guide walks you through the creation of the project and provides everything you need to create your own!
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.
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.
To add the alarm to Home Assistant, simply drop this into your file:
alarm_control_panel: platform: manual_mqtt state_topic: "home/alarm" command_topic: "home/alarm/set" name: Alarm
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).
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!
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!
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
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
example file to
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:
Lastly, if you'd like the alarm panel to start on boot, add something like this to your rc.local file (above the
python /srv/main.py &
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)
Make sure to add the following line to your
file so the control panel knows about your sensor - replace 23 with whichever GPIO pin you chose to use:
(If your control panel is already running then you'll need to restart it after making this change.)
The display should automatically connect to MQTT once the application starts.
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:
- Arm Home
- Arm Away
Pressing any of these will send a command via MQTT to Home Assistant to make that corresponding change.
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.
PIN input (1-9, *, 0, and #):
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.
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.
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.
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.
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 :)