Automatic Battery Date Tracker Help

So I was trying to keep better track of how long my batteries were lasting in some devices… so I made a bunch of input_datetimes and an automation to update them when the corresponding battery levels are 100.
That all seemed to work fine for my devices that update the battery levels regularly… I didn’t mind if the date was off a few days/week until it dropped to 99.
The issue I didn’t really think of was some of my devices only update when the change is like 10% some possibly 30% (some of my zigbee contact sensors)
The problem comes up that after a reboot it is changing the date again, which with the devices that don’t update battery level often it will start to throw the dates pretty far off…
Anyone have any idea how I could prevent it from updating the input_datetime after the initial time it triggers at 100? I was trying to do this as one automation so adding a condition to the automation would prevent the whole thing from firing… so I was hoping I could somehow manage that with the template. I suppose if not my plan would be to split out the automation to devices that update regularly and those that don’t with a condition to see that last time the input_datetime was changed… I think?? :roll_eyes:
Here is the automation:

- alias: Set Battery Changed Datetimes
  trigger:
    - platform: numeric_state
      entity_id:
        - sensor.front_door_lock_battery_level
        - sensor.side_door_lock_battery_level
        - sensor.garage_door_lock_battery_level
        - sensor.bedroom_contact_sensor_battery
        - sensor.sump_pump_alarm_battery_level
        - sensor.front_door_sensor_battery
        - sensor.front_doorbell_sensor_battery       
        - sensor.side_door_sensor_battery
        - sensor.side_doorbell_sensor_battery
        - sensor.scene_switch_battery_level
        - sensor.multisensor_battery_level
      above: 99
      for:
        minutes: 10
  action:
    - service: input_datetime.set_datetime
      data_template:
        entity_id: >
          {% if trigger.entity_id == 'sensor.front_door_lock_battery_level' %}
            input_datetime.front_door_lock_batteries
          {% elif trigger.entity_id == 'sensor.side_door_lock_battery_level' %}
            input_datetime.side_door_lock_batteries
          {% elif trigger.entity_id == 'sensor.garage_door_lock_battery_level' %}
            input_datetime.garage_door_lock_batteries
          {% elif trigger.entity_id == 'sensor.bedroom_contact_sensor_battery' %}
            input_datetime.bedroom_contact_sensor_battery
          {% elif trigger.entity_id == 'sensor.sump_pump_alarm_battery_level' %}
            input_datetime.sump_pump_alarm_battery
          {% elif trigger.entity_id == 'sensor.front_door_sensor_battery' %}
            input_datetime.front_door_sensor_battery
          {% elif trigger.entity_id == 'sensor.front_doorbell_sensor_battery' %}
            input_datetime.front_doorbell_sensor_battery
          {% elif trigger.entity_id == 'sensor.front_door_sensor_battery' %}
            input_datetime.side_door_sensor_battery
          {% elif trigger.entity_id == 'sensor.front_doorbell_sensor_battery' %}
            input_datetime.side_doorbell_sensor_battery
          {% elif trigger.entity_id == 'sensor.scene_switch_battery_level' %}
            input_datetime.scene_switch_battery
          {% elif trigger.entity_id == 'sensor.multisensor_battery_level' %}
            input_datetime.multisensor_battery
          {% endif %}
        date: "{{ as_timestamp(now())|timestamp_custom('%Y-%m-%d') }}"

I think your problem stems from the way the trigger works. The first time an entity changes it will check if the value is above 99. If it is it will fire. After that, the value has to go to 99 or below and then to above 99 for it to fire again. It does this for each of the sensors individually.

If you’re ok with the automation as it is, except you don’t want it to fire for that first state change, you can add a template condition of {{ trigger.from_state is not none }}.

I’m not sure I follow… it seems to mark the date for all of them fine I just added all but the first 3 before I posted and it only set a date for those at 100 (which is want i want) the problem is that in 3 weeks lets say, my contact sensor still says 100 (it seems to only do 30% increments) it will change the date for that one after every reboot… continuously moving that date forward until it finally drops to 70%… so I think I need a way for it to check the date of previous datetime entry for that entity??
Sorry if I am misunderstanding you.

And as far as the automation as it is I would appreciate any advice on a way to do it better/easier so if there is a different method to accomplish it I have no problem trying it

Exactly. And the solution I suggested should prevent it from doing that.

