Elspotpriser i Home Assistant — Sådan lader jeg bilen på de billige timer

Energi Data Service til live spotpriser, ApexCharts stepline-diagram, og automatiseret Škoda Elroq-opladning uden at røre appen.

#el #ev #energi-data-service #automatisering #skoda-elroq
2. maj 2025
Elspotpriser i Home Assistant — Sådan lader jeg bilen på de billige timer

Der var en nat i februar hvor el kostede 0,18 kr/kWh kl. 3 og 3,40 kr/kWh kl. 8. Næsten 20 gange så dyrt på fem timer. Hvis bilen lader på en fast natplan ruller du terning om hvilken ende af det spænd du lander på.

Home Assistant kan se timepriserne. Resten følger af sig selv.

Energi Data Service

Energi Data Service er en gratis dansk offentlig API — ingen nøgle krævet. HA-integrationen henter dagens og morgendagens timepriser for dit prisområde (DK1 eller DK2).

Installer fra HACS, tilføj via Integrationer, vælg dit område. Du får:

sensor.energi_data_service    — aktuel timepris (kr/kWh inkl. moms)

raw_today- og raw_tomorrow-attributterne indeholder de fulde 24-timers prisarrays som {hour, price}-objekter, hvor hour er en ISO datetime-streng. Morgendagens priser dukker op omkring kl. 13 når Nord Pool-auktionen afregnes.

Diagrammet

custom:apexcharts-card (HACS) med column-type er det rigtige her — hver søjle holder i en hel time, derefter hopper den. Farvetærskler gør de dyre timer tydelige:

type: custom:apexcharts-card
graph_span: 30h
now:
  show: true
  label: Nu
series:
  - entity: sensor.energi_data_service
    type: column
    data_generator: |
      return entity.attributes.raw_today
        .concat(entity.attributes.raw_tomorrow || [])
        .map(h => [new Date(h.hour).getTime(), h.price]);
    color_threshold:
      - value: 0
        color: '#4caf50'
      - value: 1.0
        color: '#ff9800'
      - value: 1.5
        color: '#f44336'

Grøn under 1 kr, orange op til 1,50, rød derover. concat-delen håndterer at morgendagens priser ikke er tilgængelige endnu — uden den fejler diagrammet stille om formiddagen.

Det billigste vindue

Som template-sensor

En template-sensor der finder det billigste sammenhængende 2-timers blok der er tilbage i dag:

template:
  - sensor:
      - name: "Billigste opladningsvindue"
        state: >
          {% set prices = state_attr('sensor.energi_data_service', 'raw_today') %}
          {% if prices %}
            {% set ns = namespace(best_hour=0, best_avg=999) %}
            {% for i in range(prices | length - 1) %}
              {% set avg = (prices[i].price + prices[i+1].price) / 2 %}
              {% if avg < ns.best_avg and as_datetime(prices[i].hour).hour >= now().hour %}
                {% set ns.best_avg = avg %}
                {% set ns.best_hour = as_datetime(prices[i].hour).hour %}
              {% endif %}
            {% endfor %}
            {{ '%02d:00' % ns.best_hour }}
          {% else %}
            ukendt
          {% endif %}

Vises som 02:00 eller 14:00 på dashboardet. Ikke brugt direkte i opladningsautomatiseringen — den kører hvert time og beslutter ud fra den aktuelle pris — men nyttig til at verificere at bilen lader på et fornuftigt tidspunkt.

Som et dashboard-kort

Vil du undgå template-sensoren helt, kan dette markdown-kort beregne og vise det billigste vindue direkte — inklusiv i morgen når morgendagens priser er tilgængelige:

