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