Okay, this is absolutely beautiful. I tried playing around with it to see if I could figure it out on my own with no luck. So, how would one extract the friendly name for the sensor that falls below the threshold? Also, how often would this poll checking for battery levels?
Sorry, I completely misread your first post, I thought you were having problems getting it working.
this is great thank you…
I updated my post. For friendly names, just use item.attributes.friendly_name
instead of item.name
.
I honestly don’t know how often it’ll run, probably every single event loop (i.e. a lot). I don’t know how to reduce that without either specifying every entity to track in the template sensor or duplicating the template in both the condition and action. Maybe we can get the template sensor updated to allow a config option that specifies how often it should update.
Here’s a bit of a hack to configure how often it updates:
First, you need to create some entity that will change states to trigger the update. I used an input_boolean:
input_boolean:
update_low_battery:
Then set the template sensor to only update when that entity changes states:
sensor:
- platform: template
sensors:
low_battery:
....(see previous comment)...
entity_id:
- input_boolean.update_low_battery
Finally, add an automation to toggle the state of the entity whenever you want the template sensor to update:
- alias: Update Low Battery
trigger:
- platform: time
minutes: '/30'
action:
- alias: Update Low Battery
service: input_boolean.toggle
data:
entity_id: input_boolean.update_low_battery
In this example, input_boolean.update_low_battery
will toggle states every 30 minutes, which then triggers sensor.low_battery
to update. You could also set it up to update just before your alert automation runs as well if you wanted. That way you only update the sensor right before the automation runs to check for low battery.
@tboyce1, thanks so much! That’s definitely a lot cleaner and I like having that persistent notification. I made a few (mostly cosmetic) tweaks to what you sent. The trigger on your “Update Low Battery” automation needs a seconds: 00
attribute to keep it from running every second when the minutes match. I changed the condition on the automation to prevent empty alerts when there are no batteries. Finally, I added the current battery level to the notification.
I’ve got a few more ideas that can make this better, but I wanted to share the latest code that’s working for me.
input_boolean:
battery_status_update:
name: Battery Status Update
sensor:
- platform: template
sensors:
battery_status:
friendly_name: "Battery Status"
entity_id:
- input_boolean.battery_status_update
value_template: >
{%- set threshold = 40 -%}
{%- set domains = ['light', 'switch', 'sensor', 'zwave', 'lock'] -%}
{%- for domain in domains -%}
{%- for item in states[domain] if ((item.attributes.battery_level is defined and item.attributes['battery_level'] | int < threshold) or ("battery" in item.name | lower and ((item.state | int < threshold and item.state|int != 0) or item.state | lower == "low" or item.state | lower == "unknown"))) -%}
{%- if (item.attributes.battery_level is defined and item.attributes['battery_level'] | int < threshold) -%}
{{ item.name }} ({{ item.attributes['battery_level'] }}){%- if not loop.last %}, {% endif -%}{% endif -%}
{%- if "battery" in item.name | lower and ((item.state | int < threshold and item.state|int != 0) or item.state | lower == "low" or item.state | lower == "unknown") -%}
{{ item.name }} ({{ item.state }}){%- if not loop.last %}, {% endif -%} {% endif -%}
{%- endfor -%}
{%- endfor -%}
automation:
- alias: Battery Status Update
trigger:
- platform: time
minutes: '/5'
seconds: 00
action:
- alias: Battery Status Update
service: input_boolean.toggle
data:
entity_id: input_boolean.battery_status_update
- alias: 'Battery Alert'
trigger:
- platform: time
at: '10:00:00'
- platform: time
at: '18:00:00'
condition:
condition: template
value_template: "{% if states('sensor.battery_status') %}{{ true }}{% else %}{{ false }}{% endif %}"
action:
- service: persistent_notification.create
data_template:
title: Low Battery levels
message: "{{ states('sensor.battery_status') }}"
notification_id: low-battery-alert
- service: notify.slack_notify
data_template:
message: >-
These devices have low battery levels: {{ states('sensor.battery_status') }}
This is a great idea!
I took the last change from @NotoriousBDG and converted it into a package that can pretty much just be dropped in and will work. Just update the notification to your preference.
Awesome @sjabby! You beat me to it. That’s what I was planning to attempt next . I’ve never created a package before, so this saved me a lot of time.
Cleaned up even more with help from @skalavala !
Removed the need for input boolean and separate sensor. Put the template code within the automation itself.
################################################################
## Packages / Battery levels
################################################################
################################################
## Customize
################################################
homeassistant:
customize:
################################################
## Node Anchors
################################################
package.node_anchors:
customize: &customize
package: 'battery_alert'
expose: &expose
<<: *customize
haaska_hidden: false
homebridge_hidden: false
################################################
## Group
################################################
group.battery_alert:
<<: *customize
friendly_name: "Battery Alert"
icon: mdi:steam
################################################
## Automation
################################################
automation.battery_alert:
<<: *customize
friendly_name: "Battery Alert"
################################################
## Group
################################################
group:
battery_alert:
control: hidden
entities:
- automation.battery_alert
################################################
## Automation
################################################
automation:
- alias: battery_alert
trigger:
- platform: time
at: '10:00:00'
- platform: time
at: '18:00:00'
condition:
- condition: template
value_template: >
{% macro battery_level() %}
{%- set threshold = 40 -%}
{% set domains = ['light', 'switch', 'sensor', 'zwave', 'lock'] %}
{% for domain in domains -%}
{% for item in states[domain] if ((item.attributes.battery_level is defined and item.attributes['battery_level'] | int < threshold) or ("battery" in item.name | lower and ((item.state | int < threshold and item.state|int != 0) or item.state | lower == "low" or item.state | lower == "unknown"))) -%}
{% if (item.attributes.battery_level is defined and item.attributes['battery_level'] | int < threshold) -%}
{{ item.name }} ({{ item.attributes['battery_level'] }}){%- if not loop.last %}, {% endif -%}{% endif -%}
{% if "battery" in item.name | lower and ((item.state | int < threshold and item.state|int != 0) or item.state | lower == "low" or item.state | lower == "unknown") -%}
{{ item.name }} ({{ item.state }}){% if not loop.last %}, {%- endif %} {% endif -%}
{% endfor %}
{%- endfor %}
{% endmacro %}
{{ battery_level() |trim != "" }}
action:
- service: persistent_notification.create
data_template:
title: Low Battery levels
notification_id: low-battery-alert
message: >
{% macro battery_level() %}
{%- set threshold = 40 -%}
{% set domains = ['light', 'switch', 'sensor', 'zwave', 'lock'] %}
{% for domain in domains -%}
{% for item in states[domain] if ((item.attributes.battery_level is defined and item.attributes['battery_level'] | int < threshold) or ("battery" in item.name | lower and ((item.state | int < threshold and item.state|int != 0) or item.state | lower == "low" or item.state | lower == "unknown"))) -%}
{% if (item.attributes.battery_level is defined and item.attributes['battery_level'] | int < threshold) -%}
{{ item.name }} ({{ item.attributes['battery_level'] }}){%- if not loop.last %}, {% endif -%}{% endif -%}
{% if "battery" in item.name | lower and ((item.state | int < threshold and item.state|int != 0) or item.state | lower == "low" or item.state | lower == "unknown") -%}
{{ item.name }} ({{ item.state }}){% if not loop.last %}, {%- endif %} {% endif -%}
{% endfor %}
{%- endfor %}
{% endmacro %}
{{ battery_level() }}
- service: notify.pushover
data_template:
title: "Battery status"
message: >
{% macro battery_level() %}
{%- set threshold = 40 -%}
{% set domains = ['light', 'switch', 'sensor', 'zwave', 'lock'] %}
{% for domain in domains -%}
{% for item in states[domain] if ((item.attributes.battery_level is defined and item.attributes['battery_level'] | int < threshold) or ("battery" in item.name | lower and ((item.state | int < threshold and item.state|int != 0) or item.state | lower == "low" or item.state | lower == "unknown"))) -%}
{% if (item.attributes.battery_level is defined and item.attributes['battery_level'] | int < threshold) -%}
{{ item.name }} ({{ item.attributes['battery_level'] }}){%- if not loop.last %}, {% endif -%}{% endif -%}
{% if "battery" in item.name | lower and ((item.state | int < threshold and item.state|int != 0) or item.state | lower == "low" or item.state | lower == "unknown") -%}
{{ item.name }} ({{ item.state }}){% if not loop.last %}, {%- endif %} {% endif -%}
{% endfor %}
{%- endfor %}
{% endmacro %}
{{ battery_level()}}
Very neat, great work, time to give it a test
@sjabby can you help me understand what the Node Anchors do? I have never seen that before and not sure what homebridge is.
Node Anchors is used to simplify your configurations and avoid repetitions of settings. So instead of repeting all settings for each entity you just add an anchor to the setting. Example:
Without anchors:
################################################
## Without Node Anchors and Merge Key Tags
################################################
homeassistant:
customize:
light.back_porch:
friendly_name: "Back Porch"
package: 'philips_hue'
light.chandelier:
friendly_name: "Chandelier"
package: 'philips_hue'
light.dining_room:
friendly_name: "Dining Room"
package: 'philips_hue'
light.entry_lamp:
friendly_name: "Entry Lamp"
package: 'philips_hue'
light.front_porch:
friendly_name: "Front Porch"
package: 'philips_hue'
The same config with anchors:
################################################
## With Node Anchors and Merge Key Tags
################################################
homeassistant:
customize:
package.node_anchors: # This is just a dummy entry
customize: &customize # Also a dummy entry that allows us to define the node anchor
package: 'philips_hue'
light.back_porch:
<<: *customize # This merges the keys/values from "&customize"
friendly_name: "Back Porch"
light.chandelier:
<<: *customize
friendly_name: "Chandelier"
light.dining_room:
<<: *customize
friendly_name: "Dining Room"
light.entry_lamp:
<<: *customize
friendly_name: "Entry Lamp"
light.front_porch:
<<: *customize
friendly_name: "Front Porch"
Full example from @dale3h: https://github.com/dale3h/homeassistant-config/blob/master/examples/yaml_anchors.yaml
Here’s an update to the package with an alert that automatically clears the persistent notification when the low batteries are fixed.
################################################################
## Packages / Battery levels
################################################################
################################################
## Customize
################################################
homeassistant:
customize:
################################################
## Node Anchors
################################################
package.node_anchors:
customize: &customize
package: 'battery_alert'
expose: &expose
<<: *customize
haaska_hidden: false
homebridge_hidden: false
################################################
## Group
################################################
group.battery_alert:
<<: *customize
friendly_name: "Battery Alert"
icon: mdi:steam
################################################
## Automation
################################################
automation.battery_alert:
<<: *customize
friendly_name: "Battery Alert"
automation.battery_alert_clear:
<<: *customize
friendly_name: "Battery Alert Clear"
################################################
## Group
################################################
group:
battery_alert:
control: hidden
entities:
- automation.battery_alert
- automation.battery_alert_clear
################################################
## Automation
################################################
automation:
- alias: battery_alert
trigger:
- platform: time
at: '10:00:00'
- platform: time
at: '18:00:00'
condition:
- condition: template
value_template: >
{% macro battery_level() %}
{%- set threshold = 40 -%}
{% set domains = ['light', 'switch', 'sensor', 'zwave', 'lock'] %}
{% for domain in domains -%}
{% for item in states[domain] if ((item.attributes.battery_level is defined and item.attributes['battery_level'] | int < threshold) or ("battery" in item.name | lower and ((item.state | int < threshold and item.state|int != 0) or item.state | lower == "low" or item.state | lower == "unknown"))) -%}
{% if (item.attributes.battery_level is defined and item.attributes['battery_level'] | int < threshold) -%}
{{ item.name }} ({{ item.attributes['battery_level'] }}){%- if not loop.last %}, {% endif -%}{% endif -%}
{% if "battery" in item.name | lower and ((item.state | int < threshold and item.state|int != 0) or item.state | lower == "low" or item.state | lower == "unknown") -%}
{{ item.name }} ({{ item.state }}){% if not loop.last %}, {%- endif %} {% endif -%}
{% endfor %}
{%- endfor %}
{% endmacro %}
{{ battery_level() |trim != "" }}
action:
- service: persistent_notification.create
data_template:
title: "Low Battery levels"
notification_id: low-battery-alert
message: >
{% macro battery_level() %}
{%- set threshold = 40 -%}
{% set domains = ['light', 'switch', 'sensor', 'zwave', 'lock'] %}
{% for domain in domains -%}
{% for item in states[domain] if ((item.attributes.battery_level is defined and item.attributes['battery_level'] | int < threshold) or ("battery" in item.name | lower and ((item.state | int < threshold and item.state|int != 0) or item.state | lower == "low" or item.state | lower == "unknown"))) -%}
{% if (item.attributes.battery_level is defined and item.attributes['battery_level'] | int < threshold) -%}
{{ item.name }} ({{ item.attributes['battery_level'] }}){%- if not loop.last %}, {% endif -%}{% endif -%}
{% if "battery" in item.name | lower and ((item.state | int < threshold and item.state|int != 0) or item.state | lower == "low" or item.state | lower == "unknown") -%}
{{ item.name }} ({{ item.state }}){% if not loop.last %}, {%- endif %} {% endif -%}
{% endfor %}
{%- endfor %}
{% endmacro %}
{{ battery_level() }}
- service: notify.slack_notify
data_template:
message: "Low Battery Levels"
data:
attachments:
- color: '#52c0f2'
title: "These devices have low battery levels"
text: >
{% macro battery_level() %}
{%- set threshold = 40 -%}
{% set domains = ['light', 'switch', 'sensor', 'zwave', 'lock'] %}
{% for domain in domains -%}
{% for item in states[domain] if ((item.attributes.battery_level is defined and item.attributes['battery_level'] | int < threshold) or ("battery" in item.name | lower and ((item.state | int < threshold and item.state|int != 0) or item.state | lower == "low" or item.state | lower == "unknown"))) -%}
{% if (item.attributes.battery_level is defined and item.attributes['battery_level'] | int < threshold) -%}
{{ item.name }} ({{ item.attributes['battery_level'] }}){%- if not loop.last %}, {% endif -%}{% endif -%}
{% if "battery" in item.name | lower and ((item.state | int < threshold and item.state|int != 0) or item.state | lower == "low" or item.state | lower == "unknown") -%}
{{ item.name }} ({{ item.state }}){% if not loop.last %}, {%- endif %} {% endif -%}
{% endfor %}
{%- endfor %}
{% endmacro %}
{{ battery_level() }}
- alias: battery_alert_clear
trigger:
- platform: time
minutes: '/30'
seconds: 00
condition:
- condition: template
value_template: >
{% macro battery_level() %}
{%- set threshold = 40 -%}
{% set domains = ['light', 'switch', 'sensor', 'zwave', 'lock'] %}
{% for domain in domains -%}
{% for item in states[domain] if ((item.attributes.battery_level is defined and item.attributes['battery_level'] | int < threshold) or ("battery" in item.name | lower and ((item.state | int < threshold and item.state|int != 0) or item.state | lower == "low" or item.state | lower == "unknown"))) -%}
{% if (item.attributes.battery_level is defined and item.attributes['battery_level'] | int < threshold) -%}
{{ item.name }} ({{ item.attributes['battery_level'] }}){%- if not loop.last %}, {% endif -%}{% endif -%}
{% if "battery" in item.name | lower and ((item.state | int < threshold and item.state|int != 0) or item.state | lower == "low" or item.state | lower == "unknown") -%}
{{ item.name }} ({{ item.state }}){% if not loop.last %}, {%- endif %} {% endif -%}
{% endfor %}
{%- endfor %}
{% endmacro %}
{{ battery_level() |trim == "" }}
action:
- service: persistent_notification.dismiss
data:
notification_id: low-battery-alert
This is great. Anyway to have a space separating the various entities that are pulled up by the automation in the persistant notification box?
There should already be a comma and space between each item like this Sensor 1 (32), Sensor 2 (30), Sensor 3 (Low)
. What does yours look like?
Here is the screenshot.
works perfectly! Thanks!
Brilliant work thanks to everyone involved. I need to lower the thresholds as I have Xiaomi sensors as well and most of them are shown as low