From 29e0bed000c172faf0c13b3a1116930b1931d206 Mon Sep 17 00:00:00 2001 From: "J.D. Mallen" Date: Tue, 23 Aug 2022 09:31:18 -0400 Subject: [PATCH] Address incorrect timestamps bug in node-red-node-timeswitch; increase readability (#945) * Initial fixes before testing and reformatting * Put sun event offset back in; reformat * Tabs to spaces * Fix "Start+X" OFF time; add more comments * Undo some formatting changes * Add contributors to package.json --- time/timeswitch/package.json | 14 +- time/timeswitch/timeswitch.js | 237 ++++++++++++++++++++++------------ 2 files changed, 169 insertions(+), 82 deletions(-) diff --git a/time/timeswitch/package.json b/time/timeswitch/package.json index 5bc07d1d..b7b81098 100644 --- a/time/timeswitch/package.json +++ b/time/timeswitch/package.json @@ -25,7 +25,19 @@ }, "contributors": [ { - "name": "@pmacostapdi" + "name": "@dceejay" + }, + { + "name": "@pmacostapdi" + }, + { + "name": "@heikokue" + }, + { + "name": "@sammachin" + }, + { + "name": "@jdmallen" } ] } diff --git a/time/timeswitch/timeswitch.js b/time/timeswitch/timeswitch.js index 28adb4f6..3048f378 100644 --- a/time/timeswitch/timeswitch.js +++ b/time/timeswitch/timeswitch.js @@ -1,19 +1,18 @@ - -module.exports = function(RED) { +module.exports = function (RED) { "use strict"; var SunCalc = require('suncalc'); const spacetime = require("spacetime") + const SUNRISE_KEY = "sunrise"; + const SUNSET_KEY = "sunset"; 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.sunriseOffset = n.dawnoff; + this.sunsetOffset = n.duskoff; this.mytopic = n.mytopic; this.timezone = n.timezone || "UTC"; @@ -24,6 +23,7 @@ module.exports = function(RED) { this.thu = n.thu; this.fri = n.fri; this.sat = n.sat; + this.jan = n.jan; this.feb = n.feb; this.mar = n.mar; @@ -38,117 +38,192 @@ module.exports = function(RED) { this.dec = n.dec; var node = this; - var ison = 0; - var newendtime = 0; - this.on("input", function(msg2) { - if (msg2.payload === "reset") { ison = 0; } + this.on("input", function () { + // current global time + const now = spacetime.now(); + const nowNative = now.toNativeDate(); - 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); - var tzOff = (new Date()).getTimezoneOffset(); + // 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"); - 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); } + // add optional sun event offset, if specified + sunriseDateTime = sunriseDateTime.add(Number(node.sunriseOffset), "minutes"); + sunsetDateTime = sunsetDateTime.add(Number(node.sunsetOffset), "minutes"); + + // check if sun event has already occurred today + if (now.isAfter(sunriseDateTime)) { + // 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"); } - 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; } + // log sun events + if (RED.settings.verbose) { + node.log(`Sunrise ${sunriseDateTime.format("time")} - Sunset ${sunsetDateTime.format("time")} `); } - 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; } + // apply selected timezone to selected times (not to sunrise/sunset-- those are based on lat/long) + const currentTimeZone = now.timezone(); + const selectedTimeZone = spacetime(now.epoch, this.timezone.toLowerCase()).timezone(); + + // handler function to convert minute strings (from