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.
@@ -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
- // Check wether the user selected specific color/brightness at switch on.
103
- let jColorChoosen = null;
104
- if (node.DayTime === true && (config.specifySwitchOnBrightness === "yes" || config.specifySwitchOnBrightness === "temperature")) {
105
- jColorChoosen = config.colorAtSwitchOnDayTime;
106
- } else if (node.DayTime === false && (config.enableDayNightLighting === "yes" || config.enableDayNightLighting === "temperature")) {
107
- jColorChoosen = config.colorAtSwitchOnNightTime;
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
- // Now we have a jColorChoosen. Proceed illuminating the light
111
- if (jColorChoosen !== null && jColorChoosen.kelvin === undefined) {
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 && node.currentHUEDevice.hasOwnProperty("color") && node.currentHUEDevice.color.hasOwnProperty("gamut_type")) {
133
+ if (node.currentHUEDevice.color.gamut_type !== undefined) {
115
134
  gamut = node.currentHUEDevice.color.gamut_type;
116
135
  }
117
- const dretXY = hueColorConverter.ColorConverter.rgbToXy(jColorChoosen.red, jColorChoosen.green, jColorChoosen.blue, gamut);
118
- const dbright = hueColorConverter.ColorConverter.getBrightnessFromRGBOrHex(jColorChoosen.red, jColorChoosen.green, jColorChoosen.blue);
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 (jColorChoosen !== null && jColorChoosen.kelvin !== undefined) {
141
+ } else if (temperatureChoosen !== undefined) {
123
142
  // Kelvin
124
- const dbright = jColorChoosen.brightness;
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 = dbright;
145
+ node.currentHUEDevice.dimming.brightness = brightnessChoosen;
128
146
  node.updateKNXBrightnessState(node.currentHUEDevice.dimming.brightness);
129
147
  // Kelvin temp
130
- state = dbright > 0 ? { on: { on: true }, dimming: { brightness: dbright }, color_temperature: { mirek: mirek } } : { on: { on: false } };
131
- } else if (jColorChoosen === null || jColorChoosen === undefined) {
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.hasOwnProperty("color") || _event.hasOwnProperty("dimming")) && _event.type === 'grouped_light') {
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 || Object.keys(_event.color).length === 0) {
529
+ if (_event.color === undefined) {
504
530
  _event.color = firstLightInGroup.color;
505
531
  }
506
- if (_event.color_temperature === undefined || Object.keys(_event.color_temperature).length === 0) {
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.hasOwnProperty("color")) {
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
- // Every once on a time, the light transmit the brightness value of 0.39.
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
- knxMsgPayload.payload = hueColorConverter.ColorConverter.xyBriToRgb(
665
- _value.xy.x,
666
- _value.xy.y,
667
- node.currentHUEDevice !== undefined ? node.currentHUEDevice.dimming.brightness : 100,
668
- );
669
- knxMsgPayload.payload = { red: knxMsgPayload.payload.r, green: knxMsgPayload.payload.g, blue: knxMsgPayload.payload.b };
670
- // Send to KNX bus
671
- if (knxMsgPayload.topic !== "" && knxMsgPayload.topic !== undefined) {
672
- if (node.server !== null && node.server !== undefined) {
673
- node.server.writeQueueAdd({
674
- grpaddr: knxMsgPayload.topic,
675
- payload: knxMsgPayload.payload,
676
- dpt: knxMsgPayload.dpt,
677
- outputtype: _outputtype,
678
- nodecallerid: node.id,
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
- node.setNodeStatusHue({
683
- fill: "blue",
684
- shape: "ring",
685
- text: "HUE->KNX Color",
686
- payload: knxMsgPayload.payload,
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
 
@@ -13,7 +13,7 @@
13
13
  namelightsensor: { value: "" },
14
14
  GAlightsensor: { value: "" },
15
15
  dptlightsensor: { value: "" },
16
- readStatusAtStartup: { value: "no" },
16
+ readStatusAtStartup: { value: "yes" },
17
17
 
18
18
  hueDevice: { value: "" }
19
19
  },
@@ -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 = false;
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 === "no"));
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);
@@ -13,7 +13,7 @@
13
13
  nametemperaturesensor: { value: "" },
14
14
  GAtemperaturesensor: { value: "" },
15
15
  dpttemperaturesensor: { value: "" },
16
- readStatusAtStartup: { value: "no" },
16
+ readStatusAtStartup: { value: "yes" },
17
17
 
18
18
  hueDevice: { value: "" }
19
19
  },
@@ -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 = false;
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 === "no"));
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.25",
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",