LogicMachine Forum
NordPool prices in LogicMachine - Printable Version

+- LogicMachine Forum (https://forum.logicmachine.net)
+-- Forum: LogicMachine eco-system (https://forum.logicmachine.net/forumdisplay.php?fid=1)
+--- Forum: Scripting (https://forum.logicmachine.net/forumdisplay.php?fid=8)
+--- Thread: NordPool prices in LogicMachine (/showthread.php?tid=4456)



NordPool prices in LogicMachine - martins.neibergs@gmail.com - 19.12.2022

Hi!

Has anyone had any experience with getting (integrating) NordPool prices into LogicMachine?

Tried different versions but nothing worked. 

What about this one? 

https://dashboard.elering.ee/en/nps/price?interval=minute&period=days&start=2022-07-25T21:00:00.000Z&end=2022-07-26T20:59:59.999Z
https://dashboard.elering.ee/api/nps/price?start=2022-07-25T22%3A00%3A00.999Z&end=2022-07-26T22%3A00%3A00.999Z

Anyone had any luck or experience? Can you please share scripts for getting NordPool prices into logic machine?


RE: NordPool prices in LogicMachine - RomansP - 20.12.2022

Hi!

Here is a script, that gives six objects 1.current_time; 2.current_price; 3.cheapest_hour; 4.cheapest_price; 5.costly_hour; 6.costly_price

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

country = 'lv' -- Latvia
--country = 'fi' -- Finland
--country = 'lt' -- Lithuania
--country = 'ee' -- Estonia

obj_current_time = grp.create({ datatype = dt.time, address = '35/5/11', name = 'current_time'})
obj_current_price = grp.create({ datatype = dt.float32, address = '35/5/12', name = 'current_price'})
obj_cheapest_hour = grp.create({ datatype = dt.time, address = '35/5/13', name = 'cheapest_hour'})
obj_cheapest_hour_price = grp.create({ datatype = dt.float32, address = '35/5/14', name = 'cheapest_price'})
obj_costly_hour = grp.create({ datatype = dt.time, address = '35/5/15', name = 'costly_hour'})
obj_costly_hour_price = grp.create({ datatype = dt.float32, address = '35/5/16', name = 'costly_price'})

--[[]]
current_date = os.date('*t')

previous_date = os.date('*t', os.time()-24*60*60)
--log(previous_date)

if previous_date.month < 10 then
  previous_date.month = '0' .. previous_date.month
end

if previous_date.day < 10 then
  previous_date.day = '0' .. previous_date.day
end

previous_date_str = previous_date.year .. '-' .. previous_date.month .. '-' .. previous_date.day

--log(previous_date_str)

next_date = os.date('*t', os.time() + 24*60*60)
--log(next_date)

if next_date.month < 10 then
  next_date.month = '0' .. next_date.month
end

if next_date.day < 10 then
  next_date.day = '0' .. next_date.day
end

next_date_str = next_date.year .. '-' .. next_date.month .. '-' .. next_date.day

--log(next_date_str)

url = 'https://dashboard.elering.ee/api/nps/price?start='.. previous_date_str ..'T00%3A00%3A00.999Z&end=' .. next_date_str ..'T00%3A00%3A00.999Z'

--log(url)

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

response = {}

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

if res and code == 200 then
  data = json.pdecode(table.concat(response))
else
  log('request error', res, code)
end

--log(data)

--log(data['data'][country])

min_price = 99999
max_price = -1
min_price_hour = -1
max_price_hour = -1

for i = 23, 47, 1 do -- 23 is 00:00 for GMT+0200 (Eastern European Standard Time)
  if data['data'][country][i] then 
    price = data['data'][country][i]['price']
   
    if price < min_price then
      min_price = price -- EUR/MegaWatt*hour
      min_price_hour = i - 23 -- get hour for GMT+0200 (Eastern European Standard Time)
    end
   
    if price > max_price then
      max_price = price -- EUR/MegaWatt*hour
      max_price_hour = i - 23 -- get hour for GMT+0200 (Eastern European Standard Time)
    end
   
  end
end


--log(min_price_hour)
--log(min_price)
--log(max_price_hour)
--log(max_price)


curr_day_time = {}

if current_date['wday'] > 1 then
  current_date['wday'] = current_date['wday'] - 1 -- 1 is Monday, 2 is Tuesday
else
  current_date['wday'] = 7 -- 7 is Sunday
end
 
curr_day_time['day'] = current_date['wday']
curr_day_time['hour'] = current_date['hour']
curr_day_time['minute'] = current_date['min']

grp.write(obj_current_time, curr_day_time) -- 3 byte time day

current_price = data['data'][country][ current_date['hour'] + 23 ]['price'] -- EUR/MegaWatt*hour

--[[
timestamp = data['data'][country][ current_date['hour'] + 23 ]['timestamp']
log(timestamp)
temp = os.date("*t", timestamp)
log(temp)
--]]

grp.write(obj_current_price, current_price) -- float


cheapest_day_time = {}
cheapest_day_time['day'] = current_date['wday']
cheapest_day_time['hour'] = min_price_hour
grp.write(obj_cheapest_hour, cheapest_day_time) -- 3 byte time day
grp.write(obj_cheapest_hour_price, min_price) -- float

costly_day_time = {}
costly_day_time['day'] = current_date['wday']
costly_day_time['hour'] = max_price_hour
grp.write(obj_costly_hour, costly_day_time) -- 3 byte time day
grp.write(obj_costly_hour_price, max_price) -- float
--]]



RE: NordPool prices in LogicMachine - RomansP - 06.10.2025

Hi!

We have rewritten script (old script will not work properly), because of a change
in time intervals (previously electricity price was per hour, now per 15 minutes).

Here is a new script:

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

country = 'lv' -- Latvia
--country = 'fi' -- Finland
--country = 'lt' -- Lithuania
--country = 'ee' -- Estonia

current_price_addr = '40/1/18'
cheapest_hour_addr = '40/1/16'
cheapest_hour_price_addr = '40/1/17'
costliest_hour_addr = '40/1/19'
cosltiest_hour_price_addr = '40/1/20'
cheapest_time_addr = '40/1/14'
cheapest_price_addr = '40/1/15'
costliest_time_addr = '40/1/21'
costliest_price_addr = '40/1/22'

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 = os.time({year = current_date.year, month = current_date.month, day = current_date.day, hour = 23, min = 59, sec = 59})
local current_ts = os.time()

previous_date = os.date('%F', os.time() - 24*60*60)
next_date = os.date('%F', os.time() + 24*60*60)

url = 'https://dashboard.elering.ee/api/nps/price?start='.. previous_date ..'T00%3A00%3A00.999Z&end=' .. next_date ..'T00%3A00%3A00.999Z'

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

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

if res and code == 200 then
  data = json.pdecode(table.concat(response))
else
  log('request error', res, code)
  return
end


min_price = 99999
max_price = -1
min_price_timestamp = 0
max_price_timestamp = 0
current_price = nil


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

if not data or not data.data or not data.data[country] then
  log('No data for country: ' .. country)
  return
end

for _, record in ipairs(data.data[country]) do
  local timestamp = record.timestamp
  local price = record.price

  if timestamp >= day_start_ts and timestamp <= day_end_ts then
   
    if price < min_price then
      min_price = price
      min_price_timestamp = timestamp
    end
   
    if price > max_price then
      max_price = price
      max_price_timestamp = timestamp
    end

    local record_time = os.date('*t', timestamp)
    local hour = record_time.hour
    if hourly_prices[hour] then
      hourly_prices[hour].sum = hourly_prices[hour].sum + price
      hourly_prices[hour].count = hourly_prices[hour].count + 1
    end
  end
 
  if current_ts >= timestamp and current_ts < (timestamp + 15 * 60) then
    current_price = price
  end
end

--log('--- Current Status ---')
if current_price then
  --log('Current 15-min price: ' .. current_price .. ' EUR/MWh')
  grp.write(current_price_addr, current_price) -- float
else
  log('Could not determine current price')
end


min_avg_price = 99999
max_avg_price = -1
cheapest_hour = -1
costliest_hour = -1

for hour, data in pairs(hourly_prices) do
  if data.count > 0 then
    local avg_price = data.sum / data.count
    --log(string.format("Hour %02d:00 - Avg Price: %.2f", hour, avg_price))
   
    if avg_price < min_avg_price then
      min_avg_price = avg_price
      cheapest_hour = hour
    end

    if avg_price > max_avg_price then
      max_avg_price = avg_price
      costliest_hour = hour
    end
  end
end

cheapest_hour_time = {}
cheapest_hour_time['wday'] = current_date['wday']

--log('--- Cheapest Hour Today ---')
if cheapest_hour ~= -1 then
  --log(string.format('Hour: %02d:00 - %02d:59', cheapest_hour, cheapest_hour))
  --log(string.format('Average Price: %.2f EUR/MWh', min_avg_price))
  cheapest_hour_time['hour'] = cheapest_hour
  grp.write(cheapest_hour_addr, cheapest_hour_time)
  grp.write(cheapest_hour_price_addr, min_avg_price)
else
  log('Could not calculate the cheapest hour.')
end

costliest_hour_time = {}
costliest_hour_time['wday'] = current_date['wday']

--log('--- Costliest Hour Today ---')
if costliest_hour ~= -1 then
  --log(string.format('Hour: %02d:00 - %02d:59', costliest_hour, costliest_hour))
  --log(string.format('Average Price: %.2f EUR/MWh', max_avg_price))
  costliest_hour_time['hour'] = costliest_hour
  grp.write(costliest_hour_addr, costliest_hour_time)
  grp.write(cosltiest_hour_price_addr, max_avg_price)
else
  log('Could not calculate the costliest hour.')
end

cheapest_time = {}
cheapest_time['wday'] = current_date['wday']

--log('--- Cheapest 15-min Interval Today ---')
if min_price_timestamp > 0 then
  local min_price_time = os.date('*t', min_price_timestamp)
  --log('Price: ' .. min_price .. ' EUR/MWh')
  --log('Time: ' .. string.format('%02d:%02d', min_price_time.hour, min_price_time.min))
  cheapest_time['hour'] = min_price_time.hour
  cheapest_time['minute'] = min_price_time.min
  grp.write(cheapest_time_addr, cheapest_time)
  grp.write(cheapest_price_addr, min_price)
else
  log('Could not find minimum price for today')
end

costliest_time = {}
costliest_time['wday'] = current_date['wday']

--log('--- Costliest 15-min Interval Today ---')
if max_price_timestamp > 0 then
  local max_price_time = os.date('*t', max_price_timestamp)
  --log('Price: ' .. max_price .. ' EUR/MWh')
  --log('Time: ' .. string.format('%02d:%02d', max_price_time.hour, max_price_time.min))
  costliest_time['hour'] = max_price_time.hour
  costliest_time['minute'] = max_price_time.min
  grp.write(costliest_time_addr, costliest_time)
  grp.write(costliest_price_addr, max_price)
else
  log('Could not find maximum price for today')
end



RE: NordPool prices in LogicMachine - Novodk - 07.10.2025

(06.10.2025, 12:51)RomansP Wrote: Hi!

We have rewritten script (old script will not work properly), because of a change
in time intervals (previously electricity price was per hour, now per 15 minutes).

Here is a new script:

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

country = 'lv' -- Latvia
--country = 'fi' -- Finland
--country = 'lt' -- Lithuania
--country = 'ee' -- Estonia

current_price_addr = '40/1/18'
cheapest_hour_addr = '40/1/16'
cheapest_hour_price_addr = '40/1/17'
costliest_hour_addr = '40/1/19'
cosltiest_hour_price_addr = '40/1/20'
cheapest_time_addr = '40/1/14'
cheapest_price_addr = '40/1/15'
costliest_time_addr = '40/1/21'
costliest_price_addr = '40/1/22'

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 = os.time({year = current_date.year, month = current_date.month, day = current_date.day, hour = 23, min = 59, sec = 59})
local current_ts = os.time()

previous_date = os.date('%F', os.time() - 24*60*60)
next_date = os.date('%F', os.time() + 24*60*60)

url = 'https://dashboard.elering.ee/api/nps/price?start='.. previous_date ..'T00%3A00%3A00.999Z&end=' .. next_date ..'T00%3A00%3A00.999Z'

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

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

if res and code == 200 then
  data = json.pdecode(table.concat(response))
else
  log('request error', res, code)
  return
end


min_price = 99999
max_price = -1
min_price_timestamp = 0
max_price_timestamp = 0
current_price = nil


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

if not data or not data.data or not data.data[country] then
  log('No data for country: ' .. country)
  return
end

for _, record in ipairs(data.data[country]) do
  local timestamp = record.timestamp
  local price = record.price

  if timestamp >= day_start_ts and timestamp <= day_end_ts then
   
    if price < min_price then
      min_price = price
      min_price_timestamp = timestamp
    end
   
    if price > max_price then
      max_price = price
      max_price_timestamp = timestamp
    end

    local record_time = os.date('*t', timestamp)
    local hour = record_time.hour
    if hourly_prices[hour] then
      hourly_prices[hour].sum = hourly_prices[hour].sum + price
      hourly_prices[hour].count = hourly_prices[hour].count + 1
    end
  end
 
  if current_ts >= timestamp and current_ts < (timestamp + 15 * 60) then
    current_price = price
  end
end

--log('--- Current Status ---')
if current_price then
  --log('Current 15-min price: ' .. current_price .. ' EUR/MWh')
  grp.write(current_price_addr, current_price) -- float
else
  log('Could not determine current price')
end


min_avg_price = 99999
max_avg_price = -1
cheapest_hour = -1
costliest_hour = -1

for hour, data in pairs(hourly_prices) do
  if data.count > 0 then
    local avg_price = data.sum / data.count
    --log(string.format("Hour %02d:00 - Avg Price: %.2f", hour, avg_price))
   
    if avg_price < min_avg_price then
      min_avg_price = avg_price
      cheapest_hour = hour
    end

    if avg_price > max_avg_price then
      max_avg_price = avg_price
      costliest_hour = hour
    end
  end
end

cheapest_hour_time = {}
cheapest_hour_time['wday'] = current_date['wday']

--log('--- Cheapest Hour Today ---')
if cheapest_hour ~= -1 then
  --log(string.format('Hour: %02d:00 - %02d:59', cheapest_hour, cheapest_hour))
  --log(string.format('Average Price: %.2f EUR/MWh', min_avg_price))
  cheapest_hour_time['hour'] = cheapest_hour
  grp.write(cheapest_hour_addr, cheapest_hour_time)
  grp.write(cheapest_hour_price_addr, min_avg_price)
else
  log('Could not calculate the cheapest hour.')
end

costliest_hour_time = {}
costliest_hour_time['wday'] = current_date['wday']

--log('--- Costliest Hour Today ---')
if costliest_hour ~= -1 then
  --log(string.format('Hour: %02d:00 - %02d:59', costliest_hour, costliest_hour))
  --log(string.format('Average Price: %.2f EUR/MWh', max_avg_price))
  costliest_hour_time['hour'] = costliest_hour
  grp.write(costliest_hour_addr, costliest_hour_time)
  grp.write(cosltiest_hour_price_addr, max_avg_price)
else
  log('Could not calculate the costliest hour.')
end

cheapest_time = {}
cheapest_time['wday'] = current_date['wday']

--log('--- Cheapest 15-min Interval Today ---')
if min_price_timestamp > 0 then
  local min_price_time = os.date('*t', min_price_timestamp)
  --log('Price: ' .. min_price .. ' EUR/MWh')
  --log('Time: ' .. string.format('%02d:%02d', min_price_time.hour, min_price_time.min))
  cheapest_time['hour'] = min_price_time.hour
  cheapest_time['minute'] = min_price_time.min
  grp.write(cheapest_time_addr, cheapest_time)
  grp.write(cheapest_price_addr, min_price)
else
  log('Could not find minimum price for today')
end

costliest_time = {}
costliest_time['wday'] = current_date['wday']

--log('--- Costliest 15-min Interval Today ---')
if max_price_timestamp > 0 then
  local max_price_time = os.date('*t', max_price_timestamp)
  --log('Price: ' .. max_price .. ' EUR/MWh')
  --log('Time: ' .. string.format('%02d:%02d', max_price_time.hour, max_price_time.min))
  costliest_time['hour'] = max_price_time.hour
  costliest_time['minute'] = max_price_time.min
  grp.write(costliest_time_addr, costliest_time)
  grp.write(costliest_price_addr, max_price)
else
  log('Could not find maximum price for today')
end

What about Denmark Smile


RE: NordPool prices in LogicMachine - RomansP - 08.10.2025

Hi,

We will prepare script for Denmark, Sweden, Norway and Germany


RE: NordPool prices in LogicMachine - RomansP - 13.10.2025

Hello,

We have prepared script for electricity prices for Denmark, Norway, Sweden and Germany

Code:
price_area = 'DK1' -- west Denmark DK1 grid region
--price_area = 'DK2' -- east Denmark DK2 grid region
--price_area = 'DE' -- Germany
--price_area = 'NO2' -- southern and southwestern Norway
--price_area = 'SE3' -- north Sweden
--price_area = 'SE4' -- south Sweden

current_price_addr = '40/1/18' -- 14. 4 byte floating point
cheapest_hour_addr = '40/1/16' -- 10. 3 byte time / day
cheapest_hour_price_addr = '40/1/17' -- 14. 4 byte floating point
costliest_hour_addr = '40/1/19' -- 10. 3 byte time / day
costliest_hour_price_addr = '40/1/20' -- 14. 4 byte floating point

start_date = os.date('%Y-%m-%d')
end_date = os.date('%Y-%m-%d', os.time() + 48 * 60 * 60)

url = 'https://api.energidataservice.dk/dataset/DayAheadPrices?start=' ..
      start_date .. '&end=' .. end_date ..
      '&filter={"PriceArea":["' .. price_area .. '"]}'
resp, code = require('socket.http').request(url)

if resp and code == 200 then
  data = require('json').pdecode(resp)
else
  log('request error', resp, code)
  return
end

if not data or not data.records then
  log('No data for price area: ' .. price_area)
  return
end

curr_day = tonumber(os.date('%u'))
next_day = curr_day == 7 and 1 or (curr_day + 1)
curr_date = os.date('%Y%m%d')
curr_hour_str = curr_date .. os.date('%H')
curr_hour = tonumber(curr_hour_str)
curr_min = math.floor(tonumber(os.date('%M')) / 15) * 15
curr_ts = curr_hour_str .. string.format('%02d', curr_min)

prices = {}

for _, record in ipairs(data.records) do
  ts = record.TimeDK:gsub('%-', ''):gsub('T', ''):gsub(':', '')
  hour = tonumber(ts:sub(1, 10))
  price = record.DayAheadPriceEUR

  if hour >= curr_hour then
    store = prices[ hour ] or { sum = 0, count = 0 }
    store.sum = store.sum + price
    store.count = store.count + 1
    prices[ hour ] = store
  end

  if ts:sub(1, 12) == curr_ts then
    curr_price = price
  end
end

hourly = {}

for hour, store in pairs(prices) do
  price = store.sum / store.count
  hourly[ #hourly + 1 ] = {
    hour = hour,
    price = price
  }
end

table.sort(hourly, function(a, b)
  return a.price > b.price
end)

function update(store, hour_addr, price_addr)
  local hour = tostring(store.hour)
  local date = hour:sub(1, 8)
  local day = date == curr_date and curr_day or next_day

  grp.checkupdate(hour_addr, { day = day, hour = hour:sub(9, 10) })
  grp.checkupdate(price_addr, store.price)
end

grp.checkupdate(current_price_addr, curr_price)
update(hourly[1], costliest_hour_addr, costliest_hour_price_addr)
update(hourly[#hourly], cheapest_hour_addr, cheapest_hour_price_addr)