I am trying to create a script to send notifications to anyone currently home. I would like to leverage another of my custom scripts that unifies notification service calls. (example call to this script below)
service: script.send_notification
data:
destination:
- Me
- Wife
message: Motion Detected in Garage
title: Security Alert
tag: security_alert
url: /dashboard-mobile/security
My new script would automatically set the destination field and fill the fields in based on the script input fields. How do I create the entire “data:” field using a template? Below is what I’ve got so far but I’m getting this error: Error rendering data template: Result is not a Dictionary. How do I create a dictionary?
sequence:
- variables:
message_data: >
{% set at_home = (states.person|selectattr('state','eq','home')|map(attribute='name')|list) %}
{% set ns = namespace(data=[]) -%}
{%- set ns.data = ns.data + [{"destination": at_home}] + [{"message": message_input }] -%}
{%- set ns.data = (ns.data + [{"url": url_input }]) if url_input is defined else ns.data -%}
{%- set ns.data = (ns.data + [{"tag": tag_input }]) if tag_input is defined else ns.data -%}
{%- set ns.data = (ns.data + [{"title": title_input }]) if title_input is defined else ns.data -%}
{{ ns.data }}
- if:
- condition: state
entity_id: binary_sensor.combined_presence
state: "on"
then:
- service: script.send_notification
data: >
{{ message_data }}
Thanks!
While you can template the value for data
in a service call, you have gone a little overboard… and lost the thread. There’s no need to invoke a namespace since you aren’t using a loop. And, as indicated by the error message, you template does not output a dictionary which is what is required. What it is outputting is a list of dictionaries because you explicitly set the data type of ns.data
to a list in the set statement: {% set ns = namespace(data=[]) -%}
.
The proper configuration is a lot more basic:
sequence:
- variables:
message_data: >
{% set at_home = (states.person|selectattr('state','eq','home')|map(attribute='name')|list) %}
{{ {"destination": at_home, "message": message_input, "title": title_input, "tag": tag_input, "url": url_input} }}
- if:
- condition: state
entity_id: binary_sensor.combined_presence
state: "on"
then:
- service: script.send_notification
data: '{{ message_data }}'
Appreciate your help on this, and the clarification on namespace usage for this code noob.
The main issue I was running into (that I should have noted upfront) was that I only want the message variable to be a required field for the script. If I try to run the approach you shared, I run into “undefined” tags, urls, and titles that cause some errors with my send_notification script – which obviously needs to be fixed using the same approach.
So I’ve done more experimenting and returned back at the namespace (hopefully using it more appropriately this time
).
The following is my updated, and hopefully cleanest, approach that seems to work as expected.
- variables:
message_data: >
{%- set athome = (states.person|selectattr('state','eq','home')|map(attribute='name')|list) %}
{%- set ns = namespace(data={}) %}
{%- set ns.data = {"destination": athome, "message": message_input } -%}
{%- set opt_data = {'tag': tag_input, 'title': title_input, 'url': link_input } %}
{%- for item in opt_data %}
{%- if opt_data[item] is defined %}
{%- set dict2 = { item : opt_data[item] } -%}
{%- set ns.data = dict(ns.data, **dict2) -%}
{%- endif -%}
{%- endfor -%}
{{ ns.data }}
- if:
- condition: state
entity_id: binary_sensor.combined_presence
state: "on"
then:
- service: script.send_notification
metadata: {}
data: "{{ message_data }}"
Obviously, I’ve spent way more time on writing this marginally helpful script than it will ever be worth (compared to the alternative of a bunch of basic conditional statements or choose blocks) but I am finding this to be a fun challenge and hopefully good practice for future advanced automations.