Help copying a sensor with attributes

I have a sensor with power prices (from Tibber), containing attributes with an array (?) of electricity prices each hour and gets updated each day at 1pm. I would like to make a template sensor as a copy of that sensor, where I loop through the “total” price and change it to the real value (after i.e. the government electricity support and other stuff has been subtracted). I can do the if’s and else’s but could a used with more knowledge than me steer me into how to read the attributes and how to write them in the new sensor, that would be very much appreciated.

1 Like

What do you want to do with the price to make it “real”? Here’s an example of how you can read through the attributes and create a copied object with multiplication and addition operations on the prices: as an example, I’ve multiplied by 0.9 then subtracted 0.1. Paste this into the Developer Tools / Template editor.

{% set a = {'today': [
              {'total': 0.8922, 'startsAt': '2023-11-23T00:00:00+01:00'},
              {'total': 0.7724, 'startsAt': '2023-11-23T01:00:00+01:00'},
           ]} %}

{% set sl = a['today']|map(attribute='startsAt')|list %}
{% set tl = a['today']|map(attribute='total')
             |map('multiply',0.9)
             |batch(1)|map('sum',start=-0.1)
             |list %}
{{ sl }}
{{ tl }}
{% set ns = namespace(today=[]) %}
{% for i in range(tl|count) %}
  {% set ns.today = ns.today + [{'total': tl[i], 'startsAt': sl[i] }] %}
{% endfor %}

{{ a }}
{{ {'today': ns.today} }}

There’s no add filter available so I’ve had to bodge one together.

Once you have that output, you can create a template sensor with the new dictionary object set as the attributes.

Sorry, bad explanation on my part.

We have a government support kicking in at a certain price-point, where they cover 90% of the price above that. In addition there is a fixed “energy-tax” per kW to be added, differing according to what hour of the day it is.

So, basically I need to loop through every attribute, check the hour, then subtract the calculated government support and add the calculated energy-tax.

I’ll be using the new sensor to show apex-charts, calculate how many hours (kWh) my EV will get charged in the coming hours with the current limit (an input number with a price limit) and probably lots of other fun stuff, if only I had that new sensor with real prices.

Oh, OK. The namespace operation as in my example is the way to read through the existing entries and change as required:

{% set ns = namespace(output=[]) %}
{% for item in state_attr('sensor.tibber_prices', 'today') %}
{% set newprice = item['total'] MODIFIED AS REQUIRED HERE %}
{% set ns.output = ns.output + [{'startsAt': item['startsAt'],
                                 'total': newprice}] %}
{% endfor %}

Then ns.output contains a copy of the today list but with the updated prices.

This is my setup with price classification and a sensor with the price after subsidising:

sensor:
  - name: Pris strøm
    icon: mdi:currency-usd
    state: >-
      {% set price_cur = states('sensor.nordpool_kwh_oslo_nok_2_10_025') | float(0) %}
      {% set price_avg = state_attr('sensor.nordpool_kwh_oslo_nok_2_10_025', 'average') | float(0) %}
      {% if price_cur < 0 %}
        Negativ
      {% elif price_cur == 0.00 or price_avg == 0 %}
        Gratis
      {% else %}
        {% set price_ratio = (price_cur / price_avg) %}
        {% if price_ratio >= 1.4 %}
          Veldig dyr
        {% elif price_ratio >= 1.15 %}
          Dyr
        {% elif price_ratio <= 0.6 %}
          Veldig billig
        {% elif price_ratio <= 0.9 %}
          Billig
        {% else %}
          Normal
        {% endif %}
      {% endif %}

  - name: strøm inkl rabatt
    icon: mdi:currency-usd
    state: >-
      {% set original_value = states('sensor.nordpool_kwh_oslo_nok_2_10_025') | float %}
      {% if original_value > 0.70 %}
        {{ (0.70 + (original_value - 0.70) * 0.1) | round(2) }}
      {% else %}
        {{ original_value | round(2) }}
      {% endif %}

Great, thanks!
So, is there a quick way of transferring the ns.output into attributes in a new sensor, making the new sensor a copy of tibber_prices but with real prices?
BTW, the tibber_prices is updated at 1pm each day and until midnight it will have a ‘tomorrow:’ attribute too, but being steered in the right direction I think(/hope) I’m able to deal with that myself.

