False numeric_state trigger after restart

I have an automation which turns of the lights when the elevation of the sun falls below 4.0 degrees. This works well however sometimes the automation also triggers after a restart when the elvation is already below 4 degrees. Last night the automation triggers for example at 00:15 when the elevation is far below 4 degrees (see screen shot below).

I expect the automation only triggers when the elevation crosses the limit of 4 degrees. Could this be a bug or is this the proper behaviour of the numeric_state trigger. And so, how can I prevent the automation to be triggered after a restart?

- alias: 'zon onder - lampen aan'
  trigger:
    platform: numeric_state
    entity_id: sun.sun
    value_template: "{{ state_attr('sun.sun', 'elevation') }}"
    below: 4.0
  condition:
    condition: or
    conditions:
      - condition: state
        entity_id: binary_sensor.home
        state: 'on'
      - condition: state
        entity_id: input_boolean.vakantie
        state: 'on'
  action:
    service: homeassistant.turn_on
    entity_id: light.woonkamer

Note: I don’t have experience with sun.sun, just some thoughts:
the issue is most likely here.
when HA starts, at some point the sun component is created and it depends on how it happens - perhaps initially all its values are set to defaults (and elevation becomes 0) and that triggers your automation?
So I’d say you need to explore what is happening to that attribute on HA restart.

This is not a bug. It is intended behavior. The “crosses the boundary” thing only applies if the previous state was a valid numeric value and was “on the other side of the boundary.”

So when the entity first changes state (after the automation’s triggers are initialized, which happens when HA starts, or whenever the automation is turned on after being off, or when automations are reloaded), if the entity’s state is a valid numeric value, and it meets the above and/or below criteria, the trigger will fire. After that it remembers it has triggered and won’t trigger again until the criteria is no longer met and then is met again. However, if during this period, the automation’s triggers are re-initialized (for any of the reasons mentioned above), or the entity’s state changes to something that is not a valid numeric value, then it “forgets” that it has triggered and starts over again.

The easiest way to prevent the trigger from running the actions when it fires in one of these other scenarios is to add a condition like this:

- condition: template
  value_template: >
    {{ trigger.from_state is not none and
       trigger.from_state.state.replace('.','').isnumeric() }}

This should be AND’d in. So in your case:

  condition:
    - condition: template
      value_template: >
        {{ trigger.from_state is not none and
           trigger.from_state.state.replace('.','').isnumeric() }}
    - condition: or
      conditions:
        - condition: state
          entity_id: binary_sensor.home
          state: 'on'
        - condition: state
          entity_id: input_boolean.vakantie
          state: 'on'
1 Like

or just

- condition: template
  value_template: >
    {{ trigger.from_state and
       trigger.from_state.state.replace('.','').isnumeric() }}

?

Like the idea :wink:

Not really, because if from_state is None then the template will result in None instead of False. But, then again, the condition is considered true if the result (when converted to lower case and stripped) is exactly true, and false otherwise, so it will probably work either way. :smiley:

exactly. sometimes the expression is pretty long anyway and adding that is not none doesn’t really add any clarity (imho) :wink:

1 Like

Thats clear! thanks

1 Like
- condition: template
  value_template: >
    {{ trigger.from_state is not none and
       trigger.from_state.state.replace('.','').isnumeric() }}

This didnt work because I use the attritbute of sun.sun instead of the state of sun.sun. Now I use a template sensor of the elevation. I also had to add an extra .replace part.

- alias: 'zon onder - lampen aan'
  trigger:
    platform: numeric_state
    entity_id: sensor.elevation
    below: 5.0
  condition:
    - condition: template
      value_template: >
        {{ trigger.from_state is not none and
           trigger.from_state.state.replace('.','').replace('-','').isnumeric() }}
    - condition: or
      conditions:
        - condition: state
          entity_id: binary_sensor.home
          state: 'on'
        - condition: state
          entity_id: input_boolean.vakantie
          state: 'on'
  action:
    service: homeassistant.turn_on
    entity_id: light.woonkamer, light.eetkamer

Are you sure? What exactly didn’t work?
In your initial automation there was no sensor.elevation. I presume you created a template sensor with value_template: "{{ sun.sun.attribute.elevation }}" but why?

Thats right, The automation did not work so I thought this has to do with the from_trigger part. so I added a template sensor.elevation. However on closer inspection I think the automation did not work because of the missing “-” when the elevation is negative.

that’s more like it. @pnbruckner you overfoxed yourself! :wink:

Hmm the sun is set and it seems the automation unfortunately doesnt work yet.

      value_template: >
        {{ trigger.from_state is not none and
           trigger.from_state.state.replace('.','').replace('-','').isnumeric() }}

This value_template only works when I use a sensor which state represent the elevation. Correct me if i am wrong but i think the trigger.from_state checks the state of the entity_id (=sun.sun) and not the attribute of sun.sun. So the numeric check always return False (the state of the sun.sun is “below_horizon” or “above_horizon”) and the automation wont work.

I think you are right, we just forgot about the elevation bit while enjoyed some trickery :wink:
Think this should work

condition:
  - condition: template
    value_template: >
      {{ trigger.to_state and
         trigger.to_state.attributes.elevation.replace('.','').replace('-','').isnumeric() }}
  - condition: or
    conditions:
      - condition: state
        entity_id: binary_sensor.home
        state: 'on'
      - condition: state
        entity_id: input_boolean.vakantie
        state: 'on'

And to test it you shouldn’t wait for a sunset - just go to Template editor and paste this

{% set trigger={'to_state':{'attributes':{'elevation': '6.0'}}} %}

and then the template in question and play with it to see what it returns if you change input values.

I tried your conditon template but it seems that the replace function doesnt work with the attribute. I set the state of the sun.sun.elevation to test the automation. The following error occurs.

Error during template condition: UndefinedError: 'int object' has no attribute 'replace'

Sorry, seems I sent you down a slightly incorrect path. I had overlooked you were using the elevation attribute of sun.sun (instead of the state of some numeric sensor.)

Going back to your original automation, this is probably what you need:

  condition:
    - condition: template
      value_template: "{{ trigger.from_state is not none }}"
    - condition: or
      conditions:
        - condition: state
          entity_id: binary_sensor.home
          state: 'on'
        - condition: state
          entity_id: input_boolean.vakantie
          state: 'on'

That will prevent the automation action from running on the very first state change of sun.sun after restart (where trigger.from_state will be None), even if the elevation attribute is already below 4.0. The value will have to first go to 4.0 or above, and then “cross” the threshold to below 4.0 for the action to run.

The elevation attribute of sun.sun will always be numeric already (it’s actually a float, not a str), so no need for the second part of my original suggestion (besides the fact that it was incorrectly testing the state instead of the attribute.)

1 Like

It sounds credible… interesting to se if it works.
I can’t believe sometimes how many loops we need to go through… :wink:

That did the trick! thanks

1 Like

The uptime integration was changed in 2020.12 from storing minutes to starting a static datetime, so you now need to create your own sensor or a template to get the minutes of uptime.

This code can be added as a template in conditions:

{{ as_timestamp(now()) - as_timestamp(states.sensor.uptime.last_changed) |
int > 120 }}

where 120 is how many seconds after restart you want to ignore triggers.

Here is a thread on Condition Uptime to see examples of the correct syntax and usage.