Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

node-red-contrib-sun-position

Package Overview
Dependencies
Maintainers
1
Versions
136
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-red-contrib-sun-position - npm Package Compare versions

Comparing version 2.2.0-beta3 to 3.0.0-alpha1

nodes/icons/inputTypeSunAzimuthCfg.svg

64

CHANGELOG.md

@@ -5,7 +5,9 @@ # node-red-contrib-sun-position

### Install of a specific Version in Node-Red:
- change to the installation directory of Node-Red
- enter the command `npm install node-red-contrib-sun-position@2.0.0`
### Install of a specific Version in Node-Red
### Install of a specific Version in Redmatic (on a Homematic):
- change to the installation directory of Node-Red
- enter the command `npm install node-red-contrib-sun-position@2.0.0`
### Install of a specific Version in Redmatic (on a Homematic)
- logon per ssh

@@ -17,6 +19,10 @@ - enter the commands in the order:

### Install of a specific Version in HomeAssistant:
- go to the Supervisor
- go to the Node-Red AddOn
- add unter the `Configuration` in the Node-Red options as `npm_packages`:
### Install of a specific Version in HomeAssistant
- go to the Supervisor
- go to the Node-Red AddOn
- stop the Node-Red AddOn
- edit `config/node-red/package.json` and remove the line with `node-red-contrib-sun-position`
- add unter the `Configuration` in the Node-Red options as `npm_packages`:
```yaml

@@ -29,4 +35,13 @@ npm_packages:

### 2.2.0-beta: enhancement
### 3.0.0-alpha: enhancement
Breaking changes:
- removed all "Radiant" angle selection from typed input. The standard selection (which was previous the decimal degree output) gives now an angle based on the type selection (degree or radiant) of the configuration node. Version number is changed to 3 to reflect these API changes.
This is still a non stable development version!!
Changes:
- general

@@ -36,2 +51,11 @@ - first implementation of tests with `mocha` and some changes due to the test implementation (inject enhance and delay-until)

- added type checking
- allow of custom sun position set and rise angles in the configuration node
- allow of custom angles in the configuration node
- removed the following angle selections (replaced by existing ones without rad):
- time by azimuth (rad)
- time by elevation (set or rise in rad)
- next time by elevation (set or rise in rad)
- next rise time by elevation (rad)
- next set time by elevation (rad)
- sun-times and moon-times have now every angle in Radians and Degree

@@ -50,4 +74,13 @@ - inject enhance (time-inject)

- sun-position + moon-position
- smaller rework
- new Node `delay-until` which allows to delay messages until defined time
- blind-control and clock-timer
- implement start and end time for rules #357
- show rule edit dialog no longer modal to allow usage of JSON and JSONATA editor #432
- separated renamed earliest/latest naming to make it clearer #441
- reworked value caching mechanism; fixed bug #434
- blind-control

@@ -58,3 +91,3 @@ - fix #421

- fix not working oversteer mode limitation #431
- show rule edit dialog no longer modal to allow usage of JSON and JSONATA editor #432
- implemented optional alternative azimuth input like node-red-contrib-blindcontroller #430

@@ -86,3 +119,3 @@ - time-comp

- Fixed bug with wrong default values for Input type in blind-control and within-time-switch node, added console error in case it occurs again.
- additional check for missing position configuration
- additional check for missing position configuration

@@ -92,2 +125,3 @@ ### 2.0.10: maintenance release

- rerelease, no changed
### 2.0.9: maintenance release

@@ -170,3 +204,3 @@

- allow to setup a rule which will only overwrite slat #345 or topic
- enhanced overwrite possibilities for slat. Additional `msg.blindSlat` as message property allowed or if the topic contains __slatOverwrite __ the payload as slat position will be used - partly #346
- enhanced overwrite possibilities for slat. Additional `msg.blindSlat` as message property allowed or if the topic contains __slatOverwrite__ the payload as slat position will be used - partly #346
- for slat value make a deep clone as this could be any object and an object comparison

@@ -185,3 +219,3 @@

🛑 Nodes (especially blind, time-control nodes) that were created or saved with this version do not work in older versions of the package. This affects the export / import of flows and when switching to an older version. It is therefore **essential** to create a **backup** before upgrading to this version!
🛑 Nodes (especially blind, time-control nodes) that were created or saved with this version do not work in older versions of the package. This affects the export / import of flows and when switching to an older version. It is therefore __essential__ to create a __backup__ before upgrading to this version!

@@ -384,3 +418,3 @@ - general

- moon-times now available #161
- has now a `isUp` _Boolean_ property which gives the state if the moon is Up #162
- has now a `isUp` *Boolean* property which gives the state if the moon is Up #162
- additional properties are `positionAtRise` and `positionAtSet` with position information on rise and set

@@ -692,3 +726,3 @@

- updated dependencies
- more changes for node-red 1.0 (https://nodered.org/blog/2019/09/20/node-done)
- more changes for node-red 1.0 <https://nodered.org/blog/2019/09/20/node-done>
- added node-red 0.19.0 as required version

@@ -695,0 +729,0 @@

@@ -5,2 +5,3 @@ {

"checkJs": true,
"allowJs": true,
"module": "commonJS",

@@ -13,3 +14,4 @@ "target": "es6",

"@types": ["nodes/types"],
"@nodes": ["nodes"]
"@nodes": ["nodes"],
"@static": ["nodes/static"]
},

@@ -20,4 +22,7 @@ "sourceMap": true,

},
"include": ["./nodes/types/typedefs.js"],
"exclude": ["node_modules", "**/node_modules/*", "temp", "**/temp/*", "backup", "**/backup/*", "examples", "**/examples/*"]
"include": ["./nodes/types/typedefs.js", "./nodes/static/htmlglobal.js"],
"exclude": ["node_modules", "**/node_modules/*", "temp", "**/temp/*", "backup", "**/backup/*", "examples", "**/examples/*"],
"typeAcquisition": {
"include": ["jquery", "jqueryui", "node-red"]
}
}

@@ -198,3 +198,3 @@ /*

};
const intervalMax = 24*60*60*1000 * 3; // 3 Tage
const intervalMax = hlp.TIME_3d;

@@ -216,4 +216,6 @@ RED.nodes.createNode(this, config);

error => {
node.error(error);
node.status({fill: 'red', shape: 'dot', text: error });
const text = RED._('node-red-contrib-sun-position/position-config:errors.config-error', { error });
node.error(text);
node.status({fill: 'red', shape: 'dot', text });
return true;
}, false)) {

@@ -245,3 +247,3 @@ return;

}
node.intervalCountMultiplier = config.intervalCountMultiplier ? config.intervalCountMultiplier : 60000;
node.intervalCountMultiplier = config.intervalCountMultiplier ? config.intervalCountMultiplier : hlp.TIME_1min;

@@ -399,3 +401,3 @@ if (node.injType === tInj.interval) {

oT : (config.payloadOffset === 0 || config.payloadOffset === '') ? 'none' : (config.payloadOffsetType ? config.payloadOffsetType : 'num'),
oM : config.payloadOffsetMultiplier ? config.payloadOffsetMultiplier : 60000,
oM : config.payloadOffsetMultiplier ? config.payloadOffsetMultiplier : hlp.TIME_1min,
f : config.payloadTimeFormat ? config.payloadTimeFormat : 0,

@@ -527,3 +529,3 @@ next : true,

node.recalcTime = (config.recalcTime || 2) * 3600000;
node.recalcTime = (config.recalcTime || 2) * hlp.TIME_1h;

@@ -662,3 +664,5 @@ node.timeOutStartObj = null;

} else if (node.injType === tInj.intervalAmount) {
node.intervalCountMax = node.positionConfig.getFloatProp(node, null, node.intervalCountType, node.intervalCount, 0);
node.intervalCountMax = node.positionConfig.getFloatProp(node, null, {
type: node.intervalCountType, value: node.intervalCount, def: 0
});
node.intervalTime = Math.floor((millisecEnd - millisecStart) / node.intervalCountMax);

@@ -751,3 +755,3 @@ node.intervalCountCurrent = 0;

let millisecEnd = 1000 * 60 * 60 * 24; // 24h
let millisecEnd = hlp.TIME_24h;
if ((node.nextEndTime !== null) && (typeof node.nextEndTime !== 'undefined')) {

@@ -771,4 +775,4 @@ // node.debug('timeout ' + node.nextEndTime + ' is in ' + millisec + 'ms');

if (millisecEnd > 345600000) {
millisecEnd = Math.min((millisecEnd - 129600000), 2147483646);
if (millisecEnd > hlp.TIME_5d) {
millisecEnd = Math.min((millisecEnd - hlp.TIME_36h), 2147483646);
node.timeOutEndObj = setTimeout(() => {

@@ -812,3 +816,3 @@ node.doCreateEndTimeout();

node.getIntervalText = (mstime, val) => {
if (mstime === 604800000) {
if (mstime === hlp.TIME_WEEK) {
if (val === 1) {

@@ -818,3 +822,3 @@ return String(val) + RED._('node-red-contrib-sun-position/position-config:common.units.week');

return String(val) + RED._('node-red-contrib-sun-position/position-config:common.units.weeks');
} else if (mstime === 86400000) {
} else if (mstime === hlp.TIME_24h) {
if (val === 1) {

@@ -824,7 +828,7 @@ return String(val) + RED._('node-red-contrib-sun-position/position-config:common.units.day');

return String(val) + RED._('node-red-contrib-sun-position/position-config:common.units.days');
} else if (mstime === 3600000) {
} else if (mstime === hlp.TIME_1h) {
return String(val) + RED._('node-red-contrib-sun-position/position-config:common.units.hour');
} else if (mstime === 60000) {
} else if (mstime === hlp.TIME_1min) {
return String(val) + RED._('node-red-contrib-sun-position/position-config:common.units.min');
} else if (mstime === 1000) {
} else if (mstime === hlp.TIME_1s) {
return String(val) + RED._('node-red-contrib-sun-position/position-config:common.units.sec');

@@ -863,9 +867,9 @@ }

}, node.intervalTime);
if (node.intervalTime > 43200000) { // 12h
if (node.intervalTime > hlp.TIME_12h) {
node.status({
text: '↻' + (node.intervalTime / 3600000).toFixed(1) + 'h'
text: '↻' + (node.intervalTime / hlp.TIME_1h).toFixed(1) + 'h'
});
} else if (node.intervalTime > 3600000) { // 1h
} else if (node.intervalTime > hlp.TIME_1h) {
node.status({
text: '↻' + (node.intervalTime / 60000).toFixed(2) + 'min'
text: '↻' + (node.intervalTime / hlp.TIME_1min).toFixed(2) + 'min'
});

@@ -928,3 +932,5 @@ } else {

node.getIntervalTime = () => {
node.intervalTime = node.positionConfig.getFloatProp(node, null, node.intervalCountType, node.intervalCount, 0);
node.intervalTime = node.positionConfig.getFloatProp(node, null, {
type: node.intervalCountType, value: node.intervalCount, def: 0
});
if (node.intervalTime <= 0) {

@@ -995,3 +1001,5 @@ throw new Error('Interval wrong!');

if (node.injType === tInj.intervalAmount) {
node.intervalCountMax = node.positionConfig.getFloatProp(node, null, node.intervalCountType, node.intervalCount, 0);
node.intervalCountMax = node.positionConfig.getFloatProp(node, null, {
type: node.intervalCountType, value: node.intervalCount, def: 0
});
delete node.intervalTime;

@@ -1066,4 +1074,3 @@ }

if (millisec > 345600000) {
// > 4 Days
if (millisec > hlp.TIME_5d) {
if (node.intervalObj) {

@@ -1075,3 +1082,3 @@ clearInterval(node.intervalObj);

// should not more then 2147483647 ms (24.8 days).
millisec = Math.min((millisec - 129600000), 2147483646);
millisec = Math.min((millisec - hlp.TIME_36h), 2147483646);
// node.debug('next inject is far far away, plan a inject time recalc in ' + millisec + ' ms');

@@ -1078,0 +1085,0 @@ node.timeOutStartObj = setTimeout(() => {

@@ -318,4 +318,6 @@ /*

try {
node.propertyStart.now = dNow;
node.propertyStartThreshold.now = dNow;
result.altStartTime = node.positionConfig.comparePropValue(node, msg, node.propertyStart,
node.propertyStartOperator, node.propertyStartThreshold, false, dNow);
node.propertyStartOperator, node.propertyStartThreshold);
} catch (err) {

@@ -341,4 +343,7 @@ result.altStartTime = false;

try {
node.propertyEnd.now = dNow;
node.propertyEndThreshold.now = dNow;
result.altEndTime = node.positionConfig.comparePropValue(node, msg, node.propertyEnd,
node.propertyEndOperator, node.propertyEndThreshold, false, dNow);
node.propertyEndOperator, node.propertyEndThreshold);
} catch (err) {

@@ -384,4 +389,6 @@ result.altEndTime = false;

error => {
node.error(error);
node.status({fill: 'red', shape: 'dot', text: error });
const text = RED._('node-red-contrib-sun-position/position-config:errors.config-error', { error });
node.error(text);
node.status({fill: 'red', shape: 'dot', text });
return true;
}, false)) {

@@ -388,0 +395,0 @@ return;

@@ -103,4 +103,6 @@ /*

error => {
node.error(error);
node.status({fill: 'red', shape: 'dot', text: error });
const text = RED._('node-red-contrib-sun-position/position-config:errors.config-error', { error });
node.error(text);
node.status({fill: 'red', shape: 'dot', text });
return true;
}, false)) {

@@ -309,5 +311,5 @@ return null;

}
const dNow = getIntDate(node.tsCompare, qObj.msg, node);
node.timeData.now = getIntDate(node.tsCompare, qObj.msg, node);
node.nextTime = node.positionConfig.getTimeProp(node, qObj.msg, node.timeData, dNow);
node.nextTime = node.positionConfig.getTimeProp(node, qObj.msg, node.timeData);
if (node.nextTime.error) {

@@ -319,12 +321,12 @@ node.debug('node.nextTime=' + util.inspect(node.nextTime, { colors: true, compact: 10, breakLength: Infinity }));

}
let millisec = hlp.getTimeOut(dNow, node.nextTime.value);
// let millisec = node.nextTime.value.valueOf() - dNow.valueOf();
node.debug(`set timeout to ${node.nextTime.value.valueOf()} - ${dNow.valueOf()}`);
let millisec = hlp.getTimeOut(node.timeData.now, node.nextTime.value);
// let millisec = node.nextTime.value.valueOf() - node.timeData.now.valueOf();
node.debug(`set timeout to ${node.nextTime.value.valueOf()} - ${node.timeData.now.valueOf()}`);
// while (millisec < 1) {
// millisec += 86400000; // 24h
// millisec += hlp.TIME_24h; // 24h
// }
if (millisec > 345600000) {
if (millisec > hlp.TIME_4d) {
// there is a limitation of nodejs that the maximum setTimeout time
// should not more then 2147483647 ms (24.8 days).
millisec = Math.min((millisec - 129600000), 2147483646);
millisec = Math.min((millisec - hlp.TIME_36h), 2147483646);
// node.debug('next inject is far far away, plan a inject time recalc in ' + millisec + ' ms');

@@ -331,0 +333,0 @@ node.delayTimer = setTimeout(() => {

@@ -53,3 +53,3 @@ /*

*
* @property {*} azimuthPos end offset multipier
* @property {*} azimuthPos ??
*/

@@ -82,17 +82,5 @@

// Retrieve the config node
/** @type {IPositionConfigNode} */
node.positionConfig = RED.nodes.getNode(config.positionConfig);
node.topic = config.topic || '';
node.rules = config.rules || [];
node.azimuthPos = {};
node.start = config.start;
node.startType = config.startType || 'none';
node.startOffset = config.startOffset || 0;
node.startOffsetType = config.startOffsetType || 'none';
node.startOffsetMultiplier = config.startOffsetMultiplier || 60;
node.end = config.end;
node.endType = config.endType || 'none';
node.endOffset = config.endOffset || 0;
node.endOffsetType = config.endOffsetType || 'none';
node.endOffsetMultiplier = config.endOffsetMultiplier || 60;
node.positionConfigValid = true;
if (!node.positionConfig) {

@@ -102,4 +90,35 @@ node.error(RED._('node-red-contrib-sun-position/position-config:errors.config-missing'));

return;
} else if (node.positionConfig.checkNode(
error => {
const text = RED._('node-red-contrib-sun-position/position-config:errors.config-error', { error });
node.warn(text);
node.status({fill: 'red', shape: 'dot', text });
return true;
}, false)) {
node.positionConfigValid = false;
} else {
node.status({});
}
// Retrieve the config node
node.topic = config.topic || '';
node.rules = config.rules || [];
node.azimuthPos = {};
node.start = {
type: config.startType || 'none',
value : config.start,
offsetType : config.startOffsetType || 'none',
offset : config.startOffset || 0,
multiplier : config.startOffsetMultiplier || 60,
next: false
};
node.end = {
type: config.endType || 'none',
value : config.end,
offsetType : config.endOffsetType || 'none',
offset : config.endOffset || 0,
multiplier : config.endOffsetMultiplier || 60,
next: false
};
node.on('input', function (msg, send, done) {

@@ -111,15 +130,46 @@ // If this is pre-1.0, 'done' will be undefined

try {
let errorStatus = '';
const dNow = hlp.getNowTimeStamp(this, msg);
const data = {
now : hlp.getNowTimeStamp(this, msg),
latitude: parseFloat(msg.latitude) || parseFloat(msg.lat),
longitude: parseFloat(msg.longitude) || parseFloat(msg.lon),
height: parseFloat(msg.height)
};
if (isNaN(data.latitude)) {
delete data.latitude;
} else if ((data.latitude < -90) || (data.latitude > 90)) {
node.error(RED._('node-red-contrib-sun-position/position-config:errors.latitude-wrong', data));
delete data.latitude;
}
if (isNaN(data.longitude)) {
delete data.longitude;
} else if ((data.longitude < -180) || (data.longitude > 180)) {
node.error(RED._('position-config.errors.longitude-missing', data));
delete data.longitude;
}
if (isNaN(data.height)) { delete data.height; }
if (!node.positionConfig) {
node.error(RED._('node-red-contrib-sun-position/position-config:errors.config-missing'));
// node.error(RED._('node-red-contrib-sun-position/position-config:errors.config-missing'));
node.status({fill: 'red', shape: 'dot', text: RED._('node-red-contrib-sun-position/position-config:errors.config-missing-state') });
done(RED._('node-red-contrib-sun-position/position-config:errors.config-missing'), msg);
return null;
} else if (!node.positionConfigValid) {
let text = '';
if (isNaN(this.latitude) || (this.latitude < -90) || (this.latitude > 90)) {
text = RED._('node-red-contrib-sun-position/errors.latitude-missing');
}
if (isNaN(this.longitude) || (this.longitude < -180) || (this.longitude > 180)) {
text = RED._('node-red-contrib-sun-position/errors.longitude-missing');
}
if (text) {
node.status({fill: 'red', shape: 'dot', text });
done(text, msg);
return null;
}
}
let errorStatus = '';
const ports = new Array(node.rules.length);
ports[0] = RED.util.cloneMessage(msg);
ports[0].payload = node.positionConfig.getSunCalc(dNow, true, false, msg.latitude || msg.lat, msg.longitude || msg.lon);
ports[0].payload = node.positionConfig.getSunCalc(data.now, true, false, data.latitude, data.longitude);
ports[0].topic = node.topic;

@@ -135,15 +185,5 @@ if (!ports[0].payload.azimuth) {

ports[0].payload.posChanged = false;
if (node.startType !== 'none') {
// const startTime = node.positionConfig.getTimeProp(node, msg, node.startType, node.start, node.startOffsetType, node.startOffset, node.startOffsetMultiplier);
const startTime = node.positionConfig.getTimeProp(node, msg, {
type: node.startType,
value : node.start,
offsetType : node.startOffsetType,
offset : node.startOffset,
multiplier : node.startOffsetMultiplier,
now: dNow,
latitude: msg.latitude || msg.lat,
longitude: msg.longitude || msg.lon
});
if (node.start.type !== 'none') {
const startTime = node.positionConfig.getTimeProp(node, msg, Object.assign({}, node.start, data));
node.debug('startTime: ' + util.inspect(startTime, { colors: true, compact: 10, breakLength: Infinity }));

@@ -159,14 +199,4 @@ if (startTime.error) {

if (node.endType !== 'none') {
// const endTime = node.positionConfig.getTimeProp(node, msg, node.endType, node.end, node.endOffsetType, node.endOffset, node.endOffsetMultiplier);
const endTime = node.positionConfig.getTimeProp(node, msg, {
type: node.endType,
value : node.end,
offsetType : node.endOffsetType,
offset : node.endOffset,
multiplier : node.endOffsetMultiplier,
now: dNow,
latitude: msg.latitude || msg.lat,
longitude: msg.longitude || msg.lon
});
if (node.end.type !== 'none') {
const endTime = node.positionConfig.getTimeProp(node, msg, Object.assign({}, node.end, data));

@@ -184,3 +214,3 @@ node.debug('endTime: ' + util.inspect(endTime, { colors: true, compact: 10, breakLength: Infinity }));

if (ports[0].payload.startTime && ports[0].payload.endTime) {
const nowMillis = dNow.getTime();
const nowMillis = data.now.getTime();
ports[0].payload.sunInSky = nowMillis > ports[0].payload.startTime && nowMillis < ports[0].payload.endTime;

@@ -199,2 +229,4 @@ }

ports[i + 1] = RED.util.cloneMessage(msg);
ports[i + 1].payload.sunPos = chk;
ports[i + 1].payload.posChanged = chg;
ports[i + 1].sunPos = chk;

@@ -274,3 +306,3 @@ ports[i + 1].posChanged = chg;

}
return node.positionConfig.getFloatProp(node, msg, vType, value, 0);
return node.positionConfig.getFloatProp(node, msg, { type: vType, value, def: 0 });
} catch (err) {

@@ -277,0 +309,0 @@ return undefined;

@@ -53,3 +53,3 @@ /*

*
* @property {*} azimuthPos end offset multipier
* @property {*} azimuthPos ??
*/

@@ -65,7 +65,6 @@

'use strict';
const path = require('path');
const hlp = require(path.join(__dirname, '/lib/dateTimeHelper.js'));
const hlp = require('./lib/dateTimeHelper.js');
const util = require('util');
/******************************************************************************************/
/**

@@ -83,6 +82,5 @@ * standard Node-Red Node handler for the moonPositionNode

// Retrieve the config node
/** @type {IPositionConfigNode} */
node.positionConfig = RED.nodes.getNode(config.positionConfig);
node.topic = config.topic || '';
node.rules = config.rules || [];
node.azimuthPos = {};
node.positionConfigValid = true;
if (!node.positionConfig) {

@@ -92,4 +90,18 @@ node.error(RED._('node-red-contrib-sun-position/position-config:errors.config-missing'));

return;
} else if (node.positionConfig.checkNode(
error => {
const text = RED._('node-red-contrib-sun-position/position-config:errors.config-error', { error });
node.warn(text);
node.status({fill: 'red', shape: 'dot', text });
return true;
}, false)) {
node.positionConfigValid = false;
} else {
node.status({});
}
// Retrieve the config node
node.topic = config.topic || '';
node.rules = config.rules || [];
node.azimuthPos = {};
node.on('input', function (msg, send, done) {

@@ -101,16 +113,46 @@ // If this is pre-1.0, 'done' will be undefined

try {
const errorStatus = '';
const dNow = hlp.getNowTimeStamp(this, msg);
const data = {
now : hlp.getNowTimeStamp(this, msg),
latitude: parseFloat(msg.latitude) || parseFloat(msg.lat),
longitude: parseFloat(msg.longitude) || parseFloat(msg.lon),
height: parseFloat(msg.height)
};
if (isNaN(data.latitude)) {
delete data.latitude;
} else if ((data.latitude < -90) || (data.latitude > 90)) {
node.error(RED._('node-red-contrib-sun-position/position-config:errors.latitude-wrong', data));
delete data.latitude;
}
if (isNaN(data.longitude)) {
delete data.longitude;
} else if ((data.longitude < -180) || (data.longitude > 180)) {
node.error(RED._('position-config.errors.longitude-missing', data));
delete data.longitude;
}
if (isNaN(data.height)) { delete data.height; }
if (!node.positionConfig) {
node.error(RED._('node-red-contrib-sun-position/position-config:errors.config-missing'));
// node.error(RED._('node-red-contrib-sun-position/position-config:errors.config-missing'));
node.status({fill: 'red', shape: 'dot', text: RED._('node-red-contrib-sun-position/position-config:errors.config-missing-state') });
done(RED._('node-red-contrib-sun-position/position-config:errors.config-missing'), msg);
return null;
} else if (!node.positionConfigValid) {
let text = '';
if (isNaN(this.latitude) || (this.latitude < -90) || (this.latitude > 90)) {
text = RED._('node-red-contrib-sun-position/errors.latitude-missing');
}
if (isNaN(this.longitude) || (this.longitude < -180) || (this.longitude > 180)) {
text = RED._('node-red-contrib-sun-position/errors.longitude-missing');
}
if (text) {
node.status({fill: 'red', shape: 'dot', text });
done(text, msg);
return null;
}
}
const errorStatus = '';
const ports = new Array(node.rules.length);
ports[0] = RED.util.cloneMessage(msg);
ports[0].payload = node.positionConfig.getMoonCalc(dNow, true, true, msg.latitude || msg.lat, msg.longitude || msg.lon);
ports[0].payload = node.positionConfig.getMoonCalc(data.now, true, true, data.latitude, data.longitude);
ports[0].topic = node.topic;

@@ -196,3 +238,3 @@ if (!ports[0].payload.azimuth) {

}
return node.positionConfig.getFloatProp(node, msg, vType, value, 0);
return node.positionConfig.getFloatProp(node, msg, { type: vType, value, def: 0 });
} catch (err) {

@@ -199,0 +241,0 @@ return undefined;

@@ -55,2 +55,3 @@ /*

'use strict';
const util = require('util');

@@ -70,2 +71,3 @@ const hlp = require('./lib/dateTimeHelper.js');

const node = this;
// Retrieve the config node

@@ -81,4 +83,6 @@ node.positionConfig = RED.nodes.getNode(config.positionConfig);

error => {
node.error(error);
node.status({fill: 'red', shape: 'dot', text: error });
const text = RED._('node-red-contrib-sun-position/position-config:errors.config-error', { error });
node.error(text);
node.status({fill: 'red', shape: 'dot', text });
return true;
}, false)) {

@@ -96,3 +100,3 @@ return;

};
if (node.input.type !== 'entered' && node.input.type !== 'pdsTime' && node.input.type !== 'pdmTime') {
if (node.input.type !== 'entered' && node.input.type !== 'pdsTime' && node.input.type !== 'pdsTimeCustom' && node.input.type !== 'pdmTime') {
node.input.next = false;

@@ -113,3 +117,3 @@ }

f : config.result1Format ? config.result1Format : 0,
next : false,
next : true,
days : '*',

@@ -135,19 +139,19 @@ months : '*',

const propNew = {
outType : prop.pt,
outValue : prop.p,
type : prop.vt,
value : prop.v,
format : prop.f,
offsetType : prop.oT,
offset : prop.o,
multiplier : parseFloat(prop.oM) || 60000,
next : (typeof prop.next === 'undefined' || prop.next === null || hlp.isTrue(prop.next)) ? true : false,
days : prop.days,
months : prop.months,
onlyEvenDays: prop.onlyEvenDays,
onlyOddDays : prop.onlyOddDays,
onlyEvenWeeks: prop.onlyEvenWeeks,
onlyOddWeeks : prop.onlyOddWeeks
outType : prop.pt,
outValue : prop.p,
type : prop.vt,
value : prop.v,
format : prop.f,
offsetType : prop.oT,
offset : prop.o,
multiplier : parseFloat(prop.oM) || 60000,
next : (typeof prop.next === 'undefined' || prop.next === null || hlp.isTrue(prop.next)) ? true : false,
days : prop.days,
months : prop.months,
onlyEvenDays : prop.onlyEvenDays === 'true' || prop.onlyEvenDays === true,
onlyOddDays : prop.onlyOddDays === 'true' || prop.onlyOddDays === true,
onlyEvenWeeks : prop.onlyEvenWeeks === 'true' || prop.onlyEvenWeeks === true,
onlyOddWeeks : prop.onlyOddWeeks === 'true' || prop.onlyOddWeeks === true
};
if (propNew.type !== 'entered' && propNew.type !== 'pdsTime' && propNew.type !== 'pdmTime') {
if (propNew.type !== 'entered' && propNew.type !== 'pdsTime' && propNew.type !== 'pdsTimeCustom' && propNew.type !== 'pdmTime') {
propNew.next = false;

@@ -158,3 +162,3 @@ }

try {
propNew.expr = node.positionConfig.getJSONataExpression(this, propNew.value);
propNew.expr = node.positionConfig.getJSONataExpression(node, propNew.value);
} catch (err) {

@@ -176,3 +180,3 @@ node.error(RED._('node-red-contrib-sun-position/position-config:errors.invalid-expr', { error: err.message }));

} else {
if (rule.operandType !== 'entered' && rule.operandType !== 'pdsTime' && rule.operandType !== 'pdmTime') {
if (rule.operandType !== 'entered' && rule.operandType !== 'pdsTime' && rule.operandType !== 'pdsTimeCustom' && rule.operandType !== 'pdmTime') {
rule.next = false;

@@ -228,3 +232,3 @@ }

try {
// const inputData = node.positionConfig.getDateFromProp(node, msg, node.input.type, node.input.value);
node.input.now = dNow;
const inputData = node.positionConfig.getTimeProp(node, msg, node.input);

@@ -241,6 +245,7 @@ if (inputData.error) {

if (prop.type === 'input') {
resultObj = node.positionConfig.formatOutDate(this, msg, inputData.value, prop);
resultObj = node.positionConfig.formatOutDate(node, msg, inputData.value, prop);
} else {
resultObj = node.positionConfig.getOutDataProp(this, msg, prop, dNow);
resultObj = node.positionConfig.getOutDataProp(node, msg, prop, dNow);
}
if (resultObj === null || (typeof resultObj === 'undefined')) {

@@ -251,3 +256,3 @@ node.error('Could not evaluate ' + prop.type + '.' + prop.value + '. - Maybe settings outdated (open and save again)!');

} else {
node.positionConfig.setMessageProp(this, msg, prop.outType, prop.outValue, resultObj);
node.positionConfig.setMessageProp(node, msg, prop.outType, prop.outValue, resultObj);
}

@@ -254,0 +259,0 @@ // node.debug(`prepOutMsg-${i} msg=${util.inspect(msg, { colors: true, compact: 10, breakLength: Infinity })}`);

@@ -43,3 +43,2 @@ /*

* @property {number} operand - operand
* operand
* @property {Array} results - output data

@@ -63,8 +62,2 @@ * @property {Array} rules - input data

const perSecond = 1000;
const perMinute = 60000;
const perHour = 3600000;
const perDay = 86400000;
const perWeek = 604800000;
/**

@@ -143,13 +136,13 @@ * get the differense between two month relative

const tl = timeSpan;
const ts = Math.floor(timeSpan / perSecond);
const tm = Math.floor(timeSpan / perMinute);
const tH = Math.floor(timeSpan / perHour);
const td = Math.floor(timeSpan / perDay);
const tw = Math.floor(timeSpan / perWeek);
const ts = Math.floor(timeSpan / hlp.TIME_1s);
const tm = Math.floor(timeSpan / hlp.TIME_1min);
const tH = Math.floor(timeSpan / hlp.TIME_1h);
const td = Math.floor(timeSpan / hlp.TIME_24h);
const tw = Math.floor(timeSpan / hlp.TIME_WEEK);
const l = timeSpan % 1000;
const s = Math.floor(timeSpan / perSecond) % 60;
const m = Math.floor(timeSpan / perMinute) % 60;
const H = Math.floor(timeSpan / perHour) % 24;
const d = Math.floor(timeSpan / perDay) % 7;
const s = Math.floor(timeSpan / hlp.TIME_1s) % 60;
const m = Math.floor(timeSpan / hlp.TIME_1min) % 60;
const H = Math.floor(timeSpan / hlp.TIME_1h) % 24;
const d = Math.floor(timeSpan / hlp.TIME_24h) % 7;
const M = getMonthDiffAbs(d1, d2);

@@ -232,11 +225,11 @@ const y = getYearDiffAbs(d1, d2);

case 1: // sec
return (timeSpan) / perSecond;
return (timeSpan) / hlp.TIME_1s;
case 2: // min
return (timeSpan) / perMinute;
return (timeSpan) / hlp.TIME_1min;
case 3: // hour
return (timeSpan) / perHour;
return (timeSpan) / hlp.TIME_1h;
case 4: // days
return (timeSpan) / perDay;
return (timeSpan) / hlp.TIME_24h;
case 5: // weeks
return (timeSpan) / perWeek;
return (timeSpan) / hlp.TIME_WEEK;
case 6: // month

@@ -253,11 +246,11 @@ if (date1.getTime() > date2.getTime()) {

case 11: // sec
return Math.floor((timeSpan) / perSecond);
return Math.floor((timeSpan) / hlp.TIME_1s);
case 12: // min
return Math.floor((timeSpan) / perMinute);
return Math.floor((timeSpan) / hlp.TIME_1min);
case 13: // hour
return Math.floor((timeSpan) / perHour);
return Math.floor((timeSpan) / hlp.TIME_1h);
case 14: // days
return Math.floor((timeSpan) / perDay);
return Math.floor((timeSpan) / hlp.TIME_24h);
case 15: // weeks
return Math.floor((timeSpan) / perWeek);
return Math.floor((timeSpan) / hlp.TIME_WEEK);
case 16: // full month

@@ -295,6 +288,6 @@ if (date1.getTime() > date2.getTime()) {

ms: timeSpan % 1000,
sec: Math.floor(timeSpan / perSecond) % 60,
sec: Math.floor(timeSpan / hlp.TIME_1s) % 60,
min: timeSpan % 1000,
hours: Math.floor(timeSpan / perHour) % 24,
days: Math.floor(timeSpan / perDay) % 7,
hours: Math.floor(timeSpan / hlp.TIME_1h) % 24,
days: Math.floor(timeSpan / hlp.TIME_24h) % 7,
month: getMonthDiffAbs(date1, date2),

@@ -305,7 +298,7 @@ years: getYearDiffAbs(date1, date2)

ms: timeSpan,
sec: (timeSpan / perSecond),
min: (timeSpan / perMinute),
hour: (timeSpan / perHour),
day: (timeSpan / perDay),
week: (timeSpan / perWeek),
sec: (timeSpan / hlp.TIME_1s),
min: (timeSpan / hlp.TIME_1min),
hour: (timeSpan / hlp.TIME_1h),
day: (timeSpan / hlp.TIME_24h),
week: (timeSpan / hlp.TIME_WEEK),
month: getMonthDiff(date1, date2),

@@ -333,3 +326,3 @@ year: getMonthDiff(date1, date2) / 12

node.error(RED._('node-red-contrib-sun-position/position-config:errors.config-missing'));
node.status({fill: 'red', shape: 'dot', text: RED._('node-red-contrib-sun-position/position-config:errors.config-missing') });
node.status({fill: 'red', shape: 'dot', text: RED._('node-red-contrib-sun-position/position-config:errors.config-missing-state') });
return;

@@ -339,4 +332,6 @@ }

error => {
node.error(error);
node.status({fill: 'red', shape: 'dot', text: error });
const text = RED._('node-red-contrib-sun-position/position-config:errors.config-error', { error });
node.error(text);
node.status({fill: 'red', shape: 'dot', text });
return true;
}, false)) {

@@ -348,2 +343,3 @@ return;

value: config.operand1,
next: hlp.isTrue(config.operand1Next),
format: config.operand1Format,

@@ -354,2 +350,5 @@ offsetType: config.operand1OffsetType,

};
if (node.operand1.type !== 'entered' && node.operand1.type !== 'pdsTime' && node.operand1.type !== 'pdsTimeCustom' && node.operand1.type !== 'pdmTime') {
node.operand1.next = false;
}

@@ -359,2 +358,3 @@ node.operand2 = {

value: config.operand2,
next: hlp.isTrue(config.operand2Next),
format: config.operand2Format,

@@ -365,2 +365,5 @@ offsetType: config.operand2OffsetType,

};
if (node.operand2.type !== 'entered' && node.operand2.type !== 'pdsTime' && node.operand2.type !== 'pdsTimeCustom' && node.operand2.type !== 'pdmTime') {
node.operand2.next = false;
}

@@ -409,3 +412,3 @@ if (!Array.isArray(config.results)) {

offset : prop.o,
multiplier : prop.oM,
multiplier : parseFloat(prop.oM) || 60000,
outTSFormat : prop.fTs,

@@ -415,11 +418,14 @@ next : (typeof prop.next === 'undefined' || prop.next === null || hlp.isTrue(prop.next)) ? true : false,

months : prop.months,
onlyEvenDays : prop.onlyEvenDays,
onlyOddDays : prop.onlyOddDays,
onlyEvenWeeks : prop.onlyEvenWeeks,
onlyOddWeeks : prop.onlyOddWeeks
onlyEvenDays : prop.onlyEvenDays === 'true' || prop.onlyEvenDays === true,
onlyOddDays : prop.onlyOddDays === 'true' || prop.onlyOddDays === true,
onlyEvenWeeks : prop.onlyEvenWeeks === 'true' || prop.onlyEvenWeeks === true,
onlyOddWeeks : prop.onlyOddWeeks === 'true' || prop.onlyOddWeeks === true
};
if (propNew.type !== 'entered' && propNew.type !== 'pdsTime' && propNew.type !== 'pdsTimeCustom' && propNew.type !== 'pdmTime') {
propNew.next = false;
}
if (node.positionConfig && propNew.type === 'jsonata') {
try {
propNew.expr = node.positionConfig.getJSONataExpression(this, propNew.value);
propNew.expr = node.positionConfig.getJSONataExpression(node, propNew.value);
} catch (err) {

@@ -432,6 +438,43 @@ node.error(RED._('node-red-contrib-sun-position/position-config:errors.invalid-expr', { error: err.message }));

});
node.operand = config.operand;
node.checkall = config.checkall === 'true' || config.checkall === true;
node.rules = config.rules;
node.checkall = config.checkall;
const rulesLength = node.rules.length;
for (let i = 0; i < rulesLength; ++i) {
const rule = node.rules[i];
rule.operator = Number(rule.operator);
if (rule.operator === 99) {
rule.next = false;
} else {
if (rule.operandType !== 'entered' && rule.operandType !== 'pdsTime' && rule.operandType !== 'pdsTimeCustom' && rule.operandType !== 'pdmTime') {
rule.next = false;
}
}
rule.compare = null;
rule.result = false;
switch (rule.operator) {
case 1: // equal { id: 1, group: "ms", label: "==", "text": "equal" },
rule.compare = (op1, op2) => op1 === op2;
break;
case 2: // unequal { id: 2, group: "ms", label: "!=", "text": "unequal" },
rule.compare = (op1, op2) => op1 !== op2;
break;
case 3: // greater { id: 3, group: "ms", label: ">", "text": "greater" },
rule.compare = (op1, op2) => op1 > op2;
break;
case 4: // greaterOrEqual { id: 5, group: "ms", label: ">=", "text": "greater or equal" },
rule.compare = (op1, op2) => op1 >= op2;
break;
case 5: // lesser { id: 6, group: "ms", label: "<", "text": "lesser" },
rule.compare = (op1, op2) => op1 < op2;
break;
case 6: // lesserOrEqual { id: 7, group: "ms", label: "<=", "text": "lesser or equal" },
rule.compare = (op1, op2) => op1 <= op2;
break;
case 99: // otherwise
rule.result = true;
break;
}
}
node.on('input', (msg, send, done) => {

@@ -471,10 +514,6 @@ // If this is pre-1.0, 'done' will be undefined

let timeSpan = operand1.value.getTime() - operand2.value.getTime();
if (node.operand === 0) {
timeSpan = Math.abs(timeSpan);
}
for (let i = 0; i < node.results.length; i++) {
const prop = node.results[i];
// node.debug(`prepOutMsg-${i} node.results[${i}]=${util.inspect(prop, { colors: true, compact: 10, breakLength: Infinity })}`);
let resultObj = null;

@@ -484,5 +523,5 @@ if (prop.type === 'timespan') {

} else if (prop.type === 'operand1') {
resultObj = node.positionConfig.formatOutDate(this, msg, operand1.value, prop);
resultObj = node.positionConfig.formatOutDate(node, msg, operand1.value, prop);
} else if (prop.type === 'operand2') {
resultObj = node.positionConfig.formatOutDate(this, msg, operand2.value, prop);
resultObj = node.positionConfig.formatOutDate(node, msg, operand2.value, prop);
} else {

@@ -497,3 +536,3 @@ resultObj = node.positionConfig.getOutDataProp(node, msg, prop, dNow);

} else {
node.positionConfig.setMessageProp(this, msg, prop.outType, prop.outValue, resultObj);
node.positionConfig.setMessageProp(node, msg, prop.outType, prop.outValue, resultObj);
}

@@ -503,39 +542,20 @@ // node.debug(`prepOutMsg-${i} msg=${util.inspect(msg, { colors: true, compact: 10, breakLength: Infinity })}`);

const timeSpan = operand1.value.getTime() - operand2.value.getTime();
const resObj = [];
const rulesLength = node.rules.length;
for (let i = 0; i < rulesLength; ++i) {
const rule = node.rules[i];
const rule = node.rules[i];
try {
let ruleoperand = node.positionConfig.getFloatProp(node, msg, rule.operandType, rule.operandValue, 0);
if (!isNaN(rule.multiplier) && rule.multiplier !== 0) {
ruleoperand = ruleoperand * rule.multiplier;
rule.result = rule.operator === 99;
if (rule.compare) {
let ruleoperand = node.positionConfig.getFloatProp(node, msg,
{ type: rule.operandType, value: rule.operandValue, def: 0 });
if (!isNaN(rule.multiplier) && rule.multiplier !== 0) {
ruleoperand = ruleoperand * rule.multiplier;
}
rule.result = rule.compare(timeSpan, ruleoperand);
}
let result = false;
switch (parseInt(rule.operator)) {
case 1: // equal
result = (timeSpan === ruleoperand);
break;
case 2: // unequal
result = (timeSpan !== ruleoperand);
break;
case 3: // greater
result = (timeSpan > ruleoperand);
break;
case 4: // greaterOrEqual
result = (timeSpan >= ruleoperand);
break;
case 5: // lesser
result = (timeSpan < ruleoperand);
break;
case 6: // lesserOrEqual
result = (timeSpan <= ruleoperand);
break;
case 99: // otherwise
result = true;
break;
}
if (result) {
if (rule.result) {
resObj.push(msg);
if (node.checkall != 'true') { // eslint-disable-line eqeqeq
if (!node.checkall) { // eslint-disable-line eqeqeq
break;

@@ -583,2 +603,3 @@ }

});
node.status({});
}

@@ -585,0 +606,0 @@

@@ -63,6 +63,2 @@ // @ts-check

const cRuleUntil = 0;
const cRuleFrom = 1;
const cRuleDefault = -1;
/******************************************************************************************/

@@ -205,115 +201,57 @@ /**

// node.debug('checkRules --------------------');
ctrlLib.prepareRules(node, msg, tempData, oNow.now);
const rule = ctrlLib.getActiveRule(node, msg, oNow, tempData);
const livingRuleData = {};
ctrlLib.prepareRules(node, msg, tempData, oNow.now);
// node.debug(`checkRules rules.count=${node.rules.count}, rules.lastUntil=${node.rules.lastUntil}, oNow=${util.inspect(oNow, {colors:true, compact:10})}`);
let ruleSel = null;
let ruleindex = -1;
// node.debug('first loop count:' + node.rules.count + ' lastuntil:' + node.rules.lastUntil);
for (let i = 0; i <= node.rules.lastUntil; ++i) {
const rule = node.rules.data[i];
// node.debug('rule ' + rule.time.operator + ' - ' + (rule.time.operator !== cRuleFrom) + ' - ' + util.inspect(rule, {colors:true, compact:10, breakLength: Infinity }));
if (!rule.enabled) { continue; }
if (rule.time && rule.time.operator === cRuleFrom) { continue; }
// const res = fktCheck(rule, r => (r >= nowNr));
const res = ctrlLib.compareRules(node, msg, rule, r => (r >= oNow.nowNr), oNow);
if (res) {
// node.debug(`1. ruleSel ${rule.name} (${rule.pos}) data=${ util.inspect(res, { colors: true, compact: 10, breakLength: Infinity }) }`);
ruleSel = res;
ruleindex = i;
break;
}
}
if (!ruleSel || (ruleSel.time && ruleSel.time.operator === cRuleFrom) ) {
// node.debug('--------- starting second loop ' + node.rules.count);
for (let i = (node.rules.count - 1); i >= 0; --i) {
const rule = node.rules.data[i];
// node.debug(`rule ${rule.name} (${rule.pos}) enabled=${rule.enabled} operator=${rule.time.operator} noUntil=${rule.time.operator !== cRuleUntil} data=${util.inspect(rule, {colors:true, compact:10, breakLength: Infinity })}`);
if (!rule.enabled) { continue; }
if (rule.time && rule.time.operator === cRuleUntil) { continue; } // - From: timeOp === cRuleFrom
const res = ctrlLib.compareRules(node, msg, rule, r => (r <= oNow.nowNr), oNow);
if (res) {
// node.debug(`2. ruleSel ${rule.name} (${rule.pos}) data=${ util.inspect(res, { colors: true, compact: 10, breakLength: Infinity }) }`);
ruleSel = res;
break;
}
}
}
const checkRuleForAT = rule => {
if (!rule.time) {
return;
}
const num = ctrlLib.getRuleTimeData(node, msg, rule, oNow);
if (num > oNow.nowNr) {
node.debug('autoTrigger set to rule ' + rule.pos);
const diff = num - oNow.nowNr;
node.autoTrigger.time = Math.min(node.autoTrigger.time, diff);
node.autoTrigger.type = 2; // next rule
}
};
if (ruleSel) {
if (node.autoTrigger) {
if (ruleSel.time && ruleSel.timeData.ts > oNow.nowNr) {
node.debug('autoTrigger set to rule ' + ruleSel.pos + ' (current)');
const diff = ruleSel.timeData.ts - oNow.nowNr;
node.autoTrigger.time = Math.min(node.autoTrigger.time, diff);
node.autoTrigger.type = 1; // current rule end
} else {
for (let i = (ruleindex+1); i < node.rules.count; ++i) {
const rule = node.rules.data[i];
if (!rule.time) {
continue;
}
checkRuleForAT(rule);
}
// check first rule, maybe next day
if ((node.autoTrigger.type !== 2) && (node.rules.firstTimeLimited < node.rules.count)) {
checkRuleForAT(node.rules.data[node.rules.firstTimeLimited]);
}
}
}
// ruleSel.text = '';
// node.debug('ruleSel ' + util.inspect(ruleSel, {colors:true, compact:10, breakLength: Infinity }));
livingRuleData.id = ruleSel.pos;
livingRuleData.name = ruleSel.name;
livingRuleData.importance = ruleSel.importance;
livingRuleData.resetOverwrite = ruleSel.resetOverwrite;
if (rule.ruleSel) {
// rule.ruleSel.text = '';
// node.debug('rule.ruleSel ' + util.inspect(rule.ruleSel, {colors:true, compact:10, breakLength: Infinity }));
livingRuleData.id = rule.ruleSel.pos;
livingRuleData.name = rule.ruleSel.name;
livingRuleData.importance = rule.ruleSel.importance;
livingRuleData.resetOverwrite = rule.ruleSel.resetOverwrite;
livingRuleData.code = 4;
livingRuleData.topic = ruleSel.topic;
livingRuleData.topic = rule.ruleSel.topic;
livingRuleData.active = true;
livingRuleData.outputValue = ruleSel.outputValue;
livingRuleData.outputType = ruleSel.outputType;
// livingRuleData.outputValue = rule.ruleSel.outputValue;
// livingRuleData.outputType = rule.ruleSel.outputType;
livingRuleData.conditional = ruleSel.conditional;
livingRuleData.timeLimited = (!!ruleSel.time);
livingRuleData.payloadData = ruleSel.payload;
const data = { number: ruleSel.pos, name: ruleSel.name };
livingRuleData.conditional = rule.ruleSel.conditional;
livingRuleData.timeLimited = (!!rule.ruleSel.time);
livingRuleData.payloadData = rule.ruleSel.payload;
const data = { number: rule.ruleSel.pos, name: rule.ruleSel.name };
let name = 'rule';
if (ruleSel.conditional) {
livingRuleData.conditon = ruleSel.conditon;
data.text = ruleSel.conditon.text;
data.textShort = ruleSel.conditon.textShort;
if (rule.ruleSel.conditional) {
livingRuleData.conditon = rule.ruleSel.conditonResult;
data.text = rule.ruleSel.conditonResult.text;
data.textShort = rule.ruleSel.conditonResult.textShort;
name = 'ruleCond';
}
if (ruleSel.time && ruleSel.timeData) {
livingRuleData.time = ruleSel.timeData;
livingRuleData.time.timeLocal = node.positionConfig.toTimeString(ruleSel.timeData.value);
livingRuleData.time.timeLocalDate = node.positionConfig.toDateString(ruleSel.timeData.value);
livingRuleData.time.dateISO= ruleSel.timeData.value.toISOString();
livingRuleData.time.dateUTC= ruleSel.timeData.value.toUTCString();
data.timeOp = ruleSel.time.operatorText;
data.timeLocal = livingRuleData.time.timeLocal;
data.time = livingRuleData.time.dateISO;
name = (ruleSel.conditional) ? 'ruleTimeCond' : 'ruleTime';
if (rule.ruleSel.time && rule.ruleSel.timeResult) {
livingRuleData.time = rule.ruleSel.timeResult;
if (livingRuleData.time.start) {
livingRuleData.time.start.timeLocal = node.positionConfig.toTimeString(rule.ruleSel.timeResult.start.value);
livingRuleData.time.start.timeLocalDate = node.positionConfig.toDateString(rule.ruleSel.timeResult.start.value);
livingRuleData.time.start.dateISO= rule.ruleSel.timeResult.start.value.toISOString();
livingRuleData.time.start.dateUTC= rule.ruleSel.timeResult.start.value.toUTCString();
}
if (livingRuleData.time.end) {
livingRuleData.time.end.timeLocal = node.positionConfig.toTimeString(rule.ruleSel.timeResult.end.value);
livingRuleData.time.end.timeLocalDate = node.positionConfig.toDateString(rule.ruleSel.timeResult.end.value);
livingRuleData.time.end.dateISO= rule.ruleSel.timeResult.end.value.toISOString();
livingRuleData.time.end.dateUTC= rule.ruleSel.timeResult.end.value.toUTCString();
}
// data.timeOp = rule.ruleSel.time.operatorText;
// data.timeLocal = livingRuleData.time.timeLocal;
// data.time = livingRuleData.time.dateISO;
name = (rule.ruleSel.conditional) ? 'ruleTimeCond' : 'ruleTime';
}
livingRuleData.state = RED._('node-red-contrib-sun-position/position-config:ruleCtrl.states.'+name, data);
livingRuleData.description = RED._('node-red-contrib-sun-position/position-config:ruleCtrl.reasons.'+name, data);
// node.debug(`checkRules end livingRuleData=${util.inspect(livingRuleData, { colors: true, compact: 10, breakLength: Infinity })}`);
// node.debug(`checkRules end livingRuleData=${util.inspect(livingRuleData, { colors: true, compact: 5, breakLength: Infinity, depth: 10 })}`);
return livingRuleData;
}
livingRuleData.active = false;
livingRuleData.id = cRuleDefault;
livingRuleData.id = ctrlLib.cRuleDefault;
livingRuleData.importance = 0;

@@ -335,12 +273,3 @@ livingRuleData.resetOverwrite = false;

if (node.autoTrigger && node.rules && node.rules.count > 0) {
// check first rule, maybe next day
if (node.rules.firstTimeLimited < node.rules.count) {
checkRuleForAT(node.rules.data[node.rules.firstTimeLimited]);
}
if (node.rules.firstTimeLimited !== node.rules.firstFrom) {
checkRuleForAT(node.rules.data[node.rules.firstFrom]);
}
}
// node.debug(`checkRules end livingRuleData=${util.inspect(livingRuleData, { colors: true, compact: 10, breakLength: Infinity })}`);
// node.debug(`checkRules end livingRuleData=${util.inspect(livingRuleData, { colors: true, compact: 5, breakLength: Infinity, depth: 10 })}`);
return livingRuleData;

@@ -356,4 +285,2 @@ }

RED.nodes.createNode(this, config);
this.positionConfig = RED.nodes.getNode(config.positionConfig);
this.outputs = Number(config.outputs || 1);
/** Copy 'this' object in case we need it in context of callbacks of other functions.

@@ -364,11 +291,18 @@ * @type {IClockTimerNode}

const node = this;
if (!this.positionConfig) {
/** @type {IPositionConfigNode} */
node.positionConfig = RED.nodes.getNode(config.positionConfig);
// node.outputs = Number(config.outputs || 1);
if (!node.positionConfig) {
node.error(RED._('node-red-contrib-sun-position/position-config:errors.config-missing'));
node.status({fill: 'red', shape: 'dot', text: RED._('node-red-contrib-sun-position/position-config:errors.config-missing') });
node.status({fill: 'red', shape: 'dot', text: RED._('node-red-contrib-sun-position/position-config:errors.config-missing-state') });
return;
}
if (this.positionConfig.checkNode(
if (node.positionConfig.checkNode(
error => {
node.error(error);
node.status({fill: 'red', shape: 'dot', text: error });
const text = RED._('node-red-contrib-sun-position/position-config:errors.config-error', { error });
node.error(text);
node.status({fill: 'red', shape: 'dot', text });
return true;
}, false)) {

@@ -401,3 +335,3 @@ return;

node.autoTrigger = {
defaultTime : parseInt(config.autoTriggerTime) || 20 * 60000, // 20min
defaultTime : parseInt(config.autoTriggerTime) || hlp.TIME_20min,
time : NaN,

@@ -415,3 +349,3 @@ type : 0 // default time

// temporary node Data
node.contextStore = config.contextStore || this.positionConfig.contextStore;
node.contextStore = config.contextStore || node.positionConfig.contextStore;
node.nodeData = {

@@ -455,3 +389,3 @@ isDisabled: node.context().get('isDisabled', node.contextStore) || false,

node.debug(`--------- clock-timer - input msg.topic=${msg.topic} msg.payload=${msg.payload} msg.ts=${msg.ts}`);
if (!this.positionConfig) {
if (!node.positionConfig) {
node.error(RED._('node-red-contrib-sun-position/position-config:errors.config-missing'));

@@ -475,3 +409,3 @@ node.status({fill: 'red', shape: 'dot', text: RED._('node-red-contrib-sun-position/position-config:errors.config-missing-state') });

case 'setAutoTriggerTime':
node.autoTrigger.defaultTime = parseInt(msg.payload) || node.autoTrigger.defaultTime; // payload of 0 makes no sense, use then default
node.autoTrigger = Object.assign(node.autoTrigger ,{ defaultTime : parseInt(msg.payload) || node.autoTrigger.defaultTime }); // payload of 0 makes no sense, use then default
break;

@@ -534,7 +468,11 @@ case 'setContextStore':

value: node.nodeData.addId,
callback: (result, _obj) => {
callback: (result, _obj, cachable) => {
return ctrlLib.evalTempData(node, _obj.type, _obj.value, result, tempData, cachable);
}
/* callback: (result, _obj) => {
if (result !== null && typeof result !== 'undefined') {
tempData[_obj.type + '.' + _obj.value] = result;
}
}
return result;
} */
}, true, oNow.now);

@@ -630,3 +568,3 @@ }

if (resultObj.error) {
this.error('error on getting result: "' + resultObj.error + '"');
node.error('error on getting result: "' + resultObj.error + '"');
} else {

@@ -652,9 +590,9 @@ node.positionConfig.setMessageProp(this, msgOut, prop.outType, prop.outValue, resultObj);

node.debug('next autoTrigger will set to ' + node.autoTrigger.time + ' - ' + node.autoTrigger.type);
if (node.autoTriggerObj) {
clearTimeout(node.autoTriggerObj);
delete node.autoTriggerObj;
if (node.autoTrigger.timer) {
clearTimeout(node.autoTrigger.timer);
delete node.autoTrigger.timer;
}
node.autoTriggerObj = setTimeout(() => {
clearTimeout(node.autoTriggerObj);
delete node.autoTriggerObj;
node.autoTrigger.timer = setTimeout(() => {
clearTimeout(node.autoTrigger.timer);
delete node.autoTrigger.timer;
node.emit('input', {

@@ -711,5 +649,5 @@ topic: 'autoTrigger/triggerOnly',

node.on('close', () => {
if (node.autoTriggerObj) {
clearTimeout(node.autoTriggerObj);
delete node.autoTriggerObj;
if (node.autoTrigger && node.autoTrigger.timer) {
clearTimeout(node.autoTrigger.timer);
delete node.autoTrigger.timer;
}

@@ -716,0 +654,0 @@ if (node.startDelayTimeOutObj) {

@@ -43,2 +43,3 @@ // @ts-check

* @property {number} time - next autotrigger in milliseconds
* @property {NodeJS.Timeout} [timer] - autotrigger TimeOut Object
*/

@@ -102,6 +103,2 @@

* @property {Date} [now] - start time definition
*
* @property {(0|1)} [operator] - time operator
* @property {(0|1)} [operatorText] - time operator text
*
* @property {IRuleTimeDefSingle} [min] - minimum limitation to the time

@@ -112,6 +109,13 @@ * @property {IRuleTimeDefSingle} [max] - maximum limitation to the time

/**
* @typedef {ILimitationsObj & IRuleTimeDef} IRuleTimesDef object for a rule time definition
* @typedef {Object} IRuleTimesDefInt object for a rule time definition
*
* @property {IRuleTimeDef} [start] - start time definition
* @property {IRuleTimeDef} [end] - end time definition
*/
/**
* @typedef {ILimitationsObj & IRuleTimesDefInt} IRuleTimesDef object for a rule time definition
*/
/**
* @typedef {Object} ITimePropertyResultInt object for a rule time definition

@@ -126,3 +130,2 @@ *

* @property {('default'|'min'|'max')} [source] - source of the data if it comes from minimum or maximum limitation
* @property {number} [now] - start time definition
*/

@@ -135,2 +138,17 @@

/**
* @typedef {Object} IRuleTimeDataDef object for a rule time definition
*
* @property {ITimePropResult} [start] - start time definition
* @property {ITimePropResult} [end] - end time definition
* @property {number} [now] - start time definition
*/
/**
* @typedef {Object} IRuleTimeDataMinMaxDef object for a rule time definition
*
* @property {ITimePropResult} [start] - start time definition
* @property {ITimePropResult} [end] - end time definition
*/
/**
* @typedef {Object} IRuleData object for a rule

@@ -146,9 +164,7 @@ * @property {boolean} enabled - defines if a rle is enabled or disabled

* @property {Array.<IRuleCondition>} conditions - conditions for a rule
* @property {IRuleConditionResult} conditon - condition resule
* @property {IRuleConditionResult} conditonResult - condition resule
* @property {IRuleTimesDef} [time] - rule time Data
* @property {IRuleTimesDef} [timeMin] - rule time Data
* @property {IRuleTimesDef} [timeMax] - rule time Data
* @property {ITimePropResult} [timeData] - object for storing time Data
* @property {ITimePropResult} [timeDataMin] - object for storing time Data
* @property {ITimePropResult} [timeDataMax] - object for storing time Data
* @property {IRuleTimeDataDef} [timeResult] - object for storing time Data
* @property {IRuleTimeDataMinMaxDef} [timeResultMin] - object for storing time Data
* @property {IRuleTimeDataMinMaxDef} [timeResultMax] - object for storing time Data
* @property {Object} [payload] - rule time Data

@@ -170,5 +186,5 @@ * @property {Object} [level] - rule time Data

* @property {IRuleData} [ruleSelMax] - selected rule
* @property {IRuleTimesDef} [timeResult] - object for storing time Data
* @property {IRuleTimesDef} [timeResultMin] - object for storing time Data
* @property {IRuleTimesDef} [timeResultMax] - object for storing time Data
* @property {IRuleTimeDataDef} [timeResult] - object for storing time Data
* @property {IRuleTimeDataDef} [timeResultMin] - object for storing time Data
* @property {IRuleTimeDataDef} [timeResultMax] - object for storing time Data
*/

@@ -180,5 +196,3 @@

* @property {number} count - executuion type of a rule which is defined
* @property {number} lastUntil - last rule for first evaluation loop
* @property {number} firstFrom - first from rule
* @property {number} firstTimeLimited - first from rule with time limitation
* @property {number} last1stRun - last rule for first evaluation loop
* @property {number} maxImportance - maximum inportance of all rules

@@ -217,3 +231,2 @@ * @property {boolean} canResetOverwrite - __true__ if any rule can overwrite reset

* @property {IAutoTrigger} autoTrigger autotrigger options
* @property {NodeJS.Timeout} [autoTriggerObj] - autotrigger TimeOut Object
*

@@ -233,2 +246,22 @@ * @property {Object} startDelayTimeOut - tbd

const cRuleType = {
absolute : 0,
levelMinOversteer : 1, // ⭳❗ minimum (oversteer)
levelMaxOversteer : 2, // ⭱️❗ maximum (oversteer)
slatOversteer : 5,
topicOversteer : 8,
off : 9
};
const cRuleDefault = -1;
const cRuleLogOperatorAnd = 2;
const cRuleLogOperatorOr = 1;
const cNBC_RULE_TYPE_UNTIL = 0;
const cNBC_RULE_TYPE_FROM = 1;
const cNBC_RULE_EXEC = {
auto: 0,
first:1,
last:2
};
module.exports = {

@@ -245,13 +278,10 @@ isNullOrUndefined,

compareRules,
initializeCtrl
getActiveRule,
initializeCtrl,
cRuleType,
cRuleDefault,
cRuleLogOperatorAnd,
cRuleLogOperatorOr
};
const cRuleUntil = 0;
const cRuleFrom = 1;
const cRuleAbsolute = 0;
// const cRuleNone = 0;
// const cRuleMinOversteer = 1; // ⭳❗ minimum (oversteer)
// const cRuleMaxOversteer = 2; // ⭱️❗ maximum (oversteer)
const cRuleLogOperatorAnd = 2;
const cRuleLogOperatorOr = 1;
let RED = null;

@@ -284,5 +314,9 @@ /******************************************************************************************/

* @param {Object} tempData object which holding the chached data
* @param {boolean} [cachable = false] defines if the value is cachable
* @returns {*} data which was cached
*/
function evalTempData(node, type, value, data, tempData) {
function evalTempData(node, type, value, data, tempData, cachable) {
if (!cachable) {
return data;
}
// node.debug(`evalTempData type=${type} value=${value} data=${data}`);

@@ -447,4 +481,7 @@ const name = `${type}.${value}`;

const rule = node.rules.data[i];
if (rule.time) {
delete rule.timeResult;
}
if (rule.conditional) {
rule.conditon = {
rule.conditonResult = {
index : -1,

@@ -455,5 +492,5 @@ result : false

const el = rule.conditions[i];
if (rule.conditon.result === true && el.condition === cRuleLogOperatorOr) {
if (rule.conditonResult.result === true && el.condition === cRuleLogOperatorOr) {
break; // not nessesary, becaue already tue
} else if (rule.conditon.result === false && el.condition === cRuleLogOperatorAnd) {
} else if (rule.conditonResult.result === false && el.condition === cRuleLogOperatorAnd) {
break; // should never bekome true

@@ -472,6 +509,8 @@ }

expr: el.valueExpr,
callback: (result, _obj) => { // opCallback
callback: (result, _obj, cachable) => { // opCallback
el.valueWorth = _obj.value;
return evalTempData(node, _obj.type, _obj.value, result, tempData);
}
return evalTempData(node, _obj.type, _obj.value, result, tempData, cachable);
},
noError:false,
now: dNow
},

@@ -482,10 +521,12 @@ el.operator,

type: el.thresholdType,
callback: (result, _obj) => { // opCallback
callback: (result, _obj, cachable) => { // opCallback
el.thresholdWorth = _obj.value;
return evalTempData(node, _obj.type, _obj.value, result, tempData);
}
}, false, dNow
return evalTempData(node, _obj.type, _obj.value, result, tempData, cachable);
},
noError:false,
now: dNow
}
);
}
rule.conditon = {
rule.conditonResult = {
index : i,

@@ -497,4 +538,4 @@ result : el.result,

if (typeof el.thresholdWorth !== 'undefined') {
rule.conditon.text += ' ' + el.thresholdWorth;
rule.conditon.textShort += ' ' + hlp.clipStrLength(el.thresholdWorth, 10);
rule.conditonResult.text += ' ' + el.thresholdWorth;
rule.conditonResult.textShort += ' ' + hlp.clipStrLength(el.thresholdWorth, 10);
}

@@ -511,52 +552,63 @@ }

* @param {IRuleData} rule the rule data
* @param {('start'|'end')} timep rule type
* @param {Date} dNow base timestamp
* @param {number} def default value
*/
function getRuleTimeData(node, msg, rule, dNow) {
rule.time.now = dNow;
rule.timeData = node.positionConfig.getTimeProp(node, msg, rule.time);
if (rule.timeData.error) {
hlp.handleError(node, RED._('node-red-contrib-sun-position/position-config:errors.error-time', { message: rule.timeData.error }), undefined, rule.timeData.error);
return -1;
} else if (!rule.timeData.value) {
function getRuleTimeData(node, msg, rule, timep, dNow, def) {
if (!rule.timeResult) { rule.timeResult = {}; }
if (!rule.time || !rule.time[timep]) {
Object.assign(rule.timeResult, { [timep]: { ts: def } });
return;
}
rule.time[timep].now = dNow;
Object.assign(rule, { timeResult: { [timep]: node.positionConfig.getTimeProp(node, msg, rule.time[timep]) } });
if (rule.timeResult[timep].error) {
hlp.handleError(node, RED._('node-red-contrib-sun-position/position-config:errors.error-time', { message: rule.timeResult[timep].error }), undefined, rule.timeResult[timep].error);
Object.assign(rule.timeResult, { [timep]: { ts: def } });
// node.debug('rule data complete');
// node.debug(util.inspect(rule, { colors: true, compact: 10, depth: 10, breakLength: Infinity }));
return;
} else if (!rule.timeResult[timep].value) {
throw new Error('Error can not calc time!');
}
rule.timeData.source = 'default';
rule.timeData.ts = rule.timeData.value.getTime();
// node.debug(`time=${rule.timeData.value} -> ${new Date(rule.timeData.value)}`);
rule.timeData.dayId = hlp.getDayId(rule.timeData.value);
if (rule.timeMin) {
rule.timeMin.now = dNow;
rule.timeDataMin = node.positionConfig.getTimeProp(node, msg, rule.timeMin);
const numMin = rule.timeDataMin.value.getTime();
rule.timeDataMin.source = 'min';
if (rule.timeDataMin.error) {
hlp.handleError(node, RED._('node-red-contrib-sun-position/position-config:errors.error-time', { message: rule.timeDataMin.error }), undefined, rule.timeDataMin.error);
} else if (!rule.timeDataMin.value) {
throw new Error('Error can not calc Alt time!');
rule.timeResult[timep].source = 'default';
rule.timeResult[timep].ts = rule.timeResult[timep].value.getTime();
// node.debug(`time=${rule.timeResult[timep].value} -> ${new Date(rule.timeResult[timep].value)}`);
if (rule.time[timep].min) {
rule.time[timep].min.now = dNow;
// @ts-ignore
if (!rule.timeResultMin) rule.timeResultMin = { start:{}, end:{} };
rule.timeResultMin[timep] = node.positionConfig.getTimeProp(node, msg, rule.time[timep].min);
rule.timeResultMin[timep].source = 'min';
if (rule.timeResultMin[timep].error) {
hlp.handleError(node, RED._('node-red-contrib-sun-position/position-config:errors.error-time', { message: rule.timeResultMin[timep].error }), undefined, rule.timeResultMin[timep].error);
} else if (!rule.timeResultMin[timep].value) {
throw new Error('Error can not calc minimum time!');
} else {
if (numMin > rule.timeData.ts) {
[rule.timeData, rule.timeDataMin] = [rule.timeDataMin, rule.timeData];
rule.timeData.ts = numMin;
rule.timeData.dayId = hlp.getDayId(rule.timeDataMin.value);
rule.timeResultMin[timep].ts = rule.timeResultMin[timep].value.getTime();
if (rule.timeResultMin[timep].ts > rule.timeResult[timep].ts) {
[rule.timeResult[timep], rule.timeResultMin[timep]] = [rule.timeResultMin[timep], rule.timeResult[timep]];
}
}
}
if (rule.timeMax) {
rule.timeMax.now = dNow;
rule.timeDataMax = node.positionConfig.getTimeProp(node, msg, rule.timeMax);
const numMax = rule.timeDataMax.value.getTime();
rule.timeDataMax.source = 'max';
if (rule.timeDataMax.error) {
hlp.handleError(node, RED._('node-red-contrib-sun-position/position-config:errors.error-time', { message: rule.timeDataMax.error }), undefined, rule.timeDataMax.error);
} else if (!rule.timeDataMax.value) {
throw new Error('Error can not calc Alt time!');
if (rule.time[timep].max) {
rule.time[timep].max.now = dNow;
// @ts-ignore
if (!rule.timeResultMax) rule.timeResultMax = { start:{}, end:{} };
rule.timeResultMax[timep] = node.positionConfig.getTimeProp(node, msg, rule.time[timep].max);
rule.timeResultMax[timep].source = 'max';
if (rule.timeResultMax[timep].error) {
hlp.handleError(node, RED._('node-red-contrib-sun-position/position-config:errors.error-time', { message: rule.timeResultMax[timep].error }), undefined, rule.timeResultMin[timep].error);
} else if (!rule.timeResultMax[timep].value) {
throw new Error('Error can not calc maximum time!');
} else {
if (numMax < rule.timeData.ts) {
[rule.timeData, rule.timeDataMax] = [rule.timeDataMax, rule.timeData];
rule.timeData.ts = numMax;
rule.timeData.dayId = hlp.getDayId(rule.timeDataMax.value);
rule.timeResultMax[timep].ts = rule.timeResultMax[timep].value.getTime();
if (rule.timeResultMax[timep].ts < rule.timeResult[timep].ts) {
[rule.timeResult[timep], rule.timeResultMax[timep]] = [rule.timeResultMax[timep], rule.timeResult[timep]];
}
}
}
return rule.timeData.ts;
rule.timeResult[timep].dayId = hlp.getDayId(rule.timeResult[timep].value);
return;
}

@@ -570,11 +622,10 @@

* @param {IRuleData} rule a rule object to test
* @param {ICompareTimeStamp} cmp a function to compare two timestamps.
* @param {ITimeObject} tData Now time object
* @returns {IRuleData|null} returns the rule if rule is valid, otherwhise null
*/
function compareRules(node, msg, rule, cmp, tData) {
function compareRules(node, msg, rule, tData) {
// node.debug(`compareRules rule ${rule.name} (${rule.pos}) rule=${util.inspect(rule, {colors:true, compact:10})}`);
if (rule.conditional) {
try {
if (!rule.conditon.result) {
if (!rule.conditonResult.result) {
node.debug(`compareRules rule ${rule.name} (${rule.pos}) conditon does not match`);

@@ -636,10 +687,141 @@ return null;

}
const num = getRuleTimeData(node, msg, rule, tData.now);
// node.debug(`compareRules ${rule.name} (${rule.pos}) type=${rule.time.operatorText} - ${rule.time.value} - num=${num} - rule.timeData = ${ util.inspect(rule.timeData, { colors: true, compact: 40, breakLength: Infinity }) }`);
if (tData.dayId === rule.timeData.dayId && num >=0 && (cmp(num) === true)) {
return rule;
rule.timeResult = {
now: tData.now
};
if (rule.time.start) {
getRuleTimeData(node, msg, rule, 'start', tData.now, Number.MIN_VALUE);
if (rule.time.end) {
getRuleTimeData(node, msg, rule, 'end', tData.now, Number.MAX_VALUE);
if (rule.timeResult.start.ts > rule.timeResult.end.ts) {
if ((tData.dayId === rule.timeResult.start.dayId &&
rule.timeResult.start.ts <= tData.nowNr) ||
(tData.dayId === rule.timeResult.end.dayId &&
rule.timeResult.end.ts > tData.nowNr)) {
return rule;
}
return null;
}
if (rule.timeResult.start.ts <= tData.nowNr &&
tData.dayId === rule.timeResult.start.dayId &&
rule.timeResult.end.ts > tData.nowNr &&
tData.dayId === rule.timeResult.end.dayId) {
return rule;
}
}
if (rule.timeResult.start.ts <= tData.nowNr &&
tData.dayId === rule.timeResult.start.dayId) {
return rule;
}
} else if (rule.time.end) {
getRuleTimeData(node, msg, rule, 'end', tData.now, Number.MAX_VALUE);
if (rule.timeResult.end.ts > tData.nowNr &&
tData.dayId === rule.timeResult.end.dayId) {
return rule;
}
}
// node.debug(`compareRules rule ${rule.name} (${rule.pos}) dayId=${tData.dayId} rule-DayID=${rule.timeData.dayId} num=${num} cmp=${cmp(num)} invalid time`);
// node.debug(`compareRules rule ${rule.name} (${rule.pos}) dayId=${tData.dayId} rule-DayID=${rule.timeResult[timep].dayId} num=${num} invalid time`);
return null;
}
/******************************************************************************************/
/**
* check all rules and determinate the active rule
* @param {ITimeControlNode} node node data
* @param {Object} msg the message object
* @param {ITimeObject} oNow the *current* date Object
* @param {Object} tempData the object storing the temporary caching data
* @returns {IRuleResultData} the active rule or null
*/
function getActiveRule(node, msg, oNow, tempData) {
// node.debug('getActiveRule --------------------');
prepareRules(node, msg, tempData, oNow.now);
// node.debug(`getActiveRule rules.count=${node.rules.count}, rules.last1stRun=${node.rules.last1stRun}, oNow=${util.inspect(oNow, {colors:true, compact:10})}`);
/** @type {IRuleResultData} */
const result = {
ruleindex : -1,
ruleSel : null
};
const setRes = (i, res) => {
if (res) {
// node.debug('new 1. ruleSel ' + util.inspect(res, { colors: true, compact: 5, breakLength: Infinity, depth: 10 }));
if (res.level && res.level.operator === cRuleType.slatOversteer) {
result.ruleSlatOvs = res;
} else if (res.level && res.level.operator === cRuleType.topicOversteer) {
result.ruleTopicOvs = res;
} else if (res.level && res.level.operator === cRuleType.levelMinOversteer) {
result.ruleSelMin = res;
} else if (res.level && res.level.operator === cRuleType.levelMaxOversteer) {
result.ruleSelMax = res;
} else {
result.ruleSel = res;
result.ruleindex = i;
return true;
}
}
return false;
};
for (let i = 0; i <= node.rules.last1stRun; ++i) {
const rule = node.rules.data[i];
// node.debug('rule ' + util.inspect(rule, {colors:true, compact:10, breakLength: Infinity }));
if (!rule.enabled || rule.execUse === cNBC_RULE_EXEC.last) { continue; }
if (setRes(i, compareRules(node, msg, rule, oNow))) break;
}
if (!result.ruleSel) {
// node.debug('--------- starting second loop ' + node.rules.count);
for (let i = (node.rules.count - 1); i >= 0; --i) {
const rule = node.rules.data[i];
// node.debug('rule ' + util.inspect(rule, {colors:true, compact:10, breakLength: Infinity }));
if (!rule.enabled || rule.execUse === cNBC_RULE_EXEC.first) { continue; }
if (setRes(i, compareRules(node, msg, rule, oNow))) break;
}
}
if (node.autoTrigger) {
const setAutoTrigger = (ts, type) => {
const d = new Date();
d.setHours(24,0,0,1); // next midnight
const diff = ts - oNow.nowNr;
node.autoTrigger.time = Math.min(node.autoTrigger.time, diff, d.getTime());
node.autoTrigger.type = type; // current rule end
};
if (result.ruleSel && result.ruleSel.time && result.timeResult && result.timeResult.end && result.ruleSel.timeResult.end.ts > oNow.nowNr) {
node.debug('autoTrigger set to current rule ' + result.ruleSel.pos + ' end');
setAutoTrigger(result.ruleSel.timeResult.end.ts, 1);
} else {
const times = [];
for (let i = (result.ruleindex+1); i < node.rules.count; ++i) {
const rule = node.rules.data[i];
if (!rule.time) { continue; }
rule.timeResult = { now: oNow };
if (rule.time.start) {
getRuleTimeData(node, msg, rule, 'start', oNow, Number.MIN_VALUE);
if (rule.timeResult.start.ts > oNow.nowNr) {
times.push(rule.timeResult.start.ts);
}
}
if (rule.time.end) {
getRuleTimeData(node, msg, rule, 'end', oNow, Number.MAX_VALUE);
if (rule.timeResult.end.ts > oNow.nowNr) {
times.push(rule.timeResult.end.ts);
}
}
}
if (times.length > 0) {
times.sort();
node.debug('autoTrigger set to next rule time ' + times[0]);
setAutoTrigger(times[0], 2);
} else {
// check maybe next day
const d = new Date();
d.setHours(24,0,0,1); // after next midnight
node.autoTrigger.time = Math.min(node.autoTrigger.time, d.getTime());
node.autoTrigger.type = 9; // no rule based autotrigger
}
}
}
return result;
}
/*************************************************************************************************************************/

@@ -757,11 +939,11 @@ /**

node.rules.count = node.rules.data.length;
node.rules.lastUntil = node.rules.count -1;
node.rules.firstFrom = node.rules.lastUntil;
node.rules.firstTimeLimited = node.rules.count;
node.rules.last1stRun = node.rules.count -1;
node.rules.maxImportance = 0;
node.rules.canResetOverwrite = false;
// node.debug('all node.rules before convert');
// node.debug(util.inspect(node.rules, { colors: true, compact: 10, depth: 10, breakLength: Infinity }));
for (let i = 0; i < node.rules.count; ++i) {
const rule = node.rules.data[i];
rule.pos = i + 1;
rule.exec = rule.exec || cNBC_RULE_EXEC.auto;
// Backward compatibility

@@ -835,4 +1017,13 @@ if (!rule.conditions) {

// @ts-ignore
rule.time = {
const operator = (parseInt(rule.timeOp) || cNBC_RULE_TYPE_UNTIL);
rule.time = { };
/** @type {('start'|'end')} */
let ttype = 'end'; // cNBC_RULE_TYPE_UNTIL
if (operator === cNBC_RULE_TYPE_FROM) {
// @ts-ignore
rule.time.start = {};
ttype = 'start';
}
rule.time[ttype] = {
// @ts-ignore
type : rule.timeType,

@@ -842,4 +1033,2 @@ // @ts-ignore

// @ts-ignore
operator : (parseInt(rule.timeOp) || cRuleUntil),
// @ts-ignore
offsetType : (rule.offsetType || 'none'),

@@ -849,3 +1038,4 @@ // @ts-ignore

// @ts-ignore
multiplier : (parseInt(rule.multiplier) || 60000),
multiplier : (parseInt(rule.multiplier) || hlp.TIME_1min),
next : false,
// @ts-ignore

@@ -857,38 +1047,35 @@ days : (rule.timeDays || '*'),

// @ts-ignore
if (rule.timeOnlyOddDays) rule.time.onlyOddDays = rule.timeOnlyOddDays; // @ts-ignore
if (rule.timeOnlyEvenDays) rule.time.onlyEvenDays = rule.timeOnlyEvenDays; // @ts-ignore
if (rule.timeDateStart) rule.time.dateStart = rule.timeDateStart; // @ts-ignore
if (rule.timeDateEnd) rule.time.dateEnd = rule.timeDateEnd; // @ts-ignore
if (rule.timeOpText) rule.time.operatorText = rule.timeOpText; // @ts-ignore
if (rule.timeMinType) {
// @ts-ignore
if (!rule.timeMin && rule.timeMinType !== 'none') {
rule.timeMin = {
// @ts-ignore
type : rule.timeMinType, // @ts-ignore
value : (rule.timeMinValue || ''), // @ts-ignore
offsetType : (rule.offsetMinType || 'none'), // @ts-ignore
offset : (rule.offsetMinValue || 1), // @ts-ignore
multiplier : (parseInt(rule.multiplierMin) || 60000),
next : false
};
}
if (rule.timeMinType && rule.timeMinType !== 'none') {
rule.time[ttype].min = {
// @ts-ignore
type : rule.timeMinType, // @ts-ignore
value : (rule.timeMinValue || ''), // @ts-ignore
offsetType : (rule.offsetMinType || 'none'), // @ts-ignore
offset : (rule.offsetMinValue || 1), // @ts-ignore
multiplier : (parseInt(rule.multiplierMin) || 60000),
next : false
};
}
// @ts-ignore
if (rule.timeMaxType) {
// @ts-ignore
if (!rule.timeMax && rule.timeMaxType !== 'none') {
rule.timeMax = {
// @ts-ignore
type : rule.timeMaxType, // @ts-ignore
value : (rule.timeMaxValue || ''), // @ts-ignore
offsetType : (rule.offsetMaxType || 'none'), // @ts-ignore
offset : (rule.offsetMaxValue || 1), // @ts-ignore
multiplier : (parseInt(rule.multiplierMax) || 60000),
next : false
};
}
if (rule.timeMaxType && rule.timeMaxType !== 'none') {
rule.time[ttype].max = {
// @ts-ignore
type : rule.timeMaxType, // @ts-ignore
value : (rule.timeMaxValue || ''), // @ts-ignore
offsetType : (rule.offsetMaxType || 'none'), // @ts-ignore
offset : (rule.offsetMaxValue || 1), // @ts-ignore
multiplier : (parseInt(rule.multiplierMax) || 60000),
next : false
};
}
}
// @ts-ignore
if (rule.timeDays && rule.timeDays !== '*') rule.time.days = rule.timeDays; // @ts-ignore
if (rule.timeMonths && rule.timeMonths !== '*') rule.time.months = rule.timeMonths; // @ts-ignore
if (rule.timeOnlyOddDays) rule.time.onlyOddDays = rule.timeOnlyOddDays; // @ts-ignore
if (rule.timeOnlyEvenDays) rule.time.onlyEvenDays = rule.timeOnlyEvenDays; // @ts-ignore
if (rule.timeDateStart) rule.time.dateStart = rule.timeDateStart; // @ts-ignore
if (rule.timeDateEnd) rule.time.dateEnd = rule.timeDateEnd;
// @ts-ignore
delete rule.timeType; // @ts-ignore

@@ -921,2 +1108,66 @@ delete rule.timeValue; // @ts-ignore

// @ts-ignore
if (rule.time && (typeof rule.time.operator !== 'undefined')) {
/** @type {('start'|'end')} */
let ttype = 'end'; // cNBC_RULE_TYPE_UNTIL
// @ts-ignore
if (rule.time.operator === cNBC_RULE_TYPE_FROM) {
ttype = 'start';
}
rule.time[ttype] = Object.assign({
// @ts-ignore
type : rule.time.type,
// @ts-ignore
value : rule.time.value,
// @ts-ignore
offsetType : rule.time.offsetType,
// @ts-ignore
offset : rule.time.offset,
// @ts-ignore
multiplier : rule.time.multiplier,
next : false
}, rule.time[ttype]);
// @ts-ignore
if (rule.timeMin && rule.timeMin.type !== 'none' ) {
rule.time[ttype].min = Object.assign({
// @ts-ignore
type : rule.timeMin.type,
// @ts-ignore
value : (rule.timeMin.value || ''),
// @ts-ignore
offsetType : (rule.timeMin.offsetType || 'none'),
// @ts-ignore
offset : (rule.timeMin.offset || 1),
// @ts-ignore
multiplier : (parseInt(rule.timeMin.multiplier) || 60000),
next : false
}, rule.time[ttype].min);
}
// @ts-ignore
if (rule.timeMax && rule.timeMax.type !== 'none' ) {
rule.time[ttype].max = Object.assign({
// @ts-ignore
type : rule.timeMax.type,
// @ts-ignore
value : (rule.timeMax.value || ''),
// @ts-ignore
offsetType : (rule.timeMax.offsetType || 'none'),
// @ts-ignore
offset : (rule.timeMax.offset || 1),
// @ts-ignore
multiplier : (parseInt(rule.timeMax.multiplier) || 60000),
next : false
}, rule.time[ttype].max);
}
// @ts-ignore
delete rule.time.operator; // @ts-ignore
delete rule.time.operatorText; // @ts-ignore
delete rule.time.type; // @ts-ignore
delete rule.time.value; // @ts-ignore
delete rule.time.offsetType; // @ts-ignore
delete rule.time.offset; // @ts-ignore
delete rule.time.multiplier; // @ts-ignore
delete rule.timeMin; // @ts-ignore
delete rule.timeMax;
}
// @ts-ignore
if (rule.levelType) {

@@ -930,3 +1181,3 @@ if (!rule.level) {

// @ts-ignore
operator : (parseInt(rule.levelOp) || cRuleAbsolute),
operator : (parseInt(rule.levelOp) || cRuleType.absolute),
// @ts-ignore

@@ -936,12 +1187,6 @@ operatorText : rule.levelOpText || RED._('node-red-contrib-sun-position/position-config:ruleCtrl.label.ruleLevelAbs')

}
if (!rule.slat) {
rule.slat = {
type : 'str',
value : ''
};
}
if ((rule.level.operator === 3) || (rule.level.operator === 4)) { // 3 -> ⭳✋ reset minimum; 4 -> ⭱️✋ reset maximum
rule.level.type = 'levelND';
rule.level.value = '';
rule.level.operator = rule.level.operator - 2;
rule.level.operator = rule.level.operator - 2; // cRuleType.absolute;
}

@@ -968,3 +1213,3 @@ // @ts-ignore

// @ts-ignore
multiplier : (parseInt(rule.payloadOffsetMultiplier) || 60000),
multiplier : (parseInt(rule.payloadOffsetMultiplier) || hlp.TIME_1min),
// @ts-ignore

@@ -985,2 +1230,13 @@ format : (parseInt(rule.payloadFormat) || 99)

}
/**
* non time rules will be executed if auto in order to first/last, so the will be let as auto
*/
rule.execUse = rule.exec;
if (rule.exec === cNBC_RULE_EXEC.first || (rule.time && !rule.time.start && rule.time.end)) {
rule.execUse = cNBC_RULE_EXEC.first;
node.rules.last1stRun = i;
} else if (rule.exec === cNBC_RULE_EXEC.last || (rule.time && rule.time.start && !rule.time.end)) {
rule.execUse = cNBC_RULE_EXEC.last;
}
/// check generic rule settings

@@ -991,3 +1247,15 @@ rule.name = rule.name || 'rule ' + rule.pos;

rule.resetOverwrite = hlp.isTrue(rule.resetOverwrite === true) ? true : false;
if (rule.payload || (rule.level && (rule.level.operator === cRuleAbsolute))) {
if (rule.level) {
if (!rule.slat) {
rule.slat = {
type : 'none',
value : ''
};
}
if (rule.level.type === 'levelND') {
rule.level.operator = cRuleType.absolute;
}
}
if (rule.payload || (rule.level && (rule.level.operator === cRuleType.absolute))) {
rule.importance = Number(rule.importance) || 0;

@@ -999,11 +1267,12 @@ node.rules.maxImportance = Math.max(node.rules.maxImportance, rule.importance);

if (rule.time) {
rule.time.next = false;
if (rule.timeMax) { rule.timeMax.next = false; }
if (rule.timeMin) { rule.timeMin.next = false; }
node.rules.firstTimeLimited = Math.min(i, node.rules.firstTimeLimited);
if (rule.time.operator === cRuleUntil) {
node.rules.lastUntil = i;
const checkTimeR = id => {
if (rule.time[id].max) { rule.time[id].max.next = false; }
if (rule.time[id].min) { rule.time[id].min.next = false; }
rule.time[id].next = false;
};
if (rule.time.start) { // cNBC_RULE_TYPE_FROM
checkTimeR('start');
}
if (rule.time.operator === cRuleFrom) {
node.rules.firstFrom = Math.min(i,node.rules.firstFrom);
if (rule.time.end) { // cNBC_RULE_TYPE_UNTIL
checkTimeR('end');
}

@@ -1084,2 +1353,4 @@ if (!rule.time.days || rule.time.days === '*') {

}
// node.debug('all node.rules after convert');
// node.debug(util.inspect(node.rules, { colors: true, compact: 10, depth: 10, breakLength: Infinity }));

@@ -1086,0 +1357,0 @@ if (node.autoTrigger || (parseFloat(config.startDelayTime) > 9)) {

@@ -44,2 +44,4 @@ {

"msgInput": "eingangs Nachricht",
"undefinedTimeFrom":"von Mitternacht oder vorhergehender Regel",
"undefinedTimeUntil":"bis Mitternacht oder nächster Regel",
"datespecific": "Zeitpunkt (erweitert)",

@@ -57,2 +59,4 @@ "nodeId":"Node Name",

"timesunnow": "nächste Uhrzeit Sonnenstand",
"timesuncustom":"Uhrzeit Sonnenstand (benutzerdefiniert)",
"timesuncustomnamed":"Uhrzeit Sonnenstand __value__",
"timemoon": "Uhrzeit Mond Auf/Untergang",

@@ -67,18 +71,10 @@ "randomNumber":"zufällige Zahl (immer neu)",

"sunElevation":"Sonnenhöhenwinkel",
"sunAzimuthRad":"Sonnenrichtung (rad)",
"sunElevationRad":"Sonnenhöhenwinkel (rad)",
"numAzimuth":"Sonnenrichtung",
"numAltitude":"Sonnenhöhenwinkel",
"numAzimuthRad":"Sonnenrichtung (rad)",
"numAltitudeRad":"Sonnenhöhenwinkel (rad)",
"numAnglePreDef":"Winkel aus Konfiguration",
"SunTimeByAzimuth":"Zeit durch Sonnenrichtung",
"SunTimeByAzimuthRad":"Zeit durch Sonnenrichtung (rad)",
"SunTimeByElevationObj":"Zeit Auf/Untergang Sonne durch Höhenwinkel",
"SunTimeByElevationObjRad":"Zeit Auf/Untergang Sonne durch Höhenwinkel (rad)",
"SunTimeByElevationNext":"Zeit Auf/Untergang Sonne durch Höhenwinkel",
"SunTimeByElevationNextRad":"Zeit Auf/Untergang Sonne durch Höhenwinkel (rad)",
"SunTimeByElevationRise":"Zeit Aufgang Sonne durch Höhenwinkel",
"SunTimeByElevationRiseRad":"Zeit Aufgang Sonne durch Höhenwinkel (rad)",
"SunTimeByElevationSet":"Zeit Untergang Sonne durch Höhenwinkel",
"SunTimeByElevationSetRad":"Zeit Untergang Sonne durch Höhenwinkel (rad)",
"suntime":"Sonnenzeit",

@@ -362,4 +358,10 @@ "suntimes":"Sonnenzeiten",

"ruleIsOutdated": "⚠️ Diese Regel ist ungültig und muss angepasst werden, da sie nicht mehr funktioniert!",
"ruleTimeMax": "spätestens (max)",
"ruleTimeMin": "frühestens (min)",
"ruleTimeMax_start": "von spätestens (max)",
"ruleTimeMin_start": "von frühestens (min)",
"ruleTimeMax_end": "bis spätestens (max)",
"ruleTimeMin_end": "bis frühestens (min)",
"ruleTimeMinOffset_start": "frühester (min) offset",
"ruleTimeMaxOffset_start": "spätester (max) offset",
"ruleTimeMinOffset_end": "frühester (min) offset",
"ruleTimeMaxOffset_end": "spätester (max) offset",
"ruleTimeLimit": "limitiert",

@@ -386,9 +388,21 @@ "ruleTimeLimitStart": "nur von",

"ruleTopicOversteer": "Topic (übersteuernd)",
"ruleTimeStart": "↧ von",
"ruleTimeEnd": "↥ bis",
"ruleTimeOffset": "zeit offset",
"ruleOff": "✋ nichts senden",
"ruleLevelND": "standard level (e.g. sun control)",
"ruleLevelND": "standard Level (e.g. sun control)",
"ruleState": "aktiviert oder deaktiviert die Regel",
"ruleExec":"Reihenfolge der Auswertung",
"ruleExecAuto": "auto - Regeln nur mit '↧ von', letzte gültige; alle anderen erste gültige",
"ruleExecFirst": "⭳ Erste gültige Regel (Bewertung von Anfang bis Ende [1])",
"ruleExecLast": "⭱️ letze gültige Regel (Bewertung von Ende bis Anfang [2])",
"ruleExecShort": [
"",
"¹⭳",
"²⭱️"
],
"ruleInValidElement":"ungültig",
"ruleInValidText":"ungültiges Element",
"editRule": "Regel editieren",
"duplicateRule": "Regel duplizieren",
"ruleState": "aktiviert oder deaktiviert die Regel",
"ruleTimeFrom": "↧ von",
"ruleTimeUntil": "↥ bis",
"btnAdd": "hinzufügen",

@@ -454,3 +468,3 @@ "btnSort": "sortieren",

"sunControlNotActive": "Nur Regelbasiert",
"sunControlMode": "Anstelle der standard Rollladenposition kann das Ausmaß in dem direktes Sonnenlicht in den Raum scheint eingeschränkt werden. <br><br>Der Modus kann über die eingehende Nachricht verändert werden. In diesem Falle ist der heir eingestellte Modus der maximal wählbare Modus. Der über eine nachricht eingestellte Modus wird im Node-Context persistiert und bleibt bei einem deploy erhalten.",
"sunControlMode": "Anstelle der standard Rollladenposition kann das Ausmaß in dem direktes Sonnenlicht in den Raum scheint eingeschränkt werden. <br><br>Der Modus kann über die eingehende Nachricht verändert werden. In diesem Falle ist der hier eingestellte Modus der maximal wählbare Modus. Der über eine Nachricht eingestellte Modus wird im Node-Context persistiert und bleibt bei einem deploy erhalten.",
"windowAzimuth": "Darstellung der Ausrichtung des Fensters zum geografischen Norden (in Grad), wenn die Sonne in das Fenster fällt (Sonnenrichtung/Azimuth).",

@@ -468,3 +482,3 @@ "windowPos": "Fenster Eigenschaften, Messung vom Boden bis zum unter und Oberseite des Fensters",

"enhanced":"erweiterte Einstellungen",
"startDelayTime":"Bei einem Wert von 0 wird die node nach einem Deploy oder Node-Red Start erst mit der nächsten eingehenden nachricht aktiviert und bis dahin auf keine Ereignise reagieren!"
"startDelayTime":"Bei einem Wert von 0 wird die node nach einem Deploy oder Node-Red Start erst mit der nächsten eingehenden Nachricht aktiviert und bis dahin auf keine Ereignise reagieren!"
}

@@ -480,2 +494,3 @@ },

"config-missing-state": "Node ist nicht richtig konfiguriert!!",
"config-error": "Error in used configuration node: __error__",
"unknownPropertyOperator": "Fehler, der verwendete Operator __propertyOp__=\"__propertyOpText__\" ist unbekannt!",

@@ -486,2 +501,3 @@ "unknownCompareOperator": "Fehler, der verwendete vergleichs-Operator \"__operator__\" ist unbekannt! (Vergleich \"__opTypeA__.__opValueA__\" mit \"__opTypeB__.__opValueB__\")",

"notEvaluablePropertyUsedValue": "kann den Wert von __type__.__value__ nicht ermitteln, verwende \"__usedValue__\"!",
"notEvaluableCustomAngle":"Benutzerdefinierter Winkel mit Namen \"__value__\" wurde im Konfigurationsknoten nicht definiert!",
"invalidParameter":"Der Parameter \"__param__\" hat ist ungültig \"__type__\" (nutze __newValue__)",

@@ -498,2 +514,3 @@ "invalid-expr": "Ungültiger JSONata Austruck: __error__",

"longitude": "Längengrad",
"height":"(opt) Beobachterhöhe",
"angleType": "Winkel Typ",

@@ -510,3 +527,9 @@ "timeZoneOffset": "Zeitzone",

"addDST1Hour": "Sommerzeit 1 Stunde hinzufügen",
"addDST2Hour": "Sommerzeit 2 Stunden hinzufügen"
"addDST2Hour": "Sommerzeit 2 Stunden hinzufügen",
"sunPositions": "Benutzerdefinierte Sonnenpositionen",
"predefAngles": "vordefinierte Winkel",
"angle": "Winkel",
"riseName": "Name Aufgang",
"setName": "Name Untergang",
"angleDec": "Dezimalgrad"
},

@@ -517,3 +540,3 @@ "placeholder": {

"longitude": "-1.4",
"angleType": "deg",
"height": "die Höhe des Beobachters (in Metern) in Bezug auf den Horizont",
"timeZoneOffset": "0",

@@ -526,4 +549,5 @@ "name": "Name",

"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! To update from a previous version 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.",
"timeZoneOffset":"Änderungen am Format können einige zeit dauern, bis diese Auswirkung zeigen."
"timeZoneOffset":"Änderungen am Format können einige zeit dauern, bis diese Auswirkung zeigen.",
"sunPositions": "Hier können Sie Ihre eigenen Elevationswinkel für Sonnenpositionen definieren.",
"predefAngles": "Hier können Sie Winkelwerte in Dezimalgraden mit einem Namen angeben, der in verschiedenen Knoten verwendet werden kann. Zum Beispiel kann hier ein Azimutwinkel mit dem Namen N (für Nord) definiert werden. Für die Fensterposition im Knoten Jalousie wird nur die Seite des Fensters (N) angegeben."
},

@@ -533,5 +557,9 @@ "errors": {

"longitude-missing": "Koordinate für den Längengrad fehlt oder ist falsch!",
"coordinates-missing": "Koordinaten für den Breitengrad und Längengrad ist falsch!"
"coordinates-missing": "Koordinaten für den Breitengrad und Längengrad ist falsch!",
"height-wrong": "Beobachter höhe ist Falsch. Es sind nur zahlen oder leer erlaubt!",
"invalid-custom-suntime": "Ungültiger benutzerdefinierte Sonnenzeit __riseName__ oder __setName__ angegeben! Vielleicht ein Duplikat eines bestehenden Namens.",
"custom-angles":"Ungültiger benutzerdefinierter Winkel __name__! Der Name darf keine Sonderzeichen enthalten!",
"custom-angles-duplicate":"Ungültiger benutzerdefinierter Winkel __name__! Name existiert bereits, Duplikate sind nicht erlaubt!"
}
}
}

@@ -39,4 +39,4 @@ {

"timeLimits":"Wählen Sie Tage und / oder Monate aus, für welche es gültig sein soll",
"days": "Tage auswählen, an denen die nachricht gesendet werden soll",
"months":"Monate auswählen, an denen die nachricht gesendet werden soll",
"days": "Tage auswählen, an denen die Nachricht gesendet werden soll",
"months":"Monate auswählen, an denen die Nachricht gesendet werden soll",
"recalcTime": "Intervall in dem eine Neuberechnung des Zeitpunktes zum Senden der Nachricht stattfinden soll.",

@@ -43,0 +43,0 @@ "once": "zusätzlich soll beim Start des Flows eine Nachricht (unabhängig von der Zeit) gesendet werden"

@@ -33,3 +33,2 @@ {

"sunTopic": "Topic 🌞/⛄",
"time": "Zeit",
"name": "name",

@@ -45,4 +44,2 @@ "oversteerValue": "Übersteuerung",

"offset": "Zeit offset",
"offset-timeMin": "früheste (min) offset",
"offset-timeMax": "späteste (max) offset",
"dialogtitle": "Regel bearbeiten",

@@ -49,0 +46,0 @@ "autoTrigger": "automatisch triggern",

@@ -43,2 +43,4 @@ {

"delete":"delete",
"undefinedTimeFrom":"from midnight or previous rule",
"undefinedTimeUntil":"until midnight or the next rule",
"msgInput": "input message",

@@ -57,2 +59,4 @@ "datespecific":"timestamp enhanced",

"timesunnow": "next sun time",
"timesuncustom":"sun time (custom)",
"timesuncustomnamed":"sun time __value__",
"timemoon":"moon time",

@@ -67,18 +71,10 @@ "randomNumber":"random number (continuously new)",

"sunElevation":"Elevation of sun",
"sunAzimuthRad":"Azimuth of sun (rad)",
"sunElevationRad":"Elevation of sun (rad)",
"numAzimuth":"Azimuth angle",
"numAltitude":"Elevation angle",
"numAzimuthRad":"Azimuth angle (rad)",
"numAltitudeRad":"Elevation angle (rad)",
"numAnglePreDef":"custom angle from config node",
"SunTimeByAzimuth":"time by azimuth",
"SunTimeByAzimuthRad":"time by azimuth (rad)",
"SunTimeByElevationObj":"time by elevation (set or rise)",
"SunTimeByElevationObjRad":"time by elevation (set or rise in rad)",
"SunTimeByElevationNext":"next time by elevation (set or rise)",
"SunTimeByElevationNextRad":"next time by elevation (set or rise in rad)",
"SunTimeByElevationRise":"next rise time by elevation",
"SunTimeByElevationRiseRad":"next rise time by elevation (rad)",
"SunTimeByElevationSet":"next set time by elevation",
"SunTimeByElevationSetRad":"next set time by elevation (rad)",
"suntime":"sun time",

@@ -377,4 +373,10 @@ "suntimes":"sun times",

"ruleIsOutdated": "⚠️ This rule is invalid and has to be adjusted because it no longer works!",
"ruleTimeMin": "at the earliest (min)",
"ruleTimeMax": "no later than (max)",
"ruleTimeMin_start": "from at the earliest (min)",
"ruleTimeMax_start": "from no later than (max)",
"ruleTimeMin_end": "until at the earliest (min)",
"ruleTimeMax_end": "until no later than (max)",
"ruleTimeMinOffset_start": "earliest (min) offset",
"ruleTimeMaxOffset_start": "latest (max) offset",
"ruleTimeMinOffset_end": "earliest (min) offset",
"ruleTimeMaxOffset_end": "latest (max) offset",
"ruleTimeLimit": "limited",

@@ -401,9 +403,21 @@ "ruleTimeLimitStart": "only from",

"ruleTopicOversteer": "Topic (oversteer)",
"ruleTimeStart": "↧ from",
"ruleTimeEnd": "↥ until",
"ruleTimeOffset": "time offset",
"ruleOff": "✋ send nothing",
"ruleLevelND": "use default level (e.g. sun control)",
"ruleState": "enables or disables the rule",
"ruleExec":"order of evaluation",
"ruleExecAuto": "auto - rules only with '↧ from', last matching; all other first matching",
"ruleExecFirst": "⭳ first valid rule (evaluation first to last [1])",
"ruleExecLast": "⭱️ last valid rule (evaluation last to first [2], only if no first match)",
"ruleExecShort": [
"",
"¹⭳",
"²⭱️"
],
"ruleInValidElement":"invalid",
"ruleInValidText":"invalid Element",
"editRule": "edit the rule",
"duplicateRule": "duplicate the rule",
"ruleState": "enables or disables the rule",
"ruleTimeFrom": "↧ from",
"ruleTimeUntil": "↥ until",
"btnAdd": "add",

@@ -493,2 +507,3 @@ "btnSort": "sort",

"config-missing-state": "No valid configuration is selected!",
"config-error": "Error in used configuration node: __error__",
"unknownPropertyOperator": "error, the used property operator __propertyOp__=\"__propertyOpText__\" is unknown!",

@@ -499,2 +514,3 @@ "unknownCompareOperator": "error, the used compare operator \"__operator__\" is unknown! (\"__opTypeA__.__opValueA__\" compare to \"__opTypeB__.__opValueB__\")",

"notEvaluablePropertyUsedValue": "could not evaluate __type__.__value__, using \"__usedValue__\"!",
"notEvaluableCustomAngle":"Custom Angle with name \"__value__\" is not defined in the configuration node!",
"invalidParameter":"Parameter \"__param__\" is invalid \"__type__\" (using __newValue__)",

@@ -504,3 +520,5 @@ "invalid-expr": "Invalid JSONata expression: __error__",

"error-time": "Error get time: __message__",
"usingTempValue": "Could not evaluate __type__.__value__ and using stored value \"__usedValue__\"!"
"usingTempValue": "Could not evaluate __type__.__value__ and using stored value \"__usedValue__\"!",
"latitude-wrong":"Given Latitude __latitude__ is wrong. Using default from config!",
"longitude-wrong":"Given Longitude __longitude__ is wrong. Using default from config!"
},

@@ -512,3 +530,3 @@ "position-config": {

"longitude": "Longitude",
"height":"observer height",
"height":"(opt) observer height",
"angleType": "angle type",

@@ -525,3 +543,9 @@ "timeZoneOffset": "TZ Offset",

"addDST1Hour": "DST add 1 Hour",
"addDST2Hour": "DST add 2 Hours"
"addDST2Hour": "DST add 2 Hours",
"sunPositions": "Custom Sun Positions",
"predefAngles": "defined angles",
"angle": "Angle",
"riseName": "Rise Name",
"setName": "Set Name",
"angleDec": "Decimal degree"
},

@@ -533,3 +557,2 @@ "placeholder": {

"height": "the observer height (in meters) relative to the horizon",
"angleType": "deg",
"timeZoneOffset": "0",

@@ -542,3 +565,5 @@ "name": "Name",

"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! To update from a previous version save and re-deploy is necessary.",
"timeZoneOffset": "If for the timezone OS Standard is choosen the standard timezone including daylight saving switch is used. If is not chosen this setting, but a special time zone then no change of the daylightsaving is done! Formatchanges to time could taken time until it will get any effect."
"timeZoneOffset": "If for the timezone OS Standard is choosen the standard timezone including daylight saving switch is used. If is not chosen this setting, but a special time zone then no change of the daylightsaving is done! Formatchanges to time could taken time until it will get any effect.",
"sunPositions": "Here you can define your own elevation angles for sun positions.",
"predefAngles": "Here you can specify angle values in decimal degrees with a name, which can be used in different nodes. For example, an azimuth angle with the name N (for north) can be defined here. For the window position in the blind node, only the side of the window (N) is specified."
},

@@ -548,5 +573,9 @@ "errors": {

"longitude-missing": "Longitude is missing or wrong!",
"coordinates-missing": "Coordinates Latitude and Longitude is missing in the configuration node!"
"coordinates-missing": "Coordinates Latitude and Longitude is missing in the configuration node!",
"height-wrong": "Observer height has wrong value in the configuration node! Must be a number or empty!",
"invalid-custom-suntime": "Invalid custom suntime __riseName__ or __setName__ given! Maybe duplicate to existing name.",
"custom-angles":"Invalid user-defined angle __name__! The name must not contain special characters!",
"custom-angles-duplicate":"Invalid custom angle __name__! Name already exists, duplicates are not allowed!"
}
}
}

@@ -18,3 +18,4 @@ {

"result1Format": "output format",
"result1Offset": "Offset"
"result1Offset": "Offset",
"resultContainer": "result"
},

@@ -21,0 +22,0 @@ "typeLabel":{

@@ -9,4 +9,10 @@ {

"windowBottom": "window bottom",
"windowSetMode":"setting by",
"windowSetModeAzimuthStartEnd":"Azimuth Start End",
"windowSetModeOrientation":"Orientation",
"windowAzimuthStart": "start",
"windowAzimuthEnd": "end",
"windowOrientation":"Orientation",
"windowOffsetN":"negative offset -",
"windowOffsetP":"positive offset +",
"blindIncrement": "Increment",

@@ -34,3 +40,2 @@ "blindOpenPos": "open position (max)",

"sunTopic": "Topic 🌞/⛄",
"time": "time",
"name": "name",

@@ -45,5 +50,2 @@ "oversteerValue": "oversteer",

"showEnhSettings": "Enhanced settings",
"offset": "time offset",
"offset-timeMin": "earliest (min) offset",
"offset-timeMax": "latest (max) offset",
"dialogtitle": "Edit Rule",

@@ -63,2 +65,5 @@ "autoTrigger": "auto trigger",

"windowAzimuthEnd": "window right to geographical north",
"windowOrientation":"the bearing representing the perpendicular of the window to geographical north",
"windowOffsetN":"90 - (optional) anti-clockwise offset from orientation for determination of whether the sun is coming through window.",
"windowOffsetP":"90 - (optional) clockwise offset from orientation for determination of whether the sun is coming through window",
"blindIncrement": "0.01 or 1",

@@ -65,0 +70,0 @@ "blindOpenPos": "100",

@@ -11,8 +11,5 @@ {

"overwriteExpire": "expire",
"time": "time",
"name": "name",
"showEnhSettings": "Enhanced settings",
"offset": "time offset",
"offset-timeMin": "earliest (min) offset",
"offset-timeMax": "latest (max) offset",
"dialogtitle": "Edit Rule",

@@ -19,0 +16,0 @@ "autoTrigger": "auto trigger",

@@ -26,2 +26,8 @@ /* eslint-disable no-irregular-whitespace */

/** editorRED
* @typedef {Object} RED The Node-RED core object available to a custom node's .html file
*
*/
/** editorRED
* @typedef {Object} editorRED The Node-RED core object available to a custom node's .html file

@@ -28,0 +34,0 @@ *

{
"name": "node-red-contrib-sun-position",
"version": "2.2.0-beta3",
"version": "3.0.0-alpha1",
"description": "NodeRED nodes to get sun and moon position",

@@ -53,3 +53,3 @@ "keywords": [

"engines": {
"node": ">=8.0.0"
"node": ">=12"
},

@@ -99,3 +99,3 @@ "scripts": {

"node-red": {
"version": ">=1.0.0",
"version": ">=1.2.9",
"nodes": {

@@ -115,3 +115,3 @@ "position-config": "nodes/10-position-config.js",

"dependencies": {
"suncalc3": "^2.0.1",
"suncalc3": "^2.0.5",
"lodash.clonedeep": "^4.5.0",

@@ -122,3 +122,3 @@ "lodash.isequal": "^4.5.0",

"devDependencies": {
"eslint": ">=8.11.0",
"eslint": ">=8.13.0",
"eslint-plugin-html": ">=6.2.0",

@@ -129,6 +129,7 @@ "eslint-plugin-json": ">=3.1.0",

"@types/jquery": "^3.5.14",
"@types/node-red": "^1.2.0",
"@types/jqueryui": "^1.12.16",
"@types/node-red": "^1.2.1",
"jsonata": "^1.8.6",
"mocha": "^9.2.2",
"node-red": ">=2.0.0",
"node-red": ">=2.1.0",
"node-red-dev": "^0.1.5",

@@ -135,0 +136,0 @@ "node-red-node-test-helper": "^0.2.7",

@@ -45,3 +45,3 @@ # node-red-contrib-sun-position for NodeRED

These nodes need at least NodeJS Version __8.0__ and Node-Red with Version __1.0__! Any early Version of Node-Red will not work!
These nodes need at least NodeJS Version __12.0__ and Node-Red with Version __1.2.9__! Any early Version of Node-Red will not work!

@@ -48,0 +48,0 @@ ## Installation

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

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 too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc