Help needed to update 3 year old templating example

Hey folks,

I’m trying to mimic the “cat tracking” from this Reddit thread. While I was able to work out with the ESPHome folks how to make this work on my bluetooth proxies (and added proxies to each room in my condo), I’ve hit a wall with trying to get this template to work:

- platform: template
  sensors:
    cat_location:
      friendly_name: Tuck’s Location
      entity_id:
        - sensor.outside_bluetooth_proxy_tuck_outside_rssi
        - sensor.back_basement_bluetooth_proxy_tuck_back_basement_rssi
        - sensor.basement_bluetooth_proxy_tuck_basement_rssi
        - sensor.ben_bedroom_bluetooth_proxy_tuck_ben_bedroom_rssi
        - sensor.hallway_bluetooth_proxy_tuck_hallway_rssi
        - sensor.guest_bedroom_bluetooth_proxy_tuck_guest_bedroom_rssi
        - sensor.upstairs_bathroom_bluetooth_proxy_tuck_upstairs_bathroom_rssi
        - sensor.living_room_bluetooth_proxy_tuck_living_room_rssi
        - sensor.downstairs_bathroom_bluetooth_proxy_tuck_downstairs_bathroom_rssi
        - sensor.front_door_bluetooth_proxy_tuck_front_door_rssi
        - sensor.kitchen_bluetooth_proxy_tuck_kitchen_rssi
      icon_template: mdi:cat
      value_template: >-
        {{
          [
             (states("sensor.outside_bluetooth_proxy_tuck_outside_rssi"), "Outside")
             (states("sensor.back_basement_bluetooth_proxy_tuck_back_basement_rssi"), "Back Basement")
             (states("sensor.basement_bluetooth_proxy_tuck_basement_rssi"), "Main Basement")
             (states("sensor.living_room_bluetooth_proxy_tuck_living_room_rssi"), "Living Room")
             (states("sensor.downstairs_bathroom_bluetooth_proxy_tuck_downstairs_bathroom_rssi"), "Downstairs Bathroom")
             (states("sensor.kitchen_bluetooth_proxy_tuck_kitchen_rssi"), "Kitchen")
             (states("sensor.front_door_bluetooth_proxy_tuck_front_door_rssi"), "Front Door")
             (states("sensor.hallway_bluetooth_proxy_tuck_hallway_rssi"), "Hallway")
             (states("sensor.ben_bedroom_bluetooth_proxy_tuck_ben_bedroom_rssi"), "Ben Bedroom")
             (states("sensor.upstairs_bathroom_bluetooth_proxy_tuck_upstairs_bathroom_rssi"), "Upstairs Bathroom")
             (states("sensor.guest_bedroom_bluetooth_proxy_tuck_guest_bedroom_rssi"), "Guest Bedroom")
          ]
          |rejectattr(0, "equalto", "nan")
          |rejectattr(0, "equalto", "unavailable")
          |min(default=(0, "Unknown"))
          |last()
        }}

It appears from what I’m seeing in the logs that this type of configuration has been deprecated, but even after looking over the configuration variables for templates, I’m still not sure how to resolve this.

Basically, what I’m looking to do is what the OP in that Reddit thread managed to do: figure out what room the cat(s) are in based on which proxy they’re closest to. This may seem like a ridiculous use case, but one of my cats has FHV and can get quite sick very quickly, so trying to find her during those times can be trying. At least with the tracker I’ll know what room to be concetrating on.

Apologies in advance for being an idiot.

If you assign an area to each sensor it makes the template a bit easier.

template:
  - sensor:
      - name: Tuck’s Location
        state: >
          {% set sensors = [ 'sensor.tuck_outside_rssi', 
          'sensor.tuck_back_basement_rssi', 'sensor.tuck_basement_rssi',
          'sensor.tuck_ben_bedroom_rssi', 'sensor.tuck_hallway_rssi',
          'sensor.tuck_guest_bedroom_rssi', 'sensor.tuck_upstairs_bathroom_rssi',
          'sensor.tuck_living_room_rssi', 'sensor.tuck_downstairs_bathroom_rssi',
          'sensor.tuck_front_door_rssi', 'sensor.tuck_kitchen_rssi' ] %}
          {% set close_val = expand( sensors | reject('is_state', ['unavailable','unknown'])) 
          | map(attribute='state') | map('int') | sort | last %}
          {% set match = sensors | select('is_state', close_val|string) | first %}
          {{ area_name(match) }}
        icon: mdi:cat

Another option is to use a mapper, kind of like what was being done in the original.

