Howto create battery alert without creating a template for every device


#391

It looks like you’re running an older version. Can you try upgrading to see if that fixes the issue. The latest release fixed some issues with the logic for alerts. You’ll need to clear your retained mqtt topics again when you upgrade due to changes with the matter payloads.


#392

It turned out that I needed to upgrade and now running Home Assistant 0.76.2 but that did not fix my issue. those sensors are still showing as battery, and I did delete the mqtt db file as well:


#393

I get the impression @NotoriousBDG was talking about you installing the latest version of his code, but you’re talking about the latest version of HA. Did you download and install the latest version of @NotoriousBDG’s code?


#394

Yes, I am using the latest version from git.


#395

@NotoriousBDG

Is it possible to make a sensor that checks the packages version number in GitHub?

Your package works just fine in my installation. Changes to the code happens, so having a sensor checking the latest version number, once a month, would be helpful following the version changes/upgrade.


#396

Sorry, I think I misread your post. I found what’s causing the issue. I’ll work on a fix.

I believe that’s doable. I’ll add that feature to the backlog.


#397

I just pushed an update to GitHub that should fix your issue. Try upgrading and let me know if you still have issues.


#398

I have the same sensor and I just used HA’s frontend to change the entity_id and friendly name to something without battery in there. Solved it right away.


#399

The update solve the problem. Thanks a million @NotoriousBDG

your work is really appreciated.

By the way, is there a way to edit your first post and have the GIT version there or even pin the post somehow? I have to read a super long topic to reach to the git version while trying so many code edits earlier.


#400

I just thought of something else, is it possible to do a similar package to create sensors for power meters? I am not sure if this has been done somewhere else, but I am thinking to group all power meter from my system and eventually have some statistics and reports on power consumption around the house.

I know it is easy if you have few of those, but when the number goes up it becomes complicated and dynamic is the way.


#401

not to hijack but since you mention:
Recently finished just that :slight_smile:
python_script below and accompanying automation found in link in the script:

##########################################################################################
# map_sensors_actueel.py
# reading all sensors.*_actueel using power (>0), listing and counting them,
# sorted alphabetically, and calculate summed power consumption
# colorcoded by power usage
# by @Mariusthvdb  and big hand Phil, @pnbruckner
# https://community.home-assistant.io/t/template-to-add-values-of-all-sensors-with-certain-name-ending/64488
# august 21 2018
##########################################################################################

sensor_list = []
total_power = 0
count = 0
for entity_id in hass.states.entity_ids('sensor'):
    if entity_id.endswith('_actueel') and not 'sensors' in entity_id:
        state = hass.states.get(entity_id)
        try:
            power = float(state.state)
        except:
            continue
        if power > 0:
            total_power = round(total_power + power,2)
            count = count + 1

            colorCode = '%' if power < 20 else \
                        '=' if power < 100 else \
                        '+' if power < 200 else \
                        '#' if power < 500 else \
                        '$' if power < 1000 else \
                        '@' if power < 1500 else \
                        '^' if power < 2000 else \
                        '!' if power < 2250 else \
                        '&' if power < 2500 else \
                        ''
            colorCodeTotal = '%' if total_power < 200 else \
                             '=' if total_power < 500 else \
                             '+' if total_power < 1000 else \
                             '#' if total_power < 1500 else \
                             '$' if total_power < 2000 else \
                             '@' if total_power < 3000 else \
                             '^' if total_power < 4000 else \
                             '!' if total_power < 5000 else \
                             '&' if total_power < 6000 else \
                             '*'

            sensor = colorCode +'{:22}:'.format(state.name[:-8]) + \
                                '{:>7}\n'.format(state.state)
            sensor_list.append(sensor)

summary = '\n'.join([
          '*=== Sensor ===== Power =======',
          *sorted(sensor_list,key=lambda x: x[1:]),
          '*========== Summary ==========',
          '/Total Sensors consuming power: {}',
          colorCodeTotal +'Total consumed Power: {}',
          '*' +'='*28
          ]).format(count,
                    total_power,
                    total_power)

hass.states.set('sensor.map_sensors_actueel', '', {
        'custom_ui_state_card': 'state-card-value_only',
        'text': summary
        })

