nordpool-ifttt
Version:
Check Nordpool energy prices and set IFTTT triggers based on your limits
158 lines (147 loc) • 5.65 kB
JavaScript
import schedule from 'node-schedule';
import {Prices} from 'nordpool'
import moment from 'moment-timezone';
import {config} from './config.js';
import findStreak from 'findstreak';
import request from 'request';
const prices = new Prices()
const lowEvent = 'nordpool_price_low';
const normEvent = 'nordpool_price_normal';
const highEvent = 'nordpool_price_high';
const iftttUrl = 'https://maker.ifttt.com/trigger/';
let myTZ = moment.tz.guess();
let jobs = [];
if (config.debugLevel > 1) console.log(`Config:\n${JSON.stringify(config, null, 1)}`);
// get latest prices immediately
getPrices('today');
// Prices for tomorrow are published today at 12:42 CET or later
// (http://www.nordpoolspot.com/How-does-it-work/Day-ahead-market-Elspot-/)
// update prices at 13:00 UTC
let cronPattern = moment.tz('13:00Z', 'HH:mm:Z', myTZ).format('m H * * *');
// cronPattern = '* */12 * * *';
// console.log(cronPattern);
let getPricesJob = schedule.scheduleJob(cronPattern, getPrices.bind(null, 'tomorrow'));
async function getPrices(dayName) {
const date = moment(new Date());
if (config.debugLevel > 0) console.log(`${date.format()}: Getting prices for ${dayName}`);
if (dayName == 'tomorrow') {
date.add(1, 'day');
}
try {
const opts = {
area: config.area,
currency: config.currency,
date: date
};
if (config.debugLevel > 3) console.log(`opts:\n${JSON.stringify(opts, null, 1)}`);
const results = await prices.hourly(opts);
if (config.debugLevel > 2) console.log(`results:\n${JSON.stringify(results, null, 1)}`);
let events = [];
let tmpHours = [];
let previousEvent = normEvent;
results.forEach((item, index) => {
item.date = moment(item.date).tz(myTZ);
if (config.vatPercent) {
item.value = item.value * (100 + config.vatPercent) / 100;
}
item.value = Math.round(item.value * 100)/1000; // Eur/MWh to cents/kWh
if (item.value > config.highTreshold) {
if (config.debugLevel > 1) console.log(`${item.date}: ${item.value} > ${config.highTreshold}`);
item.event = highEvent;
}
else if (item.value < config.lowTreshold) {
if (config.debugLevel > 1) console.log(`${item.date}: ${item.value} < ${config.lowTreshold}`);
item.event = lowEvent;
}
else {
if (config.debugLevel > 1) console.log(`${item.date}: ${config.lowTreshold} < ${item.value} < ${config.highTreshold}`);
item.event = normEvent;
}
// treshold crossed; let's see what we have stored...
if (item.event != previousEvent) {
var max = 24;
var lo = false;
if (previousEvent == highEvent) {
max = config.maxHighHours;
}
else if (previousEvent == lowEvent) {
max = config.maxLowHours;
var lo = true;
}
let rf = (a, b) => a + b.value;
// stored values exist
if (tmpHours.length > 0) {
// find correct number of hours
let streak = findStreak(tmpHours, max, rf, lo);
if (config.debugLevel > 3) console.log(`streak:\n${JSON.stringify(streak, null, 1)}`);
// no events for the first normal streak
if ((events.length > 0) || (previousEvent != normEvent)) {
// create an event from the first hour in the streak
events.push(streak[0]);
}
// if only some of the stored hours were included in the streak,
// mark the rest of the hours as normal and trigger events
if ((previousEvent != normEvent) && (streak.length < tmpHours.length)) {
let firstIndex = streak[0].date.get('hours') - tmpHours[0].date.get('hours');
let lastIndex = firstIndex + streak.length;
// hours were clipped from the beginning of stored hours
if (firstIndex > 0) {
tmpHours[0].event = normEvent;
events.push(tmpHours[0]);
}
// hours were clipped from the end of stored hours
if (tmpHours.length > lastIndex) {
tmpHours[lastIndex].event = normEvent;
events.push(tmpHours[lastIndex]);
}
}
// last hour in the Nordpool results
else if (index == results.length - 1) {
events.push(item);
}
}
else {
// events.push(item);
}
// start a new treshold interval
previousEvent = item.event;
tmpHours = [];
}
// last hour in the Nordpool results, create event at the first stored hour
else if (index == results.length - 1) {
events.push(tmpHours[0]);
}
// store all items in the current treshold interval
tmpHours.push(item);
});
if (config.debugLevel > 2) console.log(`events:\n${JSON.stringify(events, null, 1)}`);
events.forEach(item => {
jobs.push(schedule.scheduleJob(item.date.toDate(), trigger.bind(null, item)));
if (config.debugLevel > 0) console.log(item.date.format('D.M. H:mm'), item.value, item.event);
});
}
catch (error) {
throw new Error(error);
return;
}
}
function trigger(item) {
let values = {
value1: item.value.toFixed(3),
value2: config.currencySubUnit + '/kWh',
value3: item.date.format('H:mm')
};
var opts = {
url: iftttUrl + item.event + '/with/key/' + config.iftttKey,
json: true,
body: values
};
console.log('Triggering ' + item.event + ' event: ' + JSON.stringify(values));
request.post(opts, function(err, res) {
if (err) {
console.error(err);
return;
}
console.log('Success: ' + res.body)
})
}