Attributes in Template senor can only be simple objects (int, float, bool, string) if they are inside dict or list

Both legacy and new sensor accept only strings as attributes. At the same time integrations can but any kind of data to the attributes.

One use case where we need list and list of dict under attribute is following. Some users use NordPool electricity price sensor which has a lot of existing examples how to use it and how to visualize it. However, it only gives a partial energy price where everybody need to add different taxes, duties and additional costs.

There are many different ways to calculate final price. This makes it impossible to create a simple new custom integration for that. Without that it is a lot of work to do all those calculations for every specific use case.

It would be very handy for everyone to just create one matching template sensor for that and later use it instead of NordPool original sensor.

I have a ā€œtemplateā€ sensor (made in Node red) that has a list as attribute:

in template tool it returns this:

The possibility is there, not sure how to do it in yaml though.

I have multiple template sensors in which attributes are a list or a dict (or a native type like int or float)
And those are created in YAML

You might need to hide them in a template though.

attributes:
  list: "{{ [ 'this', 'is', 'a', 'list' ] }}"
  int: "{{ 1 }}"

You can have any object type as an attribute in template entities.

Are you sure it is still a real dict and not a JSON string? Check with template like {{ state_attr('sensor.smhi_hourly', 'hourly')['2022-09-30 15:00'] }}.

My sensor is like this:

sensor:
  - platform: template
    sensors:
      test_2:
        value_template: "xxx"
        attribute_templates:
          x-test1: >-
            {% set x = states.sensor.nordpool_kwh_ee_eur_3_10_02.attributes.raw_today|list %}
            {{ x|list }}
          x-test2: >-
            {% set xtest = ["aa", "bb", "cc"] %}
            {{ xtest|list }}

Btw, this is the only syntax that works. I canā€™t put list under attribute directly like this because attribute value must be string:

        attribute_templates:
          x-test2:
            - aa
            - bb
            - cc

Here are the results from my testsensor:

{{ state_attr('sensor.test_1' , 'x-test1')[1] }} gives me second character from JSON string [{'start': datā€¦:

{

and {{ state_attr('sensor.test_2' , 'x-test2')[1] }} gives me:

bb

Source is a list and {{ states.sensor.nordpool_kwh_ee_eur_3_10_02.attributes.raw_today[1] }} works:

{'start': datetime.datetime(2022, 9, 30, 1, 0, tzinfo=zoneinfo.ZoneInfo(key='Europe/Tallinn')), 'end': datetime.datetime(2022, 9, 30, 2, 0, tzinfo=zoneinfo.ZoneInfo(key='Europe/Tallinn')), 'value': 0.183}

Ahh, I didnā€™t notice that you sensor data comes from Node RED :smiley: Iā€™m looking a HA template sensor syntax that can do the same. A lot of integrations can do it and it works well but Template sensor has this limitations right now

Youā€™re doing somethign wrong in your templates. What your asking for already exists.

Look at this template I have that I made 17 months ago.

Now look at the output in the template editor

Iā€™d wager that raw_today has invalid syntax in it causing it to resolve to a string. Post all of raw_today and iā€™ll point it out.

{{ states.sensor.nordpool_kwh_ee_eur_3_10_02.attributes.raw_today }} is

[{'start': datetime.datetime(2022, 9, 30, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='Europe/Tallinn')), 'end': datetime.datetime(2022, 9, 30, 1, 0, tzinfo=zoneinfo.ZoneInfo(key='Europe/Tallinn')), 'value': 0.196}, {'start': datetime.datetime(2022, 9, 30, 1, 0, tzinfo=zoneinfo.ZoneInfo(key='Europe/Tallinn')), 'end': datetime.datetime(2022, 9, 30, 2, 0, tzinfo=zoneinfo.ZoneInfo(key='Europe/Tallinn')), 'value': 0.183}, ā€¦ {'start': datetime.datetime(2022, 9, 30, 21, 0, tzinfo=zoneinfo.ZoneInfo(key='Europe/Tallinn')), 'end': datetime.datetime(2022, 9, 30, 22, 0, tzinfo=zoneinfo.ZoneInfo(key='Europe/Tallinn')), 'value': 0.6}, {'start': datetime.datetime(2022, 9, 30, 22, 0, tzinfo=zoneinfo.ZoneInfo(key='Europe/Tallinn')), 'end': datetime.datetime(2022, 9, 30, 23, 0, tzinfo=zoneinfo.ZoneInfo(key='Europe/Tallinn')), 'value': 0.519}, {'start': datetime.datetime(2022, 9, 30, 23, 0, tzinfo=zoneinfo.ZoneInfo(key='Europe/Tallinn')), 'end': datetime.datetime(2022, 10, 1, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='Europe/Tallinn')), 'value': 0.428}]

{{ states.sensor.nordpool_kwh_ee_eur_3_10_02.attributes.raw_today[1] }} and any other index works fine in template devel tool. Conversion to sting most probably happens inside Template integration because based on schema the attribute must be a string

No. Thatā€™s not how this works. They all go through the same resolution code. Itā€™s because you have a datetime object in the output.

1 Like

To clarify typing is applied after the template is resolvedā€¦

So when you have objects that the template resolver expects, it can properly type it. Those objects are:

  • list
  • dictionary
  • int
  • float
  • bool
  • datetime object
  • timedelta object

If your list or dictionary does not resolve to a list or dictionary with SIMPLE objects (int, float, bool, string). Then the resulting output will be a string because the resolver is not recursive.

I.e.

{{ [{'x':0}] }} will resolve to a list of dictionaries

{{ [{'x':now()}] }} will resolve to a string because now() is not a simple object.

OK, I didnā€™t think that datetime might be a problem. Original integration puts it to the attribute and it can be used it in another template like this:

              {%- set prices = state_attr('sensor.nordpool_kwh_ee_eur_3_10_02', 'raw_today') -%}
              {% for price in prices %}
                {%- set week_day = as_timestamp(price.start) | timestamp_custom('%w') | float -%}
                {%- set oclock = as_timestamp(price.start) | timestamp_custom('%H') | float -%}  
                {%- if week_day != 0 and week_day != 6 and oclock > 7 and oclock < 23 -%}

So, Am I right that the problem is that this datetime object is deeply inside list and dict and resolver is not recursive? Is there any way to solve it vi template or it still needs some sort of development in code?

You can solve it by changing the datetime objects to strings. Otherwise the resolver would need to be recursive for lists and dictionaries.

I see but then this new template sensor is not a drop-in replacement for the original sensor any more. So, it is still missing feature. The subject just needs to be changed if it is not a simply string related problem. Thanks for pointing this out

Yes but I donā€™t think what you want is possible. The output of a template before itā€™s resolved is a string. We then test a few things to see what type it will be. The exec() function is used to test lists and dictionaries. Itā€™ll never get to the point where we can recursively search the dictionary because itā€™ll still be a string. This will always be a limitation.