matterbridge 3.2.8-dev-20250918-52dc90c → 3.2.8-dev-20250919-e967b55

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/dist/frontend.js CHANGED
@@ -636,20 +636,12 @@ export class Frontend extends EventEmitter {
636
636
  this.matterbridge.matterbridgeInformation.profile = this.matterbridge.profile;
637
637
  this.matterbridge.matterbridgeInformation.loggerLevel = this.matterbridge.log.logLevel;
638
638
  this.matterbridge.matterbridgeInformation.matterLoggerLevel = Logger.defaultLogLevel;
639
- this.matterbridge.matterbridgeInformation.mattermdnsinterface = this.matterbridge.mdnsInterface;
640
- this.matterbridge.matterbridgeInformation.matteripv4address = this.matterbridge.ipv4address;
641
- this.matterbridge.matterbridgeInformation.matteripv6address = this.matterbridge.ipv6address;
639
+ this.matterbridge.matterbridgeInformation.matterMdnsInterface = this.matterbridge.mdnsInterface;
640
+ this.matterbridge.matterbridgeInformation.matterIpv4Address = this.matterbridge.ipv4address;
641
+ this.matterbridge.matterbridgeInformation.matterIpv6Address = this.matterbridge.ipv6address;
642
642
  this.matterbridge.matterbridgeInformation.matterPort = (await this.matterbridge.nodeContext?.get('matterport', 5540)) ?? 5540;
643
643
  this.matterbridge.matterbridgeInformation.matterDiscriminator = await this.matterbridge.nodeContext?.get('matterdiscriminator');
644
644
  this.matterbridge.matterbridgeInformation.matterPasscode = await this.matterbridge.nodeContext?.get('matterpasscode');
645
- if (this.matterbridge.bridgeMode === 'bridge' && this.matterbridge.serverNode && !this.matterbridge.hasCleanupStarted) {
646
- this.matterbridge.matterbridgeInformation.matter = this.matterbridge.getServerNodeData(this.matterbridge.serverNode);
647
- this.matterbridge.matterbridgeInformation.matterbridgePaired = this.matterbridge.serverNode.state.commissioning.commissioned;
648
- this.matterbridge.matterbridgeInformation.matterbridgeQrPairingCode = this.matterbridge.matterbridgeInformation.matterbridgeEndAdvertise ? undefined : this.matterbridge.serverNode.state.commissioning.pairingCodes.qrPairingCode;
649
- this.matterbridge.matterbridgeInformation.matterbridgeManualPairingCode = this.matterbridge.matterbridgeInformation.matterbridgeEndAdvertise ? undefined : this.matterbridge.serverNode.state.commissioning.pairingCodes.manualPairingCode;
650
- this.matterbridge.matterbridgeInformation.matterbridgeFabricInformations = this.matterbridge.sanitizeFabricInformations(Object.values(this.matterbridge.serverNode.state.commissioning.fabrics));
651
- this.matterbridge.matterbridgeInformation.matterbridgeSessionInformations = this.matterbridge.sanitizeSessionInformation(Object.values(this.matterbridge.serverNode.state.sessions.sessions));
652
- }
653
645
  return { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: this.matterbridge.matterbridgeInformation };
654
646
  }
