Skip to content

SmartCharge

Status: Fundament — spotpris-estimat med opt-in årlig projektering

SmartCharge viser brugeren hvor meget de kan spare på elregningen ved at oplade deres elbil i de billigste timer. Widgeten henter spotpriser fra Greenbows API og beregner en estimeret besparelse baseret på brugerens valg af kWh-behov, ladehastighed, deadline og (valgfrit) årligt kilometertal.

Live preview

Embed-snippet

html
<div data-greenbow-smartcharge data-zone="DK1"></div>
<script src="https://smartcharge.widget.greenbow.dk/loader.js" async></script>

Data-attributter

AttributVærdierDefaultBeskrivelse
data-zoneDK1, DK2DK2Initialt valgt prisområde. Vises som "Vest"/"Øst" i UI'et.

URL-parametre

ParameterVærdierBeskrivelse
zoneDK1, DK2Overskriver data-zone og persisteret valg.

Eksempel: https://smartcharge.widget.greenbow.dk/v1/?zone=DK1

De underliggende zone-identifikatorer matcher Greenbow API'ets DK1/DK2 — UI-labels er lokaliseret til Vest / Øst for danske brugere, men embed-snippet og URL-parameter bruger stadig DK1/DK2.

Hvad viser widgeten?

Widgeten er bygget op som én samlet "Beregn din besparelse med Greenbow SmartCharge"-sektion efterfulgt af en collapsible spotprisgraf.

1. Besparelses-beregner

Overskrift: "Beregn din besparelse med Greenbow SmartCharge" med Vest/Øst zone-toggle i samme række.

Brugeren konfigurerer:

  • Bilens ladehastighed — talfelt 1–22 kW, default 11 kW (typisk 3-faset hjemmeladestander). Tooltip bag et i-ikon forklarer antagelsen.
  • Færdig kl. — tids-vælger der automatisk vises som "I dag kl. X" eller "I morgen kl. X" baseret på aktuel tid
  • Hvor mange kWh skal du lade? — slider 1–100 kWh, default 50

Under inputtene vises tre resultatkort:

  • Pris med SmartCharge — smart charging-omkostning for sessionen
  • Pris uden SmartCharge — gennemsnitspris i samme tidsvindue × kWh
  • Besparelse med SmartCharge — fremhævet grøn, differencen

Efterfulgt af en linje "Billigste ladetider" med de konkrete klokkeslæt algoritmen vil vælge, sorteret kronologisk (ikke efter tal) så en natladning korrekt vises som 22:00, 23:00, 00:00, 01:00 ….

2. Årlig besparelse (opt-in)

Under resultatkortene sidder en toggle-switch "Vis årlig besparelse" — default slået fra. Når brugeren aktiverer den, slider en reveal-container ned (samme grid-template-rows transition som de øvrige accordions) og viser:

  • Km pr. år — dropdown med leasing-standard intervaller (10/15/20/25/30.000), default 15.000
  • Årlig besparelse-kort — hvidt kort med subtil skygge og subtil gradient, "Årlig besparelse" som h3-overskrift, det årlige besparelses-tal i hero-størrelse og en beskrivende meta-linje.

Hero-tallet tæller op/ned som en slot machine når brugeren ændrer nogen af inputtene (kWh, ladehastighed, deadline, km/år). Animationen bruger RAF og ease-out cubic over 550 ms. Respekterer prefers-reduced-motion.

Den årlige besparelse beregnes ved at projicere per-session-besparelsen ud fra (km_pr_år × 20 kWh/100 km) / session-kWh sessioner om året. 20 kWh/100 km svarer til "5 km pr. kWh" — den enkle tommelfingerregel Greenbow bruger i kunderejsen. Dokumenteret i disclaimer-accordionen.

3. Disclaimer-accordion

Under beregneren ligger en custom <Accordion>-komponent med titlen "Hvordan er besparelsen beregnet?". Den slider blødt op/ned via grid-template-rows transition, er skjult by default, og indeholder:

  1. Forklaring om at besparelsen er baseret på spotpriser alene
  2. Forklaring af årlig projektering og 5 km/kWh (20 kWh/100 km)-antagelsen
  3. Call-to-action der peger mod en elaftale hos Greenbow for en præcis ladeplan

