A Home Assistant custom integration for orchestrating multi-step A/V and automation sequences. Define "room modes" that execute a series of steps with dependency tracking, parallel execution, verification, and retry logic.
Includes a companion Lovelace card (room-mode-card) for one-tap mode activation with real-time step status feedback.
- Add this repository as a custom repository in HACS
- Install "Room Modes"
- Restart Home Assistant
- Add the frontend card resource (see Frontend Card)
- Copy
custom_components/room_modes/to yourconfig/custom_components/directory - Copy
custom_components/room_modes/room-mode-card.jsto yourconfig/www/directory - Copy
custom_components/room_modes/tv-control-card.jsto yourconfig/www/directory - Restart Home Assistant
Add your modes to room_modes.yaml in your config directory (or inline under room_modes: in configuration.yaml).
If using a separate file, add this to configuration.yaml:
room_modes: !include room_modes.yamlliving_room_present:
name: Living Room Present
icon: mdi:presentation-play
description: Present from the HDMI cable in the living room.
steps:
- id: ensure_tv_on
label: TV power
icon: mdi:power
service: automation.trigger
service_data:
entity_id: automation.turn_on_living_room_tv
skip_condition: true
verify:
type: state
entity_id: media_player.living_room_tv
value: "on"
timeout: 40
retry: 0
- id: set_tv_hdmi1
label: TV HDMI1
icon: mdi:video-input-hdmi
depends_on:
- ensure_tv_on
service: media_player.select_source
service_data:
entity_id: media_player.living_room_tv
source: HDMI1
verify:
type: attribute
entity_id: media_player.living_room_tv
attribute: source
value: HDMI1
timeout: 20
retry: 1
- id: set_audio
label: Audio HDMI
icon: mdi:speaker
service: media_player.select_source
service_data:
entity_id: media_player.audio_switch
source: HDMI
verify:
type: attribute
entity_id: media_player.audio_switch
attribute: source
value: HDMI
timeout: 20
retry: 1| Option | Required | Default | Description |
|---|---|---|---|
id |
Yes | Unique step identifier (slug) | |
label |
Yes | Human-readable step name | |
icon |
No | mdi:button-cursor |
MDI icon for the step |
service |
Yes | Service to call (e.g. media_player.select_source) |
|
service_data |
No | {} |
Data to pass to the service call |
depends_on |
No | [] |
List of step IDs that must succeed before this step runs |
targets |
No | [] |
List of entity IDs or {entity_id: data} maps for per-target execution |
verify |
No | Verification condition (see below) | |
timeout |
No | 30 |
Timeout in seconds for verification |
retry |
No | 0 |
Number of retry attempts on failure |
parallel_mode |
No | per_target |
How targets execute: per_target (parallel) or sequential |
Each step can verify its result before being marked as successful:
verify:
type: state # "state" or "attribute"
entity_id: media_player.my_tv
value: "on" # Expected state valueverify:
type: attribute
entity_id: media_player.my_tv
attribute: source
value: HDMI1 # Expected attribute valueIf verification is omitted or type: none, the step succeeds immediately after the service call.
Steps can declare dependencies on other steps using depends_on. Independent steps run in parallel; dependent steps wait for their dependencies to succeed.
steps:
- id: power_on
label: Power
service: ...
- id: select_input
label: Input
depends_on:
- power_on # Waits for power_on to succeed
service: ...
- id: set_audio
label: Audio
service: ... # Runs in parallel with power_onExecute all steps of a mode.
| Field | Required | Description |
|---|---|---|
mode |
Yes | Mode ID (the top-level key in your config) |
Run a single step (and its dependencies) within a mode.
| Field | Required | Description |
|---|---|---|
mode |
Yes | Mode ID |
step |
Yes | Step ID to execute |
target_entity_id |
No | Specific target entity (for multi-target steps) |
Reset a mode sensor back to idle state.
| Field | Required | Description |
|---|---|---|
mode |
Yes | Mode ID |
Each mode creates a sensor entity: sensor.room_mode_<mode_id>
| State | Description |
|---|---|
idle |
Not running |
running |
Currently executing steps |
success |
All steps completed successfully |
partial |
Some steps succeeded, some failed |
failed |
Execution failed |
The sensor exposes detailed runtime state including per-step status, timing, attempt counts, and error messages.
The room-mode-card is a custom Lovelace card that provides one-tap mode activation with expandable step-level detail.
Add the card as a Lovelace resource:
- Go to Settings > Dashboards > Resources
- Add
/local/room-mode-card.jsas a JavaScript Module
Or add to your Lovelace YAML:
resources:
- url: /local/room-mode-card.js
type: moduletype: custom:room-mode-card
entity: sensor.room_mode_living_room_present
title: Present # Optional, overrides mode name
icon: mdi:presentation-play # Optional, overrides mode iconThe card shows:
- Mode status with color coding (idle/ready, running, success, failed)
- Step icons with individual status indicators
- Expandable drawer with per-step detail and retry buttons
- One-tap to run the entire mode
Add a documentation property with markdown content to show a help button (?) that opens a scrollable modal:
type: custom:room-mode-card
entity: sensor.room_mode_living_room_present
title: Present
documentation: |
## Connect your laptop
Plug the **HDMI cable** into your laptop.

- **Entire Screen** — mirrors your screen
- **Extended Display** — second screenSupported markdown:
#,##,###headings**bold**and*italic*images — optional=SIZEsuffix (e.g.=50%,=300px) setsmax-width[text](url)links-unordered lists{columns}/{/columns}— text on the left, images on the right
Add custom action buttons to a card with the buttons property. Buttons appear next to the hero icon.
type: custom:room-mode-card
entity: sensor.room_mode_living_room_live_tv
title: Live TV
buttons:
- icon: mdi:chevron-up
label: "Channel +"
service: media_player.media_next_track
service_data:
entity_id: media_player.living_room_tv
- icon: mdi:chevron-down
label: "Channel -"
service: media_player.media_previous_track
service_data:
entity_id: media_player.living_room_tvThe tv-control-card provides a TV off button and vertical volume sliders, designed to sit alongside the room mode cards.
Add the card as a Lovelace resource:
resources:
- url: /local/tv-control-card.js
type: moduletype: custom:tv-control-card
tv_off_entity: automation.turn_off_living_room_tv # Optional
tv_off_service: automation.trigger # Default
tv_off_label: TV Off # Default
section_columns: "5fr 1fr" # Optional, CSS grid columns
sliders:
- entity: media_player.living_room_tv
label: TV Vol
- entity: media_player.living_room_speakers
label: Speakers| Option | Required | Default | Description |
|---|---|---|---|
tv_off_entity |
No | null |
Entity for the TV off button. Omit to hide the button. |
tv_off_service |
No | automation.trigger |
Service to call for TV off |
tv_off_service_data |
No | {skip_condition: true} |
Additional service data |
tv_off_label |
No | TV Off |
Button label |
section_columns |
No | 5fr 1fr |
CSS grid template for the sections layout |
sliders |
Yes | Array of volume sliders (at least one) |
Each slider entry:
| Option | Required | Description |
|---|---|---|
entity |
Yes | Media player entity with volume_level attribute |
label |
No | Slider label (default: "Volume") |
The card automatically:
- Matches its slider height to the sibling section (room mode cards grid)
- Injects CSS to create an asymmetric two-column layout in HA sections views
- Adapts slider width based on the number of sliders (1, 2, or 3)
MIT