Binary sensor template triggers in the developer tools, but not in actual config

Can anyone offer me any advice on why this code works perfectly fine in the developer tools, but in practice the binary sensor will not turn on? I have reloaded the ‘Template Entities’ as well as restarted home assistant. This is new original code, so I’m sure I’ve missed something simple?

template:

  - binary_sensor:

      - name: Basement Movie Mode Off Delay Trigger
        state: >-
          #* * * convert motion sensor delay to seconds * * *
          {% set delay_offset = states('input_number.basement_movie_mode_off_sensor_trigger_minutes_dalay')|float*60 %}

          #* * * convert movie duration to seconds * * *
          {% set movie_duration = states('input_number.basement_movie_mode_duration')|float*60 %}

          #* * * time movie ends * * *
          {% set movie_ended_time = as_timestamp(states.input_boolean.basement_movie_mode.last_changed) + movie_duration %}

          #* * * time motion sensors change to off * * *
          {% set sensors_turned_off_time = as_timestamp(states.binary_sensor.basement_movie_mode_off_sensor_group.last_changed)%}

          #* * * time since movie ended * * *
          {% set time_since_movie_ended = as_timestamp(now()) - movie_ended_time %}

          #* * * time since sensors turned off * * *
          {% set time_since_sensors_turned_off = as_timestamp(now()) - sensors_turned_off_time %}

          #* * * check if movie has ended {true} * * *
          {% set movie_has_ended = time_since_movie_ended > 0 %}

          #* * * check if sensor offset has occurred {true} * * *
          {% set sensor_offset_has_triggered = time_since_sensors_turned_off > delay_offset %}

          #* * * check if movie offset has occurred {true} * * *
          {% set movie_offset_has_triggered = time_since_movie_ended > delay_offset %}

          # Sensor Status
          {{
            is_state('input_boolean.basement_movie_mode','on') and
            (movie_has_ended) and
            (sensor_offset_has_triggered) and
            (movie_offset_has_triggered)
          }}

One reason I can come up with is that the float filter needs a default, e.g. float(0). There have been warnings about it for quite a while now, and recently it gives an error if during boot the value is unknown.

I’m wondering, since the last two events that would ever trigger this sensor are time-based, ‘sensor_offset_has_triggered’ and ‘movie_offset_has_triggered’, would this have something to do with it?

Okay, I’ll try that.

Possible typo when setting the first variable? You have basement_movie_mode_off_sensor_trigger_minutes_dalay, should that be delay at the end?

This does not seem to have fixed it.

I did double check the name of the input_number, it is correct. Thanks for taking a look at it. This all seems to work fine when testing in the developer tools, so I think I can pretty much rule out any errors with entity names, etc.

All instances of as_timestamp also need a default.

Have you checked the error logs on loading? May be there are hints there? It was how I found out about required defaults first.

And may I ask why you define a trigger as a binary sensor? This looks like it is way easier to implement as a normal automation trigger, especially the delay parts. I would personally never code delays in sensors, but always in the behavior based on the sensors.

An oddity I noticed:

You describe this as “the time the sensors turn off”. But it’s just last changed of a binary sensor. Last changed is set any time the state of an entity changed whether it becomes on, off, unknown, unavailable, etc. And I don’t see anything else in this template that checks whether binary_sensor.basement_movie_mode_off_sensor_group actually has state on to ensure that that you’re actually checking if it’s been the desired amount of time since the sensors turned off and not the desired amount of time since the sensors turned on or became unavailable or something else. Perhaps that is it?

Also as an aside, you might be able to reduce the complexity of this template by using delay_on like this:

delay_on: "{{ states('input_number.basement_movie_mode_off_sensor_trigger_minutes_dalay') | float(0) * 60 }}"

This makes it so instead of immediately turning on when the conditions are met the sensor only turns on if the conditions are met for the specified number of seconds. Then you can remove the “has it been this many seconds” checks and just check if the movie is over and the motion sensors are off.

That is a very impressive catch. Thank you @CentralCommand I will add that check in the sensor and continue troubleshooting. Sometimes it’s hard to see the forest through the trees lol.

1 Like

I’ve never used this before, I will definitely see how that might help slim things down. I’ll post back my updates and changes soon and let you know if it works.

1 Like

Had another thought with this (and feel free to ignore me if you’ve got something working now), what if you used a timer instead of an input number for movie_mode_duration and a boolean for movie_mode?

Right now from what I can tell something sets the expected length of movie mode and then you toggle a boolean on. If you used a timer instead you could simply call timer.start with the duration set to the expected time. Then movie mode is on when the timer is running and off when it ends. It’s basically the number and the boolean wrapped into one entity.

Plus timers can be paused if you wanted to work that into the logic. So the lights come back on temporarily if everyone needs a pee/snack break.

Hahaha, :laughing: that would be amazing. I like that you are thinking of those types of things. I suppose, as long as you don’t go pee after the movie duration ends (which would only happen if you incorrectly input the movie duration), the very sensitive motion sensor near the stadium seating should prevent a premature shutoff. At least in theory. I’ll keep your suggestions in mind, however.

So, here is my current code. I have carefully troubleshot each and every event. They all seem to fire properly, in the order they occur, at the correct time they are suppose to occur, and the final sensor eventually changes to ‘on’ when all conditions are met, but only when I plug this entire thing into the the developer tools Template Editor. I am still unable to get the sensor to trigger in the config. Ugh !!!

template:

  - binary_sensor:

      - name: Basement Movie Mode Off Delay Trigger
        state: >-
          #* * * convert motion sensor delay to seconds * * *
          {% set delay_offset = states('input_number.basement_movie_mode_off_sensor_trigger_minutes_dalay')|float(0) * 60 %}

          #* * * convert movie duration to seconds * * *
          {% set movie_duration = states('input_number.basement_movie_mode_duration')|float(0) * 60 %}

          #* * * time movie ends * * *
          {% set movie_ended_time = as_timestamp(states.input_boolean.basement_movie_mode.last_changed, default=0) + movie_duration %}

          #* * * time motion sensors change to off * * *
          {% set sensors_turned_off_time = as_timestamp(states.binary_sensor.basement_movie_mode_off_sensor_group.last_changed, default=0)%}

          #* * * time since movie ended * * *
          {% set time_since_movie_ended = as_timestamp(now(), default=0) - movie_ended_time %}

          #* * * time since sensors turned off * * *
          {% set time_since_sensors_turned_off = as_timestamp(now(), default=0) - sensors_turned_off_time %}

          #* * * check if movie has ended {true} * * *
          {% set movie_has_ended = time_since_movie_ended > 0 %}

          #* * * check if sensor offset has occurred {true} * * *
          {% set sensor_offset_has_triggered = time_since_sensors_turned_off > delay_offset %}

          #* * * check if movie offset has occurred {true} * * *
          {% set movie_offset_has_triggered = time_since_movie_ended > delay_offset %}

          # Sensor Status
          {{
            is_state('input_boolean.basement_movie_mode','on') and
            is_state('binary_sensor.basement_movie_mode_off_sensor_group','off') and
            (movie_has_ended) and
            (sensor_offset_has_triggered) and
            (movie_offset_has_triggered)
          }}

Oh wait, your comments. I believe this how you do comments in jinja:

{# I am a comment! #}

Although I’m not sure why that text didn’t show up in developer tools then…

EDIT: oh right, your comments currently aren’t in a template tag at all. That’s just going to be treated as normal text then and throw the whole thing off

template:

  - binary_sensor:

          {#* * * convert motion sensor delay to seconds * * *#}
          {%- set delay_offset = states('input_number.basement_movie_mode_off_sensor_trigger_minutes_dalay')|float(0) * 60 -%}

          {#* * * convert movie duration to seconds * * *#}
          {%- set movie_duration = states('input_number.basement_movie_mode_duration')|float(0) * 60 -%}

          {#* * * time movie ends * * *#}
          {%- set movie_ended_time = as_timestamp(states.input_boolean.basement_movie_mode.last_changed, default=0) + movie_duration -%}

          {#* * * time motion sensors change to off * * *#}
          {%- set sensors_turned_off_time = as_timestamp(states.binary_sensor.basement_movie_mode_off_sensor_group.last_changed, default=0) -%}

          {#* * * time since movie ended * * *#}
          {%- set time_since_movie_ended = as_timestamp(now(), default=0) - movie_ended_time -%}

          {#* * * time since sensors turned off * * *#}
          {%- set time_since_sensors_turned_off = as_timestamp(now(), default=0) - sensors_turned_off_time -%}

          {#* * * check if movie has ended {true} * * *#}
          {%- set movie_has_ended = time_since_movie_ended > 0 -%}

          {#* * * check if sensor offset has occurred {true} * * *#}
          {%- set sensor_offset_has_triggered = time_since_sensors_turned_off > delay_offset -%}

          {#* * * check if movie offset has occurred {true} * * *#}
          {%- set movie_offset_has_triggered = time_since_movie_ended > delay_offset -%}

          {# Sensor Status #}
          {{
            is_state('input_boolean.basement_movie_mode','on') and
            is_state('binary_sensor.basement_movie_mode_off_sensor_group','off') and
            (movie_has_ended) and
            (sensor_offset_has_triggered) and
            (movie_offset_has_triggered)
          }}

Thank you for walking through this with me @CentralCommand, I truly do appreciate you were kind enough to think this through with me. Here is the final code that works. I will admit, I removed whitespace at the same time ‘{%-’ and ‘-%}’ as I fixed the comments so I’m not 100% sure which fixed this, but either way, it works now. Thanks again partner.

1 Like