Files
zorruno-homeassistant/packages/16a_ev_charging_controls.yaml
T
2026-07-21 13:40:06 +12:00

433 lines
15 KiB
YAML

# yaml-language-server: $schema=null
###############################################################################
# PACKAGE: 16A EV Charger Control
###############################################################################
#
# FILE:
# packages/16a_ev_charging_controls.yaml
#
# VERSION:
# V1.2 2026-07-20
# - Added structured mode, timing, and restart behavior documentation.
#
# V1.1 2026-05-15
# - Reworked 1hr topup logic to use a hard deadline and watchdog.
# - Removed dependency on timer.finished event for relay shutoff.
# - Offpeak until charged now continues past offpeak end until charging stops.
# - 1hr topup now rolls into Normal Offpeak if the hour ends during
# the offpeak window, without switching the relay off and back on.
#
# V1.0 2026-05-11
# - Initial package for 16A EV charger offpeak and charge-until-full control.
#
# PURPOSE:
# Controls the Leaf 16A charger relay using scheduled offpeak operation and
# user-selectable immediate or charge-until-full modes.
#
# DEPENDENCIES:
# - switch.garage_db_control_16a_wallcharger_operation controls charger power.
# - binary_sensor.garage_db_control_16a_wallcharger_charging reports whether
# the vehicle is actively charging.
#
# CHARGE MODES:
# - Normal (Offpeak) turns the relay on and off at the configured offpeak
# start and end times. Selecting this mode takes no immediate action.
# - Offpeak until charged starts at the offpeak time, or immediately if
# selected during offpeak, and may continue beyond offpeak end until the
# vehicle stops charging.
# - 1hr topup now turns the relay on immediately and records a hard deadline
# one hour ahead.
# - Charge now until full turns the relay on immediately and keeps it on until
# the vehicle stops charging.
# - Stop charging now turns the relay off immediately and returns the selector
# to Normal (Offpeak).
#
# TIMING AND COMPLETION:
# - Charge-until-full modes allow five minutes for charging to start. This
# also handles a vehicle that is already full.
# - Charging is considered complete after the charging sensor remains off for
# five minutes.
# - The one-hour topup deadline is stored in input_datetime and checked every
# minute and when Home Assistant starts.
# - If a topup ends during offpeak, the relay remains on and the mode returns
# to Normal (Offpeak), avoiding an off/on relay cycle.
# - Equal offpeak start and end times are interpreted as an all-day window.
#
# OPERATION NOTES:
# - Normal offpeak start and end use exact-time triggers.
# - There is no startup catch-up if Home Assistant is offline at either time.
#
# PACKAGE SETTINGS:
# Car display name:
# - Leaf
#
# Charger relay output:
# - switch.garage_db_control_16a_wallcharger_operation
#
# Vehicle charging sensor:
# - binary_sensor.garage_db_control_16a_wallcharger_charging
#
# Default offpeak period:
# - Start: 21:00:00
# - End: 00:00:00
#
###############################################################################
input_datetime:
ev_16a_offpeak_start:
name: 16A EV Offpeak Start
has_date: false
has_time: true
initial: "21:00:00"
ev_16a_offpeak_end:
name: 16A EV Offpeak End
has_date: false
has_time: true
initial: "00:00:00"
ev_16a_1hr_topup_until:
name: 16A EV 1hr topup until
has_date: true
has_time: true
initial: "2000-01-01 00:00:00"
input_select:
ev_16a_charge_mode:
name: Leaf EV charge mode
icon: mdi:ev-station
options:
- "Normal (Offpeak)"
- "Offpeak until charged"
- "1hr topup now"
- "Charge now until full"
- "Stop charging now"
initial: "Normal (Offpeak)"
automation:
#############################################################################
# OFFPEAK START
#############################################################################
- id: ev_16a_charger_offpeak_start
alias: "16A EV Charger - Offpeak Start"
mode: single
triggers:
- trigger: time
at: input_datetime.ev_16a_offpeak_start
conditions:
- condition: template
value_template: >
{{ states('input_select.ev_16a_charge_mode') in
['Normal (Offpeak)', 'Offpeak until charged'] }}
actions:
- action: switch.turn_on
target:
entity_id: switch.garage_db_control_16a_wallcharger_operation
- choose:
- conditions:
- condition: state
entity_id: input_select.ev_16a_charge_mode
state: "Offpeak until charged"
sequence:
# If the car never starts charging, or is already full, turn off
# after a 5 minute grace period.
- delay: "00:05:00"
- condition: state
entity_id: input_select.ev_16a_charge_mode
state: "Offpeak until charged"
- condition: state
entity_id: binary_sensor.garage_db_control_16a_wallcharger_charging
state: "off"
- action: switch.turn_off
target:
entity_id: switch.garage_db_control_16a_wallcharger_operation
- action: input_select.select_option
target:
entity_id: input_select.ev_16a_charge_mode
data:
option: "Normal (Offpeak)"
#############################################################################
# OFFPEAK END
#############################################################################
- id: ev_16a_charger_offpeak_end
alias: "16A EV Charger - Offpeak End"
mode: single
triggers:
- trigger: time
at: input_datetime.ev_16a_offpeak_end
conditions:
- condition: state
entity_id: input_select.ev_16a_charge_mode
state: "Normal (Offpeak)"
actions:
- action: switch.turn_off
target:
entity_id: switch.garage_db_control_16a_wallcharger_operation
#############################################################################
# USER CHARGE MODE SELECTIONS
#############################################################################
- id: ev_16a_charger_charge_mode_selected
alias: "16A EV Charger - Charge Mode Selected"
mode: restart
triggers:
- trigger: state
entity_id: input_select.ev_16a_charge_mode
actions:
- variables:
selected_mode: "{{ trigger.to_state.state }}"
is_offpeak_now: >
{% set start = states('input_datetime.ev_16a_offpeak_start') %}
{% set end = states('input_datetime.ev_16a_offpeak_end') %}
{% set now_time = now().strftime('%H:%M:%S') %}
{% if start == end %}
{{ true }}
{% elif start < end %}
{{ start <= now_time < end }}
{% else %}
{{ now_time >= start or now_time < end }}
{% endif %}
- choose:
#####################################################################
# NORMAL OFFPEAK
#####################################################################
- conditions:
- condition: template
value_template: "{{ selected_mode == 'Normal (Offpeak)' }}"
sequence:
# No immediate action.
# Normal mode only acts when the offpeak start/end triggers fire.
- stop: "Normal offpeak mode selected."
#####################################################################
# OFFPEAK UNTIL CHARGED
#####################################################################
- conditions:
- condition: template
value_template: "{{ selected_mode == 'Offpeak until charged' }}"
sequence:
- if:
- condition: template
value_template: "{{ is_offpeak_now }}"
then:
- action: switch.turn_on
target:
entity_id: switch.garage_db_control_16a_wallcharger_operation
# If the car never starts charging, or is already full, turn
# off after a 5 minute grace period.
- delay: "00:05:00"
- condition: state
entity_id: input_select.ev_16a_charge_mode
state: "Offpeak until charged"
- condition: state
entity_id: binary_sensor.garage_db_control_16a_wallcharger_charging
state: "off"
- action: switch.turn_off
target:
entity_id: switch.garage_db_control_16a_wallcharger_operation
- action: input_select.select_option
target:
entity_id: input_select.ev_16a_charge_mode
data:
option: "Normal (Offpeak)"
#####################################################################
# 1 HOUR TOPUP NOW
#####################################################################
- conditions:
- condition: template
value_template: "{{ selected_mode == '1hr topup now' }}"
sequence:
- action: input_datetime.set_datetime
target:
entity_id: input_datetime.ev_16a_1hr_topup_until
data:
datetime: >
{{ (as_timestamp(now()) + 3600)
| timestamp_custom('%Y-%m-%d %H:%M:%S', true) }}
- action: switch.turn_on
target:
entity_id: switch.garage_db_control_16a_wallcharger_operation
#####################################################################
# CHARGE NOW UNTIL FULL
#####################################################################
- conditions:
- condition: template
value_template: "{{ selected_mode == 'Charge now until full' }}"
sequence:
- action: switch.turn_on
target:
entity_id: switch.garage_db_control_16a_wallcharger_operation
# If the car never starts charging, or is already full, turn off
# after a 5 minute grace period.
- delay: "00:05:00"
- condition: state
entity_id: input_select.ev_16a_charge_mode
state: "Charge now until full"
- condition: state
entity_id: binary_sensor.garage_db_control_16a_wallcharger_charging
state: "off"
- action: switch.turn_off
target:
entity_id: switch.garage_db_control_16a_wallcharger_operation
- action: input_select.select_option
target:
entity_id: input_select.ev_16a_charge_mode
data:
option: "Normal (Offpeak)"
#####################################################################
# STOP CHARGING NOW
#####################################################################
- conditions:
- condition: template
value_template: "{{ selected_mode == 'Stop charging now' }}"
sequence:
- action: switch.turn_off
target:
entity_id: switch.garage_db_control_16a_wallcharger_operation
- action: input_select.select_option
target:
entity_id: input_select.ev_16a_charge_mode
data:
option: "Normal (Offpeak)"
#############################################################################
# 1 HOUR TOPUP WATCHDOG
#############################################################################
- id: ev_16a_charger_1hr_topup_watchdog
alias: "16A EV Charger - 1hr Topup Watchdog"
mode: single
triggers:
- trigger: time_pattern
minutes: "/1"
- trigger: homeassistant
event: start
conditions:
- condition: state
entity_id: input_select.ev_16a_charge_mode
state: "1hr topup now"
- condition: template
value_template: >
{{ as_timestamp(now()) >=
as_timestamp(states('input_datetime.ev_16a_1hr_topup_until')) }}
actions:
- variables:
is_offpeak_now: >
{% set start = states('input_datetime.ev_16a_offpeak_start') %}
{% set end = states('input_datetime.ev_16a_offpeak_end') %}
{% set now_time = now().strftime('%H:%M:%S') %}
{% if start == end %}
{{ true }}
{% elif start < end %}
{{ start <= now_time < end }}
{% else %}
{{ now_time >= start or now_time < end }}
{% endif %}
- action: input_select.select_option
target:
entity_id: input_select.ev_16a_charge_mode
data:
option: "Normal (Offpeak)"
- choose:
# If the 1 hour topup finishes during offpeak, do not flick the relay.
# Leave it on and let the Normal Offpeak end automation turn it off.
- conditions:
- condition: template
value_template: "{{ is_offpeak_now }}"
sequence:
- if:
- condition: state
entity_id: switch.garage_db_control_16a_wallcharger_operation
state: "off"
then:
- action: switch.turn_on
target:
entity_id: switch.garage_db_control_16a_wallcharger_operation
default:
- if:
- condition: state
entity_id: switch.garage_db_control_16a_wallcharger_operation
state: "on"
then:
- action: switch.turn_off
target:
entity_id: switch.garage_db_control_16a_wallcharger_operation
#############################################################################
# CHARGING COMPLETE MONITOR
#############################################################################
- id: ev_16a_charger_stop_when_charging_complete
alias: "16A EV Charger - Stop When Charging Complete"
mode: single
triggers:
- trigger: state
entity_id: binary_sensor.garage_db_control_16a_wallcharger_charging
to: "off"
for: "00:05:00"
conditions:
- condition: template
value_template: >
{{ states('input_select.ev_16a_charge_mode') in
['Offpeak until charged', 'Charge now until full'] }}
actions:
- action: switch.turn_off
target:
entity_id: switch.garage_db_control_16a_wallcharger_operation
- action: input_select.select_option
target:
entity_id: input_select.ev_16a_charge_mode
data:
option: "Normal (Offpeak)"