node-red-contrib-knx-ultimate 6.0.10 → 6.0.12
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 +10 -0
- package/nodes/knxUltimateHueLight.html +1 -5
- package/nodes/knxUltimateMatterBridge.html +67 -2
- package/nodes/knxUltimateMatterControllerDevice.html +329 -44
- package/nodes/locales/de/knxUltimateMatterBridge.html +0 -2
- package/nodes/locales/de/knxUltimateMatterControllerDevice.html +10 -2
- package/nodes/locales/de/knxUltimateMatterControllerDevice.json +17 -1
- package/nodes/locales/en/knxUltimateMatterBridge.html +0 -2
- package/nodes/locales/en/knxUltimateMatterControllerDevice.html +10 -2
- package/nodes/locales/en/knxUltimateMatterControllerDevice.json +17 -1
- package/nodes/locales/es/knxUltimateMatterBridge.html +0 -2
- package/nodes/locales/es/knxUltimateMatterControllerDevice.html +10 -2
- package/nodes/locales/es/knxUltimateMatterControllerDevice.json +17 -1
- package/nodes/locales/fr/knxUltimateMatterBridge.html +0 -2
- package/nodes/locales/fr/knxUltimateMatterControllerDevice.html +10 -2
- package/nodes/locales/fr/knxUltimateMatterControllerDevice.json +17 -1
- package/nodes/locales/it/knxUltimateMatterBridge.html +0 -2
- package/nodes/locales/it/knxUltimateMatterControllerDevice.html +10 -2
- package/nodes/locales/it/knxUltimateMatterControllerDevice.json +17 -1
- package/nodes/locales/zh-CN/knxUltimateMatterBridge.html +0 -2
- package/nodes/locales/zh-CN/knxUltimateMatterControllerDevice.html +10 -2
- package/nodes/locales/zh-CN/knxUltimateMatterControllerDevice.json +17 -1
- package/nodes/matter-config.js +5 -4
- package/nodes/utils/matterControllerProfiles/doorLock.js +19 -2
- package/nodes/utils/matterControllerProfiles/fan.js +20 -0
- package/nodes/utils/matterControllerProfiles/index.js +11 -1
- package/nodes/utils/matterControllerProfiles/mappedEndpoint.js +53 -15
- package/nodes/utils/matterControllerProfiles/switch.js +14 -0
- package/nodes/utils/matterControllerProfiles/thermostat.js +20 -0
- package/nodes/utils/matterControllerProfiles/universal.js +462 -0
- package/nodes/utils/matterControllerProfiles/windowCovering.js +20 -0
- package/nodes/utils/matterEngine.mjs +12 -3
- package/package.json +3 -3
|
@@ -14,6 +14,16 @@
|
|
|
14
14
|
//buttonState: {value: true},
|
|
15
15
|
server: { type: "knxUltimate-config", required: false },
|
|
16
16
|
serverMatter: { type: "matter-config", required: true },
|
|
17
|
+
matterControllerMode: { value: "single" },
|
|
18
|
+
universalService: { value: "batteryMonitor" },
|
|
19
|
+
universalBatteryThreshold: { value: 20, validate: RED.validators.number() },
|
|
20
|
+
universalLowBatteryGA: { value: "" },
|
|
21
|
+
universalLowBatteryGAName: { value: "" },
|
|
22
|
+
universalLowBatteryTextGA: { value: "" },
|
|
23
|
+
universalLowBatteryTextGAName: { value: "" },
|
|
24
|
+
universalBatteryOnlyLow: { value: true },
|
|
25
|
+
universalEmitInitialState: { value: true },
|
|
26
|
+
universalIncludeRawEvent: { value: true },
|
|
17
27
|
matterNodeId: { value: "" },
|
|
18
28
|
matterEndpointId: { value: 1 },
|
|
19
29
|
matterDeviceName: { value: "" },
|
|
@@ -221,6 +231,8 @@
|
|
|
221
231
|
const KNX_EMPTY_VALUES = new Set(['', 'none', '_ADD_', '__NONE__']);
|
|
222
232
|
// Historical variable names are retained for saved-flow compatibility; they point to Matter widgets.
|
|
223
233
|
const $hueServerInput = $("#node-input-serverMatter");
|
|
234
|
+
const $matterControllerModeInput = $("#node-input-matterControllerMode");
|
|
235
|
+
const $universalServiceInput = $("#node-input-universalService");
|
|
224
236
|
const $hueDeviceInput = $("#node-input-matterNodeId");
|
|
225
237
|
const $deviceNameInput = $("#node-input-matterDeviceName");
|
|
226
238
|
const $matterEndpointInput = $("#node-input-matterEndpointId");
|
|
@@ -229,6 +241,9 @@
|
|
|
229
241
|
const $refreshDevicesButton = $(".hue-refresh-devices");
|
|
230
242
|
const $locateDeviceButton = $(".hue-locate-device");
|
|
231
243
|
const $hueDevicesLoading = $(".hue-devices-loading");
|
|
244
|
+
const UNIVERSAL_NODE_ID = '__UNIVERSAL__';
|
|
245
|
+
const isUniversalMode = () => $matterControllerModeInput.val() === 'universal';
|
|
246
|
+
$matterControllerModeInput.val(node.matterControllerMode || 'single');
|
|
232
247
|
let cachedHueDevices = Array.isArray(node._cachedHueLightDevices) ? node._cachedHueLightDevices : [];
|
|
233
248
|
node._cachedHueLightDevices = cachedHueDevices;
|
|
234
249
|
const defaultHueDevicePlaceholder = $deviceNameInput.attr('placeholder') || '';
|
|
@@ -289,7 +304,10 @@
|
|
|
289
304
|
const title = locateSessionActive
|
|
290
305
|
? (node._('knxUltimateMatterControllerDevice.locate_stop_title') || 'Stop Matter locate')
|
|
291
306
|
: (node._('knxUltimateMatterControllerDevice.locate_start_title') || 'Locate selected Matter device');
|
|
292
|
-
$locateDeviceButton.attr('title',
|
|
307
|
+
$locateDeviceButton.attr('title', isUniversalMode()
|
|
308
|
+
? (node._('knxUltimateMatterControllerDevice.universal_mode_locate_disabled') || 'Locate is unavailable in Universal Mode.')
|
|
309
|
+
: title);
|
|
310
|
+
$locateDeviceButton.prop('disabled', isUniversalMode());
|
|
293
311
|
};
|
|
294
312
|
|
|
295
313
|
const removeNodeRemovalListener = () => {
|
|
@@ -340,6 +358,10 @@
|
|
|
340
358
|
};
|
|
341
359
|
|
|
342
360
|
const performLocateRequest = ({ silent = false, allowStoredContext = false, action } = {}) => {
|
|
361
|
+
if (isUniversalMode()) {
|
|
362
|
+
if (!silent) RED.notify(node._('knxUltimateMatterControllerDevice.universal_mode_locate_disabled') || 'Locate is unavailable in Universal Mode.', 'warning');
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
343
365
|
const context = buildLocateContext({ allowStored: allowStoredContext });
|
|
344
366
|
if (!context) {
|
|
345
367
|
if (!silent) {
|
|
@@ -419,7 +441,7 @@
|
|
|
419
441
|
}).always(() => {
|
|
420
442
|
locatePendingRequest = null;
|
|
421
443
|
if ($locateDeviceButton.length) {
|
|
422
|
-
$locateDeviceButton.prop('disabled',
|
|
444
|
+
$locateDeviceButton.prop('disabled', isUniversalMode());
|
|
423
445
|
}
|
|
424
446
|
});
|
|
425
447
|
return request;
|
|
@@ -554,6 +576,11 @@
|
|
|
554
576
|
}
|
|
555
577
|
const isMatterLight = deviceTypes.some((type) => /(?:onoff|dimmable|colortemperature|extendedcolor)light/.test(type));
|
|
556
578
|
if (!isMatterLight) {
|
|
579
|
+
const specializedProfile = getMatterCluster(ep, 258) ? 'windowCovering'
|
|
580
|
+
: getMatterCluster(ep, 513) ? 'thermostat'
|
|
581
|
+
: getMatterCluster(ep, 514) ? 'fan'
|
|
582
|
+
: getMatterCluster(ep, 59) ? 'switch'
|
|
583
|
+
: 'mapped';
|
|
557
584
|
const mappedTargets = [];
|
|
558
585
|
const addCommand = (clusterId, target, label, dpt) => {
|
|
559
586
|
const cluster = getMatterCluster(ep, clusterId);
|
|
@@ -584,47 +611,79 @@
|
|
|
584
611
|
addAttribute(47, 'batPercentRemaining', 'battery', '5.001', false);
|
|
585
612
|
addAttribute(144, 'activePower', 'active_power', '14.056', false);
|
|
586
613
|
addAttribute(145, 'cumulativeEnergyImported', 'imported_energy', '13.013', false);
|
|
587
|
-
return { known: true, profile:
|
|
614
|
+
return { known: true, profile: specializedProfile, deviceTypeDisplay, onOff: false, level: false, colorTemperature: false, color: false, mappedTargets };
|
|
588
615
|
}
|
|
589
616
|
const hasColorTemperatureType = /colortemperature|extendedcolor/.test(typeText);
|
|
590
617
|
const hasColorType = /extendedcolor/.test(typeText);
|
|
618
|
+
const isTunableWhiteOnly = hasColorTemperatureType && !hasColorType;
|
|
591
619
|
const hasLevelType = /dimmable|colortemperature|extendedcolor/.test(typeText);
|
|
620
|
+
const colorFeatureMapAttribute = (colorCluster?.attributes || []).find((attribute) => normalizeMatterToken(attribute.name) === 'featuremap');
|
|
621
|
+
const colorFeatureMap = Number(colorFeatureMapAttribute?.value);
|
|
622
|
+
const hasColorFeatureMap = Number.isFinite(colorFeatureMap);
|
|
592
623
|
const hasColorTemperature = !!colorCluster && (
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
624
|
+
hasColorFeatureMap
|
|
625
|
+
? (colorFeatureMap & 0x10) !== 0
|
|
626
|
+
: (
|
|
627
|
+
hasColorTemperatureType ||
|
|
628
|
+
hasMatterAttribute(colorCluster, ['colorTemperatureMireds', 'colorTempPhysicalMinMireds', 'colorTempPhysicalMaxMireds']) ||
|
|
629
|
+
hasMatterCommand(colorCluster, ['moveToColorTemperature'])
|
|
630
|
+
)
|
|
596
631
|
);
|
|
597
632
|
const hasColor = !!colorCluster && (
|
|
598
|
-
|
|
599
|
-
|
|
633
|
+
!isTunableWhiteOnly && (
|
|
634
|
+
hasColorFeatureMap
|
|
635
|
+
? (colorFeatureMap & 0x09) !== 0
|
|
636
|
+
: (
|
|
637
|
+
hasColorType ||
|
|
638
|
+
hasMatterCommand(colorCluster, ['moveToColor', 'moveToHue', 'moveToSaturation', 'moveToHueAndSaturation'])
|
|
639
|
+
)
|
|
640
|
+
)
|
|
600
641
|
);
|
|
601
642
|
return {
|
|
602
643
|
known: true,
|
|
603
644
|
deviceTypeDisplay,
|
|
604
|
-
|
|
645
|
+
matterLightType: isTunableWhiteOnly ? 'colorTemperature' : (hasColorType ? 'extendedColor' : 'other'),
|
|
646
|
+
colorDetectionVersion: 3,
|
|
605
647
|
onOff: !!onOffCluster || /onoff|dimmable|colortemperature|extendedcolor/.test(typeText),
|
|
606
648
|
level: !!levelCluster || hasLevelType,
|
|
607
649
|
colorTemperature: hasColorTemperature,
|
|
608
650
|
color: hasColor
|
|
609
651
|
};
|
|
610
652
|
};
|
|
653
|
+
const normalizeMatterCapabilities = (capabilities) => {
|
|
654
|
+
if (!capabilities || typeof capabilities !== 'object') return capabilities;
|
|
655
|
+
const normalized = Object.assign({}, capabilities);
|
|
656
|
+
const displayType = normalizeMatterToken(normalized.deviceTypeDisplay);
|
|
657
|
+
const tunableWhiteOnly = normalized.matterLightType === 'colorTemperature' ||
|
|
658
|
+
displayType === 'tunablewhite' ||
|
|
659
|
+
displayType === 'colortemperaturelight';
|
|
660
|
+
if (tunableWhiteOnly) {
|
|
661
|
+
normalized.colorTemperature = true;
|
|
662
|
+
normalized.color = false;
|
|
663
|
+
normalized.colorDetectionVersion = 3;
|
|
664
|
+
} else if (normalized.known === true && normalized.color === true &&
|
|
665
|
+
normalized.colorDetectionVersion !== 2 && normalized.colorDetectionVersion !== 3) {
|
|
666
|
+
normalized.color = false;
|
|
667
|
+
}
|
|
668
|
+
return normalized;
|
|
669
|
+
};
|
|
611
670
|
const parseMatterCapabilities = (raw) => {
|
|
612
671
|
if (raw && typeof raw === 'object') {
|
|
613
|
-
|
|
614
|
-
return raw;
|
|
672
|
+
return normalizeMatterCapabilities(raw);
|
|
615
673
|
}
|
|
616
674
|
if (typeof raw !== 'string' || raw.trim() === '') return null;
|
|
617
675
|
try {
|
|
618
|
-
|
|
619
|
-
if (parsed && parsed.known === true && parsed.color === true && parsed.colorDetectionVersion !== 2) {
|
|
620
|
-
parsed.color = false;
|
|
621
|
-
}
|
|
622
|
-
return parsed;
|
|
676
|
+
return normalizeMatterCapabilities(JSON.parse(raw));
|
|
623
677
|
} catch (error) {
|
|
624
678
|
return null;
|
|
625
679
|
}
|
|
626
680
|
};
|
|
627
681
|
const serializeMatterCapabilities = (capabilities) => JSON.stringify(capabilities || {});
|
|
682
|
+
const universalMatterCapabilities = () => ({
|
|
683
|
+
known: true,
|
|
684
|
+
profile: 'universal',
|
|
685
|
+
deviceTypeDisplay: node._('knxUltimateMatterControllerDevice.universal_mode') || 'Universal Mode'
|
|
686
|
+
});
|
|
628
687
|
const getJSONPromise = (url) => new Promise((resolve, reject) => { $.getJSON(url, resolve).fail(reject); });
|
|
629
688
|
|
|
630
689
|
// Filters Matter items shaped as { value, matterNodeId, matterEndpointId }.
|
|
@@ -737,13 +796,22 @@
|
|
|
737
796
|
|
|
738
797
|
|
|
739
798
|
const $tabs = $("#tabs");
|
|
799
|
+
const $universalTabs = $("#matter-universal-tabs");
|
|
740
800
|
const $pinSectionRow = $("#node-input-enableNodePINS").closest('.form-row');
|
|
741
801
|
const $pinSelect = $("#node-input-enableNodePINS");
|
|
742
802
|
let currentMatterCapabilities = parseMatterCapabilities($matterCapabilitiesInput.val() || node.matterDeviceCapabilities);
|
|
803
|
+
if (currentMatterCapabilities) {
|
|
804
|
+
$matterCapabilitiesInput.val(serializeMatterCapabilities(currentMatterCapabilities));
|
|
805
|
+
node.matterDeviceCapabilities = $matterCapabilitiesInput.val();
|
|
806
|
+
}
|
|
743
807
|
$tabs.addClass('hue-vertical-tabs');
|
|
744
808
|
$tabs.tabs(); // Tabs gestione KNX
|
|
745
809
|
$tabs.find('ul').addClass('ui-tabs-nav');
|
|
746
810
|
$tabs.find('li').removeClass('ui-corner-top').addClass('ui-corner-left');
|
|
811
|
+
$universalTabs.addClass('hue-vertical-tabs');
|
|
812
|
+
$universalTabs.tabs();
|
|
813
|
+
$universalTabs.find('ul').addClass('ui-tabs-nav');
|
|
814
|
+
$universalTabs.find('li').removeClass('ui-corner-top').addClass('ui-corner-left');
|
|
747
815
|
|
|
748
816
|
function getDPT(_dpt, _destinationWidget) {
|
|
749
817
|
// DPT Switch command
|
|
@@ -830,7 +898,49 @@
|
|
|
830
898
|
} catch (e) { }
|
|
831
899
|
}
|
|
832
900
|
|
|
901
|
+
function getFixedDptGroupAddress(_sourceWidgetAutocomplete, _destinationWidgetName, _dptPrefix) {
|
|
902
|
+
const $source = $(_sourceWidgetAutocomplete);
|
|
903
|
+
if ($source.data('ui-autocomplete')) {
|
|
904
|
+
try { $source.autocomplete('destroy'); } catch (error) { /* empty */ }
|
|
905
|
+
}
|
|
906
|
+
$source.autocomplete({
|
|
907
|
+
minLength: 0,
|
|
908
|
+
source: function (request, response) {
|
|
909
|
+
if (!hasKnxServerSelected()) {
|
|
910
|
+
response([]);
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
const serverId = resolveKnxServerValue();
|
|
914
|
+
$.getJSON(`knxUltimatecsv?nodeID=${serverId}&_=${Date.now()}`, (data) => {
|
|
915
|
+
response($.map(data, function (value) {
|
|
916
|
+
const searchable = `${value.ga} (${value.devicename}) DPT${value.dpt}`;
|
|
917
|
+
if (!htmlUtilsfullCSVSearch(searchable, `${request.term || ''} ${_dptPrefix}`)) return null;
|
|
918
|
+
return {
|
|
919
|
+
label: `${value.ga} # ${value.devicename} # ${value.dpt}`,
|
|
920
|
+
value: value.ga,
|
|
921
|
+
deviceName: value.devicename
|
|
922
|
+
};
|
|
923
|
+
}));
|
|
924
|
+
});
|
|
925
|
+
},
|
|
926
|
+
select: function (event, ui) {
|
|
927
|
+
$(_destinationWidgetName).val(ui.item.deviceName || '');
|
|
928
|
+
}
|
|
929
|
+
}).focus(function () {
|
|
930
|
+
$(this).autocomplete('search', `${$(this).val()}exactmatch`);
|
|
931
|
+
});
|
|
932
|
+
try {
|
|
933
|
+
if (hasKnxServerSelected()) {
|
|
934
|
+
const srv = RED.nodes.node(resolveKnxServerValue());
|
|
935
|
+
if (srv && srv.id) KNX_enableSecureFormatting($source, srv.id);
|
|
936
|
+
}
|
|
937
|
+
} catch (error) { /* empty */ }
|
|
938
|
+
}
|
|
939
|
+
|
|
833
940
|
const refreshKnxBindings = () => {
|
|
941
|
+
getFixedDptGroupAddress("#node-input-universalLowBatteryGA", "#node-input-universalLowBatteryGAName", "1.");
|
|
942
|
+
getFixedDptGroupAddress("#node-input-universalLowBatteryTextGA", "#node-input-universalLowBatteryTextGAName", "16.");
|
|
943
|
+
|
|
834
944
|
getDPT("1.", "#node-input-dptLightSwitch");
|
|
835
945
|
getGroupAddress("#node-input-GALightSwitch", "#node-input-nameLightSwitch", "#node-input-dptLightSwitch", ["1."]);
|
|
836
946
|
|
|
@@ -986,7 +1096,7 @@
|
|
|
986
1096
|
};
|
|
987
1097
|
|
|
988
1098
|
const applyMatterCapabilities = (capabilities) => {
|
|
989
|
-
currentMatterCapabilities = capabilities || null;
|
|
1099
|
+
currentMatterCapabilities = normalizeMatterCapabilities(capabilities) || null;
|
|
990
1100
|
const caps = getEffectiveMatterCapabilities();
|
|
991
1101
|
const hasHueDevice = getHueDeviceValue() !== '';
|
|
992
1102
|
const supportsSwitch = hasHueDevice && caps.onOff !== false;
|
|
@@ -995,15 +1105,19 @@
|
|
|
995
1105
|
const supportsColor = hasHueDevice && caps.color === true;
|
|
996
1106
|
const hasRichBehaviour = supportsDim && (supportsTemperature || supportsColor);
|
|
997
1107
|
const isDoorLock = caps.profile === 'doorLock';
|
|
998
|
-
const isMapped =
|
|
1108
|
+
const isMapped = ['mapped', 'windowCovering', 'thermostat', 'fan', 'switch'].includes(caps.profile);
|
|
1109
|
+
const isUniversal = caps.profile === 'universal' || isUniversalMode();
|
|
999
1110
|
const deviceTypeDisplay = String(caps.deviceTypeDisplay || '').trim();
|
|
1000
1111
|
|
|
1001
|
-
setMatterTabVisible('tabs-1', supportsSwitch);
|
|
1002
|
-
setMatterTabVisible('tabs-2', supportsDim);
|
|
1003
|
-
setMatterTabVisible('tabs-3', supportsTemperature);
|
|
1004
|
-
setMatterTabVisible('tabs-4', supportsColor);
|
|
1005
|
-
setMatterTabVisible('tabs-mapped', isMapped);
|
|
1006
|
-
setMatterTabVisible('tabs-6', hasHueDevice);
|
|
1112
|
+
setMatterTabVisible('tabs-1', !isUniversal && supportsSwitch);
|
|
1113
|
+
setMatterTabVisible('tabs-2', !isUniversal && supportsDim);
|
|
1114
|
+
setMatterTabVisible('tabs-3', !isUniversal && supportsTemperature);
|
|
1115
|
+
setMatterTabVisible('tabs-4', !isUniversal && supportsColor);
|
|
1116
|
+
setMatterTabVisible('tabs-mapped', !isUniversal && isMapped);
|
|
1117
|
+
setMatterTabVisible('tabs-6', !isUniversal && hasHueDevice);
|
|
1118
|
+
$('#matter-universal-description').toggle(isUniversal);
|
|
1119
|
+
$pinSelect.val(isUniversal ? 'yes' : $pinSelect.val()).prop('disabled', isUniversal);
|
|
1120
|
+
updateLocateButtonState(false);
|
|
1007
1121
|
$('#matter-door-lock-options').toggle(isDoorLock);
|
|
1008
1122
|
$('#matter-switch-command-label').text(isDoorLock
|
|
1009
1123
|
? (node._('knxUltimateMatterControllerDevice.door_lock_command') || 'Lock / unlock')
|
|
@@ -1074,7 +1188,7 @@
|
|
|
1074
1188
|
const updateTabsVisibility = () => {
|
|
1075
1189
|
const knxSelected = hasKnxServerSelected();
|
|
1076
1190
|
const hueDeviceSelected = getHueDeviceValue() !== '';
|
|
1077
|
-
const shouldShowTabs = knxSelected && hueDeviceSelected;
|
|
1191
|
+
const shouldShowTabs = !isUniversalMode() && knxSelected && hueDeviceSelected;
|
|
1078
1192
|
|
|
1079
1193
|
if (shouldShowTabs) {
|
|
1080
1194
|
$tabs.show();
|
|
@@ -1088,7 +1202,47 @@
|
|
|
1088
1202
|
$pinSectionRow.show();
|
|
1089
1203
|
}
|
|
1090
1204
|
};
|
|
1205
|
+
|
|
1206
|
+
const refreshUniversalServiceVisibility = () => {
|
|
1207
|
+
const universal = $matterControllerModeInput.val() === 'universal';
|
|
1208
|
+
$('#matter-universal-options').toggle(universal);
|
|
1209
|
+
$universalTabs.toggle(universal && $universalServiceInput.val() === 'batteryMonitor');
|
|
1210
|
+
if ($universalTabs.is(':visible')) {
|
|
1211
|
+
try { $universalTabs.tabs('refresh'); } catch (error) { /* empty */ }
|
|
1212
|
+
}
|
|
1213
|
+
};
|
|
1214
|
+
|
|
1215
|
+
const applyControllerMode = () => {
|
|
1216
|
+
const universal = $matterControllerModeInput.val() === 'universal';
|
|
1217
|
+
$('#matter-device-section-title, #matter-device-row').toggle(!universal);
|
|
1218
|
+
if (universal) {
|
|
1219
|
+
const universalName = node._('knxUltimateMatterControllerDevice.universal_mode') || 'Universal Mode';
|
|
1220
|
+
currentMatterCapabilities = universalMatterCapabilities();
|
|
1221
|
+
selectedMatterDeviceName = universalName;
|
|
1222
|
+
$deviceNameInput.val(universalName);
|
|
1223
|
+
$hueDeviceInput.val(UNIVERSAL_NODE_ID);
|
|
1224
|
+
$matterEndpointInput.val('');
|
|
1225
|
+
$matterCapabilitiesInput.val(serializeMatterCapabilities(currentMatterCapabilities));
|
|
1226
|
+
$nodeNameInput.val(node._('knxUltimateMatterControllerDevice.universal_controller_name') || 'Matter Universal Controller');
|
|
1227
|
+
$pinSelect.val('yes');
|
|
1228
|
+
} else if (String($hueDeviceInput.val() || '') === UNIVERSAL_NODE_ID) {
|
|
1229
|
+
currentMatterCapabilities = null;
|
|
1230
|
+
selectedMatterDeviceName = '';
|
|
1231
|
+
$deviceNameInput.val('');
|
|
1232
|
+
$hueDeviceInput.val('');
|
|
1233
|
+
$matterEndpointInput.val('');
|
|
1234
|
+
$matterCapabilitiesInput.val('');
|
|
1235
|
+
}
|
|
1236
|
+
refreshUniversalServiceVisibility();
|
|
1237
|
+
applyMatterCapabilities(currentMatterCapabilities);
|
|
1238
|
+
updateTabsVisibility();
|
|
1239
|
+
};
|
|
1240
|
+
|
|
1091
1241
|
updateTabsVisibility();
|
|
1242
|
+
applyControllerMode();
|
|
1243
|
+
|
|
1244
|
+
$matterControllerModeInput.on('change.knxUltimateMatterControllerDevice', applyControllerMode);
|
|
1245
|
+
$universalServiceInput.on('change.knxUltimateMatterControllerDevice', refreshUniversalServiceVisibility);
|
|
1092
1246
|
|
|
1093
1247
|
$knxServerInput.on('change.knxUltimateMatterControllerDevice', () => {
|
|
1094
1248
|
refreshKnxBindings();
|
|
@@ -1412,9 +1566,12 @@
|
|
|
1412
1566
|
} catch (error) { }
|
|
1413
1567
|
|
|
1414
1568
|
//RED.sidebar.removeTab("tabNRColor");
|
|
1415
|
-
|
|
1569
|
+
const universalMode = $("#node-input-matterControllerMode").val() === 'universal';
|
|
1570
|
+
this.matterControllerMode = universalMode ? 'universal' : 'single';
|
|
1571
|
+
if (universalMode || $("#node-input-enableNodePINS").val() === "yes") {
|
|
1416
1572
|
this.outputs = 1;
|
|
1417
1573
|
this.inputs = 1;
|
|
1574
|
+
this.enableNodePINS = 'yes';
|
|
1418
1575
|
} else {
|
|
1419
1576
|
this.outputs = 0;
|
|
1420
1577
|
this.inputs = 0;
|
|
@@ -1423,7 +1580,7 @@
|
|
|
1423
1580
|
this.updateLocalStateFromKNXWrite = $("#node-input-updateLocalStateFromKNXWrite").is(":checked"); // Starting from v 4.1.31
|
|
1424
1581
|
this.matterDeviceName = ($("#node-input-matterDeviceName").val() || '').trim();
|
|
1425
1582
|
this.matterNodeId = ($("#node-input-matterNodeId").val() || '').trim();
|
|
1426
|
-
this.matterEndpointId = Number($("#node-input-matterEndpointId").val() || 1);
|
|
1583
|
+
this.matterEndpointId = universalMode ? '' : Number($("#node-input-matterEndpointId").val() || 1);
|
|
1427
1584
|
this.matterDeviceCapabilities = ($("#node-input-matterDeviceCapabilities").val() || '').trim();
|
|
1428
1585
|
const mappedMappings = [];
|
|
1429
1586
|
const $mappedRows = $('#matter-mapped-profile-body .matter-mapped-row');
|
|
@@ -1439,7 +1596,9 @@
|
|
|
1439
1596
|
? JSON.stringify(mappedMappings)
|
|
1440
1597
|
: ($('#node-input-matterMappings').val() || this.matterMappings || '[]');
|
|
1441
1598
|
$('#node-input-matterMappings').val(this.matterMappings);
|
|
1442
|
-
this.name =
|
|
1599
|
+
this.name = universalMode
|
|
1600
|
+
? ($("#node-input-name").val() || this._('knxUltimateMatterControllerDevice.universal_controller_name') || 'Matter Universal Controller')
|
|
1601
|
+
: (this.matterDeviceName || this.name || '');
|
|
1443
1602
|
$("#node-input-name").val(this.name);
|
|
1444
1603
|
const parseSavedMatterCapabilities = (raw) => {
|
|
1445
1604
|
if (typeof raw !== 'string' || raw.trim() === '') return null;
|
|
@@ -1626,10 +1785,6 @@
|
|
|
1626
1785
|
target="_blank" href="https://youtu.be/jjEUI1J8bkA"><u><span data-i18n="common.youtube_sample"></span></u></a>
|
|
1627
1786
|
<br />
|
|
1628
1787
|
<br />
|
|
1629
|
-
<p align="center">
|
|
1630
|
-
<i class="fa-regular fa-lightbulb fa-bounce fa-2x"></i>
|
|
1631
|
-
</p>
|
|
1632
|
-
<br />
|
|
1633
1788
|
<label for="node-input-server">
|
|
1634
1789
|
<img
|
|
1635
1790
|
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>
|
|
@@ -1646,12 +1801,116 @@
|
|
|
1646
1801
|
<input type="text" id="node-input-serverMatter" />
|
|
1647
1802
|
</div>
|
|
1648
1803
|
|
|
1804
|
+
<div class="form-row">
|
|
1805
|
+
<label for="node-input-matterControllerMode">
|
|
1806
|
+
<i class="fa fa-list"></i>
|
|
1807
|
+
<span data-i18n="knxUltimateMatterControllerDevice.controller_mode"></span>
|
|
1808
|
+
</label>
|
|
1809
|
+
<select id="node-input-matterControllerMode">
|
|
1810
|
+
<option value="single" data-i18n="knxUltimateMatterControllerDevice.single_mode"></option>
|
|
1811
|
+
<option value="universal" data-i18n="knxUltimateMatterControllerDevice.universal_mode"></option>
|
|
1812
|
+
</select>
|
|
1813
|
+
</div>
|
|
1814
|
+
|
|
1815
|
+
<div id="matter-universal-description" class="form-tips" style="display:none; margin:8px 0;"
|
|
1816
|
+
data-i18n="knxUltimateMatterControllerDevice.universal_mode_description"></div>
|
|
1817
|
+
|
|
1818
|
+
<div id="matter-universal-options" style="display:none;">
|
|
1819
|
+
<div class="form-row">
|
|
1820
|
+
<label for="node-input-universalService">
|
|
1821
|
+
<i class="fa fa-bell"></i>
|
|
1822
|
+
<span data-i18n="knxUltimateMatterControllerDevice.universal_service"></span>
|
|
1823
|
+
</label>
|
|
1824
|
+
<select id="node-input-universalService">
|
|
1825
|
+
<option value="batteryMonitor" data-i18n="knxUltimateMatterControllerDevice.universal_service_battery_monitor"></option>
|
|
1826
|
+
<option value="allEvents" data-i18n="knxUltimateMatterControllerDevice.universal_service_all_events"></option>
|
|
1827
|
+
</select>
|
|
1828
|
+
</div>
|
|
1829
|
+
<div id="matter-universal-tabs" style="display:none; width:900px;">
|
|
1830
|
+
<ul>
|
|
1831
|
+
<li>
|
|
1832
|
+
<a href="#matter-universal-battery-options">
|
|
1833
|
+
<i class="fa fa-battery-quarter"></i>
|
|
1834
|
+
<span data-i18n="knxUltimateMatterControllerDevice.universal_service_battery_monitor"></span>
|
|
1835
|
+
</a>
|
|
1836
|
+
</li>
|
|
1837
|
+
</ul>
|
|
1838
|
+
<div id="matter-universal-battery-options">
|
|
1839
|
+
<div class="form-row">
|
|
1840
|
+
<label for="node-input-universalBatteryThreshold">
|
|
1841
|
+
<i class="fa fa-battery-quarter"></i>
|
|
1842
|
+
<span data-i18n="knxUltimateMatterControllerDevice.universal_battery_threshold"></span>
|
|
1843
|
+
</label>
|
|
1844
|
+
<input type="number" id="node-input-universalBatteryThreshold" min="0" max="100" step="1" style="width:100px;" />
|
|
1845
|
+
<span style="margin-left:5px;">%</span>
|
|
1846
|
+
</div>
|
|
1847
|
+
<div class="form-row" style="display:flex; align-items:center; flex-wrap:nowrap; gap:5px;">
|
|
1848
|
+
<label for="node-input-universalLowBatteryGA" style="width:155px; flex:0 0 155px; margin:0;">
|
|
1849
|
+
<i class="fa fa-bell"></i>
|
|
1850
|
+
<span data-i18n="knxUltimateMatterControllerDevice.universal_low_battery_ga"></span>
|
|
1851
|
+
</label>
|
|
1852
|
+
|
|
1853
|
+
<label for="node-input-universalLowBatteryGA" style="width:25px; flex:0 0 25px; margin:0;"><span data-i18n="common.ga"></span></label>
|
|
1854
|
+
<input type="text" id="node-input-universalLowBatteryGA" placeholder="Ex: 1/1/1"
|
|
1855
|
+
style="width:70px; flex:0 0 70px; margin:0; text-align:left;" />
|
|
1856
|
+
|
|
1857
|
+
<label for="node-input-universalLowBatteryDPT" style="width:38px; flex:0 0 38px; margin:0; text-align:right;"><span data-i18n="common.dpt"></span></label>
|
|
1858
|
+
<input type="text" id="node-input-universalLowBatteryDPT" value="1.005" readonly
|
|
1859
|
+
style="width:75px; flex:0 0 75px; margin:0;" />
|
|
1860
|
+
|
|
1861
|
+
<label for="node-input-universalLowBatteryGAName" style="width:45px; flex:0 0 45px; margin:0; text-align:right;"><span data-i18n="common.name"></span></label>
|
|
1862
|
+
<input type="text" id="node-input-universalLowBatteryGAName"
|
|
1863
|
+
style="width:auto; min-width:90px; flex:1 1 auto; margin:0; text-align:left;" />
|
|
1864
|
+
</div>
|
|
1865
|
+
<div class="form-row" style="display:flex; align-items:center; flex-wrap:nowrap; gap:5px;">
|
|
1866
|
+
<label for="node-input-universalLowBatteryTextGA" style="width:155px; flex:0 0 155px; margin:0;">
|
|
1867
|
+
<i class="fa fa-font"></i>
|
|
1868
|
+
<span data-i18n="knxUltimateMatterControllerDevice.universal_low_battery_text_ga"></span>
|
|
1869
|
+
</label>
|
|
1870
|
+
|
|
1871
|
+
<label for="node-input-universalLowBatteryTextGA" style="width:25px; flex:0 0 25px; margin:0;"><span data-i18n="common.ga"></span></label>
|
|
1872
|
+
<input type="text" id="node-input-universalLowBatteryTextGA" placeholder="Ex: 1/1/1"
|
|
1873
|
+
style="width:70px; flex:0 0 70px; margin:0; text-align:left;" />
|
|
1874
|
+
|
|
1875
|
+
<label for="node-input-universalLowBatteryTextDPT" style="width:38px; flex:0 0 38px; margin:0; text-align:right;"><span data-i18n="common.dpt"></span></label>
|
|
1876
|
+
<input type="text" id="node-input-universalLowBatteryTextDPT" value="16.001" readonly
|
|
1877
|
+
style="width:75px; flex:0 0 75px; margin:0;" />
|
|
1878
|
+
|
|
1879
|
+
<label for="node-input-universalLowBatteryTextGAName" style="width:45px; flex:0 0 45px; margin:0; text-align:right;"><span data-i18n="common.name"></span></label>
|
|
1880
|
+
<input type="text" id="node-input-universalLowBatteryTextGAName"
|
|
1881
|
+
style="width:auto; min-width:90px; flex:1 1 auto; margin:0; text-align:left;" />
|
|
1882
|
+
</div>
|
|
1883
|
+
<div class="form-row">
|
|
1884
|
+
<label for="node-input-universalBatteryOnlyLow" style="width:260px;">
|
|
1885
|
+
<i class="fa fa-filter"></i>
|
|
1886
|
+
<span data-i18n="knxUltimateMatterControllerDevice.universal_battery_only_low"></span>
|
|
1887
|
+
</label>
|
|
1888
|
+
<input type="checkbox" id="node-input-universalBatteryOnlyLow" style="display:inline-block; width:auto;" />
|
|
1889
|
+
</div>
|
|
1890
|
+
<div class="form-row">
|
|
1891
|
+
<label for="node-input-universalEmitInitialState" style="width:260px;">
|
|
1892
|
+
<i class="fa fa-camera"></i>
|
|
1893
|
+
<span data-i18n="knxUltimateMatterControllerDevice.universal_emit_initial"></span>
|
|
1894
|
+
</label>
|
|
1895
|
+
<input type="checkbox" id="node-input-universalEmitInitialState" style="display:inline-block; width:auto;" />
|
|
1896
|
+
</div>
|
|
1897
|
+
<div class="form-row">
|
|
1898
|
+
<label for="node-input-universalIncludeRawEvent" style="width:260px;">
|
|
1899
|
+
<i class="fa fa-code"></i>
|
|
1900
|
+
<span data-i18n="knxUltimateMatterControllerDevice.universal_include_raw"></span>
|
|
1901
|
+
</label>
|
|
1902
|
+
<input type="checkbox" id="node-input-universalIncludeRawEvent" style="display:inline-block; width:auto;" />
|
|
1903
|
+
</div>
|
|
1904
|
+
</div>
|
|
1905
|
+
</div>
|
|
1906
|
+
</div>
|
|
1907
|
+
|
|
1649
1908
|
<br />
|
|
1650
|
-
<p>
|
|
1909
|
+
<p id="matter-device-section-title">
|
|
1651
1910
|
<b><span data-i18n="knxUltimateMatterControllerDevice.matter_section"></span></b>
|
|
1652
1911
|
</p>
|
|
1653
1912
|
|
|
1654
|
-
<div class="form-row">
|
|
1913
|
+
<div class="form-row" id="matter-device-row">
|
|
1655
1914
|
<label for="node-input-matterDeviceName">
|
|
1656
1915
|
<i class="fa fa-play-circle"></i> <span data-i18n="knxUltimateMatterControllerDevice.matter_device"></span>
|
|
1657
1916
|
</label>
|
|
@@ -2120,18 +2379,19 @@
|
|
|
2120
2379
|
</div>
|
|
2121
2380
|
<br/>
|
|
2122
2381
|
</div>
|
|
2123
|
-
<div class="form-row">
|
|
2124
|
-
<label for="node-input-enableNodePINS" style="width:260px;">
|
|
2125
|
-
<i class="fa fa-circle"></i> <span data-i18n="knxUltimateMatterControllerDevice.node_pins"></span>
|
|
2126
|
-
</label>
|
|
2127
|
-
<select id="node-input-enableNodePINS">
|
|
2128
|
-
<option value="no" data-i18n="knxUltimateMatterControllerDevice.node_pins_hide"></option>
|
|
2129
|
-
<option value="yes" data-i18n="knxUltimateMatterControllerDevice.node_pins_show"></option>
|
|
2130
|
-
</select>
|
|
2131
|
-
</div>
|
|
2132
2382
|
</p>
|
|
2133
2383
|
</div>
|
|
2134
2384
|
</div>
|
|
2385
|
+
|
|
2386
|
+
<div class="form-row" style="margin-top:12px;">
|
|
2387
|
+
<label for="node-input-enableNodePINS" style="width:260px;">
|
|
2388
|
+
<i class="fa fa-circle"></i> <span data-i18n="knxUltimateMatterControllerDevice.node_pins"></span>
|
|
2389
|
+
</label>
|
|
2390
|
+
<select id="node-input-enableNodePINS">
|
|
2391
|
+
<option value="no" data-i18n="knxUltimateMatterControllerDevice.node_pins_hide"></option>
|
|
2392
|
+
<option value="yes" data-i18n="knxUltimateMatterControllerDevice.node_pins_show"></option>
|
|
2393
|
+
</select>
|
|
2394
|
+
</div>
|
|
2135
2395
|
</div>
|
|
2136
2396
|
|
|
2137
2397
|
<br/>
|
|
@@ -2150,7 +2410,31 @@
|
|
|
2150
2410
|
|
|
2151
2411
|
The editor detects the selected endpoint capabilities and exposes only the corresponding
|
|
2152
2412
|
Matter functions. Bridged Matter devices are expanded into their individual endpoints in
|
|
2153
|
-
the device picker.
|
|
2413
|
+
the device picker. Door Lock, Window Covering, Thermostat, Fan and Switch endpoints use
|
|
2414
|
+
dedicated profiles. Switch press, long-press and multi-press events are emitted on the
|
|
2415
|
+
optional flow output; simpler endpoints continue through the generic mapped fallback.
|
|
2416
|
+
|
|
2417
|
+
**Universal Mode**
|
|
2418
|
+
|
|
2419
|
+
Select **Universal Mode** in the **Mode** selector to listen to every attribute report,
|
|
2420
|
+
cluster event and device initialization from this controller. It always exposes one input
|
|
2421
|
+
and one output, does not require a KNX gateway, and does not use endpoint KNX mappings.
|
|
2422
|
+
Output values are in `msg.payload`; routing metadata is in `msg.matter`, including
|
|
2423
|
+
`source`, `nodeId`, `endpointId`, `clusterId` and the attribute/event name.
|
|
2424
|
+
The **Universal Battery Monitor** scans every node and endpoint for Power Source,
|
|
2425
|
+
emits an initial snapshot, and maintains complete battery state. It can emit only
|
|
2426
|
+
batteries below the configured threshold or every battery update. `msg.payload`
|
|
2427
|
+
contains normalized percent, charge level, replacement state, replaceability and
|
|
2428
|
+
voltage; raw Matter metadata remains in `msg.matter`. Send
|
|
2429
|
+
`{payload:{action:"getAllBatteries"}}` to retrieve the cached inventory.
|
|
2430
|
+
|
|
2431
|
+
Use `msg.nodeId`, `msg.endpointId`, `msg.clusterId` and either `msg.command` plus
|
|
2432
|
+
`msg.args`, or `msg.attribute`. Add `msg.value` for an attribute write; omit it for a
|
|
2433
|
+
read. The same selectors may be placed under `msg.matter`. For example, read battery
|
|
2434
|
+
with `{nodeId:"100", endpointId:1, clusterId:47, attribute:"batPercentRemaining"}` or
|
|
2435
|
+
switch on with `{nodeId:"100", endpointId:1, clusterId:6, command:"on", args:{}}`.
|
|
2436
|
+
Battery is emitted in Matter's raw half-percent units and can be divided by two in a
|
|
2437
|
+
Function node.
|
|
2154
2438
|
|
|
2155
2439
|
|Property|Description|
|
|
2156
2440
|
|--|--|
|
|
@@ -2235,6 +2519,7 @@ _Basic Matter effects_
|
|
|
2235
2519
|
| Read status at startup | Read the Matter endpoint status at Node-RED startup or full deploy and send it to the KNX bus. |
|
|
2236
2520
|
| KNX Brightness Status | Updates the KNX brightness status whenever the Matter light switches ON/OFF. It can send 0% while OFF and restore the previous value when ON, or leave the brightness status unchanged. |
|
|
2237
2521
|
| Update local cached Matter state from KNX bus writes | When enabled, KNX writes immediately update the local Matter-state cache without waiting for the endpoint report. Disable it if the cache should follow only real Matter reports. |
|
|
2522
|
+
| Node Input/Output PINs | For mapped endpoints, all Matter selectors belong directly to `msg`. Read an attribute with `msg.clusterId` and `msg.attribute`; add `msg.requestFromRemote = true` to force a device read instead of using the subscribed value. The result is emitted as `msg.payload`. Add `msg.value` to write an attribute, or use `msg.clusterId`, `msg.command` and `msg.args` to invoke a command. Attribute IDs such as `0` are accepted. Door Lock input accepts `msg.payload = true` to lock and `false` to unlock. |
|
|
2238
2523
|
| 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. |
|
|
2239
2524
|
| 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.|
|
|
2240
2525
|
| Day/Night | Select the group address used to set the day/night behaviour. The group address value is _true_ if daytime, _false_ if nighttime. |
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
<script type="text/markdown" data-help-name="knxUltimateMatterControllerDevice">
|
|
2
|
-
# Control Matter from KNX (BETA)
|
|
3
|
-
|
|
4
2
|
> Dieser Knoten ist **BETA**: das Verhalten kann sich ändern, während die Matter-Implementierung weiter verfeinert wird.
|
|
5
3
|
|
|
6
4
|
Dieser Knoten steuert einen bereits gekoppelten Matter-Endpunkt über KNX. Wähle das Matter-Gerät aus; der Editor erkennt die Fähigkeiten des Endpunkts und zeigt nur die passenden KNX-Zuordnungen.
|
|
@@ -23,6 +21,16 @@ Er ersetzt die unveröffentlichten getrennten Matter-Controller-Nodes und behäl
|
|
|
23
21
|
| Update local state from KNX write | Aktualisiert den lokalen Matter/KNX-Cache, wenn ein Telegramm auf eine konfigurierte KNX-GA geschrieben wird. |
|
|
24
22
|
| Node Input/Output PINs | Zeigt Node-RED-Eingangs-/Ausgangspins. Der Eingang akzeptiert boolesche Payloads sowie Matter-ähnliche `msg.payload` oder `msg.on.on`; der Ausgang sendet Statusupdates. Die Auswahl bleibt beim erneuten Öffnen des Editors erhalten. |
|
|
25
23
|
|
|
24
|
+
## Universeller Modus
|
|
25
|
+
|
|
26
|
+
Wähle **Universeller Modus**, um alle Geräte zu überwachen. Der Node hat immer einen Eingang und einen Ausgang und verwendet keine Endpunkt-Zuordnungen. Ein KNX-Gateway ist optional und wird nur für die Alarm-/Text-GAs des Batteriemonitors benötigt.
|
|
27
|
+
|
|
28
|
+
Der **Universelle Batteriemonitor** speichert den vollständigen Batteriestatus. Optionale KNX-GAs senden den Sammelalarm als DPT 1.005 und wechseln alle 2 Sekunden die Gerätenamen als DPT 16.001. `{payload:{action:"getAllBatteries"}}` liefert das Cache-Inventar.
|
|
29
|
+
|
|
30
|
+
Ausgaben enthalten den Rohwert in `msg.payload` und Routingdaten in `msg.matter` (`source`, `nodeId`, `endpointId`, `clusterId`, Attribut-/Ereignisname). Eingaben verwenden `msg.nodeId`, `msg.endpointId`, `msg.clusterId` und entweder `msg.command` mit `msg.args` oder `msg.attribute`; `msg.value` schreibt, ohne `msg.value` wird gelesen. Die Felder können auch unter `msg.matter` stehen.
|
|
31
|
+
|
|
32
|
+
Beispiele: `{nodeId:"100",endpointId:1,clusterId:6,command:"on",args:{}}` schaltet ein; `{nodeId:"100",endpointId:1,clusterId:47,attribute:"batPercentRemaining"}` liest die Batterie. Batteriewerte bleiben in Matter-Halbprozenteinheiten und können in einem Function-Node durch zwei geteilt werden.
|
|
33
|
+
|
|
26
34
|
## Verhalten
|
|
27
35
|
|
|
28
36
|
Der Knoten pflegt einen lokalen Cache aus Matter-Updates und KNX-Schreibtelegrammen, beantwortet KNX-Leseanfragen aus diesem Cache und kann Werte beim Start lesen/ausgeben. Er hört nur auf konfigurierte Gruppenadressen, daher wird fremder KNX-Verkehr ignoriert.
|
|
@@ -92,7 +92,23 @@
|
|
|
92
92
|
"matter_controller": "Matter-Controller",
|
|
93
93
|
"matter_device": "Matter-Gerät",
|
|
94
94
|
"device_type": "Gerätetyp",
|
|
95
|
-
"matter_section": "Matter-Gerät"
|
|
95
|
+
"matter_section": "Matter-Gerät",
|
|
96
|
+
"controller_mode": "Modus",
|
|
97
|
+
"single_mode": "Einzelnes Gerät",
|
|
98
|
+
"universal_mode": "Universeller Modus (alle Matter-Geräte)",
|
|
99
|
+
"universal_mode_description": "Alle mit diesem Controller verbundenen Matter-Geräte überwachen und steuern. Der universelle Modus funktioniert ohne KNX-Zuordnungen.",
|
|
100
|
+
"universal_service": "Dienst",
|
|
101
|
+
"universal_service_battery_monitor": "Universeller Batteriemonitor",
|
|
102
|
+
"universal_service_all_events": "Alle Matter-Ereignisse",
|
|
103
|
+
"universal_battery_threshold": "Schwelle für niedrigen Batteriestand",
|
|
104
|
+
"universal_low_battery_ga": "GA Batteriealarm",
|
|
105
|
+
"universal_low_battery_text_ga": "GA Gerätename",
|
|
106
|
+
"universal_battery_only_low": "Nur niedrige Batteriestände ausgeben",
|
|
107
|
+
"universal_emit_initial": "Anfänglichen Batterie-Snapshot ausgeben",
|
|
108
|
+
"universal_include_raw": "Rohes Matter-Ereignis einschließen",
|
|
109
|
+
"universal_mode_status": "Universeller Matter-Modus",
|
|
110
|
+
"universal_mode_locate_disabled": "„Suchen“ ist im universellen Modus nicht verfügbar.",
|
|
111
|
+
"universal_controller_name": "Universeller Matter-Controller"
|
|
96
112
|
},
|
|
97
113
|
"common": {
|
|
98
114
|
"ga": "GA",
|