Howto create battery alert without creating a template for every device

how can i make a template

This the template that I had to build for my Kohler generator. The one you will be interested in is the battery voltage. Since the battery was showing as a percentage I had to make a multiplication to bring the normal 13.4 volts to 100%

---

# loaded by !include_dir_list this will return the content of a directory as a list with each file content being an entry in the list. 
# The list entries are ordered based on the alphanumeric ordering of the names of the files.
# https://www.home-assistant.io/integrations/sensor/
# https://www.home-assistant.io/docs/configuration/splitting_configuration/#debugging-multiple-configuration-files
# https://www.home-assistant.io/integrations/template/
#
platform: template
sensors:

  gen_lube_oil_temp:
    friendly_name: "Gen_lube_oil_Temp"
    value_template: "{{ state_attr('sensor.kohler_sensors', 'lube_oil_temperature') }}"
  engine_speed:
    friendly_name: "engine_speed"
    value_template: "{{ state_attr('sensor.kohler_sensors', 'engine_speed') }}"
  battery_voltage:
    friendly_name: "battery_voltage"
    unit_of_measurement: 'Volts'
    value_template: "{{ state_attr('sensor.kohler_sensors', 'battery_voltage') | multiply(7.463) | float(2) }}"

You could open up the code and modify it for your needs!
I’ve modified my version of battery_alert.yaml so that my front door lock alerts if it’s value is < the custom attribute I created in it that I named battery_alert_threshold and is set to 75 rather than the default 25 (percent) I set with the package for everything else.
My lines 272-275; I added line 274 and the surrounding ():

              and (
              states(entity_id) | int < states.input_number.battery_alert_threshold_max.state | int
              or states(entity_id) | int < state_attr(entity_id, 'battery_alert_threshold') | int )
              and states(entity_id) | int > states.input_number.battery_alert_threshold_min.state | int

From deciphering the battery_alert.yaml package, it looks like it should work for entities which have the state ‘low’. See or states(entity_id) | lower == 'low' in the code below…

  action:
    - condition: template
      value_template: &low_battery_check >
        {% macro battery_level() %}
        {% for entity_id in states.group.battery_status.attributes.entity_id if (
            not (
                  is_state_attr(entity_id, 'battery_alert_disabled', true)
                  or is_state_attr(entity_id, 'restored', true)
                )
          and states(entity_id) is not none
          and (
            (
              (
                states(entity_id) is number
                or states(entity_id) | length == states(entity_id)| int | string | length
                or states(entity_id) | length == states(entity_id)| float | string | length
              )
              and (
              states(entity_id) | int < states.input_number.battery_alert_threshold_max.state | int
              or states(entity_id) | int < state_attr(entity_id, 'battery_alert_threshold') | int )
              and states(entity_id) | int > states.input_number.battery_alert_threshold_min.state | int
            )
            or states(entity_id) | lower == 'low'
            or states(entity_id) | lower == 'unknown'
            or states(entity_id) | lower == 'unavailable'
          )
        ) -%}
          {{ state_attr(entity_id, "friendly_name") }} ({{ states(entity_id) }})
        {% endfor -%}
        {% endmacro %}
        {{ battery_level() | trim != "" }}

Otherwise, create a templated entity…

Templates are defined as either sensor:, or binary_sensor: for true/false types.
Start coding in Dev Tools, Template to develop your template. If you get stumped, post your code attempt and others will help as others have helped me. Here’s some templates I’ve developed in the last 6 months. Nothing battery related as all mine are normal!

# Templates  
  - platform: template
    sensors:
    
