ev_smart_charging icon indicating copy to clipboard operation
ev_smart_charging copied to clipboard

Alternative version for template sensor in Wiki

Open TheFes opened this issue 1 year ago • 17 comments

I couldn't find an edit button for the Wiki lemma, but I wanted to propose an alternative template sensor for the creation of the template sensor:

The variables set in the first 3 lines of the attribute make it more easy for the users to adjust the template for their own source sensor. I also found it a bit redundant to create the lists for both today and tomorrow in each attribute.

Not a user of the integration myself, but I was asked to help with creating a template sensor to be used with this integration, and thought it might be good to share :)

template:
  - sensor:
      - name: "Epex Spot Transformed"
        unit_of_measurement: "€/kWh"
        unique_id: 1daf4afa-8c54-4ab7-b055-7f85ea65a2c7
        state: "{{ states('sensor.epex_spot_data_net_price') }}"
        availability: "{{ 'sensor.epex_spot_data_net_price' | has_value }}"
        attributes:
            prices_today: >
                {%- set forecast_data = state_attr('sensor.epex_spot_data_net_price', 'data') %}
                {%- set time_key = 'start_time' %}
                {%- set price_key = 'price_ct_per_kwh' %}
                {%- set ns = namespace(data=[]) %}
                {%- for i in forecast_data | default([], true) if as_local(as_datetime(i[time_key])).date() == now().date() %}
                  {%- set ns.data = ns.data + [dict(time= as_local(as_datetime(i[time_key])).isoformat(), price = i[price_key])] %}
                {%- endfor %}
                {{ ns.data }}
            prices_tomorrow: >
                {%- set forecast_data = state_attr('sensor.epex_spot_data_net_price', 'data') %}
                {%- set time_key = 'start_time' %}
                {%- set price_key = 'price_ct_per_kwh' %}
                {%- set ns = namespace(data=[]) %}
                {%- for i in forecast_data | default([], true) if as_local(as_datetime(i[time_key])).date() == (now()+timedelta(days=1)).date() %}
                  {%- set ns.data = ns.data + [dict(time= as_local(as_datetime(i[time_key])).isoformat(), price = i[price_key])] %}
                {%- endfor %}
                {{ ns.data }}

TheFes avatar Jun 28 '24 11:06 TheFes

@TheFes was helping me with the template to use the Zonneplan component as source (Zonneplan is one of the Netherlands energy providers with dynamic/hourly tariffs)

This is the working result template, might be nice to add to the Wiki:

template:
  - sensor:
      - name: "Zonneplan template price sensor"
        unique_id: zonneplan_template_price_sensor
        unit_of_measurement: "€/kWh"
        availability: "{{ 'sensor.zonneplan_current_electricity_tariff' | has_value }}"
        state: "{{ states('sensor.zonneplan_current_electricity_tariff') }}"
        attributes:
          prices_today: >
            {%- set forecast = state_attr('sensor.zonneplan_current_electricity_tariff', 'forecast') %}
            {%- set time_key = 'datetime' %}
            {%- set price_key = 'electricity_price' %}
            {%- set ns = namespace(data=[]) %}
            {%- for i in forecast | default([], true) if as_local(as_datetime(i[time_key])).date() == now().date() %}
              {%- set ns.data = ns.data + [dict(time= as_local(as_datetime(i[time_key])).isoformat(), price = i[price_key] / 10000000 )] %}
            {%- endfor %}
            {{ ns.data }}
          prices_tomorrow: >
            {%- set forecast = state_attr('sensor.zonneplan_current_electricity_tariff', 'forecast') %}
            {%- set time_key = 'datetime' %}
            {%- set price_key = 'electricity_price' %}
            {%- set ns = namespace(data=[]) %}
            {%- for i in forecast | default([], true) if as_local(as_datetime(i[time_key])).date() == (now()+timedelta(days=1)).date() %}
              {%- set ns.data = ns.data + [dict(time= as_local(as_datetime(i[time_key])).isoformat(), price = i[price_key] / 10000000 )] %}
            {%- endfor %}
            {{ ns.data }}

hmmbob avatar Jun 28 '24 11:06 hmmbob

Added unit_of_measurement, unique_id and availability to the YAML

The unique_id is an UUID which I generated here https://www.uuidgenerator.net/

Also updated the name to be more read friendly, this will be slugified to epex_spot_transformed for the entity_id

TheFes avatar Jun 28 '24 12:06 TheFes

@TheFes, thanks for the alternative version. I have used it to update the EPEX Spot Wiki page. Except for the UUID, which is good for automatically generated IDs, but maybe not as good for manually created IDs.

