matterbridge 3.0.1-dev-20250502-6d36575 → 3.0.1-dev-20250502-c002841

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -17,15 +17,17 @@ It is also available the official Matterbridge Home Assistant plugin https://git
17
17
 
18
18
  ### Added
19
19
 
20
- - [docker]: The builder for the **docker** image with tag **latest** will run each day at 00:00 UTC. Inside the image matterbridge and all plugins with the latest release (as published on npm) are already loaded. You can just pull the new image and matterbridge with all plugins will be the latest.
21
- - [docker]: The builder for the **docker** image with tag **dev** will run each day at 00:00 UTC. Inside the image matterbridge and all plugins with the dev release (as pushed on GitHub) are already loaded. You can just pull the new image and matterbridge with all plugins will be the latest dev (it is possible that the devs are outdated by published latests).
22
- - [npm]: The dev of matterbridge is published with tag **dev** on **npm** each day at 00:00 UTC if there is a new commit. It is possible that the dev is outdated by published latest.
20
+ - [docker]: The builder for the **docker** image with tag **latest** will run each day at 00:00 UTC if there are new releases. Inside the image matterbridge and all plugins with the latest release (as published on npm) are already loaded. You can just pull the new image and matterbridge with all plugins will be the latest.
21
+ - [docker]: The builder for the **docker** image with tag **dev** will run each day at 00:00 UTC if there are new commits. Inside the image matterbridge and all plugins with the dev release (as pushed on GitHub) are already loaded. You can just pull the new image and matterbridge with all plugins will be the latest dev. It is possible that the devs are outdated by some published latests.
22
+ - [npm]: The dev of matterbridge is published with tag **dev** on **npm** each day at 00:00 UTC if there is a new commit. It is possible that the dev is outdated by a published latest.
23
23
  - [frontend]: Added closeSnackbarMessage() to remove the notification with timeout = 0.
24
- - [frontend]: Moved plugin actions from express to web socket.
24
+ - [frontend]: Moved all plugin actions from express to web socket.
25
+ - [frontend]: Moved all config from express to web socket.
25
26
 
26
27
  ### Changed
27
28
 
28
29
  - [docker]: Updated the [Docker configurations](README-DOCKER.md).
30
+ - [frontend]: Changing configuration for a plugin now only lock configuration on that plugin.
29
31
 
30
32
  ## [3.0.0] - 2025-04-29
31
33
 
package/README-DOCKER.md CHANGED
@@ -22,6 +22,8 @@ The image (tag **latest**) includes matterbridge and all plugins with the latest
22
22
 
23
23
  The image (tag **dev**) includes matterbridge and all plugins with the dev release (as pushed on GitHub). You can just pull the new image and matterbridge with all plugins will be the latest release pushed on GitHub. It is possible that the devs are outdated by published latests.
24
24
 
25
+ You can directly select and add a plugin without installing it.
26
+
25
27
  It is based on node:22-bookworm-slim and integrates the health check.
26
28
 
27
29
  How Health Checks Work in Different Scenarios
package/dist/frontend.js CHANGED
@@ -413,192 +413,6 @@ export class Frontend {
413
413
  }
414
414
  });
415
415
  });
