This is part 3 of my homeassistant migration. I'll cover some insights on the automations (especially blueprints) here.
In the past years, I've come across a few things I like to be automated in my home. It started with a few sensors for temperature monitoring, added Tasmota devices, Shellys and ended with open/close sensors for the doors.
So how to cobble all of this together?
Common usecases are e.g. notifications on low temperatures, trigger a switch or light if movement was detected.
My largest fears were how automations will work in comparison to openHAB.
The main difference between the two system lies in HA using YAML configurations with Jinja2 templating support that evaluate to code vs. actual code that's being written in a Java-like DSL in OH.
In opposition to OH, HA has things like blueprints and scripts to add to your automations. Everything goes into automations.yaml as a big pile of config.
You can choose to just click together what you need as an automation via the provided UI and fit in pieces of YAML config as you go, if you need non-standart stuff or just want to use evaluations via templates.
I strongly suggest you read up on automation basics in the documentation.
In addition to the basics: As soon as you have recurring tasks, consider to use a blueprint. Before you start to write one yourself, check the forums for available solutions you may reuse or adapt to your usecase.
I went through everything I did in OH3 and made a list of all automations from my previous setup.
These are the current usescases I have:
I've collected all my current solutions in a github repository, so make sure to collect what you want to reuse or change there, code samples below might be outdated.
I prefer the lights in my staircase to turn on and off automatically, especially when it's after dawn or before sunrise and on motion.
The below code is not perfectly elegant, since you can't configure the offset for sunrise/sundawn.
What's happeing?
The time for the light being on depends on three factors: How long does the sensor stay in the activated state and after it does not detect any more movement, the timer.
# motion_activated_device.yaml
blueprint:
name: Motion activated device at night
description: Turn on a device when motion is detected, turn off after delay. Works only from dusk till dawn + offset
domain: automation
input:
motion_entity:
name: Motion Sensor
selector:
entity:
domain: binary_sensor
device_class: motion
light_target:
name: Light
default: {}
selector:
target:
entity:
domain: light
switch_target:
name: Switch
default: {}
selector:
target:
entity:
domain: switch
light_brightness:
name: Night brightness
description: The brightness to use when turning the light on
default: 20
selector:
number:
min: 10
max: 100
step: 10
mode: slider
no_motion_wait:
name: Wait time
description: Time to leave the light on after last motion is detected.
default: 90
selector:
number:
min: 0
max: 300
step: 5
unit_of_measurement: seconds
# If motion is detected within the delay,
# we restart the script.
# this resolves the timer reset issue
mode: restart
max_exceeded: silent
variables:
motion_entity: !input 'motion_entity'
light_target: !input 'light_target'
switch_target: !input 'switch_target'
light_brightness: !input 'light_brightness'
no_motion_wait: !input 'no_motion_wait'
trigger:
platform: state
entity_id: !input 'motion_entity'
from: 'off'
to: 'on'
action:
- condition: or
conditions:
- condition: sun
after: sunset
after_offset: '-1:00:00'
- condition: sun
before: sunrise
before_offset: '+1:00:00'
- choose:
- conditions:
condition: template
value_template: '{{ light_target | length > 0 }}'
sequence:
- alias: 'Turn on light'
service: light.turn_on
data:
brightness: '{{ light_brightness }}'
target: !input 'light_target'
- conditions:
condition: template
value_template: '{{ switch_target | length > 0 }}'
sequence:
- alias: 'Turn on Switch'
service: switch.turn_on
target: !input 'switch_target'
- alias: 'Wait until there is no motion from device'
wait_for_trigger:
platform: state
entity_id: !input 'motion_entity'
from: 'on'
to: 'off'
- alias: 'Wait the number of seconds that has been set'
delay: !input 'no_motion_wait'
- choose:
- conditions:
condition: template
value_template: '{{ light_target | length > 0 }}'
sequence:
- alias: 'Turn off Light'
service: light.turn_off
target: !input 'light_target'
- conditions:
condition: template
value_template: '{{ switch_target | length > 0 }}'
sequence:
- alias: 'Turn off Switch'
service: switch.turn_off
target: !input 'switch_target'
I'm using a few devices for heating e.g. water (boiler).
# timed_device.yaml
blueprint:
name: Switch Timer
description: Start a Timer on turning on a device.
domain: automation
input:
switch_trigger:
name: Trigger device
description: Device that will trigger the timer
selector:
entity:
domain: switch
wait_for_it:
name: Wait time
description: Time to wait until device is turned off.
default: 10
selector:
number:
min: 1
max: 60
unit_of_measurement: minutes
variables:
switch_trigger: !input 'switch_trigger'
wait_for_it: !input 'wait_for_it'
mode: restart
max_exceeded: silent
trigger:
platform: state
entity_id: !input 'switch_trigger'
from: 'off'
to: 'on'
action:
- alias: 'Wait the number of minutes that has been set'
delay: "{{ wait_for_it | multiply(60) | int }}"
- alias: 'Turn off switch'
service: switch.turn_off
entity_id: !input 'switch_trigger'
I want to know when my doors are opened... And also if/when they are closed.
The difficulty here, is to provide a name and the state for a message in a notifier service. With this blueprint you only have to c&p the template snippet into the message field.
I would have preferred a pre-filled variable and evaluated/translated state. But this only works for values that come with the inputs themselfs. The trigger is evaluated on state change and is therefore dynamic :-(
# open_close_notifier.yaml
blueprint:
name: Open/Close notifier
description: Notify if a door was opened or closed
domain: automation
input:
trigger_device:
name: Door
description: The triggering binary sensor
selector:
entity:
domain: binary_sensor
device_class: opening
actions:
name: Actions
description: >
Run notifications or similar actions.
Use something like
{{ trigger.to_state.attributes.friendly_name }} was {% if trigger.to_state.state == "off" %}closed{% elif trigger.to_state.state == "on" %}opened{% endif %}
selector:
action: {}
mode: single
variables:
trigger_device: !input 'trigger_device'
trigger:
platform: state
entity_id: !input 'trigger_device'
action:
- choose: []
default: !input 'actions'
I stole this nifty piece of code from this template and re-arranged it to fit my usecase.
There are 9 temp sensors in my home and I want to monitor all of them, exept e.g. the outdoor ones, because they are allowed to have temperatures below 10°C.
This blueprint checks the states of the sensors every 15 minutes, whis is the trigger, naturally. It's running through all sensors with temperature and evaluates vs. the temperature threshold.
If the threshold is met, it sends a notification.
And you can set which sensors to ignore.
# temperature_alert.yaml
blueprint:
name: Low temperature alert for all temperature sensors
description: Regularly test all sensors with 'temperature' device-class for crossing
a certain temperature threshold and if so execute an action.
domain: automation
input:
threshold:
name: Temperature threshold
description: Temperature
default: 10
selector:
number:
min: 0.0
max: 30.0
unit_of_measurement: '°C'
mode: slider
step: 5.0
exclude:
name: Excluded Sensors
description: Battery sensors (e.g. smartphone) to exclude from detection. Only entities are supported, devices must be expanded!
default: {entity_id: []}
selector:
target:
entity:
device_class: temperature
actions:
name: Actions
description: Notifications or similar to be run. {{ sensors }} is replaced with
the names of sensors being below temperature threshold.
selector:
action: {}
variables:
threshold: !input 'threshold'
exclude: !input 'exclude'
sensors: >-
{% set result = namespace(sensors=[]) %}
{% for state in states.sensor | selectattr('attributes.device_class', '==', 'temperature') %}
{% if 0 <= state.state | int(-1) < threshold | int and not state.entity_id in exclude.entity_id %}
{% set result.sensors = result.sensors + [state.name ~ ' (' ~ state.state ~ ' °C)'] %}
{% endif %}
{% endfor %}
{% for state in states.binary_sensor | selectattr('attributes.device_class', '==', 'temperature') | selectattr('state', '==', 'on') %}
{% if not state.entity_id in exclude.entity_id %}
{% set result.sensors = result.sensors + [state.name] %}
{% endif %}
{% endfor %}
{{ result.sensors|join(', ') }}
trigger:
- platform: time_pattern
# You can also match on interval. This will match every 5 minutes
minutes: "/15"
condition:
- condition: template
value_template: '{{ sensors != '''' }}'
action:
- choose: []
default: !input 'actions'
mode: single
Will continue in part 4.