Last motion sensor - but ignore certain values

  - sensor:
    - name: "Letzte Bewegung"
      unique_id: LetzteBewegung
      icon: "mdi:motion-sensor"
      state: >-
        {% set x = expand(states.binary_sensor | selectattr("attributes.device_class", "eq", "motion"))
                    | sort(reverse=true, attribute='last_changed')
                    | list %}
        {% if (x | count > 0) and (((as_timestamp(now()) - as_timestamp(x[0].last_changed)) | int) < 1) %}
          {% if (area_name(x[0].entity_id) != None) %}
            {{ area_name(x[0].entity_id) }}
          {% else %}
            {{ x[0].name }}
          {% endif %}
        {% else %}
          {{ states('sensor.last_area_motion_detected') }}
        {% endif %}

This works, but I have some sensors (probably zwave) that report “Unknown”. How can i catch these messages.

It depends what you mean by “catch”.

To exclude them:

| rejectattr( 'state', 'eq', 'unknown' )

To include only them:

| selectattr( 'state', 'eq', 'unknown' )

Do you mean like this?

state: >-
        {% set x = expand(states.binary_sensor | selectattr("attributes.device_class", "eq", "motion")| rejectattr( "state", "eq", "Unknown" )
)
                    | sort(reverse=true, attribute='last_changed')
                    | list %}
        {% if (x | count > 0) and (((as_timestamp(now()) - as_timestamp(x[0].last_changed)) | int) < 1) %}
          {% if (area_name(x[0].entity_id) != None) %}
            {{ area_name(x[0].entity_id) }}
          {% else %}
            {{ x[0].name }}
          {% endif %}
        {% else %}
          {{ states('sensor.last_area_motion_detected') }}
        {% endif %}

It is not working yet.

This

Is not the same as:

The letter case matters, the quote types don’t.

I will test again, but the state in the gui is actually upper case.

The GUI lies to make things took pretty. Check Developer Tools / States for the actual state.

Just an FYI you don’t actually need the expand. states.binary_sensor is a list of all the binary sensors you have already expanded. That’s why you can use selectattr and rejectattr on it. Also the last | list is redundant, | sort already makes things into a list. I think you can simplify this first bit to just this:

{% set x = states.binary_sensor
                   | selectattr("attributes.device_class", "eq", "motion")
                   | rejectattr("state", "in", ["unknown", "unavailable"])
                   | sort(reverse=true, attribute='last_changed')
%}

Note: I also added an ignore unavailable as I assume you want to ignore binary_sensors in that state as well.

One other thought, this sensor is going to track changes for every single binary sensor in your system. It’s only going to change state when a binary sensor with device_class: motion changes but its going to run the template every time any binary sensor changes because you’re accessing the state object of every binary sensor to find out its device class. In addition to updating once a minute since you’re accessing now().

I point this out because I actually just tried something like this and ran into issues. I tried to use a sensor to tell me the entity ID of the last light which updated so I could trigger an automation which changed something about the room that light was in like so:

state: >-
  {{ (states.light
      | rejectattr('state', 'in', ['unknown', 'unavailable'])
      | sort(reverse=true, attribute='last_updated')
      | first).entity_id
  }}

I found it didn’t work very well. If changes to lights happened too close together then my sensor would just never have its state set to the entity ID of some of the lights. Like I knew the light changed and the sensor should’ve tried to run but the automation never ran and the sensor never showed that entity ID in its state history.

Now you’re doing area name rather then entity ID which is good since it means the template will have the same result more then mine did. But still something to keep an eye on if you’re planning to trigger an automation from this. The simpler the template the better since its gotta be lightning fast for how much its going to run.

Like maybe consider dropping the timestamp check? Why does it matter if it changed literally in the same second? Seems like a recipe for very weird bugs. Like if the motion actually occurred at .99 after the last whole second but this template didn’t get to that point until .02 of the next second.