1
0
mirror of https://github.com/node-red/node-red-nodes.git synced 2023-10-10 13:36:58 +02:00
node-red-nodes/time/timeswitch/timeswitch.js
Pablo Acosta-Serafini d69da74843
timeswitch node: time zone support; do not mark as misconfigured when sunrise/sunset not used and lat/lon not given (#757)
* timeswitch node: a) do not mark node as misconfigured if sunrise and
sunset are not used and latitude/longitude are not given. b) support for
specifying time zone when on and/or off times are not specified as
sunrise and/or sunset.

* Replaced moment dependency with spacetime

* Timezone defaults to UTC for compatibility with previous node version
2021-02-26 14:38:28 +00:00

159 lines
6.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

module.exports = function(RED) {
"use strict";
var SunCalc = require('suncalc');
const spacetime = require("spacetime")
function TimeswitchNode(n) {
RED.nodes.createNode(this, n);
this.lat = n.lat;
this.lon = n.lon;
this.start = n.start || "sunrise";
this.end = n.end || "sunset";
this.startt = n.starttime;
this.endt = n.endtime;
this.duskoff = n.duskoff;
this.dawnoff = n.dawnoff;
this.mytopic = n.mytopic;
this.timezone = n.timezone || "UTC";
this.sun = n.sun;
this.mon = n.mon;
this.tue = n.tue;
this.wed = n.wed;
this.thu = n.thu;
this.fri = n.fri;
this.sat = n.sat;
this.jan = n.jan;
this.feb = n.feb;
this.mar = n.mar;
this.apr = n.apr;
this.may = n.may;
this.jun = n.jun;
this.jul = n.jul;
this.aug = n.aug;
this.sep = n.sep;
this.oct = n.oct;
this.nov = n.nov;
this.dec = n.dec;
var node = this;
var ison = 0;
var newendtime = 0;
this.on("input", function(msg2) {
if (msg2.payload === "reset") { ison = 0; }
var timeOffset = spacetime(Date.now()).goto(this.timezone.toLowerCase()).timezone().current.offset * 60 * 60 * 1000;
var now = new Date(Date.now() + timeOffset);
var nowMillis = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes(), 0);
var midnightMillis = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), 0, 0);
var today = Math.round((nowMillis - midnightMillis) / 60000) % 1440;
var starttime = Number(node.startt);
var endtime = Number(node.endt);
if ((starttime >= 5000) || (endtime == 5000) || (endtime == 6000)) {
var times = SunCalc.getTimes(now, node.lat, node.lon);
var startMillis = Date.UTC(times[node.start].getUTCFullYear(), times[node.start].getUTCMonth(), times[node.start].getUTCDate(), times[node.start].getUTCHours(), times[node.start].getUTCMinutes());
var endMillis = Date.UTC(times[node.end].getUTCFullYear(), times[node.end].getUTCMonth(), times[node.end].getUTCDate(), times[node.end].getUTCHours(), times[node.end].getUTCMinutes());
var dawn = ((startMillis - midnightMillis) / 60000) + Number(node.dawnoff);
var dusk = ((endMillis - midnightMillis) / 60000) + Number(node.duskoff);
if (starttime == 5000) { starttime = dawn; }
if (starttime == 6000) { starttime = dusk; }
if (endtime == 5000) { endtime = dawn; }
if (endtime == 6000) { endtime = dusk; }
if (RED.settings.verbose) { node.log("Dawn " + parseInt(dawn / 60) + ":" + dawn % 60 + " - Dusk " + parseInt(dusk / 60) + ":" + dusk % 60); }
}
var proceed = 0;
switch (now.getDay()) {
case 0 : { if (node.sun) { proceed++; } break; }
case 1 : { if (node.mon) { proceed++; } break; }
case 2 : { if (node.tue) { proceed++; } break; }
case 3 : { if (node.wed) { proceed++; } break; }
case 4 : { if (node.thu) { proceed++; } break; }
case 5 : { if (node.fri) { proceed++; } break; }
case 6 : { if (node.sat) { proceed++; } break; }
}
if (proceed) {
switch (now.getMonth()) {
case 0 : { if (node.jan) { proceed++; } break; }
case 1 : { if (node.feb) { proceed++; } break; }
case 2 : { if (node.mar) { proceed++; } break; }
case 3 : { if (node.apr) { proceed++; } break; }
case 4 : { if (node.may) { proceed++; } break; }
case 5 : { if (node.jun) { proceed++; } break; }
case 6 : { if (node.jul) { proceed++; } break; }
case 7 : { if (node.aug) { proceed++; } break; }
case 8 : { if (node.sep) { proceed++; } break; }
case 9 : { if (node.oct) { proceed++; } break; }
case 10: { if (node.nov) { proceed++; } break; }
case 11: { if (node.dec) { proceed++; } break; }
}
}
if (proceed >= 2) { proceed = 1; }
else { proceed = 0; }
newendtime = endtime;
if (endtime > 10000) { newendtime = starttime + (endtime - 10000); }
if (proceed) { // have to handle midnight wrap
if (starttime <= newendtime) {
if ((today >= starttime) && (today <= newendtime)) { proceed++; }
}
else {
if ((today >= starttime) || (today <= newendtime)) { proceed++; }
}
}
if (proceed >= 2) {
var duration = newendtime - today;
if (today > newendtime) { duration += 1440; }
//node.status({fill:"yellow",shape:"dot",text:"on for " + duration + " mins"});
node.status({fill:"yellow", shape:"dot", text:"on until " + parseInt(newendtime / 60) + ":" + ("0" + newendtime % 60).substr(-2)});
}
//else { node.status({fill:"blue",shape:"dot",text:"off"}); }
else { node.status({fill:"blue", shape:"dot", text:"off until " + parseInt(starttime / 60) + ":" + ("0" + starttime % 60).substr(-2)}); }
var msg = {};
if (node.mytopic) { msg.topic = node.mytopic; }
msg.payload = (proceed >= 2) ? 1 : 0;
node.send(msg);
});
var tock = setTimeout(function() {
node.emit("input", {});
}, 2000); // wait 2 secs before starting to let things settle down e.g. UI connect
var tick = setInterval(function() {
node.emit("input", {});
}, 60000); // trigger every 60 secs
this.on("close", function() {
if (tock) { clearTimeout(tock); }
if (tick) { clearInterval(tick); }
});
}
RED.httpAdmin.post("/timeswitch/:id", RED.auth.needsPermission("timeswitch.write"), function(req, res) {
var node = RED.nodes.getNode(req.params.id);
if (node != null) {
try {
node.emit("input", {payload:"reset"});
res.sendStatus(200);
}
catch (err) {
res.sendStatus(500);
node.error("Inject failed:" + err);
}
}
else {
res.sendStatus(404);
}
});
RED.nodes.registerType("timeswitch", TimeswitchNode);
};