En talt morgenbriefing i Home Assistant: kalender, vejr og elpris
En talt besked kl. 06:00 hver dag i Home Assistant: Google AI TTS, tre familiekalendere, elbilens status, trafik fra Waze, elpris og affaldsnedtælling.
Hver morgen åbnede jeg Home Assistant-appen for at se dagens kalender, kigge på vejret og vurdere ud fra elprisen, om aftenen var et godt tidspunkt at starte opvaskemaskinen. Tre forskellige opslag før kaffen.
Morgenbriefingen erstattede det hele. Kl. 06:00 læser højttaleren i køkkenet dagens aftaler fra tre familiekalendere op, sammen med udetemperaturen, en påmindelse om affald, når det hentes i morgen, og den aktuelle elpris. Det hele tager cirka 15 sekunder.
Hvad briefingen siger
På en typisk morgen lyder det sådan her:
“God morgen! I dag er det mandag. Temperaturen ude er 14 grader. Du har 2 aftaler i dag: tandlæge, teammøde. Husk: affald hentes i morgen. Elprisen er 0,42 kroner per kilowattime.”
På en rolig dag uden aftaler og uden affaldsafhentning lige forude bliver den kortet ned til vejr og pris. Der læses ikke noget op, hvis der ikke er noget at sige.
Det centrale mønster: calendar.get_events med response_variable
De fleste vejledninger til automationer i Home Assistant stopper ved at udløse noget, når en kalenderaftale starter. Denne automation gør noget andet: den spørger selv kalenderen om dagens aftaler og bruger svaret i en template.
Handlingen calendar.get_events returnerer et struktureret svar, som kan gemmes i en variabel og bruges i de følgende trin:
- action: calendar.get_events
target:
entity_id: calendar.rolf_szimnau_dk
data:
start_date_time: "{{ today_at('00:00') }}"
end_date_time: "{{ today_at('23:59') }}"
response_variable: kalender
Svaret er en dict med entitets-id’et som nøgle. Sådan får du fat i listen over aftaler:
{% set events = kalender['calendar.rolf_szimnau_dk']['events'] %}
Hver aftale i listen har et summary-felt med titlen. Til en talt besked er det det eneste, der skal bruges.
Flere kalendere
Kør calendar.get_events én gang for hver kalender med hver sin response_variable, og saml derefter listerne i templaten:
- action: calendar.get_events
target:
entity_id: calendar.annette_familie
data:
start_date_time: "{{ today_at('00:00') }}"
end_date_time: "{{ today_at('23:59') }}"
response_variable: kalender_annette
I templaten for beskeden:
{% set events = events_rolf + events_annette + events_louise %}
Den komplette automation
alias: "Morgenbriefing: TTS kl. 06"
mode: single
trigger:
- platform: time
at: "06:00:00"
action:
- action: calendar.get_events
target:
entity_id: calendar.rolf_szimnau_dk
data:
start_date_time: "{{ today_at('00:00') }}"
end_date_time: "{{ today_at('23:59') }}"
response_variable: kalender
- action: calendar.get_events
target:
entity_id: calendar.annette_familie
data:
start_date_time: "{{ today_at('00:00') }}"
end_date_time: "{{ today_at('23:59') }}"
response_variable: kalender_annette
- action: calendar.get_events
target:
entity_id: calendar.louise_familie
data:
start_date_time: "{{ today_at('00:00') }}"
end_date_time: "{{ today_at('23:59') }}"
response_variable: kalender_louise
- action: tts.speak
target:
entity_id: tts.google_ai_tts
data:
media_player_entity_id: media_player.hojtaler_kokken
language: da-DK
message: >-
{% set dage = ['mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag', 'søndag'] %}
{% set dag = dage[now().weekday()] %}
{% set events_rolf = kalender['calendar.rolf_szimnau_dk']['events'] %}
{% set events_annette = kalender_annette['calendar.annette_familie']['events'] %}
{% set events_louise = kalender_louise['calendar.louise_familie']['events'] %}
{% set events = events_rolf + events_annette + events_louise %}
{% set temp = state_attr('weather.forecast_home', 'temperature') %}
{% set affald = states('sensor.affalddk_bytoften_1_naeste_afhentning') | int(99) %}
{% set elpris = states('sensor.energi_data_service') | float(0) | round(2) %}
{% set km = states('sensor.skoda_elroq_range') | int(0) %}
{% set bat = states('sensor.skoda_elroq_battery_percentage') | int(0) %}
{% set maal = states('sensor.skoda_elroq_target_battery_percentage') | int(80) %}
{% set lader = states('sensor.skoda_elroq_charging_state') %}
{% set ac = states('climate.skoda_elroq_air_conditioning') %}
{% set rejsetid = states('sensor.rejsetid_vejle_travel_time') | float(0) | round(0) | int %}
God morgen! I dag er det {{ dag }}.
Temperaturen ude er {{ temp }} grader.
{% if events | length > 0 %}
Du har {{ events | length }} aftale{% if events | length > 1 %}r{% endif %} i dag:
{% for event in events %}{{ event.summary }}{% if not loop.last %}, {% endif %}{% endfor %}.
{% else %}Ingen aftaler i dag.
{% endif %}
{% if affald <= 1 %}Husk: affald hentes i dag!
{% elif affald <= 2 %}Husk: affald hentes i morgen.
{% endif %}
{% if km > 0 and km < 100 %}Elroq har kun {{ km }} kilometer tilbage.
{% endif %}
{% if lader == 'charging' %}Elroq lader: {{ bat }}% ud af {{ maal }}%.
{% elif bat < maal %}Elroq er {{ bat }}% – har ikke nået målet på {{ maal }}%.
{% endif %}
{% if ac != 'off' %}Elroq varmer op.
{% endif %}
{% if now().weekday() < 5 and rejsetid > 0 %}
{% if rejsetid > 40 %}Trafik til arbejde: {{ rejsetid }} minutter – forvent forsinkelse.
{% else %}Kørsel til arbejde: {{ rejsetid }} minutter.
{% endif %}{% endif %}
Elprisen er {{ elpris }} kroner per kilowattime.
Tilpasning
Kun hverdage: tilføj en betingelse før handlingerne:
condition:
- condition: time
weekday: [mon, tue, wed, thu, fri]
En anden højttaler: erstat media_player.hojtaler_kokken med en hvilken som helst media player-entitet i HA.
En anden TTS-motor: skift tts.google_ai_tts ud med tts.google_translate_en_com, hvis du vil have den gratis løsning.
En anden elpris-sensor: erstat sensor.energi_data_service med din egen sensor for spotprisen.
Elbilens status og forvarmning
To sensorer fra MyŠkoda-integrationen fortæller i briefingen, om bilen er klar til dagen.
Ladestatus: briefingen siger kun noget, når der er noget at gøre. Nåede bilen sit lademål i løbet af natten, siges der ingenting.
{% set bat = states('sensor.skoda_elroq_battery_percentage') | int(0) %}
{% set maal = states('sensor.skoda_elroq_target_battery_percentage') | int(80) %}
{% set lader = states('sensor.skoda_elroq_charging_state') %}
{% if lader == 'charging' %}Elroq lader: {{ bat }}% ud af {{ maal }}%.
{% elif bat < maal %}Elroq er {{ bat }}% – har ikke nået målet på {{ maal }}%.
{% endif %}
sensor.skoda_elroq_target_battery_percentage sættes i MyŠkoda-appen og findes direkte som sensor i HA. Bruger din elbils integration ikke et lademål, så erstat maal med et fast tal som 80.
Bekræftelse af forvarmningen: kører en automation, der varmer bilen op, få minutter før kl. 06:00, kan briefingen bekræfte, at den faktisk gik i gang:
{% set ac = states('climate.skoda_elroq_air_conditioning') %}
{% if ac != 'off' %}Elroq varmer op.
{% endif %}
Det virker, fordi opvarmningen starter kl. 05:55, fem minutter før briefingen. Kl. 06:00 er climate.skoda_elroq_air_conditioning enten i gang (så kommer en kort bekræftelse) eller stadig off (så siges der ingenting, for opvarmningsautomationen sender selv en advarsel, hvis den fejler).
Trafikinformation
Integrationen Waze Travel Time opretter en sensor med den aktuelle rejsetid, hvor trafikken er regnet med. Der skal ingen API-nøgle til, data fra Waze er gratis.
Installation: Indstillinger → Enheder og tjenester → Tilføj integration → Waze Travel Time
Brug GPS-koordinater (i formatet breddegrad,længdegrad) til start og mål i stedet for adresser. Waze tolker danske adresser upålideligt, mens koordinater er entydige. Du finder dem ved at højreklikke på et sted i Google Maps og kopiere koordinaterne.
Sæt Region til EU og Rutetype til hurtigste. Giv sensoren et sigende navn, fx Rejsetid Vejle. HA laver entitets-id’et ud fra navnet, typisk sensor.rejsetid_vejle_travel_time.
Tilføj denne blok i templaten for beskeden, lige før elprisen:
{% set rejsetid = states('sensor.rejsetid_vejle_travel_time') | float(0) | round(0) | int %}
{% if now().weekday() < 5 and rejsetid > 0 %}
{% if rejsetid > 40 %}Trafik til arbejde: {{ rejsetid }} minutter i dag – forvent forsinkelse.
{% else %}Kørsel til arbejde: {{ rejsetid }} minutter.
{% endif %}
{% endif %}
now().weekday() < 5 springer automatisk weekenden over. Tilpas grænsen på 40 minutter til din normale køretid til arbejde plus lidt luft.
Hvorfor tts.speak og ikke den gamle handling
Fra Home Assistant 2024 kaldes tts.speak på selve TTS-motorens entitet med media_player_entity_id som datafelt. Den gamle handling tts.google_translate_say virker stadig, men er forældet. Det nye mønster holder motor og afspiller adskilt, så du let kan skifte den ene uden den anden.
tts.google_ai_tts kommer fra integrationen Google Generative AI, den samme, der står bag Gemini som samtaleagent i Home Assistant. Den kræver en API-nøgle fra Google AI Studio, men stemmen lyder naturlig og menneskelig sammenlignet med den robotagtige lyd fra den gratis Google Translate TTS.
Nye indlæg direkte i din RSS-læser: følg med via RSS