matterbridge 3.1.4 → 3.1.5-dev-20250720-5a0b41e

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.
Files changed (209) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README-DEV.md +59 -0
  3. package/dist/cli.js +2 -91
  4. package/dist/cliEmitter.js +0 -30
  5. package/dist/clusters/export.js +0 -2
  6. package/dist/defaultConfigSchema.js +0 -24
  7. package/dist/deviceManager.js +1 -94
  8. package/dist/devices/batteryStorage.js +1 -48
  9. package/dist/devices/evse.js +10 -74
  10. package/dist/devices/export.js +0 -2
  11. package/dist/devices/heatPump.js +2 -50
  12. package/dist/devices/laundryDryer.js +6 -83
  13. package/dist/devices/laundryWasher.js +7 -91
  14. package/dist/devices/roboticVacuumCleaner.js +17 -97
  15. package/dist/devices/solarPower.js +0 -38
  16. package/dist/devices/waterHeater.js +2 -82
  17. package/dist/frontend.js +22 -430
  18. package/dist/globalMatterbridge.js +0 -47
  19. package/dist/helpers.js +0 -53
  20. package/dist/index.js +1 -30
  21. package/dist/logger/export.js +0 -1
  22. package/dist/matter/behaviors.js +0 -2
  23. package/dist/matter/clusters.js +0 -2
  24. package/dist/matter/devices.js +0 -2
  25. package/dist/matter/endpoints.js +0 -2
  26. package/dist/matter/export.js +0 -3
  27. package/dist/matter/types.js +0 -3
  28. package/dist/matterbridge.js +66 -802
  29. package/dist/matterbridgeAccessoryPlatform.js +0 -36
  30. package/dist/matterbridgeBehaviors.js +1 -61
  31. package/dist/matterbridgeDeviceTypes.js +15 -579
  32. package/dist/matterbridgeDynamicPlatform.js +0 -36
  33. package/dist/matterbridgeEndpoint.js +42 -1106
  34. package/dist/matterbridgeEndpointHelpers.js +12 -322
  35. package/dist/matterbridgePlatform.js +0 -233
  36. package/dist/matterbridgeTypes.js +0 -25
  37. package/dist/pluginManager.js +46 -350
  38. package/dist/shelly.js +7 -168
  39. package/dist/storage/export.js +0 -1
  40. package/dist/update.js +0 -54
  41. package/dist/utils/colorUtils.js +2 -263
  42. package/dist/utils/commandLine.js +0 -54
  43. package/dist/utils/copyDirectory.js +1 -38
  44. package/dist/utils/createDirectory.js +0 -33
  45. package/dist/utils/createZip.js +2 -47
  46. package/dist/utils/deepCopy.js +0 -39
  47. package/dist/utils/deepEqual.js +1 -72
  48. package/dist/utils/error.js +9 -0
  49. package/dist/utils/export.js +0 -1
  50. package/dist/utils/hex.js +0 -58
  51. package/dist/utils/isvalid.js +0 -101
  52. package/dist/utils/network.js +5 -81
  53. package/dist/utils/spawn.js +0 -18
  54. package/dist/utils/wait.js +9 -62
  55. package/npm-shrinkwrap.json +5 -5
  56. package/package.json +1 -2
  57. package/dist/cli.d.ts +0 -26
  58. package/dist/cli.d.ts.map +0 -1
  59. package/dist/cli.js.map +0 -1
  60. package/dist/cliEmitter.d.ts +0 -34
  61. package/dist/cliEmitter.d.ts.map +0 -1
  62. package/dist/cliEmitter.js.map +0 -1
  63. package/dist/clusters/export.d.ts +0 -2
  64. package/dist/clusters/export.d.ts.map +0 -1
  65. package/dist/clusters/export.js.map +0 -1
  66. package/dist/defaultConfigSchema.d.ts +0 -28
  67. package/dist/defaultConfigSchema.d.ts.map +0 -1
  68. package/dist/defaultConfigSchema.js.map +0 -1
  69. package/dist/deviceManager.d.ts +0 -112
  70. package/dist/deviceManager.d.ts.map +0 -1
  71. package/dist/deviceManager.js.map +0 -1
  72. package/dist/devices/batteryStorage.d.ts +0 -48
  73. package/dist/devices/batteryStorage.d.ts.map +0 -1
  74. package/dist/devices/batteryStorage.js.map +0 -1
  75. package/dist/devices/evse.d.ts +0 -75
  76. package/dist/devices/evse.d.ts.map +0 -1
  77. package/dist/devices/evse.js.map +0 -1
  78. package/dist/devices/export.d.ts +0 -9
  79. package/dist/devices/export.d.ts.map +0 -1
  80. package/dist/devices/export.js.map +0 -1
  81. package/dist/devices/heatPump.d.ts +0 -47
  82. package/dist/devices/heatPump.d.ts.map +0 -1
  83. package/dist/devices/heatPump.js.map +0 -1
  84. package/dist/devices/laundryDryer.d.ts +0 -87
  85. package/dist/devices/laundryDryer.d.ts.map +0 -1
  86. package/dist/devices/laundryDryer.js.map +0 -1
  87. package/dist/devices/laundryWasher.d.ts +0 -242
  88. package/dist/devices/laundryWasher.d.ts.map +0 -1
  89. package/dist/devices/laundryWasher.js.map +0 -1
  90. package/dist/devices/roboticVacuumCleaner.d.ts +0 -110
  91. package/dist/devices/roboticVacuumCleaner.d.ts.map +0 -1
  92. package/dist/devices/roboticVacuumCleaner.js.map +0 -1
  93. package/dist/devices/solarPower.d.ts +0 -40
  94. package/dist/devices/solarPower.d.ts.map +0 -1
  95. package/dist/devices/solarPower.js.map +0 -1
  96. package/dist/devices/waterHeater.d.ts +0 -111
  97. package/dist/devices/waterHeater.d.ts.map +0 -1
  98. package/dist/devices/waterHeater.js.map +0 -1
  99. package/dist/frontend.d.ts +0 -304
  100. package/dist/frontend.d.ts.map +0 -1
  101. package/dist/frontend.js.map +0 -1
  102. package/dist/globalMatterbridge.d.ts +0 -59
  103. package/dist/globalMatterbridge.d.ts.map +0 -1
  104. package/dist/globalMatterbridge.js.map +0 -1
  105. package/dist/helpers.d.ts +0 -48
  106. package/dist/helpers.d.ts.map +0 -1
  107. package/dist/helpers.js.map +0 -1
  108. package/dist/index.d.ts +0 -33
  109. package/dist/index.d.ts.map +0 -1
  110. package/dist/index.js.map +0 -1
  111. package/dist/logger/export.d.ts +0 -2
  112. package/dist/logger/export.d.ts.map +0 -1
  113. package/dist/logger/export.js.map +0 -1
  114. package/dist/matter/behaviors.d.ts +0 -2
  115. package/dist/matter/behaviors.d.ts.map +0 -1
  116. package/dist/matter/behaviors.js.map +0 -1
  117. package/dist/matter/clusters.d.ts +0 -2
  118. package/dist/matter/clusters.d.ts.map +0 -1
  119. package/dist/matter/clusters.js.map +0 -1
  120. package/dist/matter/devices.d.ts +0 -2
  121. package/dist/matter/devices.d.ts.map +0 -1
  122. package/dist/matter/devices.js.map +0 -1
  123. package/dist/matter/endpoints.d.ts +0 -2
  124. package/dist/matter/endpoints.d.ts.map +0 -1
  125. package/dist/matter/endpoints.js.map +0 -1
  126. package/dist/matter/export.d.ts +0 -5
  127. package/dist/matter/export.d.ts.map +0 -1
  128. package/dist/matter/export.js.map +0 -1
  129. package/dist/matter/types.d.ts +0 -3
  130. package/dist/matter/types.d.ts.map +0 -1
  131. package/dist/matter/types.js.map +0 -1
  132. package/dist/matterbridge.d.ts +0 -444
  133. package/dist/matterbridge.d.ts.map +0 -1
  134. package/dist/matterbridge.js.map +0 -1
  135. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -42
  136. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  137. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  138. package/dist/matterbridgeBehaviors.d.ts +0 -1340
  139. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  140. package/dist/matterbridgeBehaviors.js.map +0 -1
  141. package/dist/matterbridgeDeviceTypes.d.ts +0 -709
  142. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  143. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  144. package/dist/matterbridgeDynamicPlatform.d.ts +0 -42
  145. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  146. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  147. package/dist/matterbridgeEndpoint.d.ts +0 -1250
  148. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  149. package/dist/matterbridgeEndpoint.js.map +0 -1
  150. package/dist/matterbridgeEndpointHelpers.d.ts +0 -3198
  151. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  152. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  153. package/dist/matterbridgePlatform.d.ts +0 -310
  154. package/dist/matterbridgePlatform.d.ts.map +0 -1
  155. package/dist/matterbridgePlatform.js.map +0 -1
  156. package/dist/matterbridgeTypes.d.ts +0 -195
  157. package/dist/matterbridgeTypes.d.ts.map +0 -1
  158. package/dist/matterbridgeTypes.js.map +0 -1
  159. package/dist/pluginManager.d.ts +0 -291
  160. package/dist/pluginManager.d.ts.map +0 -1
  161. package/dist/pluginManager.js.map +0 -1
  162. package/dist/shelly.d.ts +0 -174
  163. package/dist/shelly.d.ts.map +0 -1
  164. package/dist/shelly.js.map +0 -1
  165. package/dist/storage/export.d.ts +0 -2
  166. package/dist/storage/export.d.ts.map +0 -1
  167. package/dist/storage/export.js.map +0 -1
  168. package/dist/update.d.ts +0 -59
  169. package/dist/update.d.ts.map +0 -1
  170. package/dist/update.js.map +0 -1
  171. package/dist/utils/colorUtils.d.ts +0 -117
  172. package/dist/utils/colorUtils.d.ts.map +0 -1
  173. package/dist/utils/colorUtils.js.map +0 -1
  174. package/dist/utils/commandLine.d.ts +0 -59
  175. package/dist/utils/commandLine.d.ts.map +0 -1
  176. package/dist/utils/commandLine.js.map +0 -1
  177. package/dist/utils/copyDirectory.d.ts +0 -33
  178. package/dist/utils/copyDirectory.d.ts.map +0 -1
  179. package/dist/utils/copyDirectory.js.map +0 -1
  180. package/dist/utils/createDirectory.d.ts +0 -34
  181. package/dist/utils/createDirectory.d.ts.map +0 -1
  182. package/dist/utils/createDirectory.js.map +0 -1
  183. package/dist/utils/createZip.d.ts +0 -39
  184. package/dist/utils/createZip.d.ts.map +0 -1
  185. package/dist/utils/createZip.js.map +0 -1
  186. package/dist/utils/deepCopy.d.ts +0 -32
  187. package/dist/utils/deepCopy.d.ts.map +0 -1
  188. package/dist/utils/deepCopy.js.map +0 -1
  189. package/dist/utils/deepEqual.d.ts +0 -54
  190. package/dist/utils/deepEqual.d.ts.map +0 -1
  191. package/dist/utils/deepEqual.js.map +0 -1
  192. package/dist/utils/export.d.ts +0 -12
  193. package/dist/utils/export.d.ts.map +0 -1
  194. package/dist/utils/export.js.map +0 -1
  195. package/dist/utils/hex.d.ts +0 -49
  196. package/dist/utils/hex.d.ts.map +0 -1
  197. package/dist/utils/hex.js.map +0 -1
  198. package/dist/utils/isvalid.d.ts +0 -103
  199. package/dist/utils/isvalid.d.ts.map +0 -1
  200. package/dist/utils/isvalid.js.map +0 -1
  201. package/dist/utils/network.d.ts +0 -74
  202. package/dist/utils/network.d.ts.map +0 -1
  203. package/dist/utils/network.js.map +0 -1
  204. package/dist/utils/spawn.d.ts +0 -11
  205. package/dist/utils/spawn.d.ts.map +0 -1
  206. package/dist/utils/spawn.js.map +0 -1
  207. package/dist/utils/wait.d.ts +0 -56
  208. package/dist/utils/wait.d.ts.map +0 -1
  209. package/dist/utils/wait.js.map +0 -1
@@ -1,44 +1,16 @@
1
- /**
2
- * This file contains the class Matterbridge.
3
- *
4
- * @file matterbridge.ts
5
- * @author Luca Liguori
6
- * @created 2023-12-29
7
- * @version 1.6.0
8
- * @license Apache-2.0
9
- *
10
- * Copyright 2023, 2024, 2025 Luca Liguori.
11
- *
12
- * Licensed under the Apache License, Version 2.0 (the "License");
13
- * you may not use this file except in compliance with the License.
14
- * You may obtain a copy of the License at
15
- *
16
- * http://www.apache.org/licenses/LICENSE-2.0
17
- *
18
- * Unless required by applicable law or agreed to in writing, software
19
- * distributed under the License is distributed on an "AS IS" BASIS,
20
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
- * See the License for the specific language governing permissions and
22
- * limitations under the License.
23
- */
24
- // Node.js modules
25
1
  import os from 'node:os';
26
2
  import path from 'node:path';
27
3
  import { promises as fs } from 'node:fs';
28
4
  import EventEmitter from 'node:events';
29
5
  import { inspect } from 'node:util';