type: markdown
content: >
  {%- set d=state_attr("sensor.energi_data_service","raw_today") -%}
  {%- set r=state_attr("sensor.energi_data_service","raw_tomorrow") -%}
  {%- set tv=state_attr("sensor.energi_data_service","tomorrow_valid") -%}
  {%- set tm=d|map(attribute="price")|min -%}{%- set th=tm*1.25 -%}
  {%- set t=namespace(mi=0,s=0,e=0) -%}
  {%- for h in d -%}{%- if h.price==tm -%}{%- set t.mi=loop.index0 -%}{%- endif -%}{%- endfor -%}
  {%- set t.s=t.mi -%}{%- set t.e=t.mi -%}
  {%- for i in range(23) -%}{%- if t.s>0 and d[t.s-1].price<=th -%}{%- set t.s=t.s-1 -%}{%- endif -%}{%- endfor -%}
  {%- for i in range(23) -%}{%- if t.e<23 and d[t.e+1].price<=th -%}{%- set t.e=t.e+1 -%}{%- endif -%}{%- endfor -%}
  {%- set ts=t.s -%}{%- set te=t.e+1 -%}{%- set tmi=t.mi -%}
  {%- if tv and r -%}
  {%- set rm=r|map(attribute="price")|min -%}{%- set rh=rm*1.25 -%}
  {%- set n=namespace(mi=0,s=0,e=0) -%}
  {%- for h in r -%}{%- if h.price==rm -%}{%- set n.mi=loop.index0 -%}{%- endif -%}{%- endfor -%}
  {%- set n.s=n.mi -%}{%- set n.e=n.mi -%}
  {%- for i in range(23) -%}{%- if n.s>0 and r[n.s-1].price<=rh -%}{%- set n.s=n.s-1 -%}{%- endif -%}{%- endfor -%}
  {%- for i in range(23) -%}{%- if n.e<23 and r[n.e+1].price<=rh -%}{%- set n.e=n.e+1 -%}{%- endif -%}{%- endfor -%}
  {%- set rs=n.s -%}{%- set re=n.e+1 -%}{%- set rmi=n.mi -%}
  {%- endif -%}
  ⚡ **Billigste strøm**

  **I dag** · {{ "%02d:00"|format(ts) }}–{{ "%02d:00"|format(te) }} · lavest **{{ "%.2f"|format(tm)|replace(".",",") }} kr/kWh** kl. {{ "%02d:00"|format(tmi) }}
  {%- if tv and r %}

  **I morgen** · {{ "%02d:00"|format(rs) }}–{{ "%02d:00"|format(re) }} · lavest **{{ "%.2f"|format(rm)|replace(".",",") }} kr/kWh** kl. {{ "%02d:00"|format(rmi) }}
  {%- endif %}

  💡 Start opvaskemaskinen eller vaskemaskinen midt på dagen for at spare mest

Logikken: find minimumsprisen for dagen, udvid derefter vinduet til at inkludere alle tilstødende timer inden for 25% af det minimum. Kortet opdaterer sig automatisk når sensoren ændrer sig — ingen separat automatisering nødvendig.

Opladningsautomatiseringen

Automationen bruger switch.skoda_elroq_charging fra MySkoda-integrationen (HACS) til at starte og stoppe opladningen.

alias: Elroq — Smart opladning
trigger:
  - platform: time_pattern
    minutes: "0"
condition:
  - condition: state
    entity_id: binary_sensor.skoda_elroq_charger_connected
    state: "on"
  - condition: numeric_state
    entity_id: sensor.skoda_elroq_battery_level
    below: 90
action:
  - choose:
      - conditions:
          - condition: numeric_state
            entity_id: sensor.energi_data_service
            below: 1.0
        sequence:
          - service: switch.turn_on
            target:
              entity_id: switch.skoda_elroq_charging
      - conditions:
          - condition: numeric_state
            entity_id: sensor.energi_data_service
            above: 1.5
        sequence:
          - service: switch.turn_off
            target:
              entity_id: switch.skoda_elroq_charging

Under 1,00 kr — oplad. Over 1,50 kr — stop. Imellem de to tal — rør den ikke. Dødszonen er bevidst: uden den ville kontakten toggle frem og tilbage hver time når priserne svæver omkring tærsklen.

Der er en input_boolean.elroq_force_charge-override til de morgener hvor jeg har brug for fuld opladning uanset pris.

Virker det?

Første hele måned: ca. 28% lavere opladningsomkostning sammenlignet med altid-tændt natopladning. Besparelsen kommer næsten udelukkende fra nætterne med store prisspænd — der er uger i Danmark hvor spændet er lille og automatiseringen ikke gør nogen forskel.

Det jeg ikke forventede: det ændrede hvordan jeg tænker på at køre andre apparater. Elprisdiagrammet er nu et af de mest tjekkede kort på mit dashboard — og jeg har siden tilføjet vindue-kortet ovenfor, som automatisk viser det bedste tidspunkt til at køre opvaskemaskinen eller vaskemaskinen. Den adfærdsændring sparer sandsynligvis mere end den automatiserede EV-opladning gør.