node-red-contrib-knx-ultimate 3.0.0-beta1 → 3.0.0-beta2

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 CHANGED
@@ -6,7 +6,11 @@
6
6
 
7
7
  # CHANGELOG
8
8
 
9
- **Version 3.0.0** - Juni 2024<br/>
9
+ **Version 3.0.0-beta2** - Juni 2024<br/>
10
+ - Warning: Node-Red version **equals or major than 3.1.1** is needed to run this node.<br/>
11
+ - NEW: Hue Node Software Update Status for the HUE devices. <br/>
12
+
13
+ **Version 3.0.0-beta1** - Juni 2024<br/>
10
14
  - Warning: Node-Red version **equals or major than 3.1.1** is needed to run this node.<br/>
11
15
  - FEATURE CAUTION: rewrote the KNX engine in Typescript. If you encounter problems, please open a gitub issue. You can revert by installing the older version 2.5.1 <br/>
12
16
  - FEATURE: KNX Ultimate node: you can now set the group address from a global, flow or $env variable, beside the standard 3-level format. <br/>
@@ -344,6 +344,14 @@ module.exports = (RED) => {
344
344
  id: resource.id,
345
345
  });
346
346
  }
347
+ if (_rtype === 'device_software_update') {
348
+ const Room = node.hueAllRooms.find((room) => room.children.find((child) => child.rid === resource.owner.rid))
349
+ const linkedDevName = node.hueAllResources.find((dev) => dev.type === 'device' && dev.services.find((serv) => serv.rid === resource.id)).metadata.name || ''
350
+ retArray.push({
351
+ name: `Software status: ${linkedDevName}${Room !== undefined ? `, room ${Room.metadata.name}` : ''}`,
352
+ id: resource.id,
353
+ });
354
+ }
347
355
  } catch (error) {
348
356
  retArray.push({
349
357
  name: `${_rtype}: ERROR ${error.message}`,
@@ -729,9 +729,9 @@ The new configuration will be retained until next msg.setConfig or until restart
729
729
  All properties (*setGroupAddress* and *setDPT*) **are mandatory**..
730
730
  Use it like that, in a functon node:
731
731
 
732
- ** Set both GA and DPT **
732
+ **Set both GA and DPT**
733
733
 
734
- ```json
734
+ ```javascript
735
735
  // Change the node properties as follows:
736
736
  // setGroupAddress: set the new group address.
737
737
  // setDPT: set the new Datapoint, as you can see in the dropdown list (the numeric part, for example "1.001", "237.600", etc...). If set to **auto**, the datapoint will be read from the ETS file (if present).
@@ -743,9 +743,9 @@ msg.setConfig = config;
743
743
  return msg;
744
744
  ```
745
745
 
746
- ** Set GA and read the datapoint from the ETS file **
746
+ **Set GA and read the datapoint from the ETS file**
747
747
 
748
- ```json
748
+ ```javascript
749
749
  // Change the node properties as follows:
750
750
  // setGroupAddress: set the new group address.
751
751
  // setDPT: set the new Datapoint, as you can see in the dropdown list (the numeric part, for example "1.001", "237.600", etc...). If set to "auto", the datapoint will be read from the ETS file (if present).
@@ -209,6 +209,7 @@ module.exports = function (RED) {
209
209
  node.setLocalStatus({ fill: 'grey', shape: 'dot', text: 'ERROR: You must provide payload (true/false)', payload: '', GA: '', dpt: '', devicename: '' });
210
210
  return;
211
211
  }
212
+
212
213
  msg.knx = { dpt: '1.001' };
213
214
  node.handleSend(msg);
214
215
  });
@@ -0,0 +1,261 @@
1
+ <script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/11f26b4500.js"></script>
2
+
3
+ <script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/htmlUtils.js"></script>
4
+
5
+ <script type="text/javascript">
6
+ RED.nodes.registerType('knxUltimateHuedevice_software_update', {
7
+ category: "KNX Ultimate",
8
+ color: '#C0C7E9',
9
+ defaults: {
10
+ //buttonState: {value: true},
11
+ server: { type: "knxUltimate-config", required: false },
12
+ serverHue: { type: "hue-config", required: true },
13
+ name: { value: "" },
14
+
15
+ namedevice_software_update: { value: "" },
16
+ GAdevice_software_update: { value: "" },
17
+ dptdevice_software_update: { value: "" },
18
+ readStatusAtStartup: { value: "yes" },
19
+
20
+
21
+ hueDevice: { value: "" }
22
+ },
23
+ inputs: 0,
24
+ outputs: 1,
25
+ icon: "node-hue-icon.svg",
26
+ label: function () {
27
+ return (this.name || "Hue Software Update");
28
+ },
29
+ paletteLabel: "Hue Software Update",
30
+ // button: {
31
+ // enabled: function() {
32
+ // // return whether or not the button is enabled, based on the current
33
+ // // configuration of the node
34
+ // return !this.changed
35
+ // },
36
+ // visible: function() {
37
+ // // return whether or not the button is visible, based on the current
38
+ // // configuration of the node
39
+ // return this.hasButton
40
+ // },
41
+ // //toggle: "buttonState",
42
+ // onclick: function() {}
43
+ // },
44
+ oneditprepare: function () {
45
+ var node = this;
46
+ var oNodeServer = RED.nodes.node($("#node-input-server").val()); // Store the config-node
47
+ var oNodeServerHue = RED.nodes.node($("#node-input-serverHue").val()); // Store the config-node
48
+
49
+ // 19/02/2020 Used to get the server sooner als deploy.
50
+ $("#node-input-server").change(function () {
51
+ try {
52
+ oNodeServer = RED.nodes.node($(this).val());
53
+ } catch (error) { }
54
+ });
55
+ // 19/02/2020 Used to get the server sooner als deploy.
56
+ $("#node-input-serverHue").change(function () {
57
+ try {
58
+ oNodeServerHue = RED.nodes.node($(this).val());
59
+ } catch (error) { }
60
+ });
61
+
62
+
63
+
64
+ // DPT
65
+ // ########################
66
+ $.getJSON('knxUltimateDpts?serverId=' + $("#node-input-server").val(), (data) => {
67
+ data.forEach(dpt => {
68
+ if (dpt.value.startsWith("1.")) {
69
+ $("#node-input-dptdevice_software_update").append($("<option></option>")
70
+ .attr("value", dpt.value)
71
+ .text(dpt.text))
72
+ }
73
+ });
74
+ $("#node-input-dptdevice_software_update").val(this.dptdevice_software_update)
75
+ })
76
+
77
+ // Autocomplete suggestion with ETS csv File
78
+ $("#node-input-GAdevice_software_update").autocomplete({
79
+ minLength: 0,
80
+ source: function (request, response) {
81
+ //$.getJSON("csv", request, function( data, status, xhr ) {
82
+ $.getJSON("knxUltimatecsv?nodeID=" + oNodeServer.id, (data) => {
83
+ response($.map(data, function (value, key) {
84
+ var sSearch = (value.ga + " (" + value.devicename + ") DPT" + value.dpt);
85
+ if (htmlUtilsfullCSVSearch(sSearch, request.term + " 1.")) {
86
+ return {
87
+ label: value.ga + " # " + value.devicename + " # " + value.dpt, // Label for Display
88
+ value: value.ga // Value
89
+ }
90
+ } else {
91
+ return null;
92
+ }
93
+ }));
94
+ });
95
+ }, select: function (event, ui) {
96
+ // Sets Datapoint and device name automatically
97
+ var sDevName = ui.item.label.split("#")[1].trim();
98
+ try {
99
+ sDevName = sDevName.substr(sDevName.indexOf(")") + 1).trim();
100
+ } catch (error) {
101
+ }
102
+ $('#node-input-namedevice_software_update').val(sDevName);
103
+ var optVal = $("#node-input-dptdevice_software_update option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr('value');
104
+ // Select the option value
105
+ $("#node-input-dptdevice_software_update").val(optVal);
106
+ }
107
+ }).focus(function () {
108
+ $(this).autocomplete('search', $(this).val() + 'exactmatch');
109
+ });
110
+ // ########################
111
+
112
+
113
+
114
+
115
+ // Autocomplete suggestion with HUE
116
+ $("#node-input-name").autocomplete({
117
+ minLength: 0,
118
+ source: function (request, response) {
119
+ $.getJSON("KNXUltimateGetResourcesHUE?rtype=device_software_update&serverId=" + oNodeServerHue.id, (data) => {
120
+ response($.map(data.devices, function (value, key) {
121
+ //alert(JSON.stringify(value) + " "+ key)
122
+ var sSearch = (value.name);
123
+ if (htmlUtilsfullCSVSearch(sSearch, request.term)) {
124
+ return {
125
+ hueDevice: value.id, // Label for Display
126
+ value: value.name // Value
127
+ }
128
+ } else {
129
+ return null;
130
+ }
131
+ }));
132
+ });
133
+ }, select: function (event, ui) {
134
+ // Sets the fields
135
+ $('#node-input-hueDevice').val(ui.item.hueDevice);
136
+ }
137
+ }).focus(function () {
138
+ $(this).autocomplete('search', $(this).val() + 'exactmatch');
139
+ });
140
+
141
+
142
+ // ########################
143
+
144
+
145
+ },
146
+ oneditsave: function () {
147
+
148
+
149
+ },
150
+ oneditcancel: function () {
151
+
152
+ }
153
+ })
154
+
155
+ </script>
156
+
157
+ <script type="text/html" data-template-name="knxUltimateHuedevice_software_update">
158
+
159
+
160
+ <div class="form-row">
161
+ <b>HUE Device Software Update node</b>&nbsp&nbsp<span style="color:red"
162
+ &nbsp
163
+ &nbsp<i class="fa fa-youtube"></i></span>&nbsp<a target="_blank" href="https://youtu.be/jjEUI1J8bkA"><u>Youtube sample</u></a>
164
+ <br />
165
+ <br />
166
+ <p align="center">
167
+ <i class="fa-solid fa-tower-broadcast fa-beat fa-4x"></i>
168
+ </p>
169
+ <br />
170
+ <label for="node-input-server" >
171
+ <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAKnRFWHRDcmVhdGlvbiBUaW1lAEZyIDYgQXVnIDIwMTAgMjE6NTI6MTkgKzAxMDD84aS8AAAAB3RJTUUH3gYYCicNV+4WIQAAAAlwSFlzAAALEgAACxIB0t1+/AAAAARnQU1BAACxjwv8YQUAAACUSURBVHjaY2CgFZg5c+Z/ZEyWAZ8+f/6/ZsWs/xoamqMGkGrA6Wla/1+fVARjEBuGsSoGmY4eZSCNL59d/g8DIDbIAHR14OgFGQByKjIGKX5+6/T///8gGMQGiV1+/B0Fg70GIkD+RMYgxf/O5/7//2MSmAZhkBi6OrgB6Bg5DGB4ajr3f2xqsYYLSDE2THJUDg0AAAqyDVd4tp4YAAAAAElFTkSuQmCC"></img>
172
+ KNX GW
173
+ </label>
174
+ <input type="text" id="node-input-server" />
175
+ </div>
176
+
177
+ <div class="form-row">
178
+ <label for="node-input-serverHue">
179
+ <img src="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAEKADAAQAAAABAAAAEAAAAAA0VXHyAAABFUlEQVQ4EZWSsWoCQRCG1yiENEFEi6QSkjqWWoqFoBYJ+Br6JHkMn8Iibd4ihQpaJIhWNkry/ZtdGZY78Qa+m39nZ+dm9s4550awglNBluS/gVtAX6KgDclf68w2OThgfR9iT/jnoEv4TtByDThWTCDKW4SSZTf/zj9/eZbN+izTDuKGimu0vPF8B/YN8aC8LmcOj/AAn9CFTEs70Js/oGqy79C69bqJ5XbQI2kGO5N8QL9D08S8zBtBF5ZaVsznpCMoqJnVdjTpb1Db0fwIWmQV6BLXzFOYgA6/gDVfQN9bBWp2J2hdWDPoBV5FrKnAJutHikk/CHHR8i7x4iG7qQ720IYvu3GFbpHjx3pFrOFYkA354z/5bkK826phyAAAAABJRU5ErkJggg=="/>
180
+ HUE Bridge
181
+ </label>
182
+ <input type="text" id="node-input-serverHue" />
183
+ </div>
184
+
185
+ <br/>
186
+ <p>
187
+ <b>Philips HUE</b>
188
+ </p>
189
+
190
+ <div class="form-row">
191
+ <label for="node-input-hueDevice" >
192
+ <i class="fa fa-play-circle"></i>&nbspHue Device</label>
193
+ <input type="text" id="node-input-name" placeholder="Enter your hue device name" />
194
+ <input type="hidden" id="node-input-hueDevice" />
195
+ </div>
196
+
197
+ <br/>
198
+
199
+ <p>
200
+ <b>KNX</b>
201
+ </p>
202
+
203
+ <div class="form-row">
204
+ <label for="node-input-namedevice_software_update" style="width:100px;"><i class="fa fa-play-circle-o"></i> Status</span></label>
205
+
206
+ <label for="node-input-GAdevice_software_update" style="width:20px;">GA</label>
207
+ <input type="text" id="node-input-GAdevice_software_update" placeholder="Ex: 1/1/1" style="width:70px;margin-left: 5px; text-align: left;">
208
+
209
+ <label for="node-input-dptdevice_software_update" style="width:40px; margin-left: 0px; text-align: right;">DPT</label>
210
+ <select id="node-input-dptdevice_software_update" style="width:140px;"></select>
211
+
212
+ <label for="node-input-namedevice_software_update" style="width:50px; margin-left: 0px; text-align: right;">Name</label>
213
+ <input type="text" id="node-input-namedevice_software_update" style="width:200px;margin-left: 5px; text-align: left;">
214
+ </div>
215
+
216
+ <div class="form-row">
217
+ <label style="width:180px" for="node-input-readStatusAtStartup"><i class="fa fa-play-circle"></i> Read status at startup</label>
218
+ <select id="node-input-readStatusAtStartup">
219
+ <option value="no">No</option>
220
+ <option value="yes">Yes, and emit KNX telegrams.</option>
221
+ </select>
222
+ </div>
223
+ <br/>
224
+ <br/>
225
+ <br/>
226
+
227
+
228
+ </script>
229
+
230
+ <script type="text/markdown" data-help-name="knxUltimateHuedevice_software_update">
231
+ This node monitors wether the selected device has a software update avaiable.
232
+
233
+ Start typing the name or group address of your KNX device in the GA field, the avaiable devices start showing up while
234
+ you're typing.
235
+
236
+ **General**
237
+ |Property|Description|
238
+ |--|--|
239
+ | KNX GW | Select the KNX gateway to be used |
240
+ | HUE Bridge | Select the HUE Bridge to be used |
241
+ | Hue Device | HUE Device to be monitored for software update. The avaiable devices start showing up while you're typing.|
242
+
243
+ |Property|Description|
244
+ |--|--|
245
+ | Status | The software update status KNX group address. The payload of this KNX group address will change to *true* if a device has a software update avaiable or is installing the update, or if the update is ready to be installed, otherwise *false*. |
246
+ | Read status at startup | Read the status at startup and emit the event to the KNX bus at startup/reconnection. (Default "yes")|
247
+
248
+ ### Outputs
249
+
250
+ 1. Standard output
251
+ : payload (boolean) : the standard output of the command.
252
+ : status (string) : the text representing the status. It can be: **no_update, update_pending, ready_to_install, installing**.
253
+
254
+
255
+ <br />
256
+
257
+ [DONATE HERE, THANK YOU!](https://www.paypal.me/techtoday)
258
+
259
+ <br />
260
+
261
+ </script>
@@ -0,0 +1,134 @@
1
+ module.exports = function (RED) {
2
+ function knxUltimateHuedevice_software_update(config) {
3
+ RED.nodes.createNode(this, config);
4
+ const node = this;
5
+ node.server = RED.nodes.getNode(config.server);
6
+ node.serverHue = RED.nodes.getNode(config.serverHue);
7
+ node.topic = node.name;
8
+ node.name = config.name === undefined ? 'Hue' : config.name;
9
+ node.dpt = '';
10
+ node.notifyreadrequest = true;
11
+ node.notifyreadrequestalsorespondtobus = 'false';
12
+ node.notifyreadrequestalsorespondtobusdefaultvalueifnotinitialized = '';
13
+ node.notifyresponse = false;
14
+ node.notifywrite = true;
15
+ node.initialread = true;
16
+ node.listenallga = true; // Don't remove
17
+ node.outputtype = 'write';
18
+ node.outputRBE = 'false'; // Apply or not RBE to the output (Messages coming from flow)
19
+ node.inputRBE = 'false'; // Apply or not RBE to the input (Messages coming from BUS)
20
+ node.currentPayload = ''; // Current value for the RBE input and for the .previouspayload msg
21
+ node.passthrough = 'no';
22
+ node.formatmultiplyvalue = 1;
23
+ node.formatnegativevalue = 'leave';
24
+ node.formatdecimalsvalue = 2;
25
+ node.hueDevice = config.hueDevice;
26
+ node.initializingAtStart = (config.readStatusAtStartup === undefined || config.readStatusAtStartup === "yes");
27
+ node.currentDeviceValue = false;
28
+
29
+ // Used to call the status update from the config node.
30
+ node.setNodeStatus = ({
31
+ fill, shape, text, payload,
32
+ }) => {
33
+
34
+ };
35
+ // Used to call the status update from the HUE config node.
36
+ node.setNodeStatusHue = ({
37
+ fill, shape, text, payload,
38
+ }) => {
39
+ if (payload === undefined) payload = '';
40
+ const dDate = new Date();
41
+ payload = typeof payload === 'object' ? JSON.stringify(payload) : payload.toString();
42
+ node.status({ fill, shape, text: `${text} ${payload} (${dDate.getDate()}, ${dDate.toLocaleTimeString()})` });
43
+ };
44
+
45
+ // This function is called by the knx-ultimate config node, to output a msg.payload.
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.GAdevice_software_update:
51
+ // To the KNX bus wires
52
+ node.sendResponseToKNX(node.currentDeviceValue);
53
+ break;
54
+ default:
55
+ break;
56
+ }
57
+ }
58
+ };
59
+
60
+ node.handleSendHUE = (_event) => {
61
+ try {
62
+ // Event status: one of connected, disconnected, connectivity_issue, unidirectional_incoming
63
+ if (_event.id === config.hueDevice) {
64
+ if (!_event.hasOwnProperty("state") || _event.state === undefined) return;
65
+
66
+ const knxMsgPayload = {};
67
+ knxMsgPayload.topic = config.GAdevice_software_update;
68
+ knxMsgPayload.dpt = config.dptdevice_software_update;
69
+
70
+ knxMsgPayload.payload = (_event.state !== "no_update");
71
+ // Send to KNX bus
72
+ if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) {
73
+ node.server.writeQueueAdd({
74
+ grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'write', nodecallerid: node.id,
75
+ });
76
+ }
77
+ node.currentDeviceValue = knxMsgPayload.payload;
78
+ // Setup the output msg
79
+ knxMsgPayload.name = node.name;
80
+ knxMsgPayload.status = _event.state;
81
+ knxMsgPayload.event = 'device_software_update';
82
+ // Send payload
83
+ knxMsgPayload.rawEvent = _event;
84
+ node.send(knxMsgPayload);
85
+ node.setNodeStatusHue({
86
+ fill: 'blue', shape: 'ring', text: 'HUE->KNX', payload: knxMsgPayload.payload,
87
+ });
88
+ }
89
+ } catch (error) {
90
+ node.status({ fill: 'red', shape: 'dot', text: `HUE->KNX error ${error.message} (${new Date().getDate()}, ${new Date().toLocaleTimeString()})` });
91
+ }
92
+ };
93
+
94
+
95
+ node.sendResponseToKNX = (_level) => {
96
+ const knxMsgPayload = {};
97
+ knxMsgPayload.topic = config.GAdevice_software_update;
98
+ knxMsgPayload.dpt = config.dptdevice_software_update;
99
+
100
+ knxMsgPayload.payload = _level;
101
+ // Send to KNX bus
102
+ if (knxMsgPayload.topic !== '' && knxMsgPayload.topic !== undefined) {
103
+ node.server.writeQueueAdd({
104
+ grpaddr: knxMsgPayload.topic, payload: knxMsgPayload.payload, dpt: knxMsgPayload.dpt, outputtype: 'response', nodecallerid: node.id,
105
+ });
106
+ }
107
+ };
108
+
109
+ // On each deploy, unsubscribe+resubscribe
110
+ if (node.server) {
111
+ node.server.removeClient(node);
112
+ node.server.addClient(node);
113
+ }
114
+ if (node.serverHue) {
115
+ node.serverHue.removeClient(node);
116
+ node.serverHue.addClient(node);
117
+ }
118
+
119
+ node.on('input', (msg) => {
120
+
121
+ });
122
+
123
+ node.on('close', (done) => {
124
+ if (node.server) {
125
+ node.server.removeClient(node);
126
+ }
127
+ if (node.serverHue) {
128
+ node.serverHue.removeClient(node);
129
+ }
130
+ done();
131
+ });
132
+ }
133
+ RED.nodes.registerType('knxUltimateHuedevice_software_update', knxUltimateHuedevice_software_update);
134
+ };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "engines": {
4
4
  "node": ">=16.0.0"
5
5
  },
6
- "version": "3.0.0-beta1",
6
+ "version": "3.0.0-beta2",
7
7
  "description": "Control your KNX intallation via Node-Red! A bunch of KNX nodes, with integrated Philips HUE control and ETS group address importer. Easy to use and highly configurable.",
8
8
  "dependencies": {
9
9
  "binary-parser": "2.2.1",
@@ -47,7 +47,8 @@
47
47
  "knxUltimateHueBattery": "/nodes/knxUltimateHueBattery.js",
48
48
  "knxUltimateHueZigbeeConnectivity": "/nodes/knxUltimateHueZigbeeConnectivity.js",
49
49
  "knxUltimateContactSensor": "/nodes/knxUltimateHueContactSensor.js",
50
- "knxUltimateHATranslator": "/nodes/knxUltimateHATranslator.js"
50
+ "knxUltimateHATranslator": "/nodes/knxUltimateHATranslator.js",
51
+ "knxUltimateHuedevice_software_update": "/nodes/knxUltimateHuedevice_software_update.js"
51
52
  }
52
53
  },
53
54
  "repository": {