From 4a155ad54520082e43ea4f8edb21e08527ea8735 Mon Sep 17 00:00:00 2001 From: Claus Dethlefsen Date: Mon, 16 Mar 2026 16:51:30 +0100 Subject: [PATCH] feat: implement Tesla smart charging v3 for Zaptec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Beregner manglende kWh baseret på SOC og charge limit - Finder de billigste 15-min elspot-timer før deadline - Starter/stopper opladning via switch.home_charging - Tilføjer failsafe 1 time før deadline - Håndterer connected_finished session reset automatisk - Stopper opladning når charge limit er nået - Fuld modulopdeling: input_datetime, templates, binary_sensors, automations --- .../automations/tesla_charge_failsafe.yaml | 0 include/automations/tesla_smart_charging.yaml | 44 +++++++++++++++++++ include/automations/tesla_stop_when_full.yaml | 12 +++++ .../binary_sensors/tesla_smart_charge.yaml | 25 +++++++++++ include/input/datetime/tesla.yaml | 0 include/templates/tesla_charging.yaml | 16 +++++++ 6 files changed, 97 insertions(+) create mode 100644 include/automations/tesla_charge_failsafe.yaml create mode 100644 include/automations/tesla_smart_charging.yaml create mode 100644 include/automations/tesla_stop_when_full.yaml create mode 100644 include/binary_sensors/tesla_smart_charge.yaml create mode 100644 include/input/datetime/tesla.yaml create mode 100644 include/templates/tesla_charging.yaml diff --git a/include/automations/tesla_charge_failsafe.yaml b/include/automations/tesla_charge_failsafe.yaml new file mode 100644 index 0000000..e69de29 diff --git a/include/automations/tesla_smart_charging.yaml b/include/automations/tesla_smart_charging.yaml new file mode 100644 index 0000000..cdd9fe9 --- /dev/null +++ b/include/automations/tesla_smart_charging.yaml @@ -0,0 +1,44 @@ +- alias: Tesla smart charging v3 + mode: single + + trigger: + - platform: time_pattern + minutes: "/5" + + condition: + - condition: time + before: input_datetime.tesla_charge_deadline + + action: + - choose: + + - conditions: + - condition: state + entity_id: binary_sensor.tesla_charge_now + state: "on" + + sequence: + # Reset hvis session står i connected_finished + - choose: + - conditions: + - condition: template + value_template: "{{ states('sensor.home_charger_mode') == 'connected_finished' }}" + sequence: + - service: switch.turn_off + target: + entity_id: switch.home_charging + - delay: "00:00:05" + + - service: switch.turn_on + target: + entity_id: switch.home_charging + + - conditions: + - condition: state + entity_id: binary_sensor.tesla_charge_now + state: "off" + + sequence: + - service: switch.turn_off + target: + entity_id: switch.home_charging \ No newline at end of file diff --git a/include/automations/tesla_stop_when_full.yaml b/include/automations/tesla_stop_when_full.yaml new file mode 100644 index 0000000..463c04a --- /dev/null +++ b/include/automations/tesla_stop_when_full.yaml @@ -0,0 +1,12 @@ +- alias: Tesla stop when charged + trigger: + - platform: template + value_template: > + {{ states('sensor.snowywhite_battery')|float >= + states('number.snowywhite_charge_limit')|float }} + + action: + - service: switch.turn_off + target: + entity_id: switch.home_charging + \ No newline at end of file diff --git a/include/binary_sensors/tesla_smart_charge.yaml b/include/binary_sensors/tesla_smart_charge.yaml new file mode 100644 index 0000000..bc1ee3a --- /dev/null +++ b/include/binary_sensors/tesla_smart_charge.yaml @@ -0,0 +1,25 @@ +- name: tesla_charge_now + state: > + {% set deadline = states('input_datetime.tesla_charge_deadline') %} + {% set hours_needed = states('sensor.tesla_charge_hours_needed')|float(0)|round(0,'ceil') %} + {% set prices = state_attr('sensor.energidataservice','today') + state_attr('sensor.energidataservice','tomorrow') %} + {% set valid = [] %} + + {# Filtrer kun timer før deadline #} + {% for p in prices %} + {% set slot_time = as_timestamp(strptime(p.hour,'%Y-%m-%dT%H:%M:%S')) %} + {% if slot_time <= as_timestamp(deadline) %} + {% set valid = valid + [p] %} + {% endif %} + {% endfor %} + + {# Sorter efter pris #} + {% set sorted = valid | sort(attribute='price') %} + + {# Vælg de billigste slots der dækker ladetiden #} + {% set cheapest = sorted[:hours_needed] %} + + {# Tjek om nuværende slot er i listen #} + {% set now_slot = now().replace(minute=(now().minute//15)*15, second=0, microsecond=0).isoformat() %} + {{ cheapest | selectattr('hour','equalto',now_slot) | list | count > 0 }} + \ No newline at end of file diff --git a/include/input/datetime/tesla.yaml b/include/input/datetime/tesla.yaml new file mode 100644 index 0000000..e69de29 diff --git a/include/templates/tesla_charging.yaml b/include/templates/tesla_charging.yaml new file mode 100644 index 0000000..ac01bce --- /dev/null +++ b/include/templates/tesla_charging.yaml @@ -0,0 +1,16 @@ +- sensor: + + - name: tesla_kwh_needed + unit_of_measurement: "kWh" + state: > + {% set capacity = 75 %} + {% set soc = states('sensor.snowywhite_battery')|float %} + {% set limit = states('number.snowywhite_charge_limit')|float %} + {{ ((limit - soc)/100 * capacity)|round(2) }} + + - name: tesla_charge_hours_needed + unit_of_measurement: "h" + state: > + {% set power = 11 %} + {% set kwh = states('sensor.tesla_kwh_needed')|float %} + {{ (kwh / power)|round(2) }} \ No newline at end of file