The first state change for any entity will be from “no state” to “some state”. Basically, trigger.from_state will be none. The numeric_state trigger ignores the from_state and only looks at the to_state. So the condition will prevent the automation from triggering for that first state change (for each of the entities.)

I suppose it’s also possible for that first state change to happen before the trigger is initialized. If that’s the case, then a more foolproof solution would be:

condition:
  condition: template
  value_template: >
    {{ trigger.from_state is not none and
       trigger.from_state.state|float <= 99 }}

This will prevent it from triggering for the first state change, or any state change after that that isn’t due to the value coming from below or equal to 99 to above 99 (e.g., in the case the first state change the trigger sees is from, say, 99.1 to 99.2, or even staying at 99.1 but an attribute changed.)

Ok thanks for explaining it… I thought the “is not none” would pertain to the state after a restart but forgot that the state would already be stored still … in my head I guess I was thinking it was like a template sensor where it would take a minute to populate the state… I will try it out. Thanks again!

Let me know if it helps. This is all based on theory. I haven’t actually done anything exactly like this. :stuck_out_tongue:

So far so good after a little testing! Thanks.

1 Like

Rather than a slew of input_datetime helpers, I created a single sensor using snarky-snark’s home-assistant-variables integration.

var:
  batteries_replaced:
    friendly_name: Batteries Replaced
    unique_id: batteries_replaced
    restore: true

The automation is almost the same as above:

alias: Track Battery Changed Dates
description: ""
trigger:
  - platform: numeric_state
    entity_id:
      - sensor.front_door_lock_battery_level
      - sensor.garage_2_battery_level
      - sensor.garage_3_battery_level
      - sensor.garage_door_battery_level
      - sensor.laundry_room_battery_level
      - sensor.garage_door_lock_battery_level
      - sensor.4_in_1_multisensor_battery_level
      - sensor.front_door_multisensor_battery_level
      - sensor.garage_1_battery
      - sensor.office_battery
      - sensor.bedroom_battery
      - sensor.kitchen_battery
      - sensor.bathroom_battery
      - sensor.button_1_battery
      - sensor.landing_2_battery
      - sensor.front_porch_battery
      - sensor.landing_1_5_battery
      - sensor.living_room_battery
      - sensor.powder_room_battery
      - sensor.south_patio_battery
      - sensor.kitchen_mijia_battery
      - sensor.outside_weather_battery
      - sensor.southeast_patio_battery
      - sensor.southwest_patio_battery
      - sensor.rear_smart_timer_battery
      - sensor.front_smart_timer_battery
      - sensor.phillips_hue_switch_battery
    above: 99
    for:
      hours: 0
      minutes: 5
      seconds: 0
condition:
  - condition: template
    value_template: >-
      {{ trigger.from_state is not none and trigger.from_state.state|float(0) <
      100 }}
action:
  - service: var.set
    data:
      entity_id: var.batteries_replaced
      attributes:
        "{{ trigger.entity_id }}": "{{as_timestamp(now()) | timestamp_custom('%Y-%m-%d') }}"
mode: single

I wrote this

Thanks, looks great. It initially seemed to work as, once I created the variable and automation, the variable had a list of the battery sensors that had a numeric state of 100%. However, even though the variable was configured with restore: true, after the next time Home Assistant restarted, the variable was empty, no attributes. This is my first experience using the Variable integration. Any suggestions?

I guess everything is working as intended now. Not sure why a bunch of the sensors showed up initially with a battery change date and then weren’t there any longer after a restart (even with restore: true set) but when I did change a battery today, that sensor properly appeared in the variable entity. One other showed up that I hadn’t changed but it’s a Phillips Hue dimmer switch that for quite a while now has vacillated between 100% and gradually lower levels, eventually (within a half-day or less) returning to 100%. That means that it will apparently end up with the “change date” getting updated every day or two but shy of changing something in the automation that would effect all other sensors too (e.g., only updating var when numeric state has been less than 100% for 24 hours, etc.), I can’t think of any other solution. So, for now, I’m looking for to this solution giving me an automated way to track when most of my IOT devices have had a battery changed.

@nate.eaton.jr, I’m now using the Battery Notes for Home Assistant integration to track my battery changed dates.

1 Like

I’m also now using the hass-variables integration in lieu of the older snarky-snark one.

Google Photos

Thanks! That seems to work great.

1 Like