node-red-contrib-power-saver
Version:
A module for Node-RED that you can use to turn on and off a switch based on power prices
85 lines (76 loc) • 2.82 kB
JavaScript
const {
booleanConfig,
calcNullSavings,
fixOutputValues,
fixPeriods,
getSavings,
saveOriginalConfig,
} = require("./utils");
const { strategyOnInput } = require("./strategy-functions");
const { DateTime } = require("luxon");
const cloneDeep = require("lodash.clonedeep");
module.exports = function (RED) {
function StrategyFixedScheduleNode(config) {
RED.nodes.createNode(this, config);
const node = this;
node.status({});
const validConfig = {
periods: config.periods || [],
validFrom: config.validFrom,
validTo: config.validTo,
days: config.days || { Mon: true, Tue: true, Wed: true, Thu: true, Fri: true, Sat: true, Sun: true },
contextStorage: config.contextStorage || "default",
outputIfNoSchedule: booleanConfig(config.outputIfNoSchedule),
outputValueForOn: config.outputValueForOn || true,
outputValueForOff: config.outputValueForOff || false,
outputValueForOntype: config.outputValueForOntype || "bool",
outputValueForOfftype: config.outputValueForOfftype || "bool",
override: "auto",
sendCurrentValueWhenRescheduling: config.sendCurrentValueWhenRescheduling,
};
fixOutputValues(validConfig);
fixPeriods(validConfig);
saveOriginalConfig(node, validConfig);
node.on("close", function () {
clearTimeout(node.schedulingTimeout);
});
node.on("input", function (msg) {
strategyOnInput(node, msg, doPlanning, calcNullSavings);
});
}
RED.nodes.registerType("ps-strategy-fixed-schedule", StrategyFixedScheduleNode);
};
function doPlanning(node, priceData) {
const startTimes = priceData.map((pd) => pd.start);
const onOff = startTimes.map(() => node.outputIfNoSchedule);
const allHours = buildAllHours(node, node.periods);
const validFrom = DateTime.fromISO(node.validFrom || startTimes[0].substr(0, 10));
const validTo = DateTime.fromISO(node.validTo || startTimes[startTimes.length - 1].substr(0, 10));
startTimes.forEach((st, i) => {
const date = DateTime.fromISO(st.substr(0, 10));
const hour = DateTime.fromISO(st).hour;
const day = DateTime.fromISO(st).weekday;
const dayName = Object.keys(node.days)[day - 1];
if (date >= validFrom && date <= validTo && node.days[dayName]) {
onOff[i] = allHours[hour];
}
});
return onOff;
}
function buildAllHours(node, periods) {
const sortedPeriods = cloneDeep(periods);
sortedPeriods.sort((a, b) => a.start - b.start);
let res = [];
let hour = 0;
let current = sortedPeriods[sortedPeriods.length - 1];
sortedPeriods.push({ start: 24, value: null });
sortedPeriods.forEach((period) => {
const nextHour = parseInt(period.start);
while (hour < nextHour) {
res[hour] = current.value;
hour++;
}
current = period;
});
return res;
}