#   Sun
      next_midnight:
        friendly_name: 'Next Midnight'
        value_template: >
          {{ as_timestamp(states.sun.sun.attributes.next_dusk) | timestamp_custom('%H:%M')}}
        icon_template: mdi:weather-sunset-up
        
      next_dawn:
        friendly_name: 'Next Dawn'
        value_template: >
          {{ as_timestamp(states.sun.sun.attributes.next_dawn) | timestamp_custom('%H:%M')}}
        icon_template: mdi:weather-sunset-up
      
      next_sunrise:
        friendly_name: 'Next Sunrise'
        value_template: >
          {{ as_timestamp(states.sun.sun.attributes.next_rising) | timestamp_custom('%H:%M') }}
        icon_template: mdi:weather-sunset-up

      next_noon:
        friendly_name: 'Next Noon'
        value_template: >
          {{ as_timestamp(states.sun.sun.attributes.next_dusk) | timestamp_custom('%H:%M')}}
        icon_template: mdi:weather-sunset-up
        
      next_sunset:
        friendly_name: 'Next Sunset'
        value_template: >
          {{ as_timestamp(states.sun.sun.attributes.next_setting) | timestamp_custom('%H:%M') }}
        icon_template: mdi:weather-sunset-down  

      next_dusk:
        friendly_name: 'Next Dusk'
        value_template: >
          {{ as_timestamp(states.sun.sun.attributes.next_dusk) | timestamp_custom('%H:%M')}}
        icon_template: mdi:weather-sunset-up
        
      sun_elevation:
        friendly_name: "Sun Elevation"
        value_template: "{{ state_attr('sun.sun', 'elevation') }}"

      sun_azimuth:
        friendly_name: "Sun Azimuth"
        value_template: "{{ state_attr('sun.sun', 'azimuth') }}"
        
      period_of_day:
        friendly_name: 'Period of day'
        value_template: >-
          {% if (as_timestamp(states.sun.sun.attributes.next_dusk)) - (as_timestamp(states.sun.sun.attributes.next_setting)) < 0 %}
            Dusk
          {% elif (as_timestamp(states.sun.sun.attributes.next_rising)) - (as_timestamp(states.sun.sun.attributes.next_dawn)) < 0 %}
            Dawn
          {% elif (states.sun.sun.attributes.elevation) < 0 %}
            Night
          {% else %}
            Day
          {% endif %}
        icon_template: >-
          {% if is_state('sun.sun', 'above_horizon') %}
            mdi:weather-sunny
          {%elif (as_timestamp(states.sun.sun.attributes.next_dusk)) - (as_timestamp(states.sun.sun.attributes.next_setting)) < 0 %}
            mdi:weather-sunset-down
          {% elif (as_timestamp(states.sun.sun.attributes.next_rising)) - (as_timestamp(states.sun.sun.attributes.next_dawn)) < 0 %}
            mdi:weather-sunset-up
          {% else %}
            mdi:weather-night
          {% endif %}

#   Weather
      norton_court_temperature:
        friendly_name: Norton Court Temperature
        value_template: >
          {{ state_attr('weather.norton_court','temperature') }}
         
      dest_address:
        value_template: >-
          {{ states('input_select.destination') }}
#   Climate            
      nest_time_to_temp:
        friendly_name: Living Room Time to Temp
        icon_template: mdi:camera-timer
        value_template: >
            {{ ((state_attr('climate.living_room','temperature')|float - states('sensor.living_room_temperature')|float) * state_attr('sensor.nest_time_to_temp','rate_of_change')|float/60)|abs|int }}
        attribute_templates:
          message: |
            {% if states('sensor.nest_time_to_temp')|float < 10 %}
             IN LESS THAN 10 MIN
            {% elif states('sensor.nest_time_to_temp')|float < 16 %}
             IN 15 MIN
            {% elif states('sensor.nest_time_to_temp')|float < 21 %}
             IN 20 MIN
            {% elif states('sensor.nest_time_to_temp')|float < 26 %}
             IN 25 MIN
            {% elif states('sensor.nest_time_to_temp')|float < 31 %}
             IN 30 MIN
            {% elif states('sensor.nest_time_to_temp')|float < 36 %}
             IN 35 MIN
            {% elif states('sensor.nest_time_to_temp')|float < 41 %}
             IN 40 MIN
            {% elif states('sensor.nest_time_to_temp')|float < 46 %}
             IN 45 MIN
            {% elif states('sensor.nest_time_to_temp')|float < 51 %}
             IN 50 MIN
            {% elif states('sensor.nest_time_to_temp')|float < 56 %}
             IN 55 MIN
            {% elif states('sensor.nest_time_to_temp')|float < 61 %}
             IN 1 HR
            {% elif states('sensor.nest_time_to_temp')|float < 66 %}
             IN 1 HR 5 MIN
            {% elif states('sensor.nest_time_to_temp')|float < 71 %}
             IN 1 HR 10 MIN
            {% elif states('sensor.nest_time_to_temp')|float < 76 %}
             IN 1 HR 15 MIN
            {% elif states('sensor.nest_time_to_temp')|float < 81 %}
             IN 1 HR 20 MIN
            {% elif states('sensor.nest_time_to_temp')|float < 86 %}
             IN 1 HR 25 MIN
            {% elif states('sensor.nest_time_to_temp')|float < 191 %}
             IN 1½ HR
            {% else %}
             IN 2+ HR
            {% endif %}
          time_of_current_change_to_heating: >
            {{ states('input_datetime.hvac_current_heat_started') }}
          time_of_last_change_to_heating: >
            {{ states('input_datetime.hvac_heat_started') }}
          time_of_last_change_from_heating: >
            {{ states('input_datetime.hvac_heat_ended') }}
          elapsed_seconds: >
            {{ as_timestamp(states('input_datetime.hvac_heat_ended')) - as_timestamp(states('input_datetime.hvac_heat_started')) }}
          temp_at_last_change_to_heat: >
            {{ states('input_number.hvac_heat_start_temp') }}
          temp_at_last_change_from_heat: >
            {{ states('input_number.hvac_heat_end_temp') }}
          degrees_of_separation: >-
              {{ (states('input_number.hvac_heat_end_temp')|float - states('input_number.hvac_heat_start_temp')|float)|abs|round(1) }}
          rate_of_change: >
            {% if state_attr('sensor.nest_time_to_temp', 'degrees_of_separation')|float > 0 %}
             {{ state_attr('sensor.nest_time_to_temp', 'elapsed_seconds')|float / state_attr('sensor.nest_time_to_temp', 'degrees_of_separation')|float }}
            {% else %}
             0
            {% endif %}
          current_temp: >
            {{ states('sensor.living_room_temperature') }}
          target_temp: >
            {{ state_attr('climate.living_room','temperature') }}
          last_estimated_time_to_temp: >
            {{ ((state_attr('sensor.nest_time_to_temp','temp_at_last_change_from_heat')|float - state_attr('sensor.nest_time_to_temp','temp_at_last_change_to_heat')|float) * state_attr('sensor.nest_time_to_temp','rate_of_change')|float)|abs|timestamp_custom('%H:%M:%S', false) }}
      nest_hvac_mode:
        friendly_name: Living Room HVAC Mode
        value_template: >
          {{ states('climate.living_room') }}
        attribute_templates:
          hvac_off: >
            {% if (states('sensor.living_room_hvac_mode') == 'off') %} ✔ {% else %} {% endif %}
          hvac_heat:  >
            {% if (states('sensor.living_room_hvac_mode') == 'heat') %} ✔ {% else %} {% endif %}
          hvac_cool:  >
            {% if (states('sensor.living_room_hvac_mode') == 'cool') %} ✔ {% else %} {% endif %}
          hvac_auto:  >
            {% if (states('sensor.living_room_hvac_mode') == 'auto') %} ✔ {% else %} {% endif %}
      nest_time_to_temp_message:
        friendly_name: Living Room Time to Temp
        value_template: >
          {% if state_attr('climate.living_room','hvac_action') == 'off' and states('climate.living_room') == 'heat' %}
            HEAT SET TO
          {% elif state_attr('climate.living_room','hvac_action') == 'off' and states('climate.living_room') == 'cool' %}
            COOLING SET TO
          {% else %}
            {{ state_attr('sensor.nest_time_to_temp','message') }}
          {% endif %}
        attribute_templates:
          hvac_action: >
            {{ state_attr('climate.living_room','hvac_action') }}
#   Coffee Machine
      coffee_machine:
        friendly_name: "Coffee Machine"
        unique_id: "kenmore-coffee-machine"
        value_template: >-
          {% if is_state('switch.coffee_maker_switch', 'off') %}
            Off
          {% elif states('sensor.coffee_maker_power_electric')|float > 1.0 %}
            Brewing
          {% elif is_state('input_boolean.coffee_prepared', 'off') %}
            Not Ready
          {% else %}
            Ready
          {% endif %}
  washer_status:
    friendly_name: Washer Status
    value_template: >-
       {%- if is_state('switch.washer_power_switch','off') %}
            Off
       {% elif states ('sensor.washer_power_electric_a')|float > 6.7 %}
            Spin
       {% elif states ('sensor.washer_power_electric_a')|float > 5.75 %}
            Wash
       {% elif states ('sensor.washer_power_electric_a')|float > 5.5 %}
            Drain
       {% elif states ('sensor.washer_power_electric_a')|float > 0 %}
            Fill
       {% else %}
            Idle
       {%- endif %}