Ok, I’ll answer my own last q:

        attributes:
          today: >-
            {% set ns = namespace(output=[]) %}
            {% for item in state_attr('sensor.tibber_prices', 'today') %}
            {% set newprice = (item['total'] + <CALCULATION> %}
            {% set ns.output = ns.output + [{'total': newprice,'startsAt': item['startsAt']}] %}
            {% endfor %}
            {{ ns.output }}
          tomorrow: >-
1 Like

I very much appreciate the help here.
I now have a new sensor with attributes containing adjusted prices:

attributes:
  today: >-
      {% set factor = states('input_number.elprice_support_percent')|float  %}
      {% set limit = states('input_number.stromstotte_innslag_nok_inkl_mva')|float(3) %}
      {% set energytaxD = states.input_number.nettleie_energiledd_dag.state|float %}
      {% set energytaxN = states.input_number.nettleie_energiledd_natt.state|float %}
      {% set ns = namespace(output=[]) %}
      {% for item in state_attr('sensor.tibber_prices', 'today') %}
        {% if item['total'] > limit %}
          {% set newprice = (item['total'] - (item['total'] - limit)|float * (factor / 100))|round(4,'round-to-even',0) %}
        {% else %}
          {% set newprice = item['total']|round(4) %}
        {% endif %}
        {% if((as_timestamp(item['startsAt'])|timestamp_custom('%a') == 'sat') or (as_timestamp(item['startsAt'])|timestamp_custom('%a') == 'sun')) %}
          {% set newprice = (newprice + energytaxN)|round(4,'round-to-even',0) %}
        {% else %}
          {% if((as_timestamp(item['startsAt'])|timestamp_custom('%-H')|int > 6) and (as_timestamp(item['startsAt'])|timestamp_custom('%-H')|int < 22)) %}
            {% set newprice = (newprice + energytaxD)|round(4,'round-to-even',0) %}
          {% else %}
            {% set newprice = (newprice + energytaxN)|round(4,'round-to-even',0) %}
          {% endif %}
        {% endif %}
        {% set ns.output = ns.output + [{'total': newprice,'startsAt': item['startsAt']}] %}
      {% endfor %}
      {{ ns.output }}

However, the attribute format in the new sensor is not correct (any my apex-chart got confused).

Existing sensor:

New sensor:

Any way around this?

made some improvements in your template, maybe it solves the issue as well :slight_smile:

      {% set factor = states('input_number.elprice_support_percent') | float  %}
      {% set limit = states('input_number.stromstotte_innslag_nok_inkl_mva') | float(3) %}
      {% set energytaxD = states('input_number.nettleie_energiledd_dag') | float %}
      {% set energytaxN = states('input_number.nettleie_energiledd_natt') | float %}
      {% set ns = namespace(output=[]) %}
      {% for item in state_attr('sensor.tibber_prices', 'today') %}
        {% if item['total'] > limit %}
          {% set newprice = (item['total'] - (item['total'] - limit) * (factor / 100)) | round(4, default=0) %}
        {% else %}
          {% set newprice = item['total'] | round(4) %}
        {% endif %}
        {% if as_datetime(item['startsAt']).weekday() in [5, 6] %}
          {% set newprice = (newprice + energytaxN) | round(4, default=0) %}
        {% else %}
          {% if 6 < as_datetime(item['startsAt']).hour < 22 %}
            {% set newprice = (newprice + energytaxD) | round(4, default=0) %}
          {% else %}
            {% set newprice = (newprice + energytaxN) | round(4, default=0) %}
          {% endif %}
        {% endif %}
        {% set ns.output = ns.output + [ { 'total': newprice, 'startsAt': item['startsAt'] } ] %}
      {% endfor %}
      {{ ns.output }}

BTW round-to-even isn’t a valid method for the round filter

Thanks! Unfortunately didn’t fix my problem, though.
The attributes are still being listed as in the bottom screenshot in my last post.

how is shown when you click on the entity id, it should show the attributes in yaml structure then.

Unfortunately not

Can you post the complete adjusted template sensor code please? I can’t recreate your issue nor see a problem in what you’ve posted.

My test:

- sensor:    
    - name: test
      state: "Testing"
      attributes:
        today: >-
          {% set r = range(6) %}
          {% set ns = namespace(output=[]) %}
          {% for i in r %}
            {% set ns.output = ns.output + [{'string': i|string, 'number': i}] %}
          {% endfor %}
          {{ ns.output }}
        tomorrow: >-
          {% set r = range(6,11) %}
          {% set ns = namespace(output=[]) %}
          {% for i in r %}
            {% set ns.output = ns.output + [{'string': i|string, 'number': i}] %}
          {% endfor %}
          {{ ns.output }}

Result:

The complete template sensor:

  - sensor:
      - name: "Tibber prices adjusted"
        unique_id: tibber_prices_adjusted
        state: >-
            {% if states.sensor.tibber_prices.state %}
              {{states.sensor.tibber_prices.state}}
            {% else %}
              'Error'
            {% endif %}
        attributes:
          today: >-
            {% set factor = states('input_number.elprice_support_percent') | float  %}
            {% set limit = states('input_number.stromstotte_innslag_nok_inkl_mva') | float %}
            {% set energytaxD = states('input_number.nettleie_energiledd_dag') | float %}
            {% set energytaxN = states('input_number.nettleie_energiledd_natt') | float %}
            {% set ns = namespace(output=[]) %}
            {% for item in state_attr('sensor.tibber_prices', 'today') %}
              {% if item['total'] > limit %}
                {% set newprice = (item['total'] - (item['total'] - limit) * (factor / 100)) | round(4, default=0) %}
              {% else %}
                {% set newprice = item['total'] | round(4, default=0) %}
              {% endif %}
              {% if as_datetime(item['startsAt']).weekday() in [5, 6] %}
                {% set newprice = (newprice + energytaxN) | round(4, default=0) %}
              {% else %}
                {% if 6 < as_datetime(item['startsAt']).hour < 22 %}
                  {% set newprice = (newprice + energytaxD) | round(4, default=0) %}
                {% else %}
                  {% set newprice = (newprice + energytaxN) | round(4, default=0) %}
                {% endif %}
              {% endif %}
              {% set ns.output = ns.output + [ { 'total': newprice, 'startsAt': item['startsAt']} ] %}
            {% endfor %}
            {{ ns.output }}
          tomorrow: >-
            {% set factor = states('input_number.elprice_support_percent') | float  %}
            {% set limit = states('input_number.stromstotte_innslag_nok_inkl_mva') | float %}
            {% set energytaxD = states('input_number.nettleie_energiledd_dag') | float %}
            {% set energytaxN = states('input_number.nettleie_energiledd_natt') | float %}
            {% set ns = namespace(output=[]) %}
            {% for item in state_attr('sensor.tibber_prices', 'tomorrow') %}
              {% if item['total'] > limit %}
                {% set newprice = (item['total'] - (item['total'] - limit) * (factor / 100)) | round(4, default=0) %}
              {% else %}
                {% set newprice = item['total'] | round(4, default=0) %}
              {% endif %}
              {% if as_datetime(item['startsAt']).weekday() in [5, 6] %}
                {% set newprice = (newprice + energytaxN) | round(4, default=0) %}
              {% else %}
                {% if 6 < as_datetime(item['startsAt']).hour < 22 %}
                  {% set newprice = (newprice + energytaxD) | round(4, default=0) %}
                {% else %}
                  {% set newprice = (newprice + energytaxN) | round(4, default=0) %}
                {% endif %}
              {% endif %}
              {% set ns.output = ns.output + [ { 'total': newprice, 'startsAt': item['startsAt']} ] %}
            {% endfor %}
            {{ ns.output }}
        icon: mdi:currency-usd

Hmmm, can’t see anything wrong there. You’re not running a very old version of HA are you?

In Developer Tools / Template, what does this return:

{{ state_attr('states.tibber_prices_adjusted','today')[0] }}

and what do you get if you paste the entire today template into the editor?

It returns a warning…

I’m running latest version (2023.11.3).

I think there somehow might be something wrong with the template engine.
The template editor always display Result type: String, no matter what template I put in there.

As a test, I made a new VM with a plain HA install and only added only the needed integrations, helpers and the template sensor. Looks correct there:

My HA has grown huge since 2018, too bad if I’ll end up having to more or less start from scratch :confounded:

Found it!

configuration.yaml:

homeassistant:
  ...
  #this bugger was the mother of all my problems..: 
  legacy_templates: true  
  ...

Was in the (slow) process of setting up 5 years of work from scratch on a new VM, and added part by part testing every small change. Just saved myself a sh*tload of work :sweat_smile:

“List” it is :+1:

2 Likes

Well done! I didn’t even know about that setting…