# 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)"