4. Spotprisgraf (accordion)

Hele grafen er også wrappet i en <Accordion> med titlen "Spotpriser pr. time", skjult by default. Når brugeren åbner den, slider containeren ned, og SVG-indholdet animerer synkront fra venstre mod højre over 2.6 s — linje, area-gradient, grønne højlyste ladetimer og markører — alle sammen via samme clip-path: inset() reveal-teknik. Respekterer prefers-reduced-motion.

Elementer i grafen:

  • Custom SVG-linjegraf over døgnets timer (i dag + morgendag hvis tilgængelig, typisk fra kl. 12 dansk tid)
  • Area-gradient under linjen i primary-farven, fader til transparent
  • Grøn gradient-overlay på de timer algoritmen har valgt — hver sammenhængende gruppe af optimal-timer renderes som én filled path der følger linjen og lukker ned til x-aksen, så overlayet ligger under linjen i stedet for oven på den
  • Grøn markør på billigste time, orange markør på dyreste
  • "Nu"-pill øverst på den aktuelle time — navy badge med hvid "Nu"-tekst, placeret uden for plot-området så den aldrig overlapper data-markører
  • Stiplet blå horisontal linje på gennemsnitsprisen
  • Legend i top-højre: 🟩 Valgte ladetimer (vises kun når der er valgte timer), ● Billigst, ● Dyrest, ┄┄ Gennemsnit
  • "I morgen"-label der markerer overgangen til morgendagens priser
  • Y-akse nice-ticks: ticks rundes til pæne værdier (0.5, 1, 2, 2.5, 5…) via en standard "nice step"-algoritme i stedet for at dele range jævnt. Ved prisspikes til 7 kr viser y-aksen 0, 2, 4, 6, 8 kr i stedet for 0.0, 1.9, 3.9, 5.8, 7.7 kr. Decimaler droppes når step er et helt tal.
  • Hover/touch tooltip med klokkeslæt og pris
  • Y-akse labels med "kr"-suffix

Under grafen en fodnote: "Priser vises som rå spotpriser ekskl. tariffer, afgifter og abonnement."

Beregningslogik

Per-session algoritme

  1. Widgeten henter dagens priser fra Greenbow API for både DK1 og DK2
  2. Hvis dansk lokaltid ≥ 12:00 hentes også morgendagens priser
  3. eligibleHours filtrerer timer der:
    • er før aktuel time (der kan ikke lades bagud i tid)
    • er efter den valgte deadline
  4. calculateSavings sorterer de tilgængelige timer efter pris og vælger de billigste N timer der tilsammen dækker kWh-behovet ved den valgte ladehastighed
  5. Pris med SmartCharge = sum af (pris × kWh) for de valgte timer
  6. Pris uden SmartCharge = gennemsnitspris i det tilgængelige vindue × kWh
  7. Besparelse med SmartCharge = pris uden − pris med

Årlig projektering

calculateAnnualSavings er en pure skalerings-funktion oven på per-session resultatet:

kwh_pr_år   = km_pr_år × 20 / 100         (5 km pr. kWh)
sessioner   = kwh_pr_år / session_kwh
årlig_besparelse = per_session_besparelse × sessioner

Antagelse: dagens prismønster og brugerens session-størrelse gentages året rundt. Dette er tydeligt flagget i disclaimer-accordionen som et "overslag, ikke en garanti". 20 kWh/100 km (tommelfingerreglen "5 km pr. kWh") er eksporteret som DEFAULT_CONSUMPTION_KWH_PER_100KM i calculateSavings.ts.

Vigtige invarianter

  • Ingen ladetider i fortiden: vinduet starter altid på aktuel time, aldrig før. Filtreringen sker i scheduleWindow.ts.
  • Både smart og gennemsnit bruger samme vindue: besparelsen repræsenterer "smart valg vs tilfældigt valg inden for samme tidsrum".
  • Negative spotpriser håndteres korrekt — sjældne men reelle.
  • Delvis sidste time: hvis kWh-behovet ikke går op i hele timer ved den valgte ladehastighed, inkluderes en delvis time til den resterende mængde.
  • Kronologisk rækkefølge af optimale ladetider: sorteret efter deres position i eligible-vinduet, ikke efter rå hour-tal. Det sikrer at natladning vises som 22:00, 23:00, 00:00, 01:00 ….
  • Grafens grønne overlay bruger et afledt optimalSlots-computed der beriger hver valgt time med en dayOffset (0 = i dag, 1 = i morgen). Logikken detekterer midnats-crossing ved at iagttage hvornår hour-tallet falder mellem to efter hinanden følgende elementer i den kronologiske liste. Det emittes fra SavingsCalculator via @optimal-slots-change og forwardes af App.vue til PriceChart som en prop.

Caching

API-svar caches 5 minutter i sessionStorage under nøglen smartcharge:gridprices:{date}:{is_green}. Zone-skift udløser ikke en ny forespørgsel, fordi svaret indeholder begge zoner.

Begrænsninger

Spotpriser alene — ingen nettarif, elafgift, abonnement eller tidsvarierende netselskabstariffer. Den estimerede besparelse er derfor kun retvisende for sammenligning mellem smart og tilfældig opladning — ikke for den absolutte elpris brugeren kommer til at betale.

Med en elaftale hos Greenbow får brugeren en præcis ladeplan i appen der tager højde for alle priselementer inkl. nettarif.

Tilgængelighed

  • Slider har aria-label, aria-valuemin/max/now, aria-valuetext
  • Ladehastighed-input har aria-label plus label-sammenkædning og et tooltip med role="tooltip" + aria-describedby
  • Deadline-vælger har aria-describedby der peger på den viste label
  • Km-dropdown har aria-label plus label-sammenkædning
  • Årlig besparelse-toggle er en native <input type="checkbox"> med visuelt skjult input og stylet switch-track
  • Zone-toggle bruger role="radiogroup" med aria-checked
  • Disclaimer og graf bruger en custom <Accordion>-komponent med aria-expanded, aria-controls og :inert på det skjulte indhold — fuld keyboard-navigation og screen reader-støtte
  • Årlig besparelse-reveal har :inert="!showAnnual" og :aria-hidden="!showAnnual" så hjælpeteknologier springer det over når det er collapsed
  • Grafen har en visually-hidden <table> med samme data
  • Fejl bruger role="alert"
  • Ved prefers-reduced-motion slukkes både accordion-slide, graf draw-in animationen, count-animationen på årlig besparelse og chevron-rotationen

Verificeret manuelt. Lighthouse-målet er ≥ 90 i accessibility score.

Responsivt layout

BreddeLayout
360px1 kolonne, inputs stacker vertikalt
576px+Resultat-kort 3 i række, zone-toggle ved siden af h2
768px+Inputs i bredere grid, mere padding på årlig-kort
992px+Grafen får mere højde

Sociale medier

Widgeten har fulde Open Graph og Twitter Card meta-tags på /v1/index.html, så links deler pænt på LinkedIn, Facebook, X, Slack, Teams osv.

ElementVærdi
og:titleSmartCharge — se din besparelse på elregningen
og:imagehttps://smartcharge.widget.greenbow.dk/v1/og-image.png (1200×630)
og:localeda_DK

Regenerering af OG-billedet

Billedet bor i apps/smartcharge/public/og-image.png og committes med repoet. Det genereres ud fra en inline SVG i scripts/build-og-image.mjs via @resvg/resvg-js:

bash
pnpm --filter @greenbow/smartcharge og:generate

Kør scriptet når designet ændres (farver, tekst, layout). For at tilføje et dynamisk image-endpoint — et kort der viser live spotpriser eller brugerens specifikke besparelse — skal der oprettes en DO App Platform Function-komponent der rendrer satori/resvg on-demand. Det er uden for scope for fase 1.

Versioner

VersionStatusURL
v1aktivhttps://smartcharge.widget.greenbow.dk/v1/

Loaderen peger altid på seneste stabile major. Breaking changes udgives som v2 ved siden af v1, og loaderens VERSION-konstant bumpes.

Bygget af Greenbow