Merge branch 'master' of https://github.com/zobnin/aiolauncher_scripts
This commit is contained in:
183
community/electricity-price-widget.lua
Normal file
183
community/electricity-price-widget.lua
Normal file
@@ -0,0 +1,183 @@
|
||||
-- name = "Electricity spot price"
|
||||
-- description = "Day-ahead spot price of electricity"
|
||||
-- data_source = "https://api.energy-charts.info/"
|
||||
-- type = "widget"
|
||||
-- foldable = "true"
|
||||
-- author = "Hannu Hartikainen <hannu.hartikainen@gmail.com>"
|
||||
-- version = "1.0"
|
||||
|
||||
json = require "json"
|
||||
prefs = require "prefs"
|
||||
|
||||
url_base = "https://api.energy-charts.info/price?bzn=%s&end=%d"
|
||||
|
||||
price_data = nil
|
||||
price_interval = nil
|
||||
price_unit = nil
|
||||
unit_multiplier = 1
|
||||
|
||||
next_fetch_ts = 0
|
||||
next_redraw_ts = nil
|
||||
|
||||
-- parameters and default values
|
||||
function on_load()
|
||||
-- bidding zone: see "Available bidding zones" in https://api.energy-charts.info/
|
||||
if not prefs.bidding_zone then
|
||||
prefs.bidding_zone = "FI"
|
||||
end
|
||||
|
||||
-- VAT percentage
|
||||
if not prefs.vat_percentage then
|
||||
prefs.vat_percentage = 24
|
||||
end
|
||||
|
||||
-- change threshold percentages for showing changes in folded format
|
||||
if not prefs.oneline_threshold_high then
|
||||
prefs.oneline_threshold_high = 1.3
|
||||
end
|
||||
if not prefs.oneline_threshold_low then
|
||||
prefs.oneline_threshold_low = 0.7
|
||||
end
|
||||
|
||||
-- url to open when clicked
|
||||
if not prefs.click_url then
|
||||
prefs.click_url = "https://www.sahkonhintatanaan.fi/"
|
||||
end
|
||||
end
|
||||
|
||||
function get_url()
|
||||
-- at most about 35 hours are known in advance; fetch all known prices
|
||||
local end_offset = 2*24*60*60
|
||||
local end_ts = os.time() + end_offset
|
||||
return string.format(url_base, prefs.bidding_zone, end_ts)
|
||||
end
|
||||
|
||||
function on_alarm()
|
||||
if os.time() > next_fetch_ts then
|
||||
http:get(get_url())
|
||||
end
|
||||
end
|
||||
|
||||
function on_network_result(result, code)
|
||||
if code >= 200 and code < 299 then
|
||||
parse_result(result)
|
||||
draw_widget(true)
|
||||
end
|
||||
end
|
||||
|
||||
function on_tick(t)
|
||||
local ts = os.time()
|
||||
if next_redraw_ts and ts > next_redraw_ts then
|
||||
draw_widget(true)
|
||||
end
|
||||
end
|
||||
|
||||
function on_click()
|
||||
if not ui:folding_flag() then
|
||||
system:open_browser(prefs.click_url)
|
||||
else
|
||||
draw_widget(false)
|
||||
end
|
||||
end
|
||||
|
||||
function parse_result(result)
|
||||
price_data = json.decode(result)
|
||||
local price_count = #price_data.unix_seconds
|
||||
if price_count < 2 then
|
||||
return
|
||||
end
|
||||
|
||||
price_interval = price_data.unix_seconds[2] - price_data.unix_seconds[1]
|
||||
if price_data.unit == "EUR/MWh" then
|
||||
price_unit = "c/kWh"
|
||||
unit_multiplier = 0.1
|
||||
else
|
||||
price_unit = price_data.unit
|
||||
unit_multiplier = 1
|
||||
end
|
||||
|
||||
-- assume next day is known 8 hours before it starts
|
||||
-- (eg. Nord Pool Spot typically publishes dayahead prices at 14 local time)
|
||||
local next_fetch_offset = 8*60*60
|
||||
local end_of_data_ts = price_data.unix_seconds[price_count] + price_interval
|
||||
next_fetch_ts = end_of_data_ts - next_fetch_offset
|
||||
end
|
||||
|
||||
function get_current_idx()
|
||||
local t = os.time()
|
||||
for i = 1, #price_data.unix_seconds do
|
||||
local ts = price_data.unix_seconds[i]
|
||||
if ts < t and t < (ts+price_interval) then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function price(i)
|
||||
return price_data.price[i]
|
||||
end
|
||||
|
||||
function get_display_price(idx)
|
||||
local mul = (1.0 + (prefs.vat_percentage / 100.0)) * unit_multiplier
|
||||
-- NOTE: float rounding in string.format doesn't work so do it here
|
||||
return math.floor(100.0 * price(idx) * mul + 0.5) / 100.0
|
||||
end
|
||||
|
||||
function get_display_time(idx)
|
||||
return os.date("%H", price_data.unix_seconds[idx])
|
||||
end
|
||||
|
||||
function format_price(idx)
|
||||
return string.format("%0.2f", get_display_price(idx))
|
||||
end
|
||||
|
||||
function format_price_and_unit(idx)
|
||||
return string.format("%s %s", format_price(idx), price_unit)
|
||||
end
|
||||
|
||||
function format_oneline(idx)
|
||||
local more_prices = ""
|
||||
local more_count = 0
|
||||
local cur_price = price(idx)
|
||||
for i = idx+1, #price_data.price do
|
||||
if price(i) > prefs.oneline_threshold_high * cur_price
|
||||
or price(i) < prefs.oneline_threshold_low * cur_price then
|
||||
more_count = more_count + 1
|
||||
more_prices = more_prices .. string.format("⋄ <i>%s′</i> <b>%s</b> ", get_display_time(i), get_display_price(i))
|
||||
cur_price = price(i)
|
||||
if more_count > 3 then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return string.format("<b>%s</b> %s", format_price_and_unit(idx), more_prices)
|
||||
end
|
||||
|
||||
-- NOTE: using timestamps would be better than indices, but the chart element
|
||||
-- doesn't support times spanning multiple days properly
|
||||
function make_chart_data(idx)
|
||||
local chart = {}
|
||||
for i = idx, #price_data.price do
|
||||
table.insert(chart, {
|
||||
i-1,
|
||||
get_display_price(i)
|
||||
})
|
||||
end
|
||||
return chart
|
||||
end
|
||||
|
||||
function draw_widget(fold)
|
||||
ui:set_folding_flag(fold)
|
||||
local idx = get_current_idx()
|
||||
if not idx then
|
||||
ui:show_text("Error: no current price data")
|
||||
-- request fetch on next on_alarm and don't redraw before that
|
||||
next_fetch_ts = 0
|
||||
next_redraw_ts = nil
|
||||
return
|
||||
end
|
||||
|
||||
next_redraw_ts = price_data.unix_seconds[idx+1]
|
||||
ui:set_title(string.format("Electricity spot price: %s", format_price_and_unit(idx)))
|
||||
ui:show_chart(make_chart_data(idx), "x: int, y: float", "", true, format_oneline(idx))
|
||||
end
|
||||
Reference in New Issue
Block a user