This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

Nordpool electricity
#10
(15.01.2026, 11:54)almoisey Wrote: But  perhaps can you add the second variant to give the option to choise hourly or 15min pricing ?
This should work. Don't now about the DST (summer time/winter time) because haven't tested it yet.
Code:
-------------------------------------------------
-- PRICE CALCULATION -Change these
-------------------------------------------------
vat        = 1.255
marginal  = 0.42
electricity_tax = 2.82752
night_tariff = 0.89
day_tariff = 1.87

function add_costs(base_price, hour)
  local tariff

  -- Night tariff 22:00–07:00
  if hour >= 22 or hour < 7 then
    tariff = night_tariff
  else
    tariff = day_tariff
  end

  return base_price * vat + marginal + tariff + electricity_tax
end

https = require('ssl.https')
json = require('json')
ltn12 = require('ltn12')

country = 'fi'

current_price_addr        = '35/5/12'
cheapest_hour_addr        = '35/5/13'
cheapest_hour_price_addr  = '35/5/14'
costliest_hour_addr       = '35/5/15'
cosltiest_hour_price_addr = '35/5/16'

-------------------------------------------------
-- Helper: format numbers to "xx.xx snt"
-------------------------------------------------
-- Format for KNX (string with unit)
local function fmt2s(x)
  if type(x) ~= "number" then return x end
  return string.format("%.3f snt", x)
end

-- Format for storage (pure number)
local function fmt2num(x)
  if type(x) ~= "number" then return x end
  return tonumber(string.format("%.5f", x))
end

-------------------------------------------------
-- DATE SETUP
-------------------------------------------------
local current_date = os.date('*t')

local day_start_ts = os.time({
  year  = current_date.year,
  month = current_date.month,
  day   = current_date.day,
  hour  = 0, min = 0, sec = 0
})
local day_end_ts = day_start_ts + 24 * 3600

local tomorrow_start_ts = day_start_ts + 24 * 3600
local tomorrow_end_ts   = tomorrow_start_ts + 24 * 3600

local current_ts = os.time()

-------------------------------------------------
-- FETCH DATA
-------------------------------------------------
local previous_date = os.date('%F', os.time() - 24 * 3600)
local next_date     = os.date('%F', os.time() + 24 * 3600)

local url =
  'https://dashboard.elering.ee/api/nps/price?start=' ..
  previous_date .. 'T21%3A00%3A00Z&end=' ..
  next_date .. 'T23%3A59%3A59Z'

local mac = 0
io.readfile('/sys/class/net/eth0/address'):gsub('%x%x', function(v)
  mac = mac * 256 + tonumber(v, 16)
end)

local response = {}
local res, code = https.request({
  url = url,
  protocol = 'tlsv12',
  headers = { ['user-agent'] = 'LM ' .. mac },
  sink = ltn12.sink.table(response)
})

if not (res and code == 200) then
  log('request error', res, code)
  return
end

local data = json.pdecode(table.concat(response))
if not data or not data.data or not data.data[country] then
  log('No data for country: ' .. country)
  return
end

-------------------------------------------------
-- PROCESS TODAY + TOMORROW
-------------------------------------------------
local hourly_prices_today = {}
local today_hours = {}
local tomorrow_entries = {}

for h = 0, 23 do
  hourly_prices_today[h] = { sum = 0, count = 0 }
end

for _, record in ipairs(data.data[country]) do
  local timestamp = record.timestamp
  local lt = os.date('*t', timestamp)
  local hour = lt.hour
  local price = add_costs(record.price * 0.1, hour)

  -- TODAY
  if timestamp >= day_start_ts and timestamp < day_end_ts then
    local d = hourly_prices_today[hour]
    d.sum = d.sum + price
    d.count = d.count + 1
  end

  -- TOMORROW (15-min entries)
  if timestamp >= tomorrow_start_ts and timestamp < tomorrow_end_ts then
    tomorrow_entries[#tomorrow_entries + 1] = {
      timestamp = timestamp,
      price = price
    }
  end
end

-------------------------------------------------
-- CURRENT PRICE
-------------------------------------------------
do
  local ch = tonumber(os.date('%H', current_ts))
  local d = hourly_prices_today[ch]
  if d and d.count > 0 then
    grp.write(current_price_addr, d.sum / d.count)
  end
