various tidyups
This commit is contained in:
@@ -0,0 +1,636 @@
|
||||
#:########################################################################################:#
|
||||
# Battery Notes Alerts Package #
|
||||
#:########################################################################################:#
|
||||
#
|
||||
# TITLE:
|
||||
# Battery Notes Alerts
|
||||
#
|
||||
# FILE:
|
||||
# packages/battery_notes_alerts.yaml
|
||||
#
|
||||
# VERSION:
|
||||
# V1.1.0 2026-08-26
|
||||
#
|
||||
# PURPOSE:
|
||||
# Sends immediate Pushover alerts when a non-temporary Battery Notes device newly
|
||||
# reports a low battery or becomes unavailable, plus a Thursday weekly digest.
|
||||
#
|
||||
# Immediate alerts are limited to one alert of each type per device per calendar day.
|
||||
#
|
||||
# SAFETY / PERFORMANCE DESIGN:
|
||||
# - No automation-level templated variables.
|
||||
# - Low battery detection uses the native Battery Notes threshold event.
|
||||
# - Weekly Battery Notes checks use raise_events: false.
|
||||
# - Immediate automations never scan all Home Assistant states.
|
||||
# - Immediate automations never call device_entities().
|
||||
# - The offline watcher does only cheap filtering on state_changed events.
|
||||
# - Offline alerts are inhibited for 10 minutes after Home Assistant starts.
|
||||
# - Weekly list processing is bounded to 100 returned items per category.
|
||||
# - Devices with "Temporary" anywhere in the Battery Notes note are always ignored.
|
||||
#
|
||||
# CONTROLS:
|
||||
# - input_boolean.battery_notes_alerts_master_enable
|
||||
# Master enable/disable for all notifications from this package.
|
||||
#
|
||||
# - Battery Notes - Immediate Low Alert
|
||||
# May also be independently enabled/disabled in Automations.
|
||||
#
|
||||
# - Battery Notes - Immediate Offline Alert
|
||||
# May also be independently enabled/disabled in Automations.
|
||||
#
|
||||
# - Battery Notes - Weekly Digest
|
||||
# May also be independently enabled/disabled in Automations.
|
||||
#
|
||||
# OPERATION:
|
||||
# - LOW:
|
||||
# Native Battery Notes threshold event only.
|
||||
# Reminder-generated events are ignored.
|
||||
# Maximum one low alert per device per calendar day.
|
||||
#
|
||||
# - OFFLINE:
|
||||
# Battery Notes Battery+ entities changing from a valid state to
|
||||
# unknown/unavailable.
|
||||
# Suppressed for 10 minutes after Home Assistant starts.
|
||||
# Maximum one offline alert per device per calendar day.
|
||||
#
|
||||
# - WEEKLY:
|
||||
# Thursday at 19:00.
|
||||
# Reports current low batteries and batteries not reporting for 2+ days.
|
||||
# Battery Notes devices marked Temporary are excluded.
|
||||
#
|
||||
# DEPENDENCIES:
|
||||
# - Battery Notes integration
|
||||
# - packages/view_road_announcement_router.yaml
|
||||
#
|
||||
# VERSION HISTORY:
|
||||
# - V1.1.0 2026-08-26: Complete redesign using native Battery Notes events/actions.
|
||||
# Removes high-frequency state scanning and top-level templates.
|
||||
# Adds Temporary filtering, daily per-device alert suppression,
|
||||
# startup offline suppression and master enable control.
|
||||
# - V1.0.2 2026-08-25: RETIRED - unsafe high-frequency architecture.
|
||||
# - V1.0.1 2026-08-25: RETIRED - unsafe high-frequency architecture.
|
||||
# - V1.0.0 2026-08-25: RETIRED - unsafe high-frequency architecture.
|
||||
#
|
||||
#:########################################################################################:#
|
||||
|
||||
|
||||
#:########################################################################################:#
|
||||
# HELPERS #
|
||||
#:########################################################################################:#
|
||||
|
||||
input_boolean:
|
||||
|
||||
# Master safety switch.
|
||||
#
|
||||
# No "initial" value is specified intentionally:
|
||||
# - First creation defaults to OFF.
|
||||
# - Thereafter Home Assistant restores the previous state.
|
||||
battery_notes_alerts_master_enable:
|
||||
name: "Battery Notes Alerts - Master Enable"
|
||||
icon: mdi:battery-alert
|
||||
|
||||
# Internal startup guard.
|
||||
#
|
||||
# This MUST start false on every Home Assistant restart.
|
||||
battery_notes_offline_alerts_armed:
|
||||
name: "Battery Notes Alerts - Offline Armed"
|
||||
icon: mdi:shield-clock
|
||||
initial: false
|
||||
|
||||
|
||||
input_text:
|
||||
|
||||
# Daily de-duplication caches.
|
||||
#
|
||||
# Format:
|
||||
# YYYY-MM-DD|xxxxxxxxxx|xxxxxxxxxx|...
|
||||
#
|
||||
# Only the final 10 characters of the device identifier are stored.
|
||||
# A maximum of the 20 most recent device tokens is retained.
|
||||
#
|
||||
# No initial value is set so the cache survives Home Assistant restarts.
|
||||
battery_notes_low_alert_cache:
|
||||
name: "Battery Notes - Low Alert Cache"
|
||||
max: 255
|
||||
icon: mdi:battery-alert-variant
|
||||
|
||||
battery_notes_offline_alert_cache:
|
||||
name: "Battery Notes - Offline Alert Cache"
|
||||
max: 255
|
||||
icon: mdi:battery-off-outline
|
||||
|
||||
|
||||
#:########################################################################################:#
|
||||
# AUTOMATIONS #
|
||||
#:########################################################################################:#
|
||||
|
||||
automation:
|
||||
|
||||
#:######################################################################################:#
|
||||
# Offline Alert Startup Guard #
|
||||
#:######################################################################################:#
|
||||
|
||||
- id: battery_notes_arm_offline_alerts
|
||||
alias: "Battery Notes - Arm Offline Alerts"
|
||||
description: >
|
||||
Arms Battery Notes offline notifications 10 minutes after Home Assistant starts.
|
||||
This prevents normal startup/integration initialisation from being interpreted as
|
||||
devices suddenly going offline.
|
||||
mode: restart
|
||||
|
||||
triggers:
|
||||
- trigger: homeassistant
|
||||
event: start
|
||||
|
||||
actions:
|
||||
- action: input_boolean.turn_off
|
||||
target:
|
||||
entity_id: input_boolean.battery_notes_offline_alerts_armed
|
||||
|
||||
- delay: "00:10:00"
|
||||
|
||||
- action: input_boolean.turn_on
|
||||
target:
|
||||
entity_id: input_boolean.battery_notes_offline_alerts_armed
|
||||
|
||||
|
||||
#:######################################################################################:#
|
||||
# Immediate Low Battery Alert #
|
||||
#:######################################################################################:#
|
||||
|
||||
- id: battery_notes_immediate_low_alert
|
||||
alias: "Battery Notes - Immediate Low Alert"
|
||||
description: >
|
||||
Sends one immediate Pushover alert when a non-temporary Battery Notes device
|
||||
genuinely crosses into its low-battery state. Reminder-generated Battery Notes
|
||||
events are ignored. A device can generate at most one low alert per calendar day.
|
||||
mode: queued
|
||||
max: 10
|
||||
|
||||
triggers:
|
||||
- trigger: event
|
||||
event_type: battery_notes_battery_threshold
|
||||
event_data:
|
||||
battery_low: true
|
||||
reminder: false
|
||||
|
||||
conditions:
|
||||
|
||||
# Master control.
|
||||
- condition: state
|
||||
entity_id: input_boolean.battery_notes_alerts_master_enable
|
||||
state: "on"
|
||||
|
||||
# Temporary Battery Notes devices must never generate notifications.
|
||||
- condition: template
|
||||
value_template: >-
|
||||
{% set note = trigger.event.data.note | default('', true) | lower %}
|
||||
{{ 'temporary' not in note }}
|
||||
|
||||
# Require some stable identifier for daily de-duplication.
|
||||
- condition: template
|
||||
value_template: >-
|
||||
{{ (trigger.event.data.device_id | default('', true)) != ''
|
||||
or (trigger.event.data.source_entity_id | default('', true)) != '' }}
|
||||
|
||||
actions:
|
||||
|
||||
# IMPORTANT:
|
||||
# This de-duplication check is deliberately an ACTION condition rather than an
|
||||
# automation-level condition. Because this automation is mode: queued, two events
|
||||
# arriving together are serialised before checking/updating the cache.
|
||||
- condition: template
|
||||
value_template: >-
|
||||
{% set identifier =
|
||||
trigger.event.data.device_id | default('', true)
|
||||
or trigger.event.data.source_entity_id | default('', true) %}
|
||||
{% set token = identifier[-10:] %}
|
||||
{% set today = now().date() | string %}
|
||||
{% set cache = states('input_text.battery_notes_low_alert_cache') %}
|
||||
{% set previous =
|
||||
cache.split('|')[1:]
|
||||
if cache.startswith(today ~ '|')
|
||||
else [] %}
|
||||
{{ token not in previous }}
|
||||
|
||||
- action: script.view_road_announcement
|
||||
data:
|
||||
channels: "pushover_zorruno"
|
||||
title: "Battery Alert"
|
||||
short_announcement: >-
|
||||
{% set name =
|
||||
trigger.event.data.device_name
|
||||
| default('Unknown Battery Device', true) %}
|
||||
{% set level =
|
||||
trigger.event.data.battery_level
|
||||
| default(-1, true)
|
||||
| float(-1) %}
|
||||
{% set battery_type =
|
||||
trigger.event.data.battery_type_and_quantity
|
||||
| default('Not recorded', true) %}
|
||||
New Alert: {{ name }}, Battery Low{% if level >= 0 %}
|
||||
{{ level | round(0) | int }}%{% endif %} {{ battery_type }}
|
||||
long_announcement: >-
|
||||
{% set name =
|
||||
trigger.event.data.device_name
|
||||
| default('Unknown Battery Device', true) %}
|
||||
{% set level =
|
||||
trigger.event.data.battery_level
|
||||
| default(-1, true)
|
||||
| float(-1) %}
|
||||
{% set battery_type =
|
||||
trigger.event.data.battery_type_and_quantity
|
||||
| default('Not recorded', true) %}
|
||||
New Alert: {{ name }}, Battery Low{% if level >= 0 %}
|
||||
{{ level | round(0) | int }}%{% endif %} {{ battery_type }}
|
||||
|
||||
# Record this device only after the notification action has completed.
|
||||
- action: input_text.set_value
|
||||
target:
|
||||
entity_id: input_text.battery_notes_low_alert_cache
|
||||
data:
|
||||
value: >-
|
||||
{% set identifier =
|
||||
trigger.event.data.device_id | default('', true)
|
||||
or trigger.event.data.source_entity_id | default('', true) %}
|
||||
{% set token = identifier[-10:] %}
|
||||
{% set today = now().date() | string %}
|
||||
{% set cache = states('input_text.battery_notes_low_alert_cache') %}
|
||||
{% set previous =
|
||||
cache.split('|')[1:]
|
||||
if cache.startswith(today ~ '|')
|
||||
else [] %}
|
||||
{% set updated = (previous + [token])[-20:] %}
|
||||
{{ today ~ '|' ~ updated | join('|') }}
|
||||
|
||||
|
||||
#:######################################################################################:#
|
||||
# Immediate Offline Alert #
|
||||
#:######################################################################################:#
|
||||
|
||||
- id: battery_notes_immediate_offline_alert
|
||||
alias: "Battery Notes - Immediate Offline Alert"
|
||||
description: >
|
||||
Sends one immediate Pushover alert when a non-temporary Battery Notes Battery+
|
||||
entity genuinely changes from an available state to unknown/unavailable.
|
||||
Alerts are inhibited for the first 10 minutes after Home Assistant starts.
|
||||
A device can generate at most one offline alert per calendar day.
|
||||
mode: queued
|
||||
max: 20
|
||||
|
||||
triggers:
|
||||
- trigger: event
|
||||
event_type: state_changed
|
||||
|
||||
conditions:
|
||||
|
||||
# Keep the first checks extremely cheap because state_changed is a global event.
|
||||
- condition: state
|
||||
entity_id: input_boolean.battery_notes_alerts_master_enable
|
||||
state: "on"
|
||||
|
||||
- condition: state
|
||||
entity_id: input_boolean.battery_notes_offline_alerts_armed
|
||||
state: "on"
|
||||
|
||||
# Only Battery Notes generated Battery+ entities are interesting.
|
||||
# No regex and no global state lookup is required.
|
||||
- condition: template
|
||||
value_template: >-
|
||||
{% set entity_id = trigger.event.data.entity_id | default('', true) %}
|
||||
{{ (entity_id.startswith('sensor.')
|
||||
and entity_id.endswith('_battery_plus'))
|
||||
or
|
||||
(entity_id.startswith('binary_sensor.')
|
||||
and entity_id.endswith('_battery_plus_low')) }}
|
||||
|
||||
# Require a genuine transition from available -> unavailable.
|
||||
- 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 new.state in ['unknown', 'unavailable'] }}
|
||||
|
||||
# Temporary devices are ignored.
|
||||
#
|
||||
# Prefer the new state's note but fall back to the old state's attributes because
|
||||
# integrations do not always retain every attribute on an unavailable state.
|
||||
- condition: template
|
||||
value_template: >-
|
||||
{% set old = trigger.event.data.old_state %}
|
||||
{% set new = trigger.event.data.new_state %}
|
||||
{% set note =
|
||||
new.attributes.get(
|
||||
'note',
|
||||
old.attributes.get('note', '')
|
||||
)
|
||||
| default('', true)
|
||||
| lower %}
|
||||
{{ 'temporary' not in note }}
|
||||
|
||||
actions:
|
||||
|
||||
# As with low alerts, do this after entering the queued action sequence so two
|
||||
# related Battery+ entities becoming unavailable together cannot both notify.
|
||||
- condition: template
|
||||
value_template: >-
|
||||
{% set old = trigger.event.data.old_state %}
|
||||
{% set new = trigger.event.data.new_state %}
|
||||
{% set identifier =
|
||||
new.attributes.get('device_id', '')
|
||||
or old.attributes.get('device_id', '')
|
||||
or new.entity_id %}
|
||||
{% set token = identifier[-10:] %}
|
||||
{% set today = now().date() | string %}
|
||||
{% set cache = states('input_text.battery_notes_offline_alert_cache') %}
|
||||
{% set previous =
|
||||
cache.split('|')[1:]
|
||||
if cache.startswith(today ~ '|')
|
||||
else [] %}
|
||||
{{ token not in previous }}
|
||||
|
||||
- action: script.view_road_announcement
|
||||
data:
|
||||
channels: "pushover_zorruno"
|
||||
title: "Battery Alert"
|
||||
short_announcement: >-
|
||||
{% set old = trigger.event.data.old_state %}
|
||||
{% set new = trigger.event.data.new_state %}
|
||||
{% set name =
|
||||
new.attributes.get('device_name')
|
||||
or old.attributes.get('device_name')
|
||||
or new.attributes.get('friendly_name')
|
||||
or old.attributes.get('friendly_name')
|
||||
or new.name %}
|
||||
{% set battery_type =
|
||||
new.attributes.get('battery_type_and_quantity')
|
||||
or old.attributes.get('battery_type_and_quantity')
|
||||
or 'Not recorded' %}
|
||||
New Alert: {{ name }}, Battery Unavailable {{ battery_type }}
|
||||
long_announcement: >-
|
||||
{% set old = trigger.event.data.old_state %}
|
||||
{% set new = trigger.event.data.new_state %}
|
||||
{% set name =
|
||||
new.attributes.get('device_name')
|
||||
or old.attributes.get('device_name')
|
||||
or new.attributes.get('friendly_name')
|
||||
or old.attributes.get('friendly_name')
|
||||
or new.name %}
|
||||
{% set battery_type =
|
||||
new.attributes.get('battery_type_and_quantity')
|
||||
or old.attributes.get('battery_type_and_quantity')
|
||||
or 'Not recorded' %}
|
||||
New Alert: {{ name }}, Battery Unavailable {{ battery_type }}
|
||||
|
||||
- action: input_text.set_value
|
||||
target:
|
||||
entity_id: input_text.battery_notes_offline_alert_cache
|
||||
data:
|
||||
value: >-
|
||||
{% set old = trigger.event.data.old_state %}
|
||||
{% set new = trigger.event.data.new_state %}
|
||||
{% set identifier =
|
||||
new.attributes.get('device_id', '')
|
||||
or old.attributes.get('device_id', '')
|
||||
or new.entity_id %}
|
||||
{% set token = identifier[-10:] %}
|
||||
{% set today = now().date() | string %}
|
||||
{% set cache = states('input_text.battery_notes_offline_alert_cache') %}
|
||||
{% set previous =
|
||||
cache.split('|')[1:]
|
||||
if cache.startswith(today ~ '|')
|
||||
else [] %}
|
||||
{% set updated = (previous + [token])[-20:] %}
|
||||
{{ today ~ '|' ~ updated | join('|') }}
|
||||
|
||||
|
||||
#:######################################################################################:#
|
||||
# Weekly Digest #
|
||||
#:######################################################################################:#
|
||||
|
||||
- id: battery_notes_weekly_digest
|
||||
alias: "Battery Notes - Weekly Digest"
|
||||
description: >
|
||||
Sends one Battery Notes summary every Thursday at 19:00. Reports current low
|
||||
batteries and batteries which have not reported for at least two days.
|
||||
Temporary Battery Notes devices are excluded.
|
||||
mode: single
|
||||
|
||||
triggers:
|
||||
- trigger: time
|
||||
at: "19:00:00"
|
||||
|
||||
conditions:
|
||||
- condition: time
|
||||
weekday:
|
||||
- thu
|
||||
|
||||
- condition: state
|
||||
entity_id: input_boolean.battery_notes_alerts_master_enable
|
||||
state: "on"
|
||||
|
||||
actions:
|
||||
|
||||
# IMPORTANT:
|
||||
# raise_events MUST remain false.
|
||||
#
|
||||
# This retrieves the current low list without creating Battery Notes threshold
|
||||
# reminder events.
|
||||
- action: battery_notes.check_battery_low
|
||||
data:
|
||||
raise_events: false
|
||||
response_variable: battery_low_response
|
||||
|
||||
# Ask Battery Notes for devices which have not reported for at least two days.
|
||||
# Again, retrieve a response only; do not raise one event per device.
|
||||
- action: battery_notes.check_battery_last_reported
|
||||
data:
|
||||
days_last_reported: 2
|
||||
raise_events: false
|
||||
response_variable: battery_report_response
|
||||
|
||||
- action: script.view_road_announcement
|
||||
data:
|
||||
channels: "pushover_zorruno"
|
||||
title: "Weekly Battery Digest"
|
||||
short_announcement: "Weekly Battery Digest"
|
||||
long_announcement: >-
|
||||
{# ------------------------------------------------------------------------- #}
|
||||
{# Obtain response arrays. #}
|
||||
{# #}
|
||||
{# check_battery_battery_low is confirmed from this HA installation. #}
|
||||
{# Two possible last-reported response keys are accepted defensively. #}
|
||||
{# ------------------------------------------------------------------------- #}
|
||||
|
||||
{% set low_items =
|
||||
battery_low_response.get(
|
||||
'check_battery_battery_low',
|
||||
battery_low_response.get('check_battery_low', [])
|
||||
) %}
|
||||
|
||||
{% set report_items =
|
||||
battery_report_response.get(
|
||||
'check_battery_last_reported',
|
||||
battery_report_response.get(
|
||||
'check_battery_battery_last_reported',
|
||||
[]
|
||||
)
|
||||
) %}
|
||||
|
||||
{# ------------------------------------------------------------------------- #}
|
||||
{# Resolve the Battery Notes note. #}
|
||||
{# #}
|
||||
{# The low action response on this installation does not include "note", #}
|
||||
{# so fall back to the attributes of Battery Notes entities. #}
|
||||
{# This lookup occurs ONCE PER WEEK ONLY and is bounded below. #}
|
||||
{# ------------------------------------------------------------------------- #}
|
||||
|
||||
{% macro battery_note(item) -%}
|
||||
{% set ns =
|
||||
namespace(
|
||||
note=item.get('note', '') | default('', true)
|
||||
) %}
|
||||
|
||||
{% if not ns.note %}
|
||||
{% set item_device_id =
|
||||
item.get('device_id', '') | default('', true) %}
|
||||
{% set item_source_id =
|
||||
item.get('source_entity_id', '') | default('', true) %}
|
||||
|
||||
{% for entity_id in integration_entities('battery_notes') %}
|
||||
{% if not ns.note %}
|
||||
{% set entity_device_id =
|
||||
state_attr(entity_id, 'device_id')
|
||||
| default('', true) %}
|
||||
{% set entity_source_id =
|
||||
state_attr(entity_id, 'source_entity_id')
|
||||
| default('', true) %}
|
||||
|
||||
{% if
|
||||
(item_device_id
|
||||
and entity_device_id == item_device_id)
|
||||
or
|
||||
(item_source_id
|
||||
and entity_source_id == item_source_id) %}
|
||||
{% set found_note =
|
||||
state_attr(entity_id, 'note')
|
||||
| default('', true) %}
|
||||
{% if found_note %}
|
||||
{% set ns.note = found_note %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{{ ns.note }}
|
||||
{%- endmacro %}
|
||||
|
||||
{# ------------------------------------------------------------------------- #}
|
||||
{# Build bounded problem lists, excluding Temporary devices. #}
|
||||
{# ------------------------------------------------------------------------- #}
|
||||
|
||||
{% set summary = namespace(low=[], not_reporting=[]) %}
|
||||
|
||||
{% for item in low_items[:100] %}
|
||||
{% set note = battery_note(item) | trim | lower %}
|
||||
|
||||
{% if 'temporary' not in note %}
|
||||
{% set name =
|
||||
item.get('device_name', 'Unknown Battery Device')
|
||||
| default('Unknown Battery Device', true) %}
|
||||
{% set level =
|
||||
item.get('battery_level', -1)
|
||||
| default(-1, true)
|
||||
| float(-1) %}
|
||||
{% set battery_type =
|
||||
item.get('battery_type_and_quantity', 'Not recorded')
|
||||
| default('Not recorded', true) %}
|
||||
|
||||
{% if level >= 0 %}
|
||||
{% set line =
|
||||
name
|
||||
~ ' - '
|
||||
~ (level | round(0) | int)
|
||||
~ '% - '
|
||||
~ battery_type %}
|
||||
{% else %}
|
||||
{% set line =
|
||||
name
|
||||
~ ' - '
|
||||
~ battery_type %}
|
||||
{% endif %}
|
||||
|
||||
{% set summary.low = summary.low + [line] %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% for item in report_items[:100] %}
|
||||
{% set note = battery_note(item) | trim | lower %}
|
||||
|
||||
{% if 'temporary' not in note %}
|
||||
{% set name =
|
||||
item.get('device_name', 'Unknown Battery Device')
|
||||
| default('Unknown Battery Device', true) %}
|
||||
{% set days =
|
||||
item.get('battery_last_reported_days', 0)
|
||||
| default(0, true)
|
||||
| int(0) %}
|
||||
{% set last_level =
|
||||
item.get('battery_last_reported_level', -1)
|
||||
| default(-1, true)
|
||||
| float(-1) %}
|
||||
{% set battery_type =
|
||||
item.get('battery_type_and_quantity', 'Not recorded')
|
||||
| default('Not recorded', true) %}
|
||||
|
||||
{% if last_level >= 0 %}
|
||||
{% set line =
|
||||
name
|
||||
~ ' - '
|
||||
~ days
|
||||
~ ' days - last '
|
||||
~ (last_level | round(0) | int)
|
||||
~ '% - '
|
||||
~ battery_type %}
|
||||
{% else %}
|
||||
{% set line =
|
||||
name
|
||||
~ ' - '
|
||||
~ days
|
||||
~ ' days - '
|
||||
~ battery_type %}
|
||||
{% endif %}
|
||||
|
||||
{% set summary.not_reporting =
|
||||
summary.not_reporting + [line] %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
Weekly Battery Digest
|
||||
|
||||
{% if summary.low %}
|
||||
Low Battery: {{ summary.low | count }}
|
||||
{% for line in summary.low %}
|
||||
• {{ line }}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
Low Battery: 0
|
||||
{% endif %}
|
||||
|
||||
{% if summary.not_reporting %}
|
||||
Not Reporting (2+ days): {{ summary.not_reporting | count }}
|
||||
{% for line in summary.not_reporting %}
|
||||
• {{ line }}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
Not Reporting (2+ days): 0
|
||||
{% endif %}
|
||||
|
||||
{% if not summary.low and not summary.not_reporting %}
|
||||
|
||||
All monitored Battery Notes devices are OK.
|
||||
{% endif %}
|
||||
Reference in New Issue
Block a user