node-red-contrib-knx-ultimate 2.2.25 → 2.2.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/nodes/hue-config.html +7 -9
- package/nodes/hue-config.js +94 -20
- package/nodes/knxUltimate-config.html +1 -1
- package/nodes/knxUltimateHueBattery.html +2 -2
- package/nodes/knxUltimateHueBattery.js +31 -5
- package/nodes/knxUltimateHueButton.js +0 -2
- package/nodes/knxUltimateHueLight.html +403 -289
- package/nodes/knxUltimateHueLight.js +82 -51
- package/nodes/knxUltimateHueLightSensor.html +1 -1
- package/nodes/knxUltimateHueLightSensor.js +32 -2
- package/nodes/knxUltimateHueTemperatureSensor.html +1 -1
- package/nodes/knxUltimateHueTemperatureSensor.js +32 -2
- package/package.json +1 -1
|
@@ -99,36 +99,56 @@ module.exports = function (RED) {
|
|
|
99
99
|
case config.GALightSwitch:
|
|
100
100
|
msg.payload = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(config.dptLightSwitch));
|
|
101
101
|
if (msg.payload === true) {
|
|
102
|
-
|
|
103
|
-
let
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
102
|
+
let colorChoosen;
|
|
103
|
+
let temperatureChoosen;
|
|
104
|
+
let brightnessChoosen;
|
|
105
|
+
// The light must support the temperature (in this case, colorAtSwitchOnNightTime is an object {kelvin:xx, brightness:yy})
|
|
106
|
+
if (node.currentHUEDevice.color_temperature !== undefined) {
|
|
107
|
+
if (node.DayTime === true && config.specifySwitchOnBrightness === "temperature") {
|
|
108
|
+
temperatureChoosen = config.colorAtSwitchOnDayTime.kelvin;
|
|
109
|
+
} else if (node.DayTime === false && config.enableDayNightLighting === "temperature") {
|
|
110
|
+
temperatureChoosen = config.colorAtSwitchOnNightTime.kelvin;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (node.currentHUEDevice.dimming !== undefined) {
|
|
114
|
+
// Check wether the user selected specific brightness at switch on (in this case, colorAtSwitchOnNightTime is an object {kelvin:xx, brightness:yy})
|
|
115
|
+
if (node.DayTime === true && config.specifySwitchOnBrightness === "temperature") {
|
|
116
|
+
brightnessChoosen = config.colorAtSwitchOnDayTime.brightness;
|
|
117
|
+
} else if (node.DayTime === false && config.enableDayNightLighting === "temperature") {
|
|
118
|
+
brightnessChoosen = config.colorAtSwitchOnNightTime.brightness;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (node.currentHUEDevice.color !== undefined) {
|
|
122
|
+
// Check wether the user selected specific color at switch on (in this case, colorAtSwitchOnDayTime is a text with HTML web color)
|
|
123
|
+
if (node.DayTime === true && config.specifySwitchOnBrightness === "yes") {
|
|
124
|
+
colorChoosen = config.colorAtSwitchOnDayTime;
|
|
125
|
+
} else if (node.DayTime === false && config.enableDayNightLighting === "yes") {
|
|
126
|
+
colorChoosen = config.colorAtSwitchOnNightTime;
|
|
127
|
+
}
|
|
108
128
|
}
|
|
109
129
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
// RGB
|
|
130
|
+
if (colorChoosen !== undefined) {
|
|
131
|
+
// Now we have a jColorChoosen. Proceed illuminating the light
|
|
113
132
|
let gamut = null;
|
|
114
|
-
if (node.currentHUEDevice !== undefined
|
|
133
|
+
if (node.currentHUEDevice.color.gamut_type !== undefined) {
|
|
115
134
|
gamut = node.currentHUEDevice.color.gamut_type;
|
|
116
135
|
}
|
|
117
|
-
const dretXY = hueColorConverter.ColorConverter.rgbToXy(
|
|
118
|
-
const dbright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(
|
|
136
|
+
const dretXY = hueColorConverter.ColorConverter.rgbToXy(colorChoosen.red, colorChoosen.green, colorChoosen.blue, gamut);
|
|
137
|
+
const dbright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(colorChoosen.red, colorChoosen.green, colorChoosen.blue);
|
|
119
138
|
node.currentHUEDevice.dimming.brightness = Math.round(dbright, 0);
|
|
120
139
|
node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
|
|
121
140
|
state = dbright > 0 ? { on: { on: true }, dimming: { brightness: dbright }, color: { xy: dretXY } } : { on: { on: false } };
|
|
122
|
-
} if (
|
|
141
|
+
} else if (temperatureChoosen !== undefined) {
|
|
123
142
|
// Kelvin
|
|
124
|
-
const
|
|
125
|
-
const mirek = hueColorConverter.ColorConverter.kelvinToMirek(jColorChoosen.kelvin);
|
|
143
|
+
const mirek = hueColorConverter.ColorConverter.kelvinToMirek(temperatureChoosen);
|
|
126
144
|
node.currentHUEDevice.color_temperature.mirek = mirek;
|
|
127
|
-
node.currentHUEDevice.dimming.brightness =
|
|
145
|
+
node.currentHUEDevice.dimming.brightness = brightnessChoosen;
|
|
128
146
|
node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
|
|
129
147
|
// Kelvin temp
|
|
130
|
-
state =
|
|
131
|
-
} else if (
|
|
148
|
+
state = brightnessChoosen > 0 ? { on: { on: true }, dimming: { brightness: brightnessChoosen }, color_temperature: { mirek: mirek } } : { on: { on: false } };
|
|
149
|
+
} else if (brightnessChoosen !== undefined) {
|
|
150
|
+
state = brightnessChoosen > 0 ? { on: { on: true }, dimming: { brightness: brightnessChoosen } } : { on: { on: false } };
|
|
151
|
+
} else {
|
|
132
152
|
state = { on: { on: true } };
|
|
133
153
|
}
|
|
134
154
|
} else {
|
|
@@ -481,7 +501,7 @@ module.exports = function (RED) {
|
|
|
481
501
|
node.handleSendHUE = (_event) => {
|
|
482
502
|
try {
|
|
483
503
|
if (_event.id === node.hueDevice) {
|
|
484
|
-
if (node.currentHUEDevice === undefined) {
|
|
504
|
+
if (node.currentHUEDevice === undefined || node.serverHue === null || node.serverHue === undefined) {
|
|
485
505
|
node.setNodeStatusHue({
|
|
486
506
|
fill: "red",
|
|
487
507
|
shape: "ring",
|
|
@@ -494,16 +514,22 @@ module.exports = function (RED) {
|
|
|
494
514
|
// Output the msg to the flow
|
|
495
515
|
node.send(_event);
|
|
496
516
|
|
|
517
|
+
// // DEBUG
|
|
518
|
+
//delete _event.dimming;
|
|
519
|
+
//delete _event.color;
|
|
520
|
+
//delete _event.color_temperature;
|
|
521
|
+
//delete _event.color_temperature_delta;
|
|
522
|
+
|
|
497
523
|
// As grouped_light doesn't contain all requested properties, i find the first light in the group, and use this below in the code
|
|
498
524
|
// If the event type is grouped light, and there are missing properties, i infer these missing properties from the first light in the group!
|
|
499
|
-
if ((_event.
|
|
525
|
+
if ((_event.color !== undefined || _event.dimming !== undefined || _event.color_temperature !== undefined) && _event.type === 'grouped_light') {
|
|
500
526
|
try {
|
|
501
527
|
const firstLightInGroup = node.serverHue.getFirstLightInGroup(_event.id);
|
|
502
528
|
if (firstLightInGroup !== null && firstLightInGroup !== undefined) {
|
|
503
|
-
if (_event.color === undefined
|
|
529
|
+
if (_event.color === undefined) {
|
|
504
530
|
_event.color = firstLightInGroup.color;
|
|
505
531
|
}
|
|
506
|
-
if (_event.color_temperature === undefined
|
|
532
|
+
if (_event.color_temperature === undefined) {
|
|
507
533
|
_event.color_temperature = firstLightInGroup.color_temperature;
|
|
508
534
|
}
|
|
509
535
|
}
|
|
@@ -513,23 +539,25 @@ module.exports = function (RED) {
|
|
|
513
539
|
if (_event.hasOwnProperty("on")) {
|
|
514
540
|
node.updateKNXLightState(_event.on.on);
|
|
515
541
|
// In case of switch off, set the dim to zero
|
|
516
|
-
if (
|
|
517
|
-
_event.on.on === false
|
|
518
|
-
&& (config.updateKNXBrightnessStatusOnHUEOnOff === undefined || config.updateKNXBrightnessStatusOnHUEOnOff === "onhueoff")
|
|
519
|
-
) {
|
|
542
|
+
if (_event.on.on === false && (config.updateKNXBrightnessStatusOnHUEOnOff === undefined || config.updateKNXBrightnessStatusOnHUEOnOff === "onhueoff")) {
|
|
520
543
|
node.updateKNXBrightnessState(0);
|
|
521
544
|
//node.currentHUEDevice.dimming.brightness = 0;
|
|
545
|
+
} else if (_event.on.on === true && node.currentHUEDevice.on.on === false) {
|
|
546
|
+
// Turn on always update the dimming KNX Status value as well.
|
|
547
|
+
let brightVal = 100;
|
|
548
|
+
if (node.currentHUEDevice.dimming !== undefined && node.currentHUEDevice.dimming.brightness !== undefined) brightVal = node.currentHUEDevice.dimming.brightness;
|
|
549
|
+
node.updateKNXBrightnessState(brightVal);
|
|
522
550
|
}
|
|
523
551
|
node.currentHUEDevice.on.on = _event.on.on;
|
|
524
552
|
}
|
|
525
553
|
|
|
526
|
-
if (_event.
|
|
554
|
+
if (_event.color !== undefined) { // fixed https://github.com/Supergiovane/node-red-contrib-knx-ultimate/issues/287
|
|
527
555
|
node.updateKNXLightColorState(_event.color);
|
|
528
556
|
node.currentHUEDevice.color = _event.color;
|
|
529
557
|
}
|
|
530
558
|
|
|
531
559
|
if (_event.hasOwnProperty("dimming") && _event.dimming.brightness !== undefined) {
|
|
532
|
-
//
|
|
560
|
+
// Once upon n a time, the light transmit the brightness value of 0.39.
|
|
533
561
|
// To avoid wrongly turn light state on, exit
|
|
534
562
|
if (_event.dimming.brightness < 1) _event.dimming.brightness = 0;
|
|
535
563
|
if (node.currentHUEDevice.hasOwnProperty("on") && node.currentHUEDevice.on.on === false && _event.dimming.brightness === 0) {
|
|
@@ -658,33 +686,36 @@ module.exports = function (RED) {
|
|
|
658
686
|
|
|
659
687
|
node.updateKNXLightColorState = function updateKNXLightColorState(_value, _outputtype = "write") {
|
|
660
688
|
if (config.GALightColorState !== undefined && config.GALightColorState !== "") {
|
|
689
|
+
if (!_value.hasOwnProperty('xy') || _value.xy.x === undefined) return;
|
|
661
690
|
const knxMsgPayload = {};
|
|
662
691
|
knxMsgPayload.topic = config.GALightColorState;
|
|
663
692
|
knxMsgPayload.dpt = config.dptLightColorState;
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
if (
|
|
673
|
-
node.server.
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
693
|
+
try {
|
|
694
|
+
knxMsgPayload.payload = hueColorConverter.ColorConverter.xyBriToRgb(
|
|
695
|
+
_value.xy.x,
|
|
696
|
+
_value.xy.y,
|
|
697
|
+
node.currentHUEDevice !== undefined && node.currentHUEDevice.dimming !== undefined && node.currentHUEDevice.dimming.brightness === undefined ? node.currentHUEDevice.dimming.brightness : 100,
|
|
698
|
+
);
|
|
699
|
+
knxMsgPayload.payload = { red: knxMsgPayload.payload.r, green: knxMsgPayload.payload.g, blue: knxMsgPayload.payload.b };
|
|
700
|
+
// Send to KNX bus
|
|
701
|
+
if (knxMsgPayload.topic !== "" && knxMsgPayload.topic !== undefined) {
|
|
702
|
+
if (node.server !== null && node.server !== undefined) {
|
|
703
|
+
node.server.writeQueueAdd({
|
|
704
|
+
grpaddr: knxMsgPayload.topic,
|
|
705
|
+
payload: knxMsgPayload.payload,
|
|
706
|
+
dpt: knxMsgPayload.dpt,
|
|
707
|
+
outputtype: _outputtype,
|
|
708
|
+
nodecallerid: node.id,
|
|
709
|
+
});
|
|
710
|
+
}
|
|
680
711
|
}
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
})
|
|
712
|
+
node.setNodeStatusHue({
|
|
713
|
+
fill: "blue",
|
|
714
|
+
shape: "ring",
|
|
715
|
+
text: "HUE->KNX Color",
|
|
716
|
+
payload: knxMsgPayload.payload,
|
|
717
|
+
});
|
|
718
|
+
} catch (error) { }
|
|
688
719
|
}
|
|
689
720
|
};
|
|
690
721
|
|
|
@@ -7,7 +7,7 @@ module.exports = function (RED) {
|
|
|
7
7
|
node.topic = node.name;
|
|
8
8
|
node.name = config.name === undefined ? 'Hue' : config.name;
|
|
9
9
|
node.dpt = '';
|
|
10
|
-
node.notifyreadrequest =
|
|
10
|
+
node.notifyreadrequest = true;
|
|
11
11
|
node.notifyreadrequestalsorespondtobus = 'false';
|
|
12
12
|
node.notifyreadrequestalsorespondtobusdefaultvalueifnotinitialized = '';
|
|
13
13
|
node.notifyresponse = false;
|
|
@@ -23,7 +23,8 @@ module.exports = function (RED) {
|
|
|
23
23
|
node.formatnegativevalue = 'leave';
|
|
24
24
|
node.formatdecimalsvalue = 2;
|
|
25
25
|
node.hueDevice = config.hueDevice;
|
|
26
|
-
node.initializingAtStart = !((config.readStatusAtStartup === undefined || config.readStatusAtStartup === "
|
|
26
|
+
node.initializingAtStart = !((config.readStatusAtStartup === undefined || config.readStatusAtStartup === "yes"));
|
|
27
|
+
node.currentDeviceValue = 0;
|
|
27
28
|
|
|
28
29
|
// Used to call the status update from the config node.
|
|
29
30
|
node.setNodeStatus = ({ fill, shape, text, payload }) => {
|
|
@@ -39,6 +40,19 @@ module.exports = function (RED) {
|
|
|
39
40
|
|
|
40
41
|
// This function is called by the knx-ultimate config node, to output a msg.payload.
|
|
41
42
|
node.handleSend = msg => {
|
|
43
|
+
|
|
44
|
+
// Respond to KNX read telegram, by sending the current value as response telegram.
|
|
45
|
+
if (msg.knx.event === "GroupValue_Read") {
|
|
46
|
+
switch (msg.knx.destination) {
|
|
47
|
+
case config.GAlightsensor:
|
|
48
|
+
// To the KNX bus wires
|
|
49
|
+
node.sendResponseToKNX(node.currentDeviceValue);
|
|
50
|
+
break;
|
|
51
|
+
default:
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
42
56
|
};
|
|
43
57
|
|
|
44
58
|
node.handleSendHUE = _event => {
|
|
@@ -57,6 +71,8 @@ module.exports = function (RED) {
|
|
|
57
71
|
knxMsgPayload.payload = _event.light.light_level === 0 ? 0 : Math.round(Math.pow(10, (_event.light.light_level - 1) / 10000));
|
|
58
72
|
// Send to KNX bus
|
|
59
73
|
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) node.server.writeQueueAdd({ grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id });
|
|
74
|
+
node.currentDeviceValue = knxMsgPayload.payload;
|
|
75
|
+
|
|
60
76
|
node.status({ fill: 'green', shape: 'dot', text: 'HUE->KNX ' + JSON.stringify(knxMsgPayload.payload) + ' (' + new Date().getDate() + ', ' + new Date().toLocaleTimeString() + ')' });
|
|
61
77
|
|
|
62
78
|
// Setup the output msg
|
|
@@ -74,6 +90,20 @@ module.exports = function (RED) {
|
|
|
74
90
|
}
|
|
75
91
|
};
|
|
76
92
|
|
|
93
|
+
node.sendResponseToKNX = (_level) => {
|
|
94
|
+
const knxMsgPayload = {};
|
|
95
|
+
knxMsgPayload.topic = config.GAlightsensor;
|
|
96
|
+
knxMsgPayload.dpt = config.dptlightsensor;
|
|
97
|
+
|
|
98
|
+
knxMsgPayload.payload = _level;
|
|
99
|
+
// Send to KNX bus
|
|
100
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) {
|
|
101
|
+
node.server.writeQueueAdd({
|
|
102
|
+
grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'response', nodecallerid: node.id,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
77
107
|
// On each deploy, unsubscribe+resubscribe
|
|
78
108
|
if (node.server) {
|
|
79
109
|
node.server.removeClient(node);
|
|
@@ -7,7 +7,7 @@ module.exports = function (RED) {
|
|
|
7
7
|
node.topic = node.name;
|
|
8
8
|
node.name = config.name === undefined ? 'Hue' : config.name;
|
|
9
9
|
node.dpt = '';
|
|
10
|
-
node.notifyreadrequest =
|
|
10
|
+
node.notifyreadrequest = true;
|
|
11
11
|
node.notifyreadrequestalsorespondtobus = 'false';
|
|
12
12
|
node.notifyreadrequestalsorespondtobusdefaultvalueifnotinitialized = '';
|
|
13
13
|
node.notifyresponse = false;
|
|
@@ -23,7 +23,8 @@ module.exports = function (RED) {
|
|
|
23
23
|
node.formatnegativevalue = 'leave';
|
|
24
24
|
node.formatdecimalsvalue = 2;
|
|
25
25
|
node.hueDevice = config.hueDevice;
|
|
26
|
-
node.initializingAtStart = !((config.readStatusAtStartup === undefined || config.readStatusAtStartup === "
|
|
26
|
+
node.initializingAtStart = !((config.readStatusAtStartup === undefined || config.readStatusAtStartup === "yes"));
|
|
27
|
+
node.currentDeviceValue = 0;
|
|
27
28
|
|
|
28
29
|
// Used to call the status update from the config node.
|
|
29
30
|
node.setNodeStatus = ({
|
|
@@ -43,6 +44,17 @@ module.exports = function (RED) {
|
|
|
43
44
|
|
|
44
45
|
// This function is called by the knx-ultimate config node, to output a msg.payload.
|
|
45
46
|
node.handleSend = (msg) => {
|
|
47
|
+
// Respond to KNX read telegram, by sending the current value as response telegram.
|
|
48
|
+
if (msg.knx.event === "GroupValue_Read") {
|
|
49
|
+
switch (msg.knx.destination) {
|
|
50
|
+
case config.GAtemperaturesensor:
|
|
51
|
+
// To the KNX bus wires
|
|
52
|
+
node.sendResponseToKNX(node.currentDeviceValue);
|
|
53
|
+
break;
|
|
54
|
+
default:
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
46
58
|
};
|
|
47
59
|
|
|
48
60
|
node.handleSendHUE = (_event) => {
|
|
@@ -60,6 +72,8 @@ module.exports = function (RED) {
|
|
|
60
72
|
grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id,
|
|
61
73
|
});
|
|
62
74
|
}
|
|
75
|
+
node.currentDeviceValue = knxMsgPayload.payload;
|
|
76
|
+
|
|
63
77
|
node.status({ fill: 'green', shape: 'dot', text: `HUE->KNX ${JSON.stringify(knxMsgPayload.payload)} (${new Date().getDate()}, ${new Date().toLocaleTimeString()})` });
|
|
64
78
|
|
|
65
79
|
// Setup the output msg
|
|
@@ -79,6 +93,22 @@ module.exports = function (RED) {
|
|
|
79
93
|
}
|
|
80
94
|
};
|
|
81
95
|
|
|
96
|
+
|
|
97
|
+
node.sendResponseToKNX = (_level) => {
|
|
98
|
+
const knxMsgPayload = {};
|
|
99
|
+
knxMsgPayload.topic = config.GAtemperaturesensor;
|
|
100
|
+
knxMsgPayload.dpt = config.dpttemperaturesensor;
|
|
101
|
+
|
|
102
|
+
knxMsgPayload.payload = _level;
|
|
103
|
+
// Send to KNX bus
|
|
104
|
+
if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) {
|
|
105
|
+
node.server.writeQueueAdd({
|
|
106
|
+
grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'response', nodecallerid: node.id,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
|
|
82
112
|
// On each deploy, unsubscribe+resubscribe
|
|
83
113
|
if (node.server) {
|
|
84
114
|
node.server.removeClient(node);
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"engines": {
|
|
4
4
|
"node": ">=16.0.0"
|
|
5
5
|
},
|
|
6
|
-
"version": "2.2.
|
|
6
|
+
"version": "2.2.27",
|
|
7
7
|
"description": "Control your KNX intallation via Node-Red! Single Node KNX IN/OUT with optional ETS group address importer. Easy to use and highly configurable. With integrated Philips HUE devices control.",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"binary-parser": "2.2.1",
|