Automatic unit conversion

With the help of this integration a sensor can be automatically converted to a desired unit within Jinja2 templates, no matter what unit the sensor has - as long as the integration knows how to convert to the desired unit.

Sometimes I struggle with sensors that have different unit_of_measurement values. For example some of my sensors have “W” and others have “kW”. Whenever I write an automation or a template (sensor) or a chart, I need to be aware of the units. Even worse, if I change the unit of a sensor all my related automations and templates are corrupted.

Unfortunately, I did not find any solution to my problem. That’s the reason why I implemented my own integration.

Example:

{{ to_unit(states.sensor.power_consumption_total, 'kW') }}

In this example, the sensor can have any unit_of_measurement value of e.g. “W”, “kW”, “MW” and will be converted to kW.

Even better, I can do calculations that will always work without taking care of actual unit_of_measurement values.

{{ (
      with_unit(states.sensor.power_consumption_total)
      - with_unit(states.sensor.grid_power_supply_total)
   ) | to_unit('kW')
}}

This approach works where Jinja2 templates are used. For charts, I am thinking about implementing the same approach for Javascript. However, I haven’t figured out how to access unit_of_measurement values of sensors in charting components like plotly-graph-card, apexcharts-card or history-graph-card

1 Like

Sounds good, but I could not run my code.

I have installed the integration from your repository successfully.

I have rebooted HA as requested.

Now I’m testing the following Jinja2-Code in Template-Editor.

{{ states('sensor.total_energy_kwh') | to_unit('MWh') }}

This should convert the 2990.0 kWh to 2.99 MWh
but it shows the following error:

TemplateAssertionError: No filter named ‘to_unit’.

Is there anything I can check, if installation was fine?

I am quite new to HomeAssistant development myself. Maybe adding

template_unit_helper:

to your configuration.yaml does the trick. Is there anything in your logfile? I will investigate on how to check if an extension is properly loaded and let you know. Maybe I can produce some output to the log …

Walter, I created an issue for your issue on Github: No filter named ‘to_unit’ · Issue #1 · ultravail/homeassistant-template-unit-helper · GitHub

Thanks for your feedback, first step is done now.

After adding the line to my config and after a reboot of HA the error is gone, but it’s still not working as expected.

{{ states('sensor.total_energy_kwh') }}
{{ states('sensor.total_energy_kwh') | to_unit('MWh') }}
{{ states('sensor.total_energy_kwh') | to_unit('Wh') }}

All 3 lines are returning the original kWh, no conversion is being done.

Here are the attributes of my sensor, maybe to_unit needs other attributes to work with?

state_class: total
unit_of_measurement: kWh
device_class: energy

The states(...) function only returns the value (without any reference to the unit or its original state), hence only a number is handed over to the to_unit filter. Use the followint instead

{{ states.sensor.total_energy_kwh | to_unit(‘Wh’) }}

Alternatively, you could use

{{ with_unit(‘states.sensor.temperature’) | to_unit(‘Wh’) }}

This is the way it’s working for me

{{ ('states.sensor.total_energy_kwh') | to_unit('MWh') }}
{{ ('states.sensor.total_energy_kwh') | to_unit('Wh') }}

with_unit can be added, but is not needed.

Is the following behavior intended:

{{ ('states.sensor.total_energy_kwh') | with_unit }}
{{ ('states.sensor.total_energy_kwh') | to_unit('MWh') | with_unit }}
{{ ('states.sensor.total_energy_kwh') | to_unit('Wh') | with_unit }}

Line 1 shows: kilowatt_hour
Line 2 and 3 are showing: dimensionless

See the README: The with_unit helper returns a Pint Quantity. The helpers to_unit, from_unit and without_unit return the plain number. I suggest to do the conversion to the desired unit at the very end and use Pint Quantity objects for any calculations.