hass.states.set('sensor.total_sensors',total_power, {
        'unit_of_measurement': 'Watt',
        'friendly_name': '{} sensors'.format(count),
        'count': count
        })

##########################################################################################
# map_total_sensors.py
##########################################################################################
##########################################################################################
# Codes for text_colors declared in 
# Custom card: /custom_ui/state-card-value_only.html
##########################################################################################
#      case "*": return "bold";
#      case "/": return "italic";
#      case "!": return "red";
#      case "+": return "green";
#      case "=": return "yellow";
#      case "%": return "grey";
#      case "$": return "brown";
#      case "#": return "blue";
#      case "@": return "darkbrown";
#      case "^": return "deepbrown";
#      case "&": return "purple";

#      default:  return "normal";
##########################################################################################

##########################################################################################
# lessons learned:
##########################################################################################
#Try. The else doesn’t go with the if, it goes with the try. Notice that it is at the same
#indentation level as try and except. In a try statement, if an exception occurs
#the except clause is executed.
#But if no exception occurs, then the else clause is executed (if there is one.)
#So, in this case, if the conversion to int works, then the else clause it executed,
#which increments the count.

#*iterable means expand the iterable. So *['a','b','c'] is 'a', 'b', 'c'. Used here to 
#expand sensor_list into individual items that then become part of the bigger list.

#sorted. You can give the function sorted a key function that can change what it sorts. 
#So you could change *sorted(sensor_list) to *sorted(sensor_list, key=lambda x: x[1:]). 
#Instead of sorting by the whole strings, it will sort using the strings minus their 
#first characters.
##########################################################################################
# Older snippets
##########################################################################################
#        logger.info('entity_id = {}, state = {}'.format(entity_id, state.state))
#        sensor_id = '{}'.format(entity_id[7:-8].replace('_',' ').title())
#        sensor_power = '\t{}'.format(state.state)
#        sensor = '#{} :'.format(sensor_id) + ' {}\n'.format(sensor_power)


#            sensor_list.append(sensor)
##            sensor_list.append('%{:21}:{:>7.2f}'.format(
#                state.name.replace('actueel','').replace('_',' '),
#                power))

#            sensor_list.append(colorCode +'{:21}: {:>7.2f}'.format(
#               state.name.replace('actueel','').replace('_',' '),
#                power))

#sensor_map = '\n'.join(sensor_list)

#summary = '*{:=^30}\n' \
#          '$----------  Sensor : Power  ----------\n' \
#          '{}\n' \
#          '*=============== Sumary ==============\n' \
#          ' Sensors consuming power: {}\n' \
#          ' Total consumed Power :  {}\n' \
#          '*====================================\n' \
#          .format(' Sensors ',
#                  sensor_map,
#                  count,
#                  total_power)

# complete version @pnbruckner
#sensor_list = []
#total_power = 0
#count = 0
#for entity_id in hass.states.entity_ids('sensor'):
#    if entity_id.endswith('_actueel') and 'sensors' not in entity_id:
#        state = hass.states.get(entity_id)
#        try:
#            power = round(float(state.state), 2)
#        except:
#            continue
#        if power > 0:
#            total_power = total_power + power
#            count = count + 1
#            sensor_list.append('#{:21}: {:>7.2f}'.format(
#                state.object_id.replace('_actueel','').replace('_',' ').title(),
#                power))

#summary = '\n'.join([
#    '*{:=^30}'.format(' Sensors '),
#    '${:-^20} : {:-^7}'.format(' Sensor ', 'Power '),
#    *sensor_list,
#    '*{:=^30}'.format(' Summary '),
#    '$ Total: # {:<4} Power : {:>7.2f}'.format(count, total_power),
#    '*' + '='*30])
#
#hass.states.set('sensor.map_total_sensors', '', {
#    'custom_ui_state_card': 'state-card-value_only',
#    'text': summary})
##########################################################################################
# map_sensors_actueel.py
##########################################################################################

#402

Unfortunately, the OP isn’t editable anymore. I would update it if I could.

I tried that a while back, but the database design for Home Assistant doesn’t scale well. I can’t keep more than a day or 2 of data before having performance issues. I found it’s much easier to use InfluxDB and Grafana to visualize and consume power data.


#403

