#:########################################################################################:# # Battery Notes Alerts Package # #:########################################################################################:# # # TITLE: # Battery Notes Alerts # # FILE: # packages/battery_notes_alerts.yaml # # VERSION: # V1.0.1 2026-08-25 # # PURPOSE: # Sends immediate and weekly Pushover alerts for non-temporary Battery Notes devices. # Device lists are generated from Battery Notes at runtime, so adding a note starts # monitoring the device without maintaining a second entity list. # # CONTROLS: # - Battery Notes - Immediate Alert and Battery Notes - Weekly Digest are independent # automation entities. Each can be enabled or disabled in Home Assistant Automations. # # DEPENDENCIES: # - Battery Notes integration # - packages/view_road_announcement_router.yaml # # VERSION HISTORY: # - V1.0.1 2026-08-25: Bound companion lookups and prevent oversized template output. # - V1.0.0 2026-08-25: Initial immediate and Thursday weekly battery alerts. # #:########################################################################################:# automation: - id: battery_notes_immediate_alert alias: "Battery Notes - Immediate Alert" description: > Sends a Pushover alert when a monitored Battery Notes device newly reports low battery or becomes unavailable. Temporary Battery Notes devices are ignored. mode: single max_exceeded: silent triggers: - trigger: event event_type: state_changed conditions: - condition: template value_template: >- {{ trigger.event.data.entity_id is match('^(sensor|binary_sensor)\\..*_battery_plus(?:_low)?$') }} - condition: template value_template: >- {% set old = trigger.event.data.old_state %} {% set new = trigger.event.data.new_state %} {{ old is not none and new is not none and old.state not in ['unknown', 'unavailable'] and old.state != new.state }} - condition: template value_template: >- {% set new = trigger.event.data.new_state %} {% set note = new.attributes.note | default('', true) | lower %} {{ new.attributes.device_id | default('') | bool and 'temporary' not in note }} - condition: template value_template: >- {%- set old = trigger.event.data.old_state -%} {%- set new = trigger.event.data.new_state -%} {%- set device_id = new.attributes.device_id -%} {%- set companions = namespace(percentage_id='', qualitative_id='') -%} {%- for entity_id in device_entities(device_id) -%} {%- if entity_id.startswith('sensor.') and entity_id.endswith('_battery_plus') -%} {%- set companions.percentage_id = entity_id -%} {%- elif entity_id.startswith('sensor.') and entity_id.endswith('_battery_state') -%} {%- set companions.qualitative_id = entity_id -%} {%- endif -%} {%- endfor -%} {%- set source_id = companions.percentage_id or new.entity_id -%} {%- set qualitative_available = companions.qualitative_id and states(companions.qualitative_id) in ['high', 'medium', 'low'] -%} {%- set newly_low = new.attributes.battery_low | default(false) and not old.attributes.battery_low | default(false) -%} {%- set newly_binary_low = new.entity_id.startswith('binary_sensor.') and new.state == 'on' -%} {%- set newly_unavailable = new.state in ['unknown', 'unavailable'] and source_id == new.entity_id and not qualitative_available -%} {{ newly_low or newly_binary_low or newly_unavailable }} variables: alert_name: >- {% set new = trigger.event.data.new_state %} {{ new.attributes.device_name | default(new.attributes.friendly_name, true) | default(new.name, true) }} alert_type: >- {{ trigger.event.data.new_state.attributes.battery_type_and_quantity | default('Not recorded', true) }} alert_level: >- {%- set device_id = trigger.event.data.new_state.attributes.device_id -%} {%- set level = namespace(value='') -%} {%- for entity_id in device_entities(device_id) -%} {%- if entity_id.startswith('sensor.') and entity_id.endswith('_battery_plus') and states(entity_id) not in ['unknown', 'unavailable'] -%} {%- set level.value = states(entity_id) -%} {%- endif -%} {%- endfor -%} {{ level.value ~ '%' if level.value else '' }} alert_line: >- {% if trigger.event.data.new_state.state in ['unknown', 'unavailable'] %} New Alert: {{ alert_name }}, Battery Unavailable {{ alert_type }} {% else %} New Alert: {{ alert_name }}, Battery Low {{ alert_level }} {{ alert_type }} {% endif %} alert_summary: &battery_notes_summary >- {%- set monitored = namespace(device_ids=[], low=[], unavailable=[]) -%} {%- for item in states -%} {%- set note = item.attributes.note | default('', true) | lower -%} {%- set device_id = item.attributes.device_id | default('') -%} {%- if item.entity_id is match('^(sensor|binary_sensor)\\..*_battery_plus(?:_low)?$') and device_id and 'temporary' not in note and device_id not in monitored.device_ids -%} {%- set monitored.device_ids = monitored.device_ids + [device_id] -%} {%- endif -%} {%- endfor -%} {%- for device_id in monitored.device_ids -%} {%- set device = namespace(percentage_id='', low_id='', qualitative_id='') -%} {%- for entity_id in device_entities(device_id) -%} {%- if entity_id.startswith('sensor.') and entity_id.endswith('_battery_plus') -%} {%- set device.percentage_id = entity_id -%} {%- elif entity_id.startswith('binary_sensor.') and entity_id.endswith('_battery_plus_low') -%} {%- set device.low_id = entity_id -%} {%- elif entity_id.startswith('sensor.') and entity_id.endswith('_battery_state') -%} {%- set device.qualitative_id = entity_id -%} {%- endif -%} {%- endfor -%} {%- set source_id = device.percentage_id or device.low_id -%} {%- set source_state = states(source_id) -%} {%- set qualitative_state = states(device.qualitative_id) if device.qualitative_id else '' -%} {%- set name = state_attr(source_id, 'device_name') or state_attr(source_id, 'friendly_name') or source_id -%} {%- set battery_type = state_attr(source_id, 'battery_type_and_quantity') or 'Not recorded' -%} {%- set low = state_attr(source_id, 'battery_low') | default(false, true) or (device.low_id and is_state(device.low_id, 'on')) or qualitative_state == 'low' -%} {%- set unavailable = source_state in ['unknown', 'unavailable'] and qualitative_state not in ['high', 'medium', 'low'] -%} {%- if low -%} {%- set level = source_state ~ '%' if device.percentage_id and source_state not in ['unknown', 'unavailable'] else '' -%} {%- set monitored.low = monitored.low + [name ~ ' (' ~ level ~ (', ' if level else '') ~ battery_type ~ ')'] -%} {%- endif -%} {%- if unavailable -%} {%- set monitored.unavailable = monitored.unavailable + [name ~ ' (' ~ battery_type ~ ')'] -%} {%- endif -%} {%- endfor -%} Summary: {{ monitored.device_ids | count }} Battery Notes devices, {{ monitored.unavailable | count }} unavailable, {{ monitored.low | count }} battery low. Low Battery Devices: {{ monitored.low | join(', ') if monitored.low else 'None' }} Unavailable Devices: {{ monitored.unavailable | join(', ') if monitored.unavailable else 'None' }} actions: - action: script.view_road_announcement data: channels: "pushover_zorruno" title: "Battery Alert" short_announcement: "{{ alert_line }}" long_announcement: >- {{ alert_line }} {{ alert_summary }} - id: battery_notes_weekly_digest alias: "Battery Notes - Weekly Digest" description: > Sends the Battery Notes health summary to Pushover every Thursday at 19:00. Temporary Battery Notes devices are excluded. mode: single triggers: - trigger: time at: "19:00:00" conditions: - condition: time weekday: - thu variables: alert_summary: *battery_notes_summary actions: - action: script.view_road_announcement data: channels: "pushover_zorruno" title: "Weekly Battery Digest" short_announcement: "Weekly Battery Digest" long_announcement: "{{ alert_summary }}"