Several external alarm solutions exist for integration with Home Assistant. I didn’t want to use any of those, and instead I wanted to implement an alarm with Home Assistant out-of-the-box. A manual alarm platform is provided but it has one missing functionality that was a must-have requirement in my situation, multiple user codes.
In this intermediate-level configuration example, lovelace cards are used to create a multi-user touchpad interface for Home Assistant, using only Home Assistant - lovelace cards, yaml configuration, scripts and automations.
If you are new to Home Assistant, this example will present a challenge! Enjoy
DESIGN
Home Assistant is displayed on Fully Kiosk Browser from Fire HD tablets throughout my home, and I wanted a simple way to provide each person in my home a separate user code, including guests, and integrate the alarm with Apple Homekit and Alexa voice assistants (which require user codes to be disabled).
In this solution, I use a lovelace button grid to collect touches with an input_text, and evaluated touch input against a user-code map using an automation. User codes and username are stored in the secrets.yaml file.
Note: solution was built for controlling a manual alarm, but this touchpad code solution can be adapted to do basically anything. Outside this example, I use a lovelace touchpad to disarm both an intrusion and a fire/carbon monoxide alarm panel. I also have a zwave lock on the front door and use zwave event data to call the disarm script which then notifies when and who has disarmed security.
SOLUTION
First define a user code map in secrets.yaml
# add usercode-name map entry to secrets.yaml
disarm_user_codes:
{
"1234": "Guest",
"0001": "User 1",
"0002": "User 2",
"0003": "User 3",
"0004": "User 4",
"0005": "User 5"
}
Create a manual alarm_control_panel, input_text, and two template sensors.
Optionally exclude the entities and scripts from the recorder to prevent history tracking, otherwise there will be multiple entries created for each touchpad input.
alarm_control_panel:
- platform: manual
name: Intrusion alarm
code_arm_required: false
armed_away:
delay_time: 0
arming_time: 10
armed_home:
delay_time: 20
arming_time: 10
armed_night:
delay_time: 0
arming_time: 0
input_text:
touchpad_code:
name: Touchpad code
#mode: password
pattern: "[0-9]*"
min: 0
max: 4
recorder:
exclude:
entities:
- input_text.touchpad_code
- sensor.touchpad_display
- script.touchpad_key
template:
- sensor:
- name: "Disarm user codes"
state: Mapped in attributes
attributes: !secret disarm_user_codes
- name: "Touchpad display"
unique_id: touchpad_display
state: >-
{% if is_state('input_text.touchpad_code', '') %}
{% set mode =
states('alarm_control_panel.intrusion_alarm') %}
{{ {
'disarmed': 'READY TO ARM',
'armed_home': 'ARMED FOR HOME',
'armed_away': "ARMED FOR AWAY",
'armed_night': 'ARMED FOR NIGHT',
'armed_vacation': 'ARMED FOR VACATION',
'triggered': 'INTRUSION ALARM',
'pending': 'PENDING ALARM',
'arming': 'ARMING ALARM'
} [mode] }}
{% else %}
{{ '****'[:(states('input_text.touchpad_code')
| length)] }}
{% endif %}
In lovelace, add a new card, search for the manual card, and paste the following:
# lovelace card that creates a touchpad
type: vertical-stack
cards:
- type: entity
entity: sensor.touchpad_display
name: ' '
icon: none
- type: grid
cards:
- type: button
tap_action:
action: call-service
service: script.touchpad_key
service_data:
key: 1
icon: mdi:numeric-1
- type: button
tap_action:
action: call-service
service: script.touchpad_key
service_data:
key: 2
icon: mdi:numeric-2
- type: button
tap_action:
action: call-service
service: script.touchpad_key
service_data:
key: 3
icon: mdi:numeric-3
- type: button
tap_action:
action: call-service
service: script.touchpad_key
service_data:
key: 4
icon: mdi:numeric-4
- type: button
tap_action:
action: call-service
service: script.touchpad_key
service_data:
key: 5
icon: mdi:numeric-5
- type: button
tap_action:
action: call-service
service: script.touchpad_key
service_data:
key: 6
icon: mdi:numeric-6
- type: button
tap_action:
action: call-service
service: script.touchpad_key
service_data:
key: 7
icon: mdi:numeric-7
- type: button
tap_action:
action: call-service
service: script.touchpad_key
service_data:
key: 8
icon: mdi:numeric-8
- type: button
tap_action:
action: call-service
service: script.touchpad_key
service_data:
key: 9
icon: mdi:numeric-9
- type: button
tap_action:
action: call-service
service: input_text.set_value
service_data:
value: ''
target:
entity_id: input_text.touchpad_code
name: Cancel
show_name: false
icon: mdi:close
- type: button
tap_action:
action: call-service
service: script.touchpad_key
service_data:
key: 0
icon: mdi:numeric-0
- type: button
tap_action:
action: call-service
service: script.touchpad_key
service_data:
key: '*'
name: Backspace
show_name: false
icon: mdi:backspace-outline
square: false
- type: horizontal-stack
cards:
- type: button
tap_action:
action: call-service
service: script.arm_home
icon: mdi:home
show_name: true
name: Home
- type: button
tap_action:
action: call-service
service: script.arm_away
icon: mdi:shield-lock
name: Away
- type: button
tap_action:
action: call-service
service: script.arm_night
icon: mdi:bed
name: Night
- type: history-graph
entities:
- entity: alarm_control_panel.intrusion_alarm
hours_to_show: 24
refresh_interval: 0
At this point there is a manual alarm_control_panel, two new sensors, an input_text and touchpad defined in lovelace
Each lovelace button calls a script that exposes a key variable to collect touch presses. Arming is implemented using arming scripts. When a manual alarm arming level is set while in a pending or triggered state, the triggered state is lost. Arming scripts have a condition that prevents kiosk users from effectively resetting a tripped manual alarm.
The buttons use the script’s entity_id, these can be pasted into the script ui but the entity_id must match
# scripts for button presses
touchpad_key:
alias: Touchpad key
sequence:
- choose:
- alias: asterix is backspace
conditions:
- condition: template
value_template: >
{{ key == '*' }}
sequence:
- service: input_text.set_value
target:
entity_id: input_text.touchpad_code
data:
value: >
{{ states('input_text.touchpad_code')[:-1] }}
default:
- service: input_text.set_value
target:
entity_id: input_text.touchpad_code
data:
value: >
{{ states('input_text.touchpad_code')[-3:] }}{{ key }}
- delay:
hours: 0
minutes: 0
seconds: 3
milliseconds: 0
- service: input_text.set_value
target:
entity_id: input_text.touchpad_code
data:
value: ''
mode: restart
fields:
key:
description: key character
example: '1'
icon: mdi:form-textbox-password
arm_away:
alias: Arm away
sequence:
# only set away from unalarmed state, and
# don't downgrade mode to home or night
- condition: not
conditions:
- condition: state
entity_id: alarm_control_panel.intrusion_alarm
state: triggered
- condition: state
entity_id: alarm_control_panel.intrusion_alarm
state: pending
- condition: state
entity_id: alarm_control_panel.intrusion_alarm
state: armed_away
- service: alarm_control_panel.alarm_arm_away
target:
entity_id: alarm_control_panel.intrusion_alarm
mode: single
icon: mdi:security
arm_home:
alias: Arm home
sequence:
# only set home from disarmed unalarmed state, but
# don't allow arming downgrade from away
- condition: not
conditions:
- condition: state
entity_id: alarm_control_panel.intrusion_alarm
state: triggered
- condition: state
entity_id: alarm_control_panel.intrusion_alarm
state: pending
- condition: state
entity_id: alarm_control_panel.intrusion_alarm
state: armed_away
- condition: state
entity_id: alarm_control_panel.intrusion_alarm
state: armed_home
- service: alarm_control_panel.alarm_arm_home
target:
entity_id: alarm_control_panel.intrusion_alarm
mode: single
icon: mdi:security
arm_night:
alias: Arm night
sequence:
# only set home from disarmed unalarmed state, and
# don't allow arming downgrade from away
- condition: not
conditions:
- condition: state
entity_id: alarm_control_panel.intrusion_alarm
state: triggered
- condition: state
entity_id: alarm_control_panel.intrusion_alarm
state: pending
- condition: state
entity_id: alarm_control_panel.intrusion_alarm
state: armed_away
- condition: state
entity_id: alarm_control_panel.intrusion_alarm
state: armed_night
- service: alarm_control_panel.alarm_arm_night
target:
entity_id: alarm_control_panel.intrusion_alarm
mode: single
icon: mdi:security
arm_disarmed:
alias: Arm disarmed
sequence:
- condition: not
conditions:
- condition: state
entity_id: alarm_control_panel.intrusion_alarm
state: disarmed
- service: alarm_control_panel.alarm_disarm
target:
entity_id: alarm_control_panel.intrusion_alarm
- service: notify.notify
data:
message: '{{ user }} disarmed security'
mode: single
fields:
user:
description: User or activity disarming security
example: guest
icon: mdi:security
Finally an automation is used to evaluate touchpad inputs
# automation to evaluate touchpad code input
alias: Touchpad code input
description: ''
trigger:
- platform: state
entity_id: input_text.touchpad_code
condition:
- condition: template
value_template: >
{{ state_attr('sensor.disarm_user_codes',
states('input_text.touchpad_code')) is not none }}
action:
- service: script.turn_on
target:
entity_id: script.arm_disarmed
data:
variables:
user: >
{{ state_attr('sensor.disarm_user_codes',
states('input_text.touchpad_code')) }}
- service: input_text.set_value
target:
entity_id: input_text.touchpad_code
data:
value: ''
- service: script.turn_off
target:
entity_id: script.touchpad_key
mode: single