node-red-contrib-knx-ultimate 6.3.24 → 6.3.25
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 +5 -0
- package/examples/IoT Bridge - Modbus Flex Adapter.json +361 -0
- package/nodes/knxUltimate-config.js +13 -4
- package/nodes/knxUltimateIoTBridge.html +349 -20
- package/nodes/knxUltimateIoTBridge.js +474 -44
- package/nodes/locales/de/knxUltimateIoTBridge.html +28 -2
- package/nodes/locales/de/knxUltimateIoTBridge.json +20 -2
- package/nodes/locales/en/knxUltimateIoTBridge.html +28 -2
- package/nodes/locales/en/knxUltimateIoTBridge.json +20 -2
- package/nodes/locales/es/knxUltimateIoTBridge.html +28 -2
- package/nodes/locales/es/knxUltimateIoTBridge.json +20 -2
- package/nodes/locales/fr/knxUltimateIoTBridge.html +28 -2
- package/nodes/locales/fr/knxUltimateIoTBridge.json +20 -2
- package/nodes/locales/it/knxUltimateIoTBridge.html +28 -2
- package/nodes/locales/it/knxUltimateIoTBridge.json +20 -2
- package/nodes/locales/zh-CN/knxUltimateIoTBridge.html +28 -2
- package/nodes/locales/zh-CN/knxUltimateIoTBridge.json +20 -2
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
**Version 6.3.25** - August 2026<br/>
|
|
10
|
+
|
|
11
|
+
- **IoT Bridge — direct Modbus Flex adapter without a bundled Modbus client**: Modbus mappings can now emit the exact `modbus-flex-write` request consumed by `node-red-contrib-modbus` and decode `modbus-read` / `modbus-flex-getter` responses back to KNX. The protocol-specific editor asks only for Unit ID, zero-based address, Modbus area and Boolean/unsigned 16-bit/signed 16-bit format; FC1–FC6 and quantity are derived automatically. TCP/RTU connections, polling, queues and reconnects remain in the external Modbus nodes. KNX responses never become Modbus commands, write acknowledgements never become KNX state, unchanged polls can be suppressed with **Emit on change only**, and local KNX echoes are loop-protected. Existing scalar Modbus mappings remain on the legacy contract until explicitly switched to Flex. A safe manual example and the six localized help/wiki sets document the wiring and host-version compatibility.<br/>
|
|
12
|
+
- **Dependency cleanup — native asynchronous gateway DNS resolution**: replaced `dns-sync` and its obsolete `shelljs` → `glob@7` → `inflight` production chain with Node's built-in promise-based OS resolver. KNX gateway hostnames and `/etc/hosts` resolution remain supported in verbatim address order, while connection startup no longer launches a blocking child process.<br/>
|
|
13
|
+
|
|
9
14
|
**Version 6.3.24** - August 2026<br/>
|
|
10
15
|
|
|
11
16
|
- **KNX AI — working Telegram confirmation buttons**: changed the `windkh/node-red-contrib-telegrambot` preset from inline callbacks to a one-time Telegram reply keyboard. **Confirm** and **Cancel** now return as normal localized messages through the already connected `telegram receiver`, eliminating the silent no-op caused by a missing `callback_query` event node. Existing saved preset output mappings are upgraded at runtime, the keyboard is removed after the decision, and legacy callback events remain accepted. The importable direct-chat example no longer requires extra callback wiring; help and wiki documentation were updated in EN, IT, DE, FR, ES and zh-CN.<br/>
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "mb_flex_tab",
|
|
4
|
+
"type": "tab",
|
|
5
|
+
"label": "IoT Bridge - Modbus Flex Adapter",
|
|
6
|
+
"disabled": true,
|
|
7
|
+
"info": "Safe starter flow for the IoT Bridge and node-red-contrib-modbus. The tab is disabled on import and every Inject node is manual. Configure the KNX gateway, group addresses and Modbus client before enabling it."
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"id": "mb_knx_cfg",
|
|
11
|
+
"type": "knxUltimate-config",
|
|
12
|
+
"z": "",
|
|
13
|
+
"host": "224.0.23.12",
|
|
14
|
+
"port": "3671",
|
|
15
|
+
"physAddr": "15.15.215",
|
|
16
|
+
"suppressACKRequest": false,
|
|
17
|
+
"csv": "",
|
|
18
|
+
"KNXEthInterface": "Auto",
|
|
19
|
+
"KNXEthInterfaceManuallyInput": "",
|
|
20
|
+
"autoReconnect": "no"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"id": "mb_client",
|
|
24
|
+
"type": "modbus-client",
|
|
25
|
+
"name": "LOCALHOST placeholder - configure me",
|
|
26
|
+
"clienttype": "tcp",
|
|
27
|
+
"bufferCommands": true,
|
|
28
|
+
"stateLogEnabled": false,
|
|
29
|
+
"queueLogEnabled": false,
|
|
30
|
+
"failureLogEnabled": true,
|
|
31
|
+
"tcpHost": "127.0.0.1",
|
|
32
|
+
"tcpPort": "1502",
|
|
33
|
+
"tcpType": "DEFAULT",
|
|
34
|
+
"serialPort": "/dev/ttyUSB",
|
|
35
|
+
"serialType": "RTU-BUFFERD",
|
|
36
|
+
"serialBaudrate": "9600",
|
|
37
|
+
"serialDatabits": "8",
|
|
38
|
+
"serialStopbits": "1",
|
|
39
|
+
"serialParity": "none",
|
|
40
|
+
"serialConnectionDelay": "100",
|
|
41
|
+
"serialAsciiResponseStartDelimiter": "0x3A",
|
|
42
|
+
"unit_id": "1",
|
|
43
|
+
"commandDelay": "1",
|
|
44
|
+
"clientTimeout": "1000",
|
|
45
|
+
"reconnectOnTimeout": false,
|
|
46
|
+
"reconnectTimeout": "2000",
|
|
47
|
+
"parallelUnitIdsAllowed": true,
|
|
48
|
+
"showWarnings": true,
|
|
49
|
+
"showLogs": false
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"id": "mb_intro",
|
|
53
|
+
"type": "comment",
|
|
54
|
+
"z": "mb_flex_tab",
|
|
55
|
+
"name": "START HERE - disabled and manual-only",
|
|
56
|
+
"info": "1. Install a node-red-contrib-modbus version compatible with your Node-RED runtime.\n2. Configure the KNX gateway and replace the LOCALHOST Modbus client placeholder.\n3. Adapt every GA, Unit ID and zero-based address.\n4. Enable this tab only after reviewing the mappings.\n\nThere is no automatic Inject or polling in this example.",
|
|
57
|
+
"x": 300,
|
|
58
|
+
"y": 40,
|
|
59
|
+
"wires": []
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"id": "mb_address_note",
|
|
63
|
+
"type": "comment",
|
|
64
|
+
"z": "mb_flex_tab",
|
|
65
|
+
"name": "Target is zero-based: manual reference 40010 is commonly address 9",
|
|
66
|
+
"info": "Always verify the addressing convention in the device manual. The bridge supports one bit or one 16-bit register per mapping.",
|
|
67
|
+
"x": 390,
|
|
68
|
+
"y": 80,
|
|
69
|
+
"wires": []
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": "mb_bridge",
|
|
73
|
+
"type": "knxUltimateIoTBridge",
|
|
74
|
+
"z": "mb_flex_tab",
|
|
75
|
+
"server": "mb_knx_cfg",
|
|
76
|
+
"name": "KNX ↔ Modbus Flex adapter",
|
|
77
|
+
"outputtopic": "",
|
|
78
|
+
"emitOnChangeOnly": true,
|
|
79
|
+
"readOnDeploy": false,
|
|
80
|
+
"acceptFlowInput": true,
|
|
81
|
+
"nodeMode": "iot",
|
|
82
|
+
"haBusMode": "standalone",
|
|
83
|
+
"inputs": 1,
|
|
84
|
+
"outputs": 2,
|
|
85
|
+
"mappings": [
|
|
86
|
+
{
|
|
87
|
+
"id": "mb_map_coil",
|
|
88
|
+
"enabled": true,
|
|
89
|
+
"label": "Light command coil",
|
|
90
|
+
"ga": "3/1/1",
|
|
91
|
+
"dpt": "1.001",
|
|
92
|
+
"direction": "bidirectional",
|
|
93
|
+
"iotType": "modbus",
|
|
94
|
+
"target": "0",
|
|
95
|
+
"method": "POST",
|
|
96
|
+
"modbusFunction": "writeCoil",
|
|
97
|
+
"modbusMessageFormat": "flex",
|
|
98
|
+
"modbusUnitId": 1,
|
|
99
|
+
"modbusAddress": 0,
|
|
100
|
+
"modbusArea": "coil",
|
|
101
|
+
"modbusDataType": "bool",
|
|
102
|
+
"scale": 1,
|
|
103
|
+
"offset": 0,
|
|
104
|
+
"template": "",
|
|
105
|
+
"property": "",
|
|
106
|
+
"timeout": 0,
|
|
107
|
+
"retry": 0
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"id": "mb_map_temperature",
|
|
111
|
+
"enabled": true,
|
|
112
|
+
"label": "Temperature x10 holding register",
|
|
113
|
+
"ga": "3/1/2",
|
|
114
|
+
"dpt": "9.001",
|
|
115
|
+
"direction": "bidirectional",
|
|
116
|
+
"iotType": "modbus",
|
|
117
|
+
"target": "9",
|
|
118
|
+
"method": "POST",
|
|
119
|
+
"modbusFunction": "writeHoldingRegister",
|
|
120
|
+
"modbusMessageFormat": "flex",
|
|
121
|
+
"modbusUnitId": 1,
|
|
122
|
+
"modbusAddress": 9,
|
|
123
|
+
"modbusArea": "holding-register",
|
|
124
|
+
"modbusDataType": "uint16",
|
|
125
|
+
"scale": 10,
|
|
126
|
+
"offset": 0,
|
|
127
|
+
"template": "",
|
|
128
|
+
"property": "",
|
|
129
|
+
"timeout": 0,
|
|
130
|
+
"retry": 0
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"id": "mb_map_contact",
|
|
134
|
+
"enabled": true,
|
|
135
|
+
"label": "Read-only contact",
|
|
136
|
+
"ga": "3/1/3",
|
|
137
|
+
"dpt": "1.001",
|
|
138
|
+
"direction": "iot-to-knx",
|
|
139
|
+
"iotType": "modbus",
|
|
140
|
+
"target": "4",
|
|
141
|
+
"method": "POST",
|
|
142
|
+
"modbusFunction": "readDiscreteInputs",
|
|
143
|
+
"modbusMessageFormat": "flex",
|
|
144
|
+
"modbusUnitId": 1,
|
|
145
|
+
"modbusAddress": 4,
|
|
146
|
+
"modbusArea": "discrete-input",
|
|
147
|
+
"modbusDataType": "bool",
|
|
148
|
+
"scale": 1,
|
|
149
|
+
"offset": 0,
|
|
150
|
+
"template": "",
|
|
151
|
+
"property": "",
|
|
152
|
+
"timeout": 0,
|
|
153
|
+
"retry": 0
|
|
154
|
+
}
|
|
155
|
+
],
|
|
156
|
+
"x": 650,
|
|
157
|
+
"y": 260,
|
|
158
|
+
"wires": [
|
|
159
|
+
[
|
|
160
|
+
"mb_flex_write",
|
|
161
|
+
"mb_debug_flex_payload"
|
|
162
|
+
],
|
|
163
|
+
[
|
|
164
|
+
"mb_debug_knx_ack"
|
|
165
|
+
]
|
|
166
|
+
]
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"id": "mb_manual_read",
|
|
170
|
+
"type": "inject",
|
|
171
|
+
"z": "mb_flex_tab",
|
|
172
|
+
"name": "MANUAL read holding register 9",
|
|
173
|
+
"props": [
|
|
174
|
+
{
|
|
175
|
+
"p": "payload",
|
|
176
|
+
"v": "{\"fc\":3,\"unitid\":1,\"address\":9,\"quantity\":1}",
|
|
177
|
+
"vt": "json"
|
|
178
|
+
}
|
|
179
|
+
],
|
|
180
|
+
"repeat": "",
|
|
181
|
+
"crontab": "",
|
|
182
|
+
"once": false,
|
|
183
|
+
"onceDelay": 0.1,
|
|
184
|
+
"x": 230,
|
|
185
|
+
"y": 180,
|
|
186
|
+
"wires": [
|
|
187
|
+
[
|
|
188
|
+
"mb_flex_getter"
|
|
189
|
+
]
|
|
190
|
+
]
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"id": "mb_flex_getter",
|
|
194
|
+
"type": "modbus-flex-getter",
|
|
195
|
+
"z": "mb_flex_tab",
|
|
196
|
+
"name": "Flex Getter (manual request)",
|
|
197
|
+
"showStatusActivities": false,
|
|
198
|
+
"showErrors": true,
|
|
199
|
+
"showWarnings": true,
|
|
200
|
+
"logIOActivities": false,
|
|
201
|
+
"server": "mb_client",
|
|
202
|
+
"useIOFile": false,
|
|
203
|
+
"ioFile": "",
|
|
204
|
+
"useIOForPayload": false,
|
|
205
|
+
"emptyMsgOnFail": false,
|
|
206
|
+
"keepMsgProperties": true,
|
|
207
|
+
"delayOnStart": false,
|
|
208
|
+
"enableDeformedMessages": false,
|
|
209
|
+
"startDelayTime": "",
|
|
210
|
+
"x": 490,
|
|
211
|
+
"y": 180,
|
|
212
|
+
"wires": [
|
|
213
|
+
[
|
|
214
|
+
"mb_bridge",
|
|
215
|
+
"mb_debug_read"
|
|
216
|
+
],
|
|
217
|
+
[
|
|
218
|
+
"mb_debug_modbus_error"
|
|
219
|
+
]
|
|
220
|
+
]
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"id": "mb_simulated_read",
|
|
224
|
+
"type": "inject",
|
|
225
|
+
"z": "mb_flex_tab",
|
|
226
|
+
"name": "MANUAL simulate raw 215 → KNX 21.5 °C",
|
|
227
|
+
"props": [
|
|
228
|
+
{
|
|
229
|
+
"p": "payload",
|
|
230
|
+
"v": "[215]",
|
|
231
|
+
"vt": "json"
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"p": "modbusRequest",
|
|
235
|
+
"v": "{\"fc\":3,\"unitid\":1,\"address\":9,\"quantity\":1}",
|
|
236
|
+
"vt": "json"
|
|
237
|
+
}
|
|
238
|
+
],
|
|
239
|
+
"repeat": "",
|
|
240
|
+
"crontab": "",
|
|
241
|
+
"once": false,
|
|
242
|
+
"onceDelay": 0.1,
|
|
243
|
+
"x": 270,
|
|
244
|
+
"y": 300,
|
|
245
|
+
"wires": [
|
|
246
|
+
[
|
|
247
|
+
"mb_bridge"
|
|
248
|
+
]
|
|
249
|
+
]
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"id": "mb_flex_write",
|
|
253
|
+
"type": "modbus-flex-write",
|
|
254
|
+
"z": "mb_flex_tab",
|
|
255
|
+
"name": "Direct Flex Write",
|
|
256
|
+
"showStatusActivities": false,
|
|
257
|
+
"showErrors": true,
|
|
258
|
+
"showWarnings": true,
|
|
259
|
+
"logIOActivities": false,
|
|
260
|
+
"server": "mb_client",
|
|
261
|
+
"emptyMsgOnFail": false,
|
|
262
|
+
"keepMsgProperties": true,
|
|
263
|
+
"delayOnStart": false,
|
|
264
|
+
"startDelayTime": "",
|
|
265
|
+
"x": 930,
|
|
266
|
+
"y": 220,
|
|
267
|
+
"wires": [
|
|
268
|
+
[
|
|
269
|
+
"mb_debug_write"
|
|
270
|
+
],
|
|
271
|
+
[
|
|
272
|
+
"mb_debug_modbus_error"
|
|
273
|
+
]
|
|
274
|
+
]
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
"id": "mb_debug_flex_payload",
|
|
278
|
+
"type": "debug",
|
|
279
|
+
"z": "mb_flex_tab",
|
|
280
|
+
"name": "Flex payload from bridge",
|
|
281
|
+
"active": true,
|
|
282
|
+
"tosidebar": true,
|
|
283
|
+
"console": false,
|
|
284
|
+
"tostatus": false,
|
|
285
|
+
"complete": "payload",
|
|
286
|
+
"targetType": "msg",
|
|
287
|
+
"statusVal": "",
|
|
288
|
+
"statusType": "auto",
|
|
289
|
+
"x": 960,
|
|
290
|
+
"y": 280,
|
|
291
|
+
"wires": []
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
"id": "mb_debug_knx_ack",
|
|
295
|
+
"type": "debug",
|
|
296
|
+
"z": "mb_flex_tab",
|
|
297
|
+
"name": "Modbus → KNX ack",
|
|
298
|
+
"active": true,
|
|
299
|
+
"tosidebar": true,
|
|
300
|
+
"console": false,
|
|
301
|
+
"tostatus": false,
|
|
302
|
+
"complete": "true",
|
|
303
|
+
"targetType": "full",
|
|
304
|
+
"statusVal": "",
|
|
305
|
+
"statusType": "auto",
|
|
306
|
+
"x": 950,
|
|
307
|
+
"y": 340,
|
|
308
|
+
"wires": []
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
"id": "mb_debug_read",
|
|
312
|
+
"type": "debug",
|
|
313
|
+
"z": "mb_flex_tab",
|
|
314
|
+
"name": "Raw Modbus read response",
|
|
315
|
+
"active": false,
|
|
316
|
+
"tosidebar": true,
|
|
317
|
+
"console": false,
|
|
318
|
+
"tostatus": false,
|
|
319
|
+
"complete": "true",
|
|
320
|
+
"targetType": "full",
|
|
321
|
+
"statusVal": "",
|
|
322
|
+
"statusType": "auto",
|
|
323
|
+
"x": 780,
|
|
324
|
+
"y": 140,
|
|
325
|
+
"wires": []
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
"id": "mb_debug_write",
|
|
329
|
+
"type": "debug",
|
|
330
|
+
"z": "mb_flex_tab",
|
|
331
|
+
"name": "Modbus write response",
|
|
332
|
+
"active": false,
|
|
333
|
+
"tosidebar": true,
|
|
334
|
+
"console": false,
|
|
335
|
+
"tostatus": false,
|
|
336
|
+
"complete": "true",
|
|
337
|
+
"targetType": "full",
|
|
338
|
+
"statusVal": "",
|
|
339
|
+
"statusType": "auto",
|
|
340
|
+
"x": 1190,
|
|
341
|
+
"y": 200,
|
|
342
|
+
"wires": []
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
"id": "mb_debug_modbus_error",
|
|
346
|
+
"type": "debug",
|
|
347
|
+
"z": "mb_flex_tab",
|
|
348
|
+
"name": "Modbus response / error",
|
|
349
|
+
"active": true,
|
|
350
|
+
"tosidebar": true,
|
|
351
|
+
"console": false,
|
|
352
|
+
"tostatus": false,
|
|
353
|
+
"complete": "true",
|
|
354
|
+
"targetType": "full",
|
|
355
|
+
"statusVal": "",
|
|
356
|
+
"statusType": "auto",
|
|
357
|
+
"x": 1190,
|
|
358
|
+
"y": 260,
|
|
359
|
+
"wires": []
|
|
360
|
+
}
|
|
361
|
+
]
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
const fs = require('fs')
|
|
7
7
|
const path = require('path')
|
|
8
8
|
const net = require('net')
|
|
9
|
+
const dns = require('dns/promises')
|
|
9
10
|
const os = require('os')
|
|
10
11
|
const _ = require('lodash')
|
|
11
12
|
const knx = require('knxultimate')
|
|
@@ -195,6 +196,11 @@ const findAutoEthernetInterface = (targetIP) => {
|
|
|
195
196
|
return bestMatch
|
|
196
197
|
}
|
|
197
198
|
|
|
199
|
+
const resolveHostAddress = async (hostname, lookup = dns.lookup) => {
|
|
200
|
+
const { address } = await lookup(hostname, { order: 'verbatim' })
|
|
201
|
+
return address
|
|
202
|
+
}
|
|
203
|
+
|
|
198
204
|
module.exports = (RED) => {
|
|
199
205
|
// Log node and KNXUltimate engine versions once, at Node-RED startup.
|
|
200
206
|
try {
|
|
@@ -1142,7 +1148,7 @@ module.exports = (RED) => {
|
|
|
1142
1148
|
}
|
|
1143
1149
|
}
|
|
1144
1150
|
|
|
1145
|
-
node.setKnxConnectionProperties = () => {
|
|
1151
|
+
node.setKnxConnectionProperties = async () => {
|
|
1146
1152
|
// 25/08/2021 Moved out of node.initKNXConnection
|
|
1147
1153
|
node.knxConnectionProperties = {
|
|
1148
1154
|
ipAddr: node.host,
|
|
@@ -1183,10 +1189,9 @@ module.exports = (RED) => {
|
|
|
1183
1189
|
switch (net.isIP(node.host)) {
|
|
1184
1190
|
case 0:
|
|
1185
1191
|
// Invalid IP, resolve the DNS name.
|
|
1186
|
-
const dns = require('dns-sync')
|
|
1187
1192
|
let resolvedIP = null
|
|
1188
1193
|
try {
|
|
1189
|
-
resolvedIP =
|
|
1194
|
+
resolvedIP = await resolveHostAddress(node.host)
|
|
1190
1195
|
} catch (error) {
|
|
1191
1196
|
throw new Error('net.isIP: INVALID IP OR DNS NAME. Error checking the Gateway Host in Config node. ' + error.message)
|
|
1192
1197
|
}
|
|
@@ -1258,7 +1263,7 @@ module.exports = (RED) => {
|
|
|
1258
1263
|
|
|
1259
1264
|
node.initKNXConnection = async () => {
|
|
1260
1265
|
try {
|
|
1261
|
-
node.setKnxConnectionProperties() // 28/12/2021 Added
|
|
1266
|
+
await node.setKnxConnectionProperties() // 28/12/2021 Added
|
|
1262
1267
|
} catch (error) {
|
|
1263
1268
|
node.sysLogger?.error('setKnxConnectionProperties: ' + error.message)
|
|
1264
1269
|
if (node.linkStatus !== 'disconnected') await node.Disconnect()
|
|
@@ -2764,3 +2769,7 @@ module.exports = (RED) => {
|
|
|
2764
2769
|
}
|
|
2765
2770
|
})
|
|
2766
2771
|
}
|
|
2772
|
+
|
|
2773
|
+
module.exports.__test = {
|
|
2774
|
+
resolveHostAddress
|
|
2775
|
+
}
|