node-red-contrib-knx-ultimate 3.0.2 → 3.0.4
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,15 +6,23 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
-
**Version 3.0.
|
|
9
|
+
**Version 3.0.4** - August 2024<br/>
|
|
10
|
+
- Warning: Node-Red version **equals or major than 3.1.1** is needed to run this node.<br/>
|
|
11
|
+
- NEW: KNX Auto Responder node: The node will respond to read request coming from the KNX BUS, with the current GA value.<br/>
|
|
12
|
+
|
|
13
|
+
**Version 3.0.3** - July 2024<br/>
|
|
14
|
+
- Warning: Node-Red version **equals or major than 3.1.1** is needed to run this node.<br/>
|
|
15
|
+
- FIX: fix crash when no more KNX tunnels avaiable.<br/>
|
|
16
|
+
|
|
17
|
+
**Version 3.0.2** - July 2024<br/>
|
|
10
18
|
- Warning: Node-Red version **equals or major than 3.1.1** is needed to run this node.<br/>
|
|
11
19
|
- HUE BRIDGE: added the message to DEPLOY the flow prior to proceed, when you're creating a new HUE CONFIG node.<br/>
|
|
12
20
|
|
|
13
|
-
**Version 3.0.1** -
|
|
21
|
+
**Version 3.0.1** - July 2024<br/>
|
|
14
22
|
- Warning: Node-Red version **equals or major than 3.1.1** is needed to run this node.<br/>
|
|
15
23
|
- FEATURE: Due to multiple users not well knowing the KNX Protocol, by default new nodes have "Auto" in the protocol field. The node will automatically detect and apply the correct protocol. This is the real AI.<br/>
|
|
16
24
|
|
|
17
|
-
**Version 3.0.0** -
|
|
25
|
+
**Version 3.0.0** - July 2024<br/>
|
|
18
26
|
- Warning: Node-Red version **equals or major than 3.1.1** is needed to run this node.<br/>
|
|
19
27
|
- 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/>
|
|
20
28
|
- 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/>
|
package/nodes/hue-config.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
csv: { value: "", required: false },
|
|
15
15
|
KNXEthInterface: { value: "Auto" },
|
|
16
16
|
KNXEthInterfaceManuallyInput: { value: "" },
|
|
17
|
-
stopETSImportIfNoDatapoint: { value: "
|
|
17
|
+
stopETSImportIfNoDatapoint: { value: "fake" },
|
|
18
18
|
loglevel: { value: "error" },
|
|
19
19
|
name: { value: "KNX Gateway" },
|
|
20
20
|
localEchoInTunneling: { value: true },
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
<script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/htmlUtils.js"></script>
|
|
2
|
+
|
|
3
|
+
<script type="text/javascript">
|
|
4
|
+
RED.nodes.registerType('knxUltimateAutoResponder', {
|
|
5
|
+
category: "KNX Ultimate",
|
|
6
|
+
color: '#C7E9C0',
|
|
7
|
+
defaults: {
|
|
8
|
+
//buttonState: {value: true},
|
|
9
|
+
server: { type: "knxUltimate-config", required: true },
|
|
10
|
+
name: { value: "Auto responder", required: false },
|
|
11
|
+
commandText: { value: '1/1/0:true\n2/2/x:Source Radio 1\n3/0/x:100\n', required: false }
|
|
12
|
+
},
|
|
13
|
+
inputs: 0,
|
|
14
|
+
outputs: 0,
|
|
15
|
+
icon: "node-knx-icon.svg",
|
|
16
|
+
label: function () {
|
|
17
|
+
return (this.name + ' (BETA)' || "Auto Responder (BETA)");
|
|
18
|
+
},
|
|
19
|
+
paletteLabel: "Auto Responder (BETA)",
|
|
20
|
+
// button: {
|
|
21
|
+
// enabled: function() {
|
|
22
|
+
// // return whether or not the button is enabled, based on the current
|
|
23
|
+
// // configuration of the node
|
|
24
|
+
// return !this.changed
|
|
25
|
+
// },
|
|
26
|
+
// visible: function() {
|
|
27
|
+
// // return whether or not the button is visible, based on the current
|
|
28
|
+
// // configuration of the node
|
|
29
|
+
// return this.hasButton
|
|
30
|
+
// },
|
|
31
|
+
// //toggle: "buttonState",
|
|
32
|
+
// onclick: function() {}
|
|
33
|
+
// },
|
|
34
|
+
oneditprepare: function () {
|
|
35
|
+
var node = this;
|
|
36
|
+
node.editor = RED.editor.createEditor({
|
|
37
|
+
id: 'node-input-editorcommandText',
|
|
38
|
+
mode: 'ace/mode/text',
|
|
39
|
+
value: node.commandText
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
},
|
|
43
|
+
oneditsave: function () {
|
|
44
|
+
var node = this;
|
|
45
|
+
node.commandText = node.editor.getValue();
|
|
46
|
+
node.editor.destroy();
|
|
47
|
+
delete node.editor;
|
|
48
|
+
|
|
49
|
+
},
|
|
50
|
+
oneditcancel: function () {
|
|
51
|
+
var node = this;
|
|
52
|
+
node.editor.destroy();
|
|
53
|
+
delete node.editor;
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<script type="text/html" data-template-name="knxUltimateAutoResponder">
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
<div class="form-row">
|
|
63
|
+
<b>Auto Responder</b>
|
|
64
|
+
<br />
|
|
65
|
+
<label for="node-input-server">
|
|
66
|
+
<img
|
|
67
|
+
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>
|
|
68
|
+
Gateway
|
|
69
|
+
</label>
|
|
70
|
+
<input type="text" id="node-input-server" />
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<div class="form-row">
|
|
74
|
+
<label for="node-input-name" >
|
|
75
|
+
<i class="fa fa-tag"></i> Name
|
|
76
|
+
</label>
|
|
77
|
+
<input type="text" id="node-input-name" data-i18n="[placeholder]knxUltimateAutoResponder.node-input-name" />
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<div class="form-row">
|
|
81
|
+
<label style="width:300px;" for="node-input-commandText"><i class="fa fa-tasks"></i> Respond to</label>
|
|
82
|
+
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-editorcommandText"></div>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<script type="text/markdown" data-help-name="knxUltimateAutoResponder">
|
|
88
|
+
<p>This node will respond to read requests from the KNX BUS. If the group address to be read has no value yet, the node will respond with a default value.
|
|
89
|
+
|
|
90
|
+
[<i class="fa fa-code"></i> Here you'll find some samples](https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/-SamplesHome)
|
|
91
|
+
|
|
92
|
+
**Configuration**
|
|
93
|
+
|Property|Description|
|
|
94
|
+
|--|--|
|
|
95
|
+
| Gateway | Select the KNX gateway to be used |
|
|
96
|
+
| Respond to | The node will respond to group addresses specified in this list. The format is **GA:default value**. See below for further infos. |
|
|
97
|
+
|
|
98
|
+
<br/>
|
|
99
|
+
|
|
100
|
+
**Accepted formats in the 'Respond to' list**
|
|
101
|
+
You can use the *x* wildchard to specify all values from 0 to 257
|
|
102
|
+
You must specify a default value to be sent to the KNX BUS, if the group address hasn't yet any value.
|
|
103
|
+
**For example**
|
|
104
|
+
```` 1/1/0:true```` will send a telegram having the GA's 1/1/0 value. If the 1/1/0 hasn't yet a value, the node will respond with **true**
|
|
105
|
+
```` 2/1/x:false```` will send a telegram having the GA's 2/1/0..257 value If the GA hasn't yet a value, the node will respond with **false**
|
|
106
|
+
|
|
107
|
+
Please take care not to do any error, because there's yet no checks on the text's list.
|
|
108
|
+
<br/>
|
|
109
|
+
|
|
110
|
+
[DONATE HERE, THANK YOU!](https://www.paypal.me/techtoday)
|
|
111
|
+
|
|
112
|
+
</script>
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
module.exports = function (RED) {
|
|
2
|
+
// msg is:
|
|
3
|
+
// // Build final input message object
|
|
4
|
+
// return {
|
|
5
|
+
// topic: _outputtopic
|
|
6
|
+
// , payload: jsValue
|
|
7
|
+
// , devicename: (typeof _devicename !== 'undefined') ? _devicename : ""
|
|
8
|
+
// , payloadmeasureunit: sPayloadmeasureunit
|
|
9
|
+
// , payloadsubtypevalue: sPayloadsubtypevalue
|
|
10
|
+
// , knx:
|
|
11
|
+
// {
|
|
12
|
+
// event: _event
|
|
13
|
+
// , dpt: sInputDpt
|
|
14
|
+
// //, details: dpt
|
|
15
|
+
// , dptdesc: sDptdesc
|
|
16
|
+
// , source: _srcGA
|
|
17
|
+
// , destination: _destGA
|
|
18
|
+
// , rawValue: _Rawvalue
|
|
19
|
+
// }
|
|
20
|
+
// };
|
|
21
|
+
|
|
22
|
+
// The node.exposedGAs is and array of:
|
|
23
|
+
// {
|
|
24
|
+
// address,
|
|
25
|
+
// dpt,
|
|
26
|
+
// payload
|
|
27
|
+
// }
|
|
28
|
+
|
|
29
|
+
function knxUltimateAutoResponder(config) {
|
|
30
|
+
RED.nodes.createNode(this, config)
|
|
31
|
+
const node = this
|
|
32
|
+
node.server = RED.nodes.getNode(config.server)
|
|
33
|
+
node.topic = node.name
|
|
34
|
+
node.name = config.name === undefined ? 'Auto responder' : config.name
|
|
35
|
+
node.outputtopic = node.name
|
|
36
|
+
node.dpt = ''
|
|
37
|
+
node.notifyreadrequest = true
|
|
38
|
+
node.notifyresponse = true
|
|
39
|
+
node.notifywrite = true
|
|
40
|
+
node.initialread = false
|
|
41
|
+
node.listenallga = true
|
|
42
|
+
node.outputtype = 'write'
|
|
43
|
+
node.outputRBE = 'false' // Apply or not RBE to the output (Messages coming from flow)
|
|
44
|
+
node.inputRBE = 'false' // Apply or not RBE to the input (Messages coming from BUS)
|
|
45
|
+
node.exposedGAs = [];
|
|
46
|
+
node.commandText = []; // Raw list Respond To
|
|
47
|
+
node.decodedRespondToList = [];
|
|
48
|
+
|
|
49
|
+
// Used to call the status update from the config node.
|
|
50
|
+
node.setNodeStatus = ({ fill, shape, text, payload, GA, dpt, devicename }) => {
|
|
51
|
+
// try {
|
|
52
|
+
// if (node.server == null) { node.status({ fill: 'red', shape: 'dot', text: '[NO GATEWAY SELECTED]' }); return }
|
|
53
|
+
// GA = GA === undefined ? '' : GA
|
|
54
|
+
// payload = payload === undefined ? '' : payload
|
|
55
|
+
// payload = typeof payload === 'object' ? JSON.stringify(payload) : payload
|
|
56
|
+
// const dDate = new Date()
|
|
57
|
+
// node.status({ fill, shape, text: GA + ' ' + payload + ' ' + text + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ')' })
|
|
58
|
+
// } catch (error) {
|
|
59
|
+
// }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (node.server.csv === undefined || node.server.csv === '' || node.server.csv.length === 0) {
|
|
63
|
+
node.setNodeStatus({ fill: 'red', shape: '', text: 'No ETS file imported', payload: '', dpt: '', devicename: '' });
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
node.server.csv.forEach(element => {
|
|
68
|
+
node.exposedGAs.push({ address: element.ga, dpt: element.dpt, devicename: element.devicename, payload: undefined })
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
// Fill the filter list
|
|
72
|
+
try {
|
|
73
|
+
node.commandText = config.commandText.split('\n');
|
|
74
|
+
if (node.commandText === undefined || node.commandText.length === 0) {
|
|
75
|
+
node.setNodeStatus({ fill: 'red', shape: '', text: 'Respond to list must be filled', payload: '', dpt: '', devicename: '' });
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
} catch (error) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Decode the commandText list be exploding the format 2/x, 2/2/x
|
|
83
|
+
for (let index = 0; index < node.commandText.length; index++) {
|
|
84
|
+
const element = node.commandText[index];
|
|
85
|
+
let defaultVal = element.split(':')[1];
|
|
86
|
+
if (element.split(':')[0].includes('x')) {
|
|
87
|
+
for (let index = 0; index < 257; index++) {
|
|
88
|
+
let decAdd = element.split(':')[0].replace(/x/g, index)
|
|
89
|
+
node.decodedRespondToList.push({ address: decAdd, default: defaultVal })
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
node.decodedRespondToList.push({ address: element.split(':')[0], default: defaultVal })
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
// This function is called by the knx-ultimate config node, to output a msg.payload.
|
|
98
|
+
node.handleSend = msg => {
|
|
99
|
+
|
|
100
|
+
if (msg.knx !== undefined && msg.knx.event !== undefined && msg.knx.event !== "GroupValue_Read") {
|
|
101
|
+
|
|
102
|
+
// Save the value
|
|
103
|
+
try {
|
|
104
|
+
var oGa = node.exposedGAs.find(ga => ga.address === msg.knx.destination)
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.log(error)
|
|
107
|
+
}
|
|
108
|
+
if (oGa === undefined) {
|
|
109
|
+
node.exposedGAs.push({ address: msg.knx.destination, devicename: undefined, dpt: msg.knx.dpt, payload: msg.payload })
|
|
110
|
+
} else {
|
|
111
|
+
oGa.dpt = msg.knx.dpt
|
|
112
|
+
oGa.payload = msg.payload
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
|
|
116
|
+
// Send the response to the bus
|
|
117
|
+
var defaultValue; // Default value if no payload in the exposedGA list
|
|
118
|
+
var bFound = false;
|
|
119
|
+
// Can i handle the incoming message?
|
|
120
|
+
for (let index = 0; index < node.decodedRespondToList.length; index++) {
|
|
121
|
+
const element = node.decodedRespondToList[index];
|
|
122
|
+
if (msg.knx.destination === element.address) {
|
|
123
|
+
defaultValue = element.default;
|
|
124
|
+
bFound = true;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (!bFound) return;
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
let retVal;
|
|
132
|
+
let oFoundGA = node.exposedGAs.find(ga => ga.address === msg.knx.destination);
|
|
133
|
+
if (oFoundGA === undefined) return;
|
|
134
|
+
if (oFoundGA.payload === undefined) {
|
|
135
|
+
if (defaultValue === 'true') defaultValue = true;
|
|
136
|
+
if (defaultValue === 'false') defaultValue = false;
|
|
137
|
+
retVal = defaultValue;
|
|
138
|
+
} else {
|
|
139
|
+
retVal = oFoundGA.payload;
|
|
140
|
+
}
|
|
141
|
+
if (retVal !== undefined) {
|
|
142
|
+
const dDate = new Date()
|
|
143
|
+
node.status({ fill: 'blue', shape: 'dot', text: 'Respond ' + oFoundGA.address + ' => ' + retVal + ' (' + dDate.getDate() + ', ' + dDate.toLocaleTimeString() + ')' })
|
|
144
|
+
node.server.writeQueueAdd({ grpaddr: oFoundGA.address, payload: retVal, dpt: oFoundGA.dpt || '', outputtype: 'response', nodecallerid: node.id });
|
|
145
|
+
}
|
|
146
|
+
} catch (error) {
|
|
147
|
+
console.log(error)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
node.on('input', function (msg) {
|
|
153
|
+
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
node.on('close', function (done) {
|
|
157
|
+
if (node.timerExposedGAs !== null) clearTimeout(node.timerExposedGAs)
|
|
158
|
+
node.exposedGAs = []
|
|
159
|
+
if (node.server) {
|
|
160
|
+
node.server.removeClient(node)
|
|
161
|
+
}
|
|
162
|
+
done()
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
// On each deploy, unsubscribe+resubscribe
|
|
166
|
+
if (node.server) {
|
|
167
|
+
node.server.removeClient(node)
|
|
168
|
+
node.server.addClient(node)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
RED.nodes.registerType('knxUltimateAutoResponder', knxUltimateAutoResponder)
|
|
172
|
+
}
|
|
@@ -1529,6 +1529,7 @@ For controlling the "V" (brightness) of the HSV, please use the standard control
|
|
|
1529
1529
|
|
|
1530
1530
|
| Property | Description |
|
|
1531
1531
|
| ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1532
|
+
| Read status at startup | Read the HUE light status at node-red's startup or node-red's full deploy, and send that status to the KNX BUS |
|
|
1532
1533
|
| KNX Brightness Status | Updates the KNX brightness group address status, whenever the HUE lamp is switched ON/OFF. The options are **When HUE light is Off send 0%. When HUE On, restore previous value (Default KNX behaviour)** and **Leave as is (default HUE behaviour)**. If you have KNX dimmer with brightness status, like MDT, the suggested option is ***When HUE light is Off send 0%. When HUE On, restore previous value (Default KNX behaviour)*** |
|
|
1533
1534
|
| Switch on behaviour | It sets the behaviour of your lights when switched on. You can choose from differents behaviours.<br/>**Select color:** the light will be switched on with the color of your choice. To change color, just CLICK on the color selector (under the *Select color* control).<br/>**Select temperature and brightness:** the light will be switched on with the temperature (Kelvin) and brightness (0-100) of your choice.<br/>**None:** the light will retain its last status. In case you've enable the night lighting, after the night time ends, the lamp will resume the color/temperature/brightness state set at day time. |
|
|
1534
1535
|
| Night Lighting | It allows to set a particular light color/brightness at nighttime. The options are the same as the daytime. You could select either a temperature/brightness or color. A cozy temperature of 2700 Kelvin, with a brightness of 10% or 20%, is a good choice for bathroom's night light.|
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"engines": {
|
|
4
4
|
"node": ">=16.0.0"
|
|
5
5
|
},
|
|
6
|
-
"version": "3.0.
|
|
6
|
+
"version": "3.0.4",
|
|
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",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"dns-sync": "0.2.1",
|
|
12
12
|
"eventsource": "2.0.2",
|
|
13
13
|
"js-yaml": "4.1.0",
|
|
14
|
-
"knxultimate": ">=2.3.
|
|
14
|
+
"knxultimate": ">=2.3.5",
|
|
15
15
|
"lodash": "4.17.21",
|
|
16
16
|
"log-driver": "1.2.7",
|
|
17
17
|
"mkdirp": "3.0.1",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"knxUltimateAlerter": "/nodes/knxUltimateAlerter.js",
|
|
37
37
|
"knxUltimateLoadControl": "/nodes/knxUltimateLoadControl.js",
|
|
38
38
|
"knxUltimateViewer": "/nodes/knxUltimateViewer.js",
|
|
39
|
+
"knxUltimateAutoResponder": "/nodes/knxUltimateAutoResponder.js",
|
|
39
40
|
"hueConfig": "/nodes/hue-config.js",
|
|
40
41
|
"knxUltimateHueLight": "/nodes/knxUltimateHueLight.js",
|
|
41
42
|
"knxUltimateHueButton": "/nodes/knxUltimateHueButton.js",
|