Yesterday I spent plenty of time reading some very interesting articles by Thomas Loven and applying tricks described.
I was mainly interested in a possibility of using constants across various configuration files.
One of the examples - I want to have an input_select
with some string constants as options and in a template sensor I need to know which one is selected and act accordingly (or I want to have a binary_sensor
that is on
when a particular option is selected).
The easiest way is to use strings where required (hardcode) but the code quickly becomes difficult to maintain/change.
One of the options I came across long time ago is to define constants in secret.yaml
and then write !secret my_const
where I need it. The problem is it doesn’t work in templates. It’s possible to overcome this restriction by creating a template sensor with
value_template: !secret my_const
The issue with this approach is it requires extra measures if you want to use that template sensor’s state (that very my_const
) in another template sensor as during HA start your const
template sensor might not be created yet when you try accessing its state
. It’s manageable but the whole thing gets too complicated for no reason really…
Anyway, I read some docs and examples, went through this forum and realised it might be useful to summarise the experience with anchors as currently it’s a bit spreaded out/not very obvious. So (briefly as it’s already tl;dr) on YAML anchors (just anchors):
- They cannot be used in templates.
- They must be declared and used in *the same
.yaml
file. - They can represent any valid YAML structure.
What does it give us?
(1) That’s sad, but sometimes it’s still useful, I’ll show an example below.
(2) No !include
will help. That mean that uless you have everything in your configuration.yaml
(unrealistic), the most benefits it gives you when used in packages. Anywhere else it’s almost useless, you can do something simple like this but no more:
- platform: template
sensors:
## groung floor ##
pir_ground_floor_hall_last_triggered:
value_template: "{{ states('input_datetime.pir_ground_floor_hall') }}"
<<: &icon
icon_template: mdi:calendar-clock
pir_ground_floor_reception_last_triggered:
value_template: "{{ states('input_datetime.pir_ground_floor_reception') }}"
<<: *icon
just because it’s difficult to find a place where you can declare it without getting errors from yaml loader.
Packages are different exactly because everything is in one file (and that’s why anchors work in Lovelace configs if you don’t split it up). You just use a dummy place like
homeassistant:
customize:
package.node_anchors:
const_preset_normal: &const_preset_normal 'normal'
at the top of your package file and it works. However, it’s still limiting you by boundaries of 1 file so no way to have global_anchors.yaml
and include it where you need it.
But with packages you can make it a little bit less dependent on secrets.yaml
- instead of the approach with const template sensors I use this
homeassistant:
customize:
package.node_anchors:
const_preset_normal: &const_preset_normal 'normal'
template_normal: &template_normal "{{ is_state('input_select.central_heating_preset', 'normal') }}"
const_preset_night: &const_preset_night 'night'
template_night: &template_night "{{ is_state('input_select.central_heating_preset', 'night') }}"
input_select:
central_heating_preset:
name: preset
options:
- *const_preset_normal
- *const_preset_night
binary_sensor:
- platform: template
sensors:
central_heating_preset_normal:
value_template: *template_normal
central_heating_preset_night:
value_template: *template_night
I still have to hard-code string constants normal
and night
but they’re in one place so it’s easy to change them/keep synchronised and I can use them in as many places as I need.
The reason we don’t have access to anchors declared in another file is the way HA processes yaml files (as all !secret
, !include
etc are not part of YAML, it’s HA). I’m not convinced that it’s impossible to implement such a feature. And maybe it’s relatively easy to write a post-processor that loads configuration.yaml
, creates a list of files to process, builds a list of anchor definitions and then performs necessary substitutions.
(3) You can use anchors to substitute a value or a piece of a dictionary (I use both approaches in my packages example).
tl;dr #2
I just summarised my and other’s experience with YAML anchors here and added some comments where I thought it wasn’t clear enough.
It’s easy to find some useful topics here (like this or this).
And I’m happy to discuss the matter further or learn something new I have missed in this write-up.