Files
N22/dashboards/views/01_home.yaml
T

869 lines
26 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
title: Overblik
path: home
icon: mdi:home
cards:
# 🌤️ Vejr + dato + sol
- type: vertical-stack
cards:
- type: weather-forecast
entity: weather.norgardsvej
show_forecast: true
- type: glance
columns: 5
show_icon: true
show_name: true
show_state: true
entities:
- entity: sensor.dato
name: Dato
icon: mdi:calendar
- entity: sensor.solopgang
name: Sol op
icon: mdi:weather-sunset-up
- entity: sensor.solnedgang
name: Sol ned
icon: mdi:weather-sunset-down
- entity: binary_sensor.arbejdsdag
name: I dag
icon: mdi:briefcase
- entity: binary_sensor.arbejdsdagimorgen
name: I morgen
icon: mdi:briefcase-outline
# 👨‍👩‍👧‍👦 Familien tryk for at toggle syg/rask
- type: grid
columns: 4
square: false
cards:
- type: custom:button-card
entity: person.daniel_schusler_dethlefsen
name: Daniel
show_name: true
show_state: false
show_label: true
show_icon: false
show_entity_picture: true
label: >
[[[
const s = entity.state;
const sick = states['input_select.daniel_status'] &&
states['input_select.daniel_status'].state === 'syg';
const loc = s === 'home' ? 'Hjemme' : s === 'not_home' ? 'Ude' : s;
return sick ? loc + ' · Syg' : loc;
]]]
styles:
card:
- padding: 8px 4px
- border: >
[[[
return states['input_select.daniel_status'] &&
states['input_select.daniel_status'].state === 'syg'
? '2px solid rgba(220,50,50,0.8)' : '2px solid transparent';
]]]
- border-radius: 12px
entity_picture:
- width: 60px
- height: 60px
- border-radius: 50%
- object-fit: cover
- filter: >
[[[
return states['input_select.daniel_status'] &&
states['input_select.daniel_status'].state === 'syg'
? 'grayscale(100%)' : 'none';
]]]
name:
- font-size: 12px
- font-weight: 600
- padding-top: 6px
- color: >
[[[
return states['input_select.daniel_status'] &&
states['input_select.daniel_status'].state === 'syg'
? 'rgb(220,50,50)' : 'var(--primary-text-color)';
]]]
label:
- font-size: 10px
- color: var(--secondary-text-color)
- padding-bottom: 2px
tap_action:
action: call-service
service: input_select.select_option
service_data:
entity_id: input_select.daniel_status
option: >
[[[
return states['input_select.daniel_status'] &&
states['input_select.daniel_status'].state === 'syg'
? 'hjemme' : 'syg';
]]]
hold_action:
action: more-info
entity: person.daniel_schusler_dethlefsen
- type: custom:button-card
entity: person.claus_dethlefsen
name: Claus
show_name: true
show_state: false
show_label: true
show_icon: false
show_entity_picture: true
label: >
[[[
const s = entity.state;
const sick = states['input_select.claus_status'] &&
states['input_select.claus_status'].state === 'syg';
const loc = s === 'home' ? 'Hjemme' : s === 'not_home' ? 'Ude' : s;
return sick ? loc + ' · Syg' : loc;
]]]
styles:
card:
- padding: 8px 4px
- border: >
[[[
return states['input_select.claus_status'] &&
states['input_select.claus_status'].state === 'syg'
? '2px solid rgba(220,50,50,0.8)' : '2px solid transparent';
]]]
- border-radius: 12px
entity_picture:
- width: 60px
- height: 60px
- border-radius: 50%
- object-fit: cover
- filter: >
[[[
return states['input_select.claus_status'] &&
states['input_select.claus_status'].state === 'syg'
? 'grayscale(100%)' : 'none';
]]]
name:
- font-size: 12px
- font-weight: 600
- padding-top: 6px
- color: >
[[[
return states['input_select.claus_status'] &&
states['input_select.claus_status'].state === 'syg'
? 'rgb(220,50,50)' : 'var(--primary-text-color)';
]]]
label:
- font-size: 10px
- color: var(--secondary-text-color)
- padding-bottom: 2px
tap_action:
action: call-service
service: input_select.select_option
service_data:
entity_id: input_select.claus_status
option: >
[[[
return states['input_select.claus_status'] &&
states['input_select.claus_status'].state === 'syg'
? 'hjemme' : 'syg';
]]]
hold_action:
action: more-info
entity: person.claus_dethlefsen
- type: custom:button-card
entity: person.anne_schusler_dethlefsen
name: Anne
show_name: true
show_state: false
show_label: true
show_icon: false
show_entity_picture: true
label: >
[[[
const s = entity.state;
const sick = states['input_select.anne_status'] &&
states['input_select.anne_status'].state === 'syg';
const loc = s === 'home' ? 'Hjemme' : s === 'not_home' ? 'Ude' : s;
return sick ? loc + ' · Syg' : loc;
]]]
styles:
card:
- padding: 8px 4px
- border: >
[[[
return states['input_select.anne_status'] &&
states['input_select.anne_status'].state === 'syg'
? '2px solid rgba(220,50,50,0.8)' : '2px solid transparent';
]]]
- border-radius: 12px
entity_picture:
- width: 60px
- height: 60px
- border-radius: 50%
- object-fit: cover
- filter: >
[[[
return states['input_select.anne_status'] &&
states['input_select.anne_status'].state === 'syg'
? 'grayscale(100%)' : 'none';
]]]
name:
- font-size: 12px
- font-weight: 600
- padding-top: 6px
- color: >
[[[
return states['input_select.anne_status'] &&
states['input_select.anne_status'].state === 'syg'
? 'rgb(220,50,50)' : 'var(--primary-text-color)';
]]]
label:
- font-size: 10px
- color: var(--secondary-text-color)
- padding-bottom: 2px
tap_action:
action: call-service
service: input_select.select_option
service_data:
entity_id: input_select.anne_status
option: >
[[[
return states['input_select.anne_status'] &&
states['input_select.anne_status'].state === 'syg'
? 'hjemme' : 'syg';
]]]
hold_action:
action: more-info
entity: person.anne_schusler_dethlefsen
- type: custom:button-card
entity: person.andreas_schusler_dethlefsen
name: Andreas
show_name: true
show_state: false
show_label: true
show_icon: false
show_entity_picture: true
label: >
[[[
const s = entity.state;
const sick = states['input_select.andreas_status'] &&
states['input_select.andreas_status'].state === 'syg';
const loc = s === 'home' ? 'Hjemme' : s === 'not_home' ? 'Ude' : s;
return sick ? loc + ' · Syg' : loc;
]]]
styles:
card:
- padding: 8px 4px
- border: >
[[[
return states['input_select.andreas_status'] &&
states['input_select.andreas_status'].state === 'syg'
? '2px solid rgba(220,50,50,0.8)' : '2px solid transparent';
]]]
- border-radius: 12px
entity_picture:
- width: 60px
- height: 60px
- border-radius: 50%
- object-fit: cover
- filter: >
[[[
return states['input_select.andreas_status'] &&
states['input_select.andreas_status'].state === 'syg'
? 'grayscale(100%)' : 'none';
]]]
name:
- font-size: 12px
- font-weight: 600
- padding-top: 6px
- color: >
[[[
return states['input_select.andreas_status'] &&
states['input_select.andreas_status'].state === 'syg'
? 'rgb(220,50,50)' : 'var(--primary-text-color)';
]]]
label:
- font-size: 10px
- color: var(--secondary-text-color)
- padding-bottom: 2px
tap_action:
action: call-service
service: input_select.select_option
service_data:
entity_id: input_select.andreas_status
option: >
[[[
return states['input_select.andreas_status'] &&
states['input_select.andreas_status'].state === 'syg'
? 'hjemme' : 'syg';
]]]
hold_action:
action: more-info
entity: person.andreas_schusler_dethlefsen
# 🪟 Gardiner
- type: grid
columns: 6
square: false
cards:
- type: button
name: ""
icon: mdi:blinds-open
tap_action:
action: call-service
service: scene.turn_on
target:
entity_id: scene.alle_lidt_nede
- type: button
name: ""
icon: mdi:blinds
tap_action:
action: call-service
service: scene.turn_on
target:
entity_id: scene.n22_alt_ned
- type: button
name: ""
icon: mdi:blinds-horizontal
tap_action:
action: call-service
service: scene.turn_on
target:
entity_id: scene.morgen
- type: button
name: ""
icon: mdi:window-shutter
tap_action:
action: call-service
service: scene.turn_on
target:
entity_id: scene.syd_ned_venstre_halvt_ned
- type: button
name: ""
icon: mdi:television-ambient-light
tap_action:
action: call-service
service: scene.turn_on
target:
entity_id: scene.n22_tv
- type: button
name: ""
icon: mdi:silverware-fork-knife
tap_action:
action: call-service
service: scene.turn_on
target:
entity_id: scene.n22_spisetid
# 🧹 Støvsuger
- type: horizontal-stack
cards:
- type: custom:button-card
entity: sensor.roborock_last_clean_end_compact
show_icon: false
show_name: true
show_state: true
name: Sidst kørt
tap_action:
action: none
hold_action:
action: none
styles:
card:
- padding: 8px
name:
- font-size: 11px
- color: var(--secondary-text-color)
- padding-bottom: 4px
state:
- white-space: normal
- word-break: break-word
- line-height: 1.2
- font-size: 13px
- text-align: center
- type: button
name: Køkken
icon: mdi:floor-plan
tap_action:
action: call-service
service: script.turn_on
target:
entity_id: script.roborock_manuelt_kokken
- type: button
name: Syd
icon: mdi:floor-plan
tap_action:
action: call-service
service: script.turn_on
target:
entity_id: script.roborock_manuelt_syd
- type: button
name: Mop
icon: mdi:floor-plan
tap_action:
action: call-service
service: script.turn_on
target:
entity_id: script.roborock_manuelt_mop
- type: custom:button-card
entity: vacuum.roborock_s8_pro_ultra
name: Start
icon: mdi:robot-vacuum
tap_action:
action: call-service
service: script.turn_on
target:
entity_id: script.roborock_manuelt_start
state:
- value: cleaning
name: Dock
styles:
card:
- background-color: rgba(255, 200, 0, 0.25)
- border: 1px solid rgba(255, 200, 0, 0.8)
tap_action:
action: call-service
service: vacuum.return_to_base
target:
entity_id: vacuum.roborock_s8_pro_ultra
- value: returning
name: Dock
styles:
card:
- background-color: rgba(255, 200, 0, 0.25)
- border: 1px solid rgba(255, 200, 0, 0.8)
tap_action:
action: call-service
service: vacuum.return_to_base
target:
entity_id: vacuum.roborock_s8_pro_ultra
- value: paused
name: Dock
styles:
card:
- background-color: rgba(255, 200, 0, 0.25)
- border: 1px solid rgba(255, 200, 0, 0.8)
tap_action:
action: call-service
service: vacuum.return_to_base
target:
entity_id: vacuum.roborock_s8_pro_ultra
# 🏎️ Plæneklipper
- type: horizontal-stack
cards:
- type: custom:button-card
entity: input_datetime.ploeneklipper_sidst_koert
show_icon: false
show_name: true
show_state: false
show_label: true
name: Sidst klippet
label: >
[[[
const s = entity.state;
if (!s || s === 'unknown') return 'Ukendt';
const d = new Date(s.replace(' ', 'T'));
if (isNaN(d)) return s;
const now = new Date();
const isToday = d.toDateString() === now.toDateString();
const yesterday = new Date(now);
yesterday.setDate(now.getDate() - 1);
const isYesterday = d.toDateString() === yesterday.toDateString();
const t = d.toLocaleTimeString('da-DK', {hour: '2-digit', minute: '2-digit'});
if (isToday) return 'I dag ' + t;
if (isYesterday) return 'I g\u00e5r ' + t;
return d.toLocaleDateString('da-DK', {day: 'numeric', month: 'short'}) + ' ' + t;
]]]
tap_action:
action: none
styles:
card:
- padding: 8px
name:
- font-size: 11px
- color: var(--secondary-text-color)
- padding-bottom: 4px
label:
- white-space: normal
- word-break: break-word
- line-height: 1.2
- font-size: 13px
- text-align: center
- type: custom:button-card
entity: lawn_mower.husqvarna_automower
name: Klip
icon: mdi:robot-mower
tap_action:
action: call-service
service: script.turn_on
target:
entity_id: script.ploeneklipper_manuelt_start
state:
- value: mowing
name: Stop
styles:
card:
- background-color: rgba(255, 200, 0, 0.25)
- border: 1px solid rgba(255, 200, 0, 0.8)
tap_action:
action: call-service
service: lawn_mower.dock
target:
entity_id: lawn_mower.husqvarna_automower
# 💡 Lys kontrol
- type: horizontal-stack
cards:
- type: tile
entity: light.indendorslamper
name: Indenfor
icon: mdi:lightbulb-group
tap_action:
action: toggle
hold_action:
action: more-info
show_state: true
- type: tile
entity: light.udendorslamper
name: Udenfor
icon: mdi:outdoor-lamp
tap_action:
action: toggle
hold_action:
action: more-info
show_state: true
- type: tile
entity: binary_sensor.garageport
name: Garage
features_position: bottom
vertical: false
tap_action:
action: call-service
service: cover.toggle
target:
entity_id: cover.anne
show_state: true
# 🎵 Sonos
- type: grid
columns: 3
square: false
cards:
- type: button
name: Stop alt
icon: mdi:stop-circle-outline
tap_action:
action: call-service
service: media_player.media_stop
target:
entity_id:
- 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
- type: button
name: P3 i bad
icon: mdi:radio
tap_action:
action: call-service
service: media_player.select_source
target:
entity_id: media_player.badevaerelse
data:
source: "0 DR P3"
- type: button
name: P3 i alrum
icon: mdi:radio
tap_action:
action: call-service
service: media_player.select_source
target:
entity_id: media_player.alrum
data:
source: "0 DR P3"
- type: button
name: Daily Mix bad
icon: mdi:music-circle-outline
tap_action:
action: call-service
service: media_player.select_source
target:
entity_id: media_player.badevaerelse
data:
source: "Andreas Daily Mix 1"
- type: button
name: Daily Mix køkken
icon: mdi:music-circle-outline
tap_action:
action: call-service
service: media_player.select_source
target:
entity_id: media_player.kokken
data:
source: "Andreas Daily Mix 1"
- type: button
name: Family Mix køkken
icon: mdi:music-note-outline
tap_action:
action: call-service
service: media_player.select_source
target:
entity_id: media_player.kokken
data:
source: "1 Family Mix"
# 🔊 Receiver presets
- type: grid
columns: 4
square: false
cards:
- type: button
name: Sonos
icon: mdi:speaker-multiple
tap_action:
action: call-service
service: script.receiver_sonos_mch_stereo
- type: button
name: TV Dolby
icon: mdi:television-speaker
tap_action:
action: call-service
service: script.receiver_tv_dolby_digital
- type: button
name: TV Stereo
icon: mdi:surround-sound
tap_action:
action: call-service
service: script.receiver_tv_mch_stereo
- type: horizontal-stack
cards:
- type: vertical-stack
cards:
- type: button
name: ""
icon: mdi:power
tap_action:
action: call-service
service: media_player.turn_off
target:
entity_id: media_player.denon_avr_x2300w
- type: button
name: ""
icon: mdi:volume-plus
tap_action:
action: call-service
service: script.receiver_volume_up_5
- type: button
name: ""
icon: mdi:volume-minus
tap_action:
action: call-service
service: script.receiver_volume_down_5
# 🍽️ Hjemmeknapper
- type: grid
columns: 2
square: false
cards:
- type: button
name: Der er mad
icon: mdi:silverware-fork-knife
tap_action:
action: call-service
service: script.mad_announcement
- type: button
name: TV hygge
icon: mdi:television-ambient-light
tap_action:
action: call-service
service: script.tv_hygge_announcement
# 🏖️ Ferie
- type: entities
title: Ferie
icon: mdi:beach
entities:
- entity: input_datetime.vacation_start
name: Afrejse
- entity: input_datetime.vacation_end
name: Hjemkomst
- entity: input_boolean.vacation_mode
name: Ferietilstand aktiv
# 🗑️ Affald
- type: glance
columns: 3
show_icon: true
show_name: false
show_state: true
entities:
- entity: sensor.affalddk_norgardsvej_22_restaffald
icon: mdi:trash-can-outline
- entity: sensor.affalddk_norgardsvej_22_papir_plast
icon: mdi:recycle
- entity: sensor.affalddk_norgardsvej_22_haveaffald
icon: mdi:leaf
# ⚡ El-priser
- type: vertical-stack
cards:
- type: custom:apexcharts-card
graph_span: 24h
span:
start: hour
stacked: false
header:
show: true
title: El-priser næste 24 timer
show_states: true
colorize_states: true
now:
show: true
label: Nu
all_series_config:
stroke_width: 0
apex_config:
chart:
height: 260
grid:
strokeDashArray: 2
xaxis:
type: datetime
labels:
datetimeFormatter:
hour: HH:mm
yaxis:
decimalsInFloat: 2
tickAmount: 5
plotOptions:
bar:
columnWidth: 82%
borderRadius: 3
series:
- entity: sensor.energi_data_service
name: Pris
type: column
float_precision: 2
unit: ' kr/kWh'
show:
in_header: raw
in_chart: true
data_generator: |
const startOfHour = new Date();
startOfHour.setMinutes(0, 0, 0);
const endTime = startOfHour.getTime() + (24 * 60 * 60 * 1000);
const rawToday = entity.attributes.raw_today || [];
const rawTomorrow = entity.attributes.tomorrow_valid ? (entity.attributes.raw_tomorrow || []) : [];
const forecast = entity.attributes.forecast || [];
const allKnown = [...rawToday, ...rawTomorrow];
const data = [];
const seen = new Set();
const pushPoint = (item) => {
const timestamp = new Date(item.hour).getTime();
if (Number.isNaN(timestamp) || timestamp < startOfHour.getTime() || timestamp >= endTime || seen.has(timestamp)) {
return;
}
const price = Number(item.price);
if (Number.isNaN(price)) {
return;
}
seen.add(timestamp);
data.push({ x: timestamp, y: price });
};
allKnown.forEach(pushPoint);
if (data.length < 24) {
forecast.forEach(pushPoint);
}
data.sort((left, right) => left.x - right.x);
const trimmed = data.slice(0, 24);
if (!trimmed.length) {
return [];
}
const prices = trimmed.map((item) => item.y);
const minPrice = Math.min(...prices);
const maxPrice = Math.max(...prices);
const mix = (start, end, ratio) => Math.round(start + ((end - start) * ratio));
const toHex = (value) => value.toString(16).padStart(2, '0');
const rgbToHex = (red, green, blue) => `#${toHex(red)}${toHex(green)}${toHex(blue)}`;
const colorByValue = (value) => {
if (maxPrice === minPrice) {
return '#16a34a';
}
const normalized = (value - minPrice) / (maxPrice - minPrice);
if (normalized <= 0.5) {
const ratio = normalized / 0.5;
return rgbToHex(
mix(22, 250, ratio),
mix(163, 204, ratio),
mix(74, 21, ratio)
);
}
const ratio = (normalized - 0.5) / 0.5;
return rgbToHex(
mix(250, 220, ratio),
mix(204, 38, ratio),
mix(21, 38, ratio)
);
};
return trimmed.map((item) => ({
x: item.x,
y: item.y,
fillColor: colorByValue(item.y)
}));
# 🏠 Hus kontrol
- type: entities
title: Modes
entities:
- entity: input_boolean.guests_mode
name: Vi har gæster
icon: mdi:account-group
- type: conditional
conditions:
- condition: numeric_state
entity: sensor.antal_vedligeholdskort
above: 0
card:
type: tile
entity: sensor.antal_vedligeholdskort
name: Vedligehold
icon: mdi:wrench-cog