This is great, but where do you put this? do you create a new map_sensors_actueel.py in the packages folder because that is what I did and nothing was created.

too bad as I was trying to avoid adding more packages to the raspberry to keep the load low, but I guess I will try that and see how it shows.
Thanks for all the hard work.


#404

sorry, misread.
No you put the python_script in the folder /config/python_scripts (enable python by adding python_script: in your configuration.yaml), and the automation in your automations folder.

you do need the adapted state-card-value_only.html file too. Id be glad to share it, but as said don’t want to hijack @NotoriousBDG 's thread. Ive updated the file in the thread in the link I posted with setup instructions.

btw its reading the states of my power sensors, which end with _actueel, as you might have read :wink:
you need to adapt that to your needs and setup of course


#405

Thanks, I will head there and ready the full post to understand because from what I can see it searching for actueel which I do not use.


#406

I had mqtt connection issue when discovery is added, got resolved by copying and pasting from doc.
Many thanks to NotoriousBDG. :clap::clap:


#407

Hey there! Thanks a million for you time and good work
I would like to try it out. Actually, I do not need to create the battery sensors and I do not want to use mqtt. I need just notifications, when the buttery level is lower than “n%”. That is why I can not use your latest code and, as I understand, code from 5th of january isn’t gonna work on latest HA.
So, I would like to get stable one, but not the latest. How should I cut the code?
By the way, I am on Hass.io
Have a nice day!


#408

You can still use it for notifications. To prevent using MQTT, disable automation.battery_sensor_from_attributes and it won’t create any sensors, but you’ll still get notifications.


#409

Thank you, I tried it out. Unfortunately, I got only phones battery levels:

And here are some examples of my sensors:

What am I doing wrong?


#410

And here is changed file

################################################################
## Packages / Battery Alert
################################################################

################################################################
## Changelog
################################################################
##
## 1.0.0 (2018-02-14)
##   Added
##   - Added version number to enable better tracking
##
## 1.0.1 (2018-02-15)
##   Added
##   - Added battery_sensor_creation_disabled attibute to skip
##     creating a battery sensor even when an battery attribute
##     exists.
##
## 1.0.2 (2018-04-06)
##   Added
##   - Added battery icon to sensors.
##
## 1.0.3 (2018-05-10)
##   Changed
##   - Change device_class to battery and remove icon, which
##     allows dynamic icons in 0.69.
##
## 1.0.4 (2018-05-11)
##   Changed
##   - Fixed condition battery_sensor_creation_disabled condition
##   Added
##   - Documented a jinja template that can be use to assist
##     with creating a group containing all battery sensors.
##
## 1.0.5 (2018-05-14)
##   Changed
##   - Changed formatting of notifications to improve readability
##   - Nofity via Slack immediately when thresholds are modified
##   Added
##   - Entities with device_class of battery no longer need
##     battery in their friendly name to be monitored
##   - Don't create a battery sensor from an entity if
##     device_class is battery
##
## 1.0.6 (2018-05-14)
##   Changed
##   - Added object_id to notifications
##   - Updated Battery Status group jinja code to check for
##     battery device_class
##
## 1.0.7 (2018-05-16)
##   Added
##   - Added unique_id to disambiguate sensors with duplicate
##     names
##   - Added source info to mqtt config topic
##   - Consider friendly names and entity_ids that end with _bat
##     as a battery sensor (needed for rflink battery sensors)
##   - Consider entities with icon of battery, battery-alert, or
##     battery-unknown as a battery sensor regardles of its name
##   - Consider entity_ids containing battery as a battery sensor
##   Changed
##   - Reduce code duplication using yaml anchors and references
##   - Changed MQTT topic to be based on entity_id
##   - Improve method of filtering non-battery devices that have
##     battery in their name. Detection is now based on icon
##     rather than keywords.
##
## 1.0.8 (2018-06-01)
##   Added
##   - Add support for defining battery_template attibute to
##     allow manipulation of value of battery sensor
##   - Support battery attributes that contain strings
##   Removed
##   - Cleaned up notifications by removing object id
##
## 1.0.9 (2018-06-08)
##   Added
##   - Automatically create Battery Status group containing all
##     discovered batteries
##   Removed
##   - Removed sample jinja to create battery status group yaml
##
## 1.0.10 (2018-06-08)
##   Added
##   - Moved group.update_battery_status_group_members to Battery
##     Alert group
##
## 1.1.0 (2018-08-09)
##   Added
##   - Added Batteries view
##   - Added Telegram notification automation
##   - Added Pushover notification automation
##   - Added attributes to battery entities created via mqtt:
##     entity_id, attribute, mqtt_config_topic, and mqtt_state_topic
##   Changed
##   - Simplified trigger for update_battery_status_group_members
##     automation
##   - Refactored conditions on automations to rely on
##     group.battery_status members
##   Breaking Changes
##   - The attribute additions requires restarting Home Assistant
##     after the first state change or clearing retained MQTT topics
##
## 1.1.1 (2018-08-11)
##   Added
##   - Added input text box named `MQTT Topic to Clear`, which can be used
##     to clear MQTT topics with retained messages
##   - Set initial_state to on for all automations to ensure they are enabled
##     on startup
##   Changed
##   - Consider entities with battery in their entity_id or friendly_name a
##     battery sensor if neither an icon nor a device class is defined
##   - Consolidated the battery_sensor_from_* automations into a single
##     automation
##
## 1.1.2 (2018-08-23)
##   Fixed
##   - Fixed issue where non-battery sensors with Battery in their name are
##     added to group.battery_status
##
################################################################