So in your case:

  • Line 1: Provide ‘states.sensor.total_energy_kwh’ to with_unit helper. This helper recognizes the text as a sensor name, fetches the value and unit from that entity and returns a Pint Quantity (which results in value + unit as text when “handed back to HomeAssistant”
  • Line 2+3: Provide ‘states.sensor.total_energy_kwh’ to to_unit helper. This helper recognizes the text as a sensor name, fetches the value and unit from that entity, transforms to ‘MWh’ and ‘Wh’ respectively and returns a plain number (without unit) which is handed over to with_unit helper. That last helper in the pipeline does not have any information about the unit anymore (because to_unit stripped away the unit information) and hence returns dimensionless as the unit

Pint Quantity objects should not be used for further processing in HomeAssistant - only within the Jinja2 expression itself. The result of a Jinja2 expression should typically be a pure (dimensionless) number. If the result of your expression is a Pint Quantity object, then this object will be transformed into a text consisting of the value and the unit. As mentioned in the README on GitHub, the helpers to_unit, from_unit and without_unit return plain numbers while with_unit returns a Pint Quantity object.

While using with_unit is not necessary (because it is called internally for text values), I believe that explicity using with_unit is a cleaner way (i.e. explicity transforming to a Pint Quantitiy).

I can’t help myself, but pipes are a little bit clumsy to read for me. That’s why I would prefer the following expression:

{{ to_unit('states.sensor.total_energy_kwh', 'Wh') }}

This expression transforms your sensor to Wh (no matter what unit it initially had) and returns a simple (dimensionless) number similar to what states(....) would return.

If you need to do more calculations with the entity value (and don’t want to loose the unit information) then use with_unit.

Example:

{{ (with_unit('states.sensor.total_energy_kwh', 'Wh') + with_unit(1.2, 'kWh')) | without_unit }}

The result is a pure number (without unit) reflecting the value in Wh. However, a much clearer way would be the following:

{{ (with_unit('states.sensor.total_energy_kwh') + with_unit(1200, 'Wh')) | to_unit('MWh') }}

In this example it is quite clear that the result is in MWh.

If you don’t like pipes, then use the following:

{{ to_unit(with_unit('states.sensor.total_energy_kwh') + with_unit(1200, 'Wh'), 'MWh') }}

However, in this case I would prefer the pipe syntax.

When dealing with Pint Quantity objects, you don’t need to care about the units. So you can safely use the following expression to test if your total energy exceeds 1 MWh (no matter what the actual unit of your sensor is):

{{ with_unit('states.sensor.total_energy_kwh') > with_unit(1, 'MWh') }}
1 Like

I am using helper entities in HomeAssistant for my automations. For example, I am still using an old electric water boiler that consumes 5.5 kW when active. I configured helper entities that help me enabling the water boiler only if enough Solar energy is available. For this I use the following entities:

  • input_boolean.waterboiler_automation_active that I can manually set to true or false to enable/disable the automation
  • switch.waterboiler_authorization evaluates if the boiler can be switched on or not
  • sensor.power_consumption_idle calculates the 30% percentile of the power consumption of the last 24 hours which defines my base load
  • sensor.energy_production_today_remaining_unreserved stores the estimated remaining energy production until sunset that has not yet been reserved (i.e. estimated remaining energy production minus reserved energy)
  • sensor.solar_production sums the power currently produced by all of my solar panels

Once the power produced by my solar panels exceeds the threshold of 5.5 kW plus the idle power consumption and there is at least 1kWh unreserved energy, I “authorize” the boiler to heat the water.

The switch.waterboiler_authorization entity is a Template entity with the following expression:

{% set mimimum_solar_production=with_unit('states.sensor.power_consumption_idle') + with_unit(5.5, 'kW') %}
{% set minimum_unreserved_energy=with_unit(1, 'kWh') %}

{{
with_unit('states.sensor.solar_production') >= mimimum_solar_production
and with_unit('states.sensor.energy_production_today_remaining_unreserved') > minimum_unreserved_energy
}}

The automation itself is triggered whenever switch.waterboiler_authorization or input_boolean.waterboiler_automation_active change. If switch.waterboiler_authorization and input_boolean.waterboiler_automation_active are both true, then the boiler is switched on.

This is the automation:

alias: Boiler-Activation-On-Solar-Surplus
triggers:
  - trigger: state
    entity_id:
      - switch.waterboiler_authorization
    to: "on"
    for:
      hours: 0
      minutes: 2
      seconds: 0
  - trigger: state
    entity_id:
      - input_boolean.waterboiler_automation_active
    to: "on"
conditions:
  - condition: state
    entity_id: switch.waterboiler_authorization
    state: "on"
  - condition: state
    entity_id: input_boolean.waterboiler_automation_active
    state: "on"
actions:
  - action: switch.turn_on
    target:
      entity_id: switch.boiler
mode: single

There is a similar automation that switches the boiler off if either of the two entities is off.

1 Like