Hi there.
I need some help for a template sensor.
I have the below garage sensor, which works great.
sensor:
- name: Garage Status
unique_id: Garage_status
icon: mdi:garage-variant
state: >
{% if (states('binary_sensor.garage_closed') == 'on' and states('binary_sensor.garage_open_debounced') == 'off') %}
closed
{% elif (trigger.to_state.state == 'off' and trigger.from_state.state == 'on' and trigger.entity_id == 'binary_sensor.garage_closed') %}
opening
{% elif (states('binary_sensor.garage_open_debounced') == 'on' and states('binary_sensor.garage_closed') == 'off') %}
open
{% elif (trigger.to_state.state == 'off' and trigger.from_state.state == 'on' and trigger.entity_id == 'binary_sensor.garage_open_debounced') %}
closing
{% else %}
unknown
{% endif %}
Now sometimes, there is something in the way (physically) and the garage wont close of course. It will stop at the position and HA will in this state report closing indefinitely.
Since the binary sensors will both have the state âoffâ for time it takes for opening/closing (~20 seconds), i wanted to add the condition that a state change for either opening or closing must have had happen in the last 30s, and for the opposite binary sensor, it must be longer than 30s. Iâm unable to get this work, as soon as I add that condition, the sensor becomes unavailable when opening or closing. When finally the garage is closed/open, its back to the ânormalâ state. Has anyone a hint? The portion with the time check does not workâŚ
This is my adapted sensor code:
sensor:
- name: Garage Status
unique_id: Garage_status
icon: mdi:garage-variant
state: >
{% if (states('binary_sensor.garage_closed') == 'on' and states('binary_sensor.garage_open_debounced') == 'off') %}
closed
{% elif (trigger.to_state.state == 'off' and trigger.from_state.state == 'on' and trigger.entity_id == 'binary_sensor.garage_closed' and (as_timestamp(now()) - as_timestamp(states.binary_sensor.garage_closed.last_changed)) < 30 and (as_timestamp(now()) - as_timestamp(states.binary_sensor.garage_open_debounced.last_changed)) > 30) %}
opening
{% elif (states('binary_sensor.garage_open_debounced') == 'on' and states('binary_sensor.garage_closed') == 'off') %}
open
{% elif (trigger.to_state.state == 'off' and trigger.from_state.state == 'on' and trigger.entity_id == 'binary_sensor.garage_open_debounced' and (as_timestamp(now()) - as_timestamp(states.binary_sensor.garage_closed.last_changed)) > 30 and (as_timestamp(now()) - as_timestamp(states.binary_sensor.garage_open_debounced.last_changed)) < 30) %}
closing
{% else %}
unknown
{% endif %}
Without digging too deep in the conditions themselves:
You are not posting the full code. As you use a trigger variable, I assume it is a trigger based template sensor? If it is, the templates will only ever be evaluated when the trigger happens, at the time it happens. You will maybe be able to test when the trigger happens how long the previous state has been, but not after a state has held for some time. So the âlongerâ will never happen because there is no trigger. If the trigger is time, the entity id will not be set.
But last but not least, by adding extra conditions, but no or and no extra elifs, you will likely have multiple conditions where the last else will trigger. Because due to the extra conditions, fewer times youâll have defined states.
Thanks for the hints and advice, I appreciate it
.
Yes thats right, its a trigger based sensor:
- trigger:
- platform: state
entity_id:
- binary_sensor.garage_closed
- binary_sensor.garage_open_debounced
Looks like this wont be as easy as I initially thought. My workaround would be to create another sensor, i.e. a switch, which will be turned on as soon as I detect I pressed the button for closing, but the garage never closed. (I already have a push notification for that)
That could then be put into another elif of this sensor.
Are there other ways to check state_changes with time consideration, would you by any chance have a more elegant idea?
I forgot you can also add a trigger with a for clause for the delay. Then youâll get to the template at the time you want, and you can simply test for the trigger id to know time has passed.
But first of all, Iâd use a template cover to emulate the garage door, so youâll have the full experience. Itâs state template is evaluated like any other template sensor, but it would also be hard to do what you do above. So you might want to use your trigger based sensor to prepare the state for it.
I am a bit unclear what youâll do when the door is stuck though. I would keep it in opening or closing just for the sake of detecting it is stuck. If it is in that state too long, you know thereâs something wrong.
As for more elegant solutions, there is an integration or blueprint out there that estimates the percentage ooen based on time, but I donât remember what it is called. If you search, it might be just what you want.
You are correct, i could simply leave it on âclosingâ or âopeningâ and I know something is wrong. Thats how it is working today - I just had the idea to change the state after a certain amount of time for easy of useâŚ
Your approach is interesting.
To get this right, the interesting portion of my sensor is the âclosingâ part:
{% elif (trigger.to_state.state == 'off' and trigger.from_state.state == 'on' and trigger.entity_id == 'binary_sensor.garage_open_debounced') %}
closing
Did I understand this correctly, you would first check the normal closing and then re-evaluate 30seconds later again? Something like this?
delay off is for binary sensors. They will turn off after that time. I was referring to an exttra trigger, besides the one you already had, with a for clause. That will fire if the state is as requested for the given time. So for instance when the state is closing or opening for x time. If you give that trigger an id, you can test for it in the template and set the state to either closed or open as you wish.
I see, so it should be something like this I reckon?
- trigger:
- platform: state
entity_id:
- binary_sensor.garage_closed
- binary_sensor.garage_open_debounced
- binary_sensor.garage_closed
for:
seconds: 30
id: "opening-check"
sensor:
- name: Garage Status
unique_id: Garage_status
[config of the rest of the sensor]
As soon as I do this, all 3 triggers only fire after 30 seconds. The for clause cant be only for the last of these three triggers, is that right? I was playing around with indentation but that does not work.
Yes, the for clause would require the state to be stable for 30 secs.My suggestion was to add this in addition to the triggers you already had, not as the sole triggers. You can have multiple triggers.
In fact, I would trigger on the garage status itself being opening or closing, not on the end switches. So, if the state is closing too long, set it closed. If the state is opening too long, set it to open.
- trigger:
- platform: state
entity_id:
- binary_sensor.garage_closed
- binary_sensor.garage_open_debounced
- platform: state
entity_id: sensor.garage_status
to:
- closing
- opening
id: timeout
for:
seconds: 30
sensor:
- name: Garage Status
unique_id: Garage_status
state: |
{% if trigger.id == 'timeout' %}
{{ 'closed' if trigger.to_state.state == 'closing' else 'open' }}
{% elif (states('binary_sensor.garage_closed') == 'on' and states('binary_sensor.garage_open_debounced') == 'off') %}
closed
{% elif (trigger.to_state.state == 'off' and trigger.from_state.state == 'on' and trigger.entity_id == 'binary_sensor.garage_closed') %}
opening
{% elif (states('binary_sensor.garage_open_debounced') == 'on' and states('binary_sensor.garage_closed') == 'off') %}
open
{% elif (trigger.to_state.state == 'off' and trigger.from_state.state == 'on' and trigger.entity_id == 'binary_sensor.garage_open_debounced') %}
closing
{% else %}
unknown
{% endif %}