Home Assistant Timer Dashboard¶
This example demonstrates how to create a comprehensive Home Assistant dashboard for monitoring and controlling voice assistant timers. The dashboard displays device status, timer progress, and provides quick controls for all timer-enabled areas.
Overview¶
Prerequisites¶
Required HACS Components¶
This dashboard uses several custom cards from HACS (Home Assistant Community Store):
- Mushroom Cards - Modern, customizable cards
- Timer Bar Card - Visual timer progress bars
- card-mod - CSS styling for cards
Install these via HACS before using this dashboard.
Required Entities¶
The dashboard expects these entities from the Voice Assistant Persistent Timers setup:
| Entity | Description |
|---|---|
sensor.{area}_voice_assistant_state |
Voice assistant phase (idle, listening, etc.) |
timer.{area} |
Home Assistant timer entity |
switch.{area}_voice_assistant_mute |
Microphone mute control |
input_number.{area}_timer_duration_minutes |
Quick-start timer duration |
Configuration¶
Dashboard Header¶
# file: home-assistant/dashboards/timer-dashboard.yaml
# section: header
title: Voice Assistant Dashboard
views:
- title: Timers
path: timers
icon: mdi:timer
type: sections
max_columns: 3
Section: Device Status Title¶
# file: home-assistant/dashboards/timer-dashboard.yaml
# section: status_title
sections:
- type: grid
column_span: 2
cards:
- type: custom:mushroom-title-card
title: Device Status
subtitle: Voice assistant monitoring across all areas
Section: Device Status Cards¶
Each device status card consists of two parts:
- A
picture-entitycard showing state-based images - A
mushroom-template-cardshowing status text and mute toggle
# file: home-assistant/dashboards/timer-dashboard.yaml
# section: device_status_cards
- type: horizontal-stack
cards:
# Kitchen Device Status
- type: vertical-stack
cards:
- type: picture-entity
entity: sensor.kitchen_voice_assistant_state
name: Kitchen
show_name: false
show_state: false
state_image:
idle: /local/voice-assistant/idle.png
listening: /local/voice-assistant/listening.png
thinking: /local/voice-assistant/thinking.png
replying: /local/voice-assistant/replying.png
error: /local/voice-assistant/error.png
not_ready: /local/voice-assistant/loading.png
muted: /local/voice-assistant/muted.png
timer_finished: /local/voice-assistant/timer-finished.png
unavailable: /local/voice-assistant/loading.png
unknown: /local/voice-assistant/loading.png
image: /local/voice-assistant/idle.png
tap_action:
action: more-info
card_mod:
style: |
ha-card {
background: transparent;
box-shadow: none;
border-radius: 12px;
overflow: hidden;
}
- type: custom:mushroom-template-card
primary: Kitchen
secondary: >-
{% set state = states('sensor.kitchen_voice_assistant_state') %}
{% if state == 'muted' %} MUTED
{% elif state == 'idle' %} Online · Ready
{% elif state == 'listening' %} Listening...
{% elif state == 'thinking' %} Processing...
{% elif state == 'replying' %} Speaking...
{% elif state == 'timer_finished' %} Timer Complete!
{% elif state == 'error' %} Error
{% elif state == 'not_ready' %} Connecting...
{% else %} {{ state | title }}
{% endif %}
icon: >-
{% if is_state('switch.kitchen_voice_assistant_mute', 'on') %}
mdi:microphone-off
{% else %}
mdi:microphone
{% endif %}
icon_color: >-
{% if is_state('switch.kitchen_voice_assistant_mute', 'on') %}
red
{% else %}
green
{% endif %}
entity: switch.kitchen_voice_assistant_mute
tap_action:
action: toggle
hold_action:
action: more-info
card_mod:
style: |
ha-card {
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
border-bottom: 3px solid var(--primary-color);
margin-top: -8px;
}
# Bedroom Device Status
- type: vertical-stack
cards:
- type: picture-entity
entity: sensor.bedroom_voice_assistant_state
name: Bedroom
show_name: false
show_state: false
state_image:
idle: /local/voice-assistant/idle.png
listening: /local/voice-assistant/listening.png
thinking: /local/voice-assistant/thinking.png
replying: /local/voice-assistant/replying.png
error: /local/voice-assistant/error.png
not_ready: /local/voice-assistant/loading.png
muted: /local/voice-assistant/muted.png
timer_finished: /local/voice-assistant/timer-finished.png
unavailable: /local/voice-assistant/loading.png
unknown: /local/voice-assistant/loading.png
image: /local/voice-assistant/idle.png
tap_action:
action: more-info
card_mod:
style: |
ha-card {
background: transparent;
box-shadow: none;
border-radius: 12px;
overflow: hidden;
}
- type: custom:mushroom-template-card
primary: Bedroom
secondary: >-
{% set state = states('sensor.bedroom_voice_assistant_state') %}
{% if state == 'muted' %} MUTED
{% elif state == 'idle' %} Online · Ready
{% elif state == 'listening' %} Listening...
{% elif state == 'thinking' %} Processing...
{% elif state == 'replying' %} Speaking...
{% elif state == 'timer_finished' %} Timer Complete!
{% elif state == 'error' %} Error
{% elif state == 'not_ready' %} Connecting...
{% else %} {{ state | title }}
{% endif %}
icon: >-
{% if is_state('switch.bedroom_voice_assistant_mute', 'on') %}
mdi:microphone-off
{% else %}
mdi:microphone
{% endif %}
icon_color: >-
{% if is_state('switch.bedroom_voice_assistant_mute', 'on') %}
red
{% else %}
green
{% endif %}
entity: switch.bedroom_voice_assistant_mute
tap_action:
action: toggle
hold_action:
action: more-info
card_mod:
style: |
ha-card {
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
border-bottom: 3px solid #FF8000;
margin-top: -8px;
}
# Playroom Device Status
- type: vertical-stack
cards:
- type: picture-entity
entity: sensor.playroom_voice_assistant_state
name: Playroom
show_name: false
show_state: false
state_image:
idle: /local/voice-assistant/idle.png
listening: /local/voice-assistant/listening.png
thinking: /local/voice-assistant/thinking.png
replying: /local/voice-assistant/replying.png
error: /local/voice-assistant/error.png
not_ready: /local/voice-assistant/loading.png
muted: /local/voice-assistant/muted.png
timer_finished: /local/voice-assistant/timer-finished.png
unavailable: /local/voice-assistant/loading.png
unknown: /local/voice-assistant/loading.png
image: /local/voice-assistant/idle.png
tap_action:
action: more-info
card_mod:
style: |
ha-card {
background: transparent;
box-shadow: none;
border-radius: 12px;
overflow: hidden;
}
- type: custom:mushroom-template-card
primary: Playroom
secondary: >-
{% set state = states('sensor.playroom_voice_assistant_state') %}
{% if state == 'muted' %} MUTED
{% elif state == 'idle' %} Online · Ready
{% elif state == 'listening' %} Listening...
{% elif state == 'thinking' %} Processing...
{% elif state == 'replying' %} Speaking...
{% elif state == 'timer_finished' %} Timer Complete!
{% elif state == 'error' %} Error
{% elif state == 'not_ready' %} Connecting...
{% else %} {{ state | title }}
{% endif %}
icon: >-
{% if is_state('switch.playroom_voice_assistant_mute', 'on') %}
mdi:microphone-off
{% else %}
mdi:microphone
{% endif %}
icon_color: >-
{% if is_state('switch.playroom_voice_assistant_mute', 'on') %}
red
{% else %}
green
{% endif %}
entity: switch.playroom_voice_assistant_mute
tap_action:
action: toggle
hold_action:
action: more-info
card_mod:
style: |
ha-card {
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
border-bottom: 3px solid #0080FF;
margin-top: -8px;
}
Section: Timer Status with Progress Bars¶
The timer status section uses timer-bar-card for visual countdown representation with play/pause/stop controls:
# file: home-assistant/dashboards/timer-dashboard.yaml
# section: timer_status
- type: grid
column_span: 3
cards:
- type: custom:mushroom-title-card
title: Timer Status
subtitle: Active timer monitoring across all areas
- type: horizontal-stack
cards:
# Kitchen Timer
- type: vertical-stack
cards:
- type: custom:timer-bar-card
entity: timer.kitchen
name: Kitchen
icon: mdi:chef-hat
bar_height: 8px
bar_background: "#333333"
bar_foreground: var(--primary-color)
text_width: 6em
layout: hide_name
invert: true
card_mod:
style: |
ha-card {
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
border-left: 4px solid var(--primary-color);
}
- type: horizontal-stack
cards:
# Play button
- type: custom:mushroom-template-card
icon: mdi:play
icon_color: green
tap_action:
action: call-service
service: script.kitchen_start_timer
card_mod:
style: |
ha-card {
background: #1a1a1a;
--icon-size: 32px;
}
mushroom-shape-icon {
--shape-color: rgba(76, 175, 80, 0.2) !important;
}
# Pause button
- type: custom:mushroom-template-card
icon: mdi:pause
icon_color: orange
tap_action:
action: call-service
service: timer.pause
service_data:
entity_id: timer.kitchen
card_mod:
style: |
ha-card {
background: #1a1a1a;
--icon-size: 32px;
}
mushroom-shape-icon {
--shape-color: rgba(255, 152, 0, 0.2) !important;
}
# Stop button
- type: custom:mushroom-template-card
icon: mdi:stop
icon_color: red
tap_action:
action: call-service
service: timer.cancel
service_data:
entity_id: timer.kitchen
card_mod:
style: |
ha-card {
background: #1a1a1a;
--icon-size: 32px;
}
mushroom-shape-icon {
--shape-color: rgba(244, 67, 54, 0.2) !important;
}
# Bedroom Timer
- type: vertical-stack
cards:
- type: custom:timer-bar-card
entity: timer.bedroom
name: Bedroom
icon: mdi:bed
bar_height: 8px
bar_background: "#333333"
bar_foreground: "#FF8000"
text_width: 6em
layout: hide_name
invert: true
card_mod:
style: |
ha-card {
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
border-left: 4px solid #FF8000;
}
- type: horizontal-stack
cards:
- type: custom:mushroom-template-card
icon: mdi:play
icon_color: green
tap_action:
action: call-service
service: script.bedroom_start_timer
card_mod:
style: |
ha-card {
background: #1a1a1a;
--icon-size: 32px;
}
mushroom-shape-icon {
--shape-color: rgba(76, 175, 80, 0.2) !important;
}
- type: custom:mushroom-template-card
icon: mdi:pause
icon_color: orange
tap_action:
action: call-service
service: timer.pause
service_data:
entity_id: timer.bedroom
card_mod:
style: |
ha-card {
background: #1a1a1a;
--icon-size: 32px;
}
mushroom-shape-icon {
--shape-color: rgba(255, 152, 0, 0.2) !important;
}
- type: custom:mushroom-template-card
icon: mdi:stop
icon_color: red
tap_action:
action: call-service
service: timer.cancel
service_data:
entity_id: timer.bedroom
card_mod:
style: |
ha-card {
background: #1a1a1a;
--icon-size: 32px;
}
mushroom-shape-icon {
--shape-color: rgba(244, 67, 54, 0.2) !important;
}
# Playroom Timer
- type: vertical-stack
cards:
- type: custom:timer-bar-card
entity: timer.playroom
name: Playroom
icon: mdi:gamepad-variant
bar_height: 8px
bar_background: "#333333"
bar_foreground: "#0080FF"
text_width: 6em
layout: hide_name
invert: true
card_mod:
style: |
ha-card {
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
border-left: 4px solid #0080FF;
}
- type: horizontal-stack
cards:
- type: custom:mushroom-template-card
icon: mdi:play
icon_color: green
tap_action:
action: call-service
service: script.playroom_start_timer
card_mod:
style: |
ha-card {
background: #1a1a1a;
--icon-size: 32px;
}
mushroom-shape-icon {
--shape-color: rgba(76, 175, 80, 0.2) !important;
}
- type: custom:mushroom-template-card
icon: mdi:pause
icon_color: orange
tap_action:
action: call-service
service: timer.pause
service_data:
entity_id: timer.playroom
card_mod:
style: |
ha-card {
background: #1a1a1a;
--icon-size: 32px;
}
mushroom-shape-icon {
--shape-color: rgba(255, 152, 0, 0.2) !important;
}
- type: custom:mushroom-template-card
icon: mdi:stop
icon_color: red
tap_action:
action: call-service
service: timer.cancel
service_data:
entity_id: timer.playroom
card_mod:
style: |
ha-card {
background: #1a1a1a;
--icon-size: 32px;
}
mushroom-shape-icon {
--shape-color: rgba(244, 67, 54, 0.2) !important;
}
Section: Quick Controls¶
Quick controls allow setting timer duration and toggling microphone mute:
# file: home-assistant/dashboards/timer-dashboard.yaml
# section: quick_controls
- type: grid
column_span: 3
cards:
- type: custom:mushroom-title-card
title: Quick Controls
subtitle: Timer duration and microphone management
- type: horizontal-stack
cards:
# Kitchen Quick Controls
- type: vertical-stack
cards:
- type: custom:mushroom-title-card
title: Kitchen
card_mod:
style: |
ha-card {
--primary-text-color: var(--primary-color);
--title-font-size: 16px;
}
- type: custom:mushroom-number-card
entity: input_number.kitchen_timer_duration_minutes
name: Duration
icon: mdi:timer-outline
display_mode: buttons
card_mod:
style: |
ha-card {
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
border-left: 3px solid var(--primary-color);
}
- type: custom:mushroom-template-card
entity: switch.kitchen_voice_assistant_mute
primary: Microphone
secondary: >-
{% if is_state('switch.kitchen_voice_assistant_mute', 'on') %}
Muted
{% else %}
Active
{% endif %}
icon: >-
{% if is_state('switch.kitchen_voice_assistant_mute', 'on') %}
mdi:microphone-off
{% else %}
mdi:microphone
{% endif %}
icon_color: >-
{% if is_state('switch.kitchen_voice_assistant_mute', 'on') %}
red
{% else %}
green
{% endif %}
tap_action:
action: toggle
card_mod:
style: |
ha-card {
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
border-left: 3px solid var(--primary-color);
}
# Bedroom Quick Controls
- type: vertical-stack
cards:
- type: custom:mushroom-title-card
title: Bedroom
card_mod:
style: |
ha-card {
--primary-text-color: #FF8000;
--title-font-size: 16px;
}
- type: custom:mushroom-number-card
entity: input_number.bedroom_timer_duration_minutes
name: Duration
icon: mdi:timer-outline
display_mode: buttons
card_mod:
style: |
ha-card {
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
border-left: 3px solid #FF8000;
}
- type: custom:mushroom-template-card
entity: switch.bedroom_voice_assistant_mute
primary: Microphone
secondary: >-
{% if is_state('switch.bedroom_voice_assistant_mute', 'on') %}
Muted
{% else %}
Active
{% endif %}
icon: >-
{% if is_state('switch.bedroom_voice_assistant_mute', 'on') %}
mdi:microphone-off
{% else %}
mdi:microphone
{% endif %}
icon_color: >-
{% if is_state('switch.bedroom_voice_assistant_mute', 'on') %}
red
{% else %}
green
{% endif %}
tap_action:
action: toggle
card_mod:
style: |
ha-card {
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
border-left: 3px solid #FF8000;
}
# Playroom Quick Controls
- type: vertical-stack
cards:
- type: custom:mushroom-title-card
title: Playroom
card_mod:
style: |
ha-card {
--primary-text-color: #0080FF;
--title-font-size: 16px;
}
- type: custom:mushroom-number-card
entity: input_number.playroom_timer_duration_minutes
name: Duration
icon: mdi:timer-outline
display_mode: buttons
card_mod:
style: |
ha-card {
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
border-left: 3px solid #0080FF;
}
- type: custom:mushroom-template-card
entity: switch.playroom_voice_assistant_mute
primary: Microphone
secondary: >-
{% if is_state('switch.playroom_voice_assistant_mute', 'on') %}
Muted
{% else %}
Active
{% endif %}
icon: >-
{% if is_state('switch.playroom_voice_assistant_mute', 'on') %}
mdi:microphone-off
{% else %}
mdi:microphone
{% endif %}
icon_color: >-
{% if is_state('switch.playroom_voice_assistant_mute', 'on') %}
red
{% else %}
green
{% endif %}
tap_action:
action: toggle
card_mod:
style: |
ha-card {
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
border-left: 3px solid #0080FF;
}
cards: []
Supporting Configuration¶
Input Number Helpers¶
Create input_number entities for quick-start timer durations:
# file: home-assistant/configuration.yaml
# section: input_number
input_number:
kitchen_timer_duration_minutes:
name: Kitchen Timer Duration
min: 1
max: 60
step: 1
unit_of_measurement: min
icon: mdi:timer
bedroom_timer_duration_minutes:
name: Bedroom Timer Duration
min: 1
max: 60
step: 1
unit_of_measurement: min
icon: mdi:timer
playroom_timer_duration_minutes:
name: Playroom Timer Duration
min: 1
max: 60
step: 1
unit_of_measurement: min
icon: mdi:timer
Quick Start Scripts¶
Create scripts to start timers with the configured duration:
# file: home-assistant/scripts/timer_quick_start.yaml
# section: quick_start_scripts
script:
kitchen_start_timer:
alias: "Kitchen: Start Timer"
sequence:
- service: timer.start
target:
entity_id: timer.kitchen
data:
duration: >-
{{ states('input_number.kitchen_timer_duration_minutes') | int * 60 }}
bedroom_start_timer:
alias: "Bedroom: Start Timer"
sequence:
- service: timer.start
target:
entity_id: timer.bedroom
data:
duration: >-
{{ states('input_number.bedroom_timer_duration_minutes') | int * 60 }}
playroom_start_timer:
alias: "Playroom: Start Timer"
sequence:
- service: timer.start
target:
entity_id: timer.playroom
data:
duration: >-
{{ states('input_number.playroom_timer_duration_minutes') | int * 60 }}
Status Images¶
Place voice assistant state images in your Home Assistant www directory:
config/
└── www/
└── voice-assistant/
├── idle.png
├── listening.png
├── thinking.png
├── replying.png
├── error.png
├── loading.png
├── muted.png
└── timer-finished.png
You can download the default ESPHome casita images from:
Customization¶
Area Colors¶
Each area uses a distinct accent color:
- Kitchen: Primary theme color (
var(--primary-color)) - Bedroom: Orange (
#FF8000) - Playroom: Blue (
#0080FF)
Change these by editing the border-left and bar_foreground values.
Adding More Areas¶
To add a new area (e.g., office):
- Create the timer entity:
timer.office - Add the ESPHome device with
timer_area: "office" - Create
input_number.office_timer_duration_minutes - Create
script.office_start_timer - Duplicate one of the device status cards and timer cards
- Replace all entity references with
office
Dark/Light Theme Support¶
The dashboard uses hardcoded dark theme colors. For automatic theme support, replace:
#1a1a1awithvar(--card-background-color)#2d2d2dwithvar(--secondary-background-color)#333333withvar(--divider-color)
Installation¶
- Install required HACS components (Mushroom, Timer Bar Card, card-mod)
- Create the input_number helpers (via UI or YAML)
- Create the quick-start scripts
- Add the dashboard YAML to your Lovelace configuration
- Place status images in
www/voice-assistant/ - Reload Lovelace
Troubleshooting¶
| Issue | Solution |
|---|---|
| Cards show "Custom element doesn't exist" | Install the required HACS components |
| Timer bar not updating | Ensure timer.{area} entity exists and is properly configured |
| Images not loading | Check that images are in www/ and referenced as /local/ |
| Styles not applying | Ensure card-mod is installed and reload the browser |