655
647
  getReachability(device) {
@@ -928,8 +920,16 @@ export class Frontend extends EventEmitter {
928
920
  let data;
929
921
  const sendResponse = (data) => {
930
922
  if (client.readyState === WebSocket.OPEN) {
931
- const { response, ...rest } = data;
932
- this.log.debug(`Sending api response broadcast message: ${debugStringify(rest)}`);
923
+ if ('response' in data) {
924
+ const { response, ...rest } = data;
925
+ this.log.debug(`Sending api response message: ${debugStringify(rest)}`);
926
+ }
927
+ else if ('error' in data) {
928
+ this.log.debug(`Sending api error message: ${debugStringify(data)}`);
929
+ }
930
+ else {
931
+ this.log.debug(`Sending api response message: ${debugStringify(data)}`);
932
+ }
933
933
  client.send(JSON.stringify(data));
934
934
  }
935
935
  };
@@ -964,6 +964,7 @@ export class Frontend extends EventEmitter {
964
964
  }
965
965
  }
966
966
  else if (data.method === '/api/install') {
967
+ const localData = data;
967
968
  if (!isValidString(data.params.packageName, 10) || !isValidBoolean(data.params.restart)) {
968
969
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Wrong parameter in /api/install' });
969
970
  return;
@@ -972,11 +973,11 @@ export class Frontend extends EventEmitter {
972
973
  const { spawnCommand } = await import('./utils/spawn.js');
973
974
  spawnCommand(this.matterbridge, 'npm', ['install', '-g', data.params.packageName, '--omit=dev', '--verbose'])
974
975
  .then((_response) => {
975
- sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
976
- this.wssSendCloseSnackbarMessage(`Installing package ${data.params.packageName}...`);
977
- this.wssSendSnackbarMessage(`Installed package ${data.params.packageName}`, 5, 'success');
978
- const packageName = data.params.packageName.replace(/@.*$/, '');
979
- if (data.params.restart === false && packageName !== 'matterbridge') {
976
+ sendResponse({ id: localData.id, method: localData.method, src: 'Matterbridge', dst: data.src, success: true });
977
+ this.wssSendCloseSnackbarMessage(`Installing package ${localData.params.packageName}...`);
978
+ this.wssSendSnackbarMessage(`Installed package ${localData.params.packageName}`, 5, 'success');
979
+ const packageName = localData.params.packageName.replace(/@.*$/, '');
980
+ if (localData.params.restart === false && packageName !== 'matterbridge') {
980
981
  this.matterbridge.plugins
981
982
  .add(packageName)
982
983
  .then((plugin) => {
@@ -1018,11 +1019,12 @@ export class Frontend extends EventEmitter {
1018
1019
  })
1019
1020
  .catch((error) => {
1020
1021
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: error instanceof Error ? error.message : error });
1021
- this.wssSendCloseSnackbarMessage(`Installing package ${data.params.packageName}...`);
1022
- this.wssSendSnackbarMessage(`Package ${data.params.packageName} not installed`, 10, 'error');
1022
+ this.wssSendCloseSnackbarMessage(`Installing package ${localData.params.packageName}...`);
1023
+ this.wssSendSnackbarMessage(`Package ${localData.params.packageName} not installed`, 10, 'error');
1023
1024
  });
1024
1025
  }
1025
1026
  else if (data.method === '/api/uninstall') {
1027
+ const localData = data;
1026
1028
  if (!isValidString(data.params.packageName, 10)) {
1027
1029
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Wrong parameter packageName in /api/uninstall' });
1028
1030
  return;
@@ -1039,19 +1041,20 @@ export class Frontend extends EventEmitter {
1039
1041
  const { spawnCommand } = await import('./utils/spawn.js');
1040
1042
  spawnCommand(this.matterbridge, 'npm', ['uninstall', '-g', data.params.packageName, '--verbose'])
1041
1043
  .then((_response) => {
1042
- sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
1043
- this.wssSendCloseSnackbarMessage(`Uninstalling package ${data.params.packageName}...`);
1044
- this.wssSendSnackbarMessage(`Uninstalled package ${data.params.packageName}`, 5, 'success');
1044
+ sendResponse({ id: localData.id, method: localData.method, src: 'Matterbridge', dst: data.src, success: true });
1045
+ this.wssSendCloseSnackbarMessage(`Uninstalling package ${localData.params.packageName}...`);
1046
+ this.wssSendSnackbarMessage(`Uninstalled package ${localData.params.packageName}`, 5, 'success');
1045
1047
  return;
1046
1048
  })
1047
1049
  .catch((error) => {
1048
1050
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: error instanceof Error ? error.message : error });
1049
- this.wssSendCloseSnackbarMessage(`Uninstalling package ${data.params.packageName}...`);
1050
- this.wssSendSnackbarMessage(`Package ${data.params.packageName} not uninstalled`, 10, 'error');
1051
+ this.wssSendCloseSnackbarMessage(`Uninstalling package ${localData.params.packageName}...`);
1052
+ this.wssSendSnackbarMessage(`Package ${localData.params.packageName} not uninstalled`, 10, 'error');
1051
1053
  this.wssSendSnackbarMessage(`Restart required`, 0);
1052
1054
  });
1053
1055
  }
1054
1056
  else if (data.method === '/api/addplugin') {
1057
+ const localData = data;
1055
1058
  if (!isValidString(data.params.pluginNameOrPath, 10)) {
1056
1059
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Wrong parameter pluginNameOrPath in /api/addplugin' });
1057
1060
  return;
@@ -1064,14 +1067,14 @@ export class Frontend extends EventEmitter {
1064
1067
  }
1065
1068
  const plugin = await this.matterbridge.plugins.add(data.params.pluginNameOrPath);
1066
1069
  if (plugin) {
1067
- sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: plugin.name });
1070
+ sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
1068
1071
  this.wssSendSnackbarMessage(`Added plugin ${data.params.pluginNameOrPath}`, 5, 'success');
1069
1072
  this.matterbridge.plugins
1070
1073
  .load(plugin, true, 'The plugin has been added', true)
1071
1074
  .then(() => {
1072
1075
  this.wssSendRefreshRequired('plugins');
1073
1076
  this.wssSendRefreshRequired('devices');
1074
- this.wssSendSnackbarMessage(`Started plugin ${data.params.pluginNameOrPath}`, 5, 'success');
1077
+ this.wssSendSnackbarMessage(`Started plugin ${localData.params.pluginNameOrPath}`, 5, 'success');
1075
1078
  return;
1076
1079
  })
1077
1080
  .catch((_error) => {
@@ -1096,6 +1099,7 @@ export class Frontend extends EventEmitter {
1096
1099
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
1097
1100
  }
1098
1101
  else if (data.method === '/api/enableplugin') {
1102
+ const localData = data;
1099
1103
  if (!isValidString(data.params.pluginName, 10) || !this.matterbridge.plugins.has(data.params.pluginName)) {
1100
1104
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Wrong parameter pluginName in /api/enableplugin' });
1101
1105
  return;
@@ -1117,7 +1121,7 @@ export class Frontend extends EventEmitter {
1117
1121
  .then(() => {
1118
1122
  this.wssSendRefreshRequired('plugins');
1119
1123
  this.wssSendRefreshRequired('devices');
1120
- this.wssSendSnackbarMessage(`Started plugin ${data.params.pluginName}`, 5, 'success');
1124
+ this.wssSendSnackbarMessage(`Started plugin ${localData.params.pluginName}`, 5, 'success');
1121
1125
  return;
1122
1126
  })
1123
1127
  .catch((_error) => {
@@ -1188,7 +1192,6 @@ export class Frontend extends EventEmitter {
1188
1192
  if (plugin) {
1189
1193
  this.matterbridge.plugins.saveConfigFromJson(plugin, data.params.formData, true);
1190
1194
  this.wssSendSnackbarMessage(`Saved config for plugin ${data.params.pluginName}`);
1191
- this.wssSendRefreshRequired('pluginsRestart');
1192
1195
  this.wssSendRestartRequired();
1193
1196
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
1194
1197
  }
@@ -1270,6 +1273,7 @@ export class Frontend extends EventEmitter {
1270
1273
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
1271
1274
  }
1272
1275
  else if (data.method === '/api/matter') {
1276
+ const localData = data;
1273
1277
  if (!isValidString(data.params.id)) {
1274
1278
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Wrong parameter id in /api/matter' });
1275
1279
  return;
@@ -1278,7 +1282,7 @@ export class Frontend extends EventEmitter {
1278
1282
  if (data.params.id === 'Matterbridge')
1279
1283
  serverNode = this.matterbridge.serverNode;
1280
1284
  else
1281
- serverNode = this.matterbridge.getPlugins().find((p) => p.serverNode && p.serverNode.id === data.params.id)?.serverNode || this.matterbridge.getDevices().find((d) => d.serverNode && d.serverNode.id === data.params.id)?.serverNode;
1285
+ serverNode = this.matterbridge.getPlugins().find((p) => p.serverNode && p.serverNode.id === localData.params.id)?.serverNode || this.matterbridge.getDevices().find((d) => d.serverNode && d.serverNode.id === localData.params.id)?.serverNode;
1282
1286
  if (!serverNode) {
1283
1287
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Unknown server node id in /api/matter' });
1284
1288
  return;
@@ -1292,14 +1296,14 @@ export class Frontend extends EventEmitter {
1292
1296
  if (data.params.startCommission) {
1293
1297
  await serverNode.env.get(DeviceCommissioner)?.allowBasicCommissioning();
1294
1298
  this.matterbridge.advertisingNodes.set(serverNode.id, Date.now());
1295
- this.log.debug(`*Commissioning has been sent for node ${data.params.id}`);
1296
- this.wssSendRefreshRequired('matter', { matter: { ...matter, advertising: true } });
1299
+ this.log.debug(`*Allow commissioning has been sent for node ${data.params.id}`);
1300
+ this.wssSendRefreshRequired('matter', { matter: { ...matter, advertiseTime: Date.now(), advertising: true } });
1297
1301
  }
1298
1302
  if (data.params.stopCommission) {
1299
1303
  await serverNode.env.get(DeviceCommissioner)?.endCommissioning();
1300
1304
  this.matterbridge.advertisingNodes.delete(serverNode.id);
1301
- this.log.debug(`*Stop commissioning has been sent for node ${data.params.id}`);
1302
- this.wssSendRefreshRequired('matter', { matter: { ...matter, advertising: false } });
1305
+ this.log.debug(`*End commissioning has been sent for node ${data.params.id}`);
1306
+ this.wssSendRefreshRequired('matter', { matter: { ...matter, advertiseTime: 0, advertising: false } });
1303
1307
  }
1304
1308
  if (data.params.advertise) {
1305
1309
  await serverNode.env.get(DeviceAdvertiser)?.advertise(true);
@@ -1315,15 +1319,15 @@ export class Frontend extends EventEmitter {
1315
1319
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true, response: matter });
1316
1320
  }
1317
1321
  else if (data.method === '/api/settings') {
1318
- sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: await this.getApiSettings() });
1322
+ sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true, response: await this.getApiSettings() });
1319
1323
  }
1320
1324
  else if (data.method === '/api/plugins') {
1321
1325
  const plugins = this.getPlugins();
1322
- sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: plugins });
1326
+ sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true, response: plugins });
1323
1327
  }
1324
1328
  else if (data.method === '/api/devices') {
1325
1329
  const devices = await this.getDevices(isValidString(data.params.pluginName) ? data.params.pluginName : undefined);
1326
- sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: devices });
1330
+ sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true, response: devices });
1327
1331
  }
1328
1332
  else if (data.method === '/api/clusters') {
1329
1333
  if (!isValidString(data.params.plugin, 10)) {
@@ -1341,6 +1345,7 @@ export class Frontend extends EventEmitter {
1341
1345
  method: data.method,
1342
1346
  src: 'Matterbridge',
1343
1347
  dst: data.src,
1348
+ success: true,
1344
1349
  response,
1345
1350
  });
1346
1351
  }
@@ -1359,7 +1364,7 @@ export class Frontend extends EventEmitter {
1359
1364
  return;
1360
1365
  }
1361
1366
  const selectDeviceValues = plugin.platform?.getSelectDevices().sort((keyA, keyB) => keyA.name.localeCompare(keyB.name));
1362
- sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: selectDeviceValues });
1367
+ sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true, response: selectDeviceValues });
1363
1368
  }
1364
1369
  else if (data.method === '/api/select/entities') {
1365
1370
  if (!isValidString(data.params.plugin, 10)) {
@@ -1372,9 +1377,10 @@ export class Frontend extends EventEmitter {
1372
1377
  return;
1373
1378
  }
1374
1379
  const selectEntityValues = plugin.platform?.getSelectEntities().sort((keyA, keyB) => keyA.name.localeCompare(keyB.name));
1375
- sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: selectEntityValues });
1380
+ sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true, response: selectEntityValues });
1376
1381
  }
