Live Elpris – Svenska

Live Elpris – Svenska

Få Direkta Elpriser i Shelly-appen

Genom att köra ett script på en Shelly-enhet kan vi lägga till direkta elpriser direkt i appen. På så sätt kan du enkelt få en överblick över de exakta kostnaderna för din konsumtion.

Vad man ska använda

  • Du behöver en Shelly-enhet som stöder skript (Gen2 eller senare).
  • Du måste också ha minst en enhet som mäter effekt (PM eller EM).
  • Använd Shelly Smart Control-appen på Android, iOS eller http://control.shelly.cloud på din PC. Det rekommenderas, och det är också det jag använder i den här guiden.

Steg 1: Kopiera Script

Kopiera scriptet nedan
(När du håller musen över den kan du välja Kopiera i det övre högra hörnet)

let CONFIG = {
  api_endpoint_template: "https://www.elprisetjustnu.se/api/v1/prices/{YEAR}/{DATE}_{PRICE_AREA}.json",
  // Ex på slutgenereret URL:
  // https://www.elprisetjustnu.se/api/v1/prices/2025/01-08_SE1.json

  // ********Inställningar nedan***********
  // Välj prisområde:
  // SE1 = Luleå / Norra Sverige
  // SE2 = Sundsvall / Norra centrala Sverige
  // SE3 = Stockholm / Södra centrala Sverige
  // SE4 = Malmö / Södra Sverige
  price_area: "SE1",

  
  include_vat: true, // Sätt till true för att inkludera moms (25%) i priset, eller false för att exkludera moms.

 
  include_elafgift: true,  // Sätt till true för att inkludera elskatt i priset, eller false för att exkludera elskatt.
  elafgift: 0.72, // Elskatt i kr/kWh (utan moms). Om include_vat är true, läggs moms även till på denna avgift.
  additional_cost: 0.164, // Extra kostnad i kr/kWh. Lägger till detta i det slutliga priset.
  include_tariffs: false, // Är inte aktuellt i Sverige, så inställt på false
  // Endast för orter där det tillkommer en extra avgift på timpriset under vissa perioder på dygnet
  tariff_periods: [
    { start: "00:01", end: "06:00", tariff: 0.0 }
  ],

  // URL för POST (Skicka det beräknade priset hit)
  post_url: "https://shelly-t1-eu.shelly.cloud/v2/user/pp-ltu/eyJpZCI6MzQ4NzQ4LCJzbiI6MjQwMzU5MjY0NH0.MisIm5ns_TV5_LuC4-XhvQ",
 
  // Styrning av uppdateringsfrekvens:
  // För att inte belasta servern bör det vara false. 
  // 1-minutskontroll endast för test.
  check_every_minute: false,
  check_delay_seconds: 10,   // Sekunder efter skifte när uppdateringen körs
  vc_id: 200,                // ID på virtuell numerisk enhet
};

let current_price = null;
let loggingIntervalTimer = null;
let nextUpdateInMs = 0;

/**
 * Hjälpfunktion:
 * Omvandlar millisekunder till "0h 5m 10s"-format
 */
function formatDelay(delayMs) {
  try {
    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";
  } catch (err) {
    print("Error in formatDelay:", err);
    return "";
  }
}

/**
 * Hämtar den fullständiga URL-slutpunkten för vårt pris-API,
 * baserat på dagens datum.
 */
function getApiEndpoint() {
  try {
    let now = new Date();
    let year = now.getFullYear();
    let month = now.getMonth() + 1;
    let day = now.getDate();
    let formattedMonth = (month < 10 ? "0" : "") + month;
    let formattedDay   = (day   < 10 ? "0" : "") + day;
    return CONFIG.api_endpoint_template
      .replace("{YEAR}", year)
      .replace("{DATE}", formattedMonth + "-" + formattedDay)
      .replace("{PRICE_AREA}", CONFIG.price_area);
  } catch (err) {
    print("Error building API URL:", err);
    return null;
  }
}

/**
 * Hittar den aktuella nätariffen (utifrån den aktuella tiden).
 */
function getCurrentTariff() {
  try {
    if (!CONFIG.include_tariffs) return 0;
    let now = new Date();
    let h = now.getHours(), m = now.getMinutes();
    for (let p of CONFIG.tariff_periods) {
      let [sh, sm] = p.start.split(":").map(Number);
      let [eh, em] = p.end.split(":").map(Number);
      if ((h > sh || (h === sh && m >= sm)) &&
          (h < eh || (h === eh && m <= em))) {
        return p.tariff;
      }
    }
    return 0;
  } catch (err) {
    print("Error in getCurrentTariff:", err);
    return 0;
  }
}

/**
 * Hämtar aktuellt pris från API, beräknar slutligt pris,
 * och skickar det via POST.
 */
