Put sun event offset back in; reformat

This commit is contained in:
J.D. Mallen 2022-08-22 20:30:54 -04:00
parent 5cfd36e1dc
commit 5faab8507a
No known key found for this signature in database
GPG Key ID: 91A7CC9239E54C92

View File

@ -1,216 +1,223 @@
module.exports = function (RED) {
"use strict";
var SunCalc = require('suncalc');
const spacetime = require("spacetime")
const SUNRISE_KEY = "sunrise";
const SUNSET_KEY = "sunset";
module.exports = function(RED) { function TimeswitchNode(n) {
"use strict"; RED.nodes.createNode(this, n);
var SunCalc = require('suncalc'); this.lat = n.lat;
const spacetime = require("spacetime") this.lon = n.lon;
const SUNRISE_KEY = "sunrise"; this.startt = n.starttime;
const SUNSET_KEY = "sunset"; this.endt = n.endtime;
this.sunriseOffset = n.dawnoff;
this.sunsetOffset = n.duskoff;
this.mytopic = n.mytopic;
this.timezone = n.timezone || "UTC";
function TimeswitchNode(n) { this.sun = n.sun;
RED.nodes.createNode(this, n); this.mon = n.mon;
this.lat = n.lat; this.tue = n.tue;
this.lon = n.lon; this.wed = n.wed;
this.start = n.start || "sunrise"; this.thu = n.thu;
this.end = n.end || "sunset"; this.fri = n.fri;
this.startt = n.starttime; this.sat = n.sat;
this.endt = n.endtime;
this.duskoff = n.duskoff; this.jan = n.jan;
this.dawnoff = n.dawnoff; this.feb = n.feb;
this.mytopic = n.mytopic; this.mar = n.mar;
this.timezone = n.timezone || "UTC"; 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;
this.sun = n.sun; var node = this;
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; this.on("input", function () {
var ison = 0; // current global time
var newendtime = 0; const now = spacetime.now();
const nowNative = now.toNativeDate();
this.on("input", function(msg2) { // all sun events for the given lat/long
if (msg2.payload === "reset") { ison = 0; } const sunEvents = SunCalc.getTimes(nowNative, node.lat, node.lon);
let sunriseDateTime = spacetime(sunEvents[SUNRISE_KEY]).nearest("minute");
// current global time let sunsetDateTime = spacetime(sunEvents[SUNSET_KEY]).nearest("minute");
const now = spacetime.now();
const nowNative = now.toNativeDate();
// all sun events for the given lat/long
const sunEvents = SunCalc.getTimes(nowNative, node.lat, node.lon);
let sunriseDateTime = spacetime(sunEvents[SUNRISE_KEY]).nearest("minute");
let sunsetDateTime = spacetime(sunEvents[SUNSET_KEY]).nearest("minute");
// check if sun event has already occurred today // add optional sun event offset, if specified
if (now.isAfter(sunriseDateTime)) { sunriseDateTime = sunriseDateTime.add(Number(node.sunriseOffset), "minutes");
// get tomorrow's sunrise, since it'll be different sunsetDateTime = sunsetDateTime.add(Number(node.sunsetOffset), "minutes");
sunriseDateTime = spacetime(SunCalc.getTimes(now.add(1, "day").toNativeDate(), node.lat, node.lon)[SUNRISE_KEY]).nearest("minute");
}
if (now.isAfter(sunsetDateTime)) {
// get tomorrow's sunset, since it'll be different
sunsetDateTime = spacetime(SunCalc.getTimes(now.add(1, "day").toNativeDate(), node.lat, node.lon)[SUNSET_KEY]).nearest("minute");
}
// log // check if sun event has already occurred today
if (RED.settings.verbose) { if (now.isAfter(sunriseDateTime)) {
node.log(`Sunrise ${sunriseDateTime.format("time")} - Sunset ${sunsetDateTime.format("time")} `); // get tomorrow's sunrise, since it'll be different
} sunriseDateTime = spacetime(SunCalc.getTimes(now.add(1, "day").toNativeDate(), node.lat, node.lon)[SUNRISE_KEY]).nearest("minute");
// add optional sun event offset, if specified (again)
sunriseDateTime = sunriseDateTime.add(Number(node.sunriseOffset), "minutes");
}
if (now.isAfter(sunsetDateTime)) {
// get tomorrow's sunset, since it'll be different
sunsetDateTime = spacetime(SunCalc.getTimes(now.add(1, "day").toNativeDate(), node.lat, node.lon)[SUNSET_KEY]).nearest("minute");
// add optional sun event offset, if specified (again)
sunsetDateTime = sunsetDateTime.add(Number(node.sunsetOffset), "minutes");
}
// apply selected timezone to selected times (not to sunrise/sunset-- those are based on lat/long) // log sun events
const currentTimeZone = now.timezone(); if (RED.settings.verbose) {
const selectedTimeZone = spacetime(now.epoch, this.timezone.toLowerCase()).timezone(); node.log(`Sunrise ${sunriseDateTime.format("time")} - Sunset ${sunsetDateTime.format("time")} `);
}
let getSelectedTimeFromMinuteString = minuteString => { // apply selected timezone to selected times (not to sunrise/sunset-- those are based on lat/long)
const selectedTimeInMinutesAfterMidnight = Number(minuteString); const currentTimeZone = now.timezone();
let selectedTime = spacetime.now(); const selectedTimeZone = spacetime(now.epoch, this.timezone.toLowerCase()).timezone();
// if less than 1440, what are the time values for the next start and stop time?
if (selectedTimeInMinutesAfterMidnight < 1440) {
// determine offset to get from selected time zone to current timezone
// e.g. current (EDT) is -4, selected (PDT) is -7
// to get from PDT to EDT, you must add 3
// (-4) - (-7) = +3
const offset = currentTimeZone.current.offset - selectedTimeZone.current.offset;
const selectedHourValue = Math.floor(selectedTimeInMinutesAfterMidnight / 60);
const selectedMinuteValue = Math.floor(selectedTimeInMinutesAfterMidnight % 60);
selectedTime = selectedTime.hour(selectedHourValue).minute(selectedMinuteValue).second(0).millisecond(0);
selectedTime = selectedTime.add(offset, "hours");
// select the next time if it's in the past
if(now.isAfter(selectedTime)) {
selectedTime = selectedTime.add(1, "day");
}
} else if (selectedTimeInMinutesAfterMidnight == 5000) { // sunrise
selectedTime = sunriseDateTime;
} else if (selectedTimeInMinutesAfterMidnight == 6000) { // sunset
selectedTime = sunsetDateTime;
}
return selectedTime;
};
let selectedOnTime = getSelectedTimeFromMinuteString(node.startt); // 8/22 22:45 let getSelectedTimeFromMinuteString = minuteString => {
let selectedOffTime = getSelectedTimeFromMinuteString(node.endt); // 8/23 06:31 const selectedTimeInMinutesAfterMidnight = Number(minuteString);
let selectedTime = spacetime.now();
// if less than 1440, what are the time values for the next start and stop time?
if (selectedTimeInMinutesAfterMidnight < 1440) {
// determine offset to get from selected time zone to current timezone
// e.g. current (EDT) is -4, selected (PDT) is -7
// to get from PDT to EDT, you must add 3
// (-4) - (-7) = +3
const offset = currentTimeZone.current.offset - selectedTimeZone.current.offset;
const selectedHourValue = Math.floor(selectedTimeInMinutesAfterMidnight / 60);
const selectedMinuteValue = Math.floor(selectedTimeInMinutesAfterMidnight % 60);
selectedTime = selectedTime.hour(selectedHourValue).minute(selectedMinuteValue).second(0).millisecond(0);
selectedTime = selectedTime.add(offset, "hours");
// select the next time if it's in the past
if (now.isAfter(selectedTime)) {
selectedTime = selectedTime.add(1, "day");
}
} else if (selectedTimeInMinutesAfterMidnight == 5000) { // sunrise
selectedTime = sunriseDateTime;
} else if (selectedTimeInMinutesAfterMidnight == 6000) { // sunset
selectedTime = sunsetDateTime;
}
return selectedTime;
};
// handle the "Start + X Minutes" cases let selectedOnTime = getSelectedTimeFromMinuteString(node.startt); // 8/22 22:45
if (node.endt >= 10000) { let selectedOffTime = getSelectedTimeFromMinuteString(node.endt); // 8/23 06:31
selectedOffTime = selectedOnTime.add(node.endt - 10000, "minutes");
}
// handler function for the node payload // handle the "Start + X Minutes" cases
let sendPayload = (payload, nextTime) => { if (node.endt >= 10000) {
if (payload == 1) { selectedOffTime = selectedOnTime.add(node.endt - 10000, "minutes");
node.status({ }
fill: "yellow",
shape: "dot",
text: `on until ${nextTime.format("time")}`
});
}
else {
node.status({
fill: "blue",
shape: "dot",
text: `off until ${nextTime.format("time")}`
});
}
var msg = {};
if (node.mytopic) { msg.topic = node.mytopic; }
msg.payload = payload;
node.send(msg);
};
var proceed = true; // handler function for the node payload
// if today is not among the selected days of the week, stop here let sendPayload = (payload, nextTime) => {
switch (nowNative.getDay()) { if (payload == 1) {
case 0 : { if (!node.sun) { proceed &= false; } break; } node.status({
case 1 : { if (!node.mon) { proceed &= false; } break; } fill: "yellow",
case 2 : { if (!node.tue) { proceed &= false; } break; } shape: "dot",
case 3 : { if (!node.wed) { proceed &= false; } break; } text: `on until ${nextTime.format("time")}`
case 4 : { if (!node.thu) { proceed &= false; } break; } });
case 5 : { if (!node.fri) { proceed &= false; } break; } } else {
case 6 : { if (!node.sat) { proceed &= false; } break; } node.status({
} fill: "blue",
shape: "dot",
text: `off until ${nextTime.format("time")}`
});
}
var msg = {};
if (node.mytopic) {
msg.topic = node.mytopic;
}
msg.payload = payload;
node.send(msg);
};
if (!proceed) { var proceed = true;
sendPayload(0, selectedOnTime); // if today is not among the selected days of the week, stop here
return; switch (nowNative.getDay()) {
} case 0 : { if (!node.sun) { proceed &= false; } break; }
case 1 : { if (!node.mon) { proceed &= false; } break; }
case 2 : { if (!node.tue) { proceed &= false; } break; }
case 3 : { if (!node.wed) { proceed &= false; } break; }
case 4 : { if (!node.thu) { proceed &= false; } break; }
case 5 : { if (!node.fri) { proceed &= false; } break; }
case 6 : { if (!node.sat) { proceed &= false; } break; }
}
// if this month is not among the selected months, stop here if (!proceed) {
switch (nowNative.getMonth()) { sendPayload(0, selectedOnTime);
case 0 : { if (!node.jan) { proceed &= false; } break; } return;
case 1 : { if (!node.feb) { proceed &= false; } break; } }
case 2 : { if (!node.mar) { proceed &= false; } break; }
case 3 : { if (!node.apr) { proceed &= false; } break; }
case 4 : { if (!node.may) { proceed &= false; } break; }
case 5 : { if (!node.jun) { proceed &= false; } break; }
case 6 : { if (!node.jul) { proceed &= false; } break; }
case 7 : { if (!node.aug) { proceed &= false; } break; }
case 8 : { if (!node.sep) { proceed &= false; } break; }
case 9 : { if (!node.oct) { proceed &= false; } break; }
case 10: { if (!node.nov) { proceed &= false; } break; }
case 11: { if (!node.dec) { proceed &= false; } break; }
}
if (!proceed) { // if this month is not among the selected months, stop here
sendPayload(0, selectedOnTime); switch (nowNative.getMonth()) {
return; case 0 : { if (!node.jan) { proceed &= false; } break; }
} case 1 : { if (!node.feb) { proceed &= false; } break; }
case 2 : { if (!node.mar) { proceed &= false; } break; }
case 3 : { if (!node.apr) { proceed &= false; } break; }
case 4 : { if (!node.may) { proceed &= false; } break; }
case 5 : { if (!node.jun) { proceed &= false; } break; }
case 6 : { if (!node.jul) { proceed &= false; } break; }
case 7 : { if (!node.aug) { proceed &= false; } break; }
case 8 : { if (!node.sep) { proceed &= false; } break; }
case 9 : { if (!node.oct) { proceed &= false; } break; }
case 10: { if (!node.nov) { proceed &= false; } break; }
case 11: { if (!node.dec) { proceed &= false; } break; }
}
// if the chronological order is NOW, ON, OFF, then now should be OFF if (!proceed) {
if (proceed && selectedOffTime.isAfter(selectedOnTime)) { sendPayload(0, selectedOnTime);
sendPayload(0, selectedOnTime); return;
return; }
}
// if the chronological order is NOW, OFF, ON, then now should be ON // if the chronological order is NOW, ON, OFF, then now should be OFF
if (proceed && selectedOffTime.isBefore(selectedOnTime)) { if (proceed && selectedOffTime.isAfter(selectedOnTime)) {
sendPayload(1, selectedOnTime); sendPayload(0, selectedOnTime);
return; return;
} }
});
var tock = setTimeout(function() { // if the chronological order is NOW, OFF, ON, then now should be ON
node.emit("input", {}); if (proceed && selectedOffTime.isBefore(selectedOnTime)) {
}, 2000); // wait 2 secs before starting to let things settle down e.g. UI connect sendPayload(1, selectedOffTime);
return;
}
});
var tick = setInterval(function() { var tock = setTimeout(function () {
node.emit("input", {}); node.emit("input", {});
}, 60000); // trigger every 60 secs }, 2000); // wait 2 secs before starting to let things settle down e.g. UI connect
this.on("close", function() { var tick = setInterval(function () {
if (tock) { clearTimeout(tock); } node.emit("input", {});
if (tick) { clearInterval(tick); } }, 60000); // trigger every 60 secs
});
}
RED.httpAdmin.post("/timeswitch/:id", RED.auth.needsPermission("timeswitch.write"), function(req, res) { this.on("close", function () {
var node = RED.nodes.getNode(req.params.id); if (tock) {
if (node != null) { clearTimeout(tock);
try { }
node.emit("input", {payload:"reset"}); if (tick) {
res.sendStatus(200); clearInterval(tick);
} }
catch (err) { });
res.sendStatus(500); }
node.error("Inject failed:" + err);
}
}
else {
res.sendStatus(404);
}
});
RED.nodes.registerType("timeswitch", TimeswitchNode); 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);
}; };