end

-------------------------------------------------
-- TODAY HOURLY AVERAGES
-------------------------------------------------
for h = 0, 23 do
  local d = hourly_prices_today[h]
  if d.count > 0 then
    today_hours[h+1] = d.sum / d.count
  else
    today_hours[h+1] = "Ei hintaa"
  end
end

-- WRITE TODAY → 35/6/0..23 (numeric)
for h = 0, 23 do
  grp.checkwrite('35/6/' .. h, today_hours[h+1])
end

-------------------------------------------------
-- TOMORROW: 15-min → hourly
-------------------------------------------------
local tomorrow_segments = {}

do
  local total_quarters = #tomorrow_entries
  local full_segments = math.floor(total_quarters / 4)

  for seg = 0, full_segments do
    local base = seg * 4 + 1
    if tomorrow_entries[base + 3] then
      local ts = tomorrow_entries[base].timestamp
      local h = os.date('*t', ts).hour

      local s = 0
      for j = base, base + 3 do
        s = s + tomorrow_entries[j].price
      end

      tomorrow_segments[#tomorrow_segments + 1] = {
        hour = h,
        price = s / 4
      }
    end
  end
end

local seg_count = #tomorrow_segments
local tomorrow_hours_stored = {}

-------------------------------------------------
-- WRITE TOMORROW → 35/7/0..23 (STRING "xx.xx snt")
-------------------------------------------------
for h = 0, 23 do
  local seg_idx = nil

  if seg_count == 24 then
    seg_idx = h + 1
  elseif seg_count == 23 then
    if h <= 2 then seg_idx = h + 1
    elseif h == 3 then seg_idx = nil
    else seg_idx = h end
  elseif seg_count == 25 then
    if h <= 2 then seg_idx = h + 1
    elseif h == 3 then seg_idx = 4
    else seg_idx = h + 2 end
  else
    if h + 1 <= seg_count then seg_idx = h + 1 end
  end

  local value = "Ei hintaa"
  if seg_idx and tomorrow_segments[seg_idx] then
    value = fmt2s(tomorrow_segments[seg_idx].price)
  end

  grp.checkwrite('35/7/' .. h, value)
  tomorrow_hours_stored[h+1] = value
end

-------------------------------------------------
-- DST EXTRA HOUR → 35/7/25
-------------------------------------------------
if seg_count == 25 and tomorrow_segments[5] then
  grp.checkwrite('35/7/25', fmt2s(tomorrow_segments[5].price))
else
  grp.checkwrite('35/7/25', "Ei hintaa")
end

-------------------------------------------------
-- DAY AFTER TOMORROW FIRST HOUR → 35/7/24
-------------------------------------------------
local day_after_tomorrow_price = "Ei hintaa"

do
  local start_ts = tomorrow_end_ts
  local end_ts = tomorrow_end_ts + 3600

  local sum = 0
  local count = 0

  for _, record in ipairs(data.data[country]) do
    local ts = record.timestamp
    if ts >= start_ts and ts < end_ts then
      local lt = os.date('*t', ts)
      local p = add_costs(record.price * 0.1, lt.hour)
      sum = sum + p
      count = count + 1
    end
  end

  if count > 0 then
    day_after_tomorrow_price = fmt2s(sum / count)
  end
end

grp.checkwrite('35/7/24', day_after_tomorrow_price)
Reply


Messages In This Thread
Nordpool electricity - by almoisey - 06.10.2025, 05:00
RE: Nordpool electricity - by RomansP - 06.10.2025, 07:35
RE: Nordpool electricity - by almoisey - 06.10.2025, 09:02
RE: Nordpool electricity - by RomansP - 06.10.2025, 09:21
RE: Nordpool electricity - by RomansP - 06.10.2025, 12:52
RE: Nordpool electricity - by almoisey - 14.01.2026, 08:01
RE: Nordpool electricity - by admin - 14.01.2026, 11:01
RE: Nordpool electricity - by almoisey - 15.01.2026, 11:54
RE: Nordpool electricity - by icuzz - 19.01.2026, 02:10
RE: Nordpool electricity - by RomansP - 15.01.2026, 12:27

Forum Jump: