From cbc9badd3fcc2c394e7a8b9b5ff32e137cda7f48 Mon Sep 17 00:00:00 2001 From: Hypnos <12692680+Hypnos3@users.noreply.github.com> Date: Mon, 4 Nov 2019 12:58:57 +0100 Subject: [PATCH 1/8] 0.5.1-beta-0 --- CHANGELOG.md | 13 +++++++++ nodes/blind-control.js | 17 +++++------- nodes/lib/dateTimeHelper.js | 54 +++++++++++++++++++++++++------------ package.json | 2 +- 4 files changed, 57 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28748288..d5829571 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # node-red-contrib-sun-position +#### 0.5.1-beta-0: BugFix and Maintenance Release + +- general + - fix for week number calculation when in daylight saving #65 + - if time output as object the week is now an extra object with properties + - iso *array* `[year, week]` + - week *number* week number + - year *number* full year + - even *boolean* is true if week is even +- blind control + - change logic of rule execution: From rules within Until rules will now considered. + - change should have no affect if rule setup is equal to the examples, that time restricted rules separated in first only until and afterwards only from rules + #### 0.5.0: mayor release for blind control - configuration diff --git a/nodes/blind-control.js b/nodes/blind-control.js index 61d4257b..63c12a05 100644 --- a/nodes/blind-control.js +++ b/nodes/blind-control.js @@ -781,29 +781,24 @@ module.exports = function (RED) { const rule = node.rules.data[i]; // node.debug('rule ' + rule.timeOp + ' - ' + (rule.timeOp !== cRuleFrom) + ' - ' + util.inspect(rule, {colors:true, compact:10, breakLength: Infinity })); if (rule.timeOp === cRuleFrom) { continue; } - const res = fktCheck(rule, r => (r >= nowNr)); - /* let res = null; + // const res = fktCheck(rule, r => (r >= nowNr)); + let res = null; if (rule.timeOp === cRuleFrom) { res = fktCheck(rule, r => (r <= nowNr)); } else { res = fktCheck(rule, r => (r >= nowNr)); - } */ + } if (res) { node.debug('1. ruleSel ' + util.inspect(res, { colors: true, compact: 10, breakLength: Infinity })); - /* if (Boolean(ruleSel) && res.timeOp === cRuleUntil) { - node.debug('break'); - // es gibt bereits eine treffende Regel - // nachfolgende BIS Regel wird nicht mehr ausgeführt - // nachfolgende VON Regeln werden ausgeführt (wenn sie zeitlich passen) - break; - } */ if (res.levelOp === cRuleMinOversteer) { ruleSelMin = res; } else if (res.levelOp === cRuleMaxOversteer) { ruleSelMax = res; } else { ruleSel = res; - break; + if (rule.timeOp !== cRuleFrom) { + break; + } } } } diff --git a/nodes/lib/dateTimeHelper.js b/nodes/lib/dateTimeHelper.js index b9d97f79..774b436b 100644 --- a/nodes/lib/dateTimeHelper.js +++ b/nodes/lib/dateTimeHelper.js @@ -289,23 +289,37 @@ function getSpecialDayOfMonth(year, month, dayName) { } /** - * get the week number for a a date + * For a given date, get the ISO week number + * + * Based on information at: + * + * http://www.merlyn.demon.co.uk/weekcalc.htm#WNR + * + * Algorithm is to find nearest thursday, it's year + * is the year of the week number. Then get weeks + * between that date and the first day of that year. + * + * Note that dates in one year can be weeks of previous + * or next year, overlap is up to 3 days. + * + * e.g. 2014/12/29 is Monday in week 1 of 2015 + * 2012/1/1 is Sunday in week 52 of 2011 + * * @param {Date} date date to get week number * @returns {Number} week number */ function getWeekNumber(date) { - const dt = new Date(date); - const target = new Date(dt.valueOf()); - const dayNumber = (dt.getUTCDay() + 6) % 7; - - target.setUTCDate(target.getUTCDate() - dayNumber + 3); - const firstThursday = target.valueOf(); - target.setUTCMonth(0, 1); - - if (target.getUTCDay() !== 4) { - target.setUTCMonth(0, 1 + ((4 - target.getUTCDay()) + 7) % 7); - } - return Math.ceil((firstThursday - target) / (7 * 24 * 3600 * 1000)) + 1; + // Copy date so don't modify original + date = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())); + // Set to nearest Thursday: current date + 4 - current day number + // Make Sunday's day number 7 + date.setUTCDate(date.getUTCDate() + 4 - (date.getUTCDay()||7)); + // Get first day of year + const yearStart = new Date(Date.UTC(date.getUTCFullYear(),0,1)); + // Calculate full weeks to nearest Thursday + const weekNo = Math.ceil(( ( (date - yearStart) / 86400000) + 1)/7); + // Return array of year and week number + return [date.getUTCFullYear(), weekNo]; } /*******************************************************************************************************/ /* date-time functions */ @@ -833,7 +847,7 @@ const _dateFormat = (function () { tt: H < 12 ? 'am' : 'pm', T: H < 12 ? 'A' : 'P', TT: H < 12 ? 'AM' : 'PM', - ww: getWeekNumber(date), + ww: getWeekNumber(date)[1], Z: utc ? 'UTC' : /.*\s(.+)/.exec(date.toLocaleTimeString([], { timeZoneName: 'short' }))[1], z: utc ? '' : (String(date).match(/\b(?:GMT|UTC)(?:[-+]\d{4})?\b/g) || ['']).pop(), zz: utc ? '' : (o > 0 ? '-' : '+') + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4), @@ -1082,13 +1096,14 @@ function getFormattedDateOut(date, format, utc, timeZoneOffset) { // eslint-disa + (offset === 0 ? 'Z' : (offset < 0 ? '+' : '-') + pad2(h) + ':' + pad2(m)); } case 19: // workweek - return getWeekNumber(date); + return getWeekNumber(date)[1]; case 20: // workweek even - return !Boolean(getWeekNumber(date) % 2); // eslint-disable-line no-extra-boolean-cast + return !(getWeekNumber(date)[1] % 2); // eslint-disable-line no-extra-boolean-cast } const now = new Date(); const delay = (date.getTime() - now.getTime()); + const week = getWeekNumber(date); return { date, ts: date.getTime(), @@ -1097,7 +1112,12 @@ function getFormattedDateOut(date, format, utc, timeZoneOffset) { // eslint-disa delay, delaySec: Math.round(delay / 1000), lc: now.getTime(), - week: getWeekNumber(date) + week: { + iso : week, + week : week[1], + year : week[0], + even : !(week[1] % 2) + } }; } // =================================================================== diff --git a/package.json b/package.json index 3d584bc3..cf3ee714 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-red-contrib-sun-position", - "version": "0.5.0", + "version": "0.5.1-beta-0", "description": "NodeRED nodes to get sun and moon position", "keywords": [ "node-red", From d2f06025caa44942a8909700a8e59286eeb4e60a Mon Sep 17 00:00:00 2001 From: Hypnos <12692680+Hypnos3@users.noreply.github.com> Date: Tue, 5 Nov 2019 23:17:56 +0100 Subject: [PATCH 2/8] fix for #66 if the blind not uses values between 0 and 1 --- nodes/blind-control.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodes/blind-control.js b/nodes/blind-control.js index 63c12a05..765b5f34 100644 --- a/nodes/blind-control.js +++ b/nodes/blind-control.js @@ -265,7 +265,7 @@ module.exports = function (RED) { } else if (val > 99) { return node.blindData.levelTop; } - return (val / 100); + return posPrcToAbs_(node, val / 100); } throw new Error(`unknown value "${value}" of type "${type}"` ); } From 48371b252bcbaeac055c52e9985a1b62def0febf Mon Sep 17 00:00:00 2001 From: Hypnos <12692680+Hypnos3@users.noreply.github.com> Date: Tue, 5 Nov 2019 23:38:20 +0100 Subject: [PATCH 3/8] 0.5.1-beta-1 --- CHANGELOG.md | 2 + nodes/blind-control.html | 203 +++++++++++++++++++++++++++++-------- nodes/position-config.js | 4 +- nodes/static/htmlglobal.js | 4 +- package-lock.json | 2 +- package.json | 2 +- 6 files changed, 168 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5829571..f422bccd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ - year *number* full year - even *boolean* is true if week is even - blind control + - fix for #66 if the blind not uses values between 0 and 1 + - enhanced output of the rules - change logic of rule execution: From rules within Until rules will now considered. - change should have no affect if rule setup is equal to the examples, that time restricted rules separated in first only until and afterwards only from rules diff --git a/nodes/blind-control.html b/nodes/blind-control.html index b6bd58ed..d01caba6 100644 --- a/nodes/blind-control.html +++ b/nodes/blind-control.html @@ -173,28 +173,86 @@ } if (t === 'pdsCalcData') { - return '{sun position}'; + return `"${node._('node-red-contrib-sun-position/position-config:common.types.suncalc')}"`; } if (t === 'pdsCalcPercent') { - return '{sun in sky percent}'; + return `"${node._('node-red-contrib-sun-position/position-config:common.types.suninsky')}"`; + // return '{sun in sky percent}'; } if (t === 'pdmCalcData') { - return '{moon position}'; + return `"${node._('node-red-contrib-sun-position/position-config:common.types.mooncalc')}"`; + // return '{moon position}'; } if (t === 'pdmPhase') { - return '{moon phase}'; + return `"${node._('node-red-contrib-sun-position/position-config:common.types.moonPhase')}"`; + // return '{moon phase}'; } if (t === 'pdsTime') { - const res = v.replace('astronomical', 'astro-').replace('nautical', 'naut-').replace('amateur', 'amat-').replace('blueHour', 'blueHr-').replace('goldenHour', 'goldHr-'); - return clipValueLength(res, l); + switch (v) { + case 'astronomicalDawn': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.astronomicalDawn'); + case 'amateurDawn': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.amateurDawn'); + case 'nauticalDawn': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.nauticalDawn'); + case 'blueHourDawnStart': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.blueHourDawnStart'); + case 'civilDawn': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.civilDawn'); + case 'blueHourDawnEnd': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.blueHourDawnEnd'); + case 'goldenHourDawnStart': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.goldenHourDawnStart'); + case 'sunrise': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.sunrise'); + case 'sunriseEnd': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.sunriseEnd'); + case 'goldenHourDawnEnd': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.goldenHourDawnEnd'); + case 'solarNoon': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.solarNoon'); + case 'goldenHourDuskStart': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.goldenHourDuskStart'); + case 'sunsetStart': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.sunsetStart'); + case 'sunset': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.sunset'); + case 'goldenHourDuskEnd': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.goldenHourDuskEnd'); + case 'blueHourDuskStart': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.blueHourDuskStart'); + case 'civilDusk': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.civilDusk'); + case 'blueHourDuskEnd': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.blueHourDuskEnd'); + case 'nauticalDusk': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.nauticalDusk'); + case 'amateurDusk': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.amateurDusk'); + case 'astronomicalDusk': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.astronomicalDusk'); + case 'nadir': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.nadir'); + default: + return v; + } + // const res = v.replace('astronomical', 'astro-').replace('nautical', 'naut-').replace('amateur', 'amat-').replace('blueHour', 'blueHr-').replace('goldenHour', 'goldHr-'); + // return clipValueLength(res, l); } if (t === 'pdmTime') { - return 'moon' + v; + switch (v) { + case 'rise': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.moonRise', 'rise'); + case 'set': + return node._('node-red-contrib-sun-position/position-config:common.typeOptions.moonSet', 'set'); + default: + return 'moon' + v; + } } if (t === 'msgPayload') { return 'msg.payload'; } @@ -210,10 +268,22 @@ return clipValueLength(v, l); } + /** + * get a time in millisecond as string of the format hh:mm, hh:mm:ss or hh:mm:ss.mss + * @param {number} s - milisecond + * @returns {string} time as string + */ + function msToTime(s) { + // Pad to 2 or 3 digits, default is 2 + const pad = (n, z = 2) => ('00' + n).slice(-z); + const sec = (s%6e4)/1000|0; + const msec = s%1000; + return pad(s/3.6e6|0) + ':' + pad((s%3.6e6)/6e4 | 0) + ((msec >0) ? (':' + pad(sec) +'.' + pad(msec, 3) ) : ((sec>0) ? ':' + pad(sec) : '')); + } /** * get a description of the rule rules * @param {object} data - a rule description - * @returns {steing} description of the rule + * @returns {string} description of the rule */ function getRuleDescription(node, selFields, data) { let result = ''; @@ -222,8 +292,7 @@ result += '