Home Assistant is a powerful open-source tool for home automation, but as you start to build more complex setups, you may encounter challenges. One of these challenges is creating an intuitive and accessible interface that is also secure and child-proof. This guide is here to help.
Inspired by a desire to manage the intricate details of a Home Assistant (HASS) installation from an Amazon Fire HD 10 wall panel, without exposing critical controls to all users (especially curious little ones), Iâve developed a solution that combines the aesthetics of an alarm panel card with the functionality of a comprehensive control system. By the end of this guide, youâll know how to create a system that lets you easily switch between different screens and hide sensitive controls from non-admin users with proper password protection.
Security Caveat: Itâs important to note that this solution was not designed to function as a high-security lock, like that of a gun safe! Initial feedback highlighted considerations such as fingerprints on the screen, lock-out functionality based on bad attempts or device tracking, dynamic code cycling, and so forth. However, the primary goal here was to prevent a curious child or guest from accessing your admin screens, not to thwart a determined burglar. Therefore, while this solution serves as a useful interface management tool, it should not be relied upon for serious security purposes. Employ this at your own discretion and always assess the potential risks!
- The Sensors
The sensors for your home assistant keypad are vital components that drive the functionality of the system. They consist of two helper sensors and a template sensor.
- Keypad Input (input_text.keypad_input): This is a helper sensor, created in the UI under Settings > Devices & Services > Helpers, that serves as the input field for each button press on the keypad. Itâs configured with an icon of a dialpad (mdi:dialpad) and has a minimum length of 0 and a maximum length of 100. The display mode is set to Password to conceal the input for privacy (in certain places). It is enabled and visible in the Home Assistant User Interface (HASS UI). You can add this to your own installation by creating a new helper in the HASS UI, selecting the âTextâ type, and configuring it with the aforementioned properties.
- Keypad Code (input_text.keypad_code): This helper sensor is the âcorrect codeâ against which the Keypad Input is compared to determine if the correct PIN has been entered. It shares similar properties with the Keypad Input, including the dialpad icon, and a minimum and maximum length of 0 and 100, respectively. Although itâs enabled, itâs not visible in the HASS UI for security reasons. To add this to your own installation, follow the same steps as the Keypad Input but ensure that itâs not visible in the UI.
- Keypad Input Masked (sensor.keypad_input_masked): This is a template sensor that masks the value of the Keypad Input on the screen to maintain privacy. It uses the below template that calculates the length of the entered input and returns the same number of asterisks (*). This effectively hides the true input from view. Copy the below template to the âsensorâ configuration in your config.yaml. This will ensure that any entered input is masked with asterisks.
- sensor:
- name: Keypad Input Masked
unique_id: keypad_input_masked
state: >
{% set input_length = states('input_text.keypad_input')|length %}
{{ '*' * input_length }}
Thereâs one more sensor, Kiosk Additional Info (input_select.kiosk_additional_info), that weâll delve into in more detail in Section 5. As we explore the use of conditional cards and how they interact with our solution, weâll examine how this sensor plays a pivotal role in managing which screen is displayed, enabling a dynamic and adaptable interface.
- The Config Script
The keypad_input config script is a crucial piece of the home assistant keypad setup. This script is responsible for managing the input received from the keypad. It can be included in the main config.yaml file of your Home Assistant setup or in a separate script file using the !include method.
Hereâs how it works:
When a number is pressed on the keypad, this script is called. The scriptâs sequence involves a single service call to input_text.set_value, which sets the value of input_text.keypad_input. The value is determined by a data template.
The data template first fetches the current value of input_text.keypad_input. If the current value is neither âNoneâ nor âunknownâ, it appends the pressed number (converted to a string) to the current value. If the current value is âNoneâ or âunknownâ, it simply sets the value to the pressed number.
The script runs in âsingleâ mode, which means it doesnât allow concurrent runs. If the script is triggered while it is still running, the second trigger will be ignored. This means that rapid button pushes on the keypad may not take; youâll need to adjust your entry speed accordingly.
To add this script to your own installation, you can paste it directly into your config.yaml file under the script: key. If you have a separate scripts file, you can use the !include method in your config.yaml to reference that file.
script:
keypad_input:
alias: Keypad Input
sequence:
- service: input_text.set_value
data_template:
entity_id: input_text.keypad_input
value: >
{% set current_value = states('input_text.keypad_input') %}
{% if current_value != 'None' and current_value != 'unknown' %}
{{ current_value ~ number | string }}
{% else %}
{{ number | string }}
{% endif %}
mode: single
- The Lovelace Card
The Lovelace card for your Home Assistant keypad is a vertical-stack card, which stacks multiple cards vertically. This creates an organized, cohesive interface for user interaction. Note that this configuration requires u/thomaslovenâs lovelace-card-mod and u/RomRiderâs button-card, both of which are available through HACS (Home Assistant Community Store).
- Entity Card: The first card in the stack displays the state of the âkeypad_input_maskedâ sensor, which shows the masked input. It features a dialpad icon and the name âPasscode Requiredâ. The card has a custom style that removes the background and border, centers the text, and reduces the margin at the bottom for cleanliness.
- Grid Card: The second card in the stack is a grid card with three columns. It contains a total of 12 custom button cards that make up the numeric keypad, a clear button, and a submit button.
- Numeric Buttons: Each numeric button card (from â1â to â9â and â0â) calls a service (script.keypad_input) when tapped, passing the corresponding number as service data. They have a dialpad numeric-circle icon, a gray color scheme, and their visual effect when pressed is disabled.
- Clear Button: The clear button card, represented by an âXâ, calls a different service (input_text.set_value) when tapped, which clears the keypad input.
- Submit Button: The last button card is the submit button. Its icon color changes based on whether the entered code matches the correct code. If they match, the color turns green; if not, it stays gray. Note that this button doesnât perform an action when tapped. Instead, weâve harnessed the power of automations to unlock access to the protected screens. More on that in Section 4.
To add this to your own installation, navigate to the Lovelace UI editor in Home Assistant, create a new card of the type âManualâ, and paste the YAML code provided below. Ensure you have the necessary custom button-card component installed and the correct scripts and entities in place. The custom button-card component can be installed through HACS (Home Assistant Community Store).
type: vertical-stack
cards:
- type: entity
entity: sensor.keypad_input_masked
icon: mdi:dialpad
name: Passcode Required
style: |
ha-card {
--ha-card-background: none;
border: none;
text-align: center;
margin-bottom: -20px
}
- type: grid
columns: 3
square: false
cards:
- type: custom:button-card
show_name: false
show_icon: true
aspect_ratio: 1/.75
tap_action:
action: call-service
service: script.keypad_input
service_data:
number: '1'
icon: mdi:numeric-1-circle
color: '#bdbdbd'
size: 100%
styles:
card:
- background: none
- border: none
- '--mdc-ripple-press-opacity': 0
- type: custom:button-card
show_name: false
show_icon: true
aspect_ratio: 1/.75
tap_action:
action: call-service
service: script.keypad_input
service_data:
number: '2'
icon: mdi:numeric-2-circle
color: '#bdbdbd'
size: 100%
styles:
card:
- background: none
- border: none
- '--mdc-ripple-press-opacity': 0
- type: custom:button-card
show_name: false
show_icon: true
aspect_ratio: 1/.75
tap_action:
action: call-service
service: script.keypad_input
service_data:
number: '3'
icon: mdi:numeric-3-circle
color: '#bdbdbd'
size: 100%
styles:
card:
- background: none
- border: none
- '--mdc-ripple-press-opacity': 0
- type: custom:button-card
show_name: false
show_icon: true
aspect_ratio: 1/.75
tap_action:
action: call-service
service: script.keypad_input
service_data:
number: '4'
icon: mdi:numeric-4-circle
color: '#bdbdbd'
size: 100%
styles:
card:
- background: none
- border: none
- '--mdc-ripple-press-opacity': 0
- type: custom:button-card
show_name: false
show_icon: true
aspect_ratio: 1/.75
tap_action:
action: call-service
service: script.keypad_input
service_data:
number: '5'
icon: mdi:numeric-5-circle
color: '#bdbdbd'
size: 100%
styles:
card:
- background: none
- border: none
- '--mdc-ripple-press-opacity': 0
- type: custom:button-card
show_name: false
show_icon: true
aspect_ratio: 1/.75
tap_action:
action: call-service
service: script.keypad_input
service_data:
number: '6'
icon: mdi:numeric-6-circle
color: '#bdbdbd'
size: 100%
styles:
card:
- background: none
- border: none
- '--mdc-ripple-press-opacity': 0
- type: custom:button-card
show_name: false
show_icon: true
aspect_ratio: 1/.75
tap_action:
action: call-service
service: script.keypad_input
service_data:
number: '7'
icon: mdi:numeric-7-circle
color: '#bdbdbd'
size: 100%
styles:
card:
- background: none
- border: none
- '--mdc-ripple-press-opacity': 0
- type: custom:button-card
show_name: false
show_icon: true
aspect_ratio: 1/.75
tap_action:
action: call-service
service: script.keypad_input
service_data:
number: '8'
icon: mdi:numeric-8-circle
color: '#bdbdbd'
size: 100%
styles:
card:
- background: none
- border: none
- '--mdc-ripple-press-opacity': 0
- type: custom:button-card
show_name: false
show_icon: true
aspect_ratio: 1/.75
tap_action:
action: call-service
service: script.keypad_input
service_data:
number: '9'
icon: mdi:numeric-9-circle
color: '#bdbdbd'
size: 100%
styles:
card:
- background: none
- border: none
- '--mdc-ripple-press-opacity': 0
- type: custom:button-card
show_name: false
show_icon: true
aspect_ratio: 1/.75
tap_action:
action: call-service
service: input_text.set_value
service_data:
entity_id: input_text.keypad_input
value: ''
icon: mdi:alpha-x-circle-outline
color: '#f87272'
size: 100%
styles:
card:
- background: none
- border: none
- '--mdc-ripple-press-opacity': 0
- type: custom:button-card
show_name: false
show_icon: true
aspect_ratio: 1/.75
tap_action:
action: call-service
service: script.keypad_input
service_data:
number: '0'
icon: mdi:numeric-0-circle
color: '#bdbdbd'
size: 100%
styles:
card:
- background: none
- border: none
- '--mdc-ripple-press-opacity': 0
- type: custom:button-card
show_name: false
show_icon: true
aspect_ratio: 1/.75
tap_action:
action: none
icon: mdi:check-circle-outline
size: 100%
styles:
card:
- background: none
- border: none
- '--mdc-ripple-press-opacity': 0
icon:
- color: |
[[[
if (states['input_text.keypad_input'].state == states['input_text.keypad_code'].state) {
return "#8dc869"; //green
} else {
return "#bdbdbd"; //gray
}
]]]
- The Automation
The âKiosk Adminâ automation performs key tasks in managing the keypad and admin screens, ensuring that they are not left active for more than three minutes, and unlocking the admin screen when the entered keypad input matches the stored keypad code.
This automation triggers based on three conditions:
- Hide Keypad: When the kiosk_additional_info state changes to âkeypadâ and stays for 3 minutes.
- Hide Admin: When the kiosk_additional_info state changes to âadminâ and stays for 3 minutes.
- Authorized: When the keypad input (input_text.keypad_input) matches the stored keypad code (input_text.keypad_code).
On triggering, the automation performs the following actions based on the trigger condition:
- For âhide keypadâ and âhide adminâ triggers: The kiosk_additional_info state is set to âmainâ, effectively hiding the keypad and admin screens. The keypad input is also cleared to ensure no leftover data remains.
- For âauthorizedâ trigger: The kiosk_additional_info state is set to âadminâ, unlocking the admin screen. The keypad input is then cleared for security and readiness for the next input.
This automation runs in âsingleâ mode, which means if the automation is triggered again while itâs still running from a previous trigger, the new trigger will be ignored.
To add this automation to your own Home Assistant setup, you can paste this YAML code in your automations.yaml file, or use the automation editor in the Home Assistant UI. Make sure the entities (input_text.keypad_input, input_text.keypad_code, input_select.kiosk_additional_info) exist in your setup.
alias: Kiosk Admin
description: ""
trigger:
- platform: state
entity_id:
- input_select.kiosk_additional_info
to: keypad
for:
hours: 0
minutes: 3
seconds: 0
id: hide keypad
- platform: state
entity_id:
- input_select.kiosk_additional_info
to: admin
for:
hours: 0
minutes: 3
seconds: 0
id: hide admin
- platform: template
value_template: >-
{{ states('input_text.keypad_input') == states('input_text.keypad_code')
}}
id: authorized
condition: []
action:
- choose:
- conditions:
- condition: trigger
id: hide keypad
- condition: trigger
id: hide admin
sequence:
- service: input_select.select_option
data:
option: main
target:
entity_id: input_select.kiosk_additional_info
- service: input_text.set_value
data:
value: ""
target:
entity_id: input_text.keypad_input
- conditions:
- condition: trigger
id: authorized
sequence:
- service: input_select.select_option
data:
option: admin
target:
entity_id: input_select.kiosk_additional_info
- service: input_text.set_value
data:
value: ""
target:
entity_id: input_text.keypad_input
mode: single
- Conditional Cards
Conditional cards in Home Assistant are a powerful tool for creating dynamic, responsive dashboards that can change their displayed content based on the state of certain entities. In this case, the input_select.kiosk_additional_info entity is being used to determine which screen to display. Of note, I personally reserve half of my main display for conditional content such as a summary of key sensors, a local weather report, and a media controller.
The input_select.kiosk_additional_info entity is a Helper entity, specifically an Input Select Helper. Input Select Helpers allow you to define a list of options, and you can set or get the selected option via services or in the frontend via a dropdown.
The example conditional card below checks the state of input_select.kiosk_additional_info, and if the state is âadminâ, it displays a vertical stack card with a series of controls and information relevant to the âadminâ view.
type: vertical-stack
cards:
- type: conditional
conditions:
- entity: input_select.kiosk_additional_info
state: admin
card:
type: vertical-stack
cards: [...]
The use of an Input Select Helper here, as opposed to an Input Text Helper, adds a user-friendly dropdown interface in the Home Assistant UI, making it easier to switch between screens without needing to remember or manually type the exact state string. This is especially useful when debugging or if you have a large number of possible screens, but can also slow you down if youâre creating and testing new screens on the fly.
To set up similar functionality in your own Home Assistant instance, you would create the necessary Helper entities (such as input_select.kiosk_additional_info) with the appropriate options for your use case, then create conditional cards for each option that display the content you want for that state. Then, by changing the state of the Helper entity, either manually in the UI or automatically through an automation or script, you can control which screen is displayed.
Conclusion
Building a secure, flexible, and user-friendly interface for Home Assistant is a multifaceted task, but with the right approach, itâs entirely achievable. By leveraging Helper entities, scripts, automation, and conditional cards, you can create a control system that adapts to your needs, hides sensitive controls from unauthorized users, and even adds an extra layer of security with a password-protected admin screen.
Remember, the best part about Home Assistant is its flexibility! If this setup doesnât perfectly suit your needs, you can adjust, expand, or simplify as you see fit. Hopefully, this guide serves as a good starting point for your journey into more advanced Home Assistant interfaces.
Note: This guide was originally posted to Reddit