1377
1382
  else if (data.method === '/api/action') {
1383
+ const localData = data;
1378
1384
  if (!isValidString(data.params.plugin, 5) || !isValidString(data.params.action, 1)) {
1379
1385
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Wrong parameter in /api/action' });
1380
1386
  return;
@@ -1388,12 +1394,12 @@ export class Frontend extends EventEmitter {
1388
1394
  plugin.platform
1389
1395
  ?.onAction(data.params.action, data.params.value, data.params.id, data.params.formData)
1390
1396
  .then(() => {
1391
- sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
1397
+ sendResponse({ id: localData.id, method: localData.method, src: 'Matterbridge', dst: localData.src, success: true });
1392
1398
  return;
1393
1399
  })
1394
1400
  .catch((error) => {
1395
- this.log.error(`Error in plugin ${plugin.name} action ${data.params.action}: ${error}`);
1396
- sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: `Error in plugin ${plugin.name} action ${data.params.action}: ${error}` });
1401
+ this.log.error(`Error in plugin ${plugin.name} action ${localData.params.action}: ${error}`);
1402
+ sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: `Error in plugin ${plugin.name} action ${localData.params.action}: ${error}` });
1397
1403
  });
1398
1404
  }
1399
1405
  else if (data.method === '/api/config') {
@@ -1497,7 +1503,7 @@ export class Frontend extends EventEmitter {
1497
1503
  if (isValidString(data.params.value)) {
1498
1504
  this.log.debug(`Matter.js mdns interface: ${data.params.value === '' ? 'all interfaces' : data.params.value}`);
1499
1505
  this.matterbridge.mdnsInterface = data.params.value === '' ? undefined : data.params.value;
1500
- this.matterbridge.matterbridgeInformation.mattermdnsinterface = this.matterbridge.mdnsInterface;
1506
+ this.matterbridge.matterbridgeInformation.matterMdnsInterface = this.matterbridge.mdnsInterface;
1501
1507
  await this.matterbridge.nodeContext?.set('mattermdnsinterface', data.params.value);
1502
1508
  this.wssSendRestartRequired();
1503
1509
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
@@ -1507,7 +1513,7 @@ export class Frontend extends EventEmitter {
1507
1513
  if (isValidString(data.params.value)) {
1508
1514
  this.log.debug(`Matter.js ipv4 address: ${data.params.value === '' ? 'all ipv4 addresses' : data.params.value}`);
1509
1515
  this.matterbridge.ipv4address = data.params.value === '' ? undefined : data.params.value;
1510
- this.matterbridge.matterbridgeInformation.matteripv4address = this.matterbridge.ipv4address;
1516
+ this.matterbridge.matterbridgeInformation.matterIpv4Address = this.matterbridge.ipv4address;
1511
1517
  await this.matterbridge.nodeContext?.set('matteripv4address', data.params.value);
1512
1518
  this.wssSendRestartRequired();
1513
1519
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
@@ -1517,34 +1523,35 @@ export class Frontend extends EventEmitter {
1517
1523
  if (isValidString(data.params.value)) {
1518
1524
  this.log.debug(`Matter.js ipv6 address: ${data.params.value === '' ? 'all ipv6 addresses' : data.params.value}`);
1519
1525
  this.matterbridge.ipv6address = data.params.value === '' ? undefined : data.params.value;
1520
- this.matterbridge.matterbridgeInformation.matteripv6address = this.matterbridge.ipv6address;
1526
+ this.matterbridge.matterbridgeInformation.matterIpv6Address = this.matterbridge.ipv6address;
1521
1527
  await this.matterbridge.nodeContext?.set('matteripv6address', data.params.value);
1522
1528
  this.wssSendRestartRequired();
1523
1529
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
1524
1530
  }
1525
1531
  break;
1526
1532
  case 'setmatterport':
1527
- data.params.value = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
1528
- if (isValidNumber(data.params.value, 5540, 5580)) {
1529
- this.log.debug(`Set matter commissioning port to ${CYAN}${data.params.value}${db}`);
1530
- this.matterbridge.matterbridgeInformation.matterPort = data.params.value;
1531
- await this.matterbridge.nodeContext?.set('matterport', data.params.value);
1533
+ const port = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
1534
+ if (isValidNumber(port, 5540, 5600)) {
1535
+ this.log.debug(`Set matter commissioning port to ${CYAN}${port}${db}`);
1536
+ this.matterbridge.matterbridgeInformation.matterPort = port;
1537
+ await this.matterbridge.nodeContext?.set('matterport', port);
1532
1538
  this.wssSendRestartRequired();
1539
+ sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
1533
1540
  }
1534
1541
  else {
1535
1542
  this.log.debug(`Reset matter commissioning port to ${CYAN}5540${db}`);
1536
1543
  this.matterbridge.matterbridgeInformation.matterPort = 5540;
1537
1544
  await this.matterbridge.nodeContext?.set('matterport', 5540);
1538
1545
  this.wssSendRestartRequired();
1546
+ sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Invalid value: reset matter commissioning port to default 5540' });
1539
1547
  }
1540
- sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
1541
1548
  break;
1542
1549
  case 'setmatterdiscriminator':
1543
- data.params.value = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
1544
- if (isValidNumber(data.params.value, 1000, 4095)) {
1545
- this.log.debug(`Set matter commissioning discriminator to ${CYAN}${data.params.value}${db}`);
1546
- this.matterbridge.matterbridgeInformation.matterDiscriminator = data.params.value;
1547
- await this.matterbridge.nodeContext?.set('matterdiscriminator', data.params.value);
1550
+ const discriminator = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
1551
+ if (isValidNumber(discriminator, 1000, 4095)) {
1552
+ this.log.debug(`Set matter commissioning discriminator to ${CYAN}${discriminator}${db}`);
1553
+ this.matterbridge.matterbridgeInformation.matterDiscriminator = discriminator;
1554
+ await this.matterbridge.nodeContext?.set('matterdiscriminator', discriminator);
1548
1555
  this.wssSendRestartRequired();
1549
1556
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
1550
1557
  }
@@ -1553,15 +1560,15 @@ export class Frontend extends EventEmitter {
1553
1560
  this.matterbridge.matterbridgeInformation.matterDiscriminator = undefined;
1554
1561
  await this.matterbridge.nodeContext?.remove('matterdiscriminator');
1555
1562
  this.wssSendRestartRequired();
1556
- sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: false });
1563
+ sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Invalid value: reset matter commissioning discriminator to default undefined' });
1557
1564
  }
1558
1565
  break;
1559
1566
  case 'setmatterpasscode':
1560
- data.params.value = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
1561
- if (isValidNumber(data.params.value, 10000000, 90000000)) {
1562
- this.matterbridge.matterbridgeInformation.matterPasscode = data.params.value;
1563
- this.log.debug(`Set matter commissioning passcode to ${CYAN}${data.params.value}${db}`);
1564
- await this.matterbridge.nodeContext?.set('matterpasscode', data.params.value);
1567
+ const passcode = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
1568
+ if (isValidNumber(passcode, 10000000, 90000000)) {
1569
+ this.matterbridge.matterbridgeInformation.matterPasscode = passcode;
1570
+ this.log.debug(`Set matter commissioning passcode to ${CYAN}${passcode}${db}`);
1571
+ await this.matterbridge.nodeContext?.set('matterpasscode', passcode);
1565
1572
  this.wssSendRestartRequired();
1566
1573
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
1567
1574
  }
@@ -1570,7 +1577,7 @@ export class Frontend extends EventEmitter {
1570
1577
  this.matterbridge.matterbridgeInformation.matterPasscode = undefined;
1571
1578
  await this.matterbridge.nodeContext?.remove('matterpasscode');
1572
1579
  this.wssSendRestartRequired();
1573
- sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: false });
1580
+ sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Invalid value: reset matter commissioning passcode to default undefined' });
1574
1581
  }
1575
1582
  break;
1576
1583
  case 'setvirtualmode':
@@ -1588,6 +1595,7 @@ export class Frontend extends EventEmitter {
1588
1595
  }
1589
1596
  }
1590
1597
  else if (data.method === '/api/command') {
1598
+ const localData = data;
1591
1599
  if (!isValidString(data.params.command, 5)) {
1592
1600
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Wrong parameter command in /api/command' });
1593
1601
  return;
@@ -1618,19 +1626,16 @@ export class Frontend extends EventEmitter {
1618
1626
  }
1619
1627
  if (isValidArray(config.blackList, 1)) {
1620
1628
  if (select === 'serial' && config.blackList.includes(data.params.serial)) {
1621
- config.blackList = config.blackList.filter((item) => item !== data.params.serial);
1629
+ config.blackList = config.blackList.filter((item) => item !== localData.params.serial);
1622
1630
  }
1623
1631
  else if (select === 'name' && config.blackList.includes(data.params.name)) {
1624
- config.blackList = config.blackList.filter((item) => item !== data.params.name);
1632
+ config.blackList = config.blackList.filter((item) => item !== localData.params.name);
1625
1633
  }
1626
1634
  }
1627
1635
  if (plugin.platform)
1628
1636
  plugin.platform.config = config;
1629
1637
  plugin.configJson = config;
1630
- const restartRequired = plugin.restartRequired;
1631
1638
  await this.matterbridge.plugins.saveConfigFromPlugin(plugin, true);
1632
- if (!restartRequired)
1633
- this.wssSendRefreshRequired('pluginsRestart');
1634
1639
  this.wssSendRestartRequired(false);
1635
1640
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
1636
1641
  }
@@ -1657,10 +1662,10 @@ export class Frontend extends EventEmitter {
1657
1662
  }
1658
1663
  if (isValidArray(config.whiteList, 1)) {
1659
1664
  if (select === 'serial' && config.whiteList.includes(data.params.serial)) {
1660
- config.whiteList = config.whiteList.filter((item) => item !== data.params.serial);
1665
+ config.whiteList = config.whiteList.filter((item) => item !== localData.params.serial);
1661
1666
  }
1662
1667
  else if (select === 'name' && config.whiteList.includes(data.params.name)) {
1663
- config.whiteList = config.whiteList.filter((item) => item !== data.params.name);
1668
+ config.whiteList = config.whiteList.filter((item) => item !== localData.params.name);
1664
1669
  }
1665
1670
  }
1666
1671
  if (isValidArray(config.blackList)) {
@@ -1674,10 +1679,7 @@ export class Frontend extends EventEmitter {
1674
1679
  if (plugin.platform)
1675
1680
  plugin.platform.config = config;
1676
1681
  plugin.configJson = config;
1677
- const restartRequired = plugin.restartRequired;
1678
1682
  await this.matterbridge.plugins.saveConfigFromPlugin(plugin, true);
1679
- if (!restartRequired)
1680
- this.wssSendRefreshRequired('pluginsRestart');
1681
1683
  this.wssSendRestartRequired(false);
1682
1684
  sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, success: true });
1683
1685
  }
@@ -1688,8 +1690,9 @@ export class Frontend extends EventEmitter {
1688
1690
  }
1689
1691
  }
1690
1692
  else {
1691
- this.log.error(`Invalid method from websocket client: ${debugStringify(data)}`);
1692
- sendResponse({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Invalid method' });
1693
+ const localData = data;
1694
+ this.log.error(`Invalid method from websocket client: ${debugStringify(localData)}`);
1695
+ sendResponse({ id: localData.id, method: localData.method, src: 'Matterbridge', dst: localData.src, error: 'Invalid method' });
1693
1696
  }
1694
1697
  }
1695
1698
  catch (error) {
@@ -1719,7 +1722,7 @@ export class Frontend extends EventEmitter {
1719
1722
  .join(' ');
1720
1723
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'log', params: { level, time, name, message } });
1721
1724
  }
1722
- wssSendRefreshRequired(changed = null, params) {
1725
+ wssSendRefreshRequired(changed, params) {
1723
1726
  this.log.debug('Sending a refresh required message to all connected clients');
1724
1727
  this.wssBroadcastMessage({ id: 1, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', params: { changed, ...params } });
1725
1728
  }
@@ -1746,7 +1749,7 @@ export class Frontend extends EventEmitter {
1746
1749
  wssSendCpuUpdate(cpuUsage) {
1747
1750
  if (hasParameter('debug'))
1748
1751
  this.log.debug('Sending a cpu update message to all connected clients');
1749
- this.wssBroadcastMessage({ id: 4, src: 'Matterbridge', dst: 'Frontend', method: 'cpu_update', params: { cpuUsage } });
1752
+ this.wssBroadcastMessage({ id: 4, src: 'Matterbridge', dst: 'Frontend', method: 'cpu_update', params: { cpuUsage: Math.round(cpuUsage * 100) / 100 } });
1750
1753
  }
1751
1754
  wssSendMemoryUpdate(totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers) {
1752
1755
  if (hasParameter('debug'))
@@ -51,14 +51,6 @@ export class Matterbridge extends EventEmitter {
51
51
  matterbridgeVersion: '',
52
52
  matterbridgeLatestVersion: '',
53
53
  matterbridgeDevVersion: '',
54
- matterbridgeSerialNumber: '',
55
- matterbridgeQrPairingCode: undefined,
56
- matterbridgeManualPairingCode: undefined,
57
- matterbridgeFabricInformations: [],
58
- matterbridgeSessionInformations: [],
59
- matterbridgePaired: false,
60
- matterbridgeAdvertise: false,
61
- matterbridgeEndAdvertise: false,
62
54
  bridgeMode: '',
63
55
  restartMode: '',
64
56
  virtualMode: 'outlet',
@@ -71,9 +63,9 @@ export class Matterbridge extends EventEmitter {
71
63
  fileLogger: false,
72
64
  matterLoggerLevel: MatterLogLevel.INFO,
73
65
  matterFileLogger: false,
74
- mattermdnsinterface: undefined,
75
- matteripv4address: undefined,
76
- matteripv6address: undefined,
66
+ matterMdnsInterface: undefined,
67
+ matterIpv4Address: undefined,
68
+ matterIpv6Address: undefined,
77
69
  matterPort: 5540,
78
70
  matterDiscriminator: undefined,
79
71
  matterPasscode: undefined,
@@ -112,7 +104,6 @@ export class Matterbridge extends EventEmitter {
112
104
  checkUpdateTimeout;
113
105
  configureTimeout;
114
106
  reachabilityTimeout;
115
- endAdvertiseTimeout;
116
107
  sigintHandler;
117
108
  sigtermHandler;
118
109
  exceptionHandler;
@@ -673,7 +664,6 @@ export class Matterbridge extends EventEmitter {
673
664
  await storageContext?.set('serialNumber', this.aggregatorSerialNumber);
674
665
  if (this.aggregatorUniqueId)
675
666
  await storageContext?.set('uniqueId', this.aggregatorUniqueId);
676
- this.matterbridgeInformation.matterbridgeSerialNumber = this.aggregatorSerialNumber;
677
667
  }
678
668
  }
679
669
  catch (error) {
@@ -1253,7 +1243,6 @@ export class Matterbridge extends EventEmitter {
1253
1243
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1254
1244
  if (this.aggregatorNode)
1255
1245
  this.setAggregatorReachability(this.aggregatorNode, true);
1256
- this.frontend.wssSendRefreshRequired('reachability');
1257
1246
  }, 60 * 1000).unref();
1258
1247
  this.emit('bridge_started');
1259
1248
  this.log.notice('Matterbridge bridge started successfully');
@@ -1342,7 +1331,6 @@ export class Matterbridge extends EventEmitter {
1342
1331
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${nf} type ${plugin.type} server node ${plugin.serverNode !== undefined} aggregator node ${plugin.aggregatorNode !== undefined} device ${plugin.device !== undefined}`);
1343
1332
  if (plugin.type === 'DynamicPlatform' && plugin.aggregatorNode)
1344
1333
  this.setAggregatorReachability(plugin.aggregatorNode, true);
1345
- this.frontend.wssSendRefreshRequired('reachability');
1346
1334
  }, 60 * 1000).unref();
1347
1335
  }
1348
1336
  for (const device of this.devices.array()) {
@@ -1364,7 +1352,6 @@ export class Matterbridge extends EventEmitter {
1364
1352
  this.matterStorageManager = await this.matterStorageService.open('Matterbridge');
1365
1353
  this.log.info('Matter node storage manager "Matterbridge" created');
1366
1354
  this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId);
1367
- this.matterbridgeInformation.matterbridgeSerialNumber = await this.matterbridgeContext.get('serialNumber', '');
1368
1355
  this.log.info('Matter node storage started');
1369
1356
  await this.backupMatterStorage(path.join(this.matterbridgeDirectory, this.matterStorageName), path.join(this.matterbridgeDirectory, this.matterStorageName + '.backup'));
1370
1357
  }
@@ -1470,21 +1457,29 @@ export class Matterbridge extends EventEmitter {
1470
1457
  });
1471
1458
  serverNode.lifecycle.commissioned.on(() => {
1472
1459
  this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`);
1473
- clearTimeout(this.endAdvertiseTimeout);
1460
+ this.advertisingNodes.delete(storeId);
1461
+ this.frontend.wssSendRefreshRequired('settings');
1462
+ this.frontend.wssSendRefreshRequired('plugins');
1463
+ this.frontend.wssSendRefreshRequired('devices');
1464
+ this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
1474
1465
  });
1475
1466
  serverNode.lifecycle.decommissioned.on(() => {
1476
1467
  this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`);
1477
- clearTimeout(this.endAdvertiseTimeout);
1468
+ this.advertisingNodes.delete(storeId);
1469
+ this.frontend.wssSendRefreshRequired('settings');
1470
+ this.frontend.wssSendRefreshRequired('plugins');
1471
+ this.frontend.wssSendRefreshRequired('devices');
1472
+ this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
1473
+ this.frontend.wssSendSnackbarMessage(`${storeId} is offline`, 5, 'warning');
1478
1474
  });
1479
1475
  serverNode.lifecycle.online.on(async () => {
1480
1476
  this.log.notice(`Server node for ${storeId} is online`);
1481
1477
  if (!serverNode.lifecycle.isCommissioned) {
1482
1478
  this.log.notice(`Server node for ${storeId} is not commissioned. Pair to commission ...`);
1479
+ this.advertisingNodes.set(storeId, Date.now());
1483
1480
  const { qrPairingCode, manualPairingCode } = serverNode.state.commissioning.pairingCodes;
1484
1481
  this.log.notice(`QR Code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=${qrPairingCode}`);
1485
1482
  this.log.notice(`Manual pairing code: ${manualPairingCode}`);
1486
- this.startEndAdvertiseTimer(serverNode);
1487
- this.advertisingNodes.set(storeId, Date.now());
1488
1483
  }
1489
1484
  else {
1490
1485
  this.log.notice(`Server node for ${storeId} is already commissioned. Waiting for controllers to connect ...`);
@@ -1498,7 +1493,6 @@ export class Matterbridge extends EventEmitter {
1498
1493
  });
1499
1494
  serverNode.lifecycle.offline.on(() => {
1500
1495
  this.log.notice(`Server node for ${storeId} is offline`);
1501
- this.matterbridgeInformation.matterbridgeEndAdvertise = true;
1502
1496
  this.frontend.wssSendRefreshRequired('plugins');
1503
1497
  this.frontend.wssSendRefreshRequired('settings');
1504
1498
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
@@ -1510,9 +1504,6 @@ export class Matterbridge extends EventEmitter {
1510
1504
  switch (fabricAction) {
1511
1505
  case FabricAction.Added:
1512
1506
  this.advertisingNodes.delete(storeId);
1513
- clearTimeout(this.endAdvertiseTimeout);
1514
- this.endAdvertiseTimeout = undefined;
1515
- this.matterbridgeInformation.matterbridgeEndAdvertise = true;
1516
1507
  action = 'added';
1517
1508
  break;
1518
1509
  case FabricAction.Removed:
@@ -1523,46 +1514,23 @@ export class Matterbridge extends EventEmitter {
1523
1514
  break;
1524
1515
  }
1525
1516
  this.log.notice(`Commissioned fabric index ${fabricIndex} ${action} on server node for ${storeId}: ${debugStringify(serverNode.state.commissioning.fabrics[fabricIndex])}`);
1526
- this.frontend.wssSendRefreshRequired('fabrics');
1527
1517
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
1528
1518
  });
1529
1519
  serverNode.events.sessions.opened.on((session) => {
1530
1520
  this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
1531
- this.frontend.wssSendRefreshRequired('sessions');
1532
1521
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
1533
1522
  });
1534
1523
  serverNode.events.sessions.closed.on((session) => {
1535
1524
  this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
1536
- this.frontend.wssSendRefreshRequired('sessions');
1537
1525
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
1538
1526
  });
1539
1527
  serverNode.events.sessions.subscriptionsChanged.on((session) => {
1540
1528
  this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
1541
- this.frontend.wssSendRefreshRequired('sessions');
1542
1529
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
1543
1530
  });
1544
1531
  this.log.info(`Created server node for ${storeId}`);
1545
1532
  return serverNode;
1546
1533
  }
1547
- startEndAdvertiseTimer(matterServerNode) {
1548
- if (this.endAdvertiseTimeout) {
1549
- this.log.debug(`Clear ${matterServerNode.id} server node end advertise timer`);
1550
- clearTimeout(this.endAdvertiseTimeout);
1551
- }
1552
- this.log.debug(`Starting ${matterServerNode.id} server node end advertise timer`);
1553
- this.endAdvertiseTimeout = setTimeout(() => {
1554
- if (matterServerNode.lifecycle.isCommissioned)
1555
- return;
1556
- this.matterbridgeInformation.matterbridgeEndAdvertise = true;
1557
- this.frontend.wssSendRefreshRequired('plugins');
1558
- this.frontend.wssSendRefreshRequired('settings');
1559
- this.frontend.wssSendRefreshRequired('fabrics');
1560
- this.frontend.wssSendRefreshRequired('sessions');
1561
- this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(matterServerNode) } });
1562
- this.frontend.wssSendSnackbarMessage(`Advertising stopped.`, 0);
1563
- this.log.notice(`Advertising stopped.`);
1564
- }, 15 * 60 * 1000).unref();
1565
- }
1566
1534
  getServerNodeData(serverNode) {
1567
1535
  const advertiseTime = this.advertisingNodes.get(serverNode.id) || 0;
1568
1536
  return {
package/dist/update.js CHANGED
@@ -51,7 +51,6 @@ export async function getMatterbridgeLatestVersion(matterbridge) {
51
51
  if (matterbridge.matterbridgeVersion !== matterbridge.matterbridgeLatestVersion) {
52
52
  matterbridge.log.notice(`Matterbridge is out of date. Current version: ${matterbridge.matterbridgeVersion}. Latest version: ${matterbridge.matterbridgeLatestVersion}.`);
53
53
  matterbridge.frontend.wssSendSnackbarMessage('Matterbridge latest update available', 0, 'info');
54
- matterbridge.frontend.wssSendRefreshRequired('matterbridgeLatestVersion');
55
54
  matterbridge.frontend.wssSendUpdateRequired();
56
55
  }
57
56
  else {
@@ -73,7 +72,6 @@ export async function getMatterbridgeDevVersion(matterbridge) {
73
72
  if (matterbridge.matterbridgeVersion.includes('-dev-') && matterbridge.matterbridgeVersion !== version) {
74
73
  matterbridge.log.notice(`Matterbridge@dev is out of date. Current version: ${matterbridge.matterbridgeVersion}. Latest dev version: ${matterbridge.matterbridgeDevVersion}.`);
75
74
  matterbridge.frontend.wssSendSnackbarMessage('Matterbridge dev update available', 0, 'info');
76
- matterbridge.frontend.wssSendRefreshRequired('matterbridgeDevVersion');
77
75
  matterbridge.frontend.wssSendUpdateRequired(true);
78
76
  }
79
77
  else if (matterbridge.matterbridgeVersion.includes('-dev-') && matterbridge.matterbridgeVersion === version) {