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
<div data-greenbow-smartcharge data-zone="DK1"></div>
<script src="https://smartcharge.widget.greenbow.dk/loader.js" async></script>Data-attributter
| Attribut | Værdier | Default | Beskrivelse |
|---|---|---|---|
data-zone | DK1, DK2 | DK2 | Initialt valgt prisområde. Vises som "Vest"/"Øst" i UI'et. |
URL-parametre
| Parameter | Værdier | Beskrivelse |
|---|---|---|
zone | DK1, DK2 | Overskriver 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:
- Forklaring om at besparelsen er baseret på spotpriser alene
- Forklaring af årlig projektering og 5 km/kWh (20 kWh/100 km)-antagelsen
- 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 kri stedet for0.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
- Widgeten henter dagens priser fra Greenbow API for både DK1 og DK2
- Hvis dansk lokaltid ≥ 12:00 hentes også morgendagens priser
eligibleHoursfiltrerer timer der:- er før aktuel time (der kan ikke lades bagud i tid)
- er efter den valgte deadline
calculateSavingssorterer de tilgængelige timer efter pris og vælger de billigste N timer der tilsammen dækker kWh-behovet ved den valgte ladehastighed- Pris med SmartCharge = sum af (pris × kWh) for de valgte timer
- Pris uden SmartCharge = gennemsnitspris i det tilgængelige vindue × kWh
- 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 × sessionerAntagelse: 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 endayOffset(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-changeog 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-labelpluslabel-sammenkædning og et tooltip medrole="tooltip"+aria-describedby - Deadline-vælger har
aria-describedbyder peger på den viste label - Km-dropdown har
aria-labelpluslabel-sammenkædning - Årlig besparelse-toggle er en native
<input type="checkbox">med visuelt skjult input og stylet switch-track - Zone-toggle bruger
role="radiogroup"medaria-checked - Disclaimer og graf bruger en custom
<Accordion>-komponent medaria-expanded,aria-controlsog:inertpå 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-motionslukkes 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
| Bredde | Layout |
|---|---|
| 360px | 1 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.
| Element | Værdi |
|---|---|
og:title | SmartCharge — se din besparelse på elregningen |
og:image | https://smartcharge.widget.greenbow.dk/v1/og-image.png (1200×630) |
og:locale | da_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:
pnpm --filter @greenbow/smartcharge og:generateKø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
| Version | Status | URL |
|---|---|---|
v1 | aktiv | https://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.