How to return attribute that contains a string?

I want to know how to extract the attribute from a text contained in it. How to do that?

In Habitica integration each daily task is an attribute of the entity sensor.habitica_myusername_dailys

So the attributes will change as I change those tasks.

In the following (simplified) example, since I am looking for the attribute refering to the “cooking” task, what template would return ‘37e06aeb-0a4b-4a19-a087-9390c6f5b323’, knowing only that the text is “cooking” ?

states.sensor.habitica_myusername_dailys.attributes gives this in the template dev tool:

{
  "37e06aeb-0a4b-4a19-a087-9390c6f5b323": {
    "repeat": {
      "m": false,
      "t": false,
      "w": false,
      "th": false,
      "f": false,
      "s": false,
      "su": true
    },
    "group": {
      "completedBy": {},
      "assignedUsers": []
    },
    "frequency": "weekly",
    "every_x": 1,
    "next_due": [
      "2024-01-14T05:00:00.000Z",
      "2024-01-21T05:00:00.000Z",
      "2024-01-28T05:00:00.000Z",
      "2024-02-04T05:00:00.000Z",
      "2024-02-11T05:00:00.000Z",
      "2024-02-18T05:00:00.000Z"
    ],
    "yester_daily": true,
    "type": "daily",
    "priority": 1.5,
    "start_date": "2024-01-07T05:00:00.000Z",
    "created_at": "2024-01-07T22:01:28.302Z",
    "text": "cooking",
    "is_due": true
  },
  "395ea8a4-5a8d-4bc4-9d56-eb6415ca9571": {
    "repeat": {
      "m": false,
      "t": false,
      "w": false,
      "th": true,
      "f": false,
      "s": false,
      "su": false
    },
    "group": {
      "completedBy": {},
      "assignedUsers": []
    },
    "frequency": "weekly",
    "every_x": 1,
    "next_due": [
      "2024-01-11T05:00:00.000Z",
      "2024-01-18T05:00:00.000Z",
      "2024-01-25T05:00:00.000Z",
      "2024-02-01T05:00:00.000Z",
      "2024-02-08T05:00:00.000Z",
      "2024-02-15T05:00:00.000Z"
    ],
    "yester_daily": true,
    "type": "daily",
    "value": 1.0240441476547515,
    "priority": 0.1,
    "start_date": "2023-12-18T05:00:00.000Z",
    "created_at": "2023-12-19T02:55:54.830Z",
    "text": "cleaning"
  } 

In the context of my question, let’s just assume that “cooking” will always be found, and be found once only.

Copy-paste the following template into the Template Editor and confirm it reports the desired value.

{% set x = states.sensor.habitica_myusername_dailys.attributes %}
{% set ns = namespace(id='') %}
{% for k in x if x[k]['text'] == 'cooking' %}
{% set ns.id = k %}
{% endfor %}
{{ ns.id }}

EDIT

Overkill alert: The use of namespace isn’t needed for this application because the desired value isn’t modified within the for-loop. Here’s the stripped down version:

{% set x = states.sensor.habitica_myusername_dailys.attributes %}
{% for k in x if x[k]['text'] == 'cooking' %}
{{ k }}
{% endfor %}

NOTE

This is based on the assumptions you made that there will always be one and only one entry with cooking.If there’s a chance of multiple instances, you need to explain which one you want to report (or all of them).

1 Like

I feel like there’s got to be a better way using filters, but this seems to work with what you’ve provided:

{% set a = states.sensor.habitica_myusername_dailys.attributes %}
{% for key, value in a.items() if value.text == "cooking" %}
{{ key }}
{% endfor %}

EDIT: Corrected typo noted below

1 Like

I guess I shouldn’t have bothered with namespace for this particular application. The for-loop will either spit out a value or not.

FWIW, I was also looking for a way to do this in a one-liner but it always gravitated to iterating through the dictionary’s keys.

1 Like

The result is empty in all cases.

Maybe if you first try by creating an entity with the same values I presented you could test it to get a correct result. I wish I could find some good tutorials about Jinja2 templates to figure those things out. Just the Jinja docs isn’t enough to really grasp some things, sometimes.

I’m sorry BOTH ways work!!

It was my mistake to not correct some values since there was some fictive info in my example. (the task was not “cooking” in my system. :exploding_head: My bad.)

Thanks a lot!!

What is the intended application for this template? Now that you can find the attribute’s name, how will you use it?

Habitica is a task and habits manager. If the sensor says that my fitness training is due today, then in my morning routine HA will send an actionable notification on my phone. Once the training is finished, I will click “accomplished” in the notification. Then HA will send to Habitica that the task is done, using its attribute.

This is something that can be done manually, finding for each task its attribute in the dev tool. But I may want something more flexible, since I may add or remove some tasks in the Habitica app, and that way I don’t have to reprogram all my routine automations. For example, if I delete a task “Fitness”, and then I create it again, it’s assigned attribute will be different, but can be programmatically found again.

I may also want to simply perform the “task done” action for some new tasks added in Habitica by using the actual words I used when creating those tasks without bothering checking in the dev tools.

This works if we remove the extra ) after “cooking”. (It’s just a typo)

I am also curious, for the benefit of my Jinja education, if there’s a way to achieve the same thing using filters.

1 Like

Hi all,
I think I have a similar topic. New to templates and you might be able to help me. I want to extract a string from an attribute which has nested many more attributes within.
See simplified example:

{{ state_attr('entity', 'attribute') }}

delivers following result:

{
  "map_present": 1,
  "in_cleaning": 0,
  "in_returning": 0,
  "in_fresh_state": 1,
  "lab_status": 3,
  "water_box_status": 1,
  "back_type": -1,
  "wash_phase": 0,
  "wash_ready": 0,
  "fan_power": 102,
  "dnd_enabled": 0,
  "map_status": 11,
  "is_locating": 0,
  "lock_status": 0,
  "water_box_mode": 202,
  "water_box_carriage_status": 0,
  "mop_forbidden_enable": 0,
  "camera_status": 389,
  "is_exploring": 0,
  "home_sec_status": 0,
  "home_sec_enable_password": 0,
  "adbumper_status": [
    0,
    0,
    0
  ],
  "water_shortage_status": 0,
  "dock_type": 1,
  "dust_collection_status": 0,
  "auto_dust_collection": 1
}

Now say I want to extract only “map_status”: 11 and especially the value 11 itself, which I then use as a sensor in my integration.

Can you help? Right forum thread? Was searching whole morning and now posting my first question in the forum :slight_smile:
Thanks!

ok could not give up and found the solution.

state: "{% for key, value in states.entity.attributes.items() %}{% if 'map_status' in value | string %}{{ value.map_status }}{% endif %} {% endfor %}"

Here’s an improved version of my solution, returning the attributes list of all the tasks containing some text. So, no error if not found (empty list), neither if multiple results.

{% set task_name = 'Training' %}
{% set x = states.sensor.habitica_myusername_dailys.attributes %}
{%- set ns = namespace(liste = []) %}
{%- for k in x if ('text' in x[k] and task_name in
x[k]['text'] ) %}
{%- set ns.liste = ns.liste + [k] %}
{%- endfor %}
{{ ns.liste }}

There is no need for a loop to retrieve the value from a simple sub-attribute.

{{ state_attr('entity', 'attribute')['map_status'] }}