Skip to content

Commit d7a964e

Browse files
committed
offset for blind open/close #371 + disable node #365
1 parent e79bb99 commit d7a964e

8 files changed

+124
-16
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ This can be also used to go back to an older Version.
2121
- fixed blind-control example 3 and 4; clock-time example #388
2222
- the function node in the example can now simulate different days for testing at the same time on different days #389
2323
- renamed external given time property from `.dNow` to `.now` to maintain consistency to other nodes
24+
- nodes can be completely disables and enabled by incoming message (topic must be `enableNode` and `disableNode`) #365
2425

2526
- blind-control
2627
- after expire of manual override with -1 force to send output #387
2728
- add possibility to force output to first output when topic contains `forceOutput`
29+
- add possibility to add offset for the open/close position of the blind in active sun control #371
2830

2931
### 2.0.6: bug fixes
3032

nodes/blind-control.html

+54-10
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,34 @@
244244
blindPosMaxType: {
245245
value: 'levelFixed'
246246
},
247+
blindOpenPosOffset: {
248+
value: 0.00,
249+
required: false,
250+
validate(v) {
251+
if (typeof v === 'undefined' || v === '') return true;
252+
const n = parseFloat(v);
253+
const mm = getMinMaxBlindPos(this);
254+
return n === 0.00 ||
255+
(RED.validators.number()(v) &&
256+
(Number.isInteger(n / parseFloat(getVal(this, 'blindIncrement')))) &&
257+
(n < mm.max) &&
258+
(n > mm.min));
259+
}
260+
},
261+
blindClosedPosOffset: {
262+
value: 0.00,
263+
required: false,
264+
validate(v) {
265+
if (typeof v === 'undefined' || v === '') return true;
266+
const n = parseFloat(v);
267+
const mm = getMinMaxBlindPos(this);
268+
return n === 0.00 ||
269+
(RED.validators.number()(v) &&
270+
(Number.isInteger(n / parseFloat(getVal(this, 'blindIncrement')))) &&
271+
(n < mm.max) &&
272+
(n > mm.min));
273+
}
274+
},
247275
sunSlat: {
248276
value: '',
249277
validate: RED.validators.typedInput('sunSlatType')
@@ -3777,16 +3805,6 @@
37773805
<label for="node-input-sunMinDelta"><i class="fa fa-star-half"></i> <span data-i18n="blind-control.label.sunMinDelta"></span></label>
37783806
<input type="text" class="spinner-level row-full-width" id="node-input-sunMinDelta" data-i18n="[placeholder]blind-control.placeholder.sunMinDelta"/>
37793807
</div>
3780-
<div class="form-row form-row-sunControlRestriction is-initial-hidden block-indent1" data-i18n="[title]blind-control.placeholder.smoothTime">
3781-
<label for="blind-control-smoothTime"><i class="fa fa-calculator"></i> <span data-i18n="blind-control.label.smoothTime"></span></label>
3782-
<input type="text" class="spinner-time" id="blind-control-smoothTime" data-i18n="[placeholder]blind-control.placeholder.smoothTime" value=""/>
3783-
<select id="blind-control-smoothTime-multiplier" class="node-input-multiplier">
3784-
<option value="1000" data-i18n="node-red-contrib-sun-position/position-config:common.multiplier.1"></option>
3785-
<option value="60000" data-i18n="node-red-contrib-sun-position/position-config:common.multiplier.2"></option>
3786-
<option value="3600000" data-i18n="node-red-contrib-sun-position/position-config:common.multiplier.3"></option>
3787-
</select>
3788-
<input type="hidden" id="node-input-smoothTime"/>
3789-
</div>
37903808
<div class="form-row form-row-sunControlActive block-indent1-noadd" data-i18n="[title]blind-control.placeholder.blindLevelMin">
37913809
<label for="node-input-blindPosMin"><i class="fa fa-angle-down"></i> <span data-i18n="blind-control.label.blindLevelMin"></span></label>
37923810
<input type="text" id="node-input-blindPosMin" class="row-full-width" data-i18n="[placeholder]blind-control.placeholder.blindLevelMin"/>
@@ -3813,6 +3831,32 @@
38133831
<label for="node-input-oversteerTopic"><i class="fa fa-tasks"></i> <span data-i18n="blind-control.label.oversteerTopic"></span></label>
38143832
<input type="text" id="node-input-oversteerTopic" class="row-full-width" data-i18n="[placeholder]node-red:common.label.topic"/>
38153833
</div>
3834+
<hr class="form-row-sunControlRestriction" >
3835+
<!-- advanced ########################################################################## -->
3836+
<div class="form-row form-row-sunControlRestriction block-noindent">
3837+
<span data-i18n="[html]node-red-contrib-sun-position/position-config:ruleCtrl.text.sunAdvanced" class="row-full-width" style="word-wrap:break-word;"></span>
3838+
</div>
3839+
<div class="form-row form-row-sunControlRestriction is-initial-hidden block-indent1" data-i18n="[title]blind-control.placeholder.smoothTime">
3840+
<label for="blind-control-smoothTime"><i class="fa fa-calculator"></i> <span data-i18n="blind-control.label.smoothTime"></span></label>
3841+
<input type="text" class="spinner-time" id="blind-control-smoothTime" data-i18n="[placeholder]blind-control.placeholder.smoothTime" value=""/>
3842+
<select id="blind-control-smoothTime-multiplier" class="node-input-multiplier">
3843+
<option value="1000" data-i18n="node-red-contrib-sun-position/position-config:common.multiplier.1"></option>
3844+
<option value="60000" data-i18n="node-red-contrib-sun-position/position-config:common.multiplier.2"></option>
3845+
<option value="3600000" data-i18n="node-red-contrib-sun-position/position-config:common.multiplier.3"></option>
3846+
</select>
3847+
<input type="hidden" id="node-input-smoothTime"/>
3848+
</div>
3849+
<div class="form-row form-row-sunControlRestriction block-noindent">
3850+
<span data-i18n="[html]node-red-contrib-sun-position/position-config:ruleCtrl.text.blindPosOffset" class="row-full-width" style="word-wrap:break-word;"></span>
3851+
</div>
3852+
<div class="form-row form-row-sunControlRestriction block-indent1-noadd" data-i18n="[title]blind-control.placeholder.blindOpenPosOffset">
3853+
<label for="node-input-blindOpenPosOffset"><i class="fa fa-chevron-circle-up"></i> <span data-i18n="blind-control.label.blindOpenPosOffset"></span></label>
3854+
<input type="text" class="spinner-level row-full-width" id="node-input-blindOpenPosOffset" data-i18n="[placeholder]blind-control.placeholder.blindOpenPosOffset"/>
3855+
</div>
3856+
<div class="form-row form-row-sunControlRestriction block-indent1-noadd" data-i18n="[title]blind-control.placeholder.blindClosedPosOffset">
3857+
<label for="node-input-blindClosedPosOffset"><i class="fa fa-chevron-circle-down"></i> <span data-i18n="blind-control.label.blindClosedPosOffset"></span></label>
3858+
<input type="text" class="spinner-level row-full-width" id="node-input-blindClosedPosOffset" data-i18n="[placeholder]blind-control.placeholder.blindClosedPosOffset"/>
3859+
</div>
38163860
</div>
38173861
<div id="blind-control-tab-output" style="display:none">
38183862
<!-- Output ######################################################################## -->

nodes/blind-control.js

+37-3
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,8 @@ module.exports = function (RED) {
430430
node.level.current = node.nodeData.levelTop;
431431
node.level.currentInverse = node.nodeData.levelBottom;
432432
} else {
433-
node.level.current = posPrcToAbs_(node, (height - wBottom) / (wTop - wBottom));
433+
const levelPercent = (height - wBottom) / (wTop - wBottom);
434+
node.level.current = posRound_(node, ((node.nodeData.levelTopSun - node.nodeData.levelBottomSun) * levelPercent) + node.nodeData.levelBottomSun);
434435
node.level.currentInverse = getInversePos_(node, node.level.current);
435436
}
436437
node.level.slat = node.positionConfig.getPropValue(node, msg, node.sunData.slat, false, oNow.now);
@@ -846,9 +847,12 @@ module.exports = function (RED) {
846847
azimuthEndType: config.windowAzimuthEndType || 'num'
847848
};
848849
node.nodeData = {
850+
isDisabled: false,
849851
/** The Level of the window */
850852
levelTop: Number(hlp.chkValueFilled(config.blindOpenPos, 100)),
851853
levelBottom: Number(hlp.chkValueFilled(config.blindClosedPos, 0)),
854+
levelTopOffset: Number(hlp.chkValueFilled(config.blindOpenPosOffset, 0)),
855+
levelBottomOffset: Number(hlp.chkValueFilled(config.blindClosedPosOffset, 0)),
852856
increment: Number(hlp.chkValueFilled(config.blindIncrement, 1)),
853857
levelDefault: NaN,
854858
levelMin: NaN,
@@ -869,11 +873,28 @@ module.exports = function (RED) {
869873
node.nodeData.overwrite.expireDuration = parseFloat(hlp.chkValueFilled(config.overwriteExpire, NaN));
870874

871875
if (node.nodeData.levelTop < node.nodeData.levelBottom) {
872-
const tmp = node.nodeData.levelBottom;
876+
let tmp = node.nodeData.levelBottom;
873877
node.nodeData.levelBottom = node.nodeData.levelTop;
874878
node.nodeData.levelTop = tmp;
879+
880+
tmp = node.nodeData.levelBottomOffset;
881+
node.nodeData.levelBottomOffset = node.nodeData.levelTopOffset;
882+
node.nodeData.levelTopOffset = tmp;
875883
node.levelReverse = true;
876884
}
885+
node.nodeData.levelBottomSun = node.nodeData.levelBottom + node.nodeData.levelBottomOffset;
886+
if (node.nodeData.levelBottomSun < node.nodeData.levelBottom || node.nodeData.levelBottomSun > node.nodeData.levelTop) {
887+
node.nodeData.levelBottomSun = node.nodeData.levelBottom;
888+
node.error(RED._('blind-control.errors.invalidOpenPosOffset'));
889+
}
890+
891+
node.nodeData.levelTopSun = node.nodeData.levelTop - node.nodeData.levelTopOffset;
892+
if (node.nodeData.levelTopSun < node.nodeData.levelBottom || node.nodeData.levelTopSun > node.nodeData.levelTop) {
893+
node.nodeData.levelTopSun = node.nodeData.levelTop;
894+
node.error(RED._('blind-control.errors.invalidClosedPosOffset'));
895+
}
896+
delete node.nodeData.levelBottomOffset;
897+
delete node.nodeData.levelTopOffset;
877898

878899
node.nodeData.levelDefault = getBlindPosFromTI(node, undefined, config.blindPosDefaultType, config.blindPosDefault, node.nodeData.levelTop);
879900
node.nodeData.levelMin = getBlindPosFromTI(node, undefined, config.blindPosMinType, config.blindPosMin, node.nodeData.levelBottom);
@@ -1086,7 +1107,10 @@ module.exports = function (RED) {
10861107
node.context().set('mode', newMode, node.contextStore);
10871108
}
10881109

1089-
if (msg.topic && (typeof msg.topic === 'string') && msg.topic.startsWith('set')) {
1110+
if (msg.topic && (typeof msg.topic === 'string') &&
1111+
(msg.topic.startsWith('set') ||
1112+
msg.topic.startsWith('disable') ||
1113+
msg.topic.startsWith('enable'))) {
10901114
const getFloatValue = def => {
10911115
const val = parseFloat(msg.payload);
10921116
if (isNaN(val)) {
@@ -1150,6 +1174,12 @@ module.exports = function (RED) {
11501174
case 'enableRuleByPos':
11511175
changeRules(node, parseInt(msg.payload), undefined, { enabled: true });
11521176
break;
1177+
case 'enableNode':
1178+
node.nodeData.isDisabled = false;
1179+
break;
1180+
case 'disableNode':
1181+
node.nodeData.isDisabled = true;
1182+
break;
11531183
default:
11541184
break;
11551185
}
@@ -1160,6 +1190,10 @@ module.exports = function (RED) {
11601190
node.levelReverse = true;
11611191
}
11621192
}
1193+
if (node.nodeData.isDisabled) {
1194+
done();
1195+
return null;
1196+
}
11631197

11641198
// initialize
11651199
node.nowarn = {};

nodes/clock-timer.js

+16-2
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ module.exports = function (RED) {
349349
// temporary node Data
350350
node.contextStore = config.contextStore || this.positionConfig.contextStore;
351351
node.nodeData = {
352+
isDisabled: false,
352353
/** The Level of the window */
353354
payloadDefault: config.payloadDefault,
354355
payloadDefaultType: config.payloadDefaultType,
@@ -428,7 +429,10 @@ module.exports = function (RED) {
428429
}
429430

430431
// allow to overwrite settings by incomming message
431-
if (msg.topic && (typeof msg.topic === 'string') && msg.topic.startsWith('set')) {
432+
if (msg.topic && (typeof msg.topic === 'string') &&
433+
(msg.topic.startsWith('set') ||
434+
msg.topic.startsWith('disable') ||
435+
msg.topic.startsWith('enable'))) {
432436
switch (msg.topic) {
433437
/* Default Settings */
434438
case 'setSettingsTopic':
@@ -438,7 +442,7 @@ module.exports = function (RED) {
438442
case 'setAutoTriggerTime':
439443
node.autoTrigger.defaultTime = parseInt(msg.payload) || node.autoTrigger.defaultTime; // payload of 0 makes no sense, use then default
440444
break;
441-
case 'setCntextStore':
445+
case 'setContextStore':
442446
node.contextStore = msg.payload || node.contextStore;
443447
break;
444448
case 'disableRule':
@@ -453,10 +457,20 @@ module.exports = function (RED) {
453457
case 'enableRuleByPos':
454458
changeRules(node, parseInt(msg.payload), undefined, { enabled: true });
455459
break;
460+
case 'enableNode':
461+
node.nodeData.isDisabled = false;
462+
break;
463+
case 'disableNode':
464+
node.nodeData.isDisabled = true;
465+
break;
456466
default:
457467
break;
458468
}
459469
}
470+
if (node.nodeData.isDisabled) {
471+
done();
472+
return null;
473+
}
460474

461475
// initialize
462476
node.nowarn = {};

nodes/locales/de/blind-control.json

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
"blindIncrement": "Schritt",
1212
"blindOpenPos": "Rollladen offen (max)",
1313
"blindClosedPos": "Rollladen geschlossen (min)",
14+
"blindOpenPosOffset": "Rollladen offen offset",
15+
"blindClosedPosOffset": "Rollladen geschlossen offset",
1416
"blindLevelDefault": "Standard Rollladenposition",
1517
"slatPosDefault": "Standard Lamellenposition",
1618
"blindLevelMin": "minimale Rollladenposition",
@@ -58,6 +60,8 @@
5860
"blindIncrement": "0.01 oder 1",
5961
"blindOpenPos": "1 oder 100",
6062
"blindClosedPos": "0",
63+
"blindOpenPosOffset": "offset für die Position geöffnet",
64+
"blindClosedPosOffset": "offset für die Position geschlossen",
6165
"blindLevelDefault": "Rollladenposition, wenn keine andere zutrifft",
6266
"slatPosDefault": "Lamellenposition, wenn keine andere zutrifft",
6367
"blindLevelMin": "maximale Rollladenposition Sonnenstands abhängig",

nodes/locales/de/position-config.json

+2
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,8 @@
439439
"windowAzimuth": "Darstellung der Ausrichtung des Fensters zum geografischen Norden (in Grad), wenn die Sonne in das Fenster fällt (Sonnenrichtung/Azimuth).",
440440
"windowPos": "Fenster Eigenschaften, Messung vom Boden bis zum unter und Oberseite des Fensters",
441441
"oversteer": "erlaubt das Übersteuern der Position in Abhängigkeit von der Sonne unter definierten Bedingungen wie Sonnenwinkel oder Wetter (z. B. Wolkenhimmel, Beleuchtung, etc.). Hiermit kann auch eine minimale oder maximaler Höhenwinkel definiert werden, wenn Berge/Gebäude, etc das Fenster verdecken.",
442+
"sunAdvanced": "Erweiterte Einstellungen für die Sonnensteuerung",
443+
"blindPosOffset": "Wenn der Fensterbereich kleiner als der Rollladen öffnen/schließenBereichs entspricht, weil ein breiter Fensterrahmen vorhanden ist oder verzögerte öffnen/schließen vorliegt (durch beispielsweise Schlitze welche sich erst Öffnen/schließen müssen), kann hier ein Offset dafür eingestellt werden.",
442444
"sunControlMaximization": "<ul><li>Wenn keine Regel oder Überschreiben (Override) zutrifft,<ul><li>Wenn die Sonne <em>nicht</ em> in das Fenster scheint, wird die Rollladenhöhe die definierte <strong>Minimalposition</ strong> gesetzt. (Übersteuern wird ignoriert)</ li><li>Wenn sich die Sonne im Fenster befindet</ li><li>Wenn eine Übersteueruzng aufgesetzt ist und die bedingung zutrifft, wird der Behang auf die Höhe des Übersteuerns gesetzt.< / li><li>Andernfalls wird die Behanghöhe auf die definierte <strong>Maximalposition</ strong> gesetzt.</ li></ ul></ li></ ul>",
443445
"sunControlMinimization": "<ul><li>Wenn keine Regel oder Überschreiben (Override) zutrifft,<ul><li>Wenn die Sonne <em>nicht</ em> in das Fenster scheint, wird die Rollladenhöhe die definierte <strong>Maximalposition</ strong> gesetzt. (Übersteuern wird ignoriert)</ li><li>Wenn sich die Sonne im Fenster befindet</ li><li>Wenn eine Übersteueruzng aufgesetzt ist und die bedingung zutrifft, wird der Behang auf die Höhe des Übersteuerns gesetzt.< / li><li>Andernfalls wird die Behanghöhe auf die definierte <strong>Minimalposition</ strong> gesetzt.</ li></ ul></ li></ ul>",
444446
"sunControlRestriction": "Wenn keine Regel oder Überschreiben (Override) zutrifft, berechnet der Knoten die entsprechende Blindposition, um die Menge des direkten Sonnenlichts, das in den Raum fällt, zu begrenzen.",

nodes/locales/en-US/blind-control.json

+7-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
"blindIncrement": "Increment",
1212
"blindOpenPos": "open position (max)",
1313
"blindClosedPos": "closed position (min)",
14+
"blindOpenPosOffset": "open position offset",
15+
"blindClosedPosOffset": "closed position offset",
1416
"blindLevelDefault": "default position",
1517
"slatPosDefault": "default slat",
1618
"blindLevelMin": "min position",
@@ -58,6 +60,8 @@
5860
"blindIncrement": "0.01 or 1",
5961
"blindOpenPos": "100",
6062
"blindClosedPos": "0",
63+
"blindOpenPosOffset": "offset for the open position",
64+
"blindClosedPosOffset": "offset for the closed position",
6165
"blindLevelDefault": "blind position if no other used",
6266
"slatPosDefault": "slat position if no other used",
6367
"blindLevelMin": "minimum position if sun calculated position",
@@ -125,7 +129,9 @@
125129
"invalid-blind-level": "Given Blind-Position __pos__ is not a valid Position!",
126130
"getOversteerData": "error getting oversteer data: __message__",
127131
"getBlindPosData": "error getting blind level: __message__",
128-
"smoothTimeToolong": "The selected smooth is too long!!"
132+
"smoothTimeToolong": "The selected smooth is too long!!",
133+
"invalidOpenPosOffset":"Invalid value for blind open position offset for the sun control!",
134+
"invalidClosedPosOffset":"Invalid value for blind closed position offset for the sun control!"
129135
}
130136
}
131137
}

0 commit comments

Comments
 (0)