Skip to content

Stress-Free School Mornings with Home Assistant

· 12 min

My wife and I have joked many times that essentially we are just soundboards, saying the same things over and over again to our kids.

“Brush your teeth! Find your shoes! Did you pack your bag?”.

What if you could outsource your nagging to your smart home?

That’s what I set out to do. By creating a Home Assistant dashboard that turns the morning routine into a game, my kids now race to get their tasks done.

Here is what we are going to end up with:

Morning Checklist on a Nest Hub

Morning Checklist on a Nest Hub

In this guide, I’ll walk you through all the building blocks — from helpers and sensors to automations and dashboards — so you can piece it together step by step. By the end, you’ll be able to automate your nagging 🤘.

NOTE

This guide assumes you are comfortable with editing YAML and adding custom integrations via HACS.

The Hardware#

I am using a Google Nest Hub as the display, but you can use any touch screen device that supports Home Assistant dashboards.

If you are using a Nest Hub:

Once you install the integration, you can cast using the cast.show_lovelace_view action.

- action: cast.show_lovelace_view
metadata: {}
data:
# Your Nest Hub's entity ID
entity_id: media_player.nesthuba962
# eg. If your dashboard link is https://yourhomeassistant/nest-hub/0
# The path to your dashboard
dashboard_path: nest-hub
# The zero indexed view to show
view_path: "0"

Backend Building Blocks#

Creating the Checklist Items#

For each child, we need a list of items that need to be checked off (eg. brushing teeth, making bed, etc).

We will create input_boolean entities for each item.

  1. Go to the Helpers page

  2. Click Create Helper

  3. Choose Toggle

  4. Give it a name and choose an icon. Make them easier to search with a prefix, something like School Ready - Bart Bag Packed.

  5. Click on it and choose the Settings () icon.

  6. Give it a label. If you have multiple children, make sure to have a label dedicated to each child. The label will be crucial for the automation and dashboard later.

Add a Label to the Toggle Helper

Add a Label to the Toggle Helper
  1. Repeat the process for each item on the checklist for each child.

Making Checklist Items Dynamic#

I had a use case where my son needed to pack his gym bag only 2 days a week.

As we are using labels to determine what is a checklist item, we can easily make them dynamic by adding or removing the label from the checklist entity.

Home Assistant itself does not have a way to add or remove labels from entities, but we can use the 👻 Spook add-on to do this.

Spook adds Label Management Actions that we can use for this:

Follow the instructions in the Spook Documentation to get it installed.

We will use these actions in an automation later.

Tracking School Leaving Time#

We will add 2 helpers:

  1. Go to the Helpers page
  2. Click Add Helper
  3. Choose Date and/or Time
  4. Choose the Time option
  5. Give a name and an icon and click Submit
  6. Click on the helper and set the time you want to leave for school
  7. Note down the name of the helper (mine is input_datetime.school_leaving_time)

Now for the countdown timer:

  1. Add another helper and choose Timer
  2. Give a name and an icon and click Submit
  3. Click on the helper and set the duration of the timer to the time you want to leave for school
  4. Note down the name of the helper (mine is timer.school_departure_timer)

The Leaving Time and Departure Timer Helpers

The Leaving Time and Departure Timer Helpers

Binary Sensors For Ready States#

Once we have all our toggle helpers created, we can build a dynamic binary sensor for each child. This will track whether each child has completed their checklist.

We will do this using YAML in either our configuration.yaml or templates.yaml file (depending on your setup).

The function below:

template.yaml
- binary_sensor:
- name: "Bart is Ready For School"
state: >
{{ now() | expand(label_entities('bart-school-ready')) | selectattr('state', 'eq', 'on') | list | count == expand(label_entities('bart-school-ready')) | list | count }}
- name: "Lisa is Ready For School"
state: >
{{ now() |expand(label_entities('lisa-school-ready')) | selectattr('state', 'eq', 'on') | list | count == expand(label_entities('lisa-school-ready')) | list | count }}
# Roll up each child's checklist completion into a single binary sensor
- name: "Both Kids are Ready For School"
state: >
{{ is_state('binary_sensor.bart_is_ready_for_school', 'on') and is_state('binary_sensor.lisa_is_ready_for_school', 'on') }}

Reload your YAML configuration to see the binary sensors in the States page.

The Roll Up Sensors in Developer Tools

The Roll Up Sensors in Developer Tools

Is It a School Day?#

To determine if its a school day or not, we can use the Workday integration.

  1. Go to the Integrations page
  2. Click Add Integration
  3. Add the Workday integration and choose the country
  4. Add any school holidays to the Add Holidays section

Add the Workday Integration

Add the Workday Integration
  1. Click Submit
  2. Note down the name of the binary sensor that is created (mine is binary_sensor.netherlands_school_day)

A Daily Fact#

To keep the dashboard engaging, we can use a sensor that will display a daily fact.

We will use the Useless Facts API, querying it daily using a sensor.

Add it to your configuration.yaml or sensor.yaml file (depending on your setup).

sensor.yaml
- platform: rest
name: "Random Fact"
scan_interval: 86400 # Daily
resource: https://uselessfacts.jsph.pl/api/v2/facts/random?language=en
value_template: "{{ value_json.text }}"

Reload your YAML configuration to see the sensor in the States page.

The Random Fact Sensor in Developer Tools

The Random Fact Sensor in Developer Tools
Tip

Alternative APIs are the Cat Facts API or the Dad Joke API.

Dashboard Building Blocks#

Additional Plugins#

We are going to need some custom lovelace plugins to add some style to our buttons, and handle loading them dynamically.

Click the name of the plugin to install it via HACS.

Dynamic Buttons#

To autogenerate buttons for each child, we can use the custom:auto-entities card, in combination with the custom:button-card custom card.

Custom-Buttons.yaml
- type: custom:auto-entities
card:
type: horizontal-stack
card_param: cards
filter:
include:
- options:
type: custom:button-card
show_name: false
show_icon: true
color_type: icon
state:
- value: 'on'
# Have a custom color for the on state
color: '#00bcd4'
- value: 'off'
color: '#9E9E9E'
# Use the label of the helper to filter the entities per child
label: bart_school_ready
grid_options:
columns: full

Test it out by adding a label to one of the task entities and refreshing the dashboard.

Dynamic Markdown Titles#

We can use Markdown cards with template syntax to create dynamic titles.

Child Is Ready#

We can use the is_state function on our binary_sensor entities to check if the child is ready for school (they’ve completed their checklist).

Child Is Ready

Child Is Ready
Child-Is-Ready.yaml
{% if is_state('binary_sensor.bart_is_ready_for_school', 'on') %}
## 👦 Bart (✅ Ready!)
{% else %}
## 👦 Bart (❌ Not Ready Yet!)
{% endif %}

We can use the is_state template to check if it’s a school day or not, and if the departure timer is active or completed.

Header-Title.yaml
{% if is_state('binary_sensor.netherlands_school_day', 'off') %}
# 🌴 It's Not a School Day
{% else %}
{% if is_state('timer.school_departure_timer', 'active') %}
# ⏰ Get Ready For School
{% else %}
# 🔥 Time To Go!
{% endif %}
{% endif %}

Countdown Timer#

We can use the custom:timer-bar-card card to display the countdown timer, which shows a progress bar based on the remaining time before we need to leave for school.

Countdown-Timer.yaml
- type: custom:timer-bar-card
entities:
- entity: timer.school_departure_timer
name: Time Left
modifications:
- remaining: '00:30:00'
bar_foreground: green
active_icon: mdi:run-fast
- remaining: '00:20:00'
bar_foreground: orange
active_icon: mdi:run-fast
- remaining: '00:10:00'
bar_foreground: red
active_icon: mdi:fire-alert
bar_height: 50px

Countdown Timer

Countdown Timer

Daily Fact#

We will display the daily fact when both children are ready for school using a visibility condition.

Daily-Fact.yaml
- type: markdown
content: |-
# 💡 Fact of the Day
## {{ states('sensor.random_fact') }}
visibility:
- condition: state
entity: binary_sensor.both_kids_are_ready_for_school
state: 'on'

The Automation#

The automation has 2 sections, depending on the trigger. I will explain each section in plain English, then share the YAML.

Start Morning Automation (school_day)#

This part is the main “get ready” part of the automation.

  1. It resets all the checklist items that were marked as done the previous day
  2. On Tuesdays and Fridays, it adds a “gym bag” item to Bart’s checklist. On other school days, it removes it. This makes the checklist dynamic
  3. It turns off the Nest Hub to clear the screen and then starts a countdown timer until the scheduled departure time
  4. Finally, it displays the school readiness dashboard on the Nest Hub, so the kids can see their tasks and the countdown

Departure Automation (timer_finished)#

This part is triggered when the countdown timer from the first automation finishes.

  1. It sends a voice notification to Bart’s Nest device, saying, “It’s Time To Go To School! Get your shoes on!”
  2. Pauses for 5 minutes
  3. It turns off the screen

Overall Automation#

The Full Automation for Visual Learners

