node-red-contrib-sun-position
Advanced tools
Comparing version 0.1.16 to 0.2.0-alpha.2
@@ -7,3 +7,3 @@ /* | ||
'use strict'; | ||
const util = require('util'); | ||
const util = require('util'); // eslint-disable-line no-unused-vars | ||
@@ -15,11 +15,18 @@ (function () { | ||
var PI = Math.PI, | ||
sin = Math.sin, | ||
cos = Math.cos, | ||
tan = Math.tan, | ||
asin = Math.asin, | ||
atan = Math.atan2, | ||
acos = Math.acos, | ||
rad = PI / 180; | ||
const PI = Math.PI; | ||
const sin = Math.sin; | ||
const cos = Math.cos; | ||
const tan = Math.tan; | ||
const asin = Math.asin; | ||
const atan = Math.atan2; | ||
const acos = Math.acos; | ||
const rad = PI / 180; | ||
// sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas | ||
@@ -29,6 +36,8 @@ | ||
var dayMs = 1000 * 60 * 60 * 24, | ||
J1970 = 2440588, | ||
J2000 = 2451545; | ||
const dayMs = 1000 * 60 * 60 * 24; | ||
const J1970 = 2440588; | ||
const J2000 = 2451545; | ||
function toJulian(date) { | ||
@@ -48,3 +57,3 @@ return date.valueOf() / dayMs - 0.5 + J1970; | ||
var e = rad * 23.4397; // obliquity of the Earth | ||
const e = rad * 23.4397; // obliquity of the Earth | ||
@@ -72,4 +81,5 @@ function rightAscension(l, b) { | ||
function astroRefraction(h) { | ||
if (h < 0) // the following formula works for positive altitudes only. | ||
h = 0; // if h = -0.08901179 a div/0 would occur. | ||
if (h < 0) { // the following formula works for positive altitudes only. | ||
h = 0; | ||
} // if h = -0.08901179 a div/0 would occur. | ||
@@ -88,5 +98,6 @@ // formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. | ||
function eclipticLongitude(M) { | ||
const C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)); | ||
// equation of center | ||
let C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center | ||
P = rad * 102.9372; // perihelion of the Earth | ||
const P = rad * 102.9372; // perihelion of the Earth | ||
@@ -97,5 +108,5 @@ return M + C + P + PI; | ||
function sunCoords(d) { | ||
const M = solarMeanAnomaly(d); | ||
let M = solarMeanAnomaly(d), | ||
L = eclipticLongitude(M); | ||
const L = eclipticLongitude(M); | ||
@@ -108,3 +119,3 @@ return { | ||
var SunCalc = {}; | ||
const SunCalc = {}; | ||
@@ -114,10 +125,19 @@ // calculates sun position for a given date and latitude/longitude | ||
SunCalc.getPosition = function (date, lat, lng) { | ||
if (isNaN(lat)) { | ||
throw new Error('latitude missing'); | ||
} | ||
if (isNaN(lng)) { | ||
throw new Error('longitude missing'); | ||
} | ||
let lw = rad * -lng, | ||
phi = rad * lat, | ||
d = toDays(date), | ||
const lw = rad * -lng; | ||
c = sunCoords(d), | ||
H = siderealTime(d, lw) - c.ra; | ||
const phi = rad * lat; | ||
const d = toDays(date); | ||
const c = sunCoords(d); | ||
const H = siderealTime(d, lw) - c.ra; | ||
return { | ||
@@ -130,3 +150,3 @@ azimuth: azimuth(H, phi, c.dec), | ||
// sun times configuration (angle, morning name, evening name) | ||
var sunTimes = SunCalc.times = [ | ||
const sunTimes = SunCalc.times = [ | ||
[6, 'goldenHourEnd', 'goldenHourStart', 9, 11], // GOLDEN_HOUR_AM | ||
@@ -142,8 +162,8 @@ [-0.3, 'sunriseEnd', 'sunsetStart', 8, 12], // SUNRISE_END | ||
]; | ||
var sunTimesDefault = SunCalc.timesDefault = { | ||
const sunTimesDefault = SunCalc.timesDefault = { | ||
solarNoon: 10, | ||
nadir: 0 | ||
}; | ||
var sunTimesAlternate = SunCalc.timesAlternate = [ | ||
// for backward compatibilit | ||
const sunTimesAlternate = SunCalc.timesAlternate = [ | ||
// for backward compatibility | ||
['dawn', 'civilDawn'], | ||
@@ -164,3 +184,3 @@ ['dusk', 'civilDusk'], | ||
var J0 = 0.0009; | ||
const J0 = 0.0009; | ||
@@ -185,5 +205,5 @@ function julianCycle(d, lw) { | ||
function getSetJ(h, lw, phi, dec, n, M, L) { | ||
const w = hourAngle(h, phi, dec); | ||
let w = hourAngle(h, phi, dec), | ||
a = approxTransit(w, lw, n); | ||
const a = approxTransit(w, lw, n); | ||
return solarTransitJ(a, M, L); | ||
@@ -195,17 +215,21 @@ } | ||
SunCalc.getTimes = function (date, lat, lng) { | ||
if (isNaN(lat)) { | ||
throw new Error('latitude missing'); | ||
} | ||
if (isNaN(lng)) { | ||
throw new Error('longitude missing'); | ||
} | ||
let lw = rad * -lng, | ||
phi = rad * lat, | ||
const lw = rad * -lng; | ||
const phi = rad * lat; | ||
d = toDays(date), | ||
n = julianCycle(d, lw), | ||
ds = approxTransit(0, lw, n), | ||
const d = toDays(date); | ||
const n = julianCycle(d, lw); | ||
const ds = approxTransit(0, lw, n); | ||
const M = solarMeanAnomaly(ds); | ||
const L = eclipticLongitude(M); | ||
const dec = declination(L, 0); | ||
const Jnoon = solarTransitJ(ds, M, L); | ||
M = solarMeanAnomaly(ds), | ||
L = eclipticLongitude(M), | ||
dec = declination(L, 0), | ||
Jnoon = solarTransitJ(ds, M, L); | ||
let result = { | ||
const result = { | ||
solarNoon: { | ||
@@ -227,6 +251,6 @@ value: fromJulian(Jnoon), | ||
for (let i = 0, len = sunTimes.length; i < len; i += 1) { | ||
let time = sunTimes[i]; | ||
const time = sunTimes[i]; | ||
let Jset = getSetJ(time[0] * rad, lw, phi, dec, n, M, L); | ||
let Jrise = Jnoon - (Jset - Jnoon); | ||
const Jset = getSetJ(time[0] * rad, lw, phi, dec, n, M, L); | ||
const Jrise = Jnoon - (Jset - Jnoon); | ||
@@ -248,8 +272,9 @@ result[time[2]] = { | ||
} | ||
// for backward compatibilit | ||
// for backward compatibility | ||
for (let i = 0, len = sunTimesAlternate.length; i < len; i += 1) { | ||
let time = sunTimesAlternate[i]; | ||
const time = sunTimesAlternate[i]; | ||
result[time[0]] = result[time[1]]; | ||
} | ||
//console.log(util.inspect(result)); | ||
// console.log(util.inspect(result)); | ||
@@ -262,11 +287,19 @@ return result; | ||
function moonCoords(d) { // geocentric ecliptic coordinates of the moon | ||
const L = rad * (218.316 + 13.176396 * d); | ||
// ecliptic longitude | ||
let L = rad * (218.316 + 13.176396 * d), // ecliptic longitude | ||
M = rad * (134.963 + 13.064993 * d), // mean anomaly | ||
F = rad * (93.272 + 13.229350 * d), // mean distance | ||
const M = rad * (134.963 + 13.064993 * d); | ||
// mean anomaly | ||
l = L + rad * 6.289 * sin(M), // longitude | ||
b = rad * 5.128 * sin(F), // latitude | ||
dt = 385001 - 20905 * cos(M); // distance to the moon in km | ||
const F = rad * (93.272 + 13.229350 * d); | ||
// mean distance | ||
const l = L + rad * 6.289 * sin(M); | ||
// longitude | ||
const b = rad * 5.128 * sin(F); | ||
// latitude | ||
const dt = 385001 - 20905 * cos(M); // distance to the moon in km | ||
return { | ||
@@ -280,15 +313,13 @@ ra: rightAscension(l, b), | ||
SunCalc.getMoonPosition = function (date, lat, lng) { | ||
const lw = rad * -lng; | ||
const phi = rad * lat; | ||
const d = toDays(date); | ||
const c = moonCoords(d); | ||
const H = siderealTime(d, lw) - c.ra; | ||
let h = altitude(H, phi, c.dec); | ||
// formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. | ||
const pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H)); | ||
let lw = rad * -lng, | ||
phi = rad * lat, | ||
d = toDays(date), | ||
h += astroRefraction(h); // altitude correction for refraction | ||
c = moonCoords(d), | ||
H = siderealTime(d, lw) - c.ra, | ||
h = altitude(H, phi, c.dec), | ||
// formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. | ||
pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H)); | ||
h = h + astroRefraction(h); // altitude correction for refraction | ||
return { | ||
@@ -302,3 +333,2 @@ azimuth: azimuth(H, phi, c.dec), | ||
// calculations for illumination parameters of the moon, | ||
@@ -309,12 +339,16 @@ // based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and | ||
SunCalc.getMoonIllumination = function (date) { | ||
const d = toDays(date || new Date()); | ||
let d = toDays(date || new Date()), | ||
s = sunCoords(d), | ||
m = moonCoords(d), | ||
const s = sunCoords(d); | ||
sdist = 149598000, // distance from Earth to Sun in km | ||
const m = moonCoords(d); | ||
phi = acos(sin(s.dec) * sin(m.dec) + cos(s.dec) * cos(m.dec) * cos(s.ra - m.ra)), | ||
inc = atan(sdist * sin(phi), m.dist - sdist * cos(phi)), | ||
angle = atan(cos(s.dec) * sin(s.ra - m.ra), sin(s.dec) * cos(m.dec) - | ||
const sdist = 149598000; | ||
// distance from Earth to Sun in km | ||
const phi = acos(sin(s.dec) * sin(m.dec) + cos(s.dec) * cos(m.dec) * cos(s.ra - m.ra)); | ||
const inc = atan(sdist * sin(phi), m.dist - sdist * cos(phi)); | ||
const angle = atan(cos(s.dec) * sin(s.ra - m.ra), sin(s.dec) * cos(m.dec) - | ||
cos(s.dec) * sin(m.dec) * cos(s.ra - m.ra)); | ||
@@ -325,7 +359,6 @@ | ||
phase: 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI, | ||
angle: angle | ||
angle | ||
}; | ||
}; | ||
function hoursLater(date, h) { | ||
@@ -338,18 +371,21 @@ return new Date(date.valueOf() + h * dayMs / 24); | ||
SunCalc.getMoonTimes = function (date, lat, lng, inUTC) { | ||
let t = new Date(date); | ||
if (inUTC) t.setUTCHours(0, 0, 0, 0); | ||
else t.setHours(0, 0, 0, 0); | ||
const t = new Date(date); | ||
if (inUTC) { | ||
t.setUTCHours(0, 0, 0, 0); | ||
} else { | ||
t.setHours(0, 0, 0, 0); | ||
} | ||
let hc = 0.133 * rad, | ||
h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc, | ||
h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx; | ||
const hc = 0.133 * rad; | ||
let h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc; | ||
let rise; let set; let ye; let d; let roots; let x1; let x2; let dx; | ||
// go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set) | ||
for (let i = 1; i <= 24; i += 2) { | ||
h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc; | ||
h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc; | ||
const h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc; | ||
const h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc; | ||
a = (h0 + h2) / 2 - h1; | ||
b = (h2 - h0) / 2; | ||
xe = -b / (2 * a); | ||
const a = (h0 + h2) / 2 - h1; | ||
const b = (h2 - h0) / 2; | ||
const xe = -b / (2 * a); | ||
ye = (a * xe + b) * xe + h1; | ||
@@ -363,11 +399,21 @@ d = b * b - 4 * a * h1; | ||
x2 = xe + dx; | ||
if (Math.abs(x1) <= 1) roots++; | ||
if (Math.abs(x2) <= 1) roots++; | ||
if (x1 < -1) x1 = x2; | ||
if (Math.abs(x1) <= 1) { | ||
roots++; | ||
} | ||
if (Math.abs(x2) <= 1) { | ||
roots++; | ||
} | ||
if (x1 < -1) { | ||
x1 = x2; | ||
} | ||
} | ||
if (roots === 1) { | ||
if (h0 < 0) rise = i + x1; | ||
else set = i + x1; | ||
if (h0 < 0) { | ||
rise = i + x1; | ||
} else { | ||
set = i + x1; | ||
} | ||
} else if (roots === 2) { | ||
@@ -378,3 +424,5 @@ rise = i + (ye < 0 ? x2 : x1); | ||
if (rise && set) break; | ||
if (rise && set) { | ||
break; | ||
} | ||
@@ -384,18 +432,20 @@ h0 = h2; | ||
let result = {}; | ||
const result = {}; | ||
if (rise) result.rise = hoursLater(t, rise); | ||
if (set) result.set = hoursLater(t, set); | ||
if (rise) { | ||
result.rise = hoursLater(t, rise); | ||
} | ||
if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true; | ||
if (set) { | ||
result.set = hoursLater(t, set); | ||
} | ||
if (!rise && !set) { | ||
result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true; | ||
} | ||
return result; | ||
}; | ||
// export as Node module / AMD module / browser variable | ||
if (typeof exports === 'object' && typeof module !== 'undefined') module.exports = SunCalc; | ||
else if (typeof define === 'function' && define.amd) define(SunCalc); | ||
else window.SunCalc = SunCalc; | ||
}()); | ||
module.exports = SunCalc; | ||
})(); |
@@ -15,5 +15,5 @@ { | ||
"tips": { | ||
"moonPosControl" : "If a message arrives through the Input the calculated position of the moon will be always send to the first output. If additionally specifyd upper and lower limits for the moon radiation and the azimuth is inside the defined limits the incomming message will send to the associated output." | ||
"moonPosControl" : "If a message arrives through the Input the calculated position of the moon will be always send to the first output. If additionally specified upper and lower limits for the moon radiation and the azimuth is inside the defined limits the incoming message will send to the associated output." | ||
} | ||
} | ||
} |
@@ -40,2 +40,3 @@ { | ||
"tips": { | ||
"config": "Starting from Version 2.0 the coordinates are not saved as credentials due to privacy reasons. So they no longer part of the regular flow and will not part of the export! On an update from previous version a save and re-deploy is necessary.", | ||
"sunPosControl": "Here you can specify the upper and lower limits for the solar radiation so that you can evaluate the sunshine on 4 sides of an object." | ||
@@ -45,3 +46,3 @@ }, | ||
"error": "<strong>Error</strong>: __message__", | ||
"error-text": "Exception occured on position-configuration", | ||
"error-text": "Exception occurred on position-configuration", | ||
"error-title": "internal error", | ||
@@ -48,0 +49,0 @@ "unexpected": "unexpected error (__status__) __message__", |
@@ -15,5 +15,5 @@ { | ||
"tips": { | ||
"sunPosControl" : "If a message arrives through the Input the calculated position of the sun will be always send to the first output. If additionally specifyd upper and lower limits for the solar radiation and the azimuth is inside the defined limits the incomming message will send to the associated output." | ||
"sunPosControl" : "If a message arrives through the Input the calculated position of the sun will be always send to the first output. If additionally specified upper and lower limits for the solar radiation and the azimuth is inside the defined limits the incoming message will send to the associated output." | ||
} | ||
} | ||
} |
@@ -13,2 +13,11 @@ { | ||
"timeAltoffset": "Offset", | ||
"addPayload1": "set", | ||
"addPayload2": "(2) set", | ||
"addPayload3": "(3) set", | ||
"addPayload1Value": "value", | ||
"addPayload2Value": "value", | ||
"addPayload3Value": "value", | ||
"addPayload1Format": "time format", | ||
"addPayload2Format": "time format", | ||
"addPayload3Format": "time format", | ||
"recalcTime": "Neuber.", | ||
@@ -20,6 +29,27 @@ "payload": "Payload", | ||
"hours": "Stunden", | ||
"timeformat": "time format", | ||
"timeformat_UNIX": "number - milliseconds UNIX timestamp", | ||
"timeformat_ECMA262": "string - ECMA-262", | ||
"timeformat_local": "string - local date and time", | ||
"timeformat_localLong": "string - local date and time ex.", | ||
"timeformat_localTime": "string - local time", | ||
"timeformat_localTimeLong": "string - local time ex.", | ||
"timeformat_localDate": "string - local date", | ||
"timeformat_localDateLong": "string - local date long", | ||
"timeformat_UTC": "string - UTC date and time", | ||
"timeformat_ISO": "string - ISO date and time", | ||
"timeformat_ms": "number - milliseconds since emit", | ||
"timeformat_sec": "number - seconds since emit", | ||
"timeformat_min": "number - minutes since emit", | ||
"timeformat_hour": "number - hour since emit", | ||
"timeformat_YYYYMMDDHHMMSS": "string - YYYYMMDDHHMMSS", | ||
"timeformat_YYYYMMDD_HHMMSS": "string - YYYYMMDD.HHMMSS", | ||
"timeformat_obj": "as object", | ||
"timeformat_other": "string - Other - free format", | ||
"timeformat_weekday": "string - day of week, e.g. Monday, 22.12.", | ||
"timeformat_weekday2": "string - day of week, e.g. Today, 22.12.", | ||
"on": "nur", | ||
"none": "nichts", | ||
"stopped": "gestoppt", | ||
"timestamp": "Zeitstempel", | ||
"timestamp": "Zeit Stempel", | ||
"binary": "binary", | ||
@@ -45,10 +75,12 @@ "json": "json", | ||
"days": [ | ||
"Montag", | ||
"Dienstag", | ||
"Mittwoch", | ||
"Donnerstag", | ||
"Freitag", | ||
"Sonnabend", | ||
"Sonntag" | ||
"Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Sonnabend", "Sonntag", | ||
"Mo", "Di", "Mi", "Do", "Fr", "Sa", "So" | ||
], | ||
"month": [ | ||
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", | ||
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" | ||
], | ||
"dayDiffNames": [ | ||
"Yesterday", "Today", "Tomorrow", "day after tomorrow" | ||
], | ||
"placeholder": { | ||
@@ -64,14 +96,29 @@ "position": "Position", | ||
"time": "18:15", | ||
"Offset": "0", | ||
"offset": "0", | ||
"timeAlt": "18:15", | ||
"timeAltOffset": "0" | ||
}, | ||
"timeFormat": { | ||
"default": "ddd dd mmm yyyy HH:MM:ss", | ||
"shortDate": "m/d/yy", | ||
"mediumDate": "d mmm, yyyy", | ||
"longDate": "d mmmm, yyyy", | ||
"fullDate": "dddd, d mmmm, yyyy", | ||
"shortTime": "h:MM TT", | ||
"mediumTime": "h:MM:ss TT", | ||
"longTime": "h:MM:ss TT Z", | ||
"isoDate": "yyyy-mm-dd", | ||
"isoTime": "HH:MM:ss", | ||
"isoDateTime": "yyyy-mm-dd'T'HH:MM:ss", | ||
"isoUtcDateTime": "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'" | ||
}, | ||
"tips": { | ||
"config": "If time is set to 'not used' the inject node can only used manually or once!", | ||
"addTimes": "Here can be defined alternate time. If the given property is true the alternate time will be used instead the normal time. This can be used to have different time for holidays or other special days.", | ||
"recalc": "If the timestamp is given through a flow or global context, changes to these contexts only lead to a change of the planned emit time if a recalculation is done." | ||
"recalc": "If the timestamp is given through a flow or global context, changes to these contexts only lead to a change of the planned emit time if a recalculation is done.", | ||
"addPayload": "With the additional message properties you can send the message with define up to 3 additional properties with enhanced settings. Especial there can be defined timestamps in relation to the message send timestamp." | ||
}, | ||
"errors": { | ||
"error": "<strong>Error</strong>: __message__", | ||
"error-text": "Exception occured on time-inject", | ||
"error-text": "Exception occurred on time-inject", | ||
"error-title": "internal error", | ||
@@ -78,0 +125,0 @@ "unexpected": "unexpected error (__status__) __message__", |
@@ -62,3 +62,3 @@ { | ||
"tips": { | ||
"addTimes": "Here can be defined alternate times for start/end. If the given property is true the alternate start/end times will be used instead the normal ones. This can be used to have differend start/end times for holidays or other special days." | ||
"addTimes": "Here can be defined alternate times for start/end. If the given property is true the alternate start/end times will be used instead the normal ones. This can be used to have different start/end times for holidays or other special days." | ||
}, | ||
@@ -70,3 +70,3 @@ "notification": { | ||
"error": "<strong>Error</strong>: __message__", | ||
"error-text": "Exception occured on withinTimeSwitch", | ||
"error-text": "Exception occurred on withinTimeSwitch", | ||
"error-title": "internal error", | ||
@@ -73,0 +73,0 @@ "invalid-propertyStart-type": "Invalid Property Type for alternate start: __type__", |
@@ -35,5 +35,18 @@ { | ||
"failed2": "Inject failed: __error__", | ||
"toolong": "Interval too large" | ||
} | ||
"toolong": "Interval too large", | ||
"longitude-missing": "Longitude is missing!", | ||
"latitude-missing": "Latitude is missing!" | ||
}, | ||
"days": [ | ||
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", | ||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" | ||
], | ||
"month": [ | ||
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", | ||
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" | ||
], | ||
"dayDiffNames": [ | ||
"1 week ago", "6 days ago", "5 days ago", "4 days ago", "3 days ago", "2 days ago", "Yesterday", "Today", "Tomorrow", "day after tomorrow", "in 3 days", "in 4 days", "in 5 days", "in 6 days" | ||
] | ||
} | ||
} |
{ | ||
"time-inject": { | ||
"label": { | ||
"time-inject": "time-inject", | ||
"inject": "inject", | ||
"position": "Position", | ||
"name": "Name", | ||
"property": "Property", | ||
"time": "Time", | ||
"offset": "Offset", | ||
"timeAlt": "Alternate time", | ||
"timeAltoffset": "Offset", | ||
"addPayload1": "set", | ||
"addPayload2": "(2) set", | ||
"addPayload3": "(3) set", | ||
"addPayload1Value": "value", | ||
"addPayload2Value": "value", | ||
"addPayload3Value": "value", | ||
"addPayload1Format": "time format", | ||
"addPayload2Format": "time format", | ||
"addPayload3Format": "time format", | ||
"recalcTime": "Reclac.", | ||
"payload": "Payload", | ||
"topic": "Topic", | ||
"seconds": "seconds", | ||
"minutes": "minutes", | ||
"hours": "hours", | ||
"timeformat": "time format", | ||
"timeformat_UNIX": "number - milliseconds UNIX timestamp", | ||
"timeformat_ECMA262": "string - ECMA-262", | ||
"timeformat_local": "string - local date and time", | ||
"timeformat_localTime": "string - local time", | ||
"timeformat_UTC": "string - UTC date and time", | ||
"timeformat_ISO": "string - ISO date and time", | ||
"timeformat_ms": "number - milliseconds since emit", | ||
"timeformat_sec": "number - seconds since emit", | ||
"timeformat_min": "number - minutes since emit", | ||
"timeformat_hour": "number - hour since emit", | ||
"timeformat_YYYYMMDDHHMMSS" : "string - YYYYMMDDHHMMSS", | ||
"timeformat_YYYYMMDD_HHMMSS" : "string - YYYYMMDD.HHMMSS", | ||
"timeformat_obj": "as object", | ||
"on": "on", | ||
"none": "none", | ||
"stopped": "stopped", | ||
"timestamp": "timestamp", | ||
"binary": "binary", | ||
"json": "json", | ||
"jsonata": "json expr.", | ||
"blank": "\"\"", | ||
"5minutes": "every 5 minutes", | ||
"10minutes": "every 10 minutes", | ||
"15minutes": "every 15 minutes", | ||
"30minutes": "every 30 minutes", | ||
"1hour": "every hour", | ||
"2hours": "every 2 hour", | ||
"4hours": "every 4 hour", | ||
"6hours": "every 6 hour", | ||
"12hours": "every 12 hour", | ||
"24hours": "every 24 hour", | ||
"once": "additional", | ||
"onstart": "Inject on start ", | ||
"onceDelay": "seconds", | ||
"success": "Successfully injected: __label__" | ||
}, | ||
"days": [ | ||
"Monday", | ||
"Tuesday", | ||
"Wednesday", | ||
"Thursday", | ||
"Friday", | ||
"Saturday", | ||
"Sunday" | ||
], | ||
"placeholder": { | ||
"position": "Position", | ||
"name": "Name", | ||
"topic": "Name", | ||
"property": "Property", | ||
"payloadStart": "", | ||
"payloadEnd": "", | ||
"startTime": "7:40", | ||
"startOffset": "0", | ||
"time": "18:15", | ||
"offset": "0", | ||
"timeAlt": "18:15", | ||
"timeAltOffset": "0" | ||
}, | ||
"tips": { | ||
"config": "If time is set to 'not used' the inject node can only used manually or once!", | ||
"addTimes": "Here can be defined alternate time. If the given property is true the alternate time will be used instead the normal time. This can be used to have different time for holidays or other special days.", | ||
"recalc": "If the timestamp is given through a flow or global context, changes to these contexts only lead to a change of the planned emit time if a recalculation is done.", | ||
"addPayload" : "With the additional message properties you can send the message with define up to 3 additional properties with enhanced settings. Especial there can be defined timestamps in relation to the message send timestamp." | ||
}, | ||
"errors": { | ||
"error": "<strong>Error</strong>: __message__", | ||
"error-text": "Exception occured on time-inject", | ||
"error-title": "internal error", | ||
"unexpected": "unexpected error (__status__) __message__", | ||
"invalid-property-type": "Invalid Property Type: __type__", | ||
"invalid-json": "Invalid 'to' JSON property", | ||
"invalid-jsonata-expr": "Invalid JSONata expression: __error__", | ||
"not-deployed": "node not deployed", | ||
"no-response": "no response from server", | ||
"failed": "inject failed, see log for details", | ||
"failed2": "Inject failed: __error__", | ||
"toolong": "Interval too large" | ||
} | ||
} | ||
"time-inject": { | ||
"label": { | ||
"time-inject": "time-inject", | ||
"inject": "inject", | ||
"position": "Position", | ||
"name": "Name", | ||
"property": "Property", | ||
"time": "Time", | ||
"offset": "Offset", | ||
"payloadOffset": "Offset", | ||
"timeAlt": "Alternate time", | ||
"timeAltOffset": "Offset", | ||
"payloadTimeFormat": "Format", | ||
"addPayload1": "set", | ||
"addPayload2": "(2) set", | ||
"addPayload3": "(3) set", | ||
"addPayload1Value": "value", | ||
"addPayload2Value": "value", | ||
"addPayload3Value": "value", | ||
"addPayload1Format": "time format", | ||
"addPayload2Format": "time format", | ||
"addPayload3Format": "time format", | ||
"recalcTime": "Reclac.", | ||
"payload": "Payload", | ||
"topic": "Topic", | ||
"seconds": "seconds", | ||
"minutes": "minutes", | ||
"hours": "hours", | ||
"timeformat": "time format", | ||
"on": "on", | ||
"none": "none", | ||
"stopped": "stopped", | ||
"timestamp": "timestamp", | ||
"binary": "binary", | ||
"json": "json", | ||
"jsonata": "json expr.", | ||
"blank": "\"\"", | ||
"5minutes": "every 5 minutes", | ||
"10minutes": "every 10 minutes", | ||
"15minutes": "every 15 minutes", | ||
"30minutes": "every 30 minutes", | ||
"1hour": "every hour", | ||
"2hours": "every 2 hour", | ||
"4hours": "every 4 hour", | ||
"6hours": "every 6 hour", | ||
"12hours": "every 12 hour", | ||
"24hours": "every 24 hour", | ||
"once": "additional", | ||
"onstart": "Inject on start ", | ||
"onceDelay": "seconds", | ||
"success": "Successfully injected: __label__" | ||
}, | ||
"outputFormatsGroups": [ | ||
"Number", | ||
"Text (string)", | ||
"time (number) since emit", | ||
"day of week", | ||
"Text free" | ||
], | ||
"outputFormats": [ | ||
"milliseconds UNIX timestamp", | ||
"YYYYMMDDHHMMSS", | ||
"YYYYMMDD.HHMMSS", | ||
"ECMA-262", | ||
"local date and time", | ||
"local date and time enh.", | ||
"local time", | ||
"local time enh.", | ||
"local date", | ||
"local date long", | ||
"UTC date and time", | ||
"ISO date and time", | ||
"milliseconds", | ||
"seconds", | ||
"minutes", | ||
"hours", | ||
"Day Name, e.g. Monday, 22.12.", | ||
"Day in relative, e.g. Today, 22.12.", | ||
"as object", | ||
"Other" | ||
], | ||
"outputFormatsName": [ | ||
"UNIX", | ||
"YYYYMMDDHHMMSS", | ||
"YYYYMMDD_HHMMSS", | ||
"ECMA262", | ||
"local", | ||
"localLong", | ||
"localTime", | ||
"localTimeLong", | ||
"localDate", | ||
"localDateLong", | ||
"UTC", | ||
"ISO", | ||
"ms", | ||
"sec", | ||
"min", | ||
"hour", | ||
"ISO", | ||
"ISO", | ||
"object", | ||
"other" | ||
], | ||
"multiplierGroups": [ | ||
"Standard", | ||
"Special" | ||
], | ||
"multiplier": [ | ||
"milliseconds", | ||
"seconds", | ||
"minutes", | ||
"hours", | ||
"days", | ||
"weeks", | ||
"month", | ||
"year" | ||
], | ||
"days": [ | ||
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", | ||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" | ||
], | ||
"month": [ | ||
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", | ||
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" | ||
], | ||
"dayDiffNames": [ | ||
"1 week ago", "6 days ago", "5 days ago", "4 days ago", "3 days ago", "2 days ago", "Yesterday", "Today", "Tomorrow", "day after tomorrow", "in 3 days", "in 4 days", "in 5 days", "in 6 days" | ||
], | ||
"placeholder": { | ||
"position": "Position", | ||
"name": "Name", | ||
"topic": "Name", | ||
"property": "Property", | ||
"payloadStart": "", | ||
"payloadEnd": "", | ||
"startTime": "7:40", | ||
"startOffset": "0", | ||
"time": "18:15", | ||
"offset": "0", | ||
"timeAlt": "18:15", | ||
"timeAltOffset": "0" | ||
}, | ||
"timeFormat": { | ||
"default": "ddd MMM dd yyyy HH:mm:ss", | ||
"shortDate": "m/d/yy", | ||
"mediumDate": "MMM d, yyyy", | ||
"longDate": "MMMM d, yyyy", | ||
"fullDate": "dddd, MMMM d, yyyy", | ||
"shortTime": "h:mm TT", | ||
"mediumTime": "h:mm:ss TT", | ||
"longTime": "h:mm:ss TT Z", | ||
"isoDate": "yyyy-MM-dd", | ||
"isoTime": "HH:MM:ss", | ||
"isoDateTime": "yyyy-MM-dd'T'HH:mm:ss", | ||
"isoUtcDateTime": "UTC:yyyy-MM-dd'T'HH:mm:ss'Z'" | ||
}, | ||
"tips": { | ||
"config": "If time is set to 'not used' the inject node can only used manually or once!", | ||
"addTimes": "Here can be defined alternate time. If the given property is true the alternate time will be used instead the normal time. This can be used to have different time for holidays or other special days.", | ||
"recalc": "If the timestamp is given through a flow or global context, changes to these contexts only lead to a change of the planned emit time if a recalculation is done.", | ||
"addPayload": "With the additional message properties you can send the message with define up to 3 additional properties with enhanced settings. Especial there can be defined timestamps in relation to the message send timestamp." | ||
}, | ||
"message": { | ||
"onceDelay": "delay __seconds__s" | ||
}, | ||
"errors": { | ||
"error": "<strong>Error</strong>: __message__", | ||
"error-text": "Exception occured on time-inject", | ||
"error-title": "internal error", | ||
"unexpected": "unexpected error (__status__) __message__", | ||
"invalid-property-type": "Invalid Property Type: __type__", | ||
"invalid-json": "Invalid 'to' JSON property", | ||
"invalid-jsonata-expr": "Invalid JSONata expression: __error__", | ||
"not-deployed": "node not deployed", | ||
"no-response": "no response from server", | ||
"failed": "inject failed, see log for details", | ||
"failed2": "Inject failed: __error__", | ||
"toolong": "Interval too large", | ||
"error-init": "error '__message__', retry in __time__", | ||
"warn-init": "warning '__message__', retry in __time__" | ||
} | ||
} | ||
} |
@@ -70,2 +70,4 @@ { | ||
"error-text": "Exception occured on withinTimeSwitch", | ||
"error-start-time": "Error get start time: __message__", | ||
"error-end-time": "Error get end time: __message__", | ||
"error-title": "internal error", | ||
@@ -78,5 +80,7 @@ "invalid-propertyStart-type": "Invalid Property Type for alternate start: __type__", | ||
"no-response": "no response from server", | ||
"unexpected": "unexpected error (__status__) __message__" | ||
"unexpected": "unexpected error (__status__) __message__", | ||
"error-init": "error '__message__', retry in 6min", | ||
"warn-init": "warning '__message__', retry in 6min" | ||
} | ||
} | ||
} |
/******************************************** | ||
* moon-position: | ||
*********************************************/ | ||
const path = require('path'); | ||
const hlp = require(path.join(__dirname, '/lib/sunPosHelper.js')); | ||
const hlp = require(path.join(__dirname, '/lib/dateTimeHelper.js')); | ||
const util = require('util'); | ||
//const hlp = '/lib/sunPosHelper.js'; | ||
module.exports = function (RED) { | ||
"use strict"; | ||
'use strict'; | ||
@@ -16,14 +17,14 @@ function moonPositionNode(config) { | ||
this.positionConfig = RED.nodes.getNode(config.positionConfig); | ||
this.topic = config.topic || ""; | ||
this.topic = config.topic || ''; | ||
this.rules = config.rules || []; | ||
this.azimuthPos = {}; | ||
var node = this; | ||
const node = this; | ||
this.on('input', function (msg) { | ||
try { | ||
var ports = new Array(this.rules.length); | ||
const ports = new Array(this.rules.length); | ||
ports[0] = { | ||
payload: this.positionConfig.getMoonCalc(msg.ts), | ||
topic: this.topic, | ||
} | ||
topic: this.topic | ||
}; | ||
if (!ports[0].payload.azimuth) { | ||
@@ -34,10 +35,11 @@ this.error('Azimuth could not calculated!'); | ||
} | ||
ports[0].payload.pos = []; | ||
ports[0].payload.posChanged = false; | ||
for (var i = 0; i < this.rules.length; i += 1) { | ||
var rule = this.rules[i]; | ||
let low = getNumProp(node, msg, rule.valueLowType, rule.valueLow); | ||
let high = getNumProp(node, msg, rule.valueHighType, rule.valueHigh); | ||
let chk = hlp.compareAzimuth(ports[0].payload.azimuth, low, high); | ||
let chg = (node.azimuthPos[i] !== chk); | ||
for (let i = 0; i < this.rules.length; i += 1) { | ||
const rule = this.rules[i]; | ||
const low = getNumProp(node, msg, rule.valueLowType, rule.valueLow); | ||
const high = getNumProp(node, msg, rule.valueHighType, rule.valueHigh); | ||
const chk = hlp.checkLimits(ports[0].payload.azimuth, low, high); | ||
const chg = (node.azimuthPos[i] !== chk); | ||
ports[0].payload.pos.push(chk); | ||
@@ -50,7 +52,8 @@ ports[0].payload.posChanged = ports[0].payload.posChanged && chg; | ||
} | ||
node.azimuthPos = ports[0].payload.pos; | ||
this.send(ports); | ||
this.status({ | ||
fill: "grey", | ||
shape: "dot", | ||
fill: 'grey', | ||
shape: 'dot', | ||
text: ports[0].payload.azimuth.toFixed(2) + '/' + ports[0].payload.altitude.toFixed(2) + ' - ' + ports[0].payload.lastUpdate.toLocaleString() | ||
@@ -60,14 +63,14 @@ }); | ||
} catch (err) { | ||
hlp.errorHandler(this, err, 'Exception occured on moon-position', 'internal error'); | ||
hlp.handleError(this, 'Exception occurred on moon-position', err, 'internal error'); | ||
} | ||
//this.error("Input parameter wrong or missing. You need to setup (or give in the input message) the 'url' and 'content type' or the 'message' and 'language'!!"); | ||
//this.status({fill:"red",shape:"dot",text:"error - input parameter"}); | ||
// this.error("Input parameter wrong or missing. You need to setup (or give in the input message) the 'url' and 'content type' or the 'message' and 'language'!!"); | ||
// this.status({fill:"red",shape:"dot",text:"error - input parameter"}); | ||
}); | ||
function getNumProp(node, msg, vType, value) { | ||
//node.debug('getNumProp vType=' + vType + ' value=' + value); | ||
let now = new Date(); | ||
function getNumProp(srcNode, msg, vType, value) { | ||
// srcNode.debug('getNumProp vType=' + vType + ' value=' + value); | ||
const now = new Date(); | ||
let result = -1; | ||
if (vType === '' || vType === 'none') { | ||
//nix | ||
// nix | ||
} else if (vType === 'num') { | ||
@@ -77,16 +80,17 @@ result = Number(now); | ||
try { | ||
//evaluateNodeProperty(value, type, node, msg, callback) | ||
let res = RED.util.evaluateNodeProperty(value, vType, srcNode, msg); | ||
// evaluateNodeProperty(value, type, srcNode, msg, callback) | ||
const res = RED.util.evaluateNodeProperty(value, vType, srcNode, msg); | ||
if (res && !isNaN(res)) { | ||
result = Number(now); | ||
} else { | ||
node.error("could not evaluate " + vType + '.' + value); | ||
srcNode.error('could not evaluate ' + vType + '.' + value); | ||
} | ||
} catch (err) { | ||
node.error("could not evaluate " + vType + '.' + value + ': ' + err.message); | ||
node.debug(util.inspect(err, Object.getOwnPropertyNames(err))); | ||
srcNode.error('could not evaluate ' + vType + '.' + value + ': ' + err.message); | ||
srcNode.debug(util.inspect(err, Object.getOwnPropertyNames(err))); | ||
} | ||
} | ||
return result; | ||
}; | ||
} | ||
} | ||
@@ -93,0 +97,0 @@ |
/******************************************** | ||
* position-config: | ||
*********************************************/ | ||
"use strict"; | ||
'use strict'; | ||
const path = require('path'); | ||
const hlp = require(path.join(__dirname, '/lib/sunPosHelper.js')); | ||
const hlp = require(path.join(__dirname, '/lib/dateTimeHelper.js')); | ||
const util = require('util'); | ||
const sunCalc = require(path.join(__dirname, '/lib/suncalc.js')); | ||
@@ -13,59 +15,58 @@ | ||
const moonPhases = [{ | ||
emoji: '🌚', | ||
code: ':new_moon_with_face:', | ||
name: 'New Moon', | ||
weight: 1 | ||
}, | ||
{ | ||
emoji: '🌒', | ||
code: ':waxing_crescent_moon:', | ||
name: 'Waxing Crescent', | ||
weight: 6.3825 | ||
}, | ||
{ | ||
emoji: '🌓', | ||
code: ':first_quarter_moon:', | ||
name: 'First Quarter', | ||
weight: 1 | ||
}, | ||
{ | ||
emoji: '🌔', | ||
code: ':waxing_gibbous_moon:', | ||
name: 'Waxing Gibbous', | ||
weight: 6.3825 | ||
}, | ||
{ | ||
emoji: '🌝', | ||
code: ':full_moon_with_face:', | ||
name: 'Full Moon', | ||
weight: 1 | ||
}, | ||
{ | ||
emoji: '🌖', | ||
code: ':waning_gibbous_moon:', | ||
name: 'Waning Gibbous', | ||
weight: 6.3825 | ||
}, | ||
{ | ||
emoji: '🌗', | ||
code: ':last_quarter_moon:', | ||
name: 'Last Quarter', | ||
weight: 1 | ||
}, | ||
{ | ||
emoji: '🌘', | ||
code: ':waning_crescent_moon:', | ||
name: 'Waning Crescent', | ||
weight: 6.3825 | ||
} | ||
]; | ||
emoji: '🌚', | ||
code: ':new_moon_with_face:', | ||
name: 'New Moon', | ||
weight: 1 | ||
}, | ||
{ | ||
emoji: '🌒', | ||
code: ':waxing_crescent_moon:', | ||
name: 'Waxing Crescent', | ||
weight: 6.3825 | ||
}, | ||
{ | ||
emoji: '🌓', | ||
code: ':first_quarter_moon:', | ||
name: 'First Quarter', | ||
weight: 1 | ||
}, | ||
{ | ||
emoji: '🌔', | ||
code: ':waxing_gibbous_moon:', | ||
name: 'Waxing Gibbous', | ||
weight: 6.3825 | ||
}, | ||
{ | ||
emoji: '🌝', | ||
code: ':full_moon_with_face:', | ||
name: 'Full Moon', | ||
weight: 1 | ||
}, | ||
{ | ||
emoji: '🌖', | ||
code: ':waning_gibbous_moon:', | ||
name: 'Waning Gibbous', | ||
weight: 6.3825 | ||
}, | ||
{ | ||
emoji: '🌗', | ||
code: ':last_quarter_moon:', | ||
name: 'Last Quarter', | ||
weight: 1 | ||
}, | ||
{ | ||
emoji: '🌘', | ||
code: ':waning_crescent_moon:', | ||
name: 'Waning Crescent', | ||
weight: 6.3825 | ||
}]; | ||
Date.prototype.addDays = function (days) { | ||
var date = new Date(this.valueOf()); | ||
const date = new Date(this.valueOf()); | ||
date.setUTCDate(date.getUTCDate() + days); | ||
return date; | ||
} | ||
}; | ||
module.exports = function (RED) { | ||
"use strict"; | ||
'use strict'; | ||
@@ -75,9 +76,9 @@ function positionConfigurationNode(n) { | ||
try { | ||
//this.debug('load position-config ' + n.name); | ||
// this.debug('load position-config ' + n.name); | ||
this.name = n.name; | ||
this.longitude = n.longitude; | ||
this.latitude = n.latitude; | ||
this.longitude = parseFloat(this.credentials.posLongitude || n.longitude); | ||
this.latitude = parseFloat(this.credentials.posLatitude || n.latitude); | ||
this.angleType = n.angleType; | ||
this.tzOffset = (n.timezoneOffset * -60) || 0; | ||
//this.debug('load position-config ' + this.name + ' long:' + this.longitude + ' lat:' + this.latitude + ' angelt:' + this.angleType + ' TZ:' + this.tzOffset); | ||
// this.debug('load position-config ' + this.name + ' long:' + this.longitude + ' latitude:' + this.latitude + ' angelt:' + this.angleType + ' TZ:' + this.tzOffset); | ||
@@ -90,17 +91,26 @@ this.lastSunCalc = { | ||
}; | ||
const node = this; | ||
/* | ||
console.log(hlp.getNodeId(node) +' old lon '+n.longitude); | ||
console.log(hlp.getNodeId(node) +' old lat '+n.latitude); | ||
console.log(hlp.getNodeId(node) +' new lon '+this.credentials.posLongitude); | ||
console.log(hlp.getNodeId(node) +' new lat '+this.credentials.posLatitude); | ||
console.log(hlp.getNodeId(node) +' result lon '+node.longitude); | ||
console.log(hlp.getNodeId(node) +' result lat '+node.latitude); | ||
*/ | ||
var node = this; | ||
/*this.getSunTimes = () => { | ||
/* | ||
this.getSunTimes = () => { | ||
//node.debug('getSunTimes'); | ||
let res = sunTimesCheck(node); | ||
res.today = node.sunTimesToday; | ||
res.tomorrow = node.sunTimesTomorow; | ||
res.tomorrow = node.sunTimesTomorrow; | ||
return res; | ||
}*/ | ||
this.getSunTime = (now, value, offset, next, days) => { | ||
//node.debug('getSunTime value=' + value + ' offset=' + offset + ' next=' + next + ' days=' + days); | ||
} | ||
*/ | ||
this.getSunTime = (now, value, offset, multiplier, next, days) => { | ||
// node.debug('getSunTime value=' + value + ' offset=' + offset + ' multiplier=' + multiplier + ' next=' + next + ' days=' + days); | ||
let result = sunTimesCheck(node, now); | ||
result = Object.assign(result, node.sunTimesToday[value]); | ||
result.value = hlp.addOffset(new Date(result.value), offset); | ||
result.value = hlp.addOffset(new Date(result.value), offset, multiplier); | ||
if (next && !isNaN(next) && result.value.getTime() <= now.getTime()) { | ||
@@ -110,65 +120,178 @@ if (next === 1) { | ||
} else if (next > 1) { | ||
let date = (new Date()).addDays(next); | ||
const date = (new Date()).addDays(next); | ||
result = Object.assign(result, sunCalc.getTimes(date, node.latitude, node.longitude)[value]); | ||
} | ||
result.value = hlp.addOffset(new Date(result.value), offset); | ||
result.value = hlp.addOffset(new Date(result.value), offset, multiplier); | ||
} | ||
if (days && (days !== '*') && (days !== '')) { | ||
let dayx = hlp.calcDayOffset(days, result.value.getDay()); | ||
//node.debug('move day ' + dayx); | ||
// node.debug('move days ' + days + ' result=' + util.inspect(result)); | ||
const dayx = hlp.calcDayOffset(days, result.value.getDay()); | ||
if (dayx > 0) { | ||
let date = result.value.addDays(dayx); | ||
//let times = sunCalc.getTimes(date, node.latitude, node.longitude); | ||
const date = result.value.addDays(dayx); | ||
// let times = sunCalc.getTimes(date, node.latitude, node.longitude); | ||
result = Object.assign(result, sunCalc.getTimes(date, node.latitude, node.longitude)[value]); | ||
result.value = hlp.addOffset(new Date(result.value), offset); | ||
result.value = hlp.addOffset(new Date(result.value), offset, multiplier); | ||
} else if (dayx < 0) { | ||
//node.debug('getSunTime - no valid day of week found value=' + value + ' - next=' + next + ' - days=' + days + ' result=' + util.inspect(result)); | ||
// node.debug('getSunTime - no valid day of week found value=' + value + ' - next=' + next + ' - days=' + days + ' result=' + util.inspect(result)); | ||
result.error = 'No valid day of week found!'; | ||
} | ||
} | ||
//node.debug('getSunTime result=' + util.inspect(result)); | ||
// node.debug('getSunTime result=' + util.inspect(result)); | ||
return result; | ||
} | ||
}; | ||
this.getMoonTimes = () => { | ||
//node.debug('getMoonTimes'); | ||
let res = moonTimesCheck(node); | ||
// node.debug('getMoonTimes'); | ||
const res = moonTimesCheck(node); | ||
res.today = node.moonTimesToday; | ||
res.tomorrow = node.moonTimesTomorow; | ||
return res; | ||
} | ||
this.getMoonTime = (now, value, offset, next, days) => { | ||
//node.debug('getMoonTime value=' + value + ' offset=' + offset + ' next=' + next + ' days=' + days); | ||
let result = moonTimesCheck(node, now); | ||
//node.debug('Moon Times today =' + util.inspect(node.moonTimesToday)); | ||
result.value = hlp.addOffset(new Date(node.moonTimesToday[value]), offset); | ||
}; | ||
this.getMoonTime = (now, value, offset, multiplier, next, days) => { | ||
// node.debug('getMoonTime value=' + value + ' offset=' + offset + ' next=' + next + ' days=' + days); | ||
const result = moonTimesCheck(node, now); | ||
// node.debug('Moon Times today =' + util.inspect(node.moonTimesToday)); | ||
result.value = hlp.addOffset(new Date(node.moonTimesToday[value]), offset, multiplier); | ||
if (next && !isNaN(next) && result.value.getTime() <= now.getTime()) { | ||
if (next === 1) { | ||
result.value = hlp.addOffset(new Date(node.moonTimesTomorow[value]), offset); | ||
//node.debug('Moon Times tomorrow =' + util.inspect(node.moonTimesTomorow)); | ||
result.value = hlp.addOffset(new Date(node.moonTimesTomorow[value]), offset, multiplier); | ||
// node.debug('Moon Times tomorrow =' + util.inspect(node.moonTimesTomorrow)); | ||
} else if (next > 1) { | ||
let date = (new Date()).addDays(next); | ||
let times = sunCalc.getMoonTimes(date, node.latitude, node.longitude, true); | ||
result.value = hlp.addOffset(new Date(new Date(times[value])), offset); | ||
//node.debug('Moon Times for ' + date + ' =' + util.inspect(times)); | ||
const date = (new Date()).addDays(next); | ||
const times = sunCalc.getMoonTimes(date, node.latitude, node.longitude, true); | ||
result.value = hlp.addOffset(new Date(new Date(times[value])), offset, multiplier); | ||
// node.debug('Moon Times for ' + date + ' =' + util.inspect(times)); | ||
} | ||
} | ||
if (days && (days !== '*') && (days !== '')) { | ||
let dayx = hlp.calcDayOffset(days, result.value.getDay()); | ||
const dayx = hlp.calcDayOffset(days, result.value.getDay()); | ||
if (dayx > 0) { | ||
let date = (new Date()).addDays(dayx); | ||
let times = sunCalc.getMoonTimes(date, node.latitude, node.longitude, true); | ||
result.value = hlp.addOffset(new Date(new Date(times[value])), offset); | ||
//node.debug('Moon Times for ' + date + ' =' + util.inspect(times)); | ||
const date = (new Date()).addDays(dayx); | ||
const times = sunCalc.getMoonTimes(date, node.latitude, node.longitude, true); | ||
result.value = hlp.addOffset(new Date(new Date(times[value])), offset, multiplier); | ||
// node.debug('Moon Times for ' + date + ' =' + util.inspect(times)); | ||
} else if (dayx < 0) { | ||
result.error = 'No valid day of week found!'; | ||
//node.debug('getMoonTime - no valid week day found value=' + value + ' - next=' + next + ' - days=' + days + ' result=' + result.value); | ||
// node.debug('getMoonTime - no valid week day found value=' + value + ' - next=' + next + ' - days=' + days + ' result=' + result.value); | ||
} | ||
} | ||
//node.debug('getMoonTime result' + util.inspect(result)); | ||
// node.debug('getMoonTime result' + util.inspect(result)); | ||
return result; | ||
} | ||
}; | ||
this.getTimeProp = (srcNode, msg, vType, value, offset, next, days) => { | ||
//node.debug('getTimeProp ' + hlp.getNodeId(srcNode) + ' vType=' + vType + ' value=' + value + ' offset=' + offset + ' next=' + next + ' days=' + days); | ||
let now = new Date(); | ||
this.getFloatProp = (_srcNode, msg, type, value) => { | ||
let data; | ||
// 'msg', 'flow', 'global', 'num', 'bin', 'env', 'jsonata' | ||
if (type === '' || type === 'none' || typeof type === 'undefined' || type === null) { | ||
return 0; | ||
} else if (type === 'msgPayload') { | ||
data = msg.payload; | ||
} else if (type === 'msgValue') { | ||
data = msg.value; | ||
} else { | ||
data = RED.util.evaluateNodeProperty(value, type, _srcNode, msg); | ||
} | ||
if (data === null || typeof data === 'undefined') { | ||
throw new Error('could not evaluate ' + type + '.' + value); | ||
} | ||
data = parseFloat(data); | ||
if (isNaN(data)) { | ||
throw new Error('the value of ' + type + '.' + value + ' is not a valid Number!'); | ||
} | ||
return data; | ||
}; | ||
this.getOutDataProp = (srcNode, msg, vType, value, format, offset, multiplier) => { | ||
let result = null; | ||
if (vType === null || vType === 'none' || vType === '' || vType === 'date') { | ||
return hlp.getFormattedDateOut(Date.now(), format, RED._('position-config.days'), RED._('position-config.month'), RED._('position-config.dayDiffNames')); | ||
} else if (vType === 'msgPayload') { | ||
return msg.payload; | ||
} else if (vType === 'msgTs') { | ||
return msg.ts; | ||
} else if (vType === 'pdsCalcData') { | ||
return node.getSunCalc(msg.ts); | ||
} else if (vType === 'pdmCalcData') { | ||
return node.getMoonCalc(msg.ts); | ||
} else if ((vType === 'pdsTime') || | ||
(vType === 'pdmTime')) { | ||
if (vType === 'pdsTime') { // sun | ||
result = node.getSunTime(Date.now(), value, offset, multiplier); | ||
} else if (vType === 'pdmTime') { // moon | ||
result = node.getMoonTime(Date.now(), value, offset, multiplier); | ||
} | ||
if (result && result.value && !result.error) { | ||
return hlp.getFormattedDateOut(result, format, RED._('position-config.days'), RED._('position-config.month'), RED._('position-config.dayDiffNames')); | ||
} | ||
return null; | ||
} else if (vType === 'entered' || vType === 'dateEntered') { | ||
result = hlp.getDateOfText(String(value)); | ||
result = hlp.addOffset(result, offset, multiplier); | ||
return hlp.getFormattedDateOut(result, format, RED._('position-config.days'), RED._('position-config.month'), RED._('position-config.dayDiffNames')); | ||
} else if (vType === 'dayOfMonth') { | ||
result = new Date(); | ||
result = hlp.getSpecialDayOfMonth(result.getFullYear(),result.getMonth(), value); | ||
if (result !== null && typeof result !== 'undefined') { | ||
result = hlp.addOffset(result, offset, multiplier); | ||
return hlp.getFormattedDateOut(result, format, RED._('position-config.days'), RED._('position-config.month'), RED._('position-config.dayDiffNames')); | ||
} | ||
return null; | ||
} | ||
return RED.util.evaluateNodeProperty(value, vType, srcNode, msg); | ||
}; | ||
this.getDateFromProp = (srcNode, msg, vType, value, format, offset, multiplier) => { | ||
let result = null; | ||
if (vType === null || vType === 'none' || vType === '') { | ||
return Date.now(); | ||
} else if (vType === 'date') { | ||
return hlp.addOffset(Date.now(), offset, multiplier); | ||
} else if (vType === 'dayOfMonth') { | ||
let d = new Date(); | ||
d = hlp.getSpecialDayOfMonth(d.getFullYear(),d.getMonth(), value); | ||
return hlp.addOffset(d, offset, multiplier); | ||
} else if ((vType === 'pdsTime') || (vType === 'pdmTime')) { | ||
if (vType === 'pdsTime') { | ||
// sun | ||
result = node.getSunTime(Date.now(), value, offset, multiplier); | ||
result.fix = true; | ||
} else if (vType === 'pdmTime') { | ||
// moon | ||
result = node.getMoonTime(Date.now(), value, offset, multiplier); | ||
result.fix = true; | ||
} | ||
if (result && result.value && !result.error) { | ||
return result.value; | ||
} | ||
throw new Error('could not evaluate ' + vType + '.' + value + ' - ' + result.error); | ||
} else if (vType === 'entered' || vType === 'dateEntered') { | ||
result = hlp.getDateOfText(String(value)); | ||
return hlp.addOffset(result, offset, multiplier); | ||
} else if (vType === 'msgPayload') { | ||
result = msg.payload; | ||
} else if (vType === 'msgTs') { | ||
result = msg.ts; | ||
} else { | ||
// msg, flow, global, str, num, env | ||
result = RED.util.evaluateNodeProperty(value, vType, srcNode, msg); | ||
} | ||
if (result !== null && typeof result !== 'undefined') { | ||
result = hlp.parseDateFromFormat(result, format, RED._('position-config.days'), RED._('position-config.month'), RED._('position-config.dayDiffNames')); | ||
if (result.value === 'Invalid Date' || isNaN(result.value) || result.value === null) { | ||
throw new Error('could not evaluate format of ' + result); | ||
} | ||
return hlp.addOffset(result, offset, multiplier); | ||
} | ||
throw new Error('could not evaluate ' + vType + '.' + value); | ||
}; | ||
this.getTimeProp = (srcNode, msg, vType, value, offset, multiplier, next, days) => { | ||
// node.debug('getTimeProp ' + hlp.getNodeId(srcNode) + ' vType=' + vType + ' value=' + value + ' offset=' + offset + ' multiplier=' + multiplier + ' next=' + next + ' days=' + days); | ||
const now = new Date(); | ||
let result = { | ||
@@ -181,31 +304,34 @@ value: null, | ||
if (vType === '' || vType === 'none' || days === '') { | ||
//nix | ||
// nix | ||
} else if (vType === 'date') { | ||
result.value = hlp.calcTimeValue(now, offset); | ||
result.value = hlp.normalizeDate(now, offset, multiplier, next, days); | ||
result.fix = true; | ||
} else if (vType === 'entered') { | ||
result.value = hlp.getTimeOfText(String(value), offset, next, days, now); | ||
//node.debug(String(value) + ' -- ' + result.value); | ||
result.value = hlp.getTimeOfText(String(value), now); | ||
if (result.value !== null) { | ||
result.value = hlp.normalizeDate(result.value, offset, multiplier, next, days); | ||
} | ||
result.fix = true; | ||
} else if (vType === 'pdsTime') { | ||
//sun | ||
result = node.getSunTime(now, value, offset, next, days); | ||
// sun | ||
result = node.getSunTime(now, value, offset, multiplier, next, days); | ||
result.fix = true; | ||
} else if (vType === 'pdmTime') { | ||
//moon | ||
result = node.getMoonTime(now, value, offset, next, days); | ||
// moon | ||
result = node.getMoonTime(now, value, offset, multiplier, next, days); | ||
result.fix = true; | ||
} else { | ||
//can handle context, json, jsonata, env, ... | ||
// can handle context, json, jsonata, env, ... | ||
result.fix = (vType === 'json'); // is not a fixed time if can be changed | ||
let res = RED.util.evaluateNodeProperty(value, vType, srcNode, msg); | ||
const res = RED.util.evaluateNodeProperty(value, vType, srcNode, msg); | ||
if (res) { | ||
result.value = hlp.getDateOfText(res, offset, next, days); | ||
//node.debug(String(res) + ' -- ' + result.value); | ||
result.value = hlp.getDateOfText(res); | ||
result.value = hlp.normalizeDate(result.value, offset, multiplier, next, days); | ||
// node.debug(String(res) + ' -- ' + result.value); | ||
} else { | ||
result.error = "could not evaluate " + vType + '.' + value; | ||
result.error = 'could not evaluate ' + vType + '.' + value; | ||
} | ||
} | ||
} catch (err) { | ||
result.error = "could not evaluate " + vType + '=' + value + ': ' + err.message; | ||
result.error = 'could not evaluate ' + vType + '=' + value + ': ' + err.message; | ||
node.debug(util.inspect(err, Object.getOwnPropertyNames(err))); | ||
@@ -216,141 +342,146 @@ } | ||
if (!result.error) { | ||
result.error = "Can not get time for " + vType + '=' + value; | ||
result.error = 'Can not get time for ' + vType + '=' + value; | ||
} | ||
result.value = now; | ||
} | ||
//node.debug('getTimeProp result' + util.inspect(result)); | ||
// node.debug('getTimeProp result' + util.inspect(result)); | ||
return result; | ||
}; | ||
initTimes(this); | ||
} catch (err) { | ||
hlp.errorHandler(this, err, RED._("position-config.errors.error-text"), RED._("position-config.errors.error-title")); | ||
} | ||
/**************************************************************************************************************/ | ||
this.getSunCalc = (date) => { | ||
if (typeof date === 'string') { | ||
//node.debug('getSunCalc for date ' + date); | ||
let dto = new Date(date); | ||
if (dto !== "Invalid Date" && !isNaN(dto)) { | ||
date = dto; | ||
/**************************************************************************************************************/ | ||
this.getSunCalc = date => { | ||
if (typeof date === 'string') { | ||
// node.debug('getSunCalc for date ' + date); | ||
const dto = new Date(date); | ||
if (dto !== 'Invalid Date' && !isNaN(dto)) { | ||
date = dto; | ||
} | ||
} | ||
} | ||
if ((typeof date === 'undefined') || !(date instanceof Date)) { | ||
//node.debug('getSunCalc, no valid date ' + date + ' given'); | ||
date = new Date(); | ||
if (Math.abs(date.getTime() - this.lastSunCalc.ts) < 4000) { | ||
//node.debug('getSunCalc, time difference since last output to low, do no calculation'); | ||
return this.lastSunCalc; | ||
if ((typeof date === 'undefined') || !(date instanceof Date)) { | ||
// node.debug('getSunCalc, no valid date ' + date + ' given'); | ||
date = new Date(); | ||
if (Math.abs(date.getTime() - this.lastSunCalc.ts) < 4000) { | ||
// node.debug('getSunCalc, time difference since last output to low, do no calculation'); | ||
return this.lastSunCalc; | ||
} | ||
} | ||
} | ||
var sunPos = sunCalc.getPosition(date, node.latitude, node.longitude); | ||
let result = { | ||
ts: date.getTime(), | ||
lastUpdate: date, | ||
latitude: node.latitude, | ||
longitude: node.longitude, | ||
angleType: node.angleType, | ||
azimuth: (node.angleType === 'deg') ? 180 + 180 / Math.PI * sunPos.azimuth : sunPos.azimuth, | ||
altitude: (node.angleType === 'deg') ? 180 / Math.PI * sunPos.altitude : sunPos.altitude, //elevation = altitude | ||
} | ||
sunTimesCheck(node); | ||
result.times = node.sunTimesToday; | ||
this.lastSunCalc = result; | ||
const sunPos = sunCalc.getPosition(date, node.latitude, node.longitude); | ||
const result = { | ||
ts: date.getTime(), | ||
lastUpdate: date, | ||
latitude: node.latitude, | ||
longitude: node.longitude, | ||
angleType: node.angleType, | ||
azimuth: (node.angleType === 'deg') ? 180 + 180 / Math.PI * sunPos.azimuth : sunPos.azimuth, | ||
altitude: (node.angleType === 'deg') ? 180 / Math.PI * sunPos.altitude : sunPos.altitude // elevation = altitude | ||
}; | ||
sunTimesCheck(node); | ||
result.times = node.sunTimesToday; | ||
this.lastSunCalc = result; | ||
return result; | ||
} | ||
/**************************************************************************************************************/ | ||
this.getMoonCalc = (date) => { | ||
if (typeof date === 'string') { | ||
let dto = new Date(date); | ||
if (dto !== "Invalid Date" && !isNaN(dto)) { | ||
date = dto; | ||
return result; | ||
}; | ||
/**************************************************************************************************************/ | ||
this.getMoonCalc = date => { | ||
if (typeof date === 'string') { | ||
const dto = new Date(date); | ||
if (dto !== 'Invalid Date' && !isNaN(dto)) { | ||
date = dto; | ||
} | ||
} | ||
} | ||
if ((typeof date === 'undefined') || !(date instanceof Date)) { | ||
date = new Date(); | ||
if (Math.abs(date.getTime() - this.lastMoonCalc.ts) < 3000) { | ||
return this.lastMoonCalc; | ||
if ((typeof date === 'undefined') || !(date instanceof Date)) { | ||
date = new Date(); | ||
if (Math.abs(date.getTime() - this.lastMoonCalc.ts) < 3000) { | ||
return this.lastMoonCalc; | ||
} | ||
} | ||
} | ||
let moonPos = sunCalc.getMoonPosition(date, node.latitude, node.longitude); | ||
let moonIllum = sunCalc.getMoonIllumination(date); | ||
const moonPos = sunCalc.getMoonPosition(date, node.latitude, node.longitude); | ||
const moonIllum = sunCalc.getMoonIllumination(date); | ||
var result = { | ||
ts: date.getTime(), | ||
lastUpdate: date, | ||
latitude: node.latitude, | ||
longitude: node.longitude, | ||
angleType: node.angleType, | ||
azimuth: (node.angleType === 'deg') ? 180 + 180 / Math.PI * moonPos.azimuth : moonPos.azimuth, | ||
altitude: (node.angleType === 'deg') ? 180 / Math.PI * moonPos.altitude : moonPos.altitude, //elevation = altitude | ||
distance: moonPos.distance, | ||
parallacticAngle: (node.angleType === 'deg') ? 180 / Math.PI * moonPos.parallacticAngle : moonPos.parallacticAngle, | ||
illumination: { | ||
angle: (node.angleType === 'deg') ? 180 / Math.PI * moonIllum.angle : moonIllum.angle, | ||
fraction: moonIllum.fraction, | ||
phase: {}, | ||
zenithAngle: (node.angleType === 'deg') ? 180 / Math.PI * (moonIllum.angle - moonPos.parallacticAngle) : moonIllum.angle - moonPos.parallacticAngle, | ||
}, | ||
} | ||
sunTimesCheck(node); | ||
result.times = node.moonTimesToday; | ||
//getAngle : angle / 57.2957795130823209 //angle(rad) * (180° / Pi) = angle(deg) | ||
const result = { | ||
ts: date.getTime(), | ||
lastUpdate: date, | ||
latitude: node.latitude, | ||
longitude: node.longitude, | ||
angleType: node.angleType, | ||
azimuth: (node.angleType === 'deg') ? 180 + 180 / Math.PI * moonPos.azimuth : moonPos.azimuth, | ||
altitude: (node.angleType === 'deg') ? 180 / Math.PI * moonPos.altitude : moonPos.altitude, // elevation = altitude | ||
distance: moonPos.distance, | ||
parallacticAngle: (node.angleType === 'deg') ? 180 / Math.PI * moonPos.parallacticAngle : moonPos.parallacticAngle, | ||
illumination: { | ||
angle: (node.angleType === 'deg') ? 180 / Math.PI * moonIllum.angle : moonIllum.angle, | ||
fraction: moonIllum.fraction, | ||
phase: {}, | ||
zenithAngle: (node.angleType === 'deg') ? 180 / Math.PI * (moonIllum.angle - moonPos.parallacticAngle) : moonIllum.angle - moonPos.parallacticAngle | ||
} | ||
}; | ||
sunTimesCheck(node); | ||
result.times = node.moonTimesToday; | ||
// getAngle : angle / 57.2957795130823209 //angle(rad) * (180° / Pi) = angle(deg) | ||
if (moonIllum.phase < 0.01) { | ||
// 0 New Moon - Neumond(Phasenwinkel = 0°) | ||
result.illumination.phase = moonPhases[0]; | ||
} else if (moonIllum.phase < 0.25) { | ||
// 0 - 0.25 Waxing Crescent - erstes Viertel bzw.zunehmende Sichel(0° < Phasenwinkel < 90°), | ||
result.illumination.phase = moonPhases[1]; | ||
} else if (moonIllum.phase < 0.26) { | ||
// 0.25 First Quarter - zunehmender Halbmond(astronomisch: erstes Viertel, Phasenwinkel = 90°), | ||
result.illumination.phase = moonPhases[2]; | ||
} else if (moonIllum.phase < 0.50) { | ||
// 0.25 - 0.5 Waxing Gibbous - zweites Viertel(90° < Phasenwinkel < 180°), | ||
result.illumination.phase = moonPhases[3]; | ||
} else if (moonIllum.phase < 0.51) { | ||
// 0.5 Full Moon - Vollmond(Phasenwinkel = 180°), | ||
result.illumination.phase = moonPhases[4]; | ||
} else if (moonIllum.phase <= 0.75) { | ||
// 0.5 - 0.75 Waning Gibbous - drittes Viertel (180° < Phasenwinkel < 270°), | ||
result.illumination.phase = moonPhases[5]; | ||
} else if (moonIllum.phase < 0.76) { | ||
// 0.75 Last Quarter - abnehmender Halbmond(astronomisch: letztes Viertel, Phasenwinkel = 270°), | ||
result.illumination.phase = moonPhases[6]; | ||
} else { | ||
// Waning Crescent - letztes Viertel bzw.abnehmende Sichel(Phasenwinkel > 270°). | ||
result.illumination.phase = moonPhases[7]; | ||
} | ||
result.illumination.phase.value = moonIllum.phase; | ||
result.illumination.phase.angle = (node.angleType === 'rad') ? (moonIllum.phase * 360) / (180 / Math.PI) : moonIllum.phase * 360; | ||
if (moonIllum.phase < 0.01) { | ||
// 0 New Moon - Neumond(Phasenwinkel = 0°) | ||
result.illumination.phase = moonPhases[0]; | ||
} else if (moonIllum.phase < 0.25) { | ||
// 0 - 0.25 Waxing Crescent - erstes Viertel bzw. zunehmende Sichel(0° < Phasenwinkel < 90°), | ||
result.illumination.phase = moonPhases[1]; | ||
} else if (moonIllum.phase < 0.26) { | ||
// 0.25 First Quarter - zunehmender Halbmond(astronomisch: erstes Viertel, Phasenwinkel = 90°), | ||
result.illumination.phase = moonPhases[2]; | ||
} else if (moonIllum.phase < 0.50) { | ||
// 0.25 - 0.5 Waxing Gibbous - zweites Viertel(90° < Phasenwinkel < 180°), | ||
result.illumination.phase = moonPhases[3]; | ||
} else if (moonIllum.phase < 0.51) { | ||
// 0.5 Full Moon - Vollmond(Phasenwinkel = 180°), | ||
result.illumination.phase = moonPhases[4]; | ||
} else if (moonIllum.phase <= 0.75) { | ||
// 0.5 - 0.75 Waning Gibbous - drittes Viertel (180° < Phasenwinkel < 270°), | ||
result.illumination.phase = moonPhases[5]; | ||
} else if (moonIllum.phase < 0.76) { | ||
// 0.75 Last Quarter - abnehmender Halbmond(astronomisch: letztes Viertel, Phasenwinkel = 270°), | ||
result.illumination.phase = moonPhases[6]; | ||
} else { | ||
// Waning Crescent - letztes Viertel bzw. abnehmende Sichel(Phasenwinkel > 270°). | ||
result.illumination.phase = moonPhases[7]; | ||
} | ||
if (!result.times.alwaysUp) { | ||
//true if the moon never rises/sets and is always above the horizon during the day | ||
result.times.alwaysUp = false; | ||
} | ||
if (!result.times.alwaysDown) { | ||
//true if the moon is always below the horizon | ||
result.times.alwaysDown = false; | ||
} | ||
this.lastMoonCalc = result; | ||
result.illumination.phase.value = moonIllum.phase; | ||
result.illumination.phase.angle = (node.angleType === 'rad') ? (moonIllum.phase * 360) / (180 / Math.PI) : moonIllum.phase * 360; | ||
return result; | ||
if (!result.times.alwaysUp) { | ||
// true if the moon never rises/sets and is always above the horizon during the day | ||
result.times.alwaysUp = false; | ||
} | ||
if (!result.times.alwaysDown) { | ||
// true if the moon is always below the horizon | ||
result.times.alwaysDown = false; | ||
} | ||
this.lastMoonCalc = result; | ||
return result; | ||
}; | ||
/**************************************************************************************************************/ | ||
initTimes(this); | ||
} catch (err) { | ||
hlp.handleError(this, RED._('position-config.errors.error-text'), err, RED._('position-config.errors.error-title')); | ||
} | ||
/**************************************************************************************************************/ | ||
//sendDebug({id:node.id, name:node.name, topic:msg.topic, msg:msg, _path:msg._path}); | ||
//{id:node.id, z:node.z, name:node.name, topic:msg.topic, property:property, msg:output, _path:msg._path} | ||
/* | ||
function sendDebug(msg) { | ||
// don't put blank errors in sidebar (but do add to logs) | ||
//if ((msg.msg === "") && (msg.hasOwnProperty("level")) && (msg.level === 20)) { return; } | ||
msg = RED.util.encodeObject(msg, { | ||
maxLength: debuglength | ||
}); | ||
RED.comms.publish("debug", msg); | ||
} /* */ | ||
/**************************************************************************************************************/ | ||
function sunTimesRefresh(node, today, tomorrow, dayId) { | ||
//node.debug('sunTimesRefresh - calculate sun times'); | ||
if (isNaN(node.longitude)) { | ||
throw new Error(RED._('position-config.errors.longitude-missing')); | ||
} | ||
if (isNaN(node.latitude)) { | ||
throw new Error(RED._('position-config.errors.latitude-missing')); | ||
} | ||
// node.debug('sunTimesRefresh - calculate sun times'); | ||
node.sunTimesToday = sunCalc.getTimes(today, node.latitude, node.longitude); | ||
@@ -362,35 +493,46 @@ node.sunTimesTomorow = sunCalc.getTimes(tomorrow, node.latitude, node.longitude); | ||
function sunTimesCheck(node, today, dayId) { | ||
//node.debug('sunTimesCheck'); | ||
let dateb = today || new Date(); | ||
let day_id = dayId || getUTCDayId(dateb); | ||
if (node.sunDayId != day_id) { | ||
let tomorrow = (new Date()).addDays(1); | ||
// node.debug('sunTimesCheck'); | ||
const dateb = today || new Date(); | ||
const day_id = dayId || getUTCDayId(dateb); | ||
if (node.sunDayId !== day_id) { | ||
const tomorrow = (new Date()).addDays(1); | ||
sunTimesRefresh(node, dateb, tomorrow, day_id); | ||
} | ||
return { | ||
calcDate: dateb, | ||
dayId: day_id | ||
} | ||
}; | ||
} | ||
function moonTimesRefresh(node, today, tomorrow, dayId) { | ||
//node.debug('moonTimesRefresh - calculate moon times'); | ||
if (isNaN(node.longitude)) { | ||
throw new Error(RED._('position-config.errors.longitude-missing')); | ||
} | ||
if (isNaN(node.latitude)) { | ||
throw new Error(RED._('position-config.errors.latitude-missing')); | ||
} | ||
// node.debug('moonTimesRefresh - calculate moon times'); | ||
node.moonTimesToday = sunCalc.getMoonTimes(today, node.latitude, node.longitude, true); | ||
if (!node.moonTimesToday.alwaysUp) { | ||
//true if the moon never rises/sets and is always above the horizon during the day | ||
// true if the moon never rises/sets and is always above the horizon during the day | ||
node.moonTimesToday.alwaysUp = false; | ||
} | ||
if (!node.moonTimesToday.alwaysDown) { | ||
//true if the moon is always below the horizon | ||
// true if the moon is always below the horizon | ||
node.moonTimesToday.alwaysDown = false; | ||
} | ||
node.moonTimesTomorow = sunCalc.getMoonTimes(tomorrow, node.latitude, node.longitude, true); | ||
if (!node.moonTimesTomorow.alwaysUp) { | ||
//true if the moon never rises/sets and is always above the horizon during the day | ||
// true if the moon never rises/sets and is always above the horizon during the day | ||
node.moonTimesTomorow.alwaysUp = false; | ||
} | ||
if (!node.moonTimesTomorow.alwaysDown) { | ||
//true if the moon is always below the horizon | ||
// true if the moon is always below the horizon | ||
node.moonTimesTomorow.alwaysDown = false; | ||
} | ||
node.moonDayId = dayId; | ||
@@ -400,20 +542,20 @@ } | ||
function moonTimesCheck(node, today, dayId) { | ||
//node.debug('moonTimesCheck'); | ||
let dateb = today || new Date(); | ||
let day_id = dayId || getUTCDayId(dateb); | ||
if (node.moonDayId != day_id) { | ||
let tomorrow = (new Date()).addDays(1); | ||
// node.debug('moonTimesCheck'); | ||
const dateb = today || new Date(); | ||
const day_id = dayId || getUTCDayId(dateb); | ||
if (node.moonDayId !== day_id) { | ||
const tomorrow = (new Date()).addDays(1); | ||
moonTimesRefresh(node, dateb, tomorrow, day_id); | ||
} | ||
return { | ||
calcDate: dateb, | ||
dayId: day_id | ||
} | ||
}; | ||
} | ||
function initTimes(node) { | ||
//node.debug('initTimes'); | ||
let today = new Date(); | ||
let dayId = getUTCDayId(today); | ||
let tomorrow = today.addDays(1); | ||
const today = new Date(); | ||
const dayId = getUTCDayId(today); | ||
const tomorrow = today.addDays(1); | ||
sunTimesRefresh(node, today, tomorrow, dayId); | ||
@@ -426,5 +568,10 @@ moonTimesRefresh(node, today, tomorrow, dayId); | ||
} | ||
/**************************************************************************************************************/ | ||
} | ||
RED.nodes.registerType("position-config", positionConfigurationNode); | ||
} | ||
RED.nodes.registerType('position-config', positionConfigurationNode, { | ||
credentials: { | ||
posLongitude: {type: 'text' }, | ||
posLatitude: { type: 'text' } | ||
} | ||
}); | ||
}; |
@@ -5,7 +5,8 @@ /******************************************** | ||
const path = require('path'); | ||
const hlp = require(path.join(__dirname, '/lib/sunPosHelper.js')); | ||
const hlp = require(path.join(__dirname, '/lib/dateTimeHelper.js')); | ||
const util = require('util'); | ||
module.exports = function (RED) { | ||
"use strict"; | ||
'use strict'; | ||
@@ -16,14 +17,14 @@ function sunPositionNode(config) { | ||
this.positionConfig = RED.nodes.getNode(config.positionConfig); | ||
this.topic = config.topic || ""; | ||
this.topic = config.topic || ''; | ||
this.rules = config.rules || []; | ||
this.azimuthPos = {}; | ||
var node = this; | ||
const node = this; | ||
this.on('input', function (msg) { | ||
try { | ||
var ports = new Array(this.rules.length); | ||
const ports = new Array(this.rules.length); | ||
ports[0] = { | ||
payload: this.positionConfig.getSunCalc(msg.ts), | ||
topic: this.topic, | ||
} | ||
topic: this.topic | ||
}; | ||
if (!ports[0].payload.azimuth) { | ||
@@ -34,10 +35,11 @@ this.error('Azimuth could not calculated!'); | ||
} | ||
ports[0].payload.pos = []; | ||
ports[0].payload.posChanged = false; | ||
for (var i = 0; i < this.rules.length; i += 1) { | ||
var rule = this.rules[i]; | ||
let low = getNumProp(node, msg, rule.valueLowType, rule.valueLow); | ||
let high = getNumProp(node, msg, rule.valueHighType, rule.valueHigh); | ||
let chk = hlp.compareAzimuth(ports[0].payload.azimuth, low, high); | ||
let chg = (node.azimuthPos[i] !== chk); | ||
for (let i = 0; i < this.rules.length; i += 1) { | ||
const rule = this.rules[i]; | ||
const low = getNumProp(node, msg, rule.valueLowType, rule.valueLow); | ||
const high = getNumProp(node, msg, rule.valueHighType, rule.valueHigh); | ||
const chk = hlp.checkLimits(ports[0].payload.azimuth, low, high); | ||
const chg = (node.azimuthPos[i] !== chk); | ||
ports[0].payload.pos.push(chk); | ||
@@ -50,7 +52,8 @@ ports[0].payload.posChanged = ports[0].payload.posChanged && chg; | ||
} | ||
node.azimuthPos = ports[0].payload.pos; | ||
this.send(ports); | ||
this.status({ | ||
fill: "grey", | ||
shape: "dot", | ||
fill: 'grey', | ||
shape: 'dot', | ||
text: ports[0].payload.azimuth.toFixed(2) + '/' + ports[0].payload.altitude.toFixed(2) + ' - ' + ports[0].payload.lastUpdate.toLocaleString() | ||
@@ -60,14 +63,14 @@ }); | ||
} catch (err) { | ||
hlp.errorHandler(this, err, 'Exception occured on sun-position', 'internal error'); | ||
hlp.handleError(this, 'Exception occurred on sun-position', err, 'internal error'); | ||
} | ||
//this.error("Input parameter wrong or missing. You need to setup (or give in the input message) the 'url' and 'content type' or the 'message' and 'language'!!"); | ||
//this.status({fill:"red",shape:"dot",text:"error - input parameter"}); | ||
// this.error("Input parameter wrong or missing. You need to setup (or give in the input message) the 'url' and 'content type' or the 'message' and 'language'!!"); | ||
// this.status({fill:"red",shape:"dot",text:"error - input parameter"}); | ||
}); | ||
function getNumProp(node, msg, vType, value) { | ||
//node.debug('getNumProp vType=' + vType + ' value=' + value); | ||
let now = new Date(); | ||
function getNumProp(srcNode, msg, vType, value) { | ||
// srcNode.debug('getNumProp vType=' + vType + ' value=' + value); | ||
const now = new Date(); | ||
let result = -1; | ||
if (vType === '' || vType === 'none') { | ||
//nix | ||
// nix | ||
} else if (vType === 'num') { | ||
@@ -77,16 +80,17 @@ result = Number(now); | ||
try { | ||
//evaluateNodeProperty(value, type, node, msg, callback) | ||
let res = RED.util.evaluateNodeProperty(value, vType, srcNode, msg); | ||
// evaluateNodeProperty(value, type, srcNode, msg, callback) | ||
const res = RED.util.evaluateNodeProperty(value, vType, srcNode, msg); | ||
if (res && !isNaN(res)) { | ||
result = Number(now); | ||
} else { | ||
node.error("could not evaluate " + vType + '.' + value); | ||
srcNode.error('could not evaluate ' + vType + '.' + value); | ||
} | ||
} catch (err) { | ||
node.error("could not evaluate " + vType + '.' + value + ': ' + err.message); | ||
node.debug(util.inspect(err, Object.getOwnPropertyNames(err))); | ||
srcNode.error('could not evaluate ' + vType + '.' + value + ': ' + err.message); | ||
srcNode.debug(util.inspect(err, Object.getOwnPropertyNames(err))); | ||
} | ||
} | ||
return result; | ||
}; | ||
} | ||
} | ||
@@ -93,0 +97,0 @@ |
@@ -1,9 +0,10 @@ | ||
var should = require("should"); | ||
var helper = require("node-red-test-helper"); | ||
var sunNode = require("../sun-position.js"); | ||
var moonNode = require("../moon-position.js"); | ||
var injectNode = require("../time-inject.js"); | ||
var withinNode = require("../within-time.js"); | ||
/* eslint-disable */ | ||
let should = require('should'); | ||
let helper = require('node-red-test-helper'); | ||
let sunNode = require('../sun-position.js'); | ||
let moonNode = require('../moon-position.js'); | ||
let injectNode = require('../time-inject.js'); | ||
let withinNode = require('../within-time.js'); | ||
describe('sun-position Node', function () { | ||
describe('sun-position Node', () => { | ||
@@ -36,2 +37,3 @@ afterEach(function () { | ||
}); | ||
}); | ||
}); | ||
/* eslint-enable */ |
/******************************************** | ||
* time-inject: | ||
*********************************************/ | ||
"use strict"; | ||
'use strict'; | ||
const util = require('util'); | ||
const path = require('path'); | ||
const hlp = require(path.join(__dirname, '/lib/sunPosHelper.js')); | ||
//const cron = require("cron"); | ||
module.exports = function(RED) { | ||
"use strict"; | ||
const hlp = require(path.join(__dirname, '/lib/dateTimeHelper.js')); | ||
function getforamtDateCmp(date) { | ||
function pad2(n) { // always returns a string | ||
return (n < 10 ? '0' : '') + n; | ||
} | ||
module.exports = function (RED) { | ||
'use strict'; | ||
return Number(date.getFullYear() + | ||
pad2(date.getMonth() + 1) + | ||
pad2(date.getDate()) + | ||
pad2(date.getHours()) + | ||
pad2(date.getMinutes()) + | ||
pad2(date.getSeconds())); | ||
} | ||
function getforamtDateCmp2(date) { | ||
function pad2(n) { // always returns a string | ||
return (n < 10 ? '0' : '') + n; | ||
} | ||
return Number(date.getFullYear() + | ||
pad2(date.getMonth() + 1) + | ||
pad2(date.getDate()) + '.' + | ||
pad2(date.getHours()) + | ||
pad2(date.getMinutes()) + | ||
pad2(date.getSeconds())); | ||
} | ||
function tsGetScheduleTime(time, limit) { | ||
var now = new Date(); | ||
var millis = time.getTime() - now.getTime(); | ||
const now = new Date(); | ||
let millis = time.getTime() - now.getTime(); | ||
if (limit) { | ||
while (millis < limit) { | ||
millis += 86400000; //24h | ||
millis += 86400000; // 24h | ||
} | ||
} | ||
return millis; | ||
} | ||
function tsGetPropData(node, msg, type, value, format, offset, days) { | ||
if (type == null || type === "none" || type === "" || (typeof type === 'undefined')) { | ||
if (value === "" || (typeof value === 'undefined')) { | ||
return Date.now(); | ||
} else { | ||
return value; | ||
function tsGetPropData(node, msg, type, value, format, offset, offsetType, multiplier, days) { | ||
if (type === null || type === 'none' || type === '' || (typeof type === 'undefined')) { | ||
if (value === '' || (typeof value === 'undefined')) { | ||
const offsetX = this.positionConfig.getFloatProp(node,offsetType, offset); | ||
const result = hlp.addOffset(Date.now(), offsetX, multiplier); | ||
return hlp.getFormattedDateOut(result, format, RED._('time-inject.days'), RED._('time-inject.month'), RED._('time-inject.dayDiffNames')); | ||
} | ||
} else if (type === "pdsCalcData") { | ||
return value; | ||
} else if (type === 'pdsCalcData') { | ||
return node.positionConfig.getSunCalc(msg.ts); | ||
} else if (type === "pdmCalcData") { | ||
} else if (type === 'pdmCalcData') { | ||
return node.positionConfig.getMoonCalc(msg.ts); | ||
} else if (type === "entered" || type === "pdsTime" || type === "pdmTime" || type === "date") { | ||
let data = node.positionConfig.getTimeProp(node, msg, type, value, offset, 1, days); | ||
if (!data.error) { | ||
format = format || 0; | ||
switch (Number(format)) { | ||
case 0: //timeformat_UNIX - milliseconds since Jan 1, 1970 00:00 | ||
return data.value.getTime(); | ||
case 1: //timeformat_ECMA262 - date as string ECMA-262 | ||
return data.value; | ||
case 2: //timeformat_local | ||
return data.value.toLocaleString(); | ||
case 3: //timeformat_localTime | ||
return data.value.toLocaleTimeString(); | ||
case 4: //timeformat_UTC | ||
return data.value.toUTCString(); | ||
case 5: //timeformat_ISO | ||
return data.value.toISOString(); | ||
case 6: //timeformat_ms | ||
return tsGetScheduleTime(data.value, (type === "date") ? 10 : undefined); | ||
case 7: //timeformat_sec | ||
return Math.round(tsGetScheduleTime(data.value, (type === "date") ? 10 : undefined) / 1000); | ||
case 8: //timeformat_min | ||
return (Math.round(tsGetScheduleTime(data.value, (type === "date") ? 10 : undefined) / 1000) / 60); | ||
case 9: //timeformat_hour | ||
return (Math.round(tsGetScheduleTime(data.value, (type === "date") ? 10 : undefined) / 1000) / 3600); | ||
case 10: //timeformat_YYYYMMDDHHMMSS | ||
return getforamtDateCmp(data.value); | ||
case 11: //timeformat_YYYYMMDD_HHMMSS | ||
return getforamtDateCmp2(data.value); | ||
default: | ||
let obj = data; | ||
obj.name = value; | ||
obj.offset = offset; | ||
obj.allowedDays = days; | ||
obj.ts = data.value.getTime(); | ||
obj.timeUTCStr = data.value.toUTCString(); | ||
obj.timeISOStr = data.value.toISOString(); | ||
obj.timeLocaleStr = data.value.toLocaleString(); | ||
obj.timeLocaleTimeStr = data.value.toLocaleTimeString(); | ||
let delay = tsGetScheduleTime(data.value, (type === "date") ? 10 : undefined); | ||
obj.delay = delay; | ||
obj.delaySec = Math.round(delay / 1000); | ||
return obj; | ||
} | ||
} else if (type === 'msgPayload') { | ||
return msg.payload; | ||
} else if (type === 'msgTs') { | ||
return msg.ts; | ||
} else if ((type === 'pdsTime') || | ||
(type === 'pdmTime')) { | ||
let result; | ||
const offsetX = this.positionConfig.getFloatProp(node,offsetType, offset); | ||
if (type === 'pdsTime') { // sun | ||
result = node.getSunTime(Date.now(), value, offsetX, multiplier, days); | ||
} else if (type === 'pdmTime') { // moon | ||
result = node.getMoonTime(Date.now(), value, offsetX, multiplier, days); | ||
} | ||
return data; | ||
if (result && result.value && !result.error) { | ||
return hlp.getFormattedDateOut(result, format, RED._('time-inject.days'), RED._('time-inject.month'), RED._('time-inject.dayDiffNames')); | ||
} | ||
return null; | ||
} else if (type === 'entered' || type === 'dateEntered') { | ||
let result = hlp.getDateOfText(String(value)); | ||
const offsetX = this.positionConfig.getFloatProp(node,offsetType, offset); | ||
result = hlp.normalizeDate(result, offsetX, multiplier, 1, days); | ||
return hlp.getFormattedDateOut(result, format, RED._('time-inject.days'), RED._('time-inject.month'), RED._('time-inject.dayDiffNames')); | ||
} else if (type === 'dayOfMonth') { | ||
let result = new Date(); | ||
result = hlp.getSpecialDayOfMonth(result.getFullYear(),result.getMonth(), value); | ||
if (result !== null && typeof result !== 'undefined') { | ||
result = hlp.addOffset(result, offset, multiplier); | ||
return hlp.getFormattedDateOut(result, format, RED._('position-config.days'), RED._('position-config.month'), RED._('position-config.dayDiffNames')); | ||
} | ||
return null; | ||
} | ||
@@ -112,7 +72,7 @@ return RED.util.evaluateNodeProperty(value, type, node, msg); | ||
function tsSetAddProp(node, msg, type, name, valueType, value, format, offset, days) { | ||
function tsSetAddProp(node, msg, type, name, valueType, value, format, offset, offsetType, multiplier, days) { | ||
if (type !== 'none' && name) { | ||
let res = tsGetPropData(node, msg, valueType, value, format, offset, days); | ||
if (res == null || (typeof res === 'undefined')) { | ||
throw new Error("could not evaluate " + valueType + '.' + value); | ||
const res = tsGetPropData(node, msg, valueType, value, format, offset, offsetType, multiplier, days); | ||
if (res === null || (typeof res === 'undefined')) { | ||
throw new Error('could not evaluate ' + valueType + '.' + value); | ||
} else if (res.error) { | ||
@@ -123,3 +83,3 @@ this.error('error on getting additional payload 1: ' + res.error); | ||
} else if ((type === 'flow' || type === 'global')) { | ||
let contextKey = RED.util.parseContextStore(name); | ||
const contextKey = RED.util.parseContextStore(name); | ||
node.context()[type].set(contextKey.key, res, contextKey.store); | ||
@@ -134,3 +94,3 @@ } | ||
this.positionConfig = RED.nodes.getNode(config.positionConfig); | ||
//this.debug('initialize timeInjectNode ' + util.inspect(config)); | ||
// this.debug('initialize timeInjectNode ' + util.inspect(config)); | ||
@@ -142,2 +102,3 @@ this.time = config.time; | ||
this.offset = config.offset || config.timeOffset || 0; | ||
this.offsetType = config.offsetType || (this.offset === 0) ? 'none' : 'num'; | ||
this.offsetMultiplier = config.offsetMultiplier || config.timeOffsetMultiplier || 60; | ||
@@ -150,2 +111,3 @@ | ||
this.timeAltOffset = config.timeAltOffset || 0; | ||
this.timeAltOffsetType = config.timeAltOffsetType || (this.timeAltOffset === 0) ? 'none' : 'num'; | ||
this.timeAltOffsetMultiplier = config.timeAltOffsetMultiplier || 60; | ||
@@ -161,5 +123,20 @@ | ||
this.nextTimeAltData = null; | ||
var node = this; | ||
const node = this; | ||
function doCreateTimeout(node, msg) { | ||
function retriggerOnInit(node, errorStatus, errorMesage) { | ||
node.warn(RED._('time-inject.errors.warn-init', { message: errorMesage, time: 6})); | ||
setTimeout(() => { | ||
try { | ||
doCreateTimeout(node); | ||
} catch (err) { | ||
hlp.handleError(this, RED._('time-inject.errors.error-text'), err, RED._('time-inject.errors.error-title')); | ||
} | ||
}, 360000); // 6 Minuten | ||
node.status({ | ||
fill: 'red', | ||
shape: 'ring', | ||
text: RED._('time-inject.errors.error-init', { message: errorStatus, time: '6min'}) | ||
}); | ||
} | ||
function doCreateTimeout(node, _onInit) { | ||
let errorStatus = ''; | ||
@@ -177,12 +154,16 @@ let isAltFirst = false; | ||
if (node.timeType !== 'none' && node.positionConfig) { | ||
//(srcNode, msg, vType, value, offset, next, days) | ||
//node.nextTime = hlp.getTimeProp(node, node.timeType, node.time, node.offset * node.offsetMultiplier, 1); | ||
node.nextTimeData = node.positionConfig.getTimeProp(node, undefined, node.timeType, node.time, node.offset * node.offsetMultiplier, 1, node.timeDays); | ||
// (srcNode, msg, vType, value, offset, next, days) | ||
// node.nextTime = hlp.getTimeProp(node, node.timeType, node.time, node.offset, node.offsetMultiplier, 1); | ||
const nextTimeOffset = node.positionConfig.getFloatProp(node, undefined, node.offsetType, node.offset); | ||
node.nextTimeData = node.positionConfig.getTimeProp(node, undefined, node.timeType, node.time, nextTimeOffset, node.offsetMultiplier, 1, node.timeDays); | ||
if (node.nextTimeData.error) { | ||
errorStatus = "could not evaluate time"; | ||
node.error(node.nextTimeData.error); | ||
node.debug(util.inspect(node.nextTimeData)); | ||
//console.log('1'); | ||
errorStatus = 'could not evaluate time'; | ||
node.nextTime = null; | ||
isFixedTime = false; | ||
if (_onInit === true) { | ||
retriggerOnInit(node, errorStatus, node.nextTimeData.error); | ||
return; | ||
} | ||
node.error(node.nextTimeData.error); | ||
node.debug('nextTimeData ' + util.inspect(node.nextTimeData)); | ||
} else { | ||
@@ -193,3 +174,2 @@ node.nextTime = node.nextTimeData.value; | ||
} | ||
//console.log(util.inspect(node.nextTimeData)); | ||
@@ -199,9 +179,14 @@ if (node.propertyType !== 'none' && | ||
node.positionConfig) { | ||
node.nextTimeAltData = node.positionConfig.getTimeProp(node, undefined, node.timeAltType, node.timeAlt, node.timeAltOffset * node.timeAltOffsetMultiplier, 1, node.timeAltDays); | ||
const nextTimeOffset = node.positionConfig.getFloatProp(node, undefined, node.timeAltOffsetType, node.timeAltOffset); | ||
node.nextTimeAltData = node.positionConfig.getTimeProp(node, undefined, node.timeAltType, node.timeAlt, nextTimeOffset, node.timeAltOffsetMultiplier, 1, node.timeAltDays); | ||
if (node.nextTimeAltData.error) { | ||
errorStatus = "could not evaluate alternate time"; | ||
node.error(node.nextTimeAltData.error); | ||
//console.log('2'); | ||
errorStatus = 'could not evaluate alternate time'; | ||
node.nextTimeAlt = null; | ||
isFixedTime = false; | ||
if (_onInit === true) { | ||
retriggerOnInit(node, errorStatus, node.nextTimeAltData.error); | ||
return; | ||
} | ||
node.error(node.nextTimeAltData.error); | ||
node.debug('nextTimeAltData: ' + util.inspect(node.nextTimeAltData)); | ||
} else { | ||
@@ -212,13 +197,13 @@ node.nextTimeAlt = node.nextTimeAltData.value; | ||
} | ||
if (node.nextTime && !errorStatus) { | ||
if ((node.nextTime !== null) && (errorStatus === '')) { | ||
if (!(node.nextTime instanceof Date) || node.nextTime === 'Invalid Date' || isNaN(node.nextTime)) { | ||
//node.debug(node.nextTime); | ||
hlp.errorHandler(this, new Error('Invalid Date'), 'Invalid time format', 'internal error!'); | ||
hlp.handleError(this, 'Invalid time format', undefined, 'internal error!'); | ||
return; | ||
} | ||
let millis = tsGetScheduleTime(node.nextTime, 10); | ||
//node.debug('timeout ' + node.nextTime + ' is in ' + millis + 'ms'); | ||
let isAlt = (node.nextTimeAlt); | ||
const isAlt = (node.nextTimeAlt); | ||
if (isAlt) { | ||
let millisAlt = tsGetScheduleTime(node.nextTimeAlt, 10); | ||
const millisAlt = tsGetScheduleTime(node.nextTimeAlt, 10); | ||
if (millisAlt < millis) { | ||
@@ -229,4 +214,6 @@ millis = millisAlt; | ||
} | ||
// node.debug('timeout ' + node.nextTime + ' is in ' + millis + 'ms (isAlt=' + isAlt + ' isAltFirst=' + isAltFirst + ')'); | ||
node.timeOutObj = setTimeout((isAlt, isAltFirst) => { | ||
let msg = { | ||
const msg = { | ||
type: 'start', | ||
@@ -240,18 +227,19 @@ timeData: {} | ||
try { | ||
let res = RED.util.evaluateNodeProperty(node.property, node.propertyType, node, msg); | ||
useAlternateTime = ((res == true) || (res == 'true')); | ||
const res = RED.util.evaluateNodeProperty(node.property, node.propertyType, node, msg); | ||
useAlternateTime = hlp.isTrue(res); | ||
needsRecalc = (isAltFirst && !useAlternateTime) || (!isAltFirst && useAlternateTime); | ||
} catch (err) { | ||
needsRecalc = isAltFirst; | ||
hlp.errorHandler(node, err, RED._("time-inject.errors.invalid-property-type", { | ||
hlp.handleError(node, RED._('time-inject.errors.invalid-property-type', { | ||
type: node.propertyType, | ||
value: node.property | ||
})); | ||
node.log('Error: ' + util.inspect(err)); | ||
}), err); | ||
} | ||
if (needsRecalc) { | ||
try { | ||
doCreateTimeout(node, msg); | ||
node.debug('needsRecalc'); | ||
doCreateTimeout(node); | ||
} catch (err) { | ||
hlp.errorHandler(node, err, RED._("time-inject.errors.error-text"), RED._("time-inject.errors.error-title")); | ||
hlp.handleError(node, RED._('time-inject.errors.error-text'), err, RED._('time-inject.errors.error-title')); | ||
} | ||
@@ -261,2 +249,3 @@ return; | ||
} | ||
if (useAlternateTime && node.nextTimeAltData) { | ||
@@ -267,11 +256,10 @@ msg.timeData = node.nextTimeAltData; | ||
} | ||
//node.debug('redo doCreateTimeout'); | ||
node.emit("input", msg); | ||
node.emit('input', msg); | ||
}, millis, isAlt, isAltFirst); | ||
} | ||
if (!isFixedTime && !node.intervalObj) { | ||
if (!isFixedTime && !node.intervalObj && (_onInit !== true)) { | ||
node.intervalObj = setInterval(() => { | ||
//node.debug('retrigger timecalc'); | ||
doCreateTimeout(node, msg); | ||
node.debug('retriggered'); | ||
doCreateTimeout(node); | ||
}, node.recalcTime); | ||
@@ -283,13 +271,19 @@ } else if (isFixedTime && node.intervalObj) { | ||
if (errorStatus) { | ||
if ((errorStatus !== '')) { | ||
if (_onInit === true) { | ||
retriggerOnInit(node, errorStatus, errorStatus); | ||
return; | ||
} | ||
node.status({ | ||
fill: "red", | ||
shape: "dot", | ||
text: errorStatus + ((node.intervalObj) ? ' 🖩' : '') | ||
fill: 'red', | ||
shape: 'dot', | ||
text: errorStatus + ((node.intervalObj) ? ' ↺🖩' : '') | ||
}); | ||
// if an error occurred, will retry in 10 minutes. This will prevent errors on initialization. | ||
} else if (node.nextTimeAlt && node.timeOutObj) { | ||
if (isAltFirst) { | ||
node.status({ | ||
fill: "green", | ||
shape: "ring", | ||
fill: 'green', | ||
shape: 'ring', | ||
text: node.nextTimeAlt.toLocaleString() + ' / ' + node.nextTime.toLocaleTimeString() | ||
@@ -299,4 +293,4 @@ }); | ||
node.status({ | ||
fill: "green", | ||
shape: "dot", | ||
fill: 'green', | ||
shape: 'dot', | ||
text: node.nextTime.toLocaleString() + ' / ' + node.nextTimeAlt.toLocaleTimeString() | ||
@@ -307,4 +301,4 @@ }); | ||
node.status({ | ||
fill: "green", | ||
shape: "dot", | ||
fill: 'green', | ||
shape: 'dot', | ||
text: node.nextTime.toLocaleString() | ||
@@ -317,6 +311,7 @@ }); | ||
this.on('close', function() { | ||
this.on('close', () => { | ||
if (node.timeOutObj) { | ||
clearTimeout(node.timeOutObj); | ||
} | ||
if (node.intervalObj) { | ||
@@ -330,9 +325,12 @@ clearInterval(node.intervalObj); | ||
try { | ||
doCreateTimeout(node, msg); | ||
node.debug('input ' + util.inspect(msg)); | ||
doCreateTimeout(node); | ||
msg.topic = config.topic; | ||
if (!node.positionConfig) { | ||
throw new Error('configuration missing!'); | ||
} | ||
let value = tsGetPropData(this, msg, config.payloadType, config.payload); | ||
if (value == null || (typeof value === 'undefined')) { | ||
throw new Error("could not evaluate " + config.payloadType + '.' + config.payload); | ||
const value = tsGetPropData(this, msg, config.payloadType, config.payload, config.payloadTimeFormat, node.payloadOffset, config.payloadOffsetType, config.payloadOffsetMultiplier); | ||
if (value === null || (typeof value === 'undefined')) { | ||
throw new Error('could not evaluate ' + config.payloadType + '.' + config.payload); | ||
} else if (value.error) { | ||
@@ -344,28 +342,52 @@ throw new Error('could not getting payload: ' + value.error); | ||
tsSetAddProp(this, msg, config.addPayload1Type, config.addPayload1, config.addPayload1ValueType, config.addPayload1Value, config.addPayload1Format, config.addPayload1Offset, config.addPayload1Days); | ||
tsSetAddProp(this, msg, config.addPayload2Type, config.addPayload2, config.addPayload2ValueType, config.addPayload2Value, config.addPayload2Format, config.addPayload2Offset, config.addPayload2Days); | ||
tsSetAddProp(this, msg, config.addPayload3Type, config.addPayload3, config.addPayload3ValueType, config.addPayload3Value, config.addPayload3Format, config.addPayload3Offset, config.addPayload3Days); | ||
tsSetAddProp(this, msg, config.addPayload1Type, config.addPayload1, config.addPayload1ValueType, config.addPayload1Value, | ||
config.addPayload1Format, config.addPayload1Offset, config.addPayload1OffsetType, config.addPayload1OffsetMultiplier, config.addPayload1Days); | ||
tsSetAddProp(this, msg, config.addPayload2Type, config.addPayload2, config.addPayload2ValueType, config.addPayload2Value, | ||
config.addPayload2Format, config.addPayload2Offset, config.addPayload2OffsetType, config.addPayload2OffsetMultiplier, config.addPayload2Days); | ||
tsSetAddProp(this, msg, config.addPayload3Type, config.addPayload3, config.addPayload3ValueType, config.addPayload3Value, | ||
config.addPayload3Format, config.addPayload3Offset, config.addPayload3OffsetType, config.addPayload3OffsetMultiplier, config.addPayload3Days); | ||
node.send(msg); | ||
} catch (err) { | ||
hlp.errorHandler(this, err, RED._("time-inject.errors.error-text"), RED._("time-inject.errors.error-title")); | ||
hlp.handleError(this, RED._('time-inject.errors.error-text'), err, RED._('time-inject.errors.error-title')); | ||
} | ||
}); | ||
try { | ||
if (config.once) { | ||
config.onceTimeout = setTimeout(function() { | ||
node.emit("input", { | ||
node.status({}); | ||
if (config.once) { | ||
try { | ||
node.status({ | ||
fill: 'yellow', | ||
shape: 'ring', | ||
text: RED._('time-inject.message.onceDelay', { seconds: (config.onceDelay || 0.1)}) | ||
}); | ||
config.onceTimeout = setTimeout(() => { | ||
node.emit('input', { | ||
type: 'once' | ||
}); | ||
doCreateTimeout(node, undefined); | ||
doCreateTimeout(node); | ||
}, (config.onceDelay || 0.1) * 1000); | ||
} else { | ||
doCreateTimeout(node, undefined); | ||
} catch (err) { | ||
hlp.handleError(this, RED._('time-inject.errors.error-text'), err, RED._('time-inject.errors.error-title')); | ||
} | ||
return; | ||
} | ||
try { | ||
doCreateTimeout(node, true); | ||
} catch (err) { | ||
hlp.errorHandler(this, err, RED._("time-inject.errors.error-text"), RED._("time-inject.errors.error-title")); | ||
hlp.handleError(this, RED._('time-inject.errors.error-text'), err, RED._('time-inject.errors.error-title')); | ||
} | ||
} | ||
RED.nodes.registerType('time-inject', timeInjectNode); | ||
RED.httpAdmin.get('/sun-position/js/*', RED.auth.needsPermission('sun-position.read'), (req,res) => { | ||
const options = { | ||
root: __dirname + '/static/', | ||
dotfiles: 'deny' | ||
}; | ||
res.sendFile(req.params[0], options); | ||
}); | ||
}; |
/******************************************** | ||
* within-time-switch: | ||
*********************************************/ | ||
"use strict"; | ||
'use strict'; | ||
const util = require('util'); | ||
const path = require('path'); | ||
const hlp = require(path.join(__dirname, '/lib/sunPosHelper.js')); | ||
const hlp = require(path.join(__dirname, '/lib/dateTimeHelper.js')); | ||
module.exports = function (RED) { | ||
"use strict"; | ||
'use strict'; | ||
function setstate(node, result, status, statusObj) { | ||
function setstate(node, result, status, statusObj, _onInit) { | ||
if (status > 255) { | ||
return result; | ||
return false; | ||
} | ||
if (result.start.error) { | ||
hlp.errorHandler(node, new Error('Error get start time:' + result.start.error), RED._("within-time-switch.errors.error-text"), result.start.error); | ||
if (_onInit === true) { | ||
node.status({ | ||
fill: 'red', | ||
shape: 'ring', | ||
text: RED._('within-time-switch..errors.error-init', result.start.error) | ||
}); | ||
node.warn(RED._('within-time-switch..errors.warn-init', result.start.error)); | ||
return true; | ||
} | ||
hlp.handleError(node, RED._('within-time-switch.errors.error-start-time', { message : result.start.error}), undefined, result.start.error); | ||
} else if (result.end.error) { | ||
hlp.errorHandler(node, new Error('Error get end time:' + result.end.error), RED._("within-time-switch.errors.error-text"), result.end.error); | ||
if (_onInit === true) { | ||
node.status({ | ||
fill: 'red', | ||
shape: 'ring', | ||
text: RED._('within-time-switch..errors.error-init', result.end.error) | ||
}); | ||
node.warn(RED._('within-time-switch..errors.warn-init', result.end.error)); | ||
return true; | ||
} | ||
hlp.handleError(node, RED._('within-time-switch.errors.error-end-time', { message : result.end.error}), undefined, result.end.error); | ||
} else if ((status & 2) && statusObj) { | ||
@@ -26,4 +45,4 @@ node.status(statusObj); | ||
node.status({ | ||
fill: "yellow", | ||
shape: "dot", | ||
fill: 'yellow', | ||
shape: 'dot', | ||
text: '⏲ ⏵' + result.start.value.toLocaleTimeString() + result.startSuffix + ' - ⏴' + result.end.value.toLocaleTimeString() + result.endSuffix | ||
@@ -33,13 +52,15 @@ }); | ||
node.status({}); | ||
/*node.status({ | ||
/* | ||
node.status({ | ||
fill: "red", | ||
shape: "dot", | ||
text: 'status not available' | ||
});*/ | ||
}); */ | ||
} | ||
return false; | ||
} | ||
function calcWithinTimes(node, msg, config, noState) { | ||
//node.debug('calcWithinTimes'); | ||
let result = { | ||
function calcWithinTimes(node, msg, config) { | ||
// node.debug('calcWithinTimes'); | ||
const result = { | ||
start: {}, | ||
@@ -51,16 +72,16 @@ end: {}, | ||
altEndTime: (node.propertyEndType !== 'none') && (msg || (node.propertyEndType !== 'msg')) | ||
} | ||
}; | ||
if (result.altStartTime) { | ||
//node.debug('alternate start times enabled ' + node.propertyStartType + '.' + node.propertyStart); | ||
// node.debug('alternate start times enabled ' + node.propertyStartType + '.' + node.propertyStart); | ||
try { | ||
//evaluateNodeProperty(node.property, type, node, msg, callback) | ||
let res = RED.util.evaluateNodeProperty(node.propertyStart, node.propertyStartType, node, msg); | ||
result.altStartTime = ((res == true) || (res == 'true')); | ||
// evaluateNodeProperty(node.property, type, node, msg, callback) | ||
const res = RED.util.evaluateNodeProperty(node.propertyStart, node.propertyStartType, node, msg); | ||
result.altStartTime = hlp.isTrue(res); | ||
} catch (err) { | ||
result.altStartTime = false; | ||
hlp.errorHandler(node, err, RED._("within-time-switch.errors.invalid-propertyStart-type", { | ||
hlp.handleError(node, RED._('within-time-switch.errors.invalid-propertyStart-type', { | ||
type: node.propertyStartType, | ||
value: node.propertyStart | ||
})); | ||
}), err); | ||
node.debug(util.inspect(err)); | ||
@@ -71,13 +92,13 @@ } | ||
if (result.altEndTime) { | ||
//node.debug('alternate end times enabled ' + node.propertyEndType + '.' + node.propertyEnd); | ||
// node.debug('alternate end times enabled ' + node.propertyEndType + '.' + node.propertyEnd); | ||
try { | ||
//evaluateNodeProperty(node.property, type, node, msg, callback) | ||
let res = RED.util.evaluateNodeProperty(node.propertyEnd, node.propertyEndType, node, msg); | ||
result.altEndTime = ((res == true) || (res == 'true')); | ||
// evaluateNodeProperty(node.property, type, node, msg, callback) | ||
const res = RED.util.evaluateNodeProperty(node.propertyEnd, node.propertyEndType, node, msg); | ||
result.altEndTime = hlp.isTrue(res); | ||
} catch (err) { | ||
result.altEndTime = false; | ||
hlp.errorHandler(node, err, RED._("within-time-switch.errors.invalid-propertyEnd-type", { | ||
hlp.handleError(node, RED._('within-time-switch.errors.invalid-propertyEnd-type', { | ||
type: node.propertyEndType, | ||
value: node.propertyEnd | ||
})); | ||
}), err); | ||
node.debug(util.inspect(err)); | ||
@@ -88,19 +109,20 @@ } | ||
if (result.altStartTime && config.startTimeAltType !== 'none') { | ||
//node.debug('using alternate start time ' + result.altStartTime + ' - ' + config.startTimeAltType); | ||
result.start = node.positionConfig.getTimeProp(node, msg, config.startTimeAltType, config.startTimeAlt, (config.startOffsetAlt || 0) * (config.startOffsetAltMultiplier || 60)); | ||
// node.debug('using alternate start time ' + result.altStartTime + ' - ' + config.startTimeAltType); | ||
result.start = node.positionConfig.getTimeProp(node, msg, config.startTimeAltType, config.startTimeAlt, config.startOffsetAlt, config.startOffsetAltMultiplier); | ||
result.startSuffix = '⎇ '; | ||
} else { | ||
//node.debug('using standard start time ' + result.altStartTime + ' - ' + config.startTimeAltType); | ||
result.start = node.positionConfig.getTimeProp(node, msg, config.startTimeType, config.startTime, (config.startOffset || 0) * (config.startOffsetMultiplier || 60)); | ||
// node.debug('using standard start time ' + result.altStartTime + ' - ' + config.startTimeAltType); | ||
result.start = node.positionConfig.getTimeProp(node, msg, config.startTimeType, config.startTime, config.startOffset, config.startOffsetMultiplier); | ||
} | ||
if (result.altEndTime && config.endTimeAltType !== 'none') { | ||
//node.debug('using alternate end time ' + result.altEndTime + ' - ' + config.startTimeAltType); | ||
result.end = node.positionConfig.getTimeProp(node, msg, config.endTimeAltType, config.endTimeAlt, (config.endOffsetAlt || 0) * (config.endOffsetAltMultiplier || 60)); | ||
// node.debug('using alternate end time ' + result.altEndTime + ' - ' + config.startTimeAltType); | ||
result.end = node.positionConfig.getTimeProp(node, msg, config.endTimeAltType, config.endTimeAlt, config.endOffsetAlt, config.endOffsetAltMultiplier); | ||
result.endSuffix = ' ⎇'; | ||
} else { | ||
//node.debug('using standard end time ' + result.altEndTime + ' - ' + config.startTimeAltType); | ||
result.end = node.positionConfig.getTimeProp(node, msg, config.endTimeType, config.endTime, (config.endOffset || 0) * (config.endOffsetMultiplier || 60)); | ||
// node.debug('using standard end time ' + result.altEndTime + ' - ' + config.startTimeAltType); | ||
result.end = node.positionConfig.getTimeProp(node, msg, config.endTimeType, config.endTime, config.endOffset, config.endOffsetMultiplier); | ||
} | ||
//node.debug(util.inspect(result, Object.getOwnPropertyNames(result))); | ||
// node.debug(util.inspect(result, Object.getOwnPropertyNames(result))); | ||
return result; | ||
@@ -110,7 +132,8 @@ } | ||
function getScheduleTime(time) { | ||
var now = new Date(); | ||
var millis = time.getTime() - now.getTime(); | ||
const now = new Date(); | ||
let millis = time.getTime() - now.getTime(); | ||
while (millis < 10) { | ||
millis += 86400000; //24h | ||
millis += 86400000; // 24h | ||
} | ||
return millis; | ||
@@ -124,6 +147,7 @@ } | ||
} | ||
if (!msg.reSendMsgDelayed && isActive && time) { | ||
node.lastMsgObj = RED.util.cloneMessage(msg); | ||
node.lastMsgObj.reSendMsgDelayed = false; | ||
let millis = getScheduleTime(time) + 10; | ||
const millis = getScheduleTime(time) + 10; | ||
node.debug('timeout for resend last message ' + time + ' is in ' + millis + 'ms'); | ||
@@ -135,3 +159,3 @@ node.timeOutObj = setTimeout(() => { | ||
node.lastMsgObj.reSendMsgDelayed = true; | ||
node.emit("input", node.lastMsgObj); | ||
node.emit('input', node.lastMsgObj); | ||
} | ||
@@ -146,23 +170,23 @@ }, millis); | ||
this.positionConfig = RED.nodes.getNode(config.positionConfig); | ||
//this.debug('initialize withinTimeSwitchNode ' + util.inspect(config)); | ||
// this.debug('initialize withinTimeSwitchNode ' + util.inspect(config)); | ||
this.propertyStart = config.propertyStart || ""; | ||
this.propertyEnd = config.propertyEnd || ""; | ||
this.propertyStartType = config.propertyStartType || "none"; | ||
this.propertyEndType = config.propertyEndType || "none"; | ||
this.propertyStart = config.propertyStart || ''; | ||
this.propertyEnd = config.propertyEnd || ''; | ||
this.propertyStartType = config.propertyStartType || 'none'; | ||
this.propertyEndType = config.propertyEndType || 'none'; | ||
this.timeOutObj = null; | ||
this.lastMsgObj = null; | ||
var node = this; | ||
const node = this; | ||
this.on('input', msg => { | ||
try { | ||
//this.debug('starting ' + util.inspect(msg, Object.getOwnPropertyNames(msg))); | ||
//this.debug('self ' + util.inspect(this, Object.getOwnPropertyNames(this))); | ||
//this.debug('config ' + util.inspect(config, Object.getOwnPropertyNames(config))); | ||
let result = calcWithinTimes(this, msg, config, true); | ||
// this.debug('starting ' + util.inspect(msg, Object.getOwnPropertyNames(msg))); | ||
// this.debug('self ' + util.inspect(this, Object.getOwnPropertyNames(this))); | ||
// this.debug('config ' + util.inspect(config, Object.getOwnPropertyNames(config))); | ||
const result = calcWithinTimes(this, msg, config); | ||
let now = new Date(); | ||
if ((typeof msg.ts === 'string') || (msg.ts instanceof Date)) { | ||
let dto = new Date(msg.ts); | ||
if (dto !== "Invalid Date" && !isNaN(dto)) { | ||
const dto = new Date(msg.ts); | ||
if (dto !== 'Invalid Date' && !isNaN(dto)) { | ||
now = dto; | ||
@@ -176,41 +200,40 @@ } | ||
let startNr = hlp.getTimeNumber(result.start.value); | ||
let endNr = hlp.getTimeNumber(result.end.value); | ||
let cmpNow = hlp.getTimeNumber(now); | ||
let status = (config.statusOut || 3); | ||
const startNr = hlp.getTimeNumber(result.start.value); | ||
const endNr = hlp.getTimeNumber(result.end.value); | ||
const cmpNow = hlp.getTimeNumber(now); | ||
const status = (config.statusOut || 3); | ||
if (startNr < endNr) { | ||
if (cmpNow >= startNr && cmpNow < endNr) { | ||
//this.debug('compare in time 1 ' + startNr + ' - ' + cmpNow + ' - ' + endNr); | ||
// this.debug('compare in time 1 ' + startNr + ' - ' + cmpNow + ' - ' + endNr); | ||
this.send([msg, null]); | ||
setstate(this, result, status, { | ||
fill: "green", | ||
shape: "ring", | ||
fill: 'green', | ||
shape: 'ring', | ||
text: '🖅 ' + result.startSuffix + now.toLocaleString() + result.endSuffix | ||
}); | ||
}, false); | ||
checkReSendMsgDelayed(config.lastMsgOnEndOut, this, result.end.value, msg); | ||
return null; | ||
} | ||
} else { | ||
if (!(cmpNow >= endNr && cmpNow < startNr)) { | ||
//this.debug('compare in time 2 ' + startNr + ' - ' + cmpNow + ' - ' + endNr); | ||
this.send([msg, null]); | ||
setstate(this, result, status, { | ||
fill: "green", | ||
shape: "dot", | ||
text: '🖅 ' + result.startSuffix + now.toLocaleString() + result.endSuffix | ||
}); | ||
checkReSendMsgDelayed(config.lastMsgOnEndOut, this, result.end.value, msg); | ||
return null; | ||
} | ||
} else if (!(cmpNow >= endNr && cmpNow < startNr)) { | ||
// this.debug('compare in time 2 ' + startNr + ' - ' + cmpNow + ' - ' + endNr); | ||
this.send([msg, null]); | ||
setstate(this, result, status, { | ||
fill: 'green', | ||
shape: 'dot', | ||
text: '🖅 ' + result.startSuffix + now.toLocaleString() + result.endSuffix | ||
}, false); | ||
checkReSendMsgDelayed(config.lastMsgOnEndOut, this, result.end.value, msg); | ||
return null; | ||
} | ||
//this.debug('compare out of time ' + startNr + ' - ' + cmpNow + ' - ' + endNr); | ||
// this.debug('compare out of time ' + startNr + ' - ' + cmpNow + ' - ' + endNr); | ||
this.send([null, msg]); | ||
setstate(this, result, status, { | ||
fill: "yellow", | ||
shape: "dot", | ||
fill: 'yellow', | ||
shape: 'dot', | ||
text: '⛔' + result.startSuffix + now.toLocaleString() + result.endSuffix | ||
}); | ||
}, false); | ||
checkReSendMsgDelayed(config.lastMsgOnStartOut, this, result.start.value, msg); | ||
} catch (err) { | ||
hlp.errorHandler(this, err, RED._("within-time-switch.errors.error-text"), RED._("within-time-switch.errors.error-title")); | ||
hlp.handleError(this, RED._('within-time-switch.errors.error-text'), err, RED._('within-time-switch.errors.error-title')); | ||
} | ||
@@ -221,9 +244,29 @@ }); | ||
node.status({}); | ||
let result = calcWithinTimes(this, null, config, true); | ||
setstate(this, result, (config.statusOut || 3)); | ||
const result = calcWithinTimes(this, null, config); | ||
// if an error occured, will retry in 6 minutes. This will prevent errors on initialisation. | ||
if (setstate(this, result, (config.statusOut || 3), null, true)) { | ||
node.debug('node is in initialisation, retrigger time calculation in 6 min'); | ||
setTimeout(() => { | ||
try { | ||
const result = calcWithinTimes(this, null, config); | ||
setstate(this, result, (config.statusOut || 3)); | ||
} catch (err) { | ||
hlp.handleError(this, RED._('within-time-switch.errors.error-text'), err, RED._('within-time-switch.errors.error-title')); | ||
} | ||
}, 360000); // 6 Minuten | ||
} | ||
} catch (err) { | ||
hlp.errorHandler(this, err, RED._("within-time-switch.errors.error-text"), RED._("within-time-switch.errors.error-title")); | ||
hlp.handleError(this, RED._('within-time-switch.errors.error-text'), err, RED._('within-time-switch.errors.error-title')); | ||
} | ||
} | ||
RED.nodes.registerType('within-time-switch', withinTimeSwitchNode); | ||
RED.httpAdmin.get('/sun-position/js/*', RED.auth.needsPermission('sun-position.read'), (req,res) => { | ||
const options = { | ||
root: __dirname + '/static/', | ||
dotfiles: 'deny' | ||
}; | ||
res.sendFile(req.params[0], options); | ||
}); | ||
}; |
309
package.json
{ | ||
"name": "node-red-contrib-sun-position", | ||
"version": "0.1.16", | ||
"description": "NodeRED nodes to get sun and moon position", | ||
"main": "none", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"predev": "npm i -g", | ||
"dev": "node-red -v" | ||
"name": "node-red-contrib-sun-position", | ||
"version": "0.2.0-alpha.2", | ||
"description": "NodeRED nodes to get sun and moon position", | ||
"keywords": [ | ||
"node-red", | ||
"nodes", | ||
"flow", | ||
"sun-position", | ||
"moon-position", | ||
"heavenly body", | ||
"sun", | ||
"sun events", | ||
"moon", | ||
"moon events", | ||
"position", | ||
"luminary", | ||
"suncalc", | ||
"mooncalc", | ||
"node-red", | ||
"router", | ||
"switch", | ||
"inject", | ||
"timer", | ||
"time", | ||
"timeswitch", | ||
"timerswitch", | ||
"timespan", | ||
"time-range", | ||
"time-range-switch", | ||
"timecheck", | ||
"time-calc", | ||
"time-comp", | ||
"time-compare", | ||
"time-span", | ||
"time-offset", | ||
"compare", | ||
"clock", | ||
"schedule", | ||
"compare", | ||
"calculate", | ||
"redmatic" | ||
], | ||
"main": "none", | ||
"engines": { | ||
"node": ">=8.0.0" | ||
}, | ||
"scripts": { | ||
"test": "camo-purge; eslint \"./**/*.js\" \"./**/*.html\"", | ||
"lintfix": "eslint --fix \"./**/*.js\" \"./**/*.html\"", | ||
"lint": "eslint \"./**/*.js\" \"./**/*.html\"", | ||
"predev": "npm i -g", | ||
"dev": "node-red -v", | ||
"prepublishOnly": "eslint \"./**/*.js\" \"./**/*.html\"" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/HM-RedMatic/node-red-contrib-sun-position.git" | ||
}, | ||
"author": { | ||
"name": "Hypnos3", | ||
"email": "hypnos3@online.de", | ||
"url": "https://github.com/hypnos3" | ||
}, | ||
"contributors": [ | ||
{ | ||
"name": "Hypnos3", | ||
"url": "https://github.com/hypnos3" | ||
} | ||
], | ||
"license": "Apache-2.0", | ||
"bugs": { | ||
"url": "https://github.com/HM-RedMatic/node-red-contrib-sun-position/issues" | ||
}, | ||
"homepage": "https://github.com/HM-RedMatic/node-red-contrib-sun-position#readme", | ||
"node-red": { | ||
"nodes": { | ||
"position-config": "nodes/position-config.js", | ||
"sun-position": "nodes/sun-position.js", | ||
"moon-position": "nodes/moon-position.js", | ||
"within-time-switch": "nodes/within-time-switch.js", | ||
"time-inject": "nodes/time-inject.js", | ||
"time-comp": "nodes/time-comp.js", | ||
"time-span": "nodes/time-span.js" | ||
} | ||
}, | ||
"dependencies": { | ||
"util": ">=0.10.0" | ||
}, | ||
"devDependencies": { | ||
"camo-purge": "^1.0.2", | ||
"eslint": "^5.12.0", | ||
"eslint-plugin-html": "^5.0.0", | ||
"eslint-plugin-jsdoc": "^4.1.0" | ||
}, | ||
"eslintConfig": { | ||
"env": { | ||
"es6": true, | ||
"node": true, | ||
"browser": true, | ||
"commonjs": true, | ||
"jquery": true | ||
}, | ||
"author": { | ||
"name": "Hypnos3", | ||
"email": "hypnos3@online.de", | ||
"url": "https://github.com/hypnos3" | ||
}, | ||
"contributors": [{ | ||
"name": "Hypnos3", | ||
"url": "https://github.com/hypnos3" | ||
}], | ||
"keywords": [ | ||
"node-red", | ||
"nodes", | ||
"flow", | ||
"sun-position", | ||
"moon-position", | ||
"heavenly body", | ||
"sun", | ||
"sun events", | ||
"moon", | ||
"moon events", | ||
"position", | ||
"luminary", | ||
"suncalc", | ||
"mooncalc", | ||
"node-red", | ||
"router", | ||
"switch", | ||
"inject", | ||
"timer", | ||
"time", | ||
"timeswitch", | ||
"timerswitch", | ||
"time-range", | ||
"time-range-switch", | ||
"timecheck", | ||
"compare", | ||
"clock", | ||
"schedule" | ||
"plugins": [ | ||
"html", | ||
"jsdoc" | ||
], | ||
"homepage": "https://github.com/HM-RedMatic/node-red-contrib-sun-position", | ||
"license": "Apache-2.0", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/HM-RedMatic/node-red-contrib-sun-position" | ||
"extends": "eslint:recommended", | ||
"settings": { | ||
"html/html-extensions": [ | ||
".html", | ||
".htm", | ||
".we" | ||
], | ||
"html/indent": "+4", | ||
"html/report-bad-indent": "error", | ||
"import/resolver": { | ||
"node": { | ||
"extensions": [ | ||
".js", | ||
".jsx" | ||
] | ||
} | ||
} | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/HM-RedMatic/node-red-contrib-sun-position/issues" | ||
"globals": { | ||
"RED": true | ||
}, | ||
"node-red": { | ||
"nodes": { | ||
"position-config": "nodes/position-config.js", | ||
"sun-position": "nodes/sun-position.js", | ||
"moon-position": "nodes/moon-position.js", | ||
"within-time-switch": "nodes/within-time-switch.js", | ||
"time-inject": "nodes/time-inject.js" | ||
"parserOptions": { | ||
"ecmaVersion": 2018, | ||
"sourceType": "module" | ||
}, | ||
"rules": { | ||
"indent": [ | ||
"error", | ||
4, | ||
{ | ||
"SwitchCase": 1 | ||
} | ||
}, | ||
"dependencies": { | ||
"util": ">=0.10.0" | ||
}, | ||
"extensions": [ | ||
"js", | ||
"html" | ||
] | ||
} | ||
], | ||
"max-len": [ | ||
"error", | ||
{ | ||
"code": 250, | ||
"ignoreComments": true, | ||
"ignoreTrailingComments": true, | ||
"ignoreUrls": true, | ||
"ignoreRegExpLiterals": true, | ||
"ignoreTemplateLiterals": true | ||
} | ||
], | ||
"no-eq-null": "error", | ||
"eqeqeq": "error", | ||
"no-else-return": "error", | ||
"prefer-arrow-callback": "error", | ||
"no-console": "warn", | ||
"no-unused-vars": [ | ||
"error", | ||
{ | ||
"args": "after-used", | ||
"argsIgnorePattern": "^_" | ||
} | ||
], | ||
"no-unused-expressions": "warn", | ||
"no-useless-escape": "warn", | ||
"no-constant-condition": "off", | ||
"no-multiple-empty-lines": [ | ||
"error", | ||
{ | ||
"max": 2, | ||
"maxEOF": 1 | ||
} | ||
], | ||
"no-var": "error", | ||
"prefer-const": "error", | ||
"linebreak-style": [ | ||
"warn", | ||
"unix" | ||
], | ||
"brace-style": [ | ||
2, | ||
"1tbs", | ||
{ | ||
"allowSingleLine": true | ||
} | ||
], | ||
"quotes": [ | ||
"warn", | ||
"single", | ||
{ | ||
"avoidEscape": true, | ||
"allowTemplateLiterals": true | ||
} | ||
], | ||
"semi": [ | ||
"error", | ||
"always" | ||
], | ||
"comma-dangle": [ | ||
"error", | ||
{ | ||
"arrays": "never", | ||
"objects": "never", | ||
"imports": "never", | ||
"exports": "never", | ||
"functions": "ignore" | ||
} | ||
], | ||
"no-trailing-spaces": "error", | ||
"spaced-comment": [ | ||
"warn", | ||
"always", | ||
{ | ||
"line": { | ||
"markers": [ | ||
"/", | ||
"*" | ||
], | ||
"exceptions": [ | ||
"-", | ||
"+", | ||
"*", | ||
"#" | ||
] | ||
}, | ||
"block": { | ||
"markers": [ | ||
"!" | ||
], | ||
"exceptions": [ | ||
"-", | ||
"+", | ||
"*", | ||
"#" | ||
], | ||
"balanced": true | ||
} | ||
} | ||
], | ||
"eol-last": [ | ||
"error", | ||
"never" | ||
] | ||
} | ||
} | ||
} |
436
README.md
@@ -18,3 +18,3 @@ # node-red-contrib-sun-position for NodeRED | ||
This is a ultimate Node-Red Timer based flow control with dusk, dawn (and variations) and much more. | ||
Addidional you can get sun and moon position or to control a flow by sun or moon position. It is ideal for usage of control smart home, but also for all other time based flow control. | ||
Additional you can get sun and moon position or to control a flow by sun or moon position. It is ideal for usage of control smart home, but also for all other time based flow control. | ||
@@ -26,22 +26,42 @@ ![nodes](images/appearance1.png?raw=true) | ||
[TOC] | ||
- [Installation](#installation) | ||
- [Quick Start](#quick-start) | ||
- [General](#general) | ||
- [Saving resources](#saving-resources) | ||
- [second based accuracy](#second-based-accuracy) | ||
- [Implemented Nodes](#implemented-nodes) | ||
- [sun-position](#sun-position) | ||
- [Node settings](#node-settings) | ||
- [sun-position - Node settings](#sun-position---node-settings) | ||
- [Node Input](#node-input) | ||
- [Node Output](#node-output) | ||
- [sun-position -Node Output](#sun-position---node-output) | ||
- [moon-position](#moon-position) | ||
- [Node settings](#node-settings-1) | ||
- [Node Input](#node-input-1) | ||
- [Node Output](#node-output-1) | ||
- [moon-position - Node settings](#moon-position---node-settings) | ||
- [moon-position - Node Output](#moon-position---node-output) | ||
- [time-inject](#time-inject) | ||
- [Node settings](#node-settings-2) | ||
- [Node Input](#node-input-2) | ||
- [Node Output](#node-output-2) | ||
- [time-inject - Node settings](#time-inject---node-settings) | ||
- [time-inject - Node Input](#time-inject---node-input) | ||
- [time-inject - Node Output](#time-inject---node-output) | ||
- [within-time](#within-time) | ||
- [Node settings](#node-settings-3) | ||
- [times definitions](#times-definitions) | ||
- [within-time - Node settings](#within-time---node-settings) | ||
- [time-comp](#time-comp) | ||
- [time-comp - Node settings](#time-comp---node-settings) | ||
- [time-span](#time-span) | ||
- [time-span - Node settings](#time-span---node-settings) | ||
- [Times definitions](#times-definitions) | ||
- [sun times](#sun-times) | ||
- [remarks](#remarks) | ||
- [blue hour](#blue-hour) | ||
- [amateurDawn /amateurDusk](#amateurdawn--amateurdusk) | ||
- [alternate properties](#alternate-properties) | ||
- [moon times](#moon-times) | ||
- [message, flow or global property or JSONATA expression](#message--flow-or-global-property-or-jsonata-expression) | ||
- [input parse formats](#input-parse-formats) | ||
- [output timestamp formats](#output-timestamp-formats) | ||
- [output timespan formats](#output-timespan-formats) | ||
- [TODO](#todo) | ||
- [Bugs and Feedback](#bugs-and-feedback) | ||
- [LICENSE](#LICENSE) | ||
- [LICENSE](#license) | ||
- [Other](#other) | ||
@@ -79,11 +99,11 @@ ## Installation | ||
``` | ||
```json | ||
[{"id":"fc962ea1.197a3","type":"inject","z":"de4e9c38.0d942","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":300,"wires":[["56265aeb.99f034"]]},{"id":"a0d0e562.7ad1d8","type":"debug","z":"de4e9c38.0d942","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":570,"y":300,"wires":[]},{"id":"56265aeb.99f034","type":"sun-position","z":"de4e9c38.0d942","name":"","positionConfig":"2831ba70.55a636","rules":[{"valueLow":"10","valueLowType":"num","valueHigh":"100","valueHighType":"num"}],"onlyOnChange":"true","topic":"","outputs":2,"x":330,"y":300,"wires":[["a0d0e562.7ad1d8","9cc2d51.4ac0828","28e91.9d63d16f6"],["e921e01a.a0fa3"]]},{"id":"9cc2d51.4ac0828","type":"change","z":"de4e9c38.0d942","name":"azimuth","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.azimuth","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":340,"wires":[["e866e950.a7f798"]]},{"id":"28e91.9d63d16f6","type":"change","z":"de4e9c38.0d942","name":"altitude","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.altitude","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":380,"wires":[["5b085e1b.4ec8a"]]},{"id":"e921e01a.a0fa3","type":"debug","z":"de4e9c38.0d942","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":550,"y":420,"wires":[]},{"id":"e866e950.a7f798","type":"debug","z":"de4e9c38.0d942","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":750,"y":340,"wires":[]},{"id":"5b085e1b.4ec8a","type":"debug","z":"de4e9c38.0d942","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":750,"y":380,"wires":[]},{"id":"2831ba70.55a636","type":"position-config","z":"","name":"Kap-Halbinsel","longitude":"-34.357051","latitude":"18.473782","angleType":"deg"}] | ||
``` | ||
#### Node settings | ||
#### sun-position - Node settings | ||
![sun-position](images/sun-position-settings.png?raw=true) | ||
- **Position** defines the current position. | ||
- **Position** connects to the central configuration node, which contains the current position, but also handles internal shared functions | ||
- **Topic** defines the topic of the first output | ||
@@ -97,3 +117,3 @@ - **position container** here you can define multiple lower and upepr limits for azimuth. If the calculated value of the azimuth is inside the defined limit the input message will send to the associated output. | ||
#### Node Output | ||
#### sun-position - Node Output | ||
@@ -126,42 +146,42 @@ - **first output** | ||
```json | ||
{ | ||
"lastUpdate": "2018-11-11T11:11:11.111Z", | ||
"latitude": "18.473782", | ||
"longitude": "-34.357051", | ||
"angleType": "deg", | ||
"azimuth": 117.72942647370792, | ||
"altitude": 20.984193272523992, | ||
"times": { | ||
"solarNoon":"2018-12-10T10:59:14.814Z", | ||
"nadir":"2018-12-10T22:59:14.814Z", | ||
"sunrise":"2018-12-10T06:58:55.584Z", | ||
"sunset":"2018-12-10T14:59:34.044Z", | ||
"sunriseEnd":"2018-12-10T07:03:12.232Z", | ||
"sunsetStart":"2018-12-10T14:55:17.395Z", | ||
"blueHourDawnEnd":"2018-12-10T06:34:22.885Z", | ||
"blueHourDuskStart":"2018-12-10T15:24:06.743Z", | ||
"civilDawn":"2018-12-10T06:19:31.249Z", | ||
"civilDusk":"2018-12-10T15:38:58.379Z", | ||
"blueHourDawnStart":"2018-12-10T06:05:03.443Z", | ||
"blueHourDuskEnd":"2018-12-10T15:53:26.185Z", | ||
"nauticalDawn":"2018-12-10T05:37:04.859Z", | ||
"nauticalDusk":"2018-12-10T16:21:24.768Z", | ||
"amateurDawn":"2018-12-10T05:16:44.832Z", | ||
"amateurDusk":"2018-12-10T16:41:44.795Z", | ||
"astronomicalDawn":"2018-12-10T04:56:49.931Z", | ||
"astronomicalDusk":"2018-12-10T17:01:39.696Z", | ||
"goldenHourEnd":"2018-12-10T07:58:28.541Z", | ||
"goldenHourStart":"2018-12-10T14:00:01.086Z", | ||
"dawn":"2018-12-10T06:19:31.249Z", | ||
"dusk":"2018-12-10T15:38:58.379Z", | ||
"nightEnd":"2018-12-10T04:56:49.931Z", | ||
"night":"2018-12-10T17:01:39.696Z", | ||
"nightStart":"2018-12-10T17:01:39.696Z", | ||
"goldenHour":"2018-12-10T14:00:01.086Z" | ||
}, | ||
"pos": [], | ||
"posChanged": false | ||
} | ||
``` | ||
{ | ||
"lastUpdate": "2018-11-11T11:11:11.111Z", | ||
"latitude": "18.473782", | ||
"longitude": "-34.357051", | ||
"angleType": "deg", | ||
"azimuth": 117.72942647370792, | ||
"altitude": 20.984193272523992, | ||
"times": { | ||
"solarNoon":"2018-12-10T10:59:14.814Z", | ||
"nadir":"2018-12-10T22:59:14.814Z", | ||
"sunrise":"2018-12-10T06:58:55.584Z", | ||
"sunset":"2018-12-10T14:59:34.044Z", | ||
"sunriseEnd":"2018-12-10T07:03:12.232Z", | ||
"sunsetStart":"2018-12-10T14:55:17.395Z", | ||
"blueHourDawnEnd":"2018-12-10T06:34:22.885Z", | ||
"blueHourDuskStart":"2018-12-10T15:24:06.743Z", | ||
"civilDawn":"2018-12-10T06:19:31.249Z", | ||
"civilDusk":"2018-12-10T15:38:58.379Z", | ||
"blueHourDawnStart":"2018-12-10T06:05:03.443Z", | ||
"blueHourDuskEnd":"2018-12-10T15:53:26.185Z", | ||
"nauticalDawn":"2018-12-10T05:37:04.859Z", | ||
"nauticalDusk":"2018-12-10T16:21:24.768Z", | ||
"amateurDawn":"2018-12-10T05:16:44.832Z", | ||
"amateurDusk":"2018-12-10T16:41:44.795Z", | ||
"astronomicalDawn":"2018-12-10T04:56:49.931Z", | ||
"astronomicalDusk":"2018-12-10T17:01:39.696Z", | ||
"goldenHourEnd":"2018-12-10T07:58:28.541Z", | ||
"goldenHourStart":"2018-12-10T14:00:01.086Z", | ||
"dawn":"2018-12-10T06:19:31.249Z", | ||
"dusk":"2018-12-10T15:38:58.379Z", | ||
"nightEnd":"2018-12-10T04:56:49.931Z", | ||
"night":"2018-12-10T17:01:39.696Z", | ||
"nightStart":"2018-12-10T17:01:39.696Z", | ||
"goldenHour":"2018-12-10T14:00:01.086Z" | ||
}, | ||
"pos": [], | ||
"posChanged": false | ||
} | ||
``` | ||
@@ -176,11 +196,11 @@ - **second output** to **... output** if limits for azimuth are defined the incomming message will send to this output. It adds a `msg.posChanged` property of type _boolean_ which is true if in the previous calculation no message was send to this output. | ||
``` | ||
```json | ||
[{"id":"d99ac08d.fdb94","type":"moon-position","z":"de4e9c38.0d942","name":"","positionConfig":"2831ba70.55a636","rules":[],"outputs":1,"topic":"","x":340,"y":520,"wires":[["e5e8e9a1.6080e8","e9ec273d.d90168","45563d84.0c4bf4","cce94ccc.b2dd2","65c76f28.3dd49","ac44c210.86465","f2deae49.60015","a9e0a2d1.0633a","948f6e2.8a4a39","cc85e458.447ba8","bff5a621.3fb498"]]},{"id":"124bfd72.dcb2f3","type":"inject","z":"de4e9c38.0d942","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":520,"wires":[["d99ac08d.fdb94"]]},{"id":"e5e8e9a1.6080e8","type":"debug","z":"de4e9c38.0d942","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":590,"y":520,"wires":[]},{"id":"e9ec273d.d90168","type":"change","z":"de4e9c38.0d942","name":"azimuth","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.azimuth","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":580,"y":560,"wires":[[]]},{"id":"45563d84.0c4bf4","type":"change","z":"de4e9c38.0d942","name":"altitude","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.altitude","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":580,"y":600,"wires":[[]]},{"id":"cce94ccc.b2dd2","type":"change","z":"de4e9c38.0d942","name":"distance","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.distance","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":580,"y":640,"wires":[[]]},{"id":"65c76f28.3dd49","type":"change","z":"de4e9c38.0d942","name":"parallacticAngle","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.parallacticAngle","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":600,"y":680,"wires":[[]]},{"id":"ac44c210.86465","type":"change","z":"de4e9c38.0d942","name":"illumination angle","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.illumination.angle","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":610,"y":720,"wires":[[]]},{"id":"f2deae49.60015","type":"change","z":"de4e9c38.0d942","name":"illumination fraction","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.illumination.fraction","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":610,"y":760,"wires":[[]]},{"id":"a9e0a2d1.0633a","type":"change","z":"de4e9c38.0d942","name":"illumination phase","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.illumination.phase.value","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":610,"y":800,"wires":[[]]},{"id":"948f6e2.8a4a39","type":"change","z":"de4e9c38.0d942","name":"illumination phase angle","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.illumination.phase.angle","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":840,"wires":[[]]},{"id":"bff5a621.3fb498","type":"change","z":"de4e9c38.0d942","name":"illumination zenithAngle","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.illumination.zenithAngle","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":920,"wires":[[]]},{"id":"cc85e458.447ba8","type":"change","z":"de4e9c38.0d942","name":"illumination phase name","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.illumination.phase.name","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":880,"wires":[[]]},{"id":"2831ba70.55a636","type":"position-config","z":"","name":"Kap-Halbinsel","longitude":"-34.357051","latitude":"18.473782","angleType":"deg"}] | ||
``` | ||
#### Node settings | ||
#### moon-position - Node settings | ||
![moon-position](images/sun-position-settings.png?raw=true) | ||
- **Position** defines the current position. | ||
- **Position** connects to the central configuration node, which contains the current position, but also handles internal shared functions | ||
- **Topic** defines the topic of the first output | ||
@@ -190,3 +210,3 @@ - **position container** here you can define multiple lower and upepr limits for azimuth. If the calculated value of the azimuth is inside the defined limit the input message will send to the associated output. | ||
#### Node Output | ||
#### moon-position - Node Output | ||
@@ -216,35 +236,35 @@ - **first output** | ||
```json | ||
{ | ||
"lastUpdate": "2018-11-11T11:11:11.111Z", | ||
"latitude": "18.473782", | ||
"longitude": "-34.357051", | ||
"angleType": "deg", | ||
"azimuth": 108.71205459404247, | ||
"altitude": -9.578482237780767, | ||
"distance": 400811.8001636167, | ||
"parallacticAngle": -73.92702172116152, | ||
"illumination": { | ||
"angle": -94.27663428960696, | ||
"fraction": 0.14981886026806135, | ||
"phase": { | ||
"emoji": "🌒", | ||
"code": ":waxing_crescent_moon:", | ||
"name": "Waxing Crescent", | ||
"weight": 6.3825, | ||
"value": 0.12651089732280724, | ||
"angle": 45.54392303621061 | ||
}, | ||
"zenithAngle": -20.349612568445437 | ||
}, | ||
"times": { | ||
"rise": "2018-11-11T11:44:22.877Z", | ||
"set": "2018-11-11T23:10:07.389Z", | ||
"alwaysUp": false, | ||
"alwaysDown": false | ||
}, | ||
"pos": [], | ||
"posChanged": false | ||
} | ||
``` | ||
{ | ||
"lastUpdate": "2018-11-11T11:11:11.111Z", | ||
"latitude": "18.473782", | ||
"longitude": "-34.357051", | ||
"angleType": "deg", | ||
"azimuth": 108.71205459404247, | ||
"altitude": -9.578482237780767, | ||
"distance": 400811.8001636167, | ||
"parallacticAngle": -73.92702172116152, | ||
"illumination": { | ||
"angle": -94.27663428960696, | ||
"fraction": 0.14981886026806135, | ||
"phase": { | ||
"emoji": "🌒", | ||
"code": ":waxing_crescent_moon:", | ||
"name": "Waxing Crescent", | ||
"weight": 6.3825, | ||
"value": 0.12651089732280724, | ||
"angle": 45.54392303621061 | ||
}, | ||
"zenithAngle": -20.349612568445437 | ||
}, | ||
"times": { | ||
"rise": "2018-11-11T11:44:22.877Z", | ||
"set": "2018-11-11T23:10:07.389Z", | ||
"alwaysUp": false, | ||
"alwaysDown": false | ||
}, | ||
"pos": [], | ||
"posChanged": false | ||
} | ||
``` | ||
@@ -259,11 +279,11 @@ - **second output** to **... output** if limits for azimuth are defined the incomming message will send to this output. It adds a `msg.payload.posChanged` property of type _boolean_ which is true if the limit has changed since the last azimuth calculation. | ||
``` | ||
```json | ||
[{"id":"d3c04d4e.ce3e3","type":"debug","z":"de4e9c38.0d942","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":570,"y":2100,"wires":[]},{"id":"586e4ae2.5b4f14","type":"debug","z":"de4e9c38.0d942","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":570,"y":2160,"wires":[]},{"id":"1b71d0e5.35b02f","type":"debug","z":"de4e9c38.0d942","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":570,"y":2220,"wires":[]},{"id":"3e4d36c0.620e7a","type":"time-inject","z":"de4e9c38.0d942","name":"","positionConfig":"bdf7c4a.9ca6c38","time":"nadir","timeType":"pdsTime","timeDays":"*","offset":0,"offsetMultiplier":60,"payload":"","payloadType":"date","topic":"","x":320,"y":2100,"wires":[["d3c04d4e.ce3e3"]]},{"id":"c11713e.db07ef","type":"time-inject","z":"de4e9c38.0d942","name":"","positionConfig":"bdf7c4a.9ca6c38","time":"dawn","timeType":"pdsTime","timeDays":"*","offset":0,"offsetMultiplier":60,"payload":"","payloadType":"date","topic":"","x":320,"y":2160,"wires":[["586e4ae2.5b4f14"]]},{"id":"b227cadc.dcf8c8","type":"time-inject","z":"de4e9c38.0d942","name":"","positionConfig":"bdf7c4a.9ca6c38","time":"rise","timeType":"pdmTime","timeDays":"1,4,0","offset":0,"offsetMultiplier":60,"payload":"{\"bool\":true}","payloadType":"json","topic":"","x":340,"y":2220,"wires":[["1b71d0e5.35b02f"]]},{"id":"bdf7c4a.9ca6c38","type":"position-config","z":"","name":"","longitude":"13.71587","latitude":"51.01732","angleType":"deg"}] | ||
``` | ||
#### Node settings | ||
#### time-inject - Node settings | ||
![time-inject](images/time-inject-settings.png?raw=true) | ||
- **Position** defines the current position | ||
- **Position** connects to the central configuration node, which contains the current position, but also handles internal shared functions | ||
- **Payload** defines the payload of the message object send to the output | ||
@@ -306,8 +326,7 @@ - **Topic** defines the topic of the send message | ||
#### time-inject - Node Input | ||
#### Node Input | ||
It has only a button as input, where the massage could injected into a flow manually. | ||
#### Node Output | ||
#### time-inject - Node Output | ||
@@ -318,9 +337,9 @@ The output is a message with the defined payload and topic in the settings. | ||
![time-inject](images/time-inject-example.png?raw=true) | ||
![within-time](images/within-time-example.png?raw=true) | ||
``` | ||
```json | ||
[{"id":"bd9bd279.302eb","type":"inject","z":"de4e9c38.0d942","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":1180,"wires":[["b5c283be.eb945"]]},{"id":"273eb4cb.2715fc","type":"debug","z":"de4e9c38.0d942","name":"out1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":590,"y":1180,"wires":[]},{"id":"78f068d6.2fe9f8","type":"debug","z":"de4e9c38.0d942","name":"out2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":590,"y":1220,"wires":[]},{"id":"b5c283be.eb945","type":"within-time-switch","z":"de4e9c38.0d942","name":"","positionConfig":"bdf7c4a.9ca6c38","startTime":"7:00","startTimeType":"entered","startOffset":0,"startOffsetMultiplier":"60","endTime":"9:00","endTimeType":"entered","endOffset":0,"endOffsetMultiplier":"60","property":"","propertyType":"none","startTimeAlt":"","startTimeAltType":"none","startOffsetAlt":0,"startOffsetAltMultiplier":"60","endTimeAlt":"","endTimeAltType":"none","endOffsetAlt":0,"endOffsetAltMultiplier":"60","x":330,"y":1180,"wires":[["273eb4cb.2715fc"],["78f068d6.2fe9f8"]]},{"id":"bdf7c4a.9ca6c38","type":"position-config","z":"","name":"","longitude":"13.71587","latitude":"51.01732","angleType":"deg"}] | ||
``` | ||
#### Node settings | ||
#### within-time - Node settings | ||
@@ -331,3 +350,3 @@ A simple node that routes messages depending on the time. If the current time falls within the range specified in the node configuration, the message is routed to output 1. Otherwise the message is routed to output 2. | ||
- **Position** defines the current position | ||
- **Position** connects to the central configuration node, which contains the current position, but also handles internal shared functions | ||
- **Start time** defines the start time of the time range with with different [configuration possibilities](#times-definitions) | ||
@@ -358,3 +377,67 @@ - **Start Offset** allows to define a positive or negative offset in *seconds*, *minutes* or *hours* to the given **Start Time**. This will be useful for sun based times. | ||
### time-comp | ||
A enhanced node for time format change and time comparision. | ||
![time-comp](images/time-comp-example.png?raw=true) | ||
**This node is in development and has a pre release state!!** | ||
```json | ||
[{"id":"1a6b5f99.4c928","type":"time-comp","z":"4e9a710a.bf0b9","outputs":1,"name":"","positionConfig":"d9e9ca6a.952218","input":"payload","inputType":"msg","inputFormat":"0","inputOffset":0,"inputOffsetMultiplier":60,"rules":[],"checkall":"true","result1":"payload","result1Type":"msg","result1Value":"","result1ValueType":"input","result1Format":"5","result1Offset":0,"result1OffsetMultiplier":60,"x":350,"y":120,"wires":[["fd45b2d2.eba89"]]},{"id":"fd45b2d2.eba89","type":"debug","z":"4e9a710a.bf0b9","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":570,"y":120,"wires":[]},{"id":"f390b758.7dd9b8","type":"inject","z":"4e9a710a.bf0b9","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":120,"wires":[["1a6b5f99.4c928"]]},{"id":"b87a5c79.d4ce3","type":"comment","z":"4e9a710a.bf0b9","name":"change Unix Timestamp to ISO","info":"","x":210,"y":80,"wires":[]},{"id":"20afdf5d.4cd8d","type":"comment","z":"4e9a710a.bf0b9","name":"compare Time","info":"","x":150,"y":180,"wires":[]},{"id":"3d8ee66c.7c86ea","type":"inject","z":"4e9a710a.bf0b9","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":240,"wires":[["f19f0fd9.8ad1d"]]},{"id":"f19f0fd9.8ad1d","type":"time-comp","z":"4e9a710a.bf0b9","outputs":3,"name":"","positionConfig":"d9e9ca6a.952218","input":"payload","inputType":"msg","inputFormat":"0","inputOffset":0,"inputOffsetMultiplier":60,"rules":[{"operator":"5","operatorType":"11,12,13,14,15,16,17,18","operatorText":"","operandType":"str","operandValue":"12:00","format":"ddd MMM dd yyyy HH:mm:ss","formatSelection":"0","offsetType":"none","offsetValue":"","propertyType":"none","propertyValue":""},{"operator":"3","operatorType":"11,12,13,14,15,16,17,18","operatorText":"","operandType":"str","operandValue":"15:00","format":"ddd MMM dd yyyy HH:mm:ss","formatSelection":"0","offsetType":"none","offsetValue":"","propertyType":"none","propertyValue":""}],"checkall":"true","result1":"payload","result1Type":"msg","result1Value":"","result1ValueType":"input","result1Format":"5","result1Offset":0,"result1OffsetMultiplier":60,"x":350,"y":240,"wires":[["723d7d7c.e7a874"],["44ac03f7.fd68fc"],["4d8512cd.73c90c"]]},{"id":"723d7d7c.e7a874","type":"debug","z":"4e9a710a.bf0b9","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":570,"y":220,"wires":[]},{"id":"44ac03f7.fd68fc","type":"debug","z":"4e9a710a.bf0b9","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":570,"y":260,"wires":[]},{"id":"4d8512cd.73c90c","type":"debug","z":"4e9a710a.bf0b9","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":570,"y":300,"wires":[]},{"id":"d9e9ca6a.952218","type":"position-config","z":0,"name":"Entenhausen","longitude":"13.72324","latitude":"51.12381","angleType":"deg"}] | ||
``` | ||
#### time-comp - Node settings | ||
A simple node that routes messages depending on the time. If the current time falls within the range specified in the node configuration, the message is routed to output 1. Otherwise the message is routed to output 2. | ||
![time-comp](images/time-comp-settings.png?raw=true) | ||
- **Position** connects to the central configuration node, which contains the current position, but also handles internal shared functions | ||
- **Input** defines the input parameter for the time stamp | ||
- **parse format** defines the format for the input parameter, more information see [input parse formats](#input-parse-formats). | ||
- **Offset** allows to define a positive or negative offset to the given **Input Time**. | ||
- **compare with** here can be defined various definitions of times to which the input time should be compared. | ||
- **operator** Drop down to define operator | ||
- **compare type** allows to define whoat parts of the timestring shoudl be compared. Default is a comparision of the complete timestamp. But it is possible to only compare a pat like the only the year. | ||
- **time** defines where the time to which should be compared comes from | ||
- **parse format** defines the format for the time to compare, more information see [input parse formats](#input-parse-formats). | ||
- **Offset** allows to define a positive or negative offset to the given time. | ||
- **limitation** here it is possible to additionally define a parameter. if defined this comparision will only be made if this parameter has the value "true". | ||
- **result** allows to write the **Input time** to a parameter in a different format. Without defining any **compare with**, the node allows by only defining input and result parameter a simply time format conversation. | ||
### time-span | ||
A enhanced node for time span calculation and time span comparision. | ||
![time-span](images/time-span-example.png?raw=true) | ||
**This node is in development and has a pre release state!!** | ||
```json | ||
tbd | ||
``` | ||
#### time-span - Node settings | ||
A simple node that routes messages depending on the time. If the current time falls within the range specified in the node configuration, the message is routed to output 1. Otherwise the message is routed to output 2. | ||
![time-span](images/time-span-settings.png?raw=true) | ||
- **Position** connects to the central configuration node, which contains the current position, but also handles internal shared functions | ||
- **Input 1** defines the first input parameter for the time span calculation | ||
- **parse format** defines the format for the first input parameter, more information see [input parse formats](#input-parse-formats). | ||
- **Offset** allows to define a positive or negative offset to the given **Input 1 Time**. | ||
- **Input 2** defines the second input parameter for the time span calculation | ||
- **parse format** defines the format for the second input parameter, more information see [input parse formats](#input-parse-formats). | ||
- **Offset** allows to define a positive or negative offset to the given **Input 2 Time**. | ||
- **compare with** here can be defined various time spams to which the time span between timestamp of input 1 and input 2 should be compared. | ||
- **operator** Drop down to define operator for comparision | ||
- **time** defines a number to which should be the timespan be compared | ||
- **time type** the unit of the given time | ||
- **result** ** as result of an incomming message, data could be written to that destination. This could be a message property, a flow or a global context. | ||
- **result value** defines the value which should be written to the result destination. Could be the timestamp, one of the Input times or any other time/data. For timestamp or times the output format or maybe an offset could be defined. | ||
Without defining any comparision, the node allows by only defining inputs and result a simply timespan calculation. | ||
### Times definitions | ||
@@ -439,2 +522,3 @@ | ||
String as one of the following formats: | ||
- `00:00 ... 23:59` 24h Format | ||
@@ -451,2 +535,146 @@ - `00:00:00 ... 23:59:00` 24h Format with seconds | ||
### input parse formats | ||
Some nodes has the ability to get an input time out of different pre defined formats or a free format definition. | ||
The formats are: | ||
- **milliseconds UNIX timestamp** This is the default for Node-ed. Timestamps are a numeric representation of the time in milliseconds since 1970-01-01 UTC | ||
- **ECMA-262** YYYY-MM-DDTHH:mm:ss.sssZ - This is the default toString output of JavaScript. This is a simplification of the ISO 8601 Extended Format. | ||
- **YYYYMMDDHHMMSS** is a number of the format YYYYMMDDHHMMSS. | ||
- **YYYYMMDD.HHMMSS** is a number of the format YYYYMMDD.HHMMSS. | ||
- **various** the system will try to parse different string formats | ||
- **other** there you can define a format like "yyyy-MM-dd HH:mm:ss" of the given time. Possible format placeholders are: | ||
Field | Full Form | Short Form | ||
-------------|--------------------|----------------------- | ||
Year | yyyy (4 digits) | yy (2 digits), y (2 or 4 digits) | ||
Month | MMM (name or abbr.)| MM (2 digits), M (1 or 2 digits) | ||
Month | NNN (abbr.) | | ||
Day of Month | dd (2 digits) | d (1 or 2 digits) | ||
Day of Week | EE (name) | E (abbr) | ||
Hour (1-12) | hh (2 digits) | h (1 or 2 digits) | ||
Hour (0-23) | HH (2 digits) | H (1 or 2 digits) | ||
Hour (0-11) | KK (2 digits) | K (1 or 2 digits) | ||
Hour (1-24) | kk (2 digits) | k (1 or 2 digits) | ||
Minute | mm (2 digits) | m (1 or 2 digits) | ||
Second | ss (2 digits) | s (1 or 2 digits) | ||
Millisecond | ll (3 digits) | l (1, 2 or 3 digits) | ||
AM/PM | tt (2 digits) | t (1 or 2 digits) | ||
### output timestamp formats | ||
For timestamp outputs some nodes has the ability to define the format of the timestamp. Therfore different pre defined formates exists or a free format definition. | ||
The formats are: | ||
- **milliseconds UNIX timestamp** Timestamps are a numeric representation of the time in milliseconds since 1970-01-01 UTC | ||
- **ECMA-262** YYYY-MM-DDTHH:mm:ss.sssZ - This is the default toString output of JavaScript. This is a simplification of the ISO 8601 Extended Format. | ||
- **YYYYMMDDHHMMSS** is a number of the format YYYYMMDDHHMMSS. | ||
- **YYYYMMDD.HHMMSS** is a number of the format YYYYMMDD.HHMMSS. | ||
- **local** is the javascript output of date.toLocaleString() | ||
- **localLong** is the javascript output of date.toString() | ||
- **localTime** is the javascript output of date.toLocaleTimeString() | ||
- **localTimeLong** is the javascript output of date.toTimeString() | ||
- **localDate** is the javascript output of date.toLocaleDateString() | ||
- **localDateLong** is the javascript output of date.toDateString() | ||
- **UTC** is the javascript output of date.toUTCString() | ||
- **ISO** YYYY-MM-DDTHH:mm:ss.sssZ (output of date.toISOString()) | ||
- **ms** the time in milliseconds between output and timestamp | ||
- **sec** the time in seconds between output and timestamp | ||
- **min** the time in minutes between output and timestamp | ||
- **hour** the time in hours between output and timestamp | ||
- **Day Name** the timestamps day in the format Monday, 22.12. | ||
- **Day in relative** the timestamps day in relative to output time in the format Today, 22.12. | ||
- **object** gived back an object for the timestamp with the following properties: | ||
- **date** Javascript Date object | ||
- **ts** number - Unix timestamp (milliseconds since 1970-01-01 UTC) | ||
- **timeUTCStr** string representation of the TIme in UTC format | ||
- **timeISOStr** string representation of the TIme in ISO format | ||
- **timeLocaleStr** the javascript output of date.toLocaleString() | ||
- **timeLocaleTimeStr** the javascript output of date.toLocaleTimeString() | ||
- **delay** the time in milliseconds between output and timestamp | ||
- **delaySec** the time in seconds between output and timestamp | ||
- **other** there you can define a format like "yyyy-MM-dd HH:mm:ss" of the given time. Possible format placeholders are: | ||
|placeholder|Description| | ||
|--- |--- | | ||
|d|Day of the month as digits; no leading zero for single-digit days.| | ||
|dd|Day of the month as digits; leading zero for single-digit days.| | ||
|ddd|Day of the week as a three-letter abbreviation. (same as E)| | ||
|dddd|Day of the week as its full name. (same as EE)| | ||
|E|Day of the week as a three-letter abbreviation.| | ||
|EE|Day of the week as its full name.| | ||
|M|Month as digits; no leading zero for single-digit months.| | ||
|MM|Month as digits; leading zero for single-digit months.| | ||
|MMM|Month as a three-letter abbreviation.| | ||
|MMMM|Month as its full name.| | ||
|yy|Year as last two digits; leading zero for years less than 10.| | ||
|yyyy|Year represented by four digits.| | ||
|h|Hours; no leading zero for single-digit hours (12-hour clock 1-12).| | ||
|hh|Hours; leading zero for single-digit hours (12-hour clock 01-12).| | ||
|H|Hours; no leading zero for single-digit hours (24-hour clock 0-23).| | ||
|HH|Hours; leading zero for single-digit hours (24-hour clock 00-23).| | ||
|k|Hours; no leading zero for single-digit hours (12-hour clock 0-11).| | ||
|kk|Hours; leading zero for single-digit hours (12-hour clock 00-11).| | ||
|K|Hours; no leading zero for single-digit hours (24-hour clock 1-24).| | ||
|KK|Hours; leading zero for single-digit hours (24-hour clock 01-24).| | ||
|m|Minutes; no leading zero for single-digit minutes.| | ||
|mm|Minutes; leading zero for single-digit minutes.| | ||
|s|Seconds; no leading zero for single-digit seconds.| | ||
|ss|Seconds; leading zero for single-digit seconds.| | ||
|l or L|Milliseconds. l gives 3 digits. L gives 2 digits.| | ||
|t|Lowercase, single-character time marker string: a or p.| | ||
|tt|Lowercase, two-character time marker string: am or pm.| | ||
|T|Uppercase, single-character time marker string: A or P.| | ||
|TT|Uppercase, two-character time marker string: AM or PM.| | ||
|Z|US timezone abbreviation, e.g. EST or MDT. With non-US timezones or in the Opera browser, the GMT/UTC offset is returned, e.g. GMT-0500| | ||
|o|GMT/UTC timezone offset, e.g. -0500 or +0230.| | ||
|S|The date's ordinal suffix (st, nd, rd, or th). Works well with d.| | ||
|x|difference of days from timestamp day to output day| | ||
|xx|difference of days from timestamp day to output day with relative names for today, tomorrow, ...| | ||
|'…' or "…"|Literal character sequence. Surrounding quotes are removed.| | ||
|UTC:|Must be the first four characters of the mask. Converts the date from local time to UTC/GMT/Zulu time before applying the mask. The "UTC:" prefix is removed.| | ||
### output timespan formats | ||
For timespan output the calc-timespan node has the ability to define the format of the timespan. Therfore different pre defined formates exists or a free format definition. | ||
The formats are: | ||
- **ms** timespan im milliseconds (integer value) | ||
- **sec**, **min**,..., **month**, **years** timespan as a floating point number or as a integer number of the the choosen unit. | ||
- **object** gived back an object for the timespan with the following properties: | ||
- **date** Javascript Date object | ||
- **ts** number - Unix timestamp (milliseconds since 1970-01-01 UTC) | ||
- **timeUTCStr** string representation of the TIme in UTC format | ||
- **timeISOStr** string representation of the TIme in ISO format | ||
- **timeLocaleStr** the javascript output of date.toLocaleString() | ||
- **timeLocaleTimeStr** the javascript output of date.toLocaleTimeString() | ||
- **delay** the time in milliseconds between output and timestamp | ||
- **delaySec** the time in seconds between output and timestamp | ||
- **other** there you can define a format like "yyyy-MM-dd HH:mm:ss" of the given time. Possible format placeholders are: | ||
## TODO | ||
- [ ] change icon size to 40x60 <https://github.com/node-red/node-red.github.io/pull/39> | ||
- [ ] add posibility to select input/output timezone | ||
- [ ] select auto ad get info from getTimezoneOffset | ||
- [ ] solve problem of dst | ||
- [x] time Span | ||
- [x] zeitraum zwischen 2 zeitpunkten ausrechnen | ||
- [x] die möglichkeit statt Zeitpunkt - Zeitraum auszugeben auch sowas wie Zeitpunkt - Zeitraum > Limit true/false rauszugeben | ||
- [ ] offset für Input als Typed Input mit Wahl des offset: NA, num, msg, flow, global | ||
- [ ] als Input 1. Des Monats, letzter Tag des Monats, Monatsmitte, erster+ letzter Mo, Di, Mi, Do, Fr, Sa, So im Monat | ||
- [ ] within-time | ||
- [ ] add Payload hinzufügen wie bei time inject - um beispielsweise dem Message Objekt mehr Infos hinzuzufügen | ||
- [ ] als Start und Ende Midnight hinzufügen | ||
- [ ] offset als Typed Input mit Wahl des offset: NA, num, msg, flow, global | ||
- [ ] Time Inject | ||
- [ ] Midnight als auswahl für Zeit hinzufügen | ||
- [ ] offset als Typed Input mit Wahl des offset: NA, num, msg, flow, global | ||
- [ ] time-comp | ||
- [ ] vergleicht mit 1. Des Monats, letzter Tag des Monats, Monatsmitte, erster+ letzter Mo, Di, Mi, Do, Fr, Sa, So im Monat | ||
- [ ] offset als Typed Input mit Wahl des offset: NA, num, msg, flow, global | ||
## Bugs and Feedback | ||
@@ -463,7 +691,5 @@ | ||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use | ||
this file except in compliance with the License. You may obtain a copy of the | ||
License at | ||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this nodes except in compliance with the License. You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
<http://www.apache.org/licenses/LICENSE-2.0> | ||
@@ -470,0 +696,0 @@ Unless required by applicable law or agreed to in writing, software distributed |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
1223841
104
5866
1
693
4
8
1