#How do I unpack TemplateState?

39 messages · Page 1 of 1 (latest)

alpine socket
#

I have an automation triggered by an NFC tag. Looking at the trace, I saw the numeric user id. I'd like to get the username instead.

So far I have this:

variables:
  user_id: "{{ trigger.event.context.user_id }}"
  triggered_by: >-
    {{ ((states.person | selectattr('attributes.user_id','==', user_id)) | list)
    | first }}
  name: "{{ triggered_by.id }}"  

which gives me

user_id: 6505d8036ad4fd21abadb63fdde7f25d
triggered_by: >-
  <template TemplateState(<state person.tim=unknown; editable=True, id=tim,
  device_trackers=['device_tracker.sm_g970u1'],
  user_id=6505d8036ad4fd21abadb63fdde7f25d,
  entity_picture=/api/image/serve/235934d9f76d905aa67804cfe33388de/512x512,
  friendly_name=Tim @ 2024-10-18T14:09:11.337636-04:00>)>
name: null

I'm trying to select the id so that I have the value tim. I thought I should be able to do something like triggered_by.id, or triggered_by.state.id, or state_attr(triggered_by, 'id'), or ... something along those lines. But everything I've tried results in a null value or an error on that step.

pale wigeon
#

try:
name: "{{ triggered_by.attributes.id }}"

#

in the raw state objects all the attributes are actually a sub-entry in a dict at attributes

alpine socket
#

when I do triggered_by.attributes I get an empty string. triggered_by.attributes.id results in Error: UndefinedError: 'str object' has no attribute 'attributes'

pale wigeon
#

Hmmm that's strange

alpine socket
#

hmm, yeah, that works for me in the template editor as well.

pale wigeon
#

what happens if you replace triggered_by with the template that sets the value of it

#

wondering if it's some weirdness in referring to other variables in the block

alpine socket
#

yup, that was it. Probably triggered_by is a string value.

    {{ ((states.person | selectattr('attributes.user_id','==', user_id))|list
    |first).attributes.id }}
``` works.
pale wigeon
#

you might also want friendly_name rather than id

hardy fractal
#
variables:
  user_id: "{{ trigger.event.context.user_id }}"
  triggered_by: >-
    {{ states.person | selectattr('attributes.user_id','==', user_id) | map(attribute='name') | list | first }}
  name: "{{ triggered_by }}"
#

state objects can't be deserialized, they end up being a string at all times.

#

@pale wigeon @alpine socket ^

ocean nexus
#
triggers:
  - trigger: tag
    tag_id: 6bc6c7ad-41c3-4a46-8a24-c909276335d3
conditions: []
actions:
  - variables:
      user_id: "{{ trigger.event.context.user_id }}"
      user: >-
        {{ states.person | selectattr('attributes.user_id', 'eq', trigger.event.context.user_id) | list | first }}

This works for me.

#

(Only for setting a variable to be clear)

hardy fractal
#

that should return a state object, which the template resolver shouldn't be able to resolve

#

because the __repr__ of it isn't something that can be turned into an object

#

it should return a mess like this:

ocean nexus
#

Yeah, you'd need to get whatever properties you want from the object before moving on.

hardy fractal
#
<template TemplateState(<state person.petro=home; editable=True, id=50ff9ab2efb14c7e8e713fe8aa239043, device_trackers=['device_tracker.petro', 'device_tracker.petro_2'], gps_accuracy=19, source=device_tracker.petro_2, user_id=7d4eefa8059f4e1fa99401b87506dcb6, entity_picture=/api/image/serve/a61698f131d097bc3c8d066425675ad5/512x512, friendly_name=Mike @ 2024-10-18T15:02:22.897173-04:00>)>
#

heh, apparently my mobile app fucked up at some point, i have an _2 in there

ocean nexus
#

But if you give yourself the entity id of the person, you can always grab the whole object again later as needed

pale wigeon
#

Thanks for explaining @hardy fractal - not a variable issue, a state object issue

#

Was bugging me

alpine socket
hardy fractal
#

that may not contain all information, it's only use is to ensure that python knows it's a unique object. When you print something to text, python uses __str__ and if it doesn't exist, it uses __repr__ so that's all that is. You won't get all the info you want out of the object by looking at the __repr__

#

map accesses properties on objects

#

.attributes is a property on the state object

#

attributes is a dictionary, which means to access things inside it, you have to use jinjas dot notation or __getitem__

#

which is the square bracket notation

#

i.e. state_object.attributes.id or state_object.attributes['id']

#

or state_object.attributes.get('id')

#

you can only access properties via dot notation

#

and map only has access to properties

#

techinically map only has access to __getitem__

alpine socket
#

ah, ok. So the properties are .name, .object_id, .attributes, etc and some of the top level properties are also available in .attributes but not necessarily under the same names.
code is probably something like:

state.name = state.attributes.friendly_name if (state.attributes.friendly_name) else state.attributes.id

state.object_id = state.attributes.id
hardy fractal
#

name and friendlyname may not be the same