Skip to content

Instantly share code, notes, and snippets.

@KrzysztofHajdamowicz
Created July 2, 2025 19:28
Show Gist options
  • Select an option

  • Save KrzysztofHajdamowicz/6908099d87959b3a0bfea235dae0cb9d to your computer and use it in GitHub Desktop.

Select an option

Save KrzysztofHajdamowicz/6908099d87959b3a0bfea235dae0cb9d to your computer and use it in GitHub Desktop.
Find cheapest and most expensive electricity hours in Home Assistant to charge your EV or Battery Storage System (BESS)
template:
- sensor:
- unique_id: 979e14f2-78f9-43bc-9fb9-47e0645419f4
name: Tesla Model Y Hours to finish charging
device_class: duration
unit_of_measurement: h
state: >
{% set current_battery_soc = states('sensor.tesla_model_y_battery') | int -%}
{% set desired_battery_soc = states('number.tesla_model_y_charge_limit_2') | int -%}
{% set battery_percent_to_charge = [((desired_battery_soc - current_battery_soc)/100),0]|max -%}
{% set battery_capacity_in_kwh = 75 -%}
{% set battery_energy_to_add = battery_percent_to_charge * battery_capacity_in_kwh -%}
{% set charging_phases = 3|int -%}
{% set charging_voltage = 230|int -%}
{% set charging_amps = states('number.tesla_model_y_charging_amps')|float(default=16) -%}
{% set charging_power = (charging_phases*charging_voltage*charging_amps)/1000 -%}
{% set charging_hours = battery_energy_to_add/charging_power -%}
{% set charging_time_left_reported_by_tesla = states('sensor.tesla_model_y_estimated_hours_to_charge_termination')|float(default=0.0) -%}
{% if charging_time_left_reported_by_tesla is not none and charging_time_left_reported_by_tesla > 0 %}
{{ charging_time_left_reported_by_tesla }}
{% else %}
{{ charging_hours }}
{% endif %}
availability: >
{{
states('sensor.tesla_model_y_battery') | is_number
and states('number.tesla_model_y_charge_limit_2') | is_number
}}
attributes:
source: >
{% set charging_time_left_reported_by_tesla = states('sensor.tesla_model_y_estimated_hours_to_charge_termination')|float -%}
{% if charging_time_left_reported_by_tesla is not none and charging_time_left_reported_by_tesla > 0 %}
Provided by Tesla
{% else %}
Our own calculations
{% endif %}
- binary_sensor:
- unique_id: 911f0a21-48de-438f-90a2-4b46401268b3
name: Tesla Model Y Charge Car Cheap
device_class: battery_charging
state: >
{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours -%}
{% set sensor = 'sensor.tge_fixing_1_rate' -%}
{% set start = now() -%}
{% set end = states('input_datetime.tesla_model_y_finish_charging_at') -%}
{% set hours = states('sensor.tesla_model_y_hours_to_finish_charging') -%}
{{
cheapest_energy_hours(
sensor=sensor,
attr_today='prices_today',
attr_tomorrow='prices_tomorrow',
time_key='time',
value_key='price',
start=start,
end=end,
include_tomorrow=true,
hours=hours,
split=true,
mode='is_now'
)
}}
availability: >
{{
states('sensor.tesla_model_y_charging_time_left') | is_number
and states('sensor.tesla_model_y_battery') | is_number
and states('number.tesla_model_y_charge_limit_2') | is_number
and states('number.tesla_model_y_charging_amps') | is_number
and states('sensor.tge_fixing_1_rate') | is_number
}}
attributes:
start: "{{ now() }}"
end: "{{ states('input_datetime.tesla_model_y_finish_charging_at') }}"
hours: "{{states('sensor.tesla_model_y_hours_to_finish_charging')}}"
debug: >
{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours -%}
{% set sensor = 'sensor.tge_fixing_1_rate' -%}
{% set start = now() -%}
{% set end = states('input_datetime.tesla_model_y_finish_charging_at') -%}
{% set hours = states('sensor.tesla_model_y_hours_to_finish_charging') -%}
{{
cheapest_energy_hours(
sensor=sensor,
attr_today='prices_today',
attr_tomorrow='prices_tomorrow',
time_key='time',
value_key='price',
start=start,
end=end,
include_tomorrow=true,
hours=hours,
split=true,
mode='all'
)
}}
- unique_id: phahw3ra8aiShohphaibiegee9ahf6Cu
name: 4 cheapest consecutive hours
device_class: battery_charging
state: >
{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours -%}
{% set sensor = 'sensor.tge_fixing_1_rate' -%}
{% set start = states('input_datetime.find_cheapest_most_expensive_hours_since') -%}
{% set end = states('input_datetime.find_cheapest_hours_until') -%}
{% set hours = 4 -%}
{{
cheapest_energy_hours(
sensor=sensor,
attr_today='prices_today',
attr_tomorrow='prices_tomorrow',
time_key='time',
value_key='price',
start=start,
end=end,
include_tomorrow=true,
hours=hours,
split=false,
mode='is_now'
)
}}
availability: >
{{
(states('sensor.tge_fixing_1_rate') | is_number)
}}
attributes:
start: "{{ states('input_datetime.find_cheapest_most_expensive_hours_since') }}"
end: "{{ states('input_datetime.find_cheapest_hours_until') }}"
hours: "4"
debug: >
{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours -%}
{% set sensor = 'sensor.tge_fixing_1_rate' -%}
{% set start = states('input_datetime.find_cheapest_most_expensive_hours_since') -%}
{% set end = states('input_datetime.find_cheapest_hours_until') -%}
{% set hours = 4 -%}
{{
cheapest_energy_hours(
sensor=sensor,
attr_today='prices_today',
attr_tomorrow='prices_tomorrow',
time_key='time',
value_key='price',
start=start,
end=end,
include_tomorrow=true,
hours=hours,
split=false,
mode='all'
)
}}
- unique_id: Aesouthaico3ic7oowa4agahiJeeghoo
name: 4 cheapest non-consecutive hours
device_class: battery_charging
state: >
{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours -%}
{% set sensor = 'sensor.tge_fixing_1_rate' -%}
{% set start = states('input_datetime.find_cheapest_most_expensive_hours_since') -%}
{% set end = states('input_datetime.find_cheapest_hours_until') -%}
{% set hours = 4 -%}
{{
cheapest_energy_hours(
sensor=sensor,
attr_today='prices_today',
attr_tomorrow='prices_tomorrow',
time_key='time',
value_key='price',
start=start,
end=end,
include_tomorrow=true,
hours=hours,
split=true,
mode='is_now'
)
}}
availability: >
{{
(states('sensor.tge_fixing_1_rate') | is_number)
}}
attributes:
start: "{{ states('input_datetime.find_cheapest_most_expensive_hours_since') }}"
end: "{{ states('input_datetime.find_cheapest_hours_until') }}"
hours: "4"
debug: >
{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours -%}
{% set sensor = 'sensor.tge_fixing_1_rate' -%}
{% set start = states('input_datetime.find_cheapest_most_expensive_hours_since') -%}
{% set end = states('input_datetime.find_cheapest_hours_until') -%}
{% set hours = 4 -%}
{{
cheapest_energy_hours(
sensor=sensor,
attr_today='prices_today',
attr_tomorrow='prices_tomorrow',
time_key='time',
value_key='price',
start=start,
end=end,
include_tomorrow=true,
hours=hours,
split=true,
mode='all'
)
}}
- unique_id: yaesat9Phai3wu4eishuThofietoo8Sh
name: 4 most expensive consecutive hours
device_class: battery_charging
state: >
{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours -%}
{% set sensor = 'sensor.tge_fixing_1_rate' -%}
{% set start = states('input_datetime.find_cheapest_most_expensive_hours_since') -%}
{% set end = states('input_datetime.find_cheapest_hours_until') -%}
{% set hours = 4 -%}
{{
cheapest_energy_hours(
sensor=sensor,
attr_today='prices_today',
attr_tomorrow='prices_tomorrow',
time_key='time',
value_key='price',
start=start,
end=end,
include_tomorrow=true,
hours=hours,
split=false,
lowest=false,
mode='is_now'
)
}}
availability: >
{{
(states('sensor.tge_fixing_1_rate') | is_number)
}}
attributes:
start: "{{ states('input_datetime.find_cheapest_most_expensive_hours_since') }}"
end: "{{ states('input_datetime.find_cheapest_hours_until') }}"
hours: "4"
debug: >
{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours -%}
{% set sensor = 'sensor.tge_fixing_1_rate' -%}
{% set start = states('input_datetime.find_cheapest_most_expensive_hours_since') -%}
{% set end = states('input_datetime.find_cheapest_hours_until') -%}
{% set hours = 4 -%}
{{
cheapest_energy_hours(
sensor=sensor,
attr_today='prices_today',
attr_tomorrow='prices_tomorrow',
time_key='time',
value_key='price',
start=start,
end=end,
include_tomorrow=true,
hours=hours,
split=false,
lowest=false,
mode='all'
)
}}
- unique_id: fuecooPhaizavoh0ShooSeequu8echee
name: 4 most expensive non-consecutive hours
device_class: battery_charging
state: >
{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours -%}
{% set sensor = 'sensor.tge_fixing_1_rate' -%}
{% set start = states('input_datetime.find_cheapest_most_expensive_hours_since') -%}
{% set end = states('input_datetime.find_cheapest_hours_until') -%}
{% set hours = 4 -%}
{{
cheapest_energy_hours(
sensor=sensor,
attr_today='prices_today',
attr_tomorrow='prices_tomorrow',
time_key='time',
value_key='price',
start=start,
end=end,
include_tomorrow=true,
hours=hours,
split=true,
lowest=false,
mode='is_now'
)
}}
availability: >
{{
(states('sensor.tge_fixing_1_rate') | is_number)
}}
attributes:
start: "{{ states('input_datetime.find_cheapest_most_expensive_hours_since') }}"
end: "{{ states('input_datetime.find_cheapest_hours_until') }}"
hours: "4"
debug: >
{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours -%}
{% set sensor = 'sensor.tge_fixing_1_rate' -%}
{% set start = states('input_datetime.find_cheapest_most_expensive_hours_since') -%}
{% set end = states('input_datetime.find_cheapest_hours_until') -%}
{% set hours = 4 -%}
{{
cheapest_energy_hours(
sensor=sensor,
attr_today='prices_today',
attr_tomorrow='prices_tomorrow',
time_key='time',
value_key='price',
start=start,
end=end,
include_tomorrow=true,
hours=hours,
split=true,
lowest=false,
mode='all'
)
}}
- unique_id: pa1ueCh3neiTahkad0Ohch8eipet4sew
name: 2 most expensive consecutive hours
device_class: battery_charging
state: >
{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours -%}
{% set sensor = 'sensor.tge_fixing_1_rate' -%}
{% set start = states('input_datetime.find_cheapest_most_expensive_hours_since') -%}
{% set end = states('input_datetime.find_cheapest_hours_until') -%}
{% set hours = 2 -%}
{{
cheapest_energy_hours(
sensor=sensor,
attr_today='prices_today',
attr_tomorrow='prices_tomorrow',
time_key='time',
value_key='price',
start=start,
end=end,
include_tomorrow=true,
hours=hours,
split=false,
lowest=false,
mode='is_now'
)
}}
availability: >
{{
(states('sensor.tge_fixing_1_rate') | is_number)
}}
attributes:
start: "{{ states('input_datetime.find_cheapest_most_expensive_hours_since') }}"
end: "{{ states('input_datetime.find_cheapest_hours_until') }}"
hours: "2"
debug: >
{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours -%}
{% set sensor = 'sensor.tge_fixing_1_rate' -%}
{% set start = states('input_datetime.find_cheapest_most_expensive_hours_since') -%}
{% set end = states('input_datetime.find_cheapest_hours_until') -%}
{% set hours = 2 -%}
{{
cheapest_energy_hours(
sensor=sensor,
attr_today='prices_today',
attr_tomorrow='prices_tomorrow',
time_key='time',
value_key='price',
start=start,
end=end,
include_tomorrow=true,
hours=hours,
split=false,
lowest=false,
mode='all'
)
}}
- unique_id: aeFee0uiM2De1ohquo1eicojiZiekaik
name: 1 most expensive consecutive hour
device_class: battery_charging
state: >
{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours -%}
{% set sensor = 'sensor.tge_fixing_1_rate' -%}
{% set start = states('input_datetime.find_cheapest_most_expensive_hours_since') -%}
{% set end = states('input_datetime.find_cheapest_hours_until') -%}
{% set hours = 1 -%}
{{
cheapest_energy_hours(
sensor=sensor,
attr_today='prices_today',
attr_tomorrow='prices_tomorrow',
time_key='time',
value_key='price',
start=start,
end=end,
include_tomorrow=true,
hours=hours,
split=false,
lowest=false,
mode='is_now'
)
}}
availability: >
{{
(states('sensor.tge_fixing_1_rate') | is_number)
}}
attributes:
start: "{{ states('input_datetime.find_cheapest_most_expensive_hours_since') }}"
end: "{{ states('input_datetime.find_cheapest_hours_until') }}"
hours: "1"
debug: >
{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours -%}
{% set sensor = 'sensor.tge_fixing_1_rate' -%}
{% set start = states('input_datetime.find_cheapest_most_expensive_hours_since') -%}
{% set end = states('input_datetime.find_cheapest_hours_until') -%}
{% set hours = 1 -%}
{{
cheapest_energy_hours(
sensor=sensor,
attr_today='prices_today',
attr_tomorrow='prices_tomorrow',
time_key='time',
value_key='price',
start=start,
end=end,
include_tomorrow=true,
hours=hours,
split=false,
lowest=false,
mode='all'
)
}}
- unique_id: queevivi4ooleeshu3aekaireeCeeng3
name: 2 cheapest consecutive hours
device_class: battery_charging
state: >
{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours -%}
{% set sensor = 'sensor.tge_fixing_1_rate' -%}
{% set start = states('input_datetime.find_cheapest_most_expensive_hours_since') -%}
{% set end = states('input_datetime.find_cheapest_hours_until') -%}
{% set hours = 2 -%}
{{
cheapest_energy_hours(
sensor=sensor,
attr_today='prices_today',
attr_tomorrow='prices_tomorrow',
time_key='time',
value_key='price',
start=start,
end=end,
include_tomorrow=true,
hours=hours,
split=false,
mode='is_now'
)
}}
availability: >
{{
(states('sensor.tge_fixing_1_rate') | is_number)
}}
attributes:
start: "{{ states('input_datetime.find_cheapest_most_expensive_hours_since') }}"
end: "{{ states('input_datetime.find_cheapest_hours_until') }}"
hours: "2"
debug: >
{% from 'cheapest_energy_hours.jinja' import cheapest_energy_hours -%}
{% set sensor = 'sensor.tge_fixing_1_rate' -%}
{% set start = states('input_datetime.find_cheapest_most_expensive_hours_since') -%}
{% set end = states('input_datetime.find_cheapest_hours_until') -%}
{% set hours = 2 -%}
{{
cheapest_energy_hours(
sensor=sensor,
attr_today='prices_today',
attr_tomorrow='prices_tomorrow',
time_key='time',
value_key='price',
start=start,
end=end,
include_tomorrow=true,
hours=hours,
split=false,
mode='all'
)
}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment