Script to track all devices with a battery_level

Thank you for the custom component. I use the vera hub for my z-wave devices but had the same problem.
I modified version of the code a bit so that the battery values were all set as sensors and not as whatever the parent component was. What I found was that if my sensor was a binary_sensor the value not display properly.

I changed the line from:

hass.states.set('%s_battery' % entity_id,

To:

hass.states.set('sensor.%s_battery' % new_state.object_id,

I was then also able to use the same custom_component template and modify it to extract the power usage from my vera switches.

Edit:
I forgot to add that when geting the values from the vera component they already had a ‘%’ on the value. I removed theis by adding a ‘[:-1]’ to the line getting the attributes. This removes the last character of the string.

float(new_state.attributes['battery_level'][:-1]),
1 Like

Thanks! I was trying to figure out how to do this myself because it interfered with a script I was trying to loop through with binary sensors.

So, when I first started creating individual template sensors for each of my devices battery states, I was told that my sensors would be polling the battery constantly for changes to the battery state, which was causing more unnecessary drain on each devices battery as it was constantly asking the device for its battery state live, for every percent change. So I was told to add the additional entity_id: reference as the last line of my sensor blocks so that it would only check for the battery level when the state changed on the device listed in entity_id:, and thus causing no extra drain on the battery as it was only reporting back when a state changed on my conditional device instead of consistently polling for changes.

Since I don’t need to know the battery levels for every percent it drops, I created an input_boolean called input_boolean.update_batteries and I have an automation that turns the input_boolean on if its off, and off if its on, every day at 6pm, and since each of my battery sensors are only updating on a state change of the input_boolean.update_batteries, it only polls my battery levels once a day.

So I haven’t tested it with your component, but for those that don’t want this component to start draining their batteries faster, you may want to try adding the extra entity_id: option into this component to see if you can save yourself from buying new batteries before you need to.

Of course, I don’t know how if you can simply add that line underneath the line that says ‘icon’: ‘mdi:battery’ and have it work, since the extra entity_id option may only be a feature of a template sensor, but you can try and report back to let us know if it works.

If not, I personally won’t be using this component unless there is a way to limit when it is polling my batteries.

Here is an example of one of my battery sensors so you can see what I mean:

sensor:
  - platform: template
    sensors:
      batt_master_bedroom_window:
          value_template: '{{ states.sensor.ecolink_doorwindow_sensor_sourcenodeid_24.attributes.battery_level }}'
          friendly_name: 'Master Bedroom Window Battery'
          unit_of_measurement: '%'
          entity_id: input_boolean.update_batteries
1 Like

This may have something to do with whether you are using usb zwave direct connection or via a hub such as Vera.

I am using my zwave devices via a VeraLite hub and have not noticed any difference to the battery life, yet…
This would make sense in my case, as far as I know querying the Vera http API does not force polling of devices.

I am no zwave expert but from my experience using the VeraLite hub with my devices I cannot wake up a battery device by polling it. My devices will only send/receive information when woken by the appropriate physical input such as internal timer, motion or door opening. I can change the device parameters to make it stay awake and send information, this does have a significant impact on battery life. But to do this i need to set the new parameters in the hub and then manually wake the device up to update the device parameters.
But as I said, I am no zwave expert and only have my setup to go by.

1 Like

This is interesting. I am actually looking for some way to create a notification once a battery of any device drops below a certain threshold the. Otification then should just contain the name of the device.

Anyone has done this?

I like this as I wanted to see the battery levels of my door sensors and you did warn that it would create multiple sensors. However, for some reason I cannot hide the extra sensors. I created lines for each of them in my customize.yaml but they still appear. I’m not getting any errors or anything in the log either.

sensor.backd_access_control_7_9_battery:
  hidden: true
sensor.backd_alarm_level_7_1_battery:
  hidden: true
sensor.backd_alarm_type_7_0_battery:
  hidden: true
sensor.backd_appliance_7_15_battery:
  hidden: true
sensor.backd_burglar_7_10_battery:
  hidden: true
sensor.backd_emergency_7_13_battery:
  hidden: true
sensor.backd_homehealth_7_16_battery:
  hidden: true
sensor.backd_sourcenodeid_7_2_battery:
  hidden: true
sensor.backd_system_7_12_battery:
  hidden: true
sensor.frontd_access_control_5_9_battery:
  hidden: true
sensor.frontd_alarm_level_5_1_battery:
  hidden: true
sensor.frontd_alarm_type_5_0_battery:
  hidden: true
sensor.frontd_burglar_5_10_battery:
  hidden: true
sensor.frontd_clock_5_14_battery:
  hidden: true
sensor.frontd_sourcenodeid_5_2_battery:
  hidden: true
sensor.garaged_alarm_level_6_1_battery:
  hidden: true
sensor.garaged_alarm_type_6_0_battery:
  hidden: true
sensor.garaged_burglar_6_10_battery:
  hidden: true
sensor.garaged_sourcenodeid_6_2_battery:
  hidden: true

Sorry, I haven’t really been around lately to reply to everyone. I pasted a new version of this script below. I changed it to work like a normal component with a config, and included the advice of some of the replies to this thread.

Personally, I have been using a whitelist of sensors I want to get battery information from. Here’s my example config, with the script saved as custom_components/battery_state.py:

# Custom components
battery_state:
  include:
    - sensor.garage_door_burglar_3
    - sensor.office_multisensor_temperature_5
    - sensor.frontroom_multisensor_temperature_4

@Corey_Johnson Using something like this should be easier than maintaining a list of things to hide.

"""
See https://community.home-assistant.io/t/script-to-track-all-devices-with-a-battery-level/2596
for more details.

- justyns
"""
import logging
import voluptuous as vol

from homeassistant.helpers.event import track_state_change
from homeassistant.const import MATCH_ALL
from homeassistant.components.sensor import PLATFORM_SCHEMA
import homeassistant.helpers.config_validation as cv

_LOGGER = logging.getLogger(__name__)

DOMAIN = 'battery_state'
DEPENDENCIES = []
CONFIG_SCHEMA = vol.Schema({
    DOMAIN: vol.Schema({
        vol.Optional('include'): cv.ensure_list,
        vol.Optional('exclude'): cv.ensure_list,
        vol.Optional('attributes'): cv.ensure_list,
    }),
}, extra=vol.ALLOW_EXTRA)

def setup(hass, config):
    """Setup the Battery component. """
    excluded_items = config[DOMAIN].get('exclude', [])
    included_items = config[DOMAIN].get('include', MATCH_ALL)
    attribute_items = config[DOMAIN].get('attributes', ['battery_level', 'battery'])

    def state_changed(entity_id, old_state, new_state):
        if new_state is None \
            or entity_id in excluded_items \
            or (included_items != MATCH_ALL and entity_id not in included_items):
            return
        for attr in attribute_items:
            if attr in new_state.attributes:
                try:
                    new_value = str(new_state.attributes[attr]).replace('%', '')
                    hass.states.set('sensor.%s_battery' % new_state.object_id,
                                    float(new_value),
                                    {
                                        'friendly_name': "%s Battery" % new_state.attributes['friendly_name'],
                                        'unit_of_measurement': '%',
                                        'icon': 'mdi:battery'
                                    })
                except Exception as e:
                    _LOGGER.error("Error setting battery sensor value: %r", e)

    # Watch for changes to the devices we're interested in
    track_state_change(hass, included_items, state_changed)
    _LOGGER.info("The 'battery' component is ready!"
                 "Include list: %r. Exclude list: %r.  Attribute list: %r",
                 included_items, excluded_items, attribute_items)

    return True

7 Likes

Definitely more manageable! Thank you!

@justyns

This custom component wouldn’t take much to turn into a generic ‘attributes sensor’ that could be submitted as a PR.

I envisage the yaml config would look something like the following.


sensor:
    - platform: attributes
      attribute: 'battery_level'
      name: 'battery'
      include:
        - sensor.garage_door_burglar_3
        - sensor.office_multisensor_temperature_5
        - sensor.frontroom_multisensor_temperature_4

    - platform: attributes
      attribute: 'current_mwh'
      name: 'Power'
      include:
        - switch.fake1
        - switch.fake2

    - platform: attributes
      attribute: 'volume_level'
      name: 'Volume'
      exclude:
        - media_player.fake1
        - media_player.fake2

Most of the component is already written, it just needs to:

  • move it to the sensor platform,
  • add the custom attribute,
  • add the custom name.

For me, this would tidy up a few template sensors and custom components into one neat component.

I might have a look at doing this in the new year if I get time. If someone else wants to tackle it then I am willing to help test.

2 Likes

@tinglis1 thanks for the idea! I was thinking a ‘battery attribute sensor’ would be a weird/too specific of a component to be included, but I really like your idea of making a generic attribute sensor.

I’ll have some time next week that I could work on this idea and get something submitted.

@justyns Does the battery_state code:

battery_state:
  include:
    - sensor.garage_door_burglar_3
    - sensor.office_multisensor_temperature_5
    - sensor.frontroom_multisensor_temperature_4

Go in the configuration.yaml file like that? I tried it in mine just like that (well, with my own sensors obviously) and nothing is showing up. I am not getting any errors but am not seeing anything in HA or even in the entities list.

I added just one:
battery_state:
include:
- sensor.aeotec_zw100_multisensor_6_sourcenodeid_8_2

and now i have an entity:
sensor.aeotec_zw100_multisensor_6_sourcenodeid_8_2_battery

After working with this for a bit, it seems the original script is creating the battery entities for every device except for my Aeotec Door/Window Sensor 6 devices. It lists the battery for even my older First Alert Smoke/CO detectors but not the door/window sensors.

I tried the updated script and when I re-loaded HA, I would initially see the battery devices in the entities list, but by the time HA finished loading fully, they were gone.

@justyns I’m having the same issue with the battery items not showing up if the include is being used or all devices duplicated which aren’t being hidden via customize.

The logs show the settings are being picked up by the component:

Dec 29 13:57:03 homeassistant hass[4275]: 16-12-29 13:57:03 INFO (Thread-3) [custom_components.battery_state] The ‘battery’ component is ready!Include list: [‘sensor.everspring_sm103_doorwindow_sensor_sensor_8_0’, ‘sensor.everspring_sm103_doorwindow_sensor_sensor_9_0’, ‘sensor.fibaro_system_fgms001_motion_sensor_sensor_3_0’]. Exclude list: . Attribute list: [‘battery_level’, ‘battery’]

Which should work since these devices had a _battery item as well once I wasn’t using the include option.

Is it possible to add a group named “group.all_battery_states” and contain a dynamic update of this group within the component, a dynamic group creation in the configuration.yaml seems to be not possible?

Maybe this helps to get it a little bit more dynamic

hmmm… still a lot work manually, i have soon 40 sensor nodes and more i don’t want to add each device manually to a group :-).

Thank you so much for contributing this! You inspired me to finally try out a custom component and it wasn’t difficult at all. Now I just need to learn to actually write the code.

I really like the other comment about turning this into an attribute sensor. Thanks again!

@justyns Did you have a chance to have a go at the general attribute component? I may have some time in the coming weeks to have a look at this.

I can’t seem to change the Friendly Name via the customize component. It seems like the Battery Level component overrides any changes you make. I tried deleting this line in the Battery Level component:

 'friendly_name': "%s Battery" % new_state.attributes['friendly_name'],

This only made the name of the sensors in lowercase instead of capitalized. Anyone have any idea how set a different friendly name?