416
- this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
417
- const command = req.params.command;
418
- let param = req.params.param;
419
- this.log.debug(`The frontend sent /api/command/${command}/${param}`);
420
- if (!command) {
421
- res.status(400).json({ error: 'No command provided' });
422
- return;
423
- }
424
- this.log.debug(`Received frontend command: ${command}:${param}`);
425
- if (command === 'setpassword') {
426
- const password = param.slice(1, -1);
427
- this.log.debug('setpassword', param, password);
428
- await this.matterbridge.nodeContext?.set('password', password);
429
- res.json({ message: 'Command received' });
430
- return;
431
- }
432
- if (command === 'setbridgemode') {
433
- this.log.debug(`setbridgemode: ${param}`);
434
- this.wssSendRestartRequired();
435
- await this.matterbridge.nodeContext?.set('bridgeMode', param);
436
- res.json({ message: 'Command received' });
437
- return;
438
- }
439
- if (command === 'backup') {
440
- this.log.notice(`Prepairing the backup...`);
441
- await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridge.matterbridgeDirectory), path.join(this.matterbridge.matterbridgePluginDirectory));
442
- this.log.notice(`Backup ready to be downloaded.`);
443
- this.wssSendSnackbarMessage('Backup ready to be downloaded', 10);
444
- res.json({ message: 'Command received' });
445
- return;
446
- }
447
- if (command === 'setmbloglevel') {
448
- this.log.debug('Matterbridge log level:', param);
449
- if (param === 'Debug') {
450
- this.log.logLevel = "debug";
451
- }
452
- else if (param === 'Info') {
453
- this.log.logLevel = "info";
454
- }
455
- else if (param === 'Notice') {
456
- this.log.logLevel = "notice";
457
- }
458
- else if (param === 'Warn') {
459
- this.log.logLevel = "warn";
460
- }
461
- else if (param === 'Error') {
462
- this.log.logLevel = "error";
463
- }
464
- else if (param === 'Fatal') {
465
- this.log.logLevel = "fatal";
466
- }
467
- await this.matterbridge.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
468
- await this.matterbridge.setLogLevel(this.log.logLevel);
469
- res.json({ message: 'Command received' });
470
- return;
471
- }
472
- if (command === 'setmjloglevel') {
473
- this.log.debug('Matter.js log level:', param);
474
- if (param === 'Debug') {
475
- Logger.defaultLogLevel = MatterLogLevel.DEBUG;
476
- }
477
- else if (param === 'Info') {
478
- Logger.defaultLogLevel = MatterLogLevel.INFO;
479
- }
480
- else if (param === 'Notice') {
481
- Logger.defaultLogLevel = MatterLogLevel.NOTICE;
482
- }
483
- else if (param === 'Warn') {
484
- Logger.defaultLogLevel = MatterLogLevel.WARN;
485
- }
486
- else if (param === 'Error') {
487
- Logger.defaultLogLevel = MatterLogLevel.ERROR;
488
- }
489
- else if (param === 'Fatal') {
490
- Logger.defaultLogLevel = MatterLogLevel.FATAL;
491
- }
492
- await this.matterbridge.nodeContext?.set('matterLogLevel', Logger.defaultLogLevel);
493
- res.json({ message: 'Command received' });
494
- return;
495
- }
496
- if (command === 'setmdnsinterface') {
497
- if (param === 'json' && isValidString(req.body.value)) {
498
- this.matterbridge.matterbridgeInformation.mattermdnsinterface = req.body.value;
499
- this.log.debug(`Matter.js mdns interface: ${req.body.value === '' ? 'all interfaces' : req.body.value}`);
500
- await this.matterbridge.nodeContext?.set('mattermdnsinterface', req.body.value);
501
- }
502
- res.json({ message: 'Command received' });
503
- return;
504
- }
505
- if (command === 'setipv4address') {
506
- if (param === 'json' && isValidString(req.body.value)) {
507
- this.log.debug(`Matter.js ipv4 address: ${req.body.value === '' ? 'all ipv4 addresses' : req.body.value}`);
508
- this.matterbridge.matterbridgeInformation.matteripv4address = req.body.value;
509
- await this.matterbridge.nodeContext?.set('matteripv4address', req.body.value);
510
- }
511
- res.json({ message: 'Command received' });
512
- return;
513
- }
514
- if (command === 'setipv6address') {
515
- if (param === 'json' && isValidString(req.body.value)) {
516
- this.log.debug(`Matter.js ipv6 address: ${req.body.value === '' ? 'all ipv6 addresses' : req.body.value}`);
517
- this.matterbridge.matterbridgeInformation.matteripv6address = req.body.value;
518
- await this.matterbridge.nodeContext?.set('matteripv6address', req.body.value);
519
- }
520
- res.json({ message: 'Command received' });
521
- return;
522
- }
523
- if (command === 'setmatterport') {
524
- const port = Math.min(Math.max(parseInt(req.body.value), 5540), 5560);
525
- this.matterbridge.matterbridgeInformation.matterPort = port;
526
- this.log.debug(`Set matter commissioning port to ${CYAN}${port}${db}`);
527
- await this.matterbridge.nodeContext?.set('matterport', port);
528
- res.json({ message: 'Command received' });
529
- return;
530
- }
531
- if (command === 'setmatterdiscriminator') {
532
- const discriminator = Math.min(Math.max(parseInt(req.body.value), 1000), 4095);
533
- this.matterbridge.matterbridgeInformation.matterDiscriminator = discriminator;
534
- this.log.debug(`Set matter commissioning discriminator to ${CYAN}${discriminator}${db}`);
535
- await this.matterbridge.nodeContext?.set('matterdiscriminator', discriminator);
536
- res.json({ message: 'Command received' });
537
- return;
538
- }
539
- if (command === 'setmatterpasscode') {
540
- const passcode = Math.min(Math.max(parseInt(req.body.value), 10000000), 90000000);
541
- this.matterbridge.matterbridgeInformation.matterPasscode = passcode;
542
- this.log.debug(`Set matter commissioning passcode to ${CYAN}${passcode}${db}`);
543
- await this.matterbridge.nodeContext?.set('matterpasscode', passcode);
544
- res.json({ message: 'Command received' });
545
- return;
546
- }
547
- if (command === 'setmblogfile') {
548
- this.log.debug('Matterbridge file log:', param);
549
- this.matterbridge.matterbridgeInformation.fileLogger = param === 'true';
550
- await this.matterbridge.nodeContext?.set('matterbridgeFileLog', param === 'true');
551
- if (param === 'true')
552
- AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug", true);
553
- else
554
- AnsiLogger.setGlobalLogfile(undefined);
555
- res.json({ message: 'Command received' });
556
- return;
557
- }
558
- if (command === 'setmjlogfile') {
559
- this.log.debug('Matter file log:', param);
560
- this.matterbridge.matterbridgeInformation.matterFileLogger = param === 'true';
561
- await this.matterbridge.nodeContext?.set('matterFileLog', param === 'true');
562
- if (param === 'true') {
563
- try {
564
- Logger.addLogger('matterfilelogger', await this.matterbridge.createMatterFileLogger(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), true), {
565
- defaultLogLevel: MatterLogLevel.DEBUG,
566
- logFormat: MatterLogFormat.PLAIN,
567
- });
568
- }
569
- catch (error) {
570
- this.log.debug(`Error adding the matterfilelogger for file ${CYAN}${path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
571
- }
572
- }
573
- else {
574
- try {
575
- Logger.removeLogger('matterfilelogger');
576
- }
577
- catch (error) {
578
- this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
579
- }
580
- }
581
- res.json({ message: 'Command received' });
582
- return;
583
- }
584
- if (command === 'saveconfig') {
585
- param = param.replace(/\*/g, '\\');
586
- this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
587
- if (!this.matterbridge.plugins.has(param)) {
588
- this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
589
- }
590
- else {
591
- const plugin = this.matterbridge.plugins.get(param);
592
- if (!plugin)
593
- return;
594
- this.matterbridge.plugins.saveConfigFromJson(plugin, req.body);
595
- this.wssSendSnackbarMessage(`Saved config for plugin ${param}`);
596
- this.wssSendRestartRequired();
597
- }
598
- res.json({ message: 'Command received' });
599
- return;
600
- }
601
- });
602
416
  this.expressApp.post('/api/uploadpackage', upload.single('file'), async (req, res) => {
603
417
  const { filename } = req.body;
604
418
  const file = req.file;
@@ -607,7 +421,7 @@ export class Frontend {
607
421
  res.status(400).send('Invalid request: file and filename are required');
608
422
  return;
609
423
  }
610
- this.wssSendSnackbarMessage(`Installing package ${filename}. Please wait...`);
424
+ this.wssSendSnackbarMessage(`Installing package ${filename}. Please wait...`, 0);
611
425
  const filePath = path.join(this.matterbridge.matterbridgeDirectory, 'uploads', filename);
612
426
  try {
613
427
  await fs.rename(file.path, filePath);
@@ -615,6 +429,7 @@ export class Frontend {
615
429
  if (filename.endsWith('.tgz')) {
616
430
  await this.matterbridge.spawnCommand('npm', ['install', '-g', filePath, '--omit=dev', '--verbose']);
617
431
  this.log.info(`Plugin package ${plg}${filename}${nf} installed successfully. Full restart required.`);
432
+ this.wssSendCloseSnackbarMessage(`Installing package ${filename}. Please wait...`);
618
433
  this.wssSendSnackbarMessage(`Installed package ${filename}`, 10, 'success');
619
434
  this.wssSendRestartRequired();
620
435
  res.send(`Plugin package ${filename} uploaded and installed successfully`);
@@ -624,6 +439,7 @@ export class Frontend {
624
439
  }
625
440
  catch (err) {
626
441
  this.log.error(`Error uploading or installing plugin package file ${plg}${filename}${er}:`, err);
442
+ this.wssSendCloseSnackbarMessage(`Installing package ${filename}. Please wait...`);
627
443
  this.wssSendSnackbarMessage(`Error uploading or installing plugin package ${filename}`, 10, 'error');
628
444
  res.status(500).send(`Error uploading or installing plugin package ${filename}`);
629
445
  }
@@ -911,6 +727,7 @@ export class Frontend {
911
727
  started: plugin.started,
912
728
  configured: plugin.configured,
913
729
  paired: plugin.paired,
730
+ restartRequired: plugin.restartRequired,
914
731
  fabricInformations: plugin.fabricInformations,
915
732
  sessionInformations: plugin.sessionInformations,
916
733
  registeredDevices: plugin.registeredDevices,
@@ -1026,7 +843,6 @@ export class Frontend {
1026
843
  this.wssSendCloseSnackbarMessage(`Installing package ${data.params.packageName}...`);
1027
844
  this.wssSendSnackbarMessage(`Package ${data.params.packageName} not installed`, 10, 'error');
1028
845
  });
1029
- return;
1030
846
  }
1031
847
  else if (data.method === '/api/uninstall') {
1032
848
  if (!isValidString(data.params.packageName, 10)) {
@@ -1130,51 +946,63 @@ export class Frontend {
1130
946
  this.wssSendRefreshRequired('plugins');
1131
947
  this.wssSendRefreshRequired('devices');
1132
948
  }
949
+ else if (data.method === '/api/savepluginconfig') {
950
+ if (!isValidString(data.params.pluginName, 10) || !this.matterbridge.plugins.has(data.params.pluginName)) {
951
+ client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Wrong parameter pluginName in /api/savepluginconfig' }));
952
+ return;
953
+ }
954
+ if (!isValidObject(data.params.formData, 5)) {
955
+ client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Wrong parameter formData in /api/savepluginconfig' }));
956
+ return;
957
+ }
958
+ this.log.info(`Saving config for plugin ${plg}${data.params.pluginName}${nf}...`);
959
+ const plugin = this.matterbridge.plugins.get(data.params.pluginName);
960
+ if (!plugin) {
961
+ this.log.warn(`Plugin ${plg}${data.params.pluginName}${wr} not found in matterbridge`);
962
+ }
963
+ else {
964
+ this.matterbridge.plugins.saveConfigFromJson(plugin, data.params.formData);
965
+ this.wssSendSnackbarMessage(`Saved config for plugin ${data.params.pluginName}`);
966
+ this.wssSendRefreshRequired('plugins');
967
+ this.wssSendRestartRequired();
968
+ }
969
+ }
1133
970
  else if (data.method === '/api/shellysysupdate') {
1134
971
  const { triggerShellySysUpdate } = await import('./shelly.js');
1135
972
  triggerShellySysUpdate(this.matterbridge);
1136
- return;
1137
973
  }
1138
974
  else if (data.method === '/api/shellymainupdate') {
1139
975
  const { triggerShellyMainUpdate } = await import('./shelly.js');
1140
976
  triggerShellyMainUpdate(this.matterbridge);
1141
- return;
1142
977
  }
1143
978
  else if (data.method === '/api/shellycreatesystemlog') {
1144
979
  const { createShellySystemLog } = await import('./shelly.js');
1145
980
  createShellySystemLog(this.matterbridge);
1146
- return;
1147
981
  }
1148
982
  else if (data.method === '/api/shellynetconfig') {
1149
983
  this.log.debug('/api/shellynetconfig:', data.params);
1150
984
  const { triggerShellyChangeIp: triggerShellyChangeNet } = await import('./shelly.js');
1151
985
  triggerShellyChangeNet(this.matterbridge, data.params);
1152
- return;
1153
986
  }
1154
987
  else if (data.method === '/api/softreset') {
1155
988
  const { triggerShellySoftReset } = await import('./shelly.js');
1156
989
  triggerShellySoftReset(this.matterbridge);
1157
- return;
1158
990
  }
1159
991
  else if (data.method === '/api/hardreset') {
1160
992
  const { triggerShellyHardReset } = await import('./shelly.js');
1161
993
  triggerShellyHardReset(this.matterbridge);
1162
- return;
1163
994
  }
1164
995
  else if (data.method === '/api/reboot') {
1165
996
  const { triggerShellyReboot } = await import('./shelly.js');
1166
997
  triggerShellyReboot(this.matterbridge);
1167
- return;
1168
998
  }
1169
999
  else if (data.method === '/api/restart') {
1170
1000
  this.wssSendSnackbarMessage(`Restarting matterbridge...`, 0);
1171
1001
  await this.matterbridge.restartProcess();
1172
- return;
1173
1002
  }
1174
1003
  else if (data.method === '/api/shutdown') {
1175
1004
  this.wssSendSnackbarMessage(`Shutting down matterbridge...`, 0);
1176
1005
  await this.matterbridge.shutdownProcess();
1177
- return;
1178
1006
  }
1179
1007
  else if (data.method === '/api/create-backup') {
1180
1008
  this.wssSendSnackbarMessage('Creating backup...', 0);
@@ -1204,7 +1032,6 @@ export class Frontend {
1204
1032
  this.wssSendRefreshRequired('matterbridgeAdvertise');
1205
1033
  this.wssSendSnackbarMessage(`Started fabrics share`, 0);
1206
1034
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: pairingCodes }));
1207
- return;
1208
1035
  }
1209
1036
  else if (data.method === '/api/stopadvertise') {
1210
1037
  await this.matterbridge.stopAdvertiseServerNode(this.matterbridge.serverNode);
@@ -1212,21 +1039,17 @@ export class Frontend {
1212
1039
  this.wssSendRefreshRequired('matterbridgeAdvertise');
1213
1040
  this.wssSendSnackbarMessage(`Stopped fabrics share`, 0);
1214
1041
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src }));
1215
- return;
1216
1042
  }
1217
1043
  else if (data.method === '/api/settings') {
1218
1044
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: await this.getApiSettings() }));
1219
- return;
1220
1045
  }
1221
1046
  else if (data.method === '/api/plugins') {
1222
1047
  const response = this.getBaseRegisteredPlugins();
1223
1048
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response }));
1224
- return;
1225
1049
  }
1226
1050
  else if (data.method === '/api/devices') {
1227
1051
  const devices = await this.getDevices(isValidString(data.params.pluginName) ? data.params.pluginName : undefined);
1228
1052
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: devices }));
1229
- return;
1230
1053
  }
1231
1054
  else if (data.method === '/api/clusters') {
1232
1055
  if (!isValidString(data.params.plugin, 10)) {
@@ -1333,7 +1156,6 @@ export class Frontend {
1333
1156
  });
1334
1157
  });
1335
1158
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, plugin: data.params.plugin, deviceName, serialNumber, endpoint: data.params.endpoint, deviceTypes, response: clusters }));
1336
- return;
1337
1159
  }
1338
1160
  else if (data.method === '/api/select' || data.method === '/api/select/devices') {
1339
1161
  if (!isValidString(data.params.plugin, 10)) {
@@ -1347,7 +1169,6 @@ export class Frontend {
1347
1169
  }
1348
1170
  const selectDeviceValues = plugin.platform?.getSelectDevices().sort((keyA, keyB) => keyA.name.localeCompare(keyB.name));
1349
1171
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, plugin: data.params.plugin, response: selectDeviceValues }));
1350
- return;
1351
1172
  }
1352
1173
  else if (data.method === '/api/select/entities') {
1353
1174
  if (!isValidString(data.params.plugin, 10)) {
@@ -1361,7 +1182,6 @@ export class Frontend {
1361
1182
  }
1362
1183
  const selectEntityValues = plugin.platform?.getSelectEntities().sort((keyA, keyB) => keyA.name.localeCompare(keyB.name));
1363
1184
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, plugin: data.params.plugin, response: selectEntityValues }));
1364
- return;
1365
1185
  }
1366
1186
  else if (data.method === '/api/action') {
1367
1187
  if (!isValidString(data.params.plugin, 5) || !isValidString(data.params.action, 1)) {
@@ -1378,6 +1198,185 @@ export class Frontend {
1378
1198
  this.log.error(`Error in plugin ${plugin.name} action ${data.params.action}: ${error}`);
1379
1199
  });
1380
1200
  }
1201
+ else if (data.method === '/api/config') {
1202
+ if (!isValidString(data.params.name, 5) || data.params.value === undefined) {
1203
+ client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Wrong parameter in /api/config' }));
1204
+ return;
1205
+ }
1206
+ this.log.debug(`Received /api/config name ${CYAN}${data.params.name}${db} value ${CYAN}${data.params.value}${db}`);
1207
+ this.log.fatal(`Received /api/config name ${CYAN}${data.params.name}${db} value(${typeof data.params.value}) ${CYAN}${data.params.value}${db}`);
1208
+ switch (data.params.name) {
1209
+ case 'setpassword':
1210
+ if (isValidString(data.params.value)) {
1211
+ await this.matterbridge.nodeContext?.set('password', data.params.value);
1212
+ }
1213
+ break;
1214
+ case 'setbridgemode':
1215
+ if (isValidString(data.params.value, 5)) {
1216
+ await this.matterbridge.nodeContext?.set('bridgeMode', data.params.value);
1217
+ this.wssSendRestartRequired();
1218
+ }
1219
+ break;
1220
+ case 'setmbloglevel':
1221
+ if (isValidString(data.params.value, 4)) {
1222
+ this.log.debug('Matterbridge logger level:', data.params.value);
1223
+ if (data.params.value === 'Debug') {
1224
+ await this.matterbridge.setLogLevel("debug");
1225
+ }
1226
+ else if (data.params.value === 'Info') {
1227
+ await this.matterbridge.setLogLevel("info");
1228
+ }
1229
+ else if (data.params.value === 'Notice') {
1230
+ await this.matterbridge.setLogLevel("notice");
1231
+ }
1232
+ else if (data.params.value === 'Warn') {
1233
+ await this.matterbridge.setLogLevel("warn");
1234
+ }
1235
+ else if (data.params.value === 'Error') {
1236
+ await this.matterbridge.setLogLevel("error");
1237
+ }
1238
+ else if (data.params.value === 'Fatal') {
1239
+ await this.matterbridge.setLogLevel("fatal");
1240
+ }
1241
+ await this.matterbridge.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
1242
+ }
1243
+ break;
1244
+ case 'setmblogfile':
1245
+ if (isValidBoolean(data.params.value)) {
1246
+ this.log.debug('Matterbridge file log:', data.params.value);
1247
+ this.matterbridge.matterbridgeInformation.fileLogger = data.params.value;
1248
+ await this.matterbridge.nodeContext?.set('matterbridgeFileLog', data.params.value);
1249
+ if (data.params.value)
1250
+ AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), this.matterbridge.matterbridgeInformation.loggerLevel, true);
1251
+ else
1252
+ AnsiLogger.setGlobalLogfile(undefined);
1253
+ }
1254
+ break;
1255
+ case 'setmjloglevel':
1256
+ if (isValidString(data.params.value, 4)) {
1257
+ this.log.debug('Matter logger level:', data.params.value);
1258
+ if (data.params.value === 'Debug') {
1259
+ Logger.level = MatterLogLevel.DEBUG;
1260
+ }
1261
+ else if (data.params.value === 'Info') {
1262
+ Logger.level = MatterLogLevel.INFO;
1263
+ }
1264
+ else if (data.params.value === 'Notice') {
1265
+ Logger.level = MatterLogLevel.NOTICE;
1266
+ }
1267
+ else if (data.params.value === 'Warn') {
1268
+ Logger.level = MatterLogLevel.WARN;
1269
+ }
1270
+ else if (data.params.value === 'Error') {
1271
+ Logger.level = MatterLogLevel.ERROR;
1272
+ }
1273
+ else if (data.params.value === 'Fatal') {
1274
+ Logger.level = MatterLogLevel.FATAL;
1275
+ }
1276
+ this.matterbridge.matterbridgeInformation.matterLoggerLevel = Logger.level;
1277
+ await this.matterbridge.nodeContext?.set('matterLogLevel', Logger.level);
1278
+ }
1279
+ break;
1280
+ case 'setmjlogfile':
1281
+ if (isValidBoolean(data.params.value)) {
1282
+ this.log.debug('Matter file log:', data.params.value);
1283
+ this.matterbridge.matterbridgeInformation.matterFileLogger = data.params.value;
1284
+ await this.matterbridge.nodeContext?.set('matterFileLog', data.params.value);
1285
+ if (data.params.value) {
1286
+ try {
1287
+ Logger.addLogger('matterfilelogger', await this.matterbridge.createMatterFileLogger(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), true), {
1288
+ defaultLogLevel: this.matterbridge.matterbridgeInformation.matterLoggerLevel,
1289
+ logFormat: MatterLogFormat.PLAIN,
1290
+ });
1291
+ }
1292
+ catch (error) {
1293
+ this.log.debug(`Error adding the matterfilelogger for file ${CYAN}${path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
1294
+ }
1295
+ }
1296
+ else {
1297
+ try {
1298
+ Logger.removeLogger('matterfilelogger');
1299
+ }
1300
+ catch (error) {
1301
+ this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
1302
+ }
1303
+ }
1304
+ }
1305
+ break;
1306
+ case 'setmdnsinterface':
1307
+ if (isValidString(data.params.value)) {
1308
+ this.log.debug(`Matter.js mdns interface: ${data.params.value === '' ? 'all interfaces' : data.params.value}`);
1309
+ this.matterbridge.mdnsInterface = data.params.value === '' ? undefined : data.params.value;
1310
+ this.matterbridge.matterbridgeInformation.mattermdnsinterface = this.matterbridge.mdnsInterface;
1311
+ await this.matterbridge.nodeContext?.set('mattermdnsinterface', data.params.value);
1312
+ this.wssSendRestartRequired();
1313
+ }
1314
+ break;
1315
+ case 'setipv4address':
1316
+ if (isValidString(data.params.value)) {
1317
+ this.log.debug(`Matter.js ipv4 address: ${data.params.value === '' ? 'all ipv4 addresses' : data.params.value}`);
1318
+ this.matterbridge.ipv4address = data.params.value === '' ? undefined : data.params.value;
1319
+ this.matterbridge.matterbridgeInformation.matteripv4address = this.matterbridge.ipv4address;
1320
+ await this.matterbridge.nodeContext?.set('matteripv4address', data.params.value);
1321
+ this.wssSendRestartRequired();
1322
+ }
1323
+ break;
1324
+ case 'setipv6address':
1325
+ if (isValidString(data.params.value)) {
1326
+ this.log.debug(`Matter.js ipv6 address: ${data.params.value === '' ? 'all ipv6 addresses' : data.params.value}`);
1327
+ this.matterbridge.ipv6address = data.params.value === '' ? undefined : data.params.value;
1328
+ this.matterbridge.matterbridgeInformation.matteripv6address = this.matterbridge.ipv6address;
1329
+ await this.matterbridge.nodeContext?.set('matteripv6address', data.params.value);
1330
+ this.wssSendRestartRequired();
1331
+ }
1332
+ break;
1333
+ case 'setmatterport':
1334
+ data.params.value = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
1335
+ if (isValidNumber(data.params.value, 5540, 5580)) {
1336
+ this.log.debug(`Set matter commissioning port to ${CYAN}${data.params.value}${db}`);
1337
+ this.matterbridge.matterbridgeInformation.matterPort = data.params.value;
1338
+ await this.matterbridge.nodeContext?.set('matterport', data.params.value);
1339
+ this.wssSendRestartRequired();
1340
+ }
1341
+ else {
1342
+ this.log.debug(`Reset matter commissioning port to ${CYAN}5040${db}`);
1343
+ this.matterbridge.matterbridgeInformation.matterPort = 5040;
1344
+ await this.matterbridge.nodeContext?.set('matterport', 5040);
1345
+ this.wssSendRestartRequired();
1346
+ }
1347
+ break;
1348
+ case 'setmatterdiscriminator':
1349
+ data.params.value = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
1350
+ if (isValidNumber(data.params.value, 1000, 4095)) {
1351
+ this.log.debug(`Set matter commissioning discriminator to ${CYAN}${data.params.value}${db}`);
1352
+ this.matterbridge.matterbridgeInformation.matterDiscriminator = data.params.value;
1353
+ await this.matterbridge.nodeContext?.set('matterdiscriminator', data.params.value);
1354
+ this.wssSendRestartRequired();
1355
+ }
1356
+ else {
1357
+ this.log.debug(`Reset matter commissioning discriminator to ${CYAN}undefined${db}`);
1358
+ this.matterbridge.matterbridgeInformation.matterDiscriminator = undefined;
1359
+ await this.matterbridge.nodeContext?.remove('matterdiscriminator');
1360
+ this.wssSendRestartRequired();
1361
+ }
1362
+ break;
1363
+ case 'setmatterpasscode':
1364
+ data.params.value = isValidString(data.params.value) ? parseInt(data.params.value) : 0;
1365
+ if (isValidNumber(data.params.value, 10000000, 90000000)) {
1366
+ this.matterbridge.matterbridgeInformation.matterPasscode = data.params.value;
1367
+ this.log.debug(`Set matter commissioning passcode to ${CYAN}${data.params.value}${db}`);
1368
+ await this.matterbridge.nodeContext?.set('matterpasscode', data.params.value);
1369
+ this.wssSendRestartRequired();
1370
+ }
1371
+ else {
1372
+ this.log.debug(`Reset matter commissioning passcode to ${CYAN}undefined${db}`);
1373
+ this.matterbridge.matterbridgeInformation.matterPasscode = undefined;
1374
+ await this.matterbridge.nodeContext?.remove('matterpasscode');
1375
+ this.wssSendRestartRequired();
1376
+ }
1377
+ break;
1378
+ }
1379
+ }
1381
1380
  else if (data.method === '/api/command') {
1382
1381
  if (!isValidString(data.params.command, 5)) {
1383
1382
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Wrong parameter command in /api/command' }));
@@ -1465,12 +1464,10 @@ export class Frontend {
1465
1464
  else {
1466
1465
  this.log.error(`Invalid method from websocket client: ${debugStringify(data)}`);
1467
1466
  client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Invalid method' }));
1468
- return;
1469
1467
  }
1470
1468
  }
1471
1469
  catch (error) {
1472
1470
  this.log.error(`Error parsing message "${message}" from websocket client:`, error instanceof Error ? error.message : error);
1473
- return;
1474
1471
  }
1475
1472
  }
1476
1473
  wssSendMessage(level, time, name, message) {
@@ -5,7 +5,7 @@ import EventEmitter from 'node:events';
5
5
  import { inspect } from 'node:util';
6
6
  import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN } from './logger/export.js';
7
7
  import { NodeStorageManager } from './storage/export.js';
8
- import { getParameter, getIntParameter, hasParameter, copyDirectory, withTimeout, waiter } from './utils/export.js';
8
+ import { getParameter, getIntParameter, hasParameter, copyDirectory, withTimeout, waiter, isValidString, parseVersionString } from './utils/export.js';
9
9
  import { logInterfaces, getGlobalNodeModules } from './utils/network.js';
10
10
  import { PluginManager } from './pluginManager.js';
11
11
  import { DeviceManager } from './deviceManager.js';
@@ -369,6 +369,7 @@ export class Matterbridge extends EventEmitter {
369
369
  if (!availableInterfaces.includes(this.mdnsInterface)) {
370
370
  this.log.error(`Invalid mdnsInterface: ${this.mdnsInterface}. Available interfaces are: ${availableInterfaces.join(', ')}. Using all available interfaces.`);
371
371
  this.mdnsInterface = undefined;
372
+ await this.nodeContext.remove('mattermdnsinterface');
372
373
  }
373
374
  else {
374
375
  this.log.info(`Using mdnsInterface ${CYAN}${this.mdnsInterface}${nf} for the Matter MdnsBroadcaster.`);
@@ -396,6 +397,7 @@ export class Matterbridge extends EventEmitter {
396
397
  if (!isValid) {
397
398
  this.log.error(`Invalid ipv4address: ${this.ipv4address}. Using all available addresses.`);
398
399
  this.ipv4address = undefined;
400
+ await this.nodeContext.remove('matteripv4address');
399
401
  }
400
402
  }
401
403
  if (hasParameter('ipv6address')) {
@@ -423,6 +425,7 @@ export class Matterbridge extends EventEmitter {
423
425
  if (!isValid) {
424
426
  this.log.error(`Invalid ipv6address: ${this.ipv6address}. Using all available addresses.`);
425
427
  this.ipv6address = undefined;
428
+ await this.nodeContext.remove('matteripv6address');
426
429
  }
427
430
  }
428
431
  this.plugins = new PluginManager(this);
@@ -1403,10 +1406,10 @@ export class Matterbridge extends EventEmitter {
1403
1406
  await storageContext.set('productLabel', productName.slice(0, 32));
1404
1407
  await storageContext.set('serialNumber', await storageContext.get('serialNumber', serialNumber ? serialNumber.slice(0, 32) : 'SN' + random));
1405
1408
  await storageContext.set('uniqueId', await storageContext.get('uniqueId', 'UI' + random));
1406
- await storageContext.set('softwareVersion', this.matterbridgeVersion !== '' && this.matterbridgeVersion.includes('.') ? parseInt(this.matterbridgeVersion.split('.')[0], 10) : 1);
1407
- await storageContext.set('softwareVersionString', this.matterbridgeVersion !== '' ? this.matterbridgeVersion : '1.0.0');
1408
- await storageContext.set('hardwareVersion', this.systemInformation.osRelease !== '' && this.systemInformation.osRelease.includes('.') ? parseInt(this.systemInformation.osRelease.split('.')[0], 10) : 1);
1409
- await storageContext.set('hardwareVersionString', this.systemInformation.osRelease !== '' ? this.systemInformation.osRelease : '1.0.0');
1409
+ await storageContext.set('softwareVersion', parseVersionString(this.matterbridgeVersion) || 1);
1410
+ await storageContext.set('softwareVersionString', isValidString(this.matterbridgeVersion, 5) ? this.matterbridgeVersion : '1.0.0');
1411
+ await storageContext.set('hardwareVersion', parseVersionString(this.systemInformation.osRelease) || 1);
1412
+ await storageContext.set('hardwareVersionString', isValidString(this.systemInformation.osRelease, 5) ? this.systemInformation.osRelease : '1.0.0');
1410
1413
  this.log.debug(`Created server node storage context "${pluginName}.persist" for ${pluginName}:`);
1411
1414
  this.log.debug(`- storeId: ${await storageContext.get('storeId')}`);
1412
1415
  this.log.debug(`- deviceName: ${await storageContext.get('deviceName')}`);