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?
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'
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.
- 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.
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 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.)
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.