Compare commits

...

22 Commits

Author SHA1 Message Date
claus 0b4fc7f2f4 fix presence 2026-03-25 21:06:57 +01:00
claus bef3fc5b4c slettes - redundant 2026-03-25 21:06:25 +01:00
claus 0416ec39de skift navn på dashboard 2026-03-25 20:59:47 +01:00
claus 4d6cd9fc58 commit besked 2026-03-25 07:35:30 +01:00
claus 34ad1c29ca small bug 2026-03-25 07:34:51 +01:00
claus cc42f93c51 feat(lovelace): refactor home dashboard layout and improve data grouping
- removed "antal hjemme" and standalone sunset card
- added weather forecast card with date, sunrise and sunset (template sensors)
- removed outdoor temperature gauge
- reorganized climate data into structured groups:
  - temperature (3 rooms)
  - CO2 (3 rooms)
  - humidity (3 rooms)
- compacted energy and dishwasher into horizontal stack
- simplified vacuum card (reduced noise)
- improved overall layout readability and consistency

focus: better UX, clearer grouping, reduced clutter, production-stable structure
2026-03-25 07:29:32 +01:00
claus 9a4efbcd6a kontekst 2026-03-25 07:19:21 +01:00
claus 40c78ed6af numeric opvasker 2026-03-25 07:15:29 +01:00
claus c91e669761 tesla 2026-03-24 20:45:05 +01:00
claus 98df2da6f9 feat(dashboard): Full Pro SnowyWhite Tesla Lovelace view
- Implemented numeric template sensors for battery, range, charging rate, energy added, and charging state
- Added gauges for battery and range
- Added tiles for charging status, rate, energy, charger power, and time to full charge
- Added Start/Stop charging buttons
- Added history-graph timeline for charging
- Added sections for doors & locks, temperature, arrival info, and maintenance/alerts
- Fully compatible with standard Lovelace (no Dwains Dashboard dependencies)
2026-03-24 20:44:38 +01:00
claus 04e89907cc støvsuger 2026-03-24 19:32:51 +01:00
claus 14548f9509 Fix: Replace roborock-map-card with static xiaomi-vacuum-map-card image
- Removed roborock-map-card causing calibration errors
- Use image.roborock_s8_pro_ultra_map_0 as a static map
- Keep vacuum status, mop, and automations functional
- Avoids "invalid calibration" errors while preserving dashboard functionality
2026-03-24 19:32:32 +01:00
claus 7f0859f446 tesla 2026-03-24 18:25:18 +01:00
claus 64032e6682 tesla charging 2026-03-24 18:24:58 +01:00
claus 6b6b69b766 vacation 2026-03-24 18:24:27 +01:00
claus cbeb832dd7 presence simulation 2026-03-24 18:22:52 +01:00
claus e542dc17c0 map 2026-03-24 18:21:56 +01:00
claus f81430d576 fix 2026-03-24 18:21:27 +01:00
claus 75928671d1 vacation 2026-03-24 18:21:13 +01:00
claus 6074dcac98 modules fixed 2026-03-24 18:20:47 +01:00
claus c979cdbf99 clean up inclusions 2026-03-24 18:20:17 +01:00
claus c60aa24576 tune 2026-03-22 20:02:40 +01:00
24 changed files with 839 additions and 407 deletions
+10 -10
View File
@@ -1,6 +1,11 @@
# --- Global ignores ---
# Ignore everything globally
.DS_Store
custom_components/
blueprints/
dwains-dashboard/
tts/
www/
backups/
old*
# System / runtime folders
@@ -8,6 +13,7 @@ old*
.cloud/
.google.token/
.Rproj.user/
.cache/
# Logs / DB / temp
*.log*
@@ -21,9 +27,6 @@ known_devices.yaml
configuration_full.yaml
configuration_minimal.yaml
# Specific ignore
include/automations/lys_have.yaml
# --- Whitelist core files ---
!*.yaml
!*.md
@@ -38,10 +41,7 @@ include/automations/lys_have.yaml
!include/
!themes/
!python_scripts/
!view/
!dashboards/
# --- Allow structured YAML inside include/ ---
!include/**/*.yaml
# --- Allow view YAML ---
!view/**/*.yaml
# --- Explicitly include all YAML in dashboards subdirs ---
!dashboards/**/*.yaml
+4 -7
View File
@@ -53,13 +53,6 @@ recorder:
zone: !include include/zone/zones.yaml
input_boolean:
first_run:
initial: off
first_run_eve:
initial: off
first_run_stue:
initial: off
timer:
indkorsel:
@@ -113,12 +106,16 @@ device_tracker: !include include/device_trackers.yaml
input_datetime: !include_dir_merge_named include/input/datetime/
input_number: !include_dir_merge_named include/input/number/
input_select: !include_dir_merge_named include/input/select/
input_boolean: !include_dir_merge_named include/input/boolean/
light: !include_dir_merge_list include/lights/
panel_iframe: !include_dir_merge_named include/panels/
script: !include_dir_merge_named include/scripts/
shell_command: !include_dir_merge_named include/shell_commands/
switch: !include_dir_merge_list include/switches/
browser_mod:
lovelace:
mode: yaml
+166 -205
View File
@@ -1,243 +1,204 @@
title: Nørgårdsvej 22
path: home
title: Nørgårdsvej 22 (Main)
path: hjem
icon: mdi:home
type: sections
sections:
cards:
# 👨‍👩‍👧‍👦 Personer (overblik)
- type: grid
# 🌤️ Vejr + dato + sol
- type: vertical-stack
cards:
- type: heading
heading: Familien
- type: glance
entities:
- entity: person.daniel_schusler_dethlefsen
name: Daniel
- entity: person.claus_dethlefsen
name: Claus
- entity: person.anne_schusler_dethlefsen
name: Anne
- entity: person.andreas_schusler_dethlefsen
name: Andreas
# 🗑️ Affald
- type: grid
cards:
- type: heading
heading: Affald
- type: weather-forecast
entity: weather.norgardsvej
show_forecast: true
- type: entities
show_header_toggle: false
entities:
- entity: sensor.affalddk_norgardsvej_22_restaffald
name: Rest
- entity: sensor.affalddk_norgardsvej_22_papir_plast
name: Papir/plast
- entity: sensor.affalddk_norgardsvej_22_haveaffald
name: Have
- entity: sensor.n22_dato
name: Dato
icon: mdi:calendar
- entity: sensor.n22_solopgang
name: Solopgang
icon: mdi:weather-sunset-up
- entity: sensor.n22_solnedgang
name: Solnedgang
icon: mdi:weather-sunset-down
# 👨‍👩‍👧‍👦 Familien
- type: glance
title: Familien
entities:
- entity: person.daniel_schusler_dethlefsen
name: Daniel
- entity: person.claus_dethlefsen
name: Claus
- entity: person.anne_schusler_dethlefsen
name: Anne
- entity: person.andreas_schusler_dethlefsen
name: Andreas
# 🗑️ Affald
- type: entities
title: Affald
entities:
- entity: sensor.affalddk_norgardsvej_22_restaffald
name: Rest
- entity: sensor.affalddk_norgardsvej_22_papir_plast
name: Papir/plast
- entity: sensor.affalddk_norgardsvej_22_haveaffald
name: Have
# 🏠 Hus kontrol
- type: grid
cards:
- type: heading
heading: Hus kontrol
- type: tile
entity: input_boolean.guests_mode
- type: entities
title: Modes
entities:
- entity: input_boolean.guests_mode
name: Vi har gæster
icon: mdi:account-group
- entity: input_boolean.vacation_mode
name: 🌴 Vacation Mode
- entity: input_datetime.vacation_end
name: Slutter
- type: button
name: Godnat
icon: mdi:weather-night
tap_action:
action: call-service
service: scene.turn_on
target:
entity_id: scene.godnat
- type: button
name: Morgen
icon: mdi:weather-sunset-up
tap_action:
action: call-service
service: scene.turn_on
target:
entity_id: scene.morgen
- type: button
name: Hjemme
icon: mdi:home
tap_action:
action: call-service
service: scene.turn_on
target:
entity_id: scene.hjemme
# 🧭 Navigation
- type: grid
# 🌡️ Temperatur + CO2 + Fugt (grupperet pr type)
- type: vertical-stack
cards:
- type: heading
heading: Navigation
- type: button
name: Stue
icon: mdi:sofa
tap_action:
action: navigate
navigation_path: /lovelace/my-dashboard/stue
# Temperatur
- type: horizontal-stack
cards:
- type: gauge
entity: sensor.sovevaerelse_temperatur
name: Soveværelse
min: 15
max: 30
unit: '°C'
- type: gauge
entity: sensor.sovevaerelse_stue_temperatur
name: Andreas
min: 15
max: 30
unit: '°C'
- type: gauge
entity: sensor.sovevaerelse_daniel_temperatur
name: Daniel
min: 15
max: 30
unit: '°C'
- type: button
name: Daniel
icon: mdi:bed
tap_action:
action: navigate
navigation_path: /lovelace/my-dashboard/daniel
# CO2
- type: horizontal-stack
cards:
- type: gauge
entity: sensor.sovevaerelse_carbon_dioxide
name: Soveværelse
min: 400
max: 2000
unit: 'ppm'
- type: gauge
entity: sensor.sovevaerelse_stue_carbon_dioxide
name: Andreas
min: 400
max: 2000
unit: 'ppm'
- type: gauge
entity: sensor.sovevaerelse_daniel_carbon_dioxide
name: Daniel
min: 400
max: 2000
unit: 'ppm'
- type: button
name: Andreas
icon: mdi:bed
tap_action:
action: navigate
navigation_path: /lovelace/my-dashboard/andreas
# Luftfugtighed
- type: horizontal-stack
cards:
- type: gauge
entity: sensor.sovevaerelse_luftfugtighed
name: Soveværelse
min: 20
max: 80
unit: '%'
- type: gauge
entity: sensor.sovevaerelse_stue_luftfugtighed
name: Andreas
min: 20
max: 80
unit: '%'
- type: gauge
entity: sensor.sovevaerelse_daniel_luftfugtighed
name: Daniel
min: 20
max: 80
unit: '%'
- type: button
name: Støvsuger
icon: mdi:robot-vacuum
tap_action:
action: navigate
navigation_path: /lovelace/my-dashboard/vacuum
- type: button
name: Energi
icon: mdi:flash
tap_action:
action: navigate
navigation_path: /lovelace/my-dashboard/energy
# 🌡️ Temperatur
- type: grid
# ⚡ Energi + 🍽️ Opvaskemaskine (kompakt)
- type: horizontal-stack
cards:
- type: heading
heading: Temperatur
- type: tile
entity: sensor.n22_temperatur
name: Ude
- type: tile
entity: sensor.sovevaerelse_temperatur
name: Soveværelse
- type: tile
entity: sensor.sovevaerelse_stue_temperatur
name: Andreas
- type: tile
entity: sensor.sovevaerelse_daniel_temperatur
name: Daniel
# ⚡ Energi
- type: grid
cards:
- type: heading
heading: Energi
- type: tile
- type: gauge
entity: sensor.energi_data_service
name: Elpris
min: 0
max: 5
unit: 'kr/kWh'
severity:
green: 2
yellow: 3
red: 4.5
- type: gauge
entity: sensor.dishwasher_remaining_minutes
name: Opvask
min: 0
max: 180
unit: 'min'
# 🧹 Støvsuger
- type: grid
cards:
- type: heading
heading: Støvsuger
- type: tile
entity: vacuum.roborock_s8_pro_ultra
- type: tile
entity: sensor.roborock_s8_pro_ultra_status
name: Status
- type: tile
entity: sensor.roborock_s8_pro_ultra_vacuum_error
name: Fejl
# 🍽️ Opvaskemaskine
- type: grid
cards:
- type: heading
heading: Opvaskemaskine
- type: tile
entity: sensor.dishwasher_remaining_time_2
name: Tid tilbage
- type: tile
entity: binary_sensor.dishwasher_svigt
name: Fejl
# 🧹 Støvsuger (forenklet mindre støj)
- type: entities
title: Støvsuger
entities:
- vacuum.roborock_s8_pro_ultra
- sensor.roborock_s8_pro_ultra_status
# 🎵 Sonos
- type: grid
cards:
- type: heading
heading: Sonos
- type: glance
entities:
- media_player.stue
- media_player.andreas
- media_player.daniel
- media_player.kokken
- type: glance
title: Sonos
entities:
- media_player.stue
- media_player.andreas
- media_player.daniel
- media_player.kokken
- media_player.alrum
- media_player.badevaerelse
- media_player.sovevaerelse
- media_player.lille_badevaerelse
# 📡 Kamera indikator
- type: grid
- type: glance
title: Kamera
entities:
- binary_sensor.indkoersel_person
- binary_sensor.indkoersel_vehicle
- binary_sensor.terrasse_person
# 🌐 System (let trimmet)
- type: horizontal-stack
cards:
- type: heading
heading: Kamera
- type: glance
entities:
- binary_sensor.indkoersel_person
- binary_sensor.indkoersel_vehicle
- binary_sensor.terrasse_person
# 🌐 System
- type: grid
cards:
- type: heading
heading: System
- type: tile
- type: sensor
entity: sensor.home_assistant_website
name: HA Version
- type: tile
- type: entity
entity: binary_sensor.home_assistant_website_update_available
name: Opdatering
- type: tile
icon: mdi:update
- type: gauge
entity: sensor.speedtest_download
name: Download
- type: tile
min: 0
max: 1000
unit: 'Mbit/s'
- type: gauge
entity: sensor.speedtest_upload
name: Upload
- type: tile
entity: sensor.speedtest_ping
name: Ping
min: 0
max: 500
unit: 'Mbit/s'
+47 -2
View File
@@ -2,12 +2,15 @@ title: Person Status
path: person-status
icon: mdi:account-group
type: sections
max_columns: 1 # én kolonne for fuld bredde
sections:
# 👨‍👩‍👧‍👦 Personer (2x2 grid)
- type: grid
columns: 2
square: false
cards:
- type: heading
heading: Person status
- type: entities
title: Daniel
@@ -32,3 +35,45 @@ sections:
entities:
- entity: person.andreas_schusler_dethlefsen
- entity: input_select.andreas_status
# 🗺️ Popup kort nederst
- type: grid
cards:
- type: custom:button-card
name: Åbn kort
icon: mdi:map
show_state: false
styles:
card:
- border-radius: 16px
- padding: 14px
- background: linear-gradient(135deg, rgba(0,0,0,0.05), rgba(0,0,0,0.1))
icon:
- color: var(--primary-color)
name:
- font-size: 14px
- font-weight: 600
tap_action:
action: call-service
service: browser_mod.popup
service_data:
title: 📍 Familien
size: fullscreen
style:
--popup-border-radius: 20px
--popup-background-color: rgba(0,0,0,0.9)
content:
type: map
default_zoom: 12
hours_to_show: 6
aspect_ratio: 1
entities:
- entity: device_tracker.andreas_iphone_12
name: Andreas
- entity: device_tracker.daniels_iphone_7_3
name: Daniel
- entity: device_tracker.annes_iphone_xs_4
name: Anne
- entity: device_tracker.clausiphone
name: Claus
+3 -7
View File
@@ -11,13 +11,9 @@ sections:
- type: heading
heading: Støvsuger
- type: custom:roborock-map-card
entity: vacuum.roborock_s8_pro_ultra
show_overlay: true
show_mop: true
show_vacuum: true
map_zoom: 1.0
map_size: 400
# Statisk kortbillede uden overlay
- type: picture-entity
entity: image.roborock_s8_pro_ultra_map_0
name: Kort
- type: tile
+93 -67
View File
@@ -1,86 +1,112 @@
title: Tesla
path: tesla
icon: mdi:car-electric
type: sections
cards:
sections:
# 🔋 Batteri og opladning
- type: grid
# 🔋 Batteri & Opladning
- type: vertical-stack
cards:
- type: heading
heading: Batteri & Opladning
- type: gauge
entity: sensor.snowywhite_battery_numeric
name: Batteri
min: 0
max: 100
severity:
green: 50
yellow: 20
red: 0
unit: '%'
- type: tile
entity: sensor.snowywhite_battery_level
name: Batteri (%)
- type: tile
entity: sensor.snowywhite_battery_range
name: Rækkevidde (km)
- type: tile
entity: sensor.snowywhite_charge_state
name: Opladningstilstand
- type: tile
entity: sensor.snowywhite_charge_rate
name: Ladehastighed (km/t)
# 🚗 Døre, låse og tilstand
- type: grid
cards:
- type: heading
heading: Døre & Lås
- type: gauge
entity: sensor.snowywhite_range_numeric
name: Rækkevidde
min: 0
max: 600
severity:
green: 400
yellow: 150
red: 0
unit: 'km'
- type: entities
entities:
- lock.snowywhite_door_lock
- binary_sensor.snowywhite_front_left_door
- binary_sensor.snowywhite_front_right_door
- binary_sensor.snowywhite_rear_left_door
- binary_sensor.snowywhite_rear_right_door
- binary_sensor.snowywhite_trunk
- binary_sensor.snowywhite_frunk
- entity: binary_sensor.snowywhite_charging
name: Oplader nu?
- entity: sensor.snowywhite_charging_rate_numeric
name: Ladehastighed (km/t)
- entity: sensor.snowywhite_energy_added_numeric
name: Energi tilføjet (kWh)
- entity: sensor.snowywhite_charger_power
name: Charger power (kW)
- entity: sensor.snowywhite_time_charge_complete
name: Forventet fuld opladning
- type: tile
entity: sensor.snowywhite_vehicle_state
name: Tilstand
- type: horizontal-stack
cards:
- type: button
name: Start opladning
icon: mdi:flash-circle
tap_action:
action: call-service
service: switch.turn_on
target:
entity_id: switch.home_charging
- type: button
name: Stop opladning
icon: mdi:flash-off
tap_action:
action: call-service
service: switch.turn_off
target:
entity_id: switch.home_charging
# 🕒 Opladning Timeline (graf)
- type: history-graph
title: Ladeplan / Timeline
entities:
- entity: sensor.snowywhite_charging_numeric
name: Lader nu
- entity: sensor.snowywhite_charging_rate_numeric
name: Ladehastighed
- entity: sensor.snowywhite_energy_added_numeric
name: Energi tilføjet
hours_to_show: 24
refresh_interval: 60
# 🚗 Døre & Lås
- type: entities
title: Døre & Lås
entities:
- binary_sensor.snowywhite_doors
- binary_sensor.snowywhite_windows
- binary_sensor.snowywhite_parking_brake
- binary_sensor.snowywhite_user_present
- sensor.snowywhite_shift_state
# 🌡️ Temperatur
- type: grid
- type: horizontal-stack
cards:
- type: heading
heading: Temperatur
- type: tile
entity: sensor.snowywhite_inside_temp
- type: sensor
entity: sensor.snowywhite_temperature_inside
name: Inde (°C)
- type: tile
entity: sensor.snowywhite_outside_temp
- type: sensor
entity: sensor.snowywhite_temperature_outside
name: Ude (°C)
# 📍 Lokation
- type: map
title: Lokation
default_zoom: 15
# 📍 Lokation / Ankomst
- type: entities
title: Ankomst / Distance
entities:
- device_tracker.snowywhite
show_state: true
- sensor.snowywhite_arrival_time
- sensor.snowywhite_distance_to_arrival
# 🔧 Maintenance / alerts
- type: grid
cards:
- type: heading
heading: Vedligeholdelse / Alerts
- type: entities
entities:
- sensor.snowywhite_maintenance_required
- sensor.snowywhite_tire_pressure_alert
- sensor.snowywhite_software_update
# 🔧 Vedligeholdelse / Alerts
- type: entities
title: Vedligeholdelse / Alerts
entities:
- sensor.snowywhite_tpms_front_left
- sensor.snowywhite_tpms_front_right
- sensor.snowywhite_tpms_rear_left
- sensor.snowywhite_tpms_rear_right
- sensor.snowywhite_data_last_update_time
+28
View File
@@ -0,0 +1,28 @@
title: Kort
path: map
icon: mdi:map
type: sections
max_columns: 1
sections:
- type: grid
cards:
- type: heading
heading: Familien live
- type: map
default_zoom: 12
hours_to_show: 6
aspect_ratio: 1
entities:
- entity: device_tracker.andreas_iphone_12
name: Andreas
- entity: device_tracker.daniels_iphone_7_3
name: Daniel
- entity: device_tracker.annes_iphone_xs_4
name: Anne
- entity: device_tracker.clausiphone
name: Claus
@@ -0,0 +1,166 @@
alias: Presence Simulation - Tidsblokke (robust)
mode: restart
trigger:
- platform: time
at: "07:00:00"
- platform: time
at: "12:00:00"
- platform: time
at: "18:00:00"
condition:
- condition: state
entity_id: input_boolean.presence_simulation
state: "on"
action:
- variables:
rand_delay: "{{ range(300,1200) | random }}" # 5-20 min
rand_music: "{{ range(0,100) | random }}"
- choose:
# 🌅 Morgen
- conditions:
- condition: time
after: "06:59:00"
before: "12:00:00"
sequence:
- service: light.turn_on
target:
entity_id:
- light.livingroom
- light.indkoersel_2
- light.andreas_vaerelse
- light.bedroom
- light.daniels_vaerelse
- light.forgang
- delay:
seconds: "{{ rand_delay }}"
- service: light.turn_off
target:
entity_id:
- light.livingroom
- light.indkoersel_2
- light.andreas_vaerelse
- light.bedroom
- light.daniels_vaerelse
- light.forgang
- choose:
- conditions:
- condition: template
value_template: "{{ rand_music < 20 }}"
sequence:
- service: media_player.play_media
target:
entity_id: media_player.kokken
data:
media_content_type: music
media_content_id: "spotify:playlist:37i9dQZF1EVHGWrwldPRtj"
- delay:
seconds: "{{ range(300,900) | random }}"
- service: media_player.media_stop
target:
entity_id: media_player.kokken
# 🌤️ Middag
- conditions:
- condition: time
after: "11:59:00"
before: "18:00:00"
sequence:
- service: light.turn_on
target:
entity_id:
- light.kokken
- light.indkoersel
- delay:
seconds: "{{ rand_delay }}"
- service: light.turn_off
target:
entity_id:
- light.livingroom
- light.indkoersel_2
- light.andreas_vaerelse
- light.bedroom
- light.daniels_vaerelse
- light.forgang
- choose:
- conditions:
- condition: template
value_template: "{{ rand_music < 30 }}"
sequence:
- service: media_player.play_media
target:
entity_id: media_player.kokken
data:
media_content_type: music
media_content_id: "spotify:playlist:37i9dQZF1EVHGWrwldPRtj"
- delay:
seconds: "{{ range(300,900) | random }}"
- service: media_player.media_stop
target:
entity_id: media_player.kokken
# 🌙 Aften
- conditions:
- condition: time
after: "17:59:00"
before: "22:30:00"
sequence:
- service: light.turn_on
target:
entity_id:
- light.livingroom
- light.indkoersel_2
- light.andreas_vaerelse
- light.bedroom
- light.daniels_vaerelse
- light.forgang
- delay:
seconds: "{{ rand_delay }}"
- service: light.turn_off
target:
entity_id:
- light.livingroom
- light.indkoersel_2
- light.andreas_vaerelse
- light.bedroom
- light.daniels_vaerelse
- light.forgang
- choose:
- conditions:
- condition: template
value_template: "{{ rand_music < 50 }}"
sequence:
- service: media_player.play_media
target:
entity_id: media_player.kokken
data:
media_content_type: music
media_content_id: "spotify:playlist:37i9dQZF1EVHGWrwldPRtj"
- delay:
seconds: "{{ range(300,1200) | random }}"
- service: media_player.media_stop
target:
entity_id: media_player.kokken
+15
View File
@@ -0,0 +1,15 @@
alias: Start Vacation Mode
description: Aktiverer presence simulation ved feriestart og planlægger slutdato
trigger:
- platform: time
at: "2026-03-28 14:00:00" # Ferie start
action:
- service: input_boolean.turn_on
target:
entity_id: input_boolean.presence_simulation
# Planlæg slutdato automatisk
- delay:
days: 7
- service: input_boolean.turn_off
target:
entity_id: input_boolean.presence_simulation
+36 -33
View File
@@ -1,71 +1,74 @@
- alias: Tesla smart charging v4
id: tesla_smart_charging_v4
- alias: Tesla smart charging PRO
id: tesla_smart_charging_pro
mode: restart
trigger:
# Kør hvert 5. min (responsiv)
- platform: time_pattern
minutes: "/5"
# Sikrer re-evaluering ved ny time
- platform: time_pattern
minutes: "0"
condition:
# Valid future deadline
# Deadline gyldig
- condition: template
value_template: >
{% set deadline = states('input_datetime.tesla_charge_deadline') %}
{{ deadline not in ['unknown','unavailable','']
and as_timestamp(deadline) > as_timestamp(now()) }}
{{ deadline not in ['unknown','unavailable',''] and as_timestamp(deadline) > as_timestamp(now()) }}
# Car must be connected
- condition: state
entity_id: binary_sensor.snowywhite_charger
state: "on"
# Kun når bilen er tilsluttet
- condition: template
value_template: >
{{ states('binary_sensor.tesla_connected') == 'on' }}
action:
- variables:
charge_now: "{{ is_state('binary_sensor.tesla_charge_now', 'on') }}"
charger_on: "{{ is_state('switch.home_charging', 'on') }}"
should_charge: "{{ states('binary_sensor.tesla_charge_now') == 'on' }}"
last_start: "{{ states('input_datetime.tesla_last_start') }}"
last_start_ts: >
{% if last_start not in ['unknown','unavailable',''] %}
{{ as_timestamp(last_start) }}
{% else %}
0
{% endif %}
runtime: "{{ as_timestamp(now()) - last_start_ts }}"
- choose:
# -------------------------
# START charging (cheap hour)
# START / CONTINUE CHARGING
# -------------------------
- conditions:
- condition: template
value_template: "{{ charge_now and not charger_on }}"
value_template: "{{ should_charge }}"
sequence:
- service: system_log.write
# Hvis ikke allerede i gang → registrer start
- condition: template
value_template: >
{{ states('switch.home_charging') != 'on' }}
- service: input_datetime.set_datetime
target:
entity_id: input_datetime.tesla_last_start
data:
message: "Tesla: START charging (cheap hour)"
level: info
datetime: "{{ now().isoformat() }}"
- service: switch.turn_on
target:
entity_id: switch.home_charging
# -------------------------
# STOP charging (not cheap)
# STOP CHARGING (med hysterese)
# -------------------------
- conditions:
- condition: template
value_template: "{{ not charge_now and charger_on }}"
value_template: >
{{ not should_charge and runtime > 3600 }}
sequence:
- service: system_log.write
data:
message: "Tesla: STOP charging (not cheap)"
level: info
- service: switch.turn_off
target:
entity_id: switch.home_charging
# -------------------------
# Default: do nothing
# -------------------------
- service: system_log.write
data:
message: >
Tesla: No action (charge_now={{ charge_now }},
charger_on={{ charger_on }})
level: debug
+26
View File
@@ -0,0 +1,26 @@
alias: Vacation Mode - Stop ved slutdato
trigger:
- platform: time_pattern
minutes: "/1"
condition:
- condition: state
entity_id: input_boolean.vacation_mode
state: "on"
- condition: template
value_template: >
{% set dt = states('input_datetime.vacation_end') %}
{{ dt not in ['unknown','unavailable',''] and
now() >= as_datetime(dt) }}
action:
- service: input_boolean.turn_off
target:
entity_id:
- input_boolean.vacation_mode
- input_boolean.presence_simulation
- service: media_player.media_stop
target:
entity_id: media_player.kokken
@@ -0,0 +1,26 @@
alias: Vacation Mode - Recovery efter restart
trigger:
- platform: homeassistant
event: start
condition:
- condition: state
entity_id: input_boolean.vacation_mode
state: "on"
action:
- choose:
- conditions:
- condition: template
value_template: >
{% set dt = states('input_datetime.vacation_end') %}
{{ dt not in ['unknown','unavailable',''] and
now() >= as_datetime(dt) }}
sequence:
- service: input_boolean.turn_off
target:
entity_id:
- input_boolean.vacation_mode
- input_boolean.presence_simulation
@@ -0,0 +1,15 @@
alias: Vacation Mode - Manuel stop
trigger:
- platform: state
entity_id: input_boolean.vacation_mode
to: "off"
action:
- service: input_boolean.turn_off
target:
entity_id: input_boolean.presence_simulation
- service: media_player.media_stop
target:
entity_id: media_player.kokken
+6
View File
@@ -0,0 +1,6 @@
first_run:
initial: off
first_run_eve:
initial: off
first_run_stue:
initial: off
+6
View File
@@ -0,0 +1,6 @@
vacation_mode:
name: Vacation Mode
icon: mdi:beach
presence_simulation:
name: Presence Simulation
+4
View File
@@ -3,3 +3,7 @@ tesla_charge_deadline:
has_date: true
has_time: true
tesla_last_start:
name: Tesla last charge start
has_date: true
has_time: true
+5
View File
@@ -0,0 +1,5 @@
vacation_end:
name: Vacation End
has_date: true
has_time: true
+21
View File
@@ -0,0 +1,21 @@
- platform: template
sensors:
dishwasher_remaining_minutes:
friendly_name: "Opvask tid tilbage"
unit_of_measurement: "min"
value_template: >
{% set val = states('sensor.dishwasher_remaining_time_2') %}
{% if val in ['unknown','unavailable',''] %}
0
{% elif ':' in val %}
{% set parts = val.split(':') %}
{{ (parts[0] | int * 60) + (parts[1] | int) }}
{% elif 'min' in val %}
{{ val.replace('min','') | int }}
{% else %}
{{ val | int(0) }}
{% endif %}
+60
View File
@@ -0,0 +1,60 @@
# Konverterer batteri til float
- platform: template
sensors:
snowywhite_battery_numeric:
friendly_name: "Batteri (%)"
unit_of_measurement: "%"
value_template: >
{% set val = states('sensor.snowywhite_battery') %}
{% if val not in ['unknown','unavailable',''] %}
{{ val.replace('%','') | float }}
{% else %}
0
{% endif %}
# Konverterer range til float
snowywhite_range_numeric:
friendly_name: "Rækkevidde (km)"
unit_of_measurement: "km"
value_template: >
{% set val = states('sensor.snowywhite_range') %}
{% if val not in ['unknown','unavailable',''] %}
{{ val.replace(' km','') | float }}
{% else %}
0
{% endif %}
# include/sensors/tesla_timeline_numeric.yaml
- platform: template
sensors:
snowywhite_charging_numeric:
friendly_name: "Charging (numeric)"
unit_of_measurement: "1"
value_template: >
{% if is_state('binary_sensor.snowywhite_charging','on') %}
1
{% else %}
0
{% endif %}
# Dette sikrer altid numeric (0 eller 1)
snowywhite_energy_added_numeric:
friendly_name: "Energy Added (kWh)"
unit_of_measurement: "kWh"
value_template: >
{% set val = states('sensor.snowywhite_energy_added') %}
{% if val not in ['unknown','unavailable',''] %}
{{ val | float }}
{% else %}
0
{% endif %}
snowywhite_charging_rate_numeric:
friendly_name: "Charging Rate (km/h)"
unit_of_measurement: "km/h"
value_template: >
{% set val = states('sensor.snowywhite_charging_rate') %}
{% if val not in ['unknown','unavailable',''] %}
{{ val | float }}
{% else %}
0
{% endif %}
+25
View File
@@ -0,0 +1,25 @@
- platform: template
sensors:
n22_dato:
friendly_name: "Dato"
value_template: >
{{ now().strftime('%A %d %B') | replace('Monday','Mandag')
| replace('Tuesday','Tirsdag')
| replace('Wednesday','Onsdag')
| replace('Thursday','Torsdag')
| replace('Friday','Fredag')
| replace('Saturday','Lørdag')
| replace('Sunday','Søndag') }}
n22_solopgang:
friendly_name: "Solopgang"
value_template: >
{% set t = state_attr('sun.sun','next_rising') %}
{{ as_timestamp(t) | timestamp_custom('%H:%M') if t else '-' }}
n22_solnedgang:
friendly_name: "Solnedgang"
value_template: >
{% set t = state_attr('sun.sun','next_setting') %}
{{ as_timestamp(t) | timestamp_custom('%H:%M') if t else '-' }}
+41
View File
@@ -0,0 +1,41 @@
- binary_sensor:
- name: tesla_charge_now
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 []) %}
{# Filter gyldige slots før deadline #}
{% set valid = [] %}
{% 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] %}
{% endif %}
{% endif %}
{% endfor %}
{# Sortér kronologisk #}
{% set valid = valid | sort(attribute='hour') %}
{# Find billigste sammenhængende blok #}
{% set best_block = [] %}
{% set best_price = 999 %}
{% 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 %}
{% endif %}
{% endfor %}
{% set now_slot = now().replace(minute=0, second=0, microsecond=0).isoformat() %}
{{ best_block | selectattr('hour','equalto',now_slot) | list | count > 0 }}
-74
View File
@@ -1,74 +0,0 @@
sensors:
tesla_kwh_needed:
friendly_name: "Tesla kWh Needed"
unit_of_measurement: "kWh"
value_template: >
{% set capacity = 75 %}
{% set soc = states('sensor.snowywhite_battery') | float(0) %}
{% set limit = states('number.snowywhite_charge_limit') | float(100) %}
{{ [0, ((limit - soc)/100 * capacity)] | max | round(2) }}
tesla_charge_hours_needed:
friendly_name: "Tesla Charge Hours Needed"
unit_of_measurement: "h"
value_template: >
{% set power = 11 %}
{% set kwh = states('sensor.tesla_kwh_needed') | float(0) %}
{{ (kwh / power)|round(2) }}
tesla_charging_plan:
friendly_name: "Tesla Charging Plan"
value_template: >
{% 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 = [1,
states('sensor.tesla_charge_hours_needed') | float(0) | round(0, 'ceil')
] | max %}
{% set prices = (state_attr('sensor.energidataservice','today') or [])
+ (state_attr('sensor.energidataservice','tomorrow') or []) %}
{% 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 %}
{% set cheapest = (valid | sort(attribute='price'))[:hours_needed] %}
{% set times = cheapest
| map(attribute='hour')
| map('as_timestamp')
| map('timestamp_local')
| list %}
{{ times | join(', ') if times | count > 0 else 'none' }}
binary_sensors:
tesla_charge_now:
friendly_name: "Tesla Charge Now"
device_class: power
value_template: >
{% set hours_needed = [1, states('sensor.tesla_charge_hours_needed') | float(0) | round(0, 'ceil')] | max %}
{% 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 prices = (state_attr('sensor.energidataservice','today') or []) + (state_attr('sensor.energidataservice','tomorrow') or []) %}
{% set valid_prices = [] %}
{% 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_prices = valid_prices + [p] %}
{% endif %}
{% endif %}
{% endfor %}
{% set cheapest = (valid_prices | sort(attribute='price'))[:hours_needed] %}
{% set now_ts = now().replace(minute=0, second=0, microsecond=0).timestamp() %}
{% set cheapest_ts = cheapest | map(attribute='hour') | map('as_timestamp') | list %}
{{ now_ts in cheapest_ts }}
+31
View File
@@ -0,0 +1,31 @@
Jeg arbejder med Home Assistant version 2026.3.3.
Min konfiguration er 100% YAML-baseret og opdelt via !include_dir_merge_* og !include i en struktureret mappestruktur (templates, sensors, automations, binary_sensors, input_*, osv.). Jeg forventer løsninger, der respekterer denne opdeling og er direkte kompatible med en splittet konfiguration.
Jeg bruger standard Lovelace (YAML mode) ikke UI editor og ikke Dwains Dashboard. Alle dashboards skal derfor leveres som valid Lovelace YAML.
Antag følgende:
- Jeg er erfaren HA-bruger
- Jeg ønsker robuste, produktionsegnet løsninger
- Jeg prioriterer stabilitet over “smart hacks”
- Jeg vil undgå unknown/unavailable states og template-fejl
- Jeg vil have korrekt datatype-håndtering (float/int/string)
- Jeg vil minimere race conditions og edge cases
Når du svarer:
- Giv altid copy-paste klar YAML
- Indiker hvor filer skal placeres (fx include/sensors/xxx.yaml)
- Brug defensive templates (default værdier, checks for unknown/unavailable)
- Undgå deprecated eller UI-only features
- Optimer for performance (undgå unødvendige loops / tunge templates)
- Forklar kort hvorfor løsningen er korrekt men vær præcis og teknisk
Hvis relevant:
- Foreslå forbedringer i arkitektur (ikke kun fixes)
- Identificér potentielle fejl før de opstår
- Prioritér simplicity + robustness over kompleksitet
Kort sagt: agér som en Home Assistant arkitekt/debugger og optimer min opsætning.
Skriv en commit besked som jeg kan bruge til git.
+4 -1
View File
@@ -2,8 +2,11 @@
# 1. Resources til custom cards
resources:
- url: /hacsfiles/lovelace-xiaomi-vacuum-map-card/roborock-map-card.js
- url: /hacsfiles/lovelace-xiaomi-vacuum-map-card/xiaomi-vacuum-map-card.js
type: module
- url: /hacsfiles/button-card/button-card.js
type: module
# 2. Selve views
views: !include_dir_list dashboards/views