Since this was a top result in my search, I thought I’d share my final config. And this thread was a great help to point me in the right direction, so thanks for that!
My rates are a little different. In Winter, there are 2 time slots.
I also setup multiple template sensors, 1 for a friendly text output to use on dashboards, and another for actual monetary rate associate with the former. And my OnPeak and OffPeak rates are stored in 2 Input Helpers.
This is my rate chart for Wisconsin Public Service
OFF Peak Times:
Summer: (May - Sept) 19:00 to 9:00
Winter: (Oct - April) 12:00 to 16:00 and 21:00 to 8:00
Holiday and Weekends are also OFF Peak
Prerequisites:
Holidays Integration (Holiday - Home Assistant)
My resulting entity = ‘calendar.united_states_wi’ (Be sure to update the references in the below code to match your entity)
Helpers/Sensors Overview:
All done in the GUI. Configurations.yaml was not touched.
Input Helpers:
These are where you enter the actual prices. Since rates fluctuate, an Input helper makes it easy to plug in updated rates without needing to update any templates.
- input_number.time_of_use_rate_offpeak
- input_number.time_of_use_rate_peak
Template Sensors:
- sensor.timeofusecalctext
(Does the main calculation depending on Time, Month, Weekend/Holiday) - sensor.time_of_use_current_rate_calc
(Determine the current rate, based off the sensor.timeofusecalctext. For USA, the unit MUST be in ‘USD/kWh’ in order to associate it with the Energy dashboard)
sensor.timeofusecalctext
{% set hour_now = now().hour %}
{% set holidayweekend = is_state('calendar.united_states_wi', 'on')
or now().weekday() in [5,6] %}
{% set this_month = now().month %}
{# Summer Rates #}
{% if this_month in [5,6,7,8,9] %}
{% if holidayweekend %} {{ 'OffPeak (Summer/Holiday/Weekend)' }}
{% elif (hour_now >=19 or hour_now <=9 )%} {{ 'OffPeak (Summer)' }}
{% else %} {{ 'OnPeak (Summer)' }}
{% endif %}
{# Winter Rates #}
{% elif this_month in [1,2,3,4,10,11,12] %}
{% if holidayweekend %} {{ 'OffPeak (Winter/Holiday/Weekend)' }}
{% elif (hour_now >=12 and hour_now <=16 )%} {{ 'OffPeak (Winter/TimeSlotA)' }}
{% elif (hour_now >=21 or hour_now <=8 )%} {{ 'OffPeak (Winter/TimeSlotB)' }}
{% else %} {{ 'OnPeak (Winter)' }}
{% endif %}
{% else %}
{{ 'unavailable' }}
{% endif %}
sensor.time_of_use_current_rate_calc
Uses a Jinja text compare, ‘in’. If you alter the text values above, make sure your text comparison here are compatible.
{% set timeOfUseText = states('sensor.timeofusecalctext') %}
{% if 'OffPeak' in timeOfUseText %}
{{states('input_number.time_of_use_rate_offpeak')}}
{% elif 'OnPeak' in timeOfUseText %}
{{states('input_number.time_of_use_rate_peak')}}
{% else %}
failed
{% endif %}
Testing/Validation in Dev Tools:
Dashboard Examples: (Using History Graph Card and Mushroom Template Card)
Updating your Energy Dashboard to use your new Time of Use rates:
Bonus: Determining cost of INDIVIDUAL devices with ToU factored in:
While HA can determine the TOTAL grid price with ToU factored in, we can’t break it down at the indicidual device level. This is a frustrating limitation of HA.
I found this HACs add-on:
Further reading:
Feature Request thread (Open since 2021)