Mapper Example
state: >
  {% set mapper = {
    "sensor.outside_bluetooth_proxy_tuck_outside_rssi": "Outside",
    "sensor.back_basement_bluetooth_proxy_tuck_back_basement_rssi": "Back Basement",
    "sensor.basement_bluetooth_proxy_tuck_basement_rssi": "Main Basement",
    "sensor.living_room_bluetooth_proxy_tuck_living_room_rssi": "Living Room",
    "sensor.downstairs_bathroom_bluetooth_proxy_tuck_downstairs_bathroom_rssi": "Downstairs Bathroom",
    "sensor.kitchen_bluetooth_proxy_tuck_kitchen_rssi": "Kitchen",
    "sensor.front_door_bluetooth_proxy_tuck_front_door_rssi": "Front Door",
    "sensor.hallway_bluetooth_proxy_tuck_hallway_rssi": "Hallway",
    "sensor.ben_bedroom_bluetooth_proxy_tuck_ben_bedroom_rssi": "Ben Bedroom",
    "sensor.upstairs_bathroom_bluetooth_proxy_tuck_upstairs_bathroom_rssi": "Upstairs Bathroom",
    "sensor.guest_bedroom_bluetooth_proxy_tuck_guest_bedroom_rssi": "Guest Bedroom" }  %}
  {% set close_val = mapper.keys() | map('states')
  | map('int', -200) | sort() | last %}
  {% set match = mapper.keys() | select('is_state', close_val | string) | first %}
  {{ mapper.get(match) }}

1 Like

This is very, very close!

The only thing is, it’s showing me the furthest away location instead of the closest. I tried changing “first” to “last” but that just changed the state to unavailable (front door/outside were also are unknown - they’re both outdoors). I removed them from the state/sensors but still not quite sure how to make that last little leap.

Reverse the sort filter… sort(attribute='state', reverse=true)

Also, make sure you get the reject filter I added to filter out unknowns and unavailables.

1 Like

Hmm. Maybe I’ve done something wrong (side note - my code was wrong initially, but I updated it, I think while you were replying). This is what I’ve put in:

template:
  - sensor:
      - name: Tuck’s Location
        state: >
          {% set sensors = [ 'sensor.outside_bluetooth_proxy_tuck_outside_rssi', 
          'sensor.back_basement_bluetooth_proxy_tuck_back_basement_rssi', 'sensor.basement_bluetooth_proxy_tuck_basement_rssi',
          'sensor.ben_bedroom_bluetooth_proxy_tuck_ben_bedroom_rssi', 'sensor.hallway_bluetooth_proxy_tuck_hallway_rssi',
          'sensor.guest_bedroom_bluetooth_proxy_tuck_guest_bedroom_rssi', 'sensor.upstairs_bathroom_bluetooth_proxy_tuck_upstairs_bathroom_rssi',
          'sensor.living_room_bluetooth_proxy_tuck_living_room_rssi', 'sensor.downstairs_bathroom_bluetooth_proxy_tuck_downstairs_bathroom_rssi',
          'sensor.front_door_bluetooth_proxy_tuck_front_door_rssi', 'sensor.kitchen_bluetooth_proxy_tuck_kitchen_rssi' ] %}
          {{  area_name( expand(sensors| reject('is_state', ['unavailable','unknown'])) 
          | sort(attribute='state', reverse=true) | map(attribute='entity_id') | first ) }}
        icon: mdi:cat

But this is what’s showing up:


It was briefly showing “Upstairs Hallway” as the location (which wouldn’t be correct - the bluetooth tracker is a few feet away from the “Living Room” proxy) but has been “unknown” for a bit now.

Should I try the mapper version, instead?

I forgot to cast the values to integers before doing the sort. Most of the time, it wouldn’t be an issue since BLE rssi is usually a two digit number. If Upstairs hallway had a value of -100, that would cause a brief false lowest. I’ve adjusted both templates above.

1 Like

That did the trick! Thank you so much!!

Hey friend. This has recently started kicking back some stuff in the system logs. I have no idea what any of this means - might you be able to help me make sense of it?

Logger: homeassistant.helpers.template
Source: helpers/template.py:665
First occurred: 3:27:46 PM (135 occurrences)
Last logged: 3:27:48 PM