function getCurrentPrice() {
  let apiUrl = getApiEndpoint();
  if (!apiUrl) {
    scheduleNextPriceCheck();
    return;
  }

  try {
    print("Fetching price from URL:", apiUrl);
    Shelly.call("http.get", { url: apiUrl, timeout: 5000 }, function (response, error_code, error_message) {
      try {
        if (error_code !== 0) {
          print("Error fetching price:", error_message);
          scheduleNextPriceCheck();
          return;
        }

        let data;
        try {
          data = JSON.parse(response.body);
        } catch (parseErr) {
          print("Error parsing JSON:", parseErr);
          scheduleNextPriceCheck();
          return;
        }

        let now = new Date();
        let year = now.getFullYear();
        let month = now.getMonth() + 1;
        let day = now.getDate();
        let hour = now.getHours();
        let fm = (month < 10 ? "0" : "") + month;
        let fd = (day   < 10 ? "0" : "") + day;
        let fh = (hour  < 10 ? "0" : "") + hour;

        // Bygg en sträng utan tidszonsdelen
        let currentHourStr = year + "-" + fm + "-" + fd + "T" + fh + ":00:00";

        let currentData = null;
        for (let i = 0; i < data.length; i++) {
          if (typeof data[i].time_start === "string" &&
              data[i].time_start.indexOf(currentHourStr) === 0) {
            currentData = data[i];
            break;
          }
        }

        if (!currentData) {
          print("No data found for current hour prefix:", currentHourStr);
          scheduleNextPriceCheck();
          return;
        }

        // Beräkna priset
        let sekPerKwh = currentData["SEK_per_kWh"];
        if (CONFIG.include_vat)      sekPerKwh *= 1.25;
        sekPerKwh += getCurrentTariff();
        if (CONFIG.include_elafgift) {
          let tax = CONFIG.elafgift;
          if (CONFIG.include_vat) tax *= 1.25;
          sekPerKwh += tax;
        }
        sekPerKwh += CONFIG.additional_cost;

        current_price = sekPerKwh.toFixed(2);
        print("Current price in SEK:", current_price);

        // Skriv till virtuell enhet
        Shelly.call("Number.Set", { id: CONFIG.vc_id, value: current_price });

        // POST till angiven 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 (pr, pe, pm) {
          try {
            if (pe !== 0) print("Error posting price:", pm);
            else        print("Price posted successfully:", current_price);
          } catch(postErr) {
            print("Error in POST callback:", postErr);
          }
        });

      } catch (cbErr) {
        print("Error in http.get callback:", cbErr);
      } finally {
        scheduleNextPriceCheck();
      }
    });

  } catch (err) {
    print("Error initiating getCurrentPrice:", err);
    scheduleNextPriceCheck();
  }
}

/**
 * Startar en återkommande timer som var 10:e minut loggar
 * "Tid kvar till nästa uppdatering".
 */
function startUpdateLogging() {
  try {
    if (loggingIntervalTimer) {
      Timer.clear(loggingIntervalTimer);
      loggingIntervalTimer = null;
    }
    let tenMin = 10 * 60 * 1000;
    loggingIntervalTimer = Timer.set(tenMin, true, function () {
      try {
        nextUpdateInMs -= tenMin;
        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));
        }
      } catch (tickErr) {
        print("Error in logging timer:", tickErr);
      }
    });
  } catch (err) {
    print("Error setting up logging timer:", err);
  }
}

/**
 * Planerar nästa uppdatering (antingen varje minut eller en gång i timmen),
 * men använder endast EN gemensam fördröjning, 'check_delay_seconds'.
 */
function scheduleNextPriceCheck() {
  try {
    let now = new Date();
    let delay = 0;
    if (CONFIG.check_every_minute) {
      let secs = 60 - now.getSeconds();
      delay = secs * 1000 - now.getMilliseconds() + CONFIG.check_delay_seconds * 1000;
      print("Scheduling next price check (minute-mode) in", formatDelay(delay));
    } else {
      let total = now.getMinutes() * 60 + now.getSeconds();
      delay = (3600 - total) * 1000 - now.getMilliseconds() + CONFIG.check_delay_seconds * 1000;
      print("Scheduling next price check (hour-mode) in", formatDelay(delay));
    }
    nextUpdateInMs = delay;
    Timer.set(delay, false, getCurrentPrice);
    startUpdateLogging();
  } catch (err) {
    print("Error scheduling next price check:", err);
  }
}

// Hämta priset omedelbart vid start, sedan enligt schema
getCurrentPrice();

Steg 2: Infoga Script

  1. Tryck på enheten och välj scriptikonen.
  2. Skapa nytt script.
  3. Ge det ett namn och klistra in det kopierade scriptet.
  4. Tryck på Spara (disk) och Stäng (kryss)

    Obs: Scriptet kan också enkelt infogas från enhetens webbgränssnitt.

Steg 3: Hitta och kopiera din Token

  1. Gå till “Energi” och välj fliken Elpris.
  2. Tryck Live bredvid Elpris.
  3. Scrolla ner till API URL och kopiera din Token.

OBS! Om du trycker på Manual och Live igen kommer en ny token att genereras, som sedan måste matas in i skriptet.

Steg 4: Infoga token

