So, im sort of trying to create a template binary sensor (room presence) that is a hybrid/combination of a pir and a mmw sensor (ie. turns on with pir, turns off with mmw, and takes into account if pir triggers without mmw, and mmw triggers without pir).
First of all, the goal is:
sensor turns on when pir turns on
sensor turns off 5s after when mmw and pir turns off
if mmw was never triggered, the sensor turns off 120s after pir turns off
Anyway, i have made the logic into a binary template sensor using states and last_changed calculations. Here is what i have:
- binary_sensor:
- name: "Test sensor"
device_class: "presence"
state: >
{% set is_pir_on = is_state('binary_sensor.sensorgroup_pir_test', 'on') %}
{% set is_pir_off = is_state('binary_sensor.sensorgroup_pir_test', 'off') %}
{% set is_mmw_on = is_state('binary_sensor.sensorgroup_ps_test', 'on') %}
{% set is_mmw_off = is_state('binary_sensor.sensorgroup_ps_test', 'off') %}
{% set pir_last_changed = as_timestamp(now()) - as_timestamp(states.binary_sensor.sensorgroup_pir_test.last_changed) %}
{% set mmw_last_changed = as_timestamp(now()) - as_timestamp(states.binary_sensor.sensorgroup_ps_test.last_changed) %}
{% if is_pir_on %}
on
{% elif is_pir_off and is_mmw_off and pir_last_changed > 5 and mmw_last_changed > 5 %}
off
{% elif is_pir_off and pir_last_changed > 120 %}
off
{% else %}
on
{% endif %}
This actually works as pretty well (if you have any other suggestions or improvements let me know).
BUT my problem is that its too slow. I mean, i think its just not updating immediately. Let me explain. The new sensor turns on IMMEDIATELY when the PIR triggers - great. but when pir and mmw both turns off, instead of turning off after 5 secs, it takes about 30s to turn off… WHY? I changed the delay to 10s but still takes about 30s to turn off.
im suspecting that its getting throttled somehow. But im not entirely sure how i can get around that. Any thoughts?
I could potentially use a trigger based template instead, but i feel like a trigger based template + complex templating conditions on the state would make it s bit messy (if trigger was set to 5s after pir turns off but if it triggers milliseconds early and the last_changed was not >5s then it may end up at a weird state).
template:
- trigger:
- trigger: state
entity_id:
- binary_sensor.sensorgroup_pir_test
- binary_sensor.sensorgroup_ps_test
to: "on"
- trigger: state
entity_id:
- binary_sensor.sensorgroup_pir_test
- binary_sensor.sensorgroup_ps_test
to: "off"
for:
seconds: 5
- trigger: state
entity_id:
- binary_sensor.sensorgroup_pir_test
to: "off"
for:
seconds: 120
condition:
- or:
- "{{ trigger.to_state.state == 'on' }}"
- condition: state
entity_id:
- binary_sensor.sensorgroup_pir_test
- binary_sensor.sensorgroup_ps_test
state: "off"
for:
seconds: 5
binary_sensor:
- name: "Test sensor"
device_class: "presence"
state: "{{ trigger.to_state.state }}"
Completely untested, probably has a typo or two, caveat emptor, etc.
Edit: The logic of my automation should be more or less equivalent to yours. Neither automation however ever really takes the highlighted part of your requirements into account:
Not sure why you’d care about this at all, and I don’t see any foolproof way of checking this either. Sure you can compare their last_changed timestamps with a certain leeway of plus-minus a few seconds, but… why bother?
Of course what this really means is that the 120 second path of the automation more or less serves no purpose, as the state of the sensor will already always be off once both sensors have been off for more than 5 seconds.
OMG that now() is the culprit. Thank you! I thought i was going crazy.
Is there anything alternative to now() that can be used to compare last_changed with that triggers/updates more frequently?
Actually, yes there is but i think i messed up the initial requirmemnts. Let me lay out the requirments again updated:
sensor turns on when pir turns on
sensor turns off 5s after when mmw and pir turns off
if mmw was never triggered, the sensor turns off 120s after pir turns off
sensor turns off 1800s after pir turns off (regardless of mmw)
i completely missed the last one. Its very easy to add that to my state based template, but maybe hard to add to the trigger based template.
The reason the last/4th point exists (“sensor turns off 1800s after pir turns off”) is because if you leave the room, but the mmw continue to trigger off something unexpected (wind, fan, aircon etc), this condition will kick in 30m later to turn off presence (its late/slow, but more of a fallback incase of something unexpected - case like mmw continuing to trigger off something you didnt account for can very easily happen, and a fallback logic like this makes the sensor significantly more reliable).
Reason why the 3rd point exists (“if mmw was never triggered, the sensor turns off 120s after pir turns off”) is in a scenario where you happen to trigger your pir without triggering the mmw (in my study the PIR has a slight view of the hallway if you leave the door wide open where as the mmw does not), So if the 3rd point is not implemented, the presence will turn off 30m later when the 4th point is met (where as if we can turn it off much earlier since we know the exact condition, it would be much more ideal).
BTW thanks again for the suggestion. It goes quite a way there but not 100% because of the last two conditions. i think your trigger based example (and some other examples/docs ive read last few days) does give me some ideas as to how i can get pretty close to what im looking for using trigger templates. I wonder if trigger based is the best answer, i would much rather have state based if there is a workaround for that re-rendering delay with now() because state gets reevaluated as opposed to trigger that could be missed (bad template, ha restart, bugs etc - im just paranoid, its probably not very likely).
Anyway, if anyone has any other bright ideas let me know. If there are any docs/examples on complex trigger/state based template sensors implementations i would love to have a look and understand them (and potentially get some ideas from them).
No. Running more often would waste system resources, hence why it does not. The only other alternative that I can think of is a trigger based template entity that runs every X seconds, but that would really be a waste of system resources.
What is your definition of “mmw was never triggered”?
As I already tried to explain above, your third trigger/condition serves no purpose/is completely redundant. If the “mmw was never triggered”, surely its state must have been off for at least as long as the pir sensor has been off, and when both have been off for five seconds, the second trigger/condition will have already been fulfilled.
Your fourth trigger/condition seems impossible to implement. Sure, one can easily make a trigger that sets the state of the sensor to off 1800 seconds after the pir turns off. But if the mmw is as unreliable as you think it is, any time it flips to off and then back to on, the sensor will be back to on again.
So in summary, IMHO you really need to do a complete rethink of your logic. What exactly is the purpose of this sensor? To trigger a light, fan, something else? Start with your end goal is and work your way backwards from there…
ill answer this first. Im trying to build a reliable and foolproof [virtual] presence sensor using actual PIR and MMW sensors. The goal of the presence sensor is to accuratly determine that someone is in the room or not and in case of any ghosting (or false positives) to then recover as well/quickly as possible while minimising false negatives (so the actual numbers would be tweaked later to accomplish this balance). The new sensor will be used to turn lights on/off and most importantly turn off things like AC/Heating/TV that you don’t want running longer than necessary. The sensor is mainly used in rooms where people tend to idle for a long period of time with minor movements (study/livingroom/bedroom) - but again the idea is the numbers can be tweaked to reduce false positives at the cost of false negatives and vice versa. As for the goals, yeah i guess it helps writing them down but i figured it may be a bit too much to explain all those here in my original post.
Here is roughly what i came up with (from an example of light control but will be used for other controls as well):
when i walk into the room, light must turn on
while im in the room, light must remain on
when i walk out of the room, light must turn off as fast as possible without affecting goal 2
3.1. cases where its unavoidable, delays in turning off the light is fine
must minimise light turning on (or atleast time light remains on) while im not in the room
expect false triggers on MMW sensor due to AC/Fan/Curtains(wind) etc
expect situations where MMW sensor not turning off at all (AC/Fan)
expect triggers on PIR without triggering MMW (could say false triggers) - PIR has a wider/different view than the MMW
7.1. its ok for light to turn on (rarely) with the false trigger, but it should turn off (ideally without taking forever)
Well… You are correct in the sense that what i originally posted is a tad wrong and i didnt explain all 4 conditions. But the 3rd condition has a purpose. The 3rd condition is to allow PIR only operation (so if mmw never triggers because you are out of view from it, the PIR has slightly more 120s offset to turn off lights rather than the 5s when operating with PIR+MMW). So there IS a valid usecase for this point, and its not redundant (in terms of my original code it was haha, my bad). That said, it is the weakest condition, if conditions 1, 2 and 4 can be achieved, then i can live without condition 3.
No, not exactly. only the PIR will turn on the sensor. So mmw turning off and on (while pir is off) will not affect the 1800s delay for turning off. Essentially MMW turning on will NOT turn on the sensor - mmw being on will only keep the sensor from turning off too quickly as pir often turns off when there are no large movements. I think this is the part that was slightly wrong on your trigger template suggestion, it should be more like:
template:
- trigger:
- trigger: state
entity_id:
- binary_sensor.sensorgroup_pir_test
# - binary_sensor.sensorgroup_ps_test ### This should be removed
to: "on"
- trigger: state
entity_id:
- binary_sensor.sensorgroup_pir_test
- binary_sensor.sensorgroup_ps_test
to: "off"
for:
seconds: 5
- trigger: state
entity_id:
- binary_sensor.sensorgroup_pir_test
to: "off"
for:
seconds: 120
condition:
- or:
- "{{ trigger.to_state.state == 'on' }}"
- condition: state
entity_id:
- binary_sensor.sensorgroup_pir_test
- binary_sensor.sensorgroup_ps_test
state: "off"
for:
seconds: 5
binary_sensor:
- name: "Test sensor"
device_class: "presence"
state: "{{ trigger.to_state.state }}"
Im still a noob with template sensors. Would you be able to explain the following code snippets from your suggestion:
1:
- trigger: state
entity_id:
- binary_sensor.sensorgroup_pir_test
- binary_sensor.sensorgroup_ps_test
to: "off"
for:
seconds: 5
Does this mean THIS trigger only triggers when BOTH binary_sensor.sensorgroup_pir_test AND binary_sensor.sensorgroup_ps_test has been off for 5s or if EITHER one is off for 5s?
Does this mean that this condition ONLY passes (and goes to state change) if BOTH sensors have been off for 5s or if EITHER sensor has been off for 5s?
If i (hypothetically) have a trigger for ever second (or some short interval), with the above mentioned condition, the condition will pass and result in state update every second so long as the condition mentioned here is met (ie: both sensors have been off for 5s or longer)?
To be fair, if i do not consider the 3rd condition (PIR only operation) we could simplify the trigger based example to something VERY simple
template:
- trigger:
# Turn on with PIR (condition 1)
- trigger: state
entity_id:
- binary_sensor.sensorgroup_pir_test
to: "on"
# Turn off with PIR+MMW with 5s delay (condition 2)
- trigger: state
entity_id:
- binary_sensor.sensorgroup_pir_test
- binary_sensor.sensorgroup_ps_test
to: "off"
for:
seconds: 5
# Turn off with PIR extended delay 1800s (condition 4)
- trigger: state
entity_id:
- binary_sensor.sensorgroup_pir_test
to: "off"
for:
seconds: 1800
binary_sensor:
- name: "Test sensor"
device_class: "presence"
state: "{{ trigger.to_state.state }}"
Maybe this is what i have to do i guess. Is there any way this can be done in a state based template without using now()? I guess not eh?
…and also out of curiosity, there isnt any way to combine that trigger template sensor into a blueprint with inputs for pir_sensor, mmw_sensor and some other integer inputs for wait times eh? I cant seem to find any docs/examples around trigger based sensor blueprints, and when i tried diy-ing, i got errors around when i put the blueprint input variables as the trigger entity_id.