I’m writing what I thought was a simple script to put together a voice announcement for low battery warnings, but it seems like if I reference the item in this way it doesn’t work:
low_battery_announcement:
alias: Low Battery Announcement
icon: "mdi:account-voice"
sequence:
- service: shell_command.speak
data:
text: >
{# INTRO #}
{%- set message = "" -%}
{%- for zwave in states.zwave if zwave.attributes.battery_level is defined and zwave.attributes.battery_level | int < 75 -%}
{%- set message = message + zwave.attributes.friendly_name + ", " -%}
{%- endfor -%}
{{ message }}
Done.
It has something to do with using the zwave.attributes.friendly_name when trying to concat the “message” variable. When used as a literal it will say the phrase (i.e., {{ zwave.attributes.friendly_name }}) but as it is now it never concats the string and just says “Done.” (Done was added just as a test to make sure it got to the bottom).
I believe I have to call it with a function, i.e., states(‘entity_name’) type of call, but I’m not sure how I can wrap that value so that it concats it to the string.
The idea is that if there are no low batteries then the “message” will be empty and nothing is said via an if statement, but until I can get message to concat I cannot test for that yet.
try putting the “{{ message }}” inside the for loop:
{%- for zwave in states.zwave if zwave.attributes.battery_level is defined and zwave.attributes.battery_level | int < 75 -%}
{%- set message = message ~ zwave.attributes.friendly_name ~ ", " -%}
{{message}}
{%- endfor -%}
I tried that before and it speaks it as expected, but the reason I’m stuffing it into a variable is so I can test that variable after the loop to determine if anything should be said or not. If it’s not possible to concat the variable then I can just run the loop twice, one to flag a true/false and one to say the message if the condition is true.
After playing around, it looks like the variable is local to the loop rather than using the defined variable above it, so it is setting a new “message” on each iteration instead of concatenating the variable I need to be concatenated. This is why this hasn’t worked.
I had hoped that setting message to be global ( {%- global message -%} ) would do the trick but it doesn’t work that way in Jinja apparently.
If anyone stumbles upon this and is curious how the entire thing is put together:
low_battery_announcement:
alias: Low Battery Announcement
icon: "mdi:account-voice"
sequence:
- service: shell_command.speak
data:
text: >
{# Check all Z-Wave batteries plus non Z-Wave devices for battery warnings #}
{% set ns = namespace(message="") %}
{%- for zwave in states.zwave if zwave.attributes.battery_level is defined and zwave.attributes.battery_level | int < 30 -%}
{% set ns.message = ns.message + zwave.attributes.friendly_name + ", " %}
{%- endfor -%}
{% if is_state('binary_sensor.sitting_area_motion_sensor_battery', 'on') %}
{% set ns.message = ns.message + "Sitting Area Motion Sensor, " %}
{% endif %}
{% if is_state('binary_sensor.refrigerator_low_battery', 'on') %}
{% set ns.message = ns.message + "Refrigerator Temperature Sensor, " %}
{% endif %}
{% if is_state('binary_sensor.deep_freeze_low_battery', 'on') %}
{% set ns.message = ns.message + "Deep Freezer Temperature Sensor, " %}
{% endif %}
{% if ns.message == "" %}
{% else %}
The following devices have low batteries and will need to be replaced soon:
{{ ns.message }}
please review the battery dashboard in Home Assistant to view these devices.
{% endif %}
I’m sure there are some improvements to be made (I left a blank message condition in place in case I decide to throw in “All batteries are fine” or something), but this works pretty well for what I wanted.