The Full Automation for Visual Learners
Automation YAML
Automation.yaml
alias: School Departure - Notify and Prepare Dashboard
triggers:
# The time to show the dashboard
- trigger: time
at: "07:15:00"
weekday:
- mon
- tue
- wed
- thu
- fri
# Set an id for the time of day trigger
id: school_day
alias: 7:15am on potential school day (school_day)
# When the timer on the dashboard has finished counting down
- event_type: timer.finished
event_data:
entity_id: timer.school_departure_timer
trigger: event
# Set an id for the timer finished trigger
id: timer_finished
alias: When get ready for school timer done (timer_finished)
conditions:
# Only run the automation on school days
- condition: state
entity_id: binary_sensor.netherlands_school_day
state: "on"
actions:
# If triggered by "school_day", start the automation
- alias: If triggered by "school_day"
if:
- condition: trigger
id:
- school_day
# Turn off all items in the checklist
then:
- action: input_boolean.turn_off
metadata: {}
data: {}
target:
label_id:
- lisa_school_ready
- bart_school_ready
# If it is a Tuesday or Friday, add the gym bag label to Bart's checklist
- if:
- condition: time
weekday:
- tue
- fri
then:
- action: homeassistant.add_label_to_entity
metadata: {}
data:
label_id:
- bart_school_ready
entity_id:
- input_boolean.school_ready_bart_gym_back
else:
- action: homeassistant.remove_label_from_entity
metadata: {}
data:
entity_id:
- input_boolean.school_ready_bart_gym_back
label_id:
- bart_school_ready
alias: Add or remove gym bag label
# Turn off the Nest Hub. This clears the screen if anything was already showing.
- target:
entity_id: media_player.nesthuba962
action: media_player.turn_off
data: {}
enabled: true
# Start the countdown timer using a dynamic duration, based on the school leaving time helper
- action: timer.start
metadata: {}
data:
duration: >
{% set leaving_time = states('input_datetime.school_leaving_time')
%} {% set now = now() %} {% set today_leaving =
today_at(leaving_time) %} {% set time_diff = (today_leaving -
now).total_seconds() %} {% if time_diff > 0 %}
{{ time_diff | int }}
{% else %}
0
{% endif %}
target:
entity_id: timer.school_departure_timer
alias: >-
Set time remaining to leave on the timer by calculating school leaving
time
# Cast the dashboard to the Nest Hub
- action: cast.show_lovelace_view
metadata: {}
data:
entity_id: media_player.nesthuba962
dashboard_path: nest-hub
view_path: "0"
# If triggered by "timer_finished", when it's time to go to school
- alias: If triggered by "timer_finished"
if:
- condition: trigger
id:
- timer_finished
then:
# Send a voice notification to Bart's Nest
- data:
message: It's Time To Go To School! Get your shoes on!
target:
- bart
action: notify.google_assistant_sdk
# Wait 5 minutes
- delay:
hours: 0
minutes: 5
seconds: 0
milliseconds: 0
# Stop displaying the dashboard
- target:
entity_id: media_player.nesthuba962
action: media_player.turn_off
data: {}
mode: single

The Final Dashboard#

Now we can put it all together in our final dashboard.

The Final Dashboard: Unchecked

The Final Dashboard: Unchecked

The Final Dashboard: Checked

The Final Dashboard: Checked
Full Dashboard YAML
Full-Dashboard.yaml
views:
- title: School Ready
cards: []
type: sections
sections:
- type: grid
cards:
- type: markdown
content: |-
{% if is_state('binary_sensor.netherlands_school_day', 'off') %}
# 🌴 It's Not a School Day
{% else %}
{% if is_state('timer.school_departure_timer', 'active') %}
# ⏰ Get Ready For School
{% else %}
# 🔥 Time To Go!
{% endif %}
{% endif %}
grid_options:
columns: full
text_only: true
- type: horizontal-stack
cards:
- type: custom:timer-bar-card
entities:
- entity: timer.school_departure_timer
name: Time Left
modifications:
- remaining: '00:30:00'
bar_foreground: green
active_icon: mdi:run-fast
- remaining: '00:20:00'
bar_foreground: orange
active_icon: mdi:run-fast
- remaining: '00:10:00'
bar_foreground: red
active_icon: mdi:fire-alert
bar_height: 50px
- clock_size: large
show_seconds: false
type: clock
grid_options:
columns: full
- type: markdown
content: |-
# 💡 Fact of the Day
## {{ states('sensor.random_fact') }}
visibility:
- condition: state
entity: binary_sensor.both_kids_are_ready_for_school
state: 'on'
grid_options:
columns: full
- type: markdown
content: |-
{% if is_state('binary_sensor.bart_is_ready_for_school', 'on') %}
## 👦 Bart (✅ Ready!)
{% else %}
## 👦 Bart (❌ Not Ready Yet!)
{% endif %}
text_only: true
- type: custom:auto-entities
card:
type: horizontal-stack
card_param: cards
filter:
include:
- options:
type: custom:button-card
show_name: false
show_icon: true
color_type: icon
state:
- value: 'on'
color: '#00bcd4'
- value: 'off'
color: '#9E9E9E'
label: bart_school_ready
grid_options:
columns: full
- type: markdown
content: |-
{% if
is_state('binary_sensor.lisa_is_ready_for_school', 'on')
%}
## 👧 Lisa (✅ Ready!)
{% else %}
## 👧 Lisa (❌ Not Ready Yet!)
{% endif %}
text_only: true
- type: custom:auto-entities
card:
type: horizontal-stack
card_param: cards
filter:
include:
- options:
type: custom:button-card
show_name: false
show_icon: true
color_type: icon
state:
- value: 'on'
color: '#fc03d7'
- value: 'off'
color: '#9E9E9E'
label: lisa_school_ready
grid_options:
columns: 48
rows: 2
column_span: 4
max_columns: 4
badges:
- type: entity
show_name: true
show_state: true
show_icon: true
entity: binary_sensor.netherlands_school_day
name: School Day
icon: mdi:bus-school

Conclusion#

Hopefully I’ve given you the tools to get your kids out the door without all the nagging.

Enjoy the 5 minutes of extra time for enjoy your morning coffee ☕.