På post_url på rad 28
Byt ut den nuvarande token med den du kopierade.
OBS! Gåsögonen borde fortfarande finnas där.

Steg 5: Redigera scriptet

För att få scriptet konfigurerat för dina priser, krävs en liten modifiering.

Script beskrivning

price_area: SE1, SE2, SE3, SE4
Här skriver du vilken priszon du befinner dig i.
SE1 = Luleå / Northern Sweden
SE2 = Sundsvall / Northern Central Sweden
SE3 = Stockholm / Southern Central Sweden
SE4 = Malmö / Southern Sweden

include_vat: true, eller false
Här kan du ange om du vill visa priset inklusive moms.
true att inkludera moms (25%) i priset.
false att exkludera moms.

include_elafgift: true, eller false
Här kan du ange om du vill se priset inklusive elskatt.
true att inkludera elskatt i priset.
false att undanta elskatt.

elafgift: värde   (Ex. 0.72)
Skriv elskatten i kronor (exkl. moms) per kWh. Om include_vat är sant läggs även moms på denna skatt.
(Från och med 2025: Ex. moms = 0,72 SEK. Inkl. moms = 90 SEK.)

additional_cost: värde (Ex. 0.168)
Här anger du dina överföringskostnader. kWh i kronor. Kommer att läggas till det slutliga priset.
(om du har ytterligare kostnader, lägg dem bara till samma belopp).

include_tariffs: true, eller false
är inte aktuellt i Sverige, så inställt på false

tariff_periods:
Endast för orter där det tillkommer en extra avgift på timpriset under vissa perioder på dygnet, tydligen inte nödvändigt i Sverige
Ex. på en rad:
{ start: “00:01”, end: “06:00”, tariff: 0.14 },

check_every_minute: true, eller false
Här skriver du om du vill att den ska hämta priset varje timme, eller varje minut.
true för att hämta pris varje minut (Bör endast användas för testning).
false för att få pris, varje timme (rekommenderas).
(För att undvika att överbelasta servern där priset hämtas ska 1-minuterskontrollen endast användas för att testa om den fungerar).

hour_check_delay_seconds:
  värde (ex 10)
Här anger du antalet sekunder efter timbytet när priskontrollen utförs.

Användbara länkar för att kontrollera dina priser

Steg 6: Se till att scriptet körs

Slutligen måste vi se till att skriptet körs och att det startar automatiskt om enheten startar om.

  1. Gå under script.
  2. Aktivera autostart.
  3. Starta manuset genom att trycka på play-knappen.
    (Blå ring = aktiv)

Steg 7: Slut på skriptinställning

När manuset har hämtat priset första gången ska du kunna se det uppdaterade priset under Energi -> Elpris.
Det är nödvändigt att uppdatera sidan genom att till exempel: för att trycka på F5

OBS! Om du kommer åt skriptet från enhetens webbgränssnitt via dess IP kommer du att kunna se en logg som visar vad som händer.

Viktig

  • Om du trycker på Manual och Live igen genereras en ny token som sedan måste matas in i scriptet.
  • Priset avrundas uppåt/nedåt till 2 decimaler, så priset kan ibland skilja sig med en slant eller två, beroende på vad som anges i “additional_cost:”
  • Kom ihåg Tarifferna kan ändras flera gånger om året, så du måste justera detta manuellt.
  • Detsamma gäller om skatter och överföringskostnader m.m. ändrats.

    Om du har problem, fråga gärna i den svenska Facebookgruppen.

Extra: Lägg till pris i virtuell enhet (kräver Gen3 eller senare)

Scriptet skriver också priset till det virtuella “numret” Enhet. ID: 200 (Detta ID-nummer kan ändras i skriptet)
– Kräver Gen3 eller senare
Med den kan du:

  • Se priset som en enhet.
  • Gör åtgärder baserat på priset.
  • Använd den i scener. (KOMMER SNART)

UPPMÄRKSAMHET!
Som standard kan du bara extrahera en virtuell enhet som en enhet.
Vill du ha mer krävs Premium)

Förfarande

  1. Välj en virtuell nummerenhet.
  2. Ange de olika inställningarna för hur enheten ska se ut (Detta kan alltid ändras i efterhand)

    UPPMÄRKSAMHET! Den första enheten du skapar börjar alltid som id:200 och sedan 201, 202 osv.

  1. Välj Grupper och skapa grupp.
  2. Ge gruppen ett namn.
  3. Kontrollera den virtuella enheten du skapade.
  4. Markera rutan för Extrahera virtuell grupp som enhet.

Det var det!
Du har nu en virtuell enhet som visar vad priset är.
Den kan läggas till i din instrumentpanel, men kan också användas för att skapa åtgärder för att slå på och av dina enheter baserat på elpriset.

UPPMÄRKSAMHET! Priset kommer givetvis att visas nästa gång skriptet hämtar priset.
UPPMÄRKSAMHET! Om du vill ha en bild av gruppen som har extraherats, infogar du webbadressen till bilden från enhetens webbgränssnitt.