30
- // AnsiLogger module
31
6
  import { AnsiLogger, UNDERLINE, UNDERLINEOFF, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN, nt, BLUE } from 'node-ansi-logger';
32
- // NodeStorage module
33
7
  import { NodeStorageManager } from 'node-persist-manager';
34
- // @matter
35
8
  import { DeviceTypeId, Endpoint, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageService, Environment, ServerNode, UINT32_MAX, UINT16_MAX, Crypto, } from '@matter/main';
36
9
  import { DeviceCommissioner, FabricAction, MdnsService, PaseClient } from '@matter/main/protocol';
37
10
  import { AggregatorEndpoint } from '@matter/main/endpoints';
38
11
  import { BasicInformationServer } from '@matter/main/behaviors/basic-information';
39
12
  import { BridgedDeviceBasicInformationServer } from '@matter/main/behaviors/bridged-device-basic-information';
40
- // Matterbridge
41
- import { getParameter, getIntParameter, hasParameter, copyDirectory, withTimeout, waiter, isValidString, parseVersionString, isValidNumber, createDirectory } from './utils/export.js';
13
+ import { getParameter, getIntParameter, hasParameter, copyDirectory, withTimeout, waiter, isValidString, parseVersionString, isValidNumber, createDirectory, wait } from './utils/export.js';
42
14
  import { dev, plg, typ } from './matterbridgeTypes.js';
43
15
  import { PluginManager } from './pluginManager.js';
44
16
  import { DeviceManager } from './deviceManager.js';
@@ -46,9 +18,6 @@ import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
46
18
  import { bridge } from './matterbridgeDeviceTypes.js';
47
19
  import { Frontend } from './frontend.js';
48
20
  import { addVirtualDevices } from './helpers.js';