Template variable warning: No last item, sequence was empty. when rendering '{% set sensors = [ 'sensor.outside_bluetooth_proxy_tuck_outside_rssi', 'sensor.back_basement_bluetooth_proxy_tuck_back_basement_rssi', 'sensor.basement_bluetooth_proxy_tuck_basement_rssi', 'sensor.ben_bedroom_bluetooth_proxy_tuck_ben_bedroom_rssi', 'sensor.hallway_bluetooth_proxy_tuck_hallway_rssi', 'sensor.guest_bedroom_bluetooth_proxy_tuck_guest_bedroom_rssi', 'sensor.upstairs_bathroom_bluetooth_proxy_tuck_upstairs_bathroom_rssi', 'sensor.living_room_bluetooth_proxy_tuck_living_room_rssi', 'sensor.downstairs_bathroom_bluetooth_proxy_tuck_downstairs_bathroom_rssi', 'sensor.front_door_bluetooth_proxy_tuck_front_door_rssi', 'sensor.kitchen_bluetooth_proxy_tuck_kitchen_rssi' ] %} {% set close_val = expand( sensors | reject('is_state', ['unavailable','unknown'])) | map(attribute='state') | map('int') | sort | last %} {% set match = sensors | select('is_state', close_val|string) | first %} {{ area_name(match) }}'
Template variable warning: No first item, sequence was empty. when rendering '{% set sensors = [ 'sensor.outside_bluetooth_proxy_tuck_outside_rssi', 'sensor.back_basement_bluetooth_proxy_tuck_back_basement_rssi', 'sensor.basement_bluetooth_proxy_tuck_basement_rssi', 'sensor.ben_bedroom_bluetooth_proxy_tuck_ben_bedroom_rssi', 'sensor.hallway_bluetooth_proxy_tuck_hallway_rssi', 'sensor.guest_bedroom_bluetooth_proxy_tuck_guest_bedroom_rssi', 'sensor.upstairs_bathroom_bluetooth_proxy_tuck_upstairs_bathroom_rssi', 'sensor.living_room_bluetooth_proxy_tuck_living_room_rssi', 'sensor.downstairs_bathroom_bluetooth_proxy_tuck_downstairs_bathroom_rssi', 'sensor.front_door_bluetooth_proxy_tuck_front_door_rssi', 'sensor.kitchen_bluetooth_proxy_tuck_kitchen_rssi' ] %} {% set close_val = expand( sensors | reject('is_state', ['unavailable','unknown'])) | map(attribute='state') | map('int') | sort | last %} {% set match = sensors | select('is_state', close_val|string) | first %} {{ area_name(match) }}'
Template variable warning: No last item, sequence was empty. when rendering '{% set sensors = [ 'sensor.outside_bluetooth_proxy_lily_outside_rssi', 'sensor.back_basement_bluetooth_proxy_lily_back_basement_rssi', 'sensor.basement_bluetooth_proxy_lily_basement_rssi', 'sensor.ben_bedroom_bluetooth_proxy_lily_ben_bedroom_rssi', 'sensor.hallway_bluetooth_proxy_lily_hallway_rssi', 'sensor.guest_bedroom_bluetooth_proxy_lily_guest_bedroom_rssi', 'sensor.upstairs_bathroom_bluetooth_proxy_lily_upstairs_bathroom_rssi', 'sensor.living_room_bluetooth_proxy_lily_living_room_rssi', 'sensor.downstairs_bathroom_bluetooth_proxy_lily_downstairs_bathroom_rssi', 'sensor.front_door_bluetooth_proxy_lily_front_door_rssi', 'sensor.kitchen_bluetooth_proxy_lily_kitchen_rssi' ] %} {% set close_val = expand( sensors | reject('is_state', ['unavailable','unknown'])) | map(attribute='state') | map('int') | sort | last %} {% set match = sensors | select('is_state', close_val|string) | first %} {{ area_name(match) }}'
Template variable warning: No first item, sequence was empty. when rendering '{% set sensors = [ 'sensor.outside_bluetooth_proxy_lily_outside_rssi', 'sensor.back_basement_bluetooth_proxy_lily_back_basement_rssi', 'sensor.basement_bluetooth_proxy_lily_basement_rssi', 'sensor.ben_bedroom_bluetooth_proxy_lily_ben_bedroom_rssi', 'sensor.hallway_bluetooth_proxy_lily_hallway_rssi', 'sensor.guest_bedroom_bluetooth_proxy_lily_guest_bedroom_rssi', 'sensor.upstairs_bathroom_bluetooth_proxy_lily_upstairs_bathroom_rssi', 'sensor.living_room_bluetooth_proxy_lily_living_room_rssi', 'sensor.downstairs_bathroom_bluetooth_proxy_lily_downstairs_bathroom_rssi', 'sensor.front_door_bluetooth_proxy_lily_front_door_rssi', 'sensor.kitchen_bluetooth_proxy_lily_kitchen_rssi' ] %} {% set close_val = expand( sensors | reject('is_state', ['unavailable','unknown'])) | map(attribute='state') | map('int') | sort | last %} {% set match = sensors | select('is_state', close_val|string) | first %} {{ area_name(match) }}'

I do have one bluetooth proxy that is routinely offline for reasons - the front_door one - should I remove that from the equation?

First, while it is offline, check the state of the front door sensor. If it is ‘none’, you should be able to fix the issue by adding a third option to the reject filter, changing reject('is_state', ['unavailable','unknown'] to reject('is_state', ['unavailable','unknown', 'none'])… if that doesn’t work, try removing the sensor that you have offline from the list.

That didn’t resolve it (that sensor was showing as unavailable), but it’s ended up being moot. Both cat trackers had their backs fall off, and I still don’t know where one of them is (or it’s battery!). So this experiment was a failure.

But I very much appreciate your efforts!