Door Locks

  frontdoor_lock_log_date:
    friendly_name: "Frontdoor Lock Log"
    value_template: '{{ states.sensor.front_door_lock_logging.attributes["TimeStamp"] | timestamp_custom("%d/%m/%y %H:%M:%S") }}'
  
  frontdoor_lock_log_message:
    friendly_name: "Frontdoor Lock Log"
    value_template: '{{ states.sensor.front_door_lock_logging.attributes["Value"].split("\t")[1].split(":")[1].strip() }}'

  frontdoor_lock_log_user:
    friendly_name: "Frontdoor Lock Log"
    value_template: '{{ states.sensor.front_door_lock_logging.attributes["Value"].split("\t")[2].split(":")[1].strip() }}'

  frontdoor_lock_log_code:
    friendly_name: "Frontdoor Lock Log"
    value_template: '{{ states.sensor.front_door_lock_logging.attributes["Value"].split("\t")[3].split(":")[1].strip() }}'
1 Like

Yeah sorry, I was able to figure this out in the exact same way yesterday. Got so busy I forgot to check yesterday. Thank you for the assistance!

Anyone still using this package, and on 2021.4.x?

getting the following error:

2021-04-09 13:17:00 WARNING (MainThread) [homeassistant.helpers.template] Template variable warning: 'mappingproxy object' has no attribute 'icon' when rendering '{%- for item in states.sensor if (
  not is_state_attr(item.entity_id, 'hidden', true)
  and (
    is_state_attr(item.entity_id, 'device_class', 'battery')
    or 'battery' in item.attributes.icon | lower
    or (item.entity_id | lower).endswith('_bat')
    or (item.name | lower).endswith('_bat')
    ) or (
      (
        'battery' in item.entity_id | lower
        or 'battery' in item.name | lower
      ) and (
        item.attributes.icon is not defined
      ) and (
        not is_state_attr(item.entity_id, 'battery_alert_disabled', true)
      ) and (
        not is_state_attr(item.entity_id, 'restored', true)
      )
    )
  )
-%}
  {{ item.entity_id }}{% if not loop.last %}, {% endif %}
{%- endfor -%}'

which is in the update_battery_status_group_members automation

I’ve changed to the following which I believe is correct:

          {%- for item in states.sensor if (
            not is_state_attr(item.entity_id, 'hidden', true)
            and (item.attributes.icon is defined) 
            and (
              is_state_attr(item.entity_id, 'device_class', 'battery')
              or 'battery' in item.attributes.icon | lower
              or (item.entity_id | lower).endswith('_bat')
              or (item.name | lower).endswith('_bat')
              ) or (
                (
                  'battery' in item.entity_id | lower
                  or 'battery' in item.name | lower
                ) and (
                  item.attributes.icon is not defined
                ) and (
                  not is_state_attr(item.entity_id, 'battery_alert_disabled', true)
                ) and (
                  not is_state_attr(item.entity_id, 'restored', true)
                )
              )
            )
          -%}
            {{ item.entity_id }}{% if not loop.last %}, {% endif %}
          {%- endfor -%}

Where and (item.attributes.icon is defined) is the addition

3 Likes

Seems there are other issues:

2021-04-09 14:49:12 WARNING (MainThread) [homeassistant.components.mqtt.mixins] Erroneous JSON:
2021-04-09 14:49:12 ERROR (MainThread) [homeassistant.helpers.template] Template variable error: 'value_json' is undefined when rendering '{{ value_json.value | int }}'

which corresponds with the MQTT payload for battery_sensor_from_attributes

stuck now…

Hmm. restarted, and no error - maybe a one off…

Thank you for this

I messed up where to put the check - see template warnings under 2021.4.x · Issue #32 · notoriousbdg/Home-AssistantConfig · GitHub

(and haven’t seen any further “Erroneous JSON” errors)

Hello,

I am having problems with my 2 climate devices. Even if they share battery status with a separate entity, as in the snapshot, those are not added intu battery_status group…

bs1

