node-red-contrib-knx-ultimate 4.3.2 → 4.3.5
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 +18 -0
- package/nodes/knxUltimate-config.js +105 -90
- package/nodes/knxUltimate.html +123 -5
- package/nodes/knxUltimate.js +94 -46
- package/nodes/locales/de/knxUltimate.html +4 -3
- package/nodes/locales/en/knxUltimate.html +11 -9
- package/nodes/locales/es/knxUltimate.html +9 -7
- package/nodes/locales/fr/knxUltimate.html +9 -7
- package/nodes/locales/it/knxUltimate.html +4 -3
- package/nodes/locales/zh-CN/knxUltimate.html +4 -3
- package/nodes/plugins/knxUltimateAI-vue/assets/app.js +3 -3
- package/package.json +1 -1
- package/resources/KNXSendSnippets.js +65 -49
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,24 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
**Version 4.3.5** - April 2026<br/>
|
|
10
|
+
|
|
11
|
+
- NEW: **KNX DEVICE** now supports explicit **`dpt = raw`** mode for incoming telegrams: decoding is skipped, `msg.payload` is `null`, and raw bytes remain available in `msg.knx.rawValue`.<br/>
|
|
12
|
+
- FIX: **KNX DEVICE RAW write** now accepts both **`msg.bitlength`** and legacy **`msg.bitlenght`**, with `bitlength` preferred and old flows kept backward compatible.<br/>
|
|
13
|
+
- CHANGE: **KNX DEVICE** in **`dpt = raw`** mode now accepts raw outgoing telegrams only via **`msg.writeraw`**, preventing accidental normal writes with an invalid datapoint.<br/>
|
|
14
|
+
- Docs/help/wiki: updated **KNX DEVICE** help HTML and **Device** wiki pages in all supported languages (**EN/IT/DE/FR/ES/zh-CN**) to document **raw mode** and the preferred **`bitlength`** property.<br/>
|
|
15
|
+
|
|
16
|
+
**Version 4.3.4** - April 2026<br/>
|
|
17
|
+
|
|
18
|
+
- UI: **KNX Function** editor areas now have colored backgrounds (light green for *input→bus*, light yellow for *bus→output*) for easier visual distinction.<br/>
|
|
19
|
+
- UI: **KNX Function** Monaco editor no longer shows red underlines for custom KNX functions (`getGAValue`, `setGAValue`, `toggle`, `self`).<br/>
|
|
20
|
+
- NEW: **KNX Function** : **`let val = await getGAValue(...)`** now automatically sends a `GroupValue_Read` to the KNX bus when the requested group address has no cached value yet, and waits up to 3 seconds for the device to respond before returning `null`. Use `await getGAValue(...)` in your KNX Function code to benefit from this behaviour.<br/>
|
|
21
|
+
|
|
22
|
+
**Version 4.3.3** - April 2026<br/>
|
|
23
|
+
|
|
24
|
+
- UI: in the **KNX Function helper**, the **Search GA** field is now always visible; if the ETS CSV is not imported, the field is disabled and shows `To enable the search, IMPORT THE ETS FILE`.<br/>
|
|
25
|
+
- In the KNX DEVICE NODE, added the "toggle with status" function snippet.<br/>
|
|
26
|
+
|
|
9
27
|
**Version 4.3.2** - April 2026<br/>
|
|
10
28
|
|
|
11
29
|
- Docs/help/wiki: updated **KNX AI** help HTML and wiki pages in all supported languages (EN/IT/DE/FR/ES/zh-CN) to reflect the latest LLM/Ollama UX changes.<br/>
|
|
@@ -2066,6 +2066,8 @@ module.exports = (RED) => {
|
|
|
2066
2066
|
}
|
|
2067
2067
|
}
|
|
2068
2068
|
|
|
2069
|
+
const isRawMode = typeof _inputDpt === 'string' && _inputDpt.trim().toLowerCase() === 'raw'
|
|
2070
|
+
|
|
2069
2071
|
const errorMessage = {
|
|
2070
2072
|
topic: _outputtopic,
|
|
2071
2073
|
payload: 'UNKNOWN, PLEASE IMPORT THE ETS FILE!',
|
|
@@ -2088,83 +2090,18 @@ module.exports = (RED) => {
|
|
|
2088
2090
|
|
|
2089
2091
|
// Resolve DPT and convert value if available
|
|
2090
2092
|
if (_Rawvalue !== null) {
|
|
2091
|
-
|
|
2092
|
-
sInputDpt =
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
_srcGA +
|
|
2098
|
-
' Destination ' +
|
|
2099
|
-
_destGA +
|
|
2100
|
-
' Event ' +
|
|
2101
|
-
_event +
|
|
2102
|
-
" GA's Datapoint " +
|
|
2103
|
-
(_inputDpt === null
|
|
2104
|
-
? "THE ETS FILE HAS NOT BEEN IMPORTED, SO I'M TRYING TO FIGURE OUT WHAT DATAPOINT BELONGS THIS GROUP ADDRESS. DON'T BLAME ME IF I'M WRONG, INSTEAD, IMPORT THE ETS FILE!"
|
|
2105
|
-
: _inputDpt) +
|
|
2106
|
-
' Devicename ' +
|
|
2107
|
-
_devicename +
|
|
2108
|
-
' Topic ' +
|
|
2109
|
-
_outputtopic +
|
|
2110
|
-
' ' +
|
|
2111
|
-
error.message
|
|
2112
|
-
)
|
|
2113
|
-
errorMessage.payload = 'UNKNOWN: ERROR tryToFigureOutDataPointFromRawValue:' + error.message
|
|
2114
|
-
return errorMessage
|
|
2115
|
-
}
|
|
2116
|
-
|
|
2117
|
-
try {
|
|
2118
|
-
var dpt = dptlib.resolve(sInputDpt)
|
|
2119
|
-
} catch (error) {
|
|
2120
|
-
node.sysLogger?.error(
|
|
2121
|
-
'buildInputMessage: Error returning from dptlib.resolve(sInputDpt). Device ' +
|
|
2122
|
-
_srcGA +
|
|
2123
|
-
' Destination ' +
|
|
2124
|
-
_destGA +
|
|
2125
|
-
' Event ' +
|
|
2126
|
-
_event +
|
|
2127
|
-
" GA's Datapoint " +
|
|
2128
|
-
(_inputDpt === null
|
|
2129
|
-
? "THE ETS FILE HAS NOT BEEN IMPORTED, SO I'M TRYING TO FIGURE OUT WHAT DATAPOINT BELONGS THIS GROUP ADDRESS. DON'T BLAME ME IF I'M WRONG, INSTEAD, IMPORT THE ETS FILE!"
|
|
2130
|
-
: _inputDpt) +
|
|
2131
|
-
' Devicename ' +
|
|
2132
|
-
_devicename +
|
|
2133
|
-
' Topic ' +
|
|
2134
|
-
_outputtopic +
|
|
2135
|
-
' ' +
|
|
2136
|
-
error.message
|
|
2137
|
-
)
|
|
2138
|
-
errorMessage.payload = 'UNKNOWN: ERROR dptlib.resolve:' + error.messages
|
|
2139
|
-
return errorMessage
|
|
2140
|
-
}
|
|
2141
|
-
|
|
2142
|
-
if (dpt !== null && _Rawvalue !== null) {
|
|
2093
|
+
if (isRawMode) {
|
|
2094
|
+
sInputDpt = 'raw'
|
|
2095
|
+
sPayloadmeasureunit = ''
|
|
2096
|
+
sDptdesc = 'Raw value'
|
|
2097
|
+
sPayloadsubtypevalue = ''
|
|
2098
|
+
} else {
|
|
2143
2099
|
try {
|
|
2144
|
-
|
|
2145
|
-
if (jsValue === null) {
|
|
2146
|
-
node.sysLogger?.warn(
|
|
2147
|
-
'buildInputMessage: received a wrong datagram form KNX BUS, from device ' +
|
|
2148
|
-
_srcGA +
|
|
2149
|
-
' Destination ' +
|
|
2150
|
-
_destGA +
|
|
2151
|
-
' Event ' +
|
|
2152
|
-
_event +
|
|
2153
|
-
" GA's Datapoint " +
|
|
2154
|
-
(_inputDpt === null
|
|
2155
|
-
? "THE ETS FILE HAS NOT BEEN IMPORTED, SO I'M TRYING TO FIGURE OUT WHAT DATAPOINT BELONGS THIS GROUP ADDRESS. DON'T BLAME ME IF I'M WRONG, INSTEAD, IMPORT THE ETS FILE!"
|
|
2156
|
-
: _inputDpt) +
|
|
2157
|
-
' Devicename ' +
|
|
2158
|
-
_devicename +
|
|
2159
|
-
' Topic ' +
|
|
2160
|
-
_outputtopic +
|
|
2161
|
-
' NodeID ' +
|
|
2162
|
-
_oNode.id || ''
|
|
2163
|
-
)
|
|
2164
|
-
}
|
|
2100
|
+
sInputDpt = _inputDpt === null ? tryToFigureOutDataPointFromRawValue(_Rawvalue) : _inputDpt
|
|
2165
2101
|
} catch (error) {
|
|
2102
|
+
// Here comes if no datapoint has beeen found
|
|
2166
2103
|
node.sysLogger?.error(
|
|
2167
|
-
'buildInputMessage: Error returning from
|
|
2104
|
+
'buildInputMessage: Error returning from tryToFigureOutDataPointFromRawValue. Device ' +
|
|
2168
2105
|
_srcGA +
|
|
2169
2106
|
' Destination ' +
|
|
2170
2107
|
_destGA +
|
|
@@ -2179,34 +2116,112 @@ module.exports = (RED) => {
|
|
|
2179
2116
|
' Topic ' +
|
|
2180
2117
|
_outputtopic +
|
|
2181
2118
|
' ' +
|
|
2182
|
-
error.message
|
|
2183
|
-
' NodeID ' +
|
|
2184
|
-
_oNode.id || ''
|
|
2119
|
+
error.message
|
|
2185
2120
|
)
|
|
2186
|
-
errorMessage.payload = 'UNKNOWN: ERROR
|
|
2121
|
+
errorMessage.payload = 'UNKNOWN: ERROR tryToFigureOutDataPointFromRawValue:' + error.message
|
|
2187
2122
|
return errorMessage
|
|
2188
2123
|
}
|
|
2189
|
-
}
|
|
2190
2124
|
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2125
|
+
try {
|
|
2126
|
+
var dpt = dptlib.resolve(sInputDpt)
|
|
2127
|
+
} catch (error) {
|
|
2128
|
+
node.sysLogger?.error(
|
|
2129
|
+
'buildInputMessage: Error returning from dptlib.resolve(sInputDpt). Device ' +
|
|
2130
|
+
_srcGA +
|
|
2131
|
+
' Destination ' +
|
|
2132
|
+
_destGA +
|
|
2133
|
+
' Event ' +
|
|
2134
|
+
_event +
|
|
2135
|
+
" GA's Datapoint " +
|
|
2136
|
+
(_inputDpt === null
|
|
2137
|
+
? "THE ETS FILE HAS NOT BEEN IMPORTED, SO I'M TRYING TO FIGURE OUT WHAT DATAPOINT BELONGS THIS GROUP ADDRESS. DON'T BLAME ME IF I'M WRONG, INSTEAD, IMPORT THE ETS FILE!"
|
|
2138
|
+
: _inputDpt) +
|
|
2139
|
+
' Devicename ' +
|
|
2140
|
+
_devicename +
|
|
2141
|
+
' Topic ' +
|
|
2142
|
+
_outputtopic +
|
|
2143
|
+
' ' +
|
|
2144
|
+
error.message
|
|
2145
|
+
)
|
|
2146
|
+
errorMessage.payload = 'UNKNOWN: ERROR dptlib.resolve:' + error.messages
|
|
2147
|
+
return errorMessage
|
|
2148
|
+
}
|
|
2195
2149
|
|
|
2196
|
-
|
|
2197
|
-
sPayloadmeasureunit = dpt.subtype.unit !== undefined ? dpt.subtype.unit : 'unknown'
|
|
2198
|
-
sDptdesc = dpt.subtype.desc !== undefined ? dpt.subtype.desc.charAt(0).toUpperCase() + dpt.subtype.desc.slice(1) : 'unknown'
|
|
2199
|
-
if (dpt.subtype.enc !== undefined) {
|
|
2150
|
+
if (dpt !== null && _Rawvalue !== null) {
|
|
2200
2151
|
try {
|
|
2201
|
-
|
|
2202
|
-
if (jsValue
|
|
2152
|
+
jsValue = dptlib.fromBuffer(_Rawvalue, dpt)
|
|
2153
|
+
if (jsValue === null) {
|
|
2154
|
+
node.sysLogger?.warn(
|
|
2155
|
+
'buildInputMessage: received a wrong datagram form KNX BUS, from device ' +
|
|
2156
|
+
_srcGA +
|
|
2157
|
+
' Destination ' +
|
|
2158
|
+
_destGA +
|
|
2159
|
+
' Event ' +
|
|
2160
|
+
_event +
|
|
2161
|
+
" GA's Datapoint " +
|
|
2162
|
+
(_inputDpt === null
|
|
2163
|
+
? "THE ETS FILE HAS NOT BEEN IMPORTED, SO I'M TRYING TO FIGURE OUT WHAT DATAPOINT BELONGS THIS GROUP ADDRESS. DON'T BLAME ME IF I'M WRONG, INSTEAD, IMPORT THE ETS FILE!"
|
|
2164
|
+
: _inputDpt) +
|
|
2165
|
+
' Devicename ' +
|
|
2166
|
+
_devicename +
|
|
2167
|
+
' Topic ' +
|
|
2168
|
+
_outputtopic +
|
|
2169
|
+
' NodeID ' +
|
|
2170
|
+
_oNode.id || ''
|
|
2171
|
+
)
|
|
2172
|
+
}
|
|
2203
2173
|
} catch (error) {
|
|
2204
|
-
|
|
2174
|
+
node.sysLogger?.error(
|
|
2175
|
+
'buildInputMessage: Error returning from DPT decoding. Device ' +
|
|
2176
|
+
_srcGA +
|
|
2177
|
+
' Destination ' +
|
|
2178
|
+
_destGA +
|
|
2179
|
+
' Event ' +
|
|
2180
|
+
_event +
|
|
2181
|
+
" GA's Datapoint " +
|
|
2182
|
+
(_inputDpt === null
|
|
2183
|
+
? "THE ETS FILE HAS NOT BEEN IMPORTED, SO I'M TRYING TO FIGURE OUT WHAT DATAPOINT BELONGS THIS GROUP ADDRESS. DON'T BLAME ME IF I'M WRONG, INSTEAD, IMPORT THE ETS FILE!"
|
|
2184
|
+
: _inputDpt) +
|
|
2185
|
+
' Devicename ' +
|
|
2186
|
+
_devicename +
|
|
2187
|
+
' Topic ' +
|
|
2188
|
+
_outputtopic +
|
|
2189
|
+
' ' +
|
|
2190
|
+
error.message +
|
|
2191
|
+
' NodeID ' +
|
|
2192
|
+
_oNode.id || ''
|
|
2193
|
+
)
|
|
2194
|
+
errorMessage.payload = 'UNKNOWN: ERROR dptlib.fromBuffer:' + error.stack
|
|
2195
|
+
return errorMessage
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2199
|
+
// 19/01/2023 FORMATTING THE OUTPUT PAYLOAD (ROUND, ETC) BASED ON THE NODE CONFIG
|
|
2200
|
+
//* ********************************************************
|
|
2201
|
+
jsValue = payloadRounder.Manipulate(_oNode, jsValue)
|
|
2202
|
+
//* ********************************************************
|
|
2203
|
+
|
|
2204
|
+
if (dpt.subtype !== undefined) {
|
|
2205
|
+
sPayloadmeasureunit = dpt.subtype.unit !== undefined ? dpt.subtype.unit : 'unknown'
|
|
2206
|
+
sDptdesc = dpt.subtype.desc !== undefined ? dpt.subtype.desc.charAt(0).toUpperCase() + dpt.subtype.desc.slice(1) : 'unknown'
|
|
2207
|
+
if (dpt.subtype.enc !== undefined) {
|
|
2208
|
+
try {
|
|
2209
|
+
if (!jsValue) sPayloadsubtypevalue = dpt.subtype.enc[0]
|
|
2210
|
+
if (jsValue) sPayloadsubtypevalue = dpt.subtype.enc[1]
|
|
2211
|
+
} catch (error) {
|
|
2212
|
+
// Don't care
|
|
2213
|
+
}
|
|
2205
2214
|
}
|
|
2206
2215
|
}
|
|
2207
2216
|
}
|
|
2208
2217
|
} else {
|
|
2209
2218
|
// Don't care, it's a READ REQUEST
|
|
2219
|
+
if (isRawMode) {
|
|
2220
|
+
sInputDpt = 'raw'
|
|
2221
|
+
sPayloadmeasureunit = ''
|
|
2222
|
+
sDptdesc = 'Raw value'
|
|
2223
|
+
sPayloadsubtypevalue = ''
|
|
2224
|
+
}
|
|
2210
2225
|
}
|
|
2211
2226
|
|
|
2212
2227
|
try {
|
package/nodes/knxUltimate.html
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
<!-- <script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/jquery.searchableSelect.js"></script> -->
|
|
2
2
|
|
|
3
|
+
<style>
|
|
4
|
+
/* Monaco editor - first area (input to bus): light green */
|
|
5
|
+
#sendMsgToKNXCode-editor .monaco-editor,
|
|
6
|
+
#sendMsgToKNXCode-editor .monaco-editor-background,
|
|
7
|
+
#sendMsgToKNXCode-editor .monaco-editor .margin,
|
|
8
|
+
#sendMsgToKNXCode-editor .monaco-editor .overflow-guard,
|
|
9
|
+
#sendMsgToKNXCode-editor .monaco-editor .lines-content,
|
|
10
|
+
#sendMsgToKNXCode-editor .monaco-editor .editor-scrollable {
|
|
11
|
+
background-color: #e8f5e9 !important;
|
|
12
|
+
}
|
|
13
|
+
/* Monaco editor - second area (bus to output): light yellow */
|
|
14
|
+
#receiveMsgFromKNXCode-editor .monaco-editor,
|
|
15
|
+
#receiveMsgFromKNXCode-editor .monaco-editor-background,
|
|
16
|
+
#receiveMsgFromKNXCode-editor .monaco-editor .margin,
|
|
17
|
+
#receiveMsgFromKNXCode-editor .monaco-editor .overflow-guard,
|
|
18
|
+
#receiveMsgFromKNXCode-editor .monaco-editor .lines-content,
|
|
19
|
+
#receiveMsgFromKNXCode-editor .monaco-editor .editor-scrollable {
|
|
20
|
+
background-color: #fffde7 !important;
|
|
21
|
+
}
|
|
22
|
+
</style>
|
|
3
23
|
|
|
4
24
|
<script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/htmlUtils.js"></script>
|
|
5
25
|
<script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/KNXSendSnippets.js"></script>
|
|
@@ -225,6 +245,15 @@
|
|
|
225
245
|
}
|
|
226
246
|
];
|
|
227
247
|
const globalScope = typeof window !== 'undefined' ? window : (typeof globalThis !== 'undefined' ? globalThis : {});
|
|
248
|
+
const rawDptOption = { value: 'raw', text: 'raw Raw telegram (no decode)' }
|
|
249
|
+
|
|
250
|
+
function appendRawDptOption($select) {
|
|
251
|
+
if (!$select || !$select.length) return
|
|
252
|
+
if ($select.find("option[value='raw']").length > 0) return
|
|
253
|
+
$select.prepend($("<option></option>")
|
|
254
|
+
.attr("value", rawDptOption.value)
|
|
255
|
+
.text(rawDptOption.text))
|
|
256
|
+
}
|
|
228
257
|
|
|
229
258
|
function knxUltimateDptsGetHelp(_dpt, _forceClose) {
|
|
230
259
|
const detailsContainer = $("#dptDetailsContainer")
|
|
@@ -233,6 +262,39 @@
|
|
|
233
262
|
}
|
|
234
263
|
const serverId = $("#node-input-server").val()
|
|
235
264
|
if (serverId === "_ADD_" || serverId === '' || _dpt === null || _dpt === '') return
|
|
265
|
+
if (String(_dpt).trim().toLowerCase() === 'raw') {
|
|
266
|
+
const helplinkContainer = $("#sampleCodeEditor")
|
|
267
|
+
try {
|
|
268
|
+
if (node.sampleEditor) {
|
|
269
|
+
node.sampleEditor.destroy()
|
|
270
|
+
delete node.sampleEditor
|
|
271
|
+
}
|
|
272
|
+
} catch (error) { }
|
|
273
|
+
$("#example-editor").empty()
|
|
274
|
+
helplinkContainer.empty()
|
|
275
|
+
node.sampleEditor = RED.editor.createEditor({
|
|
276
|
+
id: 'example-editor',
|
|
277
|
+
mode: 'ace/mode/javascript',
|
|
278
|
+
value: `// KNX-Ultimate set as RAW NODE
|
|
279
|
+
// Incoming telegrams skip datapoint decoding.
|
|
280
|
+
// msg.payload will be null and the raw telegram bytes are available in msg.knx.rawValue.
|
|
281
|
+
// For outgoing telegrams, use msg.writeraw = Buffer.from("0730", "hex")
|
|
282
|
+
// and optionally msg.bitlength for 1-bit / 2-bit / 4-bit datapoints.
|
|
283
|
+
return msg;`
|
|
284
|
+
})
|
|
285
|
+
try {
|
|
286
|
+
node.sampleEditor.setReadOnly(true)
|
|
287
|
+
node.sampleEditor.setShowPrintMargin(false)
|
|
288
|
+
} catch (error) { }
|
|
289
|
+
$("<div>", {
|
|
290
|
+
class: "dpt-details-link"
|
|
291
|
+
})
|
|
292
|
+
.append($("<span>").text("RAW mode keeps the telegram undecoded and exposes the bytes in "))
|
|
293
|
+
.append($("<code>").text("msg.knx.rawValue"))
|
|
294
|
+
.append($("<span>").text("."))
|
|
295
|
+
.appendTo(helplinkContainer)
|
|
296
|
+
return
|
|
297
|
+
}
|
|
236
298
|
$.getJSON("knxUltimateDptsGetHelp?dpt=" + _dpt + "&serverId=" + serverId + "&" + { _: new Date().getTime() }, (data) => {
|
|
237
299
|
const helplinkContainer = $("#sampleCodeEditor")
|
|
238
300
|
try {
|
|
@@ -336,15 +398,29 @@
|
|
|
336
398
|
}
|
|
337
399
|
if (typeof monaco !== 'undefined' && !globalScope.knxFunctionMonacoCompletionProvider) {
|
|
338
400
|
try {
|
|
339
|
-
const
|
|
401
|
+
const functionSuggestions = knxFunctionHelperItems.map(item => ({
|
|
340
402
|
label: item.label,
|
|
341
403
|
kind: monaco.languages.CompletionItemKind.Function,
|
|
342
404
|
insertText: item.snippet,
|
|
343
405
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
344
406
|
documentation: item.doc
|
|
345
407
|
}));
|
|
408
|
+
|
|
346
409
|
globalScope.knxFunctionMonacoCompletionProvider = monaco.languages.registerCompletionItemProvider('javascript', {
|
|
347
|
-
provideCompletionItems: () => ({ suggestions })
|
|
410
|
+
provideCompletionItems: () => ({ suggestions: functionSuggestions })
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
monaco.languages.typescript.javascriptDefaults.addExtraLib([
|
|
414
|
+
'/** Read the cached value of a KNX group address. */',
|
|
415
|
+
'declare function getGAValue(address: string, dpt?: string): any;',
|
|
416
|
+
'/** Send a value to a KNX group address. */',
|
|
417
|
+
'declare function setGAValue(address: string, value: any, dpt?: string): void;',
|
|
418
|
+
'/** Toggle (invert) this node\'s current value on the KNX bus. */',
|
|
419
|
+
'declare function toggle(): void;',
|
|
420
|
+
].join('\n'), 'knx-ultimate-globals.d.ts');
|
|
421
|
+
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
|
|
422
|
+
noSemanticValidation: true,
|
|
423
|
+
noSyntaxValidation: false
|
|
348
424
|
});
|
|
349
425
|
} catch (error) { }
|
|
350
426
|
}
|
|
@@ -499,6 +575,27 @@
|
|
|
499
575
|
value: node.receiveMsgFromKNXCode
|
|
500
576
|
});
|
|
501
577
|
applyEditorOptions(node.receiveMsgFromKNXCodeEditor);
|
|
578
|
+
if (typeof monaco !== 'undefined') {
|
|
579
|
+
try {
|
|
580
|
+
if (!globalScope._knxEditorThemesDefined) {
|
|
581
|
+
monaco.editor.defineTheme('knx-send-theme', {
|
|
582
|
+
base: 'vs', inherit: true, rules: [],
|
|
583
|
+
colors: { 'editor.background': '#e8f5e9', 'editorGutter.background': '#e8f5e9' }
|
|
584
|
+
});
|
|
585
|
+
monaco.editor.defineTheme('knx-receive-theme', {
|
|
586
|
+
base: 'vs', inherit: true, rules: [],
|
|
587
|
+
colors: { 'editor.background': '#fffde7', 'editorGutter.background': '#fffde7' }
|
|
588
|
+
});
|
|
589
|
+
globalScope._knxEditorThemesDefined = true;
|
|
590
|
+
}
|
|
591
|
+
if (typeof node.sendMsgToKNXCodeEditor.updateOptions === 'function') {
|
|
592
|
+
node.sendMsgToKNXCodeEditor.updateOptions({ theme: 'knx-send-theme' });
|
|
593
|
+
}
|
|
594
|
+
if (typeof node.receiveMsgFromKNXCodeEditor.updateOptions === 'function') {
|
|
595
|
+
node.receiveMsgFromKNXCodeEditor.updateOptions({ theme: 'knx-receive-theme' });
|
|
596
|
+
}
|
|
597
|
+
} catch (e) { }
|
|
598
|
+
}
|
|
502
599
|
node.activeCodeEditor = null;
|
|
503
600
|
attachFocusHandlers(node.sendMsgToKNXCodeEditor);
|
|
504
601
|
attachFocusHandlers(node.receiveMsgFromKNXCodeEditor);
|
|
@@ -516,6 +613,27 @@
|
|
|
516
613
|
insertTextIntoEditor(editor, sanitizedValue);
|
|
517
614
|
});
|
|
518
615
|
|
|
616
|
+
const $knxFunctionHelperInput = $("#node-input-knxFunctionHelperGAList");
|
|
617
|
+
const $knxFunctionHelperInsertButton = $("#btn-insert-knxFunctionGA");
|
|
618
|
+
let knxFunctionHelperDefaultPlaceholder = $knxFunctionHelperInput.attr('placeholder') || '';
|
|
619
|
+
if (!knxFunctionHelperDefaultPlaceholder) {
|
|
620
|
+
try {
|
|
621
|
+
knxFunctionHelperDefaultPlaceholder = RED._("node-red-contrib-knx-ultimate/knxUltimate:knxUltimate.placeholder.search") || '';
|
|
622
|
+
} catch (error) { }
|
|
623
|
+
}
|
|
624
|
+
const knxFunctionHelperNoEtsPlaceholder = 'To enable the search, IMPORT THE ETS FILE';
|
|
625
|
+
const refreshKnxFunctionHelperState = (hasEtsCsv) => {
|
|
626
|
+
$("#divknxFunctionHelperGAList").show();
|
|
627
|
+
$knxFunctionHelperInput.prop('disabled', !hasEtsCsv);
|
|
628
|
+
$knxFunctionHelperInsertButton.prop('disabled', !hasEtsCsv);
|
|
629
|
+
if (hasEtsCsv) {
|
|
630
|
+
$knxFunctionHelperInput.attr('placeholder', knxFunctionHelperDefaultPlaceholder);
|
|
631
|
+
} else {
|
|
632
|
+
$knxFunctionHelperInput.val('');
|
|
633
|
+
$knxFunctionHelperInput.attr('placeholder', knxFunctionHelperNoEtsPlaceholder);
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
|
|
519
637
|
const configureSnippetPicker = (snippets, inputSelector, datalistSelector, applySnippet) => {
|
|
520
638
|
const inputEl = $(inputSelector)
|
|
521
639
|
const datalistEl = $(datalistSelector)
|
|
@@ -628,15 +746,13 @@
|
|
|
628
746
|
try {
|
|
629
747
|
if (typeof oNodeServer.csv !== "undefined" && oNodeServer.csv !== "") {
|
|
630
748
|
$("#isETSFileLoaded").val("si");
|
|
631
|
-
$("#divknxFunctionHelperGAList").show();
|
|
632
749
|
} else {
|
|
633
750
|
$("#isETSFileLoaded").val("no");
|
|
634
|
-
$("#divknxFunctionHelperGAList").hide();
|
|
635
751
|
}
|
|
636
752
|
} catch (error) {
|
|
637
753
|
$("#isETSFileLoaded").val("no");
|
|
638
|
-
$("#divknxFunctionHelperGAList").hide();
|
|
639
754
|
}
|
|
755
|
+
refreshKnxFunctionHelperState($("#isETSFileLoaded").val() === "si");
|
|
640
756
|
if (oNodeServer.knxSecureSelected) {
|
|
641
757
|
$("#divknxsecure").show();
|
|
642
758
|
} else {
|
|
@@ -647,11 +763,13 @@
|
|
|
647
763
|
refreshSecureGAs();
|
|
648
764
|
$.getJSON("knxUltimateDpts?serverId=" + $("#node-input-server").val() + "&_=" + new Date().getTime(), (data) => {
|
|
649
765
|
$("#node-input-dpt").empty();
|
|
766
|
+
appendRawDptOption($("#node-input-dpt"));
|
|
650
767
|
data.forEach(dpt => {
|
|
651
768
|
$("#node-input-dpt").append($("<option></option>")
|
|
652
769
|
.attr("value", dpt.value)
|
|
653
770
|
.text(dpt.text))
|
|
654
771
|
});
|
|
772
|
+
if (node.dpt === undefined || node.dpt === '') node.dpt = '1.001'
|
|
655
773
|
$("#node-input-dpt").val(node.dpt);
|
|
656
774
|
// Load help sample
|
|
657
775
|
knxUltimateDptsGetHelp(node.dpt, true);
|