@hmmbob, I also added the Zonneplan variant to the Wiki page.

Also, when adding unique_id to the template, the properties of the entity changed in such a way that I needed to update the code a bit. So now there is a v1.11.0-dev2 release available.

jonasbkarlsson avatar Jun 29 '24 17:06 jonasbkarlsson

Hi @jonasbkarlsson,   I have sensor for getting tibber prices based on the template above, but when i try to use it in the integration i get the error that the sensor could not be found. The sensor is defined as follows:  

template:
  - sensor:
      - name: "my_ev_price_tibber_sensor"
        unit_of_measurement: "€/kWh"
        availability: "{{ 'sensor.tibber_electricity_price' | has_value }}"
        state: '{{state_attr("sensor.tibber_electricity_price","current")["total"] | float}}'
        attributes:
          prices_today: >
            {%- set forecast_data = state_attr('sensor.tibber_electricity_price', 'today') %}
            {%- set time_key = 'startsAt' %}
            {%- set price_key = 'total' %}
            {%- set ns = namespace(data=[]) %}
            {%- for i in forecast_data | default([], true)%}
              {%- set ns.data = ns.data + [dict(time= as_local(as_datetime(i[time_key])).isoformat(), price = i[price_key])] %}
            {%- endfor %}
            {{ ns.data }}
          prices_tomorrow: >
            {%- set forecast_data = state_attr('sensor.tibber_electricity_price', 'tomorrow') %}
            {%- set time_key = 'startsAt' %}
            {%- set price_key = 'total' %}
            {%- set ns = namespace(data=[]) %}
            {%- for i in forecast_data | default([], true)%}
              {%- set ns.data = ns.data + [dict(time= as_local(as_datetime(i[time_key])).isoformat(), price = i[price_key])] %}
            {%- endfor %}
            {{ ns.data }}

  The values within the gui look like in the screenshot attached. I would appreciate your help.

tibber_price_sensor

price_sensor_error

adegenkolbe avatar Jul 02 '24 20:07 adegenkolbe

@adegenkolbe, can you double check that there is an entity named sensor.my_ev_price_tibber_sensor? If you look in Settings->Devices & services->Entities

If there is such an entity, can you add unique_id: my_ev_price_tibber_sensor to the template and try again?

Please let me know your observations.

jonasbkarlsson avatar Jul 03 '24 07:07 jonasbkarlsson

Thanks for the quick response and your hel @jonasbkarlsson

The Entity was present. After I added the unique id i could complete the setup. So it seems to be a mandatory field.

adegenkolbe avatar Jul 03 '24 09:07 adegenkolbe

Reply on the content:

state: '{{state_attr("sensor.tibber_electricity_price","current")["total"] | float}}'

The | float has no use, as HA states are always strings. So this is he correct one:

state: '{{state_attr("sensor.tibber_electricity_price","current")["total"] }}'

(it doesn't break anything though, it's just getting converted back to string again)

hmmbob avatar Jul 03 '24 09:07 hmmbob

@adegenkolbe, thanks for the feedback. Can you confirm that it is v1.11.0-dev2 that you are using?

jonasbkarlsson avatar Jul 03 '24 09:07 jonasbkarlsson

@jonasbkarlsson i was pretty sure that i chose the beta for installation (as you stated in the comments above) but obviously i made a mistake or something else happend. i was on the latest stable. I updated and now it also worked without a unique id. sorry for the confusion

adegenkolbe avatar Jul 03 '24 09:07 adegenkolbe

@adegenkolbe, thanks for checking. And good to hear that you had the "wrong" version. I'm quite sure it should work without unique_id. However, I think it is better to include unique_id in the template.

jonasbkarlsson avatar Jul 03 '24 10:07 jonasbkarlsson

Reply on the content:

state: '{{state_attr("sensor.tibber_electricity_price","current")["total"] | float}}'

The | float has no use, as HA states are always strings. So this is he correct one:

state: '{{state_attr("sensor.tibber_electricity_price","current")["total"] }}'

(it doesn't break anything though, it's just getting converted back to string again)

Is that really correct? The documentation of entity says that state can be str | int | float | None. And the documentation of template even says that " If the sensor is numeric, i.e. it has a state_class or a unit_of_measurement, the state template must render to a number or to none. The state template must not render to a string..."

jonasbkarlsson avatar Jul 03 '24 11:07 jonasbkarlsson

Whoa. @TheFes ?

hmmbob avatar Jul 03 '24 11:07 hmmbob

It doesn't matter actually. The result of a template is always a string. The template parser in HA then tries to convert it to a native Python type (float, int, list, dict etc). If it can't, it will use the template result as string.