All other devices are discovered correctly.

Following Mqtt topic is shared:

`{
   "availability":[
      {"topic":"zigbee2mqtt/bridge/state"}
   ],
   "device":
      {
         "identifiers":
            [
               "zigbee2mqtt_0x847127fffe111655"
            ],
         "manufacturer":"TuYa",
         "model":"Radiator valve with thermostat (TS0601_thermostat)",
         "name":"Salon grzejnik","sw_version":"Zigbee2MQTT 1.18.2"
      },
   "device_class":"battery",
   "json_attributes_topic":"zigbee2mqtt/Salon grzejnik",
   "name":"Salon grzejnik battery low",
   "payload_off":false,
   "payload_on":true,
   "state_topic":"zigbee2mqtt/Salon grzejnik",
   "unique_id":"0x847127fffe111655_battery_low_zigbee2mqtt",
   "value_template":"{{ value_json.battery_low }}"
}`

Grateful for any hints…

Regards,
Maciek

Hi @NotoriousBDG,
Is there any plan making it a custom component available on HACS? That would be great as it would help the community get the latest updates.
:slight_smile:

1 Like

NotoriousBDG:

Joined: Jan 27, '17
Last Post: Jun 17, '19
Last Seen: Sep 21, '19

Damn… thank you @walaj
Does it mean there are little chances this package will evolve anymore? Too bad, the idea was quite interesting. Unless there are newer components doing the same.

there are various other options now - HA has some inbuilt support for battery status, plus there is GitHub - maxwroc/battery-state-card: Battery state card for Home Assistant

True but those other options do not provide automated alerts. We are on our own until someone spearheads this package of HA customizations, groups, inputs, and automations.

1 Like

Battery Alert does not access MQTT for battery devices. It only looks at HA devices where device_class is battery. It uses MQTT and HA discovery to create battery sensors for devices that have a battery attribute rather than a dedicated battery device (device_class: battery). The attribute has to be named battery_level, battery, 'Battery numeric' or battery_critical. It will then publish to MQTT and then the HA Discovery of MQTT devices creates the new device_class: battery battery sensor.
The group is updated by this code:

  action:
    - service: group.set
      data_template:
        object_id: "battery_status"
        entities: >-
              {%- for item in states.sensor if (
                not is_state_attr(item.entity_id, 'hidden', true)
                and (
                  is_state_attr(item.entity_id, 'device_class', 'battery')
                  or (item.attributes.icon is defined and 'battery' in item.attributes.icon | lower)
                  or (item.entity_id | lower).endswith('_bat')
                  or (item.name | lower).endswith('_bat')
                  ) or (
                    (
                      'battery' in item.entity_id | lower
                      or 'battery' in item.name | lower
                    ) and (
                      item.attributes.icon is not defined
                    ) and (
                      not is_state_attr(item.entity_id, 'battery_alert_disabled', true)
                    ) and (
                      not is_state_attr(item.entity_id, 'restored', true)
                    )
                  )
                )
              -%}
                {{ item.entity_id }}{% if not loop.last %}, {% endif %}
              {%- endfor -%}

Paste this into Dev Tools Template and see what the result is and play with the template to get what you need:

              {%- for item in states.sensor if (
                not is_state_attr(item.entity_id, 'hidden', true)
                and (
                  is_state_attr(item.entity_id, 'device_class', 'battery')
                  or (item.attributes.icon is defined and 'battery' in item.attributes.icon | lower)
                  or (item.entity_id | lower).endswith('_bat')
                  or (item.name | lower).endswith('_bat')
                  ) or (
                    (
                      'battery' in item.entity_id | lower
                      or 'battery' in item.name | lower
                    ) and (
                      item.attributes.icon is not defined
                    ) and (
                      not is_state_attr(item.entity_id, 'battery_alert_disabled', true)
                    ) and (
                      not is_state_attr(item.entity_id, 'restored', true)
                    )
                  )
                )
              -%}
                {{ item.entity_id }}{% if not loop.last %}, {% endif %}
              {%- endfor -%}

true - the notification part isn’t in the Battery state card or the inbuild view.,

Is this still the best script to monitor Battery levels in your sensors or are there alternatives I should use instead?

if you want (flexible) notifications, then this might be the best.

If you don’t need the notifications, then Battery State card may be enough.