49
- /**
50
- * Represents the Matterbridge application.
51
- */
52
21
  export class Matterbridge extends EventEmitter {
53
22
  systemInformation = {
54
23
  interfaceName: '',
@@ -97,7 +66,7 @@ export class Matterbridge extends EventEmitter {
97
66
  shellySysUpdate: false,
98
67
  shellyMainUpdate: false,
99
68
  profile: getParameter('profile'),
100
- loggerLevel: "info" /* LogLevel.INFO */,
69
+ loggerLevel: "info",
101
70
  fileLogger: false,
102
71
  matterLoggerLevel: MatterLogLevel.INFO,
103
72
  matterFileLogger: false,
@@ -125,18 +94,15 @@ export class Matterbridge extends EventEmitter {
125
94
  shutdown = false;
126
95
  edge = true;
127
96
  failCountLimit = hasParameter('shelly') ? 600 : 120;
128
- // Matterbridge log files
129
- log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
97
+ log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
130
98
  matterbridgeLoggerFile = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
131
99
  matterLoggerFile = 'matter' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
132
- plugins;
133
- devices;
100
+ plugins = new PluginManager(this);
101
+ devices = new DeviceManager(this);
134
102
  frontend = new Frontend(this);
135
- // Matterbridge storage
136
103
  nodeStorageName = 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
137
104
  nodeStorage;
138
105
  nodeContext;
139
- // Cleanup
140
106
  hasCleanupStarted = false;
141
107
  initialized = false;
142
108
  execRunningCount = 0;
@@ -150,23 +116,19 @@ export class Matterbridge extends EventEmitter {
150
116
  sigtermHandler;
151
117
  exceptionHandler;
152
118
  rejectionHandler;
153
- // Matter environment
154
119
  environment = Environment.default;
155
- // Matter storage
156
120
  matterStorageName = 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
157
121
  matterStorageService;
158
122
  matterStorageManager;
159
123
  matterbridgeContext;
160
124
  controllerContext;
161
- // Matter parameters
162
- mdnsInterface; // matter server node mdnsInterface: e.g. 'eth0' or 'wlan0' or 'WiFi'
163
- ipv4address; // matter server node listeningAddressIpv4
164
- ipv6address; // matter server node listeningAddressIpv6
165
- port; // first server node port
166
- passcode; // first server node passcode
167
- discriminator; // first server node discriminator
168
- certification; // device certification
169
- // Matter nodes
125
+ mdnsInterface;
126
+ ipv4address;
127
+ ipv6address;
128
+ port;
129
+ passcode;
130
+ discriminator;
131
+ certification;
170
132
  serverNode;
171
133
  aggregatorNode;
172
134
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
@@ -174,31 +136,15 @@ export class Matterbridge extends EventEmitter {
174
136
  aggregatorProductId = getIntParameter('productId') ?? 0x8000;
175
137
  aggregatorProductName = getParameter('productName') ?? 'Matterbridge aggregator';
176
138
  static instance;
177
- // We load asyncronously so is private
178
139
  constructor() {
179
140
  super();
180
141
  }
181
- /**
182
- * Retrieves the list of Matterbridge devices.
183
- *
184
- * @returns {MatterbridgeEndpoint[]} An array of MatterbridgeDevice objects.
185
- */
186
142
  getDevices() {
187
143
  return this.devices.array();
188
144
  }
189
- /**
190
- * Retrieves the list of registered plugins.
191
- *
192
- * @returns {RegisteredPlugin[]} An array of RegisteredPlugin objects.
193
- */
194
145
  getPlugins() {
195
146
  return this.plugins.array();
196
147
  }
197
- /**
198
- * Set the logger logLevel for the Matterbridge classes and call onChangeLoggerLevel() for each plugin.
199
- *
200
- * @param {LogLevel} logLevel The logger logLevel to set.
201
- */
202
148
  async setLogLevel(logLevel) {
203
149
  if (this.log)
204
150
  this.log.logLevel = logLevel;
@@ -212,31 +158,19 @@ export class Matterbridge extends EventEmitter {
212
158
  for (const plugin of this.plugins) {
213
159
  if (!plugin.platform || !plugin.platform.log || !plugin.platform.config)
214
160
  continue;
215
- plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel;
216
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel);
217
- }
218
- // Set the global logger callback for the WebSocketServer to the common minimum logLevel
219
- let callbackLogLevel = "notice" /* LogLevel.NOTICE */;
220
- if (this.matterbridgeInformation.loggerLevel === "info" /* LogLevel.INFO */ || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.INFO)
221
- callbackLogLevel = "info" /* LogLevel.INFO */;
222
- if (this.matterbridgeInformation.loggerLevel === "debug" /* LogLevel.DEBUG */ || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.DEBUG)
223
- callbackLogLevel = "debug" /* LogLevel.DEBUG */;
161
+ plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" : this.log.logLevel;
162
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" : this.log.logLevel);
163
+ }
164
+ let callbackLogLevel = "notice";
165
+ if (this.matterbridgeInformation.loggerLevel === "info" || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.INFO)
166
+ callbackLogLevel = "info";
167
+ if (this.matterbridgeInformation.loggerLevel === "debug" || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.DEBUG)
168
+ callbackLogLevel = "debug";
224
169
  AnsiLogger.setGlobalCallback(this.frontend.wssSendMessage.bind(this.frontend), callbackLogLevel);
225
170
  this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
226
171
  }
227
- //* ************************************************************************************************************************************ */
228
- // loadInstance() and cleanup() methods */
229
- //* ************************************************************************************************************************************ */
230
- /**
231
- * Loads an instance of the Matterbridge class.
232
- * If an instance already exists, return that instance.
233
- *
234
- * @param {boolean} initialize - Whether to initialize the Matterbridge instance after loading. Defaults to false.
235
- * @returns {Matterbridge} A promise that resolves to the Matterbridge instance.
236
- */
237
172
  static async loadInstance(initialize = false) {
238
173
  if (!Matterbridge.instance) {
239
- // eslint-disable-next-line no-console
240
174
  if (hasParameter('debug'))
241
175
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
242
176
  Matterbridge.instance = new Matterbridge();
@@ -245,17 +179,8 @@ export class Matterbridge extends EventEmitter {
245
179
  }
246
180
  return Matterbridge.instance;
247
181
  }
248
- /**
249
- * Call cleanup() and dispose MdnsService.
250
- *
251
- * @param {number} [timeout] - The timeout duration to wait for the cleanup to complete in milliseconds. Default is 1000.
252
- * @param {number} [pause] - The pause duration after the cleanup in milliseconds. Default is 250.
253
- *
254
- * @deprecated This method is deprecated and is ONLY used for jest tests.
255
- */
256
182
  async destroyInstance(timeout = 1000, pause = 250) {
257
183
  this.log.info(`Destroy instance...`);
258
- // Save server nodes to close
259
184
  const servers = [];
260
185
  if (this.bridgeMode === 'bridge') {
261
186
  if (this.serverNode)
@@ -273,109 +198,76 @@ export class Matterbridge extends EventEmitter {
273
198
  servers.push(device.serverNode);
274
199
  }
275
200
  }
276
- // Let any already‐queued microtasks run first
277
201
  await Promise.resolve();
278
- // Wait for the cleanup to finish
279
202
  await new Promise((resolve) => {
280
203
  setTimeout(resolve, pause);
281
204
  });
282
- // Cleanup
283
205
  await this.cleanup('destroying instance...', false, timeout);
284
- // Close servers mdns service
285
206
  this.log.info(`Dispose ${servers.length} MdnsService...`);
286
207
  for (const server of servers) {
287
208
  await server.env.get(MdnsService)[Symbol.asyncDispose]();
288
209
  this.log.info(`Closed ${server.id} MdnsService`);
289
210
  }
290
- // Let any already‐queued microtasks run first
291
211
  await Promise.resolve();
292
- // Wait for the cleanup to finish
293
212
  await new Promise((resolve) => {
294
213
  setTimeout(resolve, pause);
295
214
  });
296
215
  }
297
- /**
298
- * Initializes the Matterbridge application.
299
- *
300
- * @remarks
301
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
302
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
303
- * node version, registers signal handlers, initializes storage, and parses the command line.
304
- *
305
- * @returns {Promise<void>} A Promise that resolves when the initialization is complete.
306
- */
307
216
  async initialize() {
308
- // Emit the initialize_started event
309
217
  this.emit('initialize_started');
310
- // Set the restart mode
311
218
  if (hasParameter('service'))
312
219
  this.restartMode = 'service';
313
220
  if (hasParameter('docker'))
314
221
  this.restartMode = 'docker';
315
- // Set the matterbridge home directory
316
222
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
317
223
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
318
224
  await createDirectory(this.homeDirectory, 'Matterbridge Home Directory', this.log);
319
- // Set the matterbridge directory
320
225
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
321
226
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
322
227
  await createDirectory(this.matterbridgeDirectory, 'Matterbridge Directory', this.log);
323
228
  await createDirectory(path.join(this.matterbridgeDirectory, 'certs'), 'Matterbridge Frontend Certificate Directory', this.log);
324
229
  await createDirectory(path.join(this.matterbridgeDirectory, 'uploads'), 'Matterbridge Frontend Uploads Directory', this.log);
325
- // Set the matterbridge plugin directory
326
230
  this.matterbridgePluginDirectory = path.join(this.homeDirectory, 'Matterbridge');
327
231
  this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
328
232
  await createDirectory(this.matterbridgePluginDirectory, 'Matterbridge Plugin Directory', this.log);
329
- // Set the matterbridge cert directory
330
233
  this.matterbridgeCertDirectory = path.join(this.homeDirectory, '.mattercert');
331
234
  this.matterbridgeInformation.matterbridgeCertDirectory = this.matterbridgeCertDirectory;
332
235
  await createDirectory(this.matterbridgeCertDirectory, 'Matterbridge Matter Certificate Directory', this.log);
333
- // Set the matterbridge root directory
334
236
  const { fileURLToPath } = await import('node:url');
335
237
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
336
238
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
337
239
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
338
- // Setup the matter environment
339
240
  this.environment.vars.set('log.level', MatterLogLevel.INFO);
340
241
  this.environment.vars.set('log.format', MatterLogFormat.ANSI);
341
242
  this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, this.matterStorageName));
342
243
  this.environment.vars.set('runtime.signals', false);
343
244
  this.environment.vars.set('runtime.exitcode', false);
344
- // Register process handlers
345
245
  this.registerProcessHandlers();
346
- // Initialize nodeStorage and nodeContext
347
246
  try {
348
247
  this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
349
248
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
350
249
  this.log.debug('Creating node storage context for matterbridge');
351
250
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
352
- // TODO: Remove this code when node-persist-manager is updated
353
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
354
251
  const keys = (await this.nodeStorage?.storage.keys());
355
252
  for (const key of keys) {
356
253
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
357
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
358
254
  await this.nodeStorage?.storage.get(key);
359
255
  }
360
256
  const storages = await this.nodeStorage.getStorageNames();
361
257
  for (const storage of storages) {
362
258
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
363
259
  const nodeContext = await this.nodeStorage?.createStorage(storage);
364
- // TODO: Remove this code when node-persist-manager is updated
365
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
366
260
  const keys = (await nodeContext?.storage.keys());
367
261
  keys.forEach(async (key) => {
368
262
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
369
263
  await nodeContext?.get(key);
370
264
  });
371
265
  }
372
- // Creating a backup of the node storage since it is not corrupted
373
266
  this.log.debug('Creating node storage backup...');
374
267
  await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
375
268
  this.log.debug('Created node storage backup');
376
269
  }
377
270
  catch (error) {
378
- // Restoring the backup of the node storage since it is corrupted
379
271
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
380
272
  if (hasParameter('norestore')) {
381
273
  this.log.fatal(`The matterbridge storage is corrupted. Found -norestore parameter: exiting...`);
@@ -389,20 +281,14 @@ export class Matterbridge extends EventEmitter {
389
281
  if (!this.nodeStorage || !this.nodeContext) {
390
282
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
391
283
  }
392
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
393
284
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
394
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
395
285
  this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode')) ?? PaseClient.generateRandomPasscode(this.environment.get(Crypto));
396
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
397
286
  this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator')) ?? PaseClient.generateRandomDiscriminator(this.environment.get(Crypto));
398
- // Certificate management
399
287
  const pairingFilePath = path.join(this.matterbridgeCertDirectory, 'pairing.json');
400
288
  try {
401
- // eslint-disable-next-line n/no-unsupported-features/node-builtins
402
289
  await fs.access(pairingFilePath, fs.constants.R_OK);
403
290
  const pairingFileContent = await fs.readFile(pairingFilePath, 'utf8');
404
291
  const pairingFileJson = JSON.parse(pairingFileContent);
405
- // Set the vendorId, vendorName, productId and productName if they are present in the pairing file
406
292
  if (isValidNumber(pairingFileJson.vendorId))
407
293
  this.aggregatorVendorId = VendorId(pairingFileJson.vendorId);
408
294
  if (isValidString(pairingFileJson.vendorName, 3))
@@ -411,14 +297,11 @@ export class Matterbridge extends EventEmitter {
411
297
  this.aggregatorProductId = pairingFileJson.productId;
412
298
  if (isValidString(pairingFileJson.productName, 3))
413
299
  this.aggregatorProductName = pairingFileJson.productName;
414
- // Override the passcode and discriminator if they are present in the pairing file
415
300
  if (isValidNumber(pairingFileJson.passcode) && isValidNumber(pairingFileJson.discriminator)) {
416
301
  this.passcode = pairingFileJson.passcode;
417
302
  this.discriminator = pairingFileJson.discriminator;
418
303
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using passcode ${CYAN}${this.passcode}${nf} and discriminator ${CYAN}${this.discriminator}${nf} from pairing file.`);
419
304
  }
420
- // Set the certification if it is present in the pairing file
421
- /* istanbul ignore next if */
422
305
  if (pairingFileJson.privateKey && pairingFileJson.certificate && pairingFileJson.intermediateCertificate && pairingFileJson.declaration) {
423
306
  const hexStringToUint8Array = (hexString) => {
424
307
  const matches = hexString.match(/.{1,2}/g);
@@ -436,44 +319,41 @@ export class Matterbridge extends EventEmitter {
436
319
  catch (error) {
437
320
  this.log.debug(`Pairing file ${CYAN}${pairingFilePath}${db} not found: ${error instanceof Error ? error.message : error}`);
438
321
  }
439
- // Store the passcode, discriminator and port in the node context
440
322
  await this.nodeContext.set('matterport', this.port);
441
323
  await this.nodeContext.set('matterpasscode', this.passcode);
442
324
  await this.nodeContext.set('matterdiscriminator', this.discriminator);
443
325
  this.log.debug(`Initializing server node for Matterbridge on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
444
- // Set matterbridge logger level (context: matterbridgeLogLevel)
445
326
  if (hasParameter('logger')) {
446
327
  const level = getParameter('logger');
447
328
  if (level === 'debug') {
448
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
329
+ this.log.logLevel = "debug";
449
330
  }
450
331
  else if (level === 'info') {
451
- this.log.logLevel = "info" /* LogLevel.INFO */;
332
+ this.log.logLevel = "info";
452
333
  }
453
334
  else if (level === 'notice') {
454
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
335
+ this.log.logLevel = "notice";
455
336
  }
456
337
  else if (level === 'warn') {
457
- this.log.logLevel = "warn" /* LogLevel.WARN */;
338
+ this.log.logLevel = "warn";
458
339
  }
459
340
  else if (level === 'error') {
460
- this.log.logLevel = "error" /* LogLevel.ERROR */;
341
+ this.log.logLevel = "error";
461
342
  }
462
343
  else if (level === 'fatal') {
463
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
344
+ this.log.logLevel = "fatal";
464
345
  }
465
346
  else {
466
347
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
467
- this.log.logLevel = "info" /* LogLevel.INFO */;
348
+ this.log.logLevel = "info";
468
349
  }
469
350
  }
470
351
  else {
471
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.matterbridgeInformation.shellyBoard ? "notice" /* LogLevel.NOTICE */ : "info" /* LogLevel.INFO */);
352
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.matterbridgeInformation.shellyBoard ? "notice" : "info");
472
353
  }
473
354
  this.frontend.logLevel = this.log.logLevel;
474
355
  MatterbridgeEndpoint.logLevel = this.log.logLevel;
475
356
  this.matterbridgeInformation.loggerLevel = this.log.logLevel;
476
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
477
357
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
478
358
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbridgeLoggerFile), this.log.logLevel, true);
479
359
  this.matterbridgeInformation.fileLogger = true;
@@ -482,7 +362,6 @@ export class Matterbridge extends EventEmitter {
482
362
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
483
363
  if (this.profile !== undefined)
484
364
  this.log.debug(`Matterbridge profile: ${this.profile}.`);
485
- // Set matter.js logger level, format and logger (context: matterLogLevel)
486
365
  if (hasParameter('matterlogger')) {
487
366
  const level = getParameter('matterlogger');
488
367
  if (level === 'debug') {
@@ -513,9 +392,7 @@ export class Matterbridge extends EventEmitter {
513
392
  }
514
393
  Logger.format = MatterLogFormat.ANSI;
515
394
  Logger.setLogger('default', this.createMatterLogger());
516
- // Logger.destinations.default.write = this.createMatterLogger();
517
395
  this.matterbridgeInformation.matterLoggerLevel = Logger.level;
518
- // Create the file logger for matter.js (context: matterFileLog)
519
396
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
520
397
  this.matterbridgeInformation.matterFileLogger = true;
521
398
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
@@ -524,9 +401,7 @@ export class Matterbridge extends EventEmitter {
524
401
  });
525
402
  }
526
403
  this.log.debug(`Matter logLevel: ${Logger.level} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
527
- // Log network interfaces
528
404
  const networkInterfaces = os.networkInterfaces();
529
- // console.log(`Network interfaces:`, networkInterfaces);
530
405
  const availableAddresses = Object.entries(networkInterfaces);
531
406
  const availableInterfaces = Object.keys(networkInterfaces);
532
407
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -538,7 +413,6 @@ export class Matterbridge extends EventEmitter {
538
413
  });
539
414
  }
540
415
  }
541
- // Set the interface to use for matter server node mdnsInterface
542
416
  if (hasParameter('mdnsinterface')) {
543
417
  this.mdnsInterface = getParameter('mdnsinterface');
544
418
  }
@@ -547,7 +421,6 @@ export class Matterbridge extends EventEmitter {
547
421
  if (this.mdnsInterface === '')
548
422
  this.mdnsInterface = undefined;
549
423
  }
550
- // Validate mdnsInterface
551
424
  if (this.mdnsInterface) {
552
425
  if (!availableInterfaces.includes(this.mdnsInterface)) {
553
426
  this.log.error(`Invalid mdnsinterface: ${this.mdnsInterface}. Available interfaces are: ${availableInterfaces.join(', ')}. Using all available interfaces.`);
@@ -560,7 +433,6 @@ export class Matterbridge extends EventEmitter {
560
433
  }
561
434
  if (this.mdnsInterface)
562
435
  this.environment.vars.set('mdns.networkInterface', this.mdnsInterface);
563
- // Set the listeningAddressIpv4 for the matter commissioning server
564
436
  if (hasParameter('ipv4address')) {
565
437
  this.ipv4address = getParameter('ipv4address');
566
438
  }
@@ -569,7 +441,6 @@ export class Matterbridge extends EventEmitter {
569
441
  if (this.ipv4address === '')
570
442
  this.ipv4address = undefined;
571
443
  }
572
- // Validate ipv4address
573
444
  if (this.ipv4address) {
574
445
  let isValid = false;
575
446
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -585,7 +456,6 @@ export class Matterbridge extends EventEmitter {
585
456
  await this.nodeContext.remove('matteripv4address');
586
457
  }
587
458
  }
588
- // Set the listeningAddressIpv6 for the matter commissioning server
589
459
  if (hasParameter('ipv6address')) {
590
460
  this.ipv6address = getParameter('ipv6address');
591
461
  }
@@ -594,7 +464,6 @@ export class Matterbridge extends EventEmitter {
594
464
  if (this.ipv6address === '')
595
465
  this.ipv6address = undefined;
596
466
  }
597
- // Validate ipv6address
598
467
  if (this.ipv6address) {
599
468
  let isValid = false;
600
469
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -603,7 +472,6 @@ export class Matterbridge extends EventEmitter {
603
472
  isValid = true;
604
473
  break;
605
474
  }
606
- /* istanbul ignore next */
607
475
  if (ifaces && ifaces.find((iface) => iface.scopeid && iface.scopeid > 0 && iface.address + '%' + (process.platform === 'win32' ? iface.scopeid : ifaceName) === this.ipv6address)) {
608
476
  this.log.info(`Using ipv6address ${CYAN}${this.ipv6address}${nf} on interface ${CYAN}${ifaceName}${nf} for the Matter server node.`);
609
477
  isValid = true;
@@ -616,7 +484,6 @@ export class Matterbridge extends EventEmitter {
616
484
  await this.nodeContext.remove('matteripv6address');
617
485
  }
618
486
  }
619
- // Initialize the virtual mode
620
487
  if (hasParameter('novirtual')) {
621
488
  this.matterbridgeInformation.virtualMode = 'disabled';
622
489
  await this.nodeContext.set('virtualmode', 'disabled');
@@ -625,19 +492,12 @@ export class Matterbridge extends EventEmitter {
625
492
  this.matterbridgeInformation.virtualMode = (await this.nodeContext.get('virtualmode', 'outlet'));
626
493
  }
627
494
  this.log.debug(`Virtual mode ${this.matterbridgeInformation.virtualMode}.`);
628
- // Initialize PluginManager
629
- this.plugins = new PluginManager(this);
630
- await this.plugins.loadFromStorage();
631
495
  this.plugins.logLevel = this.log.logLevel;
632
- // Initialize DeviceManager
633
- this.devices = new DeviceManager(this);
496
+ await this.plugins.loadFromStorage();
634
497
  this.devices.logLevel = this.log.logLevel;
635
- // Get the plugins from node storage and create the plugins node storage contexts
636
498
  for (const plugin of this.plugins) {
637
499
  const packageJson = await this.plugins.parse(plugin);
638
500
  if (packageJson === null && !hasParameter('add') && !hasParameter('remove') && !hasParameter('enable') && !hasParameter('disable') && !hasParameter('reset') && !hasParameter('factoryreset')) {
639
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
640
- // We don't do this when the add and other parameters are set because we shut down the process after adding the plugin
641
501
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
642
502
  try {
643
503
  const { spawnCommand } = await import('./utils/spawn.js');
@@ -660,7 +520,6 @@ export class Matterbridge extends EventEmitter {
660
520
  await plugin.nodeContext.set('description', plugin.description);
661
521
  await plugin.nodeContext.set('author', plugin.author);
662
522
  }
663
- // Log system info and create .matterbridge directory
664
523
  await this.logNodeAndSystemInfo();
665
524
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
666
525
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -668,7 +527,6 @@ export class Matterbridge extends EventEmitter {
668
527
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
669
528
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
670
529
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
671
- // Check node version and throw error
672
530
  const minNodeVersion = 18;
673
531
  const nodeVersion = process.versions.node;
674
532
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -676,18 +534,10 @@ export class Matterbridge extends EventEmitter {
676
534
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
677
535
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
678
536
  }
679
- // Parse command line
680
537
  await this.parseCommandLine();
681
- // Emit the initialize_completed event
682
538
  this.emit('initialize_completed');
683
539
  this.initialized = true;
684
540
  }
685
- /**
686
- * Parses the command line arguments and performs the corresponding actions.
687
- *
688
- * @private
689
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
690
- */
691
541
  async parseCommandLine() {
692
542
  if (hasParameter('help')) {
693
543
  this.log.info(`\nUsage: matterbridge [options]\n
@@ -713,7 +563,8 @@ export class Matterbridge extends EventEmitter {
713
563
  - nosudo: force not to use sudo to install or update packages if the internal logic fails
714
564
  - norestore: force not to automatically restore the matterbridge node storage and the matter storage from backup if it is corrupted
715
565
  - novirtual: disable the creation of the virtual devices Restart, Update and Reboot Matterbridge
716
- - ssl: enable SSL for the frontend and WebSockerServer (certificates in .matterbridge/certs directory cert.pem, key.pem and ca.pem (optional))
566
+ - ssl: enable SSL for the frontend and the WebSocketServer (the server will use the certificates and switch to https)
567
+ - mtls: enable mTLS for the frontend and the WebSocketServer (both server and client will use and require the certificates and switch to https)
717
568
  - vendorId: override the default vendorId 0xfff1
718
569
  - vendorName: override the default vendorName "Matterbridge"
719
570
  - productId: override the default productId 0x8000
@@ -748,19 +599,6 @@ export class Matterbridge extends EventEmitter {
748
599
  }
749
600
  index++;
750
601
  }
751
- /*
752
- const serializedRegisteredDevices = await this.nodeContext?.get<SerializedMatterbridgeEndpoint[]>('devices', []);
753
- this.log.info(`│ Registered devices (${serializedRegisteredDevices?.length})`);
754
- serializedRegisteredDevices?.forEach((device, index) => {
755
- if (index !== serializedRegisteredDevices.length - 1) {
756
- this.log.info(`├─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
757
- this.log.info(`│ └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
758
- } else {
759
- this.log.info(`└─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
760
- this.log.info(` └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
761
- }
762
- });
763
- */
764
602
  this.shutdown = true;
765
603
  return;
766
604
  }
@@ -776,7 +614,6 @@ export class Matterbridge extends EventEmitter {
776
614
  }
777
615
  if (hasParameter('loginterfaces')) {
778
616
  const { logInterfaces } = await import('./utils/network.js');
779
- // this.log.info(`${plg}Matterbridge${nf} network interfaces log`);
780
617
  logInterfaces();
781
618
  this.shutdown = true;
782
619
  return;
@@ -811,7 +648,6 @@ export class Matterbridge extends EventEmitter {
811
648
  this.shutdown = true;
812
649
  return;
813
650
  }
814
- // Start the matter storage and create the matterbridge context
815
651
  try {
816
652
  await this.startMatterStorage();
817
653
  }
@@ -819,21 +655,18 @@ export class Matterbridge extends EventEmitter {
819
655
  this.log.fatal(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
820
656
  throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
821
657
  }
822
- // Clear the matterbridge context if the reset parameter is set
823
658
  if (hasParameter('reset') && getParameter('reset') === undefined) {
824
659
  this.initialized = true;
825
660
  await this.shutdownProcessAndReset();
826
661
  this.shutdown = true;
827
662
  return;
828
663
  }
829
- // Clear matterbridge plugin context if the reset parameter is set
830
664
  if (hasParameter('reset') && getParameter('reset') !== undefined) {
831
665
  this.log.debug(`Reset plugin ${getParameter('reset')}`);
832
666
  const plugin = this.plugins.get(getParameter('reset'));
833
667
  if (plugin) {
834
668
  const matterStorageManager = await this.matterStorageService?.open(plugin.name);
835
669
  if (!matterStorageManager) {
836
- /* istanbul ignore next */
837
670
  this.log.error(`Plugin ${plg}${plugin.name}${er} storageManager not found`);
838
671
  }
839
672
  else {
@@ -852,39 +685,32 @@ export class Matterbridge extends EventEmitter {
852
685
  this.shutdown = true;
853
686
  return;
854
687
  }
855
- // Initialize frontend
856
688
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
857
689
  await this.frontend.start(getIntParameter('frontend'));
858
- // Check in 30 seconds the latest and dev versions of matterbridge and the plugins
859
690
  clearTimeout(this.checkUpdateTimeout);
860
691
  this.checkUpdateTimeout = setTimeout(async () => {
861
692
  const { checkUpdates } = await import('./update.js');
862
693
  checkUpdates(this);
863
694
  }, 30 * 1000).unref();
864
- // Check each 12 hours the latest and dev versions of matterbridge and the plugins
865
695
  clearInterval(this.checkUpdateInterval);
866
696
  this.checkUpdateInterval = setInterval(async () => {
867
697
  const { checkUpdates } = await import('./update.js');
868
698
  checkUpdates(this);
869
699
  }, 12 * 60 * 60 * 1000).unref();
870
- // Start the matterbridge in mode test
871
700
  if (hasParameter('test')) {
872
701
  this.bridgeMode = 'bridge';
873
702
  MatterbridgeEndpoint.bridgeMode = 'bridge';
874
703
  return;
875
704
  }
876
- // Start the matterbridge in mode controller
877
705
  if (hasParameter('controller')) {
878
706
  this.bridgeMode = 'controller';
879
707
  await this.startController();
880
708
  return;
881
709
  }
882
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
883
710
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
884
711
  this.log.info('Setting default matterbridge start mode to bridge');
885
712
  await this.nodeContext?.set('bridgeMode', 'bridge');
886
713
  }
887
- // Start matterbridge in bridge mode
888
714
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
889
715
  this.bridgeMode = 'bridge';
890
716
  MatterbridgeEndpoint.bridgeMode = 'bridge';
@@ -892,7 +718,6 @@ export class Matterbridge extends EventEmitter {
892
718
  await this.startBridge();
893
719
  return;
894
720
  }
895
- // Start matterbridge in childbridge mode
896
721
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
897
722
  this.bridgeMode = 'childbridge';
898
723
  MatterbridgeEndpoint.bridgeMode = 'childbridge';
@@ -901,20 +726,10 @@ export class Matterbridge extends EventEmitter {
901
726
  return;
902
727
  }
903
728
  }
904
- /**
905
- * Asynchronously loads and starts the registered plugins.
906
- *
907
- * This method is responsible for initializing and starting all enabled plugins.
908
- * It ensures that each plugin is properly loaded and started before the bridge starts.
909
- *
910
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
911
- */
912
729
  async startPlugins() {
913
- // Check, load and start the plugins
914
730
  for (const plugin of this.plugins) {
915
731
  plugin.configJson = await this.plugins.loadConfig(plugin);
916
732
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
917
- // Check if the plugin is available
918
733
  if (!(await this.plugins.resolve(plugin.path))) {
919
734
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
920
735
  plugin.enabled = false;
@@ -932,14 +747,10 @@ export class Matterbridge extends EventEmitter {
932
747
  plugin.configured = false;
933
748
  plugin.registeredDevices = undefined;
934
749
  plugin.addedDevices = undefined;
935
- this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
750
+ this.plugins.load(plugin, true, 'Matterbridge is starting');
936
751
  }
937
752
  this.frontend.wssSendRefreshRequired('plugins');
938
753
  }
939
- /**
940
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
941
- * When either of these signals are received, the cleanup method is called with an appropriate message.
942
- */
943
754
  registerProcessHandlers() {
944
755
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
945
756
  process.removeAllListeners('uncaughtException');
@@ -966,9 +777,6 @@ export class Matterbridge extends EventEmitter {
966
777
  };
967
778
  process.on('SIGTERM', this.sigtermHandler);
968
779
  }
969
- /**
970
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
971
- */
972
780
  deregisterProcessHandlers() {
973
781
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
974
782
  if (this.exceptionHandler)
@@ -985,17 +793,12 @@ export class Matterbridge extends EventEmitter {
985
793
  process.off('SIGTERM', this.sigtermHandler);
986
794
  this.sigtermHandler = undefined;
987
795
  }
988
- /**
989
- * Logs the node and system information.
990
- */
991
796
  async logNodeAndSystemInfo() {
992
- // IP address information
993
797
  const networkInterfaces = os.networkInterfaces();
994
798
  this.systemInformation.interfaceName = '';
995
799
  this.systemInformation.ipv4Address = '';
996
800
  this.systemInformation.ipv6Address = '';
997
801
  for (const [interfaceName, interfaceDetails] of Object.entries(networkInterfaces)) {
998
- // this.log.debug(`Checking interface: '${interfaceName}' for '${this.mdnsInterface}'`);
999
802
  if (this.mdnsInterface && interfaceName !== this.mdnsInterface)
1000
803
  continue;
1001
804
  if (!interfaceDetails) {
@@ -1021,22 +824,19 @@ export class Matterbridge extends EventEmitter {
1021
824
  break;
1022
825
  }
1023
826
  }
1024
- // Node information
1025
827
  this.systemInformation.nodeVersion = process.versions.node;
1026
828
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
1027
829
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
1028
830
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
1029
- // Host system information
1030
831
  this.systemInformation.hostname = os.hostname();
1031
832
  this.systemInformation.user = os.userInfo().username;
1032
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
1033
- this.systemInformation.osRelease = os.release(); // Kernel version
1034
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
1035
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
1036
- this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
1037
- this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
1038
- this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours'; // Convert to hours
1039
- // Log the system information
833
+ this.systemInformation.osType = os.type();
834
+ this.systemInformation.osRelease = os.release();
835
+ this.systemInformation.osPlatform = os.platform();
836
+ this.systemInformation.osArch = os.arch();
837
+ this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
838
+ this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
839
+ this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours';
1040
840
  this.log.debug('Host System Information:');
1041
841
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
1042
842
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -1052,17 +852,14 @@ export class Matterbridge extends EventEmitter {
1052
852
  this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
1053
853
  this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
1054
854
  this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
1055
- // Log directories
1056
855
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
1057
856
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
1058
857
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
1059
858
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
1060
859
  this.log.debug(`Matterbridge Matter Certificate Directory: ${this.matterbridgeCertDirectory}`);
1061
- // Global node_modules directory
1062
860
  if (this.nodeContext)
1063
861
  this.globalModulesDirectory = this.matterbridgeInformation.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
1064
862
  if (this.globalModulesDirectory === '') {
1065
- // First run of Matterbridge so the node storage is empty
1066
863
  try {
1067
864
  const { getGlobalNodeModules } = await import('./utils/network.js');
1068
865
  this.execRunningCount++;
@@ -1077,81 +874,50 @@ export class Matterbridge extends EventEmitter {
1077
874
  }
1078
875
  else
1079
876
  this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
1080
- /* removed cause is too expensive for the shelly board and not really needed. Why should the globalModulesDirectory change?
1081
- else {
1082
- this.getGlobalNodeModules()
1083
- .then(async (globalModulesDirectory) => {
1084
- this.globalModulesDirectory = globalModulesDirectory;
1085
- this.matterbridgeInformation.globalModulesDirectory = this.globalModulesDirectory;
1086
- this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
1087
- await this.nodeContext?.set<string>('globalModulesDirectory', this.globalModulesDirectory);
1088
- })
1089
- .catch((error) => {
1090
- this.log.error(`Error getting global node_modules directory: ${error}`);
1091
- });
1092
- }*/
1093
- // Matterbridge version
1094
877
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
1095
878
  this.matterbridgeVersion = this.matterbridgeLatestVersion = this.matterbridgeDevVersion = packageJson.version;
1096
879
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeInformation.matterbridgeLatestVersion = this.matterbridgeInformation.matterbridgeDevVersion = packageJson.version;
1097
880
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
1098
- // Matterbridge latest version (will be set in the checkUpdate function)
1099
881
  if (this.nodeContext)
1100
882
  this.matterbridgeLatestVersion = this.matterbridgeInformation.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', this.matterbridgeVersion);
1101
883
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
1102
- // Matterbridge dev version (will be set in the checkUpdate function)
1103
884
  if (this.nodeContext)
1104
885
  this.matterbridgeDevVersion = this.matterbridgeInformation.matterbridgeDevVersion = await this.nodeContext.get('matterbridgeDevVersion', this.matterbridgeVersion);
1105
886
  this.log.debug(`Matterbridge Dev Version: ${this.matterbridgeDevVersion}`);
1106
- // Current working directory
1107
887
  const currentDir = process.cwd();
1108
888
  this.log.debug(`Current Working Directory: ${currentDir}`);
1109
- // Command line arguments (excluding 'node' and the script name)
1110
889
  const cmdArgs = process.argv.slice(2).join(' ');
1111
890
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
1112
891
  }
1113
- /**
1114
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
1115
- *
1116
- * @returns {Function} The MatterLogger function.
1117
- */
1118
892
  createMatterLogger() {
1119
- const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
893
+ const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
1120
894
  return (level, formattedLog) => {
1121
895
  const logger = formattedLog.slice(44, 44 + 20).trim();
1122
896
  const message = formattedLog.slice(65);
1123
897
  matterLogger.logName = logger;
1124
898
  switch (level) {
1125
899
  case MatterLogLevel.DEBUG:
1126
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
900
+ matterLogger.log("debug", message);
1127
901
  break;
1128
902
  case MatterLogLevel.INFO:
1129
- matterLogger.log("info" /* LogLevel.INFO */, message);
903
+ matterLogger.log("info", message);
1130
904
  break;
1131
905
  case MatterLogLevel.NOTICE:
1132
- matterLogger.log("notice" /* LogLevel.NOTICE */, message);
906
+ matterLogger.log("notice", message);
1133
907
  break;
1134
908
  case MatterLogLevel.WARN:
1135
- matterLogger.log("warn" /* LogLevel.WARN */, message);
909
+ matterLogger.log("warn", message);
1136
910
  break;
1137
911
  case MatterLogLevel.ERROR:
1138
- matterLogger.log("error" /* LogLevel.ERROR */, message);
912
+ matterLogger.log("error", message);
1139
913
  break;
1140
914
  case MatterLogLevel.FATAL:
1141
- matterLogger.log("fatal" /* LogLevel.FATAL */, message);
915
+ matterLogger.log("fatal", message);
1142
916
  break;
1143
917
  }
1144
918
  };
1145
919
  }
1146
- /**
1147
- * Creates a Matter File Logger.
1148
- *
1149
- * @param {string} filePath - The path to the log file.
1150
- * @param {boolean} [unlink] - Whether to unlink the log file before creating a new one.
1151
- * @returns {Function} - A function that logs formatted messages to the log file.
1152
- */
1153
920
  async createMatterFileLogger(filePath, unlink = false) {
1154
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1155
921
  let fileSize = 0;
1156
922
  if (unlink) {
1157
923
  try {
@@ -1162,12 +928,10 @@ export class Matterbridge extends EventEmitter {
1162
928
  }
1163
929
  }
1164
930
  return async (level, formattedLog) => {
1165
- /* istanbul ignore if */
1166
931
  if (fileSize > 100000000) {
1167
- return; // Stop logging if the file size is greater than 100MB
932
+ return;
1168
933
  }
1169
934
  fileSize += formattedLog.length;
1170
- /* istanbul ignore if */
1171
935
  if (fileSize > 100000000) {
1172
936
  await fs.appendFile(filePath, `Logging on file has been stopped because the file size is greater than 100MB.` + os.EOL);
1173
937
  return;
@@ -1200,21 +964,12 @@ export class Matterbridge extends EventEmitter {
1200
964
  }
1201
965
  };
1202
966
  }
1203
- /**
1204
- * Restarts the process by exiting the current instance and loading a new instance.
1205
- */
1206
967
  async restartProcess() {
1207
968
  await this.cleanup('restarting...', true);
1208
969
  }
1209
- /**
1210
- * Shut down the process.
1211
- */
1212
970
  async shutdownProcess() {
1213
971
  await this.cleanup('shutting down...', false);
1214
972
  }
1215
- /**
1216
- * Update matterbridge and shut down the process.
1217
- */
1218
973
  async updateProcess() {
1219
974
  this.log.info('Updating matterbridge...');
1220
975
  try {
@@ -1228,75 +983,52 @@ export class Matterbridge extends EventEmitter {
1228
983
  this.frontend.wssSendRestartRequired();
1229
984
  await this.cleanup('updating...', false);
1230
985
  }
1231
- /**
1232
- * Unregister all devices and shut down the process.
1233
- */
1234
- async unregisterAndShutdownProcess() {
986
+ async unregisterAndShutdownProcess(timeout = 1000) {
1235
987
  this.log.info('Unregistering all devices and shutting down...');
1236
988
  for (const plugin of this.plugins) {
1237
989
  await this.removeAllBridgedEndpoints(plugin.name, 250);
1238
990
  }
1239
991
  this.log.debug('Waiting for the MessageExchange to finish...');
1240
- await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second for MessageExchange to finish
992
+ await new Promise((resolve) => setTimeout(resolve, timeout));
1241
993
  this.log.debug('Cleaning up and shutting down...');
1242
- await this.cleanup('unregistered all devices and shutting down...', false);
994
+ await this.cleanup('unregistered all devices and shutting down...', false, timeout);
1243
995
  }
1244
- /**
1245
- * Reset commissioning and shut down the process.
1246
- */
1247
996
  async shutdownProcessAndReset() {
1248
997
  await this.cleanup('shutting down with reset...', false);
1249
998
  }
1250
- /**
1251
- * Factory reset and shut down the process.
1252
- */
1253
999
  async shutdownProcessAndFactoryReset() {
1254
1000
  await this.cleanup('shutting down with factory reset...', false);
1255
1001
  }
1256
- /**
1257
- * Cleans up the Matterbridge instance.
1258
- *
1259
- * @param {string} message - The cleanup message.
1260
- * @param {boolean} [restart] - Indicates whether to restart the instance after cleanup. Default is `false`.
1261
- * @param {number} [timeout] - The timeout duration to wait for the message exchange to complete in milliseconds. Default is 1000.
1262
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1263
- */
1264
1002
  async cleanup(message, restart = false, timeout = 1000) {
1265
1003
  if (this.initialized && !this.hasCleanupStarted) {
1266
1004
  this.emit('cleanup_started');
1267
1005
  this.hasCleanupStarted = true;
1268
1006
  this.log.info(message);
1269
- // Clear the start matter interval
1270
1007
  if (this.startMatterInterval) {
1271
1008
  clearInterval(this.startMatterInterval);
1272
1009
  this.startMatterInterval = undefined;
1273
1010
  this.log.debug('Start matter interval cleared');
1274
1011
  }
1275
- // Clear the check update timeout
1276
1012
  if (this.checkUpdateTimeout) {
1277
1013
  clearTimeout(this.checkUpdateTimeout);
1278
1014
  this.checkUpdateTimeout = undefined;
1279
1015
  this.log.debug('Check update timeout cleared');
1280
1016
  }
1281
- // Clear the check update interval
1282
1017
  if (this.checkUpdateInterval) {
1283
1018
  clearInterval(this.checkUpdateInterval);
1284
1019
  this.checkUpdateInterval = undefined;
1285
1020
  this.log.debug('Check update interval cleared');
1286
1021
  }
1287
- // Clear the configure timeout
1288
1022
  if (this.configureTimeout) {
1289
1023
  clearTimeout(this.configureTimeout);
1290
1024
  this.configureTimeout = undefined;
1291
1025
  this.log.debug('Matterbridge configure timeout cleared');
1292
1026
  }
1293
- // Clear the reachability timeout
1294
1027
  if (this.reachabilityTimeout) {
1295
1028
  clearTimeout(this.reachabilityTimeout);
1296
1029
  this.reachabilityTimeout = undefined;
1297
1030
  this.log.debug('Matterbridge reachability timeout cleared');
1298
1031
  }
1299
- // Call the shutdown method of each plugin and clear the plugins reachability timeout
1300
1032
  for (const plugin of this.plugins) {
1301
1033
  if (!plugin.enabled || plugin.error)
1302
1034
  continue;
@@ -1307,10 +1039,9 @@ export class Matterbridge extends EventEmitter {
1307
1039
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1308
1040
  }
1309
1041
  }
1310
- // Stop matter server nodes
1311
1042
  this.log.notice(`Stopping matter server nodes in ${this.bridgeMode} mode...`);
1312
1043
  this.log.debug('Waiting for the MessageExchange to finish...');
1313
- await new Promise((resolve) => setTimeout(resolve, timeout)); // Wait for MessageExchange to finish
1044
+ await new Promise((resolve) => setTimeout(resolve, timeout));
1314
1045
  if (this.bridgeMode === 'bridge') {
1315
1046
  if (this.serverNode) {
1316
1047
  await this.stopServerNode(this.serverNode);
@@ -1332,7 +1063,6 @@ export class Matterbridge extends EventEmitter {
1332
1063
  }
1333
1064
  }
1334
1065
  this.log.notice('Stopped matter server nodes');
1335
- // Matter commisioning reset
1336
1066
  if (message === 'shutting down with reset...') {
1337
1067
  this.log.info('Resetting Matterbridge commissioning information...');
1338
1068
  await this.matterStorageManager?.createContext('events')?.clearAll();
@@ -1342,36 +1072,18 @@ export class Matterbridge extends EventEmitter {
1342
1072
  await this.matterbridgeContext?.clearAll();
1343
1073
  this.log.info('Matter storage reset done! Remove the bridge from the controller.');
1344
1074
  }
1345
- // Stop matter storage
1346
1075
  await this.stopMatterStorage();
1347
- // Stop the frontend
1348
1076
  await this.frontend.stop();
1349
- // Remove the matterfilelogger
1350
1077
  try {
1351
1078
  Logger.removeLogger('matterfilelogger');
1352
1079
  }
1353
1080
  catch (error) {
1354
1081
  this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${db}: ${error instanceof Error ? error.message : String(error)}`);
1355
1082
  }
1356
- // Close the matterbridge node storage and context
1357
1083
  if (this.nodeStorage && this.nodeContext) {
1358
- /*
1359
- TODO: Implement serialization of registered devices in edge mode
1360
- this.log.info('Saving registered devices...');
1361
- const serializedRegisteredDevices: SerializedMatterbridgeEndpoint[] = [];
1362
- this.devices.forEach(async (device) => {
1363
- const serializedMatterbridgeDevice = MatterbridgeEndpoint.serialize(device);
1364
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1365
- if (serializedMatterbridgeDevice) serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1366
- });
1367
- await this.nodeContext.set<SerializedMatterbridgeEndpoint[]>('devices', serializedRegisteredDevices);
1368
- this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1369
- */
1370
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1371
1084
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1372
1085
  await this.nodeContext.close();
1373
1086
  this.nodeContext = undefined;
1374
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1375
1087
  for (const plugin of this.plugins) {
1376
1088
  if (plugin.nodeContext) {
1377
1089
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1388,10 +1100,8 @@ export class Matterbridge extends EventEmitter {
1388
1100
  }
1389
1101
  this.plugins.clear();
1390
1102
  this.devices.clear();
1391
- // Factory reset
1392
1103
  if (message === 'shutting down with factory reset...') {
1393
1104
  try {
1394
- // Delete matter storage directory with its subdirectories and backup
1395
1105
  const dir = path.join(this.matterbridgeDirectory, this.matterStorageName);
1396
1106
  this.log.info(`Removing matter storage directory: ${dir}`);
1397
1107
  await fs.rm(dir, { recursive: true });
@@ -1405,7 +1115,6 @@ export class Matterbridge extends EventEmitter {
1405
1115
  }
1406
1116
  }
1407
1117
  try {
1408
- // Delete matterbridge storage directory with its subdirectories and backup
1409
1118
  const dir = path.join(this.matterbridgeDirectory, this.nodeStorageName);
1410
1119
  this.log.info(`Removing matterbridge storage directory: ${dir}`);
1411
1120
  await fs.rm(dir, { recursive: true });
@@ -1420,13 +1129,12 @@ export class Matterbridge extends EventEmitter {
1420
1129
  }
1421
1130
  this.log.info('Factory reset done! Remove all paired fabrics from the controllers.');
1422
1131
  }
1423
- // Deregisters the process handlers
1424
1132
  this.deregisterProcessHandlers();
1425
1133
  if (restart) {
1426
1134
  if (message === 'updating...') {
1427
1135
  this.log.info('Cleanup completed. Updating...');
1428
1136
  Matterbridge.instance = undefined;
1429
- this.emit('update'); // Restart the process but the update has been done before. TODO move all updates to the cli
1137
+ this.emit('update');
1430
1138
  }
1431
1139
  else if (message === 'restarting...') {
1432
1140
  this.log.info('Cleanup completed. Restarting...');
@@ -1447,13 +1155,6 @@ export class Matterbridge extends EventEmitter {
1447
1155
  this.log.debug('Cleanup already started...');
1448
1156
  }
1449
1157
  }
1450
- /**
1451
- * Creates and configures the server node for a single not bridged device.
1452
- *
1453
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1454
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
1455
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
1456
- */
1457
1158
  async createDeviceServerNode(plugin, device) {
1458
1159
  if (device.mode === 'server' && !device.serverNode && device.deviceType && device.deviceName && device.vendorId && device.vendorName && device.productId && device.productName) {
1459
1160
  this.log.debug(`Creating device ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} server node...`);
@@ -1464,15 +1165,7 @@ export class Matterbridge extends EventEmitter {
1464
1165
  this.log.debug(`Added ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to server node`);
1465
1166
  }
1466
1167
  }
1467
- /**
1468
- * Creates and configures the server node for an accessory plugin for a given device.
1469
- *
1470
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1471
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
1472
- * @param {boolean} [start] - Whether to start the server node after adding the device. Default is `false`.
1473
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
1474
- */
1475
- async createAccessoryPlugin(plugin, device, start = false) {
1168
+ async createAccessoryPlugin(plugin, device) {
1476
1169
  if (!plugin.locked && device.deviceType && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
1477
1170
  plugin.locked = true;
1478
1171
  plugin.device = device;
@@ -1481,16 +1174,8 @@ export class Matterbridge extends EventEmitter {
1481
1174
  plugin.serialNumber = await plugin.storageContext.get('serialNumber', '');
1482
1175
  this.log.debug(`Adding ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to ${plg}${plugin.name}${db} server node`);
1483
1176
  await plugin.serverNode.add(device);
1484
- if (start)
1485
- await this.startServerNode(plugin.serverNode);
1486
1177
  }
1487
1178
  }
1488
- /**
1489
- * Creates and configures the server node and the aggregator node for a dynamic plugin.
1490
- *
1491
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1492
- * @returns {Promise<void>} A promise that resolves when the server node and the aggregator node for the dynamic plugin is created and configured.
1493
- */
1494
1179
  async createDynamicPlugin(plugin) {
1495
1180
  if (!plugin.locked) {
1496
1181
  plugin.locked = true;
@@ -1501,14 +1186,7 @@ export class Matterbridge extends EventEmitter {
1501
1186
  await plugin.serverNode.add(plugin.aggregatorNode);
1502
1187
  }
1503
1188
  }
1504
- /**
1505
- * Starts the Matterbridge in bridge mode.
1506
- *
1507
- * @private
1508
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1509
- */
1510
1189
  async startBridge() {
1511
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1512
1190
  if (!this.matterStorageManager)
1513
1191
  throw new Error('No storage manager initialized');
1514
1192
  if (!this.matterbridgeContext)
@@ -1547,18 +1225,15 @@ export class Matterbridge extends EventEmitter {
1547
1225
  clearInterval(this.startMatterInterval);
1548
1226
  this.startMatterInterval = undefined;
1549
1227
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1550
- // Start the Matter server node
1551
- this.startServerNode(this.serverNode); // We don't await this, because the server node is started in the background
1552
- // Start the Matter server node of single devices in mode 'server'
1228
+ this.startServerNode(this.serverNode);
1553
1229
  for (const device of this.devices.array()) {
1554
1230
  if (device.mode === 'server' && device.serverNode) {
1555
1231
  this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
1556
- this.startServerNode(device.serverNode); // We don't await this, because the server node is started in the background
1232
+ this.startServerNode(device.serverNode);
1557
1233
  }
1558
1234
  }
1559
- // Configure the plugins
1560
1235
  this.configureTimeout = setTimeout(async () => {
1561
- for (const plugin of this.plugins) {
1236
+ for (const plugin of this.plugins.array()) {
1562
1237
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1563
1238
  continue;
1564
1239
  try {
@@ -1574,25 +1249,17 @@ export class Matterbridge extends EventEmitter {
1574
1249
  }
1575
1250
  this.frontend.wssSendRefreshRequired('plugins');
1576
1251
  }, 30 * 1000).unref();
1577
- // Setting reachability to true
1578
1252
  this.reachabilityTimeout = setTimeout(() => {
1579
1253
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1580
1254
  if (this.aggregatorNode)
1581
1255
  this.setAggregatorReachability(this.aggregatorNode, true);
1582
1256
  this.frontend.wssSendRefreshRequired('reachability');
1583
1257
  }, 60 * 1000).unref();
1584
- // Logger.get('LogServerNode').info(this.serverNode);
1585
1258
  this.emit('bridge_started');
1586
1259
  this.log.notice('Matterbridge bridge started successfully');
1587
1260
  }, 1000);
1588
1261
  }
1589
- /**
1590
- * Starts the Matterbridge in childbridge mode.
1591
- *
1592
- * @private
1593
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1594
- */
1595
- async startChildbridge() {
1262
+ async startChildbridge(delay = 1000) {
1596
1263
  if (!this.matterStorageManager)
1597
1264
  throw new Error('No storage manager initialized');
1598
1265
  await this.startPlugins();
@@ -1600,7 +1267,7 @@ export class Matterbridge extends EventEmitter {
1600
1267
  let failCount = 0;
1601
1268
  this.startMatterInterval = setInterval(async () => {
1602
1269
  let allStarted = true;
1603
- for (const plugin of this.plugins) {
1270
+ for (const plugin of this.plugins.array()) {
1604
1271
  if (!plugin.enabled)
1605
1272
  continue;
1606
1273
  if (plugin.error) {
@@ -1619,7 +1286,7 @@ export class Matterbridge extends EventEmitter {
1619
1286
  this.log.debug(`Waiting (failSafeCount=${failCount}/${this.failCountLimit}) for plugin ${plg}${plugin.name}${db} to load (${plugin.loaded}) and start (${plugin.started}) ...`);
1620
1287
  failCount++;
1621
1288
  if (failCount > this.failCountLimit) {
1622
- this.log.error(`Error waiting for plugin ${plg}${plugin.name}${er} to load and start. Plugin is in error mode.`);
1289
+ this.log.error(`Error waiting for plugin ${plg}${plugin.name}${er} to load and start. Plugin is in error state.`);
1623
1290
  plugin.error = true;
1624
1291
  }
1625
1292
  }
@@ -1628,11 +1295,11 @@ export class Matterbridge extends EventEmitter {
1628
1295
  return;
1629
1296
  clearInterval(this.startMatterInterval);
1630
1297
  this.startMatterInterval = undefined;
1631
- await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second to ensure all plugins server nodes are ready
1298
+ if (delay > 0)
1299
+ await wait(delay);
1632
1300
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1633
- // Configure the plugins
1634
1301
  this.configureTimeout = setTimeout(async () => {
1635
- for (const plugin of this.plugins) {
1302
+ for (const plugin of this.plugins.array()) {
1636
1303
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
1637
1304
  continue;
1638
1305
  try {
@@ -1667,9 +1334,7 @@ export class Matterbridge extends EventEmitter {
1667
1334
  this.log.error(`Node storage context not found for plugin ${plg}${plugin.name}${er}`);
1668
1335
  continue;
1669
1336
  }
1670
- // Start the Matter server node
1671
- this.startServerNode(plugin.serverNode); // We don't await this, because the server node is started in the background
1672
- // Setting reachability to true
1337
+ this.startServerNode(plugin.serverNode);
1673
1338
  plugin.reachabilityTimeout = setTimeout(() => {
1674
1339
  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}`);
1675
1340
  if (plugin.type === 'DynamicPlatform' && plugin.aggregatorNode)
@@ -1677,241 +1342,19 @@ export class Matterbridge extends EventEmitter {
1677
1342
  this.frontend.wssSendRefreshRequired('reachability');
1678
1343
  }, 60 * 1000).unref();
1679
1344
  }
1680
- // Start the Matter server node of single devices in mode 'server'
1681
1345
  for (const device of this.devices.array()) {
1682
1346
  if (device.mode === 'server' && device.serverNode) {
1683
1347
  this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
1684
- this.startServerNode(device.serverNode); // We don't await this, because the server node is started in the background
1348
+ this.startServerNode(device.serverNode);
1685
1349
  }
1686
1350
  }
1687
- // Logger.get('LogServerNode').info(this.serverNode);
1688
1351
  this.emit('childbridge_started');
1689
1352
  this.log.notice('Matterbridge childbridge started successfully');
1690
1353
  }, 1000);
1691
1354
  }
1692
- /**
1693
- * Starts the Matterbridge controller.
1694
- *
1695
- * @private
1696
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1697
- */
1698
1355
  async startController() {
1699
- /*
1700
- if (!this.matterStorageManager) {
1701
- this.log.error('No storage manager initialized');
1702
- await this.cleanup('No storage manager initialized');
1703
- return;
1704
- }
1705
- this.log.info('Creating context: mattercontrollerContext');
1706
- this.controllerContext = this.matterStorageManager.createContext('mattercontrollerContext');
1707
- if (!this.controllerContext) {
1708
- this.log.error('No storage context mattercontrollerContext initialized');
1709
- await this.cleanup('No storage context mattercontrollerContext initialized');
1710
- return;
1711
- }
1712
-
1713
- this.log.debug('Starting matterbridge in mode', this.bridgeMode);
1714
- this.matterServer = await this.createMatterServer(this.storageManager);
1715
- this.log.info('Creating matter commissioning controller');
1716
- this.commissioningController = new CommissioningController({
1717
- autoConnect: false,
1718
- });
1719
- this.log.info('Adding matter commissioning controller to matter server');
1720
- await this.matterServer.addCommissioningController(this.commissioningController);
1721
-
1722
- this.log.info('Starting matter server');
1723
- await this.matterServer.start();
1724
- this.log.info('Matter server started');
1725
- const commissioningOptions: ControllerCommissioningFlowOptions = {
1726
- regulatoryLocation: GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor,
1727
- regulatoryCountryCode: 'XX',
1728
- };
1729
- const commissioningController = new CommissioningController({
1730
- environment: {
1731
- environment,
1732
- id: uniqueId,
1733
- },
1734
- autoConnect: false, // Do not auto connect to the commissioned nodes
1735
- adminFabricLabel,
1736
- });
1737
-
1738
- if (hasParameter('pairingcode')) {
1739
- this.log.info('Pairing device with pairingcode:', getParameter('pairingcode'));
1740
- const pairingCode = getParameter('pairingcode');
1741
- const ip = this.controllerContext.has('ip') ? this.controllerContext.get<string>('ip') : undefined;
1742
- const port = this.controllerContext.has('port') ? this.controllerContext.get<number>('port') : undefined;
1743
-
1744
- let longDiscriminator, setupPin, shortDiscriminator;
1745
- if (pairingCode !== undefined) {
1746
- const pairingCodeCodec = ManualPairingCodeCodec.decode(pairingCode);
1747
- shortDiscriminator = pairingCodeCodec.shortDiscriminator;
1748
- longDiscriminator = undefined;
1749
- setupPin = pairingCodeCodec.passcode;
1750
- this.log.info(`Data extracted from pairing code: ${Logger.toJSON(pairingCodeCodec)}`);
1751
- } else {
1752
- longDiscriminator = await this.controllerContext.get('longDiscriminator', 3840);
1753
- if (longDiscriminator > 4095) throw new Error('Discriminator value must be less than 4096');
1754
- setupPin = this.controllerContext.get('pin', 20202021);
1755
- }
1756
- if ((shortDiscriminator === undefined && longDiscriminator === undefined) || setupPin === undefined) {
1757
- throw new Error('Please specify the longDiscriminator of the device to commission with -longDiscriminator or provide a valid passcode with -passcode');
1758
- }
1759
-
1760
- const options = {
1761
- commissioning: commissioningOptions,
1762
- discovery: {
1763
- knownAddress: ip !== undefined && port !== undefined ? { ip, port, type: 'udp' } : undefined,
1764
- identifierData: longDiscriminator !== undefined ? { longDiscriminator } : shortDiscriminator !== undefined ? { shortDiscriminator } : {},
1765
- },
1766
- passcode: setupPin,
1767
- } as NodeCommissioningOptions;
1768
- this.log.info('Commissioning with options:', options);
1769
- const nodeId = await this.commissioningController.commissionNode(options);
1770
- this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1771
- this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1772
- } // (hasParameter('pairingcode'))
1773
-
1774
- if (hasParameter('unpairall')) {
1775
- this.log.info('***Commissioning controller unpairing all nodes...');
1776
- const nodeIds = this.commissioningController.getCommissionedNodes();
1777
- for (const nodeId of nodeIds) {
1778
- this.log.info('***Commissioning controller unpairing node:', nodeId);
1779
- await this.commissioningController.removeNode(nodeId);
1780
- }
1781
- return;
1782
- }
1783
-
1784
- if (hasParameter('discover')) {
1785
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1786
- // console.log(discover);
1787
- }
1788
-
1789
- if (!this.commissioningController.isCommissioned()) {
1790
- this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
1791
- return;
1792
- }
1793
-
1794
- const nodeIds = this.commissioningController.getCommissionedNodes();
1795
- this.log.info(`***Commissioning controller is commissioned ${this.commissioningController.isCommissioned()} and has ${nodeIds.length} nodes commisioned: `);
1796
- for (const nodeId of nodeIds) {
1797
- this.log.info(`***Connecting to commissioned node: ${nodeId}`);
1798
-
1799
- const node = await this.commissioningController.connectNode(nodeId, {
1800
- autoSubscribe: false,
1801
- attributeChangedCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, attributeName }, value }) =>
1802
- this.log.info(`***Commissioning controller attributeChangedCallback ${peerNodeId}: attribute ${nodeId}/${endpointId}/${clusterId}/${attributeName} changed to ${Logger.toJSON(value)}`),
1803
- eventTriggeredCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, eventName }, events }) =>
1804
- this.log.info(`***Commissioning controller eventTriggeredCallback ${peerNodeId}: Event ${nodeId}/${endpointId}/${clusterId}/${eventName} triggered with ${Logger.toJSON(events)}`),
1805
- stateInformationCallback: (peerNodeId, info) => {
1806
- switch (info) {
1807
- case NodeStateInformation.Connected:
1808
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} connected`);
1809
- break;
1810
- case NodeStateInformation.Disconnected:
1811
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} disconnected`);
1812
- break;
1813
- case NodeStateInformation.Reconnecting:
1814
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} reconnecting`);
1815
- break;
1816
- case NodeStateInformation.WaitingForDeviceDiscovery:
1817
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} waiting for device discovery`);
1818
- break;
1819
- case NodeStateInformation.StructureChanged:
1820
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} structure changed`);
1821
- break;
1822
- case NodeStateInformation.Decommissioned:
1823
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} decommissioned`);
1824
- break;
1825
- default:
1826
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} NodeStateInformation.${info}`);
1827
- break;
1828
- }
1829
- },
1830
- });
1831
-
1832
- node.logStructure();
1833
-
1834
- // Get the interaction client
1835
- this.log.info('Getting the interaction client');
1836
- const interactionClient = await node.getInteractionClient();
1837
- let cluster;
1838
- let attributes;
1839
-
1840
- // Log BasicInformationCluster
1841
- cluster = BasicInformationCluster;
1842
- attributes = await interactionClient.getMultipleAttributes({
1843
- attributes: [{ clusterId: cluster.id }],
1844
- });
1845
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1846
- attributes.forEach((attribute) => {
1847
- this.log.info(
1848
- `- endpoint ${or}${attribute.path.endpointId}${nf} cluster ${hk}${getClusterNameById(attribute.path.clusterId)}${nf} (${hk}0x${attribute.path.clusterId.toString(16)}${nf}) attribute ${zb}${attribute.path.attributeName}${nf} (${zb}0x${attribute.path.attributeId.toString(16)}${nf}): ${typeof attribute.value === 'object' ? stringify(attribute.value) : attribute.value}`,
1849
- );
1850
- });
1851
-
1852
- // Log PowerSourceCluster
1853
- cluster = PowerSourceCluster;
1854
- attributes = await interactionClient.getMultipleAttributes({
1855
- attributes: [{ clusterId: cluster.id }],
1856
- });
1857
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1858
- attributes.forEach((attribute) => {
1859
- this.log.info(
1860
- `- endpoint ${or}${attribute.path.endpointId}${nf} cluster ${hk}${getClusterNameById(attribute.path.clusterId)}${nf} (${hk}0x${attribute.path.clusterId.toString(16)}${nf}) attribute ${zb}${attribute.path.attributeName}${nf} (${zb}0x${attribute.path.attributeId.toString(16)}${nf}): ${typeof attribute.value === 'object' ? stringify(attribute.value) : attribute.value}`,
1861
- );
1862
- });
1863
-
1864
- // Log ThreadNetworkDiagnostics
1865
- cluster = ThreadNetworkDiagnosticsCluster;
1866
- attributes = await interactionClient.getMultipleAttributes({
1867
- attributes: [{ clusterId: cluster.id }],
1868
- });
1869
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1870
- attributes.forEach((attribute) => {
1871
- this.log.info(
1872
- `- endpoint ${or}${attribute.path.endpointId}${nf} cluster ${hk}${getClusterNameById(attribute.path.clusterId)}${nf} (${hk}0x${attribute.path.clusterId.toString(16)}${nf}) attribute ${zb}${attribute.path.attributeName}${nf} (${zb}0x${attribute.path.attributeId.toString(16)}${nf}): ${typeof attribute.value === 'object' ? stringify(attribute.value) : attribute.value}`,
1873
- );
1874
- });
1875
-
1876
- // Log SwitchCluster
1877
- cluster = SwitchCluster;
1878
- attributes = await interactionClient.getMultipleAttributes({
1879
- attributes: [{ clusterId: cluster.id }],
1880
- });
1881
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1882
- attributes.forEach((attribute) => {
1883
- this.log.info(
1884
- `- endpoint ${or}${attribute.path.endpointId}${nf} cluster ${hk}${getClusterNameById(attribute.path.clusterId)}${nf} (${hk}0x${attribute.path.clusterId.toString(16)}${nf}) attribute ${zb}${attribute.path.attributeName}${nf} (${zb}0x${attribute.path.attributeId.toString(16)}${nf}): ${typeof attribute.value === 'object' ? stringify(attribute.value) : attribute.value}`,
1885
- );
1886
- });
1887
-
1888
- this.log.info('Subscribing to all attributes and events');
1889
- await node.subscribeAllAttributesAndEvents({
1890
- ignoreInitialTriggers: false,
1891
- attributeChangedCallback: ({ path: { nodeId, clusterId, endpointId, attributeName }, version, value }) =>
1892
- this.log.info(
1893
- `***${db}Commissioning controller attributeChangedCallback version ${version}: attribute ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${attributeName}${db} changed to ${typeof value === 'object' ? debugStringify(value ?? { none: true }) : value}`,
1894
- ),
1895
- eventTriggeredCallback: ({ path: { nodeId, clusterId, endpointId, eventName }, events }) => {
1896
- this.log.info(
1897
- `***${db}Commissioning controller eventTriggeredCallback: event ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${eventName}${db} triggered with ${debugStringify(events ?? { none: true })}`,
1898
- );
1899
- },
1900
- });
1901
- this.log.info('Subscribed to all attributes and events');
1902
- }
1903
- */
1904
1356
  }
1905
- /** */
1906
- /** Matter.js methods */
1907
- /** */
1908
- /**
1909
- * Starts the matter storage with name Matterbridge, create the matterbridge context and performs a backup.
1910
- *
1911
- * @returns {Promise<void>} - A promise that resolves when the storage is started.
1912
- */
1913
1357
  async startMatterStorage() {
1914
- // Setup Matter storage
1915
1358
  this.log.info(`Starting matter node storage...`);
1916
1359
  this.matterStorageService = this.environment.get(StorageService);
1917
1360
  this.log.info(`Matter node storage service created: ${this.matterStorageService.location}`);
@@ -1920,17 +1363,8 @@ export class Matterbridge extends EventEmitter {
1920
1363
  this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', bridge.code, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName);
1921
1364
  this.matterbridgeInformation.matterbridgeSerialNumber = await this.matterbridgeContext.get('serialNumber', '');
1922
1365
  this.log.info('Matter node storage started');
1923
- // Backup matter storage since it is created/opened correctly
1924
1366
  await this.backupMatterStorage(path.join(this.matterbridgeDirectory, this.matterStorageName), path.join(this.matterbridgeDirectory, this.matterStorageName + '.backup'));
1925
1367
  }
1926
- /**
1927
- * Makes a backup copy of the specified matter storage directory.
1928
- *
1929
- * @param {string} storageName - The name of the storage directory to be backed up.
1930
- * @param {string} backupName - The name of the backup directory to be created.
1931
- * @private
1932
- * @returns {Promise<void>} A promise that resolves when the has been done.
1933
- */
1934
1368
  async backupMatterStorage(storageName, backupName) {
1935
1369
  this.log.info('Creating matter node storage backup...');
1936
1370
  try {
@@ -1941,11 +1375,6 @@ export class Matterbridge extends EventEmitter {
1941
1375
  this.log.error(`Error creating matter node storage backup from ${storageName} to ${backupName}:`, error);
1942
1376
  }
1943
1377
  }
1944
- /**
1945
- * Stops the matter storage.
1946
- *
1947
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1948
- */
1949
1378
  async stopMatterStorage() {
1950
1379
  this.log.info('Closing matter node storage...');
1951
1380
  await this.matterStorageManager?.close();
@@ -1954,19 +1383,6 @@ export class Matterbridge extends EventEmitter {
1954
1383
  this.matterbridgeContext = undefined;
1955
1384
  this.log.info('Matter node storage closed');
1956
1385
  }
1957
- /**
1958
- * Creates a server node storage context.
1959
- *
1960
- * @param {string} pluginName - The name of the plugin.
1961
- * @param {string} deviceName - The name of the device.
1962
- * @param {DeviceTypeId} deviceType - The device type of the device.
1963
- * @param {number} vendorId - The vendor ID.
1964
- * @param {string} vendorName - The vendor name.
1965
- * @param {number} productId - The product ID.
1966
- * @param {string} productName - The product name.
1967
- * @param {string} [serialNumber] - The serial number of the device (optional).
1968
- * @returns {Promise<StorageContext>} The storage context for the commissioning server.
1969
- */
1970
1386
  async createServerNodeContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber) {
1971
1387
  const { randomBytes } = await import('node:crypto');
1972
1388
  if (!this.matterStorageService)
@@ -2000,15 +1416,6 @@ export class Matterbridge extends EventEmitter {
2000
1416
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2001
1417
  return storageContext;
2002
1418
  }
2003
- /**
2004
- * Creates a server node.
2005
- *
2006
- * @param {StorageContext} storageContext - The storage context for the server node.
2007
- * @param {number} [port] - The port number for the server node. Defaults to 5540.
2008
- * @param {number} [passcode] - The passcode for the server node. Defaults to 20242025.
2009
- * @param {number} [discriminator] - The discriminator for the server node. Defaults to 3850.
2010
- * @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created server node.
2011
- */
2012
1419
  async createServerNode(storageContext, port = 5540, passcode = 20242025, discriminator = 3850) {
2013
1420
  const storeId = await storageContext.get('storeId');
2014
1421
  this.log.notice(`Creating server node for ${storeId} on port ${port} with passcode ${passcode} and discriminator ${discriminator}...`);
@@ -2018,37 +1425,24 @@ export class Matterbridge extends EventEmitter {
2018
1425
  this.log.debug(`- uniqueId: ${await storageContext.get('uniqueId')}`);
2019
1426
  this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
2020
1427
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2021
- /**
2022
- * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
2023
- */
2024
1428
  const serverNode = await ServerNode.create({
2025
- // Required: Give the Node a unique ID which is used to store the state of this node
2026
1429
  id: storeId,
2027
- // Provide Network relevant configuration like the port
2028
- // Optional when operating only one device on a host, Default port is 5540
2029
1430
  network: {
2030
1431
  listeningAddressIpv4: this.ipv4address,
2031
1432
  listeningAddressIpv6: this.ipv6address,
2032
1433
  port,
2033
1434
  },
2034
- // Provide the certificate for the device
2035
1435
  operationalCredentials: {
2036
1436
  certification: this.certification,
2037
1437
  },
2038
- // Provide Commissioning relevant settings
2039
- // Optional for development/testing purposes
2040
1438
  commissioning: {
2041
1439
  passcode,
2042
1440
  discriminator,
2043
1441
  },
2044
- // Provide Node announcement settings
2045
- // Optional: If Ommitted some development defaults are used
2046
1442
  productDescription: {
2047
1443
  name: await storageContext.get('deviceName'),
2048
1444
  deviceType: DeviceTypeId(await storageContext.get('deviceType')),
2049
1445
  },
2050
- // Provide defaults for the BasicInformation cluster on the Root endpoint
2051
- // Optional: If Omitted some development defaults are used
2052
1446
  basicInformation: {
2053
1447
  vendorId: VendorId(await storageContext.get('vendorId')),
2054
1448
  vendorName: await storageContext.get('vendorName'),
@@ -2065,20 +1459,14 @@ export class Matterbridge extends EventEmitter {
2065
1459
  reachable: true,
2066
1460
  },
2067
1461
  });
2068
- /**
2069
- * This event is triggered when the device is initially commissioned successfully.
2070
- * This means: It is added to the first fabric.
2071
- */
2072
1462
  serverNode.lifecycle.commissioned.on(() => {
2073
1463
  this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`);
2074
1464
  clearTimeout(this.endAdvertiseTimeout);
2075
1465
  });
2076
- /** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
2077
1466
  serverNode.lifecycle.decommissioned.on(() => {
2078
1467
  this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`);
2079
1468
  clearTimeout(this.endAdvertiseTimeout);
2080
1469
  });
2081
- /** This event is triggered when the device went online. This means that it is discoverable in the network. */
2082
1470
  serverNode.lifecycle.online.on(async () => {
2083
1471
  this.log.notice(`Server node for ${storeId} is online`);
2084
1472
  if (!serverNode.lifecycle.isCommissioned) {
@@ -2086,7 +1474,6 @@ export class Matterbridge extends EventEmitter {
2086
1474
  const { qrPairingCode, manualPairingCode } = serverNode.state.commissioning.pairingCodes;
2087
1475
  this.log.notice(`QR Code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=${qrPairingCode}`);
2088
1476
  this.log.notice(`Manual pairing code: ${manualPairingCode}`);
2089
- // Set a timeout to show that advertising stops after 15 minutes if not commissioned
2090
1477
  this.startEndAdvertiseTimer(serverNode);
2091
1478
  }
2092
1479
  else {
@@ -2097,19 +1484,14 @@ export class Matterbridge extends EventEmitter {
2097
1484
  this.frontend.wssSendSnackbarMessage(`${storeId} is online`, 5, 'success');
2098
1485
  this.emit('online', storeId);
2099
1486
  });
2100
- /** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
2101
1487
  serverNode.lifecycle.offline.on(() => {
2102
1488
  this.log.notice(`Server node for ${storeId} is offline`);
2103
- this.matterbridgeInformation.matterbridgeEndAdvertise = true; // Set the end advertise flag to true, so the frontend won't show the QR code anymore
1489
+ this.matterbridgeInformation.matterbridgeEndAdvertise = true;
2104
1490
  this.frontend.wssSendRefreshRequired('plugins');
2105
1491
  this.frontend.wssSendRefreshRequired('settings');
2106
1492
  this.frontend.wssSendSnackbarMessage(`${storeId} is offline`, 5, 'warning');
2107
1493
  this.emit('offline', storeId);
2108
1494
  });
2109
- /**
2110
- * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
2111
- * information is needed.
2112
- */
2113
1495
  serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
2114
1496
  let action = '';
2115
1497
  switch (fabricAction) {
@@ -2126,22 +1508,14 @@ export class Matterbridge extends EventEmitter {
2126
1508
  this.log.notice(`Commissioned fabric index ${fabricIndex} ${action} on server node for ${storeId}: ${debugStringify(serverNode.state.commissioning.fabrics[fabricIndex])}`);
2127
1509
  this.frontend.wssSendRefreshRequired('fabrics');
2128
1510
  });
2129
- /**
2130
- * This event is triggered when an operative new session was opened by a Controller.
2131
- * It is not triggered for the initial commissioning process, just afterwards for real connections.
2132
- */
2133
1511
  serverNode.events.sessions.opened.on((session) => {
2134
1512
  this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
2135
1513
  this.frontend.wssSendRefreshRequired('sessions');
2136
1514
  });
2137
- /**
2138
- * This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
2139
- */
2140
1515
  serverNode.events.sessions.closed.on((session) => {
2141
1516
  this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
2142
1517
  this.frontend.wssSendRefreshRequired('sessions');
2143
1518
  });
2144
- /** This event is triggered when a subscription gets added or removed on an operative session. */
2145
1519
  serverNode.events.sessions.subscriptionsChanged.on((session) => {
2146
1520
  this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
2147
1521
  this.frontend.wssSendRefreshRequired('sessions');
@@ -2149,11 +1523,6 @@ export class Matterbridge extends EventEmitter {
2149
1523
  this.log.info(`Created server node for ${storeId}`);
2150
1524
  return serverNode;
2151
1525
  }
2152
- /**
2153
- * Starts the 15 minutes timer to advice that advertising for the specified server node is ended.
2154
- *
2155
- * @param {ServerNode} [matterServerNode] - The server node to start.
2156
- */
2157
1526
  startEndAdvertiseTimer(matterServerNode) {
2158
1527
  if (this.endAdvertiseTimeout) {
2159
1528
  this.log.debug(`Clear ${matterServerNode.id} server node end advertise timer`);
@@ -2172,25 +1541,12 @@ export class Matterbridge extends EventEmitter {
2172
1541
  this.log.notice(`Advertising on server node for ${matterServerNode.id} stopped. Restart to commission.`);
2173
1542
  }, 15 * 60 * 1000).unref();
2174
1543
  }
2175
- /**
2176
- * Starts the specified server node.
2177
- *
2178
- * @param {ServerNode} [matterServerNode] - The server node to start.
2179
- * @returns {Promise<void>} A promise that resolves when the server node has started.
2180
- */
2181
1544
  async startServerNode(matterServerNode) {
2182
1545
  if (!matterServerNode)
2183
1546
  return;
2184
1547
  this.log.notice(`Starting ${matterServerNode.id} server node`);
2185
1548
  await matterServerNode.start();
2186
1549
  }
2187
- /**
2188
- * Stops the specified server node.
2189
- *
2190
- * @param {ServerNode} matterServerNode - The server node to stop.
2191
- * @param {number} [timeout] - The timeout in milliseconds for stopping the server node. Defaults to 30 seconds.
2192
- * @returns {Promise<void>} A promise that resolves when the server node has stopped.
2193
- */
2194
1550
  async stopServerNode(matterServerNode, timeout = 30000) {
2195
1551
  if (!matterServerNode)
2196
1552
  return;
@@ -2203,12 +1559,6 @@ export class Matterbridge extends EventEmitter {
2203
1559
  this.log.error(`Failed to close ${matterServerNode.id} server node: ${error instanceof Error ? error.message : error}`);
2204
1560
  }
2205
1561
  }
2206
- /**
2207
- * Advertises the specified server node.
2208
- *
2209
- * @param {ServerNode} [matterServerNode] - The server node to advertise.
2210
- * @returns {Promise<{ qrPairingCode: string, manualPairingCode: string } | undefined>} A promise that resolves to the pairing codes if the server node is advertised, or undefined if not.
2211
- */
2212
1562
  async advertiseServerNode(matterServerNode) {
2213
1563
  if (matterServerNode) {
2214
1564
  await matterServerNode.env.get(DeviceCommissioner)?.allowBasicCommissioning();
@@ -2217,39 +1567,19 @@ export class Matterbridge extends EventEmitter {
2217
1567
  return { qrPairingCode, manualPairingCode };
2218
1568
  }
2219
1569
  }
2220
- /**
2221
- * Stop advertise the specified server node.
2222
- *
2223
- * @param {ServerNode} [matterServerNode] - The server node to advertise.
2224
- * @returns {Promise<void>} A promise that resolves when the server node has stopped advertising.
2225
- */
2226
1570
  async stopAdvertiseServerNode(matterServerNode) {
2227
1571
  if (matterServerNode && matterServerNode.lifecycle.isOnline) {
2228
1572
  await matterServerNode.env.get(DeviceCommissioner)?.endCommissioning();
2229
1573
  this.log.notice(`Stopped advertising for ${matterServerNode.id}`);
2230
1574
  }
2231
1575
  }
2232
- /**
2233
- * Creates an aggregator node with the specified storage context.
2234
- *
2235
- * @param {StorageContext} storageContext - The storage context for the aggregator node.
2236
- * @returns {Promise<Endpoint<AggregatorEndpoint>>} A promise that resolves to the created aggregator node.
2237
- */
2238
1576
  async createAggregatorNode(storageContext) {
2239
1577
  this.log.notice(`Creating ${await storageContext.get('storeId')} aggregator...`);
2240
1578
  const aggregatorNode = new Endpoint(AggregatorEndpoint, { id: `${await storageContext.get('storeId')}` });
2241
1579
  this.log.info(`Created ${await storageContext.get('storeId')} aggregator`);
2242
1580
  return aggregatorNode;
2243
1581
  }
2244
- /**
2245
- * Adds a MatterbridgeEndpoint to the specified plugin.
2246
- *
2247
- * @param {string} pluginName - The name of the plugin.
2248
- * @param {MatterbridgeEndpoint} device - The device to add as a bridged endpoint.
2249
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been added.
2250
- */
2251
1582
  async addBridgedEndpoint(pluginName, device) {
2252
- // Check if the plugin is registered
2253
1583
  const plugin = this.plugins.get(pluginName);
2254
1584
  if (!plugin) {
2255
1585
  this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
@@ -2269,7 +1599,6 @@ export class Matterbridge extends EventEmitter {
2269
1599
  }
2270
1600
  else if (this.bridgeMode === 'bridge') {
2271
1601
  if (device.mode === 'matter') {
2272
- // Register and add the device to the matterbridge server node
2273
1602
  this.log.debug(`Adding matter endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge server node...`);
2274
1603
  if (!this.serverNode) {
2275
1604
  this.log.error('Server node not found for Matterbridge');
@@ -2286,7 +1615,6 @@ export class Matterbridge extends EventEmitter {
2286
1615
  }
2287
1616
  }
2288
1617
  else {
2289
- // Register and add the device to the matterbridge aggregator node
2290
1618
  this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
2291
1619
  if (!this.aggregatorNode) {
2292
1620
  this.log.error('Aggregator node not found for Matterbridge');
@@ -2304,7 +1632,6 @@ export class Matterbridge extends EventEmitter {
2304
1632
  }
2305
1633
  }
2306
1634
  else if (this.bridgeMode === 'childbridge') {
2307
- // Register and add the device to the plugin server node
2308
1635
  if (plugin.type === 'AccessoryPlatform') {
2309
1636
  try {
2310
1637
  this.log.debug(`Creating endpoint ${dev}${device.deviceName}${db} for AccessoryPlatform plugin ${plg}${plugin.name}${db} server node`);
@@ -2328,12 +1655,10 @@ export class Matterbridge extends EventEmitter {
2328
1655
  return;
2329
1656
  }
2330
1657
  }
2331
- // Register and add the device to the plugin aggregator node
2332
1658
  if (plugin.type === 'DynamicPlatform') {
2333
1659
  try {
2334
1660
  this.log.debug(`Adding bridged endpoint ${dev}${device.deviceName}${db} for DynamicPlatform plugin ${plg}${plugin.name}${db} aggregator node`);
2335
1661
  await this.createDynamicPlugin(plugin);
2336
- // Fast plugins can add another device before the server node is ready, so we wait for the server node to be ready
2337
1662
  await waiter(`createDynamicPlugin(${plugin.name})`, () => plugin.serverNode?.hasParts === true);
2338
1663
  if (!plugin.aggregatorNode) {
2339
1664
  this.log.error(`Aggregator node not found for plugin ${plg}${plugin.name}${er}`);
@@ -2356,28 +1681,17 @@ export class Matterbridge extends EventEmitter {
2356
1681
  plugin.registeredDevices++;
2357
1682
  if (plugin.addedDevices !== undefined)
2358
1683
  plugin.addedDevices++;
2359
- // Add the device to the DeviceManager
2360
1684
  this.devices.set(device);
2361
- // Subscribe to the reachable$Changed event
2362
1685
  await this.subscribeAttributeChanged(plugin, device);
2363
1686
  this.log.info(`Added and registered bridged endpoint (${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) for plugin ${plg}${pluginName}${nf}`);
2364
1687
  }
2365
- /**
2366
- * Removes a MatterbridgeEndpoint from the specified plugin.
2367
- *
2368
- * @param {string} pluginName - The name of the plugin.
2369
- * @param {MatterbridgeEndpoint} device - The device to remove as a bridged endpoint.
2370
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been removed.
2371
- */
2372
1688
  async removeBridgedEndpoint(pluginName, device) {
2373
1689
  this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
2374
- // Check if the plugin is registered
2375
1690
  const plugin = this.plugins.get(pluginName);
2376
1691
  if (!plugin) {
2377
1692
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
2378
1693
  return;
2379
1694
  }
2380
- // Register and add the device to the matterbridge aggregator node
2381
1695
  if (this.bridgeMode === 'bridge') {
2382
1696
  if (!this.aggregatorNode) {
2383
1697
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator node not found`);
@@ -2392,7 +1706,6 @@ export class Matterbridge extends EventEmitter {
2392
1706
  }
2393
1707
  else if (this.bridgeMode === 'childbridge') {
2394
1708
  if (plugin.type === 'AccessoryPlatform') {
2395
- // Nothing to do here since the server node has no aggregator node but only the device itself
2396
1709
  }
2397
1710
  else if (plugin.type === 'DynamicPlatform') {
2398
1711
  if (!plugin.aggregatorNode) {
@@ -2407,21 +1720,8 @@ export class Matterbridge extends EventEmitter {
2407
1720
  if (plugin.addedDevices !== undefined)
2408
1721
  plugin.addedDevices--;
2409
1722
  }
2410
- // Remove the device from the DeviceManager
2411
1723
  this.devices.remove(device);
2412
1724
  }
2413
- /**
2414
- * Removes all bridged endpoints from the specified plugin.
2415
- *
2416
- * @param {string} pluginName - The name of the plugin.
2417
- * @param {number} [delay] - The delay in milliseconds between removing each bridged endpoint (default: 0).
2418
- * @returns {Promise<void>} A promise that resolves when all bridged endpoints have been removed.
2419
- *
2420
- * @remarks
2421
- * This method iterates through all devices in the DeviceManager and removes each bridged endpoint associated with the specified plugin.
2422
- * It also applies a delay between each removal if specified.
2423
- * The delay is useful to allow the controllers to receive a single subscription for each device removed.
2424
- */
2425
1725
  async removeAllBridgedEndpoints(pluginName, delay = 0) {
2426
1726
  this.log.debug(`Removing all bridged endpoints for plugin ${plg}${pluginName}${db}${delay > 0 ? ` with delay ${delay} ms` : ''}`);
2427
1727
  for (const device of this.devices.array().filter((device) => device.plugin === pluginName)) {
@@ -2432,15 +1732,6 @@ export class Matterbridge extends EventEmitter {
2432
1732
  if (delay > 0)
2433
1733
  await new Promise((resolve) => setTimeout(resolve, 2000));
2434
1734
  }
2435
- /**
2436
- * Subscribes to the attribute change event for the given device and plugin.
2437
- * Specifically, it listens for changes in the 'reachable' attribute of the
2438
- * BridgedDeviceBasicInformationServer cluster server of the bridged device or BasicInformationServer cluster server of server node.
2439
- *
2440
- * @param {RegisteredPlugin} plugin - The plugin associated with the device.
2441
- * @param {MatterbridgeEndpoint} device - The device to subscribe to attribute changes for.
2442
- * @returns {Promise<void>} A promise that resolves when the subscription is set up.
2443
- */
2444
1735
  async subscribeAttributeChanged(plugin, device) {
2445
1736
  this.log.info(`Subscribing attributes for endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) plugin ${plg}${plugin.name}${nf}`);
2446
1737
  if (this.bridgeMode === 'childbridge' && plugin.type === 'AccessoryPlatform' && plugin.serverNode) {
@@ -2456,12 +1747,6 @@ export class Matterbridge extends EventEmitter {
2456
1747
  });
2457
1748
  }
2458
1749
  }
2459
- /**
2460
- * Sanitizes the fabric information by converting bigint properties to strings because `res.json` doesn't support bigint.
2461
- *
2462
- * @param {ExposedFabricInformation[]} fabricInfo - The array of exposed fabric information objects.
2463
- * @returns {SanitizedExposedFabricInformation[]} An array of sanitized exposed fabric information objects.
2464
- */
2465
1750
  sanitizeFabricInformations(fabricInfo) {
2466
1751
  return fabricInfo.map((info) => {
2467
1752
  return {
@@ -2475,12 +1760,6 @@ export class Matterbridge extends EventEmitter {
2475
1760
  };
2476
1761
  });
2477
1762
  }
2478
- /**
2479
- * Sanitizes the session information by converting bigint properties to strings because `res.json` doesn't support bigint.
2480
- *
2481
- * @param {SessionsBehavior.Session[]} sessions - The array of session information objects.
2482
- * @returns {SanitizedSession[]} An array of sanitized session information objects.
2483
- */
2484
1763
  sanitizeSessionInformation(sessions) {
2485
1764
  return sessions
2486
1765
  .filter((session) => session.isPeerActive)
@@ -2507,21 +1786,7 @@ export class Matterbridge extends EventEmitter {
2507
1786
  };
2508
1787
  });
2509
1788
  }
2510
- /**
2511
- * Sets the reachability of the specified aggregator node bridged devices and trigger.
2512
- *
2513
- * @param {Endpoint<AggregatorEndpoint>} aggregatorNode - The aggregator node to set the reachability for.
2514
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2515
- */
2516
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2517
1789
  async setAggregatorReachability(aggregatorNode, reachable) {
2518
- /*
2519
- for (const child of aggregatorNode.parts) {
2520
- this.log.debug(`Setting reachability of ${(child as unknown as MatterbridgeEndpoint)?.deviceName} to ${reachable}`);
2521
- await child.setStateOf(BridgedDeviceBasicInformationServer, { reachable });
2522
- child.act((agent) => child.eventsOf(BridgedDeviceBasicInformationServer).reachableChanged.emit({ reachableNewValue: true }, agent.context));
2523
- }
2524
- */
2525
1790
  }
2526
1791
  getVendorIdName = (vendorId) => {
2527
1792
  if (!vendorId)
@@ -2561,11 +1826,10 @@ export class Matterbridge extends EventEmitter {
2561
1826
  case 0x1488:
2562
1827
  vendorName = '(ShortcutLabsFlic)';
2563
1828
  break;
2564
- case 65521: // 0xFFF1
1829
+ case 65521:
2565
1830
  vendorName = '(MatterTest)';
2566
1831
  break;
2567
1832
  }
2568
1833
  return vendorName;
2569
1834
  };
2570
1835
  }
2571
- //# sourceMappingURL=matterbridge.js.map