################################################################
## Install Instructions
################################################################
##
##  1. Enable MQTT using your preferred MQTT broker
##     https://home-assistant.io/components/mqtt/
##
##  2. Enable MQTT Discovery by adding `discovery: true` and
##     `discovery_prefix: homeassistant` under the `mqtt:` section
##     of your configuration.yaml
##
##     mqtt:
##       discovery: true
##       discovery_prefix: homeassistant
##
##  3. Save this file as CONFIGDIR/packages/battery_alert.yaml
##
##  4. Add `packages: !include_dir_named packages` under the
##     `homeassistant:` section of your configuration.yaml
##
##     homeassistant:
##       packages: !include_dir_named packages
##
##  5. Restart Home Assistant
##
##  6. Adjust Min Alert Threshold slider to the minimum battery
##     level to alert on.  Note: the input slider requires the
##     recorder component to keep it's state through restarts.
##     If recorder is not enabled, the threshold can be set by
##     un-remarking `initial` and setting the preferred default.
##
##  7. Adjust Max Alert Threshold slider to the maximum battery
##     level to alert on.  Note: the input slider requires the
##     recorder component to keep it's state through restarts.
##     If recorder is not enabled, the threshold can be set by
##     un-remarking `initial` and setting the preferred default.
##
##  8. To disable alerts for a specific entity, use customize to
##     set `battery_alert_disabled` to `true`
##
##     homeassistant:
##       customize:
##         sensor.sensor_name_to_ignore_battery:
##           battery_alert_disabled: true
##
##  9. To disable creating a sensor from battery attributes for a specific entity, use customize to
##     set `battery_sensor_creation_disabled` to `true`
##
##     homeassistant:
##       customize:
##         sensor.sensor_with_battery_attibute:
##           battery_sensor_creation_disabled: true
##
## 10. If a battery attribute requires a template to convert it into a usable percent
##     or string, use customize to add `battery_template` with the necessary template.
##     The template should result in either a percentage or a string ("Low" will
##     trigger low battery notification).
##
##     This example will create a battery sensor with the value of battery_level * 2
##
##     homeassistant:
##       customize:
##         sensor.sensor_with_battery_attibute_template:
##           battery_template: "{{ value_json.value | int * 2 }}"
##
##     This example will create a battery sensor that contains "Low" if battery_level
##     is less than 2
##
##     homeassistant:
##       customize:
##         sensor.sensor_with_battery_attibute_template:
##           battery_template: >-
##             {%- if value < 2 -%}
##             "Low"
##             {%- else -%}
##             "Full"
##             {%- endif -%}
##
################################################################

