Compare commits

...

4 Commits

Author SHA1 Message Date
claus 5a9db0b8c2 improve(automation): increase reliability of tesla charging control
- Change mode to restart to prevent skipped runs
- Replace failsafe template trigger with time_pattern
- Add plugged-in condition to avoid unnecessary switching
- Add explicit deadline validation condition

Result:
- More reliable execution of charging logic
- Prevents missed failsafe activation
- Reduces unnecessary charger toggling
2026-03-17 06:18:50 +01:00
claus dde5ff292a fix(template): correct and simplify tesla_charge_now logic
- Convert tesla_charge_now to binary_sensor
- Replace strptime with as_timestamp for robust time parsing
- Fix hour alignment (remove 15-min slot mismatch)
- Implement proper deadline filtering using timestamps
- Simplify template to minimal, readable logic

Result:
- Accurate identification of cheapest charging hours
- Eliminates false negatives in charge scheduling
2026-03-17 06:18:27 +01:00
claus bed93b148f Get rid of warnings in the log 2026-03-16 21:03:57 +01:00
claus da931bbca6 Make startup happy 2026-03-16 19:38:07 +01:00
3 changed files with 34 additions and 29 deletions
@@ -1,12 +1,15 @@
- alias: Tesla failsafe charge - alias: Tesla failsafe charge
trigger: trigger:
- platform: template - platform: time_pattern
minutes: "/5"
condition:
- condition: template
value_template: > value_template: >
{% set deadline_ts = as_timestamp(states('input_datetime.tesla_charge_deadline')) %} {% set deadline_ts = as_timestamp(states('input_datetime.tesla_charge_deadline')) %}
{% set now_ts = as_timestamp(now()) %} {% set now_ts = as_timestamp(now()) %}
{{ (deadline_ts - now_ts) <= 3600 }} # 1 time = 3600 sekunder {{ (deadline_ts - now_ts) <= 3600 }}
condition:
- condition: numeric_state - condition: numeric_state
entity_id: sensor.tesla_kwh_needed entity_id: sensor.tesla_kwh_needed
above: 0 above: 0
@@ -14,4 +17,4 @@
action: action:
- service: switch.turn_on - service: switch.turn_on
target: target:
entity_id: switch.home_charging entity_id: switch.home_charging
@@ -2,8 +2,8 @@
trigger: trigger:
- platform: template - platform: template
value_template: > value_template: >
{{ states('sensor.snowywhite_battery')|float >= {{ (states('sensor.snowywhite_battery') | default(0)) | float >=
states('number.snowywhite_charge_limit')|float }} (states('number.snowywhite_charge_limit') | default(100)) | float }}
action: action:
- service: switch.turn_off - service: switch.turn_off
+25 -23
View File
@@ -1,27 +1,29 @@
platform: template binary_sensor:
sensors: - name: tesla_charge_now
- name: tesla_charge_now state: >
state: > {% set deadline_raw = states('input_datetime.tesla_charge_deadline') %}
{% set deadline = states('input_datetime.tesla_charge_deadline') %} {% set deadline_ts = as_timestamp(deadline_raw) if deadline_raw not in ['unknown','unavailable',''] else none %}
{% 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 #} {% set hours_needed = states('sensor.tesla_charge_hours_needed') | float(0) | round(0, 'ceil') %}
{% 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 prices = (state_attr('sensor.energidataservice','today') or [])
{% set sorted = valid | sort(attribute='price') %} + (state_attr('sensor.energidataservice','tomorrow') or []) %}
{# Vælg de billigste slots der dækker ladetiden #} {# Filter valid price entries and apply deadline #}
{% set cheapest = sorted[:hours_needed] %} {% set valid = [] %}
{% for p in prices %}
{% if p.hour is defined and p.hour %}
{% set ts = as_timestamp(p.hour) %}
{% if not deadline_ts or ts <= deadline_ts %}
{% set valid = valid + [p] %}
{% endif %}
{% endif %}
{% endfor %}
{# Tjek om nuværende slot er i listen #} {# Pick cheapest hours #}
{% set now_slot = now().replace(minute=(now().minute//15)*15, second=0, microsecond=0).isoformat() %} {% set cheapest = (valid | sort(attribute='price'))[:hours_needed] %}
{{ cheapest | selectattr('hour','equalto',now_slot) | list | count > 0 }}
{# Current hour #}
{% set now_slot = now().replace(minute=0, second=0, microsecond=0).isoformat() %}
{{ cheapest | selectattr('hour','equalto',now_slot) | list | count > 0 }}