390 lines
13 KiB
YAML
390 lines
13 KiB
YAML
# yaml-language-server: $schema=null
|
|
|
|
###############################################################################
|
|
# PACKAGE: 16A EV Charger Control
|
|
###############################################################################
|
|
#
|
|
# VERSION:
|
|
# 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 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.
|
|
#
|
|
# 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)"
|