That's why something like {{ "[ 'a', 'b', 'c']" }} will show as a list in developer tools > templates (as it uses the same template parser).

Screenshot_20240703-133936.png

Or a numeric string will show as a floating point number

Screenshot_20240703-134320.png

TheFes avatar Jul 03 '24 11:07 TheFes

@TheFes was helping me with the template to use the Zonneplan component as source (Zonneplan is one of the Netherlands energy providers with dynamic/hourly tariffs)

This is the working result template, might be nice to add to the Wiki:

template:
  - sensor:
      - name: "Zonneplan template price sensor"
        unique_id: zonneplan_template_price_sensor
        unit_of_measurement: "€/kWh"
        availability: "{{ 'sensor.zonneplan_current_electricity_tariff' | has_value }}"
        state: "{{ states('sensor.zonneplan_current_electricity_tariff') }}"
        attributes:
          prices_today: >
            {%- set forecast = state_attr('sensor.zonneplan_current_electricity_tariff', 'forecast') %}
            {%- set time_key = 'datetime' %}
            {%- set price_key = 'electricity_price' %}
            {%- set ns = namespace(data=[]) %}
            {%- for i in forecast | default([], true) if as_local(as_datetime(i[time_key])).date() == now().date() %}
              {%- set ns.data = ns.data + [dict(time= as_local(as_datetime(i[time_key])).isoformat(), price = i[price_key] / 10000000 )] %}
            {%- endfor %}
            {{ ns.data }}
          prices_tomorrow: >
            {%- set forecast = state_attr('sensor.zonneplan_current_electricity_tariff', 'forecast') %}
            {%- set time_key = 'datetime' %}
            {%- set price_key = 'electricity_price' %}
            {%- set ns = namespace(data=[]) %}
            {%- for i in forecast | default([], true) if as_local(as_datetime(i[time_key])).date() == (now()+timedelta(days=1)).date() %}
              {%- set ns.data = ns.data + [dict(time= as_local(as_datetime(i[time_key])).isoformat(), price = i[price_key] / 10000000 )] %}
            {%- endfor %}
            {{ ns.data }}

Let me update this one with the trigger we added in #279

template:
  - trigger:
        # This generates triggers for all changes in the entity, both in its state and its attributes.
      - platform: state
        entity_id: sensor.zonneplan_current_electricity_tariff
    sensor:
      - name: "Zonneplan template price sensor"
        unique_id: zonneplan_template_price_sensor
        unit_of_measurement: "€/kWh"
        state: "{{ states('sensor.zonneplan_current_electricity_tariff') }}"
        availability: "{{ 'sensor.zonneplan_current_electricity_tariff' | has_value }}"
        attributes:
          prices_today: >
            {%- set forecast = state_attr('sensor.zonneplan_current_electricity_tariff', 'forecast') %}
            {%- set time_key = 'datetime' %}
            {%- set price_key = 'electricity_price' %}
            {%- set ns = namespace(data=[]) %}
            {%- for i in forecast | default([], true) if as_local(as_datetime(i[time_key])).date() == now().date() %}
              {%- set ns.data = ns.data + [dict(time= as_local(as_datetime(i[time_key])).isoformat(), price = i[price_key] / 10000000 )] %}
            {%- endfor %}
            {{ ns.data }}
          prices_tomorrow: >
            {%- set forecast = state_attr('sensor.zonneplan_current_electricity_tariff', 'forecast') %}
            {%- set time_key = 'datetime' %}
            {%- set price_key = 'electricity_price' %}
            {%- set ns = namespace(data=[]) %}
            {%- for i in forecast | default([], true) if as_local(as_datetime(i[time_key])).date() == (now()+timedelta(days=1)).date() %}
              {%- set ns.data = ns.data + [dict(time= as_local(as_datetime(i[time_key])).isoformat(), price = i[price_key] / 10000000 )] %}
            {%- endfor %}
            {{ ns.data }}

And I think it would be great for readability if all the yaml is inside YAML blocks, instead of plain blocks: image

hmmbob avatar Jul 04 '24 11:07 hmmbob

@hmmbob, thanks for the suggestion of using ```yaml. I have put your first template in the Wiki.

For the second template, should it really be - sensor:? I thought that hyphen will mean that the preceesing trigger is not used. Meaning that it should be sensor: (without a hypen) for the trigger to be applied.

jonasbkarlsson avatar Jul 04 '24 15:07 jonasbkarlsson

@jonasbkarlsson you are right, it should be without the hyphen

TheFes avatar Jul 04 '24 20:07 TheFes

Yeah, that's a typo here. I have it without hypen in my config. Good spot!

hmmbob avatar Jul 05 '24 07:07 hmmbob