Thank you @ccpk1 – this is amazing!
For those that have different rates by time of day, I used the following to setup automatic rate tracking for Toronto Hydro.
Input number is used to define rates for each tariff rate.
input_number:
energy_tou_rate_onpeak:
name: Energy kWh Cost On-Peak
icon: mdi:currency-usd
mode: box
unit_of_measurement: "CAD/kWh"
min: 0.001
max: 1
initial: 0.17
energy_tou_rate_midpeak:
name: Energy kWh Cost Mid-Peak
icon: mdi:currency-usd
mode: box
unit_of_measurement: "CAD/kWh"
min: 0.001
max: 1
initial: 0.113
energy_tou_rate_offpeak:
name: Energy kWh Cost Off-Peak
icon: mdi:currency-usd
mode: box
unit_of_measurement: "CAD/kWh"
min: 0.001
max: 1
initial: 0.082
energy_tou_rate_average:
name: Energy kWh Cost Average
icon: mdi:currency-usd
mode: box
unit_of_measurement: "CAD/kWh"
min: 0.001
max: 1
initial: 0.10325
A template is used to define the name of the tariff rate, and another is used to retrieve the current tariff rate. The name is important since it will be used in utility_meter to calculate which rates apply.
The energy_tou_tariff
state can be adjusted as needed
template:
- trigger:
- platform: time_pattern
seconds: "/1"
- platform: homeassistant
event: start
- platform: event
event_type: "call_service"
event_data:
domain: "template"
service: "reload"
sensor:
- name: energy_tou_tariff
unique_id: e09d54cbfd1e4511a66a847f25e246ef
icon: mdi:chart-bar
state: >
{% if now().weekday() >= 0 and now().weekday() < 5 %}
{% if now().month >= 5 and now().month < 11 %}
{% if now().hour >= 7 and now().hour < 11 %} onpeak
{% elif now().hour >= 11 and now().hour < 17 %} midpeak
{% elif now().hour >= 17 and now().hour < 19 %} onpeak
{% else %} offpeak
{% endif %}
{% else %}
{% if now().hour >= 7 and now().hour < 11 %} midpeak
{% elif now().hour >= 11 and now().hour < 17 %} onpeak
{% elif now().hour >= 17 and now().hour < 19 %} midpeak
{% else %} offpeak
{% endif %}
{% endif %}
{% else %} offpeak
{% endif %}
- name: energy_kwh_cost
unique_id: 97041eea00d0448caf9e300ee08694a5
unit_of_measurement: "CAD/kWh"
icon: mdi:currency-usd
state: >
{% if is_state('sensor.energy_tou_tariff', 'onpeak') %} {{ states('input_number.energy_tou_rate_onpeak') | float }}
{% elif is_state('sensor.energy_tou_tariff', 'midpeak') %} {{ states('input_number.energy_tou_rate_midpeak') | float }}
{% elif is_state('sensor.energy_tou_tariff', 'offpeak') %} {{ states('input_number.energy_tou_rate_offpeak') | float }}
{% else %} {{ states('input_number.energy_tou_rate_average') | float }}
{% endif %}
Utility Meter is setup for daily and monthly cycles, and tariffs are defined. These tariff names must match the template sensor values above for automatic rate select. Once implemented, usage is then split into “buckets”, where the sensor name will now include the tariff name as a suffix.
For example, sensor.electric_home_daily_total_energy
would become …
-
sensor.electric_home_daily_total_energy_onpeak
for onpeak usage
-
sensor.electric_home_daily_total_energy_midpeak
for midpeak usage
- and
sensor.electric_home_daily_total_energy
for offpeak usage
Actual tariff names can be changed as needed, just make sure they still match. Note the use of yaml anchor on the first value using <<:
&
utility_meter_tariff_defaults
, and all other utility_meter
definitions have <<:
*
utility_meter_tariff_defaults
instead.
utility_meter:
################ Track daily consumption for each grouping ###############
electric_home_daily_total_energy:
source: sensor.electric_home_total_energy
cycle: daily
<<: &utility_meter_tariff_defaults
tariffs:
- offpeak
- midpeak
- onpeak
other_daily_total_energy:
source: sensor.other_total_energy
cycle: daily
<<: *utility_meter_tariff_defaults
# ... repeat as needed ...
################ Track monthly consumption for each grouping ###############
electric_home_monthly_total_energy:
source: sensor.electric_home_total_energy
cycle: monthly
<<: *utility_meter_tariff_defaults
other_monthly_total_energy:
source: sensor.other_total_energy
cycle: monthly
<<: *utility_meter_tariff_defaults
# ... repeat as needed ...
Since utility_meter
will now output usage into multiple “buckets” by tariff, total usage must then be configured to aggregate each tariff rate.
sensor:
- platform: template
sensors:
################ Calculate daily energy usage for each grouping ###############
electric_home_daily_total_energy_usage:
friendly_name: "Electric Home Daily Total Energy Usage"
value_template: "{{ states('sensor.electric_home_daily_total_energy_onpeak') | float(2) + states('sensor.electric_home_daily_total_energy_midpeak') | float(2) + states('sensor.electric_home_daily_total_energy_offpeak') | float(2) }}"
<<: &energy_usage_defaults
unit_of_measurement: "kWh"
icon_template: mdi:gauge
electric_other_daily_total_energy_usage:
friendly_name: "Electric Other Daily Total Energy Usage"
value_template: "{{ states('sensor.other_daily_total_energy_onpeak') | float(2) + states('sensor.other_daily_total_energy_midpeak') | float(2) + states('sensor.other_daily_total_energy_offpeak') | float(2) }}"
<<: *energy_usage_defaults
# ... repeat as needed ...
################ Calculate monthly energy usage for each grouping ###############
electric_home_monthly_total_energy_usage:
friendly_name: "Electric Home Monthly Total Energy Usage"
value_template: "{{ states('sensor.electric_home_monthly_total_energy_onpeak') | float(2) + states('sensor.electric_home_monthly_total_energy_midpeak') | float(2) + states('sensor.electric_home_monthly_total_energy_offpeak') | float(2) }}"
<<: *energy_usage_defaults
electric_other_monthly_total_energy_usage:
friendly_name: "Electric Other Monthly Total Energy Usage"
value_template: "{{ states('sensor.other_monthly_total_energy_onpeak') | float(2) + states('sensor.other_monthly_total_energy_midpeak') | float(2) + states('sensor.other_monthly_total_energy_offpeak') | float(2) * states('input_number.energy_tou_rate_offpeak') | float(2) }}"
<<: *energy_usage_defaults
# ... repeat as needed ...
In addition, cost must be calculated and aggregated for each tariff as well.
sensor:
- platform: template
sensors:
################ Calculate daily energy cost for each grouping ###############
electric_home_daily_total_energy_cost:
friendly_name: "Electric Home Daily Total Energy Cost"
value_template: >-
{{ max((states('sensor.electric_home_daily_total_energy_onpeak') | float(2) * states('input_number.energy_tou_rate_onpeak') | float(2))
+ (states('sensor.electric_home_daily_total_energy_midpeak') | float(2) * states('input_number.energy_tou_rate_midpeak') | float(2))
+ (states('sensor.electric_home_daily_total_energy_offpeak') | float(2) * states('input_number.energy_tou_rate_offpeak') | float(2)) | round(2), 0.00) }}
<<: &energy_cost_defaults
unit_of_measurement: "$"
icon_template: mdi:currency-usd
electric_other_daily_total_energy_cost:
friendly_name: "Electric Other Daily Total Energy Cost"
value_template: >-
{{ max((states('sensor.other_daily_total_energy_onpeak') | float(2) * states('input_number.energy_tou_rate_onpeak') | float(2))
+ (states('sensor.other_daily_total_energy_midpeak') | float(2) * states('input_number.energy_tou_rate_midpeak') | float(2))
+ (states('sensor.other_daily_total_energy_offpeak') | float(2) * states('input_number.energy_tou_rate_offpeak') | float(2)) | round(2), 0.00) }}
<<: *energy_cost_defaults
# ... repeat as needed ...
################ Calculate monthly energy cost for each grouping ###############
electric_home_monthly_total_energy_cost:
friendly_name: "Electric Home Monthly Total Energy Cost"
value_template: >-
{{ max((states('sensor.electric_home_monthly_total_energy_onpeak') | float(2) * states('input_number.energy_tou_rate_onpeak') | float(2))
+ (states('sensor.electric_home_monthly_total_energy_midpeak') | float(2) * states('input_number.energy_tou_rate_midpeak') | float(2))
+ (states('sensor.electric_home_monthly_total_energy_offpeak') | float(2) * states('input_number.energy_tou_rate_offpeak') | float(2)) | round(2), 0.00) }}
<<: *energy_cost_defaults
electric_other_monthly_total_energy_cost:
friendly_name: "Electric Other Monthly Total Energy Cost"
value_template: >-
{{ max((states('sensor.other_monthly_total_energy_onpeak') | float(2) * states('input_number.energy_tou_rate_onpeak') | float(2))
+ (states('sensor.other_monthly_total_energy_midpeak') | float(2) * states('input_number.energy_tou_rate_midpeak') | float(2))
+ (states('sensor.other_monthly_total_energy_offpeak') | float(2) * states('input_number.energy_tou_rate_offpeak') | float(2)) | round(2), 0.00) }}
<<: *energy_cost_defaults
# ... repeat as needed ...
Finally, an automation is configured to set the tariff rate for each utility_meter
. We use an automated group to simplify rate automation.
automation:
################ Create and update power groupings for circuits and devices ###############
- alias: "Update Utility Groups"
trigger:
- platform: homeassistant
event: start
- platform: event
event_type: "call_service"
event_data:
domain: "group"
service: "reload"
action:
- service: group.set
data_template:
object_id: utility_meters
entities: >
{% set ns = namespace(entities=[]) %}
{% for s in states.utility_meter if s.object_id.endswith('_daily_total_energy') or s.object_id.endswith('_monthly_total_energy') %}
{% set ns.entities = ns.entities + [ s.entity_id ] %}
{% endfor %}
{{ ns.entities }}
################ Update power tariffs for all circuits ###############
- alias: "Update Power Tariffs"
trigger:
- platform: homeassistant
event: start
- platform: event
event_type: "call_service"
event_data:
domain: "group"
service: "reload"
- platform: state
entity_id: sensor.energy_tou_tariff
- platform: time_pattern
seconds: "/5"
action:
- service: utility_meter.select_tariff
data:
entity_id: group.utility_meters
tariff: '{{ states("sensor.energy_tou_tariff") }}'
Edited: simplified yaml using anchors and automatic group creation