################################################
## Customize
################################################
homeassistant:
  customize:
    ################################################
    ## Node Anchors
    ################################################
    package.node_anchors:
      customize: &customize
        package: 'battery_alert'

    ################################################
    ## Group
    ################################################
    group.battery_view:
      <<: *customize
      friendly_name: "Batteries"
      icon: mdi:battery-alert

    group.battery_alert:
      <<: *customize
      friendly_name: "Battery Alert"
      icon: mdi:steam
      control: hidden

    group.battery_status:
      <<: *customize
      friendly_name: "Battery Status"
      icon: mdi:battery-charging
      control: hidden

    ################################################
    ## Automation
    ################################################
    automation.battery_notification:
      <<: *customize
      friendly_name: "Battery Notification"
      icon: mdi:comment-alert-outline

    automation.battery_notification_clear:
      <<: *customize
      friendly_name: "Battery Notification Clear"
      icon: mdi:comment-remove-outline

    automation.battery_notification_ios:
      <<: *customize
      friendly_name: "Battery Notification ios"
      icon: mdi:comment-alert-outline


################################################
## Group
################################################
group:
  battery_view:
    view: yes
    entities:
      - group.battery_status
      - group.battery_alert

  battery_alert:
    control: hidden
    entities:
      - input_number.battery_alert_threshold_min
      - input_number.battery_alert_threshold_max
      - automation.battery_notification
      - automation.battery_notification_clear
      - automation.battery_notification_ios
      - automation.update_battery_status_group_members

################################################
## Input Number
################################################
input_number:
  battery_alert_threshold_max:
    name: "Max Alert Threshold"
    icon: mdi:arrow-collapse-up
    mode: slider
    min: -1
    max: 100
    initial: 40

  battery_alert_threshold_min:
    name: "Min Alert Threshold"
    icon: mdi:arrow-collapse-down
    mode: slider
    min: -1
    max: 100
    initial: -1

################################################
## Automation
################################################
automation:
- alias: battery_notification
  initial_state: 'on'
  trigger:
    - platform: time
      minutes: '/15'
      seconds: 00
    - platform: state
      entity_id:
        - input_number.battery_alert_threshold_min
        - input_number.battery_alert_threshold_max
  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)
          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
              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'
          )
        ) -%}
          {{ state_attr(entity_id, "friendly_name") }} ({{ states(entity_id) }})
        {% endfor -%}
        {% endmacro %}
        {{ battery_level() | trim != "" }}
    - service: persistent_notification.create
      data_template:
        title: "Low Battery Levels"
        notification_id: low_battery_alert
        message: &message >
          {% 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)
            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
                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'
            )
          ) -%}
            {{ state_attr(entity_id, "friendly_name") }} ({{ states(entity_id) }})
          {% endfor -%}
          {% endmacro %}
          {{ battery_level() }}

- alias: battery_notification_clear
  initial_state: 'on'
  trigger:
    - platform: time
      minutes: '/15'
      seconds: 00
    - platform: state
      entity_id:
        - input_number.battery_alert_threshold_min
        - input_number.battery_alert_threshold_max
  action:
    - condition: template
      value_template: &low_battery_clear >
        {% 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)
          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
              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'
          )
        ) -%}
          {{ state_attr(entity_id, "friendly_name") }} ({{ states(entity_id) }})
        {% endfor -%}
        {% endmacro %}
        {{ battery_level() | trim == "" }}
    - service: persistent_notification.dismiss
      data:
        notification_id: low_battery_alert

- alias: battery_notification_ios
  initial_state: 'on'
  trigger:
    - platform: time
      at: '10:00:00'
    - platform: time
      at: '18:00:00'
    - platform: state
      entity_id:
        - input_number.battery_alert_threshold_min
        - input_number.battery_alert_threshold_max
  action:
    - condition: template
      value_template: *low_battery_check
    - service: notify.ios_argo
      data_template:
        message: "Low Battery Levels"
        data:
          attachments:
          - color: '#52c0f2'
            title: "These devices have low battery levels"
            text: *message

- alias: update_battery_status_group_members
  initial_state: 'on'
  trigger:
    - platform: homeassistant
      event: start
    - platform: time
      minutes: '/5'
      seconds: 00
  action:
    - service: group.set
      data_template:
        object_id: "battery_status"
        entities: >-
          {%- for item in states.sensor if (
            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)
              )
            )
          -%}
            {{ item.entity_id }}{% if not loop.last %}, {% endif %}
          {%- endfor -%}