diff --git a/dashboards/views/09_tesla.yaml b/dashboards/views/09_tesla.yaml index fc35c88..63af162 100644 --- a/dashboards/views/09_tesla.yaml +++ b/dashboards/views/09_tesla.yaml @@ -7,7 +7,7 @@ cards: - type: vertical-stack cards: - type: gauge - entity: sensor.snowywhite_battery_numeric + entity: sensor.batteri name: Batteri min: 0 max: 100 @@ -18,7 +18,7 @@ cards: unit: '%' - type: gauge - entity: sensor.snowywhite_range_numeric + entity: sensor.raekkevidde_km name: Rækkevidde min: 0 max: 600 @@ -32,9 +32,9 @@ cards: entities: - entity: binary_sensor.snowywhite_charging name: Oplader nu? - - entity: sensor.snowywhite_charging_rate_numeric + - entity: sensor.charging_rate_km_h name: Ladehastighed (km/t) - - entity: sensor.snowywhite_energy_added_numeric + - entity: sensor.energy_added_kwh name: Energi tilføjet (kWh) - entity: sensor.snowywhite_charger_power name: Charger power (kW) @@ -49,7 +49,7 @@ cards: tap_action: action: call-service service: switch.turn_on - target: + service_data: entity_id: switch.home_charging - type: button @@ -58,18 +58,37 @@ cards: tap_action: action: call-service service: switch.turn_off - target: + service_data: entity_id: switch.home_charging - # 🕒 Opladning Timeline (graf) - - type: history-graph - title: Ladeplan / Timeline + # 🕒 Opladningsplan + - type: entities + title: Opladningsplan entities: - - entity: sensor.snowywhite_charging_numeric + - entity: binary_sensor.tesla_charge_now + name: Skal lade nu + - entity: sensor.tesla_charge_plan + name: Billigste vindue + - entity: sensor.tesla_charge_hours_needed + name: Timer nødvendige + - entity: input_datetime.tesla_charge_deadline + name: Klar senest + - entity: input_datetime.tesla_last_start + name: Sidste start + - entity: number.snowywhite_charge_limit + name: Lademål + - entity: binary_sensor.snowywhite_charger + name: Tilsluttet lader + + # 📈 Faktisk opladning + - type: history-graph + title: Faktisk opladning sidste 24 timer + entities: + - entity: sensor.charging_numeric name: Lader nu - - entity: sensor.snowywhite_charging_rate_numeric + - entity: sensor.charging_rate_km_h name: Ladehastighed - - entity: sensor.snowywhite_energy_added_numeric + - entity: sensor.energy_added_kwh name: Energi tilføjet hours_to_show: 24 refresh_interval: 60 diff --git a/include/templates/legacy_sensors.yaml b/include/templates/legacy_sensors.yaml index dcafd38..d28fc8c 100644 --- a/include/templates/legacy_sensors.yaml +++ b/include/templates/legacy_sensors.yaml @@ -16,7 +16,7 @@ state: > {% set val = states('sensor.snowywhite_range') %} {% if val not in ['unknown','unavailable',''] %} - {{ val.replace(' km','') | float }} + {{ val.replace(' km','') | float | round(0) | int }} {% else %} 0 {% endif %} diff --git a/include/templates/tesla_charge_plan.yaml b/include/templates/tesla_charge_plan.yaml index ebbd4e1..3096892 100644 --- a/include/templates/tesla_charge_plan.yaml +++ b/include/templates/tesla_charge_plan.yaml @@ -10,32 +10,81 @@ + (state_attr('sensor.energidataservice','tomorrow') or []) %} {# Filter gyldige slots før deadline #} - {% set valid = [] %} + {% set ns = namespace(valid=[], best_block=[], best_price=999999) %} {% for p in prices %} {% if p.hour %} {% set ts = as_timestamp(p.hour) %} {% if not deadline_ts or ts <= deadline_ts %} - {% set valid = valid + [p] %} + {% set ns.valid = ns.valid + [p] %} {% endif %} {% endif %} {% endfor %} {# Sortér kronologisk #} - {% set valid = valid | sort(attribute='hour') %} - - {# Find billigste sammenhængende blok #} - {% set best_block = [] %} - {% set best_price = 999 %} + {% set valid = ns.valid | sort(attribute='hour') %} {% for i in range(0, (valid | length) - hours_needed + 1) %} {% set block = valid[i:i+hours_needed] %} {% set total = block | map(attribute='price') | sum %} - {% if total < best_price %} - {% set best_price = total %} - {% set best_block = block %} + {% if total < ns.best_price %} + {% set ns.best_price = total %} + {% set ns.best_block = block %} {% endif %} {% endfor %} {% set now_slot = now().replace(minute=0, second=0, microsecond=0).isoformat() %} - {{ best_block | selectattr('hour','equalto',now_slot) | list | count > 0 }} + {{ ns.best_block | selectattr('hour','equalto',now_slot) | list | count > 0 }} + +- sensor: + - name: tesla_charge_hours_needed + unique_id: tesla_charge_hours_needed + unit_of_measurement: h + icon: mdi:timer-outline + state: > + {% set battery = states('sensor.snowywhite_battery') | replace('%', '') | float(0) %} + {% set limit = states('number.snowywhite_charge_limit') | float(100) %} + {% set charger_power = states('sensor.snowywhite_charger_power') | float(0) %} + {% set effective_power = charger_power if charger_power > 0 else 11 %} + {% set battery_capacity_kwh = 75 %} + {% set remaining_pct = [limit - battery, 0] | max %} + {% set energy_needed = remaining_pct * battery_capacity_kwh / 100 %} + {{ (energy_needed / effective_power) | round(1) }} + + - name: tesla_charge_plan + unique_id: tesla_charge_plan + icon: mdi:calendar-clock + state: > + {% set deadline_raw = 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') or []) + + (state_attr('sensor.energidataservice','tomorrow') or []) %} + {% set ns = namespace(valid=[], best_block=[], best_price=999999) %} + + {% for p in prices %} + {% if p.hour %} + {% set ts = as_timestamp(p.hour) %} + {% if not deadline_ts or ts <= deadline_ts %} + {% set ns.valid = ns.valid + [p] %} + {% endif %} + {% endif %} + {% endfor %} + + {% set valid = ns.valid | sort(attribute='hour') %} + {% for i in range(0, (valid | length) - hours_needed + 1) %} + {% set block = valid[i:i+hours_needed] %} + {% set total = block | map(attribute='price') | sum %} + {% if total < ns.best_price %} + {% set ns.best_price = total %} + {% set ns.best_block = block %} + {% endif %} + {% endfor %} + + {% if hours_needed <= 0 %} + Ingen opladning nødvendig + {% elif ns.best_block | length == 0 %} + Ingen plan fundet + {% else %} + {{ as_timestamp(ns.best_block[0].hour) | timestamp_custom('%H:%M') }}-{{ (as_timestamp(ns.best_block[-1].hour) + 3600) | timestamp_custom('%H:%M') }} + {% endif %}