Template sensor remains OFF despite state template rendering TRUE

I have a template binary sensor. The template’s state renders as TRUE but the state of the sensor stays off. Can someone tell me what I missed?

I’m trying to sense when my house cleaners are at the house. I have a calendar entity that reflects when they’re supposed to visit. I have a binary sensor that is TRUE for thirty minutes before and after the calendar entity. That binary sensor is behaving as expected.

When they visit, they enter my house through my garage door, so I’m trying to have the “probably here” sensor be true when that thirty minute buffer sensor is true and the garage door has been open for 20 minutes.

Here’s my sensor definition:

- binary_sensor:
  - name: "cleaners probably here"
    unique_id: cleaners_probably_here
    device_class: occupancy
    state: >
      # buffer sensor checks for 30 minutes before or after a calendar entry
      # the rest checks to see if the garage door is open and has been for 20 minutes
      {{is_state('binary_sensor.cleaners_visit_buffer','on') and (is_state('cover.garage_door', 'open') and now() > states.cover.garage_door.last_changed + timedelta(minutes=20)) }}

the STATE renders true in the template developer tool, but the sensor remains “OFF”

My understanding is that putting now() in the function will keep the template actively updating for the timedelta part. Do I need a separate trigger sensor or something like that?

Are you sure you’re looking at the correct template entity?

That entity will update when binary_sensor.cleaners_visit_buffer changes state, when cover.garage_door changes state, and every minute on the minute.

If you’re restarting or either of those other entities are template entities, when you reload (templates) the last_changed will be within the last 20 minutes so it will render false for 20 minutes.

If that is the actual configuration you are using, you need to remove those comments or place them inside Jinja comment delimiters {# #}.

As posted, the values rendered for state will be:

# buffer sensor checks for 30 minutes before or after a calendar entry
# the rest checks to see if the garage door is open and has been for 20 minutes
True

or

# buffer sensor checks for 30 minutes before or after a calendar entry
# the rest checks to see if the garage door is open and has been for 20 minutes
False

… both of which are values that will cause the binary sensor to return off.

1 Like

Crud - that’s gotta be the issue! Too many programming languages in my brain, I missed that. Now to wait two weeks to test the real-life situation.

Funny. I just looked at my templates and found one where I had a comment in the state of a binary_sensor that is working. Just luck that I used a different block-scalar:

(Don’t do this)

$ cat test.yaml
- binary_sensor:
  - name: Some Binary Template
    state: >
      # this is true
      {{ is_state( 'light.foo', 'on') }}

  - name: Some Binary Template
    state: |-
      # this is true
      {{ is_state( 'light.foo', 'on') }}

$ yq . test.yaml
[
  {
    "binary_sensor": [
      {
        "name": "Some Binary Template",
        "state": "# this is true {{ is_state( 'light.foo', 'on') }}\n"
      },
      {
        "name": "Some Binary Template",
        "state": "# this is true\n{{ is_state( 'light.foo', 'on') }}"
      }
    ]
  }
]

Apparently the last line sets the state.

By the way, isn’t this really more of an automation (or a template with a trigger)?

The cleaner cannot get in w/o opening the garage. So, that is the event you are interested in. Then just limit or condition on the time window.

I’d use a local calendar entry to set the range and then trigger on the garage opening (or closing if they leave it open while at the house). And either use an automation to turn on or off a helper – or set the state of a template.

Nope, the entire template sets the state. Source: Am the dev.

1 Like

Interesting. Of course, I trust you. I’m just seeing this. What’s happening there?

(Again, not at all suggesting comments in there are a good idea…)

- binary_sensor:
  - name: "Foo Pipe"
    state: |-
      # this is true
      {{ is_state( 'input_boolean.foo_switch', 'on') }}

- binary_sensor:
  - name: "Foo Greater Than"
    state: >
      # this is true
      {{ is_state( 'input_boolean.foo_switch', 'on') }}

Not sure how it’s working for you as the code itself only looks for specific values and it does not strip characters:

If you turn them into sensors they return this, and notice the pipe one returns “True” or “False”, so that would match the code, right?

Debugged into it, the |- retains the carriage return between lines, e.g. # this is true\nTrue. The raw template passed to ast (a built in python lib) ends up transforming the result to True. There’s no telling why it does this because the underlying code is C++, not python and vs-code doesn’t allow me to step into it. This is likely a bug of some sort. As for some background ast is used by home assistant’s template helper, meaning this is very low level code handling this transformation. As a result, when the rendered value is provided to the template entity integration, all I see is True or False.

As for the > version, that should remain false and does remain false on my dev system. Carriage returns are stripped at replaced with white space, this preserves the comment and renders the entire string # this is true True. I.e. The template entity integration receives the value # this is true True or # this is true False which will always be treated as False because of the forgiving_boolean function.

1 Like

Interesting. Thanks for sharing. Love learning more of the internals as time goes on.

Dropping back by to say that this sensor worked as expected this week after using proper comments.

The reason I didn’t set this up as an automation was that I really want to trigger something when my cleaners leave. And there are lots of times that that particular garage door opens and closes in a given morning, near the time when my cleaners visit. So looking for it to be open for a long time in their usual window (set by a calendar entity) seemed to be a good way to handle things.