feb 9, 2025 In Shelly, Smarthome Tag Shelly, Shelly Dimmer, Strømmåling Ved at køre et script på en shelly enhed kan vi få live elpriser direkte i appen.Så får du nemt et overblik over de præcise omkostninger for dit forbrug.Hvad skal der brugesDu skal bruge en shelly enhed, der understøtter scripting (Gen2 eller nyere) Du skal have mindst en enhed der måler effekt (PM eller EM) Brug shelly smart control appen eller http://control.shelly.cloud på din pc, det anbefales og det er også det jeg benytter i denne guide. Hvis man vil bruge funktionen Virtuelle enheder, så kræves det som minimum en Gen3 eller nyere.Kopier nedenstående script// Henter data fra https://stromligning.dk // // ===== KONFIGURATION ===== let CONFIG = { postalCode: "4720", // Indtast postnummer (det eneste, du manuelt skal angive) additionalCost: 0.00, // Yderligere omkostninger (kr/kWh), som lægges oveni price.total check_every_minute: false, // true = tjek prisen hvert minut, false = tjek prisen hver time check_delay_seconds: 10, // Antal sekunder efter time-/minutskiftet, hvorefter prischecket udføres post_url: "https://shelly-147-eu.shelly.cloud/v2/user/pp-ltu/eyJpZCI6MjA3MTUzOtokeng",// (Valgfrit) URL til POST – fjern eller tilpas, hvis ikke relevant vc_id: 200 // (Valgfrit) ID på den virtuelle enhed, hvis prisen skal vises i Shelly GUI }; let current_price = null; // Her gemmes den aktuelle pris (til reference) let loggingIntervalTimer = null; // ID på gentaget log-timer (bruges til nedtælling) let nextUpdateInMs = 0; // Tid til næste update (i ms) // Hjælpefunktion: Formaterer millisekunder til "0h 5m 10s" function formatDelay(delayMs) { let totalSeconds = Math.floor(delayMs / 1000); let hours = Math.floor(totalSeconds / 3600); let minutes = Math.floor((totalSeconds % 3600) / 60); let seconds = totalSeconds % 60; return hours + "h " + minutes + "m " + seconds + "s"; } // Enkel URL-encoding: erstatter kolon (:) med "%3A" // (Espruino understøtter ikke regulære udtryk i denne version) function myEncodeURIComponent(str) { return str.split(":").join("%3A"); } /** * Henter den aktuelle pris ved at slå først supplier op (ud fra postnummer) * og derefter hente prisdata for den aktuelle time. * Resultatet (price.total + additionalCost) vises og sendes evt. videre. */ function getCurrentPrice() { // 1. HENT SUPPLIER-DATA let supplierUrl = "https://stromligning.dk/api/suppliers/find?postalCode=" + CONFIG.postalCode; print("Henter supplier-data fra: " + supplierUrl); Shelly.call("HTTP.GET", { url: supplierUrl }, function(supplierResult, supplierErrorCode, supplierErrorMessage) { if (supplierErrorCode !== 0) { print("Fejl ved supplier API GET: " + supplierErrorMessage); scheduleNextPriceCheck(); return; } let suppliers = JSON.parse(supplierResult.body); if (!suppliers || suppliers.length === 0) { print("Ingen supplier-data modtaget."); scheduleNextPriceCheck(); return; } // Brug den første supplier fra resultatet let supplier = suppliers[0]; let supplierId = supplier.id; let priceArea = supplier.priceArea; print("Fundet supplier: " + supplierId + ", priceArea: " + priceArea); // 2. HENT PRIS-DATA FOR NUVÆRENDE TIME let now = new Date(); let year = now.getFullYear(); let month = ("0" + (now.getMonth() + 1)).slice(-2); let day = ("0" + now.getDate()).slice(-2); let hour = ("0" + now.getHours()).slice(-2); // Byg tidsstrengen for den aktuelle time (eksempel: "2025-02-02T15:00:00") let fromDate = year + "-" + month + "-" + day + "T" + hour + ":00:00"; let toDate = fromDate; // Vi henter kun data for den aktuelle time // URL-encoder dato-strengene let encodedFrom = myEncodeURIComponent(fromDate); let encodedTo = myEncodeURIComponent(toDate); // Byg URL'en til pris-API'en let priceUrl = "https://stromligning.dk/api/prices?from=" + encodedFrom + "&to=" + encodedTo + "&supplierId=" + supplierId + "&priceArea=" + priceArea; print("Henter price-data fra: " + priceUrl); Shelly.call("HTTP.GET", { url: priceUrl }, function(priceResult, priceErrorCode, priceErrorMessage) { if (priceErrorCode !== 0) { print("Fejl ved price API GET: " + priceErrorMessage); scheduleNextPriceCheck(); return; } let data = JSON.parse(priceResult.body); if (!data.prices) { print("Ingen prisdata modtaget."); scheduleNextPriceCheck(); return; } // Find posten for den nuværende time let currentHour = now.getHours(); let found = false; data.prices.forEach(function(item) { let itemDate = new Date(item.date); let itemHour = itemDate.getHours(); if (itemHour === currentHour) { found = true; // Brug API'ets price.total (allerede inkl. moms) let priceTotal = item.price.total; // Læg evt. yderligere omkostninger oveni let finalPrice = priceTotal + CONFIG.additionalCost; // Afrund til 2 decimaler current_price = finalPrice.toFixed(2); print("Price total for den nuværende time (" + currentHour + ":00): " + current_price + " " + item.price.unit + " (inkl. yderligere omkostninger: " + CONFIG.additionalCost.toFixed(2) + " kr/kWh)"); // (Valgfrit) Skriv prisen til en virtuel enhed i Shelly GUI Shelly.call("Number.Set", { id: CONFIG.vc_id, value: current_price }); // (Valgfrit) POST prisen til en ekstern URL print("Posting price: " + current_price); Shelly.call("HTTP.REQUEST", { method: "POST", url: CONFIG.post_url, headers: { "Content-Type": "application/json" }, body: JSON.stringify({ price: current_price }), timeout: 5000, }, function(postResult, postErrorCode, postErrorMessage) { if (postErrorCode !== 0) { print("Fejl ved POST af pris: " + postErrorMessage); } else { print("Price posted successfully: " + current_price); } }); } }); if (!found) { print("Ingen data fundet for den nuværende time (" + currentHour + ":00)."); } // Planlæg næste prisopdatering scheduleNextPriceCheck(); }); }); } /** * Planlægger næste pris-tjek (enten hvert minut eller én gang i timen), * med en ekstra forsinkelse (CONFIG.check_delay_seconds). */ function scheduleNextPriceCheck() { let now = new Date(); let delay = 0; if (CONFIG.check_every_minute === true) { // HVERT MINUT: beregn hvor mange ms til næste hele minut + ekstra forsinkelse let secondsUntilNextMinute = 60 - now.getSeconds(); let msUntilNextMinute = (secondsUntilNextMinute * 1000) - now.getMilliseconds(); delay = msUntilNextMinute + (CONFIG.check_delay_seconds * 1000); print("Scheduling next price check (minute-mode) in " + formatDelay(delay)); } else { // HVERT TIME: beregn hvor mange ms til næste hele time + ekstra forsinkelse let totalSecsNow = now.getMinutes() * 60 + now.getSeconds(); let msUntilNextHour = (3600 - totalSecsNow) * 1000 - now.getMilliseconds(); delay = msUntilNextHour + (CONFIG.check_delay_seconds * 1000); print("Scheduling next price check (hour-mode) in " + formatDelay(delay)); } nextUpdateInMs = delay; Timer.set(delay, false, function () { getCurrentPrice(); }); // Starter en log-timer, der hvert 10. minut udskriver, hvor lang tid der er til næste opdatering if (loggingIntervalTimer) { Timer.clear(loggingIntervalTimer); loggingIntervalTimer = null; } let tenMinutesInMs = 10 * 60 * 1000; loggingIntervalTimer = Timer.set(tenMinutesInMs, true, function () { nextUpdateInMs -= tenMinutesInMs; if (nextUpdateInMs <= 0) { print("No time left to next update (it should happen now)."); Timer.clear(loggingIntervalTimer); loggingIntervalTimer = null; } else { print("Time left to next update: " + formatDelay(nextUpdateInMs)); } }); } // START: Test prisen med det samme, når scriptet starter getCurrentPrice();Indsæt scriptet ved at vælge en enhed og tryk på script ikonet Opret nyt script, giv det et navn og sæt det kopierede script ind, gem scriptet..Note: scriptet kan også nemt sættes ind fra enhedens web interface.Så skal vi have fundet din Token Gå til energi og vælg fanebladet Elpris, tryk på live ud for Elpris og find din Token API URL kopier denne..OBS! Hvis man trykker på manuelt og live igen, er der generet en ny token, som skal skrives ind i scriptet.Så indsætter du din Token, erstatter den nuværende token med din egen på linie 18OBS! Gåseøjne skal stadig være der Så skal scriptet rettes lidt til så det passer til den elpris du køber tilNyttige links til at tjekke dine priserTjek dine priser og find transmission og tarif omkostninger her:https://stromligning.dk/liveFind dine tariffer her:https://tariffer.dkOgså en god side til at tjekke priser (især på mobil)https://elpris.wen.dkScript beskrivelseFor at få Scriptet konfigureret til dine priser, skal der ændres lidt.price_area: DK1, eller DK2Her skrives, hvilken priszone du er i.DK1 for Jylland og Fyn.DK2 for Sjælland.include_vat: true, eller falseHer skrives om du vil have vist prisen med moms.true for at inkludere moms (25%) i prisen.false for at ekskludere moms.include_elafgift: true, eller falseHer skrives om du vil have vist prisen med elafgift.true for at inkludere elafgift i prisen.false for at ekskludere elafgift.elafgift: værdi (Ex. 0.72)Skriv elafgift i kroner (u.moms) per kWh. Hvis include_vat er true, lægges moms også oven i denne afgift.(Er start 2025: Ex. moms = 0.72 kr. Inkl. moms =90 kr. )additional_cost: værdi (Ex. 0.168)Her indtastes dine transmision omkostninger Ekstra omkostning pr. kWh i kroner. Bliver lagt oveni den endelige pris.(hvis du har yderligere omkostninger lægges det bare oven i samme beløb).tariff_periods:Her indtastes de forskellige tidsperioder for tarifferne og deres priser. Linjer kan sagtens fjerne, eller tilføjes.Ex. på en linje:{ start: “00:01”, end: “06:00”, tariff: 0.14 },check_every_minute: true, eller falseHer skrives om du vil have den til at hente prisen , hver time, eller, hvert minut.true for at hente pris hvert minut (Bør kun bruges til test).false for at hente pris, hver time (Anbefales).(For ikke at belaste server, hvor prisen hentes bør 1 minut check kun bruges til at teste om det virker).hour_check_delay_seconds: værdi (ex 10)Her skrives, antal sekunder efter timeskiftet, hvor prischecket udføres.Sørg for at scriptet kørerTil sidst skal vi have scriptet til at køre og til at starte automatisk op, hvis enheden genstartet Aktiver autostart og start ved at trykke på play knappen (Blå ring = aktiv)Afslutning og test af scriptNår scriptet har hentet prisen første gang skal du kunne se den under Energi -> Elpris det er nødvendig at opdaterer sidenOBS! Hvis man tilgår scriptet fra enhedens webinterface, så vil man kunne se log på hvad der sker. Ekstra muligheder kommer i næste indlæg