matterbridge 3.1.2 → 3.1.3-dev-20250712-616f7ed

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 (207) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/cli.js +2 -91
  3. package/dist/cliEmitter.js +0 -30
  4. package/dist/clusters/export.js +0 -2
  5. package/dist/defaultConfigSchema.js +0 -24
  6. package/dist/deviceManager.js +1 -94
  7. package/dist/devices/batteryStorage.js +1 -48
  8. package/dist/devices/evse.js +10 -74
  9. package/dist/devices/export.js +0 -2
  10. package/dist/devices/heatPump.js +2 -50
  11. package/dist/devices/laundryDryer.js +6 -83
  12. package/dist/devices/laundryWasher.js +7 -91
  13. package/dist/devices/roboticVacuumCleaner.js +6 -89
  14. package/dist/devices/solarPower.js +0 -38
  15. package/dist/devices/waterHeater.js +2 -82
  16. package/dist/frontend.js +16 -417
  17. package/dist/globalMatterbridge.js +0 -47
  18. package/dist/helpers.js +0 -53
  19. package/dist/index.js +1 -30
  20. package/dist/logger/export.js +0 -1
  21. package/dist/matter/behaviors.js +0 -2
  22. package/dist/matter/clusters.js +0 -2
  23. package/dist/matter/devices.js +0 -2
  24. package/dist/matter/endpoints.js +0 -2
  25. package/dist/matter/export.js +0 -3
  26. package/dist/matter/types.js +0 -3
  27. package/dist/matterbridge.js +54 -803
  28. package/dist/matterbridgeAccessoryPlatform.js +0 -36
  29. package/dist/matterbridgeBehaviors.js +1 -61
  30. package/dist/matterbridgeDeviceTypes.js +15 -579
  31. package/dist/matterbridgeDynamicPlatform.js +0 -36
  32. package/dist/matterbridgeEndpoint.js +51 -1053
  33. package/dist/matterbridgeEndpointHelpers.js +12 -322
  34. package/dist/matterbridgePlatform.js +0 -233
  35. package/dist/matterbridgeTypes.js +0 -25
  36. package/dist/pluginManager.js +3 -269
  37. package/dist/shelly.js +7 -168
  38. package/dist/storage/export.js +0 -1
  39. package/dist/update.js +0 -54
  40. package/dist/utils/colorUtils.js +2 -263
  41. package/dist/utils/commandLine.js +0 -54
  42. package/dist/utils/copyDirectory.js +1 -38
  43. package/dist/utils/createDirectory.js +0 -33
  44. package/dist/utils/createZip.js +2 -47
  45. package/dist/utils/deepCopy.js +0 -39
  46. package/dist/utils/deepEqual.js +1 -72
  47. package/dist/utils/export.js +0 -1
  48. package/dist/utils/hex.js +0 -58
  49. package/dist/utils/isvalid.js +0 -101
  50. package/dist/utils/network.js +5 -83
  51. package/dist/utils/spawn.js +0 -18
  52. package/dist/utils/wait.js +9 -62
  53. package/npm-shrinkwrap.json +5 -5
  54. package/package.json +1 -2
  55. package/dist/cli.d.ts +0 -26
  56. package/dist/cli.d.ts.map +0 -1
  57. package/dist/cli.js.map +0 -1
  58. package/dist/cliEmitter.d.ts +0 -34
  59. package/dist/cliEmitter.d.ts.map +0 -1
  60. package/dist/cliEmitter.js.map +0 -1
  61. package/dist/clusters/export.d.ts +0 -2
  62. package/dist/clusters/export.d.ts.map +0 -1
  63. package/dist/clusters/export.js.map +0 -1
  64. package/dist/defaultConfigSchema.d.ts +0 -28
  65. package/dist/defaultConfigSchema.d.ts.map +0 -1
  66. package/dist/defaultConfigSchema.js.map +0 -1
  67. package/dist/deviceManager.d.ts +0 -112
  68. package/dist/deviceManager.d.ts.map +0 -1
  69. package/dist/deviceManager.js.map +0 -1
  70. package/dist/devices/batteryStorage.d.ts +0 -48
  71. package/dist/devices/batteryStorage.d.ts.map +0 -1
  72. package/dist/devices/batteryStorage.js.map +0 -1
  73. package/dist/devices/evse.d.ts +0 -75
  74. package/dist/devices/evse.d.ts.map +0 -1
  75. package/dist/devices/evse.js.map +0 -1
  76. package/dist/devices/export.d.ts +0 -9
  77. package/dist/devices/export.d.ts.map +0 -1
  78. package/dist/devices/export.js.map +0 -1
  79. package/dist/devices/heatPump.d.ts +0 -47
  80. package/dist/devices/heatPump.d.ts.map +0 -1
  81. package/dist/devices/heatPump.js.map +0 -1
  82. package/dist/devices/laundryDryer.d.ts +0 -87
  83. package/dist/devices/laundryDryer.d.ts.map +0 -1
  84. package/dist/devices/laundryDryer.js.map +0 -1
  85. package/dist/devices/laundryWasher.d.ts +0 -242
  86. package/dist/devices/laundryWasher.d.ts.map +0 -1
  87. package/dist/devices/laundryWasher.js.map +0 -1
  88. package/dist/devices/roboticVacuumCleaner.d.ts +0 -110
  89. package/dist/devices/roboticVacuumCleaner.d.ts.map +0 -1
  90. package/dist/devices/roboticVacuumCleaner.js.map +0 -1
  91. package/dist/devices/solarPower.d.ts +0 -40
  92. package/dist/devices/solarPower.d.ts.map +0 -1
  93. package/dist/devices/solarPower.js.map +0 -1
  94. package/dist/devices/waterHeater.d.ts +0 -111
  95. package/dist/devices/waterHeater.d.ts.map +0 -1
  96. package/dist/devices/waterHeater.js.map +0 -1
  97. package/dist/frontend.d.ts +0 -303
  98. package/dist/frontend.d.ts.map +0 -1
  99. package/dist/frontend.js.map +0 -1
  100. package/dist/globalMatterbridge.d.ts +0 -59
  101. package/dist/globalMatterbridge.d.ts.map +0 -1
  102. package/dist/globalMatterbridge.js.map +0 -1
  103. package/dist/helpers.d.ts +0 -48
  104. package/dist/helpers.d.ts.map +0 -1
  105. package/dist/helpers.js.map +0 -1
  106. package/dist/index.d.ts +0 -33
  107. package/dist/index.d.ts.map +0 -1
  108. package/dist/index.js.map +0 -1
  109. package/dist/logger/export.d.ts +0 -2
  110. package/dist/logger/export.d.ts.map +0 -1
  111. package/dist/logger/export.js.map +0 -1
  112. package/dist/matter/behaviors.d.ts +0 -2
  113. package/dist/matter/behaviors.d.ts.map +0 -1
  114. package/dist/matter/behaviors.js.map +0 -1
  115. package/dist/matter/clusters.d.ts +0 -2
  116. package/dist/matter/clusters.d.ts.map +0 -1
  117. package/dist/matter/clusters.js.map +0 -1
  118. package/dist/matter/devices.d.ts +0 -2
  119. package/dist/matter/devices.d.ts.map +0 -1
  120. package/dist/matter/devices.js.map +0 -1
  121. package/dist/matter/endpoints.d.ts +0 -2
  122. package/dist/matter/endpoints.d.ts.map +0 -1
  123. package/dist/matter/endpoints.js.map +0 -1
  124. package/dist/matter/export.d.ts +0 -5
  125. package/dist/matter/export.d.ts.map +0 -1
  126. package/dist/matter/export.js.map +0 -1
  127. package/dist/matter/types.d.ts +0 -3
  128. package/dist/matter/types.d.ts.map +0 -1
  129. package/dist/matter/types.js.map +0 -1
  130. package/dist/matterbridge.d.ts +0 -450
  131. package/dist/matterbridge.d.ts.map +0 -1
  132. package/dist/matterbridge.js.map +0 -1
  133. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -42
  134. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  135. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  136. package/dist/matterbridgeBehaviors.d.ts +0 -1340
  137. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  138. package/dist/matterbridgeBehaviors.js.map +0 -1
  139. package/dist/matterbridgeDeviceTypes.d.ts +0 -709
  140. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  141. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  142. package/dist/matterbridgeDynamicPlatform.d.ts +0 -42
  143. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  144. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  145. package/dist/matterbridgeEndpoint.d.ts +0 -1196
  146. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  147. package/dist/matterbridgeEndpoint.js.map +0 -1
  148. package/dist/matterbridgeEndpointHelpers.d.ts +0 -3198
  149. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  150. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  151. package/dist/matterbridgePlatform.d.ts +0 -310
  152. package/dist/matterbridgePlatform.d.ts.map +0 -1
  153. package/dist/matterbridgePlatform.js.map +0 -1
  154. package/dist/matterbridgeTypes.d.ts +0 -192
  155. package/dist/matterbridgeTypes.d.ts.map +0 -1
  156. package/dist/matterbridgeTypes.js.map +0 -1
  157. package/dist/pluginManager.d.ts +0 -291
  158. package/dist/pluginManager.d.ts.map +0 -1
  159. package/dist/pluginManager.js.map +0 -1
  160. package/dist/shelly.d.ts +0 -174
  161. package/dist/shelly.d.ts.map +0 -1
  162. package/dist/shelly.js.map +0 -1
  163. package/dist/storage/export.d.ts +0 -2
  164. package/dist/storage/export.d.ts.map +0 -1
  165. package/dist/storage/export.js.map +0 -1
  166. package/dist/update.d.ts +0 -59
  167. package/dist/update.d.ts.map +0 -1
  168. package/dist/update.js.map +0 -1
  169. package/dist/utils/colorUtils.d.ts +0 -117
  170. package/dist/utils/colorUtils.d.ts.map +0 -1
  171. package/dist/utils/colorUtils.js.map +0 -1
  172. package/dist/utils/commandLine.d.ts +0 -59
  173. package/dist/utils/commandLine.d.ts.map +0 -1
  174. package/dist/utils/commandLine.js.map +0 -1
  175. package/dist/utils/copyDirectory.d.ts +0 -33
  176. package/dist/utils/copyDirectory.d.ts.map +0 -1
  177. package/dist/utils/copyDirectory.js.map +0 -1
  178. package/dist/utils/createDirectory.d.ts +0 -34
  179. package/dist/utils/createDirectory.d.ts.map +0 -1
  180. package/dist/utils/createDirectory.js.map +0 -1
  181. package/dist/utils/createZip.d.ts +0 -39
  182. package/dist/utils/createZip.d.ts.map +0 -1
  183. package/dist/utils/createZip.js.map +0 -1
  184. package/dist/utils/deepCopy.d.ts +0 -32
  185. package/dist/utils/deepCopy.d.ts.map +0 -1
  186. package/dist/utils/deepCopy.js.map +0 -1
  187. package/dist/utils/deepEqual.d.ts +0 -54
  188. package/dist/utils/deepEqual.d.ts.map +0 -1
  189. package/dist/utils/deepEqual.js.map +0 -1
  190. package/dist/utils/export.d.ts +0 -12
  191. package/dist/utils/export.d.ts.map +0 -1
  192. package/dist/utils/export.js.map +0 -1
  193. package/dist/utils/hex.d.ts +0 -49
  194. package/dist/utils/hex.d.ts.map +0 -1
  195. package/dist/utils/hex.js.map +0 -1
  196. package/dist/utils/isvalid.d.ts +0 -103
  197. package/dist/utils/isvalid.d.ts.map +0 -1
  198. package/dist/utils/isvalid.js.map +0 -1
  199. package/dist/utils/network.d.ts +0 -76
  200. package/dist/utils/network.d.ts.map +0 -1
  201. package/dist/utils/network.js.map +0 -1
  202. package/dist/utils/spawn.d.ts +0 -11
  203. package/dist/utils/spawn.d.ts.map +0 -1
  204. package/dist/utils/spawn.js.map +0 -1
  205. package/dist/utils/wait.d.ts +0 -56
  206. package/dist/utils/wait.d.ts.map +0 -1
  207. package/dist/utils/wait.js.map +0 -1
@@ -1,43 +1,15 @@
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 } 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
13
  import { getParameter, getIntParameter, hasParameter, copyDirectory, withTimeout, waiter, isValidString, parseVersionString, isValidNumber, createDirectory } from './utils/export.js';
42
14
  import { dev, plg, typ } from './matterbridgeTypes.js';
43
15
  import { PluginManager } from './pluginManager.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: '',
@@ -96,7 +65,7 @@ export class Matterbridge extends EventEmitter {
96
65
  shellySysUpdate: false,
97
66
  shellyMainUpdate: false,
98
67
  profile: getParameter('profile'),
99
- loggerLevel: "info" /* LogLevel.INFO */,
68
+ loggerLevel: "info",
100
69
  fileLogger: false,
101
70
  matterLoggerLevel: MatterLogLevel.INFO,
102
71
  matterFileLogger: false,
@@ -129,18 +98,15 @@ export class Matterbridge extends EventEmitter {
129
98
  shutdown = false;
130
99
  edge = true;
131
100
  failCountLimit = hasParameter('shelly') ? 600 : 120;
132
- // Matterbridge log files
133
- log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
101
+ log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
134
102
  matterbridgeLoggerFile = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
135
103
  matterLoggerFile = 'matter' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
136
104
  plugins;
137
105
  devices;
138
106
  frontend = new Frontend(this);
139
- // Matterbridge storage
140
107
  nodeStorageName = 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
141
108
  nodeStorage;
142
109
  nodeContext;
143
- // Cleanup
144
110
  hasCleanupStarted = false;
145
111
  initialized = false;
146
112
  execRunningCount = 0;
@@ -154,23 +120,19 @@ export class Matterbridge extends EventEmitter {
154
120
  sigtermHandler;
155
121
  exceptionHandler;
156
122
  rejectionHandler;
157
- // Matter environment
158
123
  environment = Environment.default;
159
- // Matter storage
160
124
  matterStorageName = 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
161
125
  matterStorageService;
162
126
  matterStorageManager;
163
127
  matterbridgeContext;
164
128
  controllerContext;
165
- // Matter parameters
166
- mdnsInterface; // matter server node mdnsInterface: e.g. 'eth0' or 'wlan0' or 'WiFi'
167
- ipv4address; // matter server node listeningAddressIpv4
168
- ipv6address; // matter server node listeningAddressIpv6
169
- port; // first server node port
170
- passcode; // first server node passcode
171
- discriminator; // first server node discriminator
172
- certification; // device certification
173
- // Matter nodes
129
+ mdnsInterface;
130
+ ipv4address;
131
+ ipv6address;
132
+ port;
133
+ passcode;
134
+ discriminator;
135
+ certification;
174
136
  serverNode;
175
137
  aggregatorNode;
176
138
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
@@ -178,31 +140,15 @@ export class Matterbridge extends EventEmitter {
178
140
  aggregatorProductId = getIntParameter('productId') ?? 0x8000;
179
141
  aggregatorProductName = getParameter('productName') ?? 'Matterbridge aggregator';
180
142
  static instance;
181
- // We load asyncronously so is private
182
143
  constructor() {
183
144
  super();
184
145
  }
185
- /**
186
- * Retrieves the list of Matterbridge devices.
187
- *
188
- * @returns {MatterbridgeEndpoint[]} An array of MatterbridgeDevice objects.
189
- */
190
146
  getDevices() {
191
147
  return this.devices.array();
192
148
  }
193
- /**
194
- * Retrieves the list of registered plugins.
195
- *
196
- * @returns {RegisteredPlugin[]} An array of RegisteredPlugin objects.
197
- */
198
149
  getPlugins() {
199
150
  return this.plugins.array();
200
151
  }
201
- /**
202
- * Set the logger logLevel for the Matterbridge classes and call onChangeLoggerLevel() for each plugin.
203
- *
204
- * @param {LogLevel} logLevel The logger logLevel to set.
205
- */
206
152
  async setLogLevel(logLevel) {
207
153
  if (this.log)
208
154
  this.log.logLevel = logLevel;
@@ -216,31 +162,19 @@ export class Matterbridge extends EventEmitter {
216
162
  for (const plugin of this.plugins) {
217
163
  if (!plugin.platform || !plugin.platform.log || !plugin.platform.config)
218
164
  continue;
219
- plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel;
220
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel);
221
- }
222
- // Set the global logger callback for the WebSocketServer to the common minimum logLevel
223
- let callbackLogLevel = "notice" /* LogLevel.NOTICE */;
224
- if (this.matterbridgeInformation.loggerLevel === "info" /* LogLevel.INFO */ || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.INFO)
225
- callbackLogLevel = "info" /* LogLevel.INFO */;
226
- if (this.matterbridgeInformation.loggerLevel === "debug" /* LogLevel.DEBUG */ || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.DEBUG)
227
- callbackLogLevel = "debug" /* LogLevel.DEBUG */;
165
+ plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" : this.log.logLevel;
166
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" : this.log.logLevel);
167
+ }
168
+ let callbackLogLevel = "notice";
169
+ if (this.matterbridgeInformation.loggerLevel === "info" || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.INFO)
170
+ callbackLogLevel = "info";
171
+ if (this.matterbridgeInformation.loggerLevel === "debug" || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.DEBUG)
172
+ callbackLogLevel = "debug";
228
173
  AnsiLogger.setGlobalCallback(this.frontend.wssSendMessage.bind(this.frontend), callbackLogLevel);
229
174
  this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
230
175
  }
231
- //* ************************************************************************************************************************************ */
232
- // loadInstance() and cleanup() methods */
233
- //* ************************************************************************************************************************************ */
234
- /**
235
- * Loads an instance of the Matterbridge class.
236
- * If an instance already exists, return that instance.
237
- *
238
- * @param {boolean} initialize - Whether to initialize the Matterbridge instance after loading. Defaults to false.
239
- * @returns {Matterbridge} A promise that resolves to the Matterbridge instance.
240
- */
241
176
  static async loadInstance(initialize = false) {
242
177
  if (!Matterbridge.instance) {
243
- // eslint-disable-next-line no-console
244
178
  if (hasParameter('debug'))
245
179
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
246
180
  Matterbridge.instance = new Matterbridge();
@@ -249,17 +183,8 @@ export class Matterbridge extends EventEmitter {
249
183
  }
250
184
  return Matterbridge.instance;
251
185
  }
252
- /**
253
- * Call cleanup() and dispose MdnsService.
254
- *
255
- * @param {number} [timeout] - The timeout duration to wait for the cleanup to complete in milliseconds. Default is 1000.
256
- * @param {number} [pause] - The pause duration after the cleanup in milliseconds. Default is 250.
257
- *
258
- * @deprecated This method is deprecated and is ONLY used for jest tests.
259
- */
260
186
  async destroyInstance(timeout = 1000, pause = 250) {
261
187
  this.log.info(`Destroy instance...`);
262
- // Save server nodes to close
263
188
  const servers = [];
264
189
  if (this.bridgeMode === 'bridge') {
265
190
  if (this.serverNode)
@@ -277,109 +202,76 @@ export class Matterbridge extends EventEmitter {
277
202
  servers.push(device.serverNode);
278
203
  }
279
204
  }
280
- // Let any already‐queued microtasks run first
281
205
  await Promise.resolve();
282
- // Wait for the cleanup to finish
283
206
  await new Promise((resolve) => {
284
207
  setTimeout(resolve, pause);
285
208
  });
286
- // Cleanup
287
209
  await this.cleanup('destroying instance...', false, timeout);
288
- // Close servers mdns service
289
210
  this.log.info(`Dispose ${servers.length} MdnsService...`);
290
211
  for (const server of servers) {
291
212
  await server.env.get(MdnsService)[Symbol.asyncDispose]();
292
213
  this.log.info(`Closed ${server.id} MdnsService`);
293
214
  }
294
- // Let any already‐queued microtasks run first
295
215
  await Promise.resolve();
296
- // Wait for the cleanup to finish
297
216
  await new Promise((resolve) => {
298
217
  setTimeout(resolve, pause);
299
218
  });
300
219
  }
301
- /**
302
- * Initializes the Matterbridge application.
303
- *
304
- * @remarks
305
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
306
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
307
- * node version, registers signal handlers, initializes storage, and parses the command line.
308
- *
309
- * @returns {Promise<void>} A Promise that resolves when the initialization is complete.
310
- */
311
220
  async initialize() {
312
- // Emit the initialize_started event
313
221
  this.emit('initialize_started');
314
- // Set the restart mode
315
222
  if (hasParameter('service'))
316
223
  this.restartMode = 'service';
317
224
  if (hasParameter('docker'))
318
225
  this.restartMode = 'docker';
319
- // Set the matterbridge home directory
320
226
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
321
227
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
322
228
  await createDirectory(this.homeDirectory, 'Matterbridge Home Directory', this.log);
323
- // Set the matterbridge directory
324
229
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
325
230
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
326
231
  await createDirectory(this.matterbridgeDirectory, 'Matterbridge Directory', this.log);
327
232
  await createDirectory(path.join(this.matterbridgeDirectory, 'certs'), 'Matterbridge Frontend Certificate Directory', this.log);
328
233
  await createDirectory(path.join(this.matterbridgeDirectory, 'uploads'), 'Matterbridge Frontend Uploads Directory', this.log);
329
- // Set the matterbridge plugin directory
330
234
  this.matterbridgePluginDirectory = path.join(this.homeDirectory, 'Matterbridge');
331
235
  this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
332
236
  await createDirectory(this.matterbridgePluginDirectory, 'Matterbridge Plugin Directory', this.log);
333
- // Set the matterbridge cert directory
334
237
  this.matterbridgeCertDirectory = path.join(this.homeDirectory, '.mattercert');
335
238
  this.matterbridgeInformation.matterbridgeCertDirectory = this.matterbridgeCertDirectory;
336
239
  await createDirectory(this.matterbridgeCertDirectory, 'Matterbridge Matter Certificate Directory', this.log);
337
- // Set the matterbridge root directory
338
240
  const { fileURLToPath } = await import('node:url');
339
241
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
340
242
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
341
243
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
342
- // Setup the matter environment
343
244
  this.environment.vars.set('log.level', MatterLogLevel.INFO);
344
245
  this.environment.vars.set('log.format', MatterLogFormat.ANSI);
345
246
  this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, this.matterStorageName));
346
247
  this.environment.vars.set('runtime.signals', false);
347
248
  this.environment.vars.set('runtime.exitcode', false);
348
- // Register process handlers
349
249
  this.registerProcessHandlers();
350
- // Initialize nodeStorage and nodeContext
351
250
  try {
352
251
  this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
353
252
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
354
253
  this.log.debug('Creating node storage context for matterbridge');
355
254
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
356
- // TODO: Remove this code when node-persist-manager is updated
357
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
358
255
  const keys = (await this.nodeStorage?.storage.keys());
359
256
  for (const key of keys) {
360
257
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
361
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
362
258
  await this.nodeStorage?.storage.get(key);
363
259
  }
364
260
  const storages = await this.nodeStorage.getStorageNames();
365
261
  for (const storage of storages) {
366
262
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
367
263
  const nodeContext = await this.nodeStorage?.createStorage(storage);
368
- // TODO: Remove this code when node-persist-manager is updated
369
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
370
264
  const keys = (await nodeContext?.storage.keys());
371
265
  keys.forEach(async (key) => {
372
266
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
373
267
  await nodeContext?.get(key);
374
268
  });
375
269
  }
376
- // Creating a backup of the node storage since it is not corrupted
377
270
  this.log.debug('Creating node storage backup...');
378
271
  await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
379
272
  this.log.debug('Created node storage backup');
380
273
  }
381
274
  catch (error) {
382
- // Restoring the backup of the node storage since it is corrupted
383
275
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
384
276
  if (hasParameter('norestore')) {
385
277
  this.log.fatal(`The matterbridge storage is corrupted. Found -norestore parameter: exiting...`);
@@ -393,20 +285,14 @@ export class Matterbridge extends EventEmitter {
393
285
  if (!this.nodeStorage || !this.nodeContext) {
394
286
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
395
287
  }
396
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
397
288
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
398
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
399
289
  this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode')) ?? PaseClient.generateRandomPasscode(this.environment.get(Crypto));
400
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
401
290
  this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator')) ?? PaseClient.generateRandomDiscriminator(this.environment.get(Crypto));
402
- // Certificate management
403
291
  const pairingFilePath = path.join(this.matterbridgeCertDirectory, 'pairing.json');
404
292
  try {
405
- // eslint-disable-next-line n/no-unsupported-features/node-builtins
406
293
  await fs.access(pairingFilePath, fs.constants.R_OK);
407
294
  const pairingFileContent = await fs.readFile(pairingFilePath, 'utf8');
408
295
  const pairingFileJson = JSON.parse(pairingFileContent);
409
- // Set the vendorId, vendorName, productId and productName if they are present in the pairing file
410
296
  if (isValidNumber(pairingFileJson.vendorId))
411
297
  this.aggregatorVendorId = VendorId(pairingFileJson.vendorId);
412
298
  if (isValidString(pairingFileJson.vendorName, 3))
@@ -415,73 +301,50 @@ export class Matterbridge extends EventEmitter {
415
301
  this.aggregatorProductId = pairingFileJson.productId;
416
302
  if (isValidString(pairingFileJson.productName, 3))
417
303
  this.aggregatorProductName = pairingFileJson.productName;
418
- // Override the passcode and discriminator if they are present in the pairing file
419
304
  if (isValidNumber(pairingFileJson.passcode) && isValidNumber(pairingFileJson.discriminator)) {
420
305
  this.passcode = pairingFileJson.passcode;
421
306
  this.discriminator = pairingFileJson.discriminator;
422
307
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using passcode ${CYAN}${this.passcode}${nf} and discriminator ${CYAN}${this.discriminator}${nf} from pairing file.`);
423
308
  }
424
- // Set the certification if it is present in the pairing file
425
- /*
426
- if (pairingFileJson.privateKey && pairingFileJson.certificate && pairingFileJson.intermediateCertificate && pairingFileJson.declaration) {
427
- const hexStringToUint8Array = (hexString: string) => {
428
- const matches = hexString.match(/.{1,2}/g);
429
- return matches ? new Uint8Array(matches.map((byte) => parseInt(byte, 16))) : new Uint8Array();
430
- };
431
- // const hexString = Buffer.from('Test string', 'utf-8').toString('hex');
432
- // console.log(hexString, Buffer.from(hexStringToUint8Array(hexString)).toString('utf-8'));
433
-
434
- this.certification = {
435
- privateKey: hexStringToUint8Array(pairingFileJson.privateKey),
436
- certificate: hexStringToUint8Array(pairingFileJson.certificate),
437
- intermediateCertificate: hexStringToUint8Array(pairingFileJson.intermediateCertificate),
438
- declaration: hexStringToUint8Array(pairingFileJson.declaration),
439
- };
440
- this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using privateKey, certificate, intermediateCertificate and declaration from pairing file.`);
441
- }
442
- */
443
309
  }
444
310
  catch (error) {
445
311
  this.log.debug(`Pairing file ${CYAN}${pairingFilePath}${db} not found: ${error instanceof Error ? error.message : error}`);
446
312
  }
447
- // Store the passcode, discriminator and port in the node context
448
313
  await this.nodeContext.set('matterport', this.port);
449
314
  await this.nodeContext.set('matterpasscode', this.passcode);
450
315
  await this.nodeContext.set('matterdiscriminator', this.discriminator);
451
316
  this.log.debug(`Initializing server node for Matterbridge on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
452
- // Set matterbridge logger level (context: matterbridgeLogLevel)
453
317
  if (hasParameter('logger')) {
454
318
  const level = getParameter('logger');
455
319
  if (level === 'debug') {
456
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
320
+ this.log.logLevel = "debug";
457
321
  }
458
322
  else if (level === 'info') {
459
- this.log.logLevel = "info" /* LogLevel.INFO */;
323
+ this.log.logLevel = "info";
460
324
  }
461
325
  else if (level === 'notice') {
462
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
326
+ this.log.logLevel = "notice";
463
327
  }
464
328
  else if (level === 'warn') {
465
- this.log.logLevel = "warn" /* LogLevel.WARN */;
329
+ this.log.logLevel = "warn";
466
330
  }
467
331
  else if (level === 'error') {
468
- this.log.logLevel = "error" /* LogLevel.ERROR */;
332
+ this.log.logLevel = "error";
469
333
  }
470
334
  else if (level === 'fatal') {
471
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
335
+ this.log.logLevel = "fatal";
472
336
  }
473
337
  else {
474
338
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
475
- this.log.logLevel = "info" /* LogLevel.INFO */;
339
+ this.log.logLevel = "info";
476
340
  }
477
341
  }
478
342
  else {
479
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.matterbridgeInformation.shellyBoard ? "notice" /* LogLevel.NOTICE */ : "info" /* LogLevel.INFO */);
343
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.matterbridgeInformation.shellyBoard ? "notice" : "info");
480
344
  }
481
345
  this.frontend.logLevel = this.log.logLevel;
482
346
  MatterbridgeEndpoint.logLevel = this.log.logLevel;
483
347
  this.matterbridgeInformation.loggerLevel = this.log.logLevel;
484
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
485
348
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
486
349
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbridgeLoggerFile), this.log.logLevel, true);
487
350
  this.matterbridgeInformation.fileLogger = true;
@@ -490,7 +353,6 @@ export class Matterbridge extends EventEmitter {
490
353
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
491
354
  if (this.profile !== undefined)
492
355
  this.log.debug(`Matterbridge profile: ${this.profile}.`);
493
- // Set matter.js logger level, format and logger (context: matterLogLevel)
494
356
  if (hasParameter('matterlogger')) {
495
357
  const level = getParameter('matterlogger');
496
358
  if (level === 'debug') {
@@ -521,9 +383,7 @@ export class Matterbridge extends EventEmitter {
521
383
  }
522
384
  Logger.format = MatterLogFormat.ANSI;
523
385
  Logger.setLogger('default', this.createMatterLogger());
524
- // Logger.destinations.default.write = this.createMatterLogger();
525
386
  this.matterbridgeInformation.matterLoggerLevel = Logger.level;
526
- // Create the file logger for matter.js (context: matterFileLog)
527
387
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
528
388
  this.matterbridgeInformation.matterFileLogger = true;
529
389
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
@@ -532,9 +392,7 @@ export class Matterbridge extends EventEmitter {
532
392
  });
533
393
  }
534
394
  this.log.debug(`Matter logLevel: ${Logger.level} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
535
- // Log network interfaces
536
395
  const networkInterfaces = os.networkInterfaces();
537
- // console.log(`Network interfaces:`, networkInterfaces);
538
396
  const availableAddresses = Object.entries(networkInterfaces);
539
397
  const availableInterfaces = Object.keys(networkInterfaces);
540
398
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -545,7 +403,6 @@ export class Matterbridge extends EventEmitter {
545
403
  });
546
404
  }
547
405
  }
548
- // Set the interface to use for matter server node mdnsInterface
549
406
  if (hasParameter('mdnsinterface')) {
550
407
  this.mdnsInterface = getParameter('mdnsinterface');
551
408
  }
@@ -554,7 +411,6 @@ export class Matterbridge extends EventEmitter {
554
411
  if (this.mdnsInterface === '')
555
412
  this.mdnsInterface = undefined;
556
413
  }
557
- // Validate mdnsInterface
558
414
  if (this.mdnsInterface) {
559
415
  if (!availableInterfaces.includes(this.mdnsInterface)) {
560
416
  this.log.error(`Invalid mdnsinterface: ${this.mdnsInterface}. Available interfaces are: ${availableInterfaces.join(', ')}. Using all available interfaces.`);
@@ -567,7 +423,6 @@ export class Matterbridge extends EventEmitter {
567
423
  }
568
424
  if (this.mdnsInterface)
569
425
  this.environment.vars.set('mdns.networkInterface', this.mdnsInterface);
570
- // Set the listeningAddressIpv4 for the matter commissioning server
571
426
  if (hasParameter('ipv4address')) {
572
427
  this.ipv4address = getParameter('ipv4address');
573
428
  }
@@ -576,7 +431,6 @@ export class Matterbridge extends EventEmitter {
576
431
  if (this.ipv4address === '')
577
432
  this.ipv4address = undefined;
578
433
  }
579
- // Validate ipv4address
580
434
  if (this.ipv4address) {
581
435
  let isValid = false;
582
436
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -592,7 +446,6 @@ export class Matterbridge extends EventEmitter {
592
446
  await this.nodeContext.remove('matteripv4address');
593
447
  }
594
448
  }
595
- // Set the listeningAddressIpv6 for the matter commissioning server
596
449
  if (hasParameter('ipv6address')) {
597
450
  this.ipv6address = getParameter('ipv6address');
598
451
  }
@@ -601,7 +454,6 @@ export class Matterbridge extends EventEmitter {
601
454
  if (this.ipv6address === '')
602
455
  this.ipv6address = undefined;
603
456
  }
604
- // Validate ipv6address
605
457
  if (this.ipv6address) {
606
458
  let isValid = false;
607
459
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -610,7 +462,6 @@ export class Matterbridge extends EventEmitter {
610
462
  isValid = true;
611
463
  break;
612
464
  }
613
- /* istanbul ignore next */
614
465
  if (ifaces && ifaces.find((iface) => iface.scopeid && iface.scopeid > 0 && iface.address + '%' + (process.platform === 'win32' ? iface.scopeid : ifaceName) === this.ipv6address)) {
615
466
  this.log.info(`Using ipv6address ${CYAN}${this.ipv6address}${nf} on interface ${CYAN}${ifaceName}${nf} for the Matter server node.`);
616
467
  isValid = true;
@@ -623,7 +474,6 @@ export class Matterbridge extends EventEmitter {
623
474
  await this.nodeContext.remove('matteripv6address');
624
475
  }
625
476
  }
626
- // Initialize the virtual mode
627
477
  if (hasParameter('novirtual')) {
628
478
  this.matterbridgeInformation.virtualMode = 'disabled';
629
479
  await this.nodeContext.set('virtualmode', 'disabled');
@@ -632,19 +482,14 @@ export class Matterbridge extends EventEmitter {
632
482
  this.matterbridgeInformation.virtualMode = (await this.nodeContext.get('virtualmode', 'outlet'));
633
483
  }
634
484
  this.log.debug(`Virtual mode ${this.matterbridgeInformation.virtualMode}.`);
635
- // Initialize PluginManager
636
485
  this.plugins = new PluginManager(this);
637
486
  await this.plugins.loadFromStorage();
638
487
  this.plugins.logLevel = this.log.logLevel;
639
- // Initialize DeviceManager
640
488
  this.devices = new DeviceManager(this);
641
489
  this.devices.logLevel = this.log.logLevel;
642
- // Get the plugins from node storage and create the plugins node storage contexts
643
490
  for (const plugin of this.plugins) {
644
491
  const packageJson = await this.plugins.parse(plugin);
645
492
  if (packageJson === null && !hasParameter('add') && !hasParameter('remove') && !hasParameter('enable') && !hasParameter('disable') && !hasParameter('reset') && !hasParameter('factoryreset')) {
646
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
647
- // We don't do this when the add and other parameters are set because we shut down the process after adding the plugin
648
493
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
649
494
  try {
650
495
  const { spawnCommand } = await import('./utils/spawn.js');
@@ -667,7 +512,6 @@ export class Matterbridge extends EventEmitter {
667
512
  await plugin.nodeContext.set('description', plugin.description);
668
513
  await plugin.nodeContext.set('author', plugin.author);
669
514
  }
670
- // Log system info and create .matterbridge directory
671
515
  await this.logNodeAndSystemInfo();
672
516
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
673
517
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -675,7 +519,6 @@ export class Matterbridge extends EventEmitter {
675
519
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
676
520
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
677
521
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
678
- // Check node version and throw error
679
522
  const minNodeVersion = 18;
680
523
  const nodeVersion = process.versions.node;
681
524
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -683,18 +526,10 @@ export class Matterbridge extends EventEmitter {
683
526
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
684
527
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
685
528
  }
686
- // Parse command line
687
529
  await this.parseCommandLine();
688
- // Emit the initialize_completed event
689
530
  this.emit('initialize_completed');
690
531
  this.initialized = true;
691
532
  }
692
- /**
693
- * Parses the command line arguments and performs the corresponding actions.
694
- *
695
- * @private
696
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
697
- */
698
533
  async parseCommandLine() {
699
534
  if (hasParameter('help')) {
700
535
  this.log.info(`\nUsage: matterbridge [options]\n
@@ -755,19 +590,6 @@ export class Matterbridge extends EventEmitter {
755
590
  }
756
591
  index++;
757
592
  }
758
- /*
759
- const serializedRegisteredDevices = await this.nodeContext?.get<SerializedMatterbridgeEndpoint[]>('devices', []);
760
- this.log.info(`│ Registered devices (${serializedRegisteredDevices?.length})`);
761
- serializedRegisteredDevices?.forEach((device, index) => {
762
- if (index !== serializedRegisteredDevices.length - 1) {
763
- this.log.info(`├─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
764
- this.log.info(`│ └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
765
- } else {
766
- this.log.info(`└─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
767
- this.log.info(` └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
768
- }
769
- });
770
- */
771
593
  this.shutdown = true;
772
594
  return;
773
595
  }
@@ -818,7 +640,6 @@ export class Matterbridge extends EventEmitter {
818
640
  this.shutdown = true;
819
641
  return;
820
642
  }
821
- // Start the matter storage and create the matterbridge context
822
643
  try {
823
644
  await this.startMatterStorage();
824
645
  }
@@ -826,21 +647,18 @@ export class Matterbridge extends EventEmitter {
826
647
  this.log.fatal(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
827
648
  throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
828
649
  }
829
- // Clear the matterbridge context if the reset parameter is set
830
650
  if (hasParameter('reset') && getParameter('reset') === undefined) {
831
651
  this.initialized = true;
832
652
  await this.shutdownProcessAndReset();
833
653
  this.shutdown = true;
834
654
  return;
835
655
  }
836
- // Clear matterbridge plugin context if the reset parameter is set
837
656
  if (hasParameter('reset') && getParameter('reset') !== undefined) {
838
657
  this.log.debug(`Reset plugin ${getParameter('reset')}`);
839
658
  const plugin = this.plugins.get(getParameter('reset'));
840
659
  if (plugin) {
841
660
  const matterStorageManager = await this.matterStorageService?.open(plugin.name);
842
661
  if (!matterStorageManager) {
843
- /* istanbul ignore next */
844
662
  this.log.error(`Plugin ${plg}${plugin.name}${er} storageManager not found`);
845
663
  }
846
664
  else {
@@ -859,39 +677,32 @@ export class Matterbridge extends EventEmitter {
859
677
  this.shutdown = true;
860
678
  return;
861
679
  }
862
- // Initialize frontend
863
680
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
864
681
  await this.frontend.start(getIntParameter('frontend'));
865
- // Check in 30 seconds the latest and dev versions of matterbridge and the plugins
866
682
  clearTimeout(this.checkUpdateTimeout);
867
683
  this.checkUpdateTimeout = setTimeout(async () => {
868
684
  const { checkUpdates } = await import('./update.js');
869
685
  checkUpdates(this);
870
686
  }, 30 * 1000).unref();
871
- // Check each 12 hours the latest and dev versions of matterbridge and the plugins
872
687
  clearInterval(this.checkUpdateInterval);
873
688
  this.checkUpdateInterval = setInterval(async () => {
874
689
  const { checkUpdates } = await import('./update.js');
875
690
  checkUpdates(this);
876
691
  }, 12 * 60 * 60 * 1000).unref();
877
- // Start the matterbridge in mode test
878
692
  if (hasParameter('test')) {
879
693
  this.bridgeMode = 'bridge';
880
694
  MatterbridgeEndpoint.bridgeMode = 'bridge';
881
695
  return;
882
696
  }
883
- // Start the matterbridge in mode controller
884
697
  if (hasParameter('controller')) {
885
698
  this.bridgeMode = 'controller';
886
699
  await this.startController();
887
700
  return;
888
701
  }
889
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
890
702
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
891
703
  this.log.info('Setting default matterbridge start mode to bridge');
892
704
  await this.nodeContext?.set('bridgeMode', 'bridge');
893
705
  }
894
- // Start matterbridge in bridge mode
895
706
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
896
707
  this.bridgeMode = 'bridge';
897
708
  MatterbridgeEndpoint.bridgeMode = 'bridge';
@@ -899,7 +710,6 @@ export class Matterbridge extends EventEmitter {
899
710
  await this.startBridge();
900
711
  return;
901
712
  }
902
- // Start matterbridge in childbridge mode
903
713
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
904
714
  this.bridgeMode = 'childbridge';
905
715
  MatterbridgeEndpoint.bridgeMode = 'childbridge';
@@ -908,20 +718,10 @@ export class Matterbridge extends EventEmitter {
908
718
  return;
909
719
  }
910
720
  }
911
- /**
912
- * Asynchronously loads and starts the registered plugins.
913
- *
914
- * This method is responsible for initializing and starting all enabled plugins.
915
- * It ensures that each plugin is properly loaded and started before the bridge starts.
916
- *
917
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
918
- */
919
721
  async startPlugins() {
920
- // Check, load and start the plugins
921
722
  for (const plugin of this.plugins) {
922
723
  plugin.configJson = await this.plugins.loadConfig(plugin);
923
724
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
924
- // Check if the plugin is available
925
725
  if (!(await this.plugins.resolve(plugin.path))) {
926
726
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
927
727
  plugin.enabled = false;
@@ -941,14 +741,10 @@ export class Matterbridge extends EventEmitter {
941
741
  plugin.addedDevices = undefined;
942
742
  plugin.qrPairingCode = undefined;
943
743
  plugin.manualPairingCode = undefined;
944
- this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
744
+ this.plugins.load(plugin, true, 'Matterbridge is starting');
945
745
  }
946
746
  this.frontend.wssSendRefreshRequired('plugins');
947
747
  }
948
- /**
949
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
950
- * When either of these signals are received, the cleanup method is called with an appropriate message.
951
- */
952
748
  registerProcessHandlers() {
953
749
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
954
750
  process.removeAllListeners('uncaughtException');
@@ -975,9 +771,6 @@ export class Matterbridge extends EventEmitter {
975
771
  };
976
772
  process.on('SIGTERM', this.sigtermHandler);
977
773
  }
978
- /**
979
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
980
- */
981
774
  deregisterProcessHandlers() {
982
775
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
983
776
  if (this.exceptionHandler)
@@ -994,17 +787,12 @@ export class Matterbridge extends EventEmitter {
994
787
  process.off('SIGTERM', this.sigtermHandler);
995
788
  this.sigtermHandler = undefined;
996
789
  }
997
- /**
998
- * Logs the node and system information.
999
- */
1000
790
  async logNodeAndSystemInfo() {
1001
- // IP address information
1002
791
  const networkInterfaces = os.networkInterfaces();
1003
792
  this.systemInformation.interfaceName = '';
1004
793
  this.systemInformation.ipv4Address = '';
1005
794
  this.systemInformation.ipv6Address = '';
1006
795
  for (const [interfaceName, interfaceDetails] of Object.entries(networkInterfaces)) {
1007
- // this.log.debug(`Checking interface: '${interfaceName}' for '${this.mdnsInterface}'`);
1008
796
  if (this.mdnsInterface && interfaceName !== this.mdnsInterface)
1009
797
  continue;
1010
798
  if (!interfaceDetails) {
@@ -1030,22 +818,19 @@ export class Matterbridge extends EventEmitter {
1030
818
  break;
1031
819
  }
1032
820
  }
1033
- // Node information
1034
821
  this.systemInformation.nodeVersion = process.versions.node;
1035
822
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
1036
823
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
1037
824
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
1038
- // Host system information
1039
825
  this.systemInformation.hostname = os.hostname();
1040
826
  this.systemInformation.user = os.userInfo().username;
1041
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
1042
- this.systemInformation.osRelease = os.release(); // Kernel version
1043
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
1044
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
1045
- this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
1046
- this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
1047
- this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours'; // Convert to hours
1048
- // Log the system information
827
+ this.systemInformation.osType = os.type();
828
+ this.systemInformation.osRelease = os.release();
829
+ this.systemInformation.osPlatform = os.platform();
830
+ this.systemInformation.osArch = os.arch();
831
+ this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
832
+ this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
833
+ this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours';
1049
834
  this.log.debug('Host System Information:');
1050
835
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
1051
836
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -1061,17 +846,14 @@ export class Matterbridge extends EventEmitter {
1061
846
  this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
1062
847
  this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
1063
848
  this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
1064
- // Log directories
1065
849
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
1066
850
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
1067
851
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
1068
852
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
1069
853
  this.log.debug(`Matterbridge Matter Certificate Directory: ${this.matterbridgeCertDirectory}`);
1070
- // Global node_modules directory
1071
854
  if (this.nodeContext)
1072
855
  this.globalModulesDirectory = this.matterbridgeInformation.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
1073
856
  if (this.globalModulesDirectory === '') {
1074
- // First run of Matterbridge so the node storage is empty
1075
857
  try {
1076
858
  const { getGlobalNodeModules } = await import('./utils/network.js');
1077
859
  this.execRunningCount++;
@@ -1086,81 +868,50 @@ export class Matterbridge extends EventEmitter {
1086
868
  }
1087
869
  else
1088
870
  this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
1089
- /* removed cause is too expensive for the shelly board and not really needed. Why should the globalModulesDirectory change?
1090
- else {
1091
- this.getGlobalNodeModules()
1092
- .then(async (globalModulesDirectory) => {
1093
- this.globalModulesDirectory = globalModulesDirectory;
1094
- this.matterbridgeInformation.globalModulesDirectory = this.globalModulesDirectory;
1095
- this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
1096
- await this.nodeContext?.set<string>('globalModulesDirectory', this.globalModulesDirectory);
1097
- })
1098
- .catch((error) => {
1099
- this.log.error(`Error getting global node_modules directory: ${error}`);
1100
- });
1101
- }*/
1102
- // Matterbridge version
1103
871
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
1104
872
  this.matterbridgeVersion = this.matterbridgeLatestVersion = this.matterbridgeDevVersion = packageJson.version;
1105
873
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeInformation.matterbridgeLatestVersion = this.matterbridgeInformation.matterbridgeDevVersion = packageJson.version;
1106
874
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
1107
- // Matterbridge latest version (will be set in the checkUpdate function)
1108
875
  if (this.nodeContext)
1109
876
  this.matterbridgeLatestVersion = this.matterbridgeInformation.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', this.matterbridgeVersion);
1110
877
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
1111
- // Matterbridge dev version (will be set in the checkUpdate function)
1112
878
  if (this.nodeContext)
1113
879
  this.matterbridgeDevVersion = this.matterbridgeInformation.matterbridgeDevVersion = await this.nodeContext.get('matterbridgeDevVersion', this.matterbridgeVersion);
1114
880
  this.log.debug(`Matterbridge Dev Version: ${this.matterbridgeDevVersion}`);
1115
- // Current working directory
1116
881
  const currentDir = process.cwd();
1117
882
  this.log.debug(`Current Working Directory: ${currentDir}`);
1118
- // Command line arguments (excluding 'node' and the script name)
1119
883
  const cmdArgs = process.argv.slice(2).join(' ');
1120
884
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
1121
885
  }
1122
- /**
1123
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
1124
- *
1125
- * @returns {Function} The MatterLogger function.
1126
- */
1127
886
  createMatterLogger() {
1128
- const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
887
+ const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
1129
888
  return (level, formattedLog) => {
1130
889
  const logger = formattedLog.slice(44, 44 + 20).trim();
1131
890
  const message = formattedLog.slice(65);
1132
891
  matterLogger.logName = logger;
1133
892
  switch (level) {
1134
893
  case MatterLogLevel.DEBUG:
1135
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
894
+ matterLogger.log("debug", message);
1136
895
  break;
1137
896
  case MatterLogLevel.INFO:
1138
- matterLogger.log("info" /* LogLevel.INFO */, message);
897
+ matterLogger.log("info", message);
1139
898
  break;
1140
899
  case MatterLogLevel.NOTICE:
1141
- matterLogger.log("notice" /* LogLevel.NOTICE */, message);
900
+ matterLogger.log("notice", message);
1142
901
  break;
1143
902
  case MatterLogLevel.WARN:
1144
- matterLogger.log("warn" /* LogLevel.WARN */, message);
903
+ matterLogger.log("warn", message);
1145
904
  break;
1146
905
  case MatterLogLevel.ERROR:
1147
- matterLogger.log("error" /* LogLevel.ERROR */, message);
906
+ matterLogger.log("error", message);
1148
907
  break;
1149
908
  case MatterLogLevel.FATAL:
1150
- matterLogger.log("fatal" /* LogLevel.FATAL */, message);
909
+ matterLogger.log("fatal", message);
1151
910
  break;
1152
911
  }
1153
912
  };
1154
913
  }
1155
- /**
1156
- * Creates a Matter File Logger.
1157
- *
1158
- * @param {string} filePath - The path to the log file.
1159
- * @param {boolean} [unlink] - Whether to unlink the log file before creating a new one.
1160
- * @returns {Function} - A function that logs formatted messages to the log file.
1161
- */
1162
914
  async createMatterFileLogger(filePath, unlink = false) {
1163
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1164
915
  let fileSize = 0;
1165
916
  if (unlink) {
1166
917
  try {
@@ -1171,12 +922,10 @@ export class Matterbridge extends EventEmitter {
1171
922
  }
1172
923
  }
1173
924
  return async (level, formattedLog) => {
1174
- /* istanbul ignore if */
1175
925
  if (fileSize > 100000000) {
1176
- return; // Stop logging if the file size is greater than 100MB
926
+ return;
1177
927
  }
1178
928
  fileSize += formattedLog.length;
1179
- /* istanbul ignore if */
1180
929
  if (fileSize > 100000000) {
1181
930
  await fs.appendFile(filePath, `Logging on file has been stopped because the file size is greater than 100MB.` + os.EOL);
1182
931
  return;
@@ -1209,21 +958,12 @@ export class Matterbridge extends EventEmitter {
1209
958
  }
1210
959
  };
1211
960
  }
1212
- /**
1213
- * Restarts the process by exiting the current instance and loading a new instance.
1214
- */
1215
961
  async restartProcess() {
1216
962
  await this.cleanup('restarting...', true);
1217
963
  }
1218
- /**
1219
- * Shut down the process.
1220
- */
1221
964
  async shutdownProcess() {
1222
965
  await this.cleanup('shutting down...', false);
1223
966
  }
1224
- /**
1225
- * Update matterbridge and shut down the process.
1226
- */
1227
967
  async updateProcess() {
1228
968
  this.log.info('Updating matterbridge...');
1229
969
  try {
@@ -1237,75 +977,52 @@ export class Matterbridge extends EventEmitter {
1237
977
  this.frontend.wssSendRestartRequired();
1238
978
  await this.cleanup('updating...', false);
1239
979
  }
1240
- /**
1241
- * Unregister all devices and shut down the process.
1242
- */
1243
980
  async unregisterAndShutdownProcess() {
1244
981
  this.log.info('Unregistering all devices and shutting down...');
1245
982
  for (const plugin of this.plugins) {
1246
983
  await this.removeAllBridgedEndpoints(plugin.name, 250);
1247
984
  }
1248
985
  this.log.debug('Waiting for the MessageExchange to finish...');
1249
- await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second for MessageExchange to finish
986
+ await new Promise((resolve) => setTimeout(resolve, 1000));
1250
987
  this.log.debug('Cleaning up and shutting down...');
1251
988
  await this.cleanup('unregistered all devices and shutting down...', false);
1252
989
  }
1253
- /**
1254
- * Reset commissioning and shut down the process.
1255
- */
1256
990
  async shutdownProcessAndReset() {
1257
991
  await this.cleanup('shutting down with reset...', false);
1258
992
  }
1259
- /**
1260
- * Factory reset and shut down the process.
1261
- */
1262
993
  async shutdownProcessAndFactoryReset() {
1263
994
  await this.cleanup('shutting down with factory reset...', false);
1264
995
  }
1265
- /**
1266
- * Cleans up the Matterbridge instance.
1267
- *
1268
- * @param {string} message - The cleanup message.
1269
- * @param {boolean} [restart] - Indicates whether to restart the instance after cleanup. Default is `false`.
1270
- * @param {number} [timeout] - The timeout duration to wait for the message exchange to complete in milliseconds. Default is 1000.
1271
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1272
- */
1273
996
  async cleanup(message, restart = false, timeout = 1000) {
1274
997
  if (this.initialized && !this.hasCleanupStarted) {
1275
998
  this.emit('cleanup_started');
1276
999
  this.hasCleanupStarted = true;
1277
1000
  this.log.info(message);
1278
- // Clear the start matter interval
1279
1001
  if (this.startMatterInterval) {
1280
1002
  clearInterval(this.startMatterInterval);
1281
1003
  this.startMatterInterval = undefined;
1282
1004
  this.log.debug('Start matter interval cleared');
1283
1005
  }
1284
- // Clear the check update timeout
1285
1006
  if (this.checkUpdateTimeout) {
1286
1007
  clearTimeout(this.checkUpdateTimeout);
1287
1008
  this.checkUpdateTimeout = undefined;
1288
1009
  this.log.debug('Check update timeout cleared');
1289
1010
  }
1290
- // Clear the check update interval
1291
1011
  if (this.checkUpdateInterval) {
1292
1012
  clearInterval(this.checkUpdateInterval);
1293
1013
  this.checkUpdateInterval = undefined;
1294
1014
  this.log.debug('Check update interval cleared');
1295
1015
  }
1296
- // Clear the configure timeout
1297
1016
  if (this.configureTimeout) {
1298
1017
  clearTimeout(this.configureTimeout);
1299
1018
  this.configureTimeout = undefined;
1300
1019
  this.log.debug('Matterbridge configure timeout cleared');
1301
1020
  }
1302
- // Clear the reachability timeout
1303
1021
  if (this.reachabilityTimeout) {
1304
1022
  clearTimeout(this.reachabilityTimeout);
1305
1023
  this.reachabilityTimeout = undefined;
1306
1024
  this.log.debug('Matterbridge reachability timeout cleared');
1307
1025
  }
1308
- // Call the shutdown method of each plugin and clear the plugins reachability timeout
1309
1026
  for (const plugin of this.plugins) {
1310
1027
  if (!plugin.enabled || plugin.error)
1311
1028
  continue;
@@ -1316,10 +1033,9 @@ export class Matterbridge extends EventEmitter {
1316
1033
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1317
1034
  }
1318
1035
  }
1319
- // Stop matter server nodes
1320
1036
  this.log.notice(`Stopping matter server nodes in ${this.bridgeMode} mode...`);
1321
1037
  this.log.debug('Waiting for the MessageExchange to finish...');
1322
- await new Promise((resolve) => setTimeout(resolve, timeout)); // Wait for MessageExchange to finish
1038
+ await new Promise((resolve) => setTimeout(resolve, timeout));
1323
1039
  if (this.bridgeMode === 'bridge') {
1324
1040
  if (this.serverNode) {
1325
1041
  await this.stopServerNode(this.serverNode);
@@ -1341,7 +1057,6 @@ export class Matterbridge extends EventEmitter {
1341
1057
  }
1342
1058
  }
1343
1059
  this.log.notice('Stopped matter server nodes');
1344
- // Matter commisioning reset
1345
1060
  if (message === 'shutting down with reset...') {
1346
1061
  this.log.info('Resetting Matterbridge commissioning information...');
1347
1062
  await this.matterStorageManager?.createContext('events')?.clearAll();
@@ -1351,36 +1066,18 @@ export class Matterbridge extends EventEmitter {
1351
1066
  await this.matterbridgeContext?.clearAll();
1352
1067
  this.log.info('Matter storage reset done! Remove the bridge from the controller.');
1353
1068
  }
1354
- // Stop matter storage
1355
1069
  await this.stopMatterStorage();
1356
- // Stop the frontend
1357
1070
  await this.frontend.stop();
1358
- // Remove the matterfilelogger
1359
1071
  try {
1360
1072
  Logger.removeLogger('matterfilelogger');
1361
1073
  }
1362
1074
  catch (error) {
1363
1075
  this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${db}: ${error instanceof Error ? error.message : String(error)}`);
1364
1076
  }
1365
- // Close the matterbridge node storage and context
1366
1077
  if (this.nodeStorage && this.nodeContext) {
1367
- /*
1368
- TODO: Implement serialization of registered devices in edge mode
1369
- this.log.info('Saving registered devices...');
1370
- const serializedRegisteredDevices: SerializedMatterbridgeEndpoint[] = [];
1371
- this.devices.forEach(async (device) => {
1372
- const serializedMatterbridgeDevice = MatterbridgeEndpoint.serialize(device);
1373
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1374
- if (serializedMatterbridgeDevice) serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1375
- });
1376
- await this.nodeContext.set<SerializedMatterbridgeEndpoint[]>('devices', serializedRegisteredDevices);
1377
- this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1378
- */
1379
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1380
1078
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1381
1079
  await this.nodeContext.close();
1382
1080
  this.nodeContext = undefined;
1383
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1384
1081
  for (const plugin of this.plugins) {
1385
1082
  if (plugin.nodeContext) {
1386
1083
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1397,10 +1094,8 @@ export class Matterbridge extends EventEmitter {
1397
1094
  }
1398
1095
  this.plugins.clear();
1399
1096
  this.devices.clear();
1400
- // Factory reset
1401
1097
  if (message === 'shutting down with factory reset...') {
1402
1098
  try {
1403
- // Delete matter storage directory with its subdirectories and backup
1404
1099
  const dir = path.join(this.matterbridgeDirectory, this.matterStorageName);
1405
1100
  this.log.info(`Removing matter storage directory: ${dir}`);
1406
1101
  await fs.rm(dir, { recursive: true });
@@ -1414,7 +1109,6 @@ export class Matterbridge extends EventEmitter {
1414
1109
  }
1415
1110
  }
1416
1111
  try {
1417
- // Delete matterbridge storage directory with its subdirectories and backup
1418
1112
  const dir = path.join(this.matterbridgeDirectory, this.nodeStorageName);
1419
1113
  this.log.info(`Removing matterbridge storage directory: ${dir}`);
1420
1114
  await fs.rm(dir, { recursive: true });
@@ -1429,13 +1123,12 @@ export class Matterbridge extends EventEmitter {
1429
1123
  }
1430
1124
  this.log.info('Factory reset done! Remove all paired fabrics from the controllers.');
1431
1125
  }
1432
- // Deregisters the process handlers
1433
1126
  this.deregisterProcessHandlers();
1434
1127
  if (restart) {
1435
1128
  if (message === 'updating...') {
1436
1129
  this.log.info('Cleanup completed. Updating...');
1437
1130
  Matterbridge.instance = undefined;
1438
- this.emit('update'); // Restart the process but the update has been done before. TODO move all updates to the cli
1131
+ this.emit('update');
1439
1132
  }
1440
1133
  else if (message === 'restarting...') {
1441
1134
  this.log.info('Cleanup completed. Restarting...');
@@ -1456,13 +1149,6 @@ export class Matterbridge extends EventEmitter {
1456
1149
  this.log.debug('Cleanup already started...');
1457
1150
  }
1458
1151
  }
1459
- /**
1460
- * Creates and configures the server node for a single not bridged device.
1461
- *
1462
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1463
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
1464
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
1465
- */
1466
1152
  async createDeviceServerNode(plugin, device) {
1467
1153
  if (device.mode === 'server' && !device.serverNode && device.deviceType && device.deviceName && device.vendorId && device.vendorName && device.productId && device.productName) {
1468
1154
  this.log.debug(`Creating device ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} server node...`);
@@ -1473,14 +1159,6 @@ export class Matterbridge extends EventEmitter {
1473
1159
  this.log.debug(`Added ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to server node`);
1474
1160
  }
1475
1161
  }
1476
- /**
1477
- * Creates and configures the server node for an accessory plugin for a given device.
1478
- *
1479
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1480
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
1481
- * @param {boolean} [start] - Whether to start the server node after adding the device. Default is `false`.
1482
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
1483
- */
1484
1162
  async createAccessoryPlugin(plugin, device, start = false) {
1485
1163
  if (!plugin.locked && device.deviceType && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
1486
1164
  plugin.locked = true;
@@ -1494,13 +1172,6 @@ export class Matterbridge extends EventEmitter {
1494
1172
  await this.startServerNode(plugin.serverNode);
1495
1173
  }
1496
1174
  }
1497
- /**
1498
- * Creates and configures the server node and the aggregator node for a dynamic plugin.
1499
- *
1500
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1501
- * @param {boolean} [start] - Whether to start the server node after adding the aggregator node.
1502
- * @returns {Promise<void>} A promise that resolves when the server node and the aggregator node for the dynamic plugin is created and configured.
1503
- */
1504
1175
  async createDynamicPlugin(plugin, start = false) {
1505
1176
  if (!plugin.locked) {
1506
1177
  plugin.locked = true;
@@ -1513,14 +1184,7 @@ export class Matterbridge extends EventEmitter {
1513
1184
  await this.startServerNode(plugin.serverNode);
1514
1185
  }
1515
1186
  }
1516
- /**
1517
- * Starts the Matterbridge in bridge mode.
1518
- *
1519
- * @private
1520
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1521
- */
1522
1187
  async startBridge() {
1523
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1524
1188
  if (!this.matterStorageManager)
1525
1189
  throw new Error('No storage manager initialized');
1526
1190
  if (!this.matterbridgeContext)
@@ -1559,16 +1223,13 @@ export class Matterbridge extends EventEmitter {
1559
1223
  clearInterval(this.startMatterInterval);
1560
1224
  this.startMatterInterval = undefined;
1561
1225
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1562
- // Start the Matter server node
1563
- this.startServerNode(this.serverNode); // We don't await this, because the server node is started in the background
1564
- // Start the Matter server node of single devices in mode 'server'
1226
+ this.startServerNode(this.serverNode);
1565
1227
  for (const device of this.devices.array()) {
1566
1228
  if (device.mode === 'server' && device.serverNode) {
1567
1229
  this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
1568
- this.startServerNode(device.serverNode); // We don't await this, because the server node is started in the background
1230
+ this.startServerNode(device.serverNode);
1569
1231
  }
1570
1232
  }
1571
- // Configure the plugins
1572
1233
  this.configureTimeout = setTimeout(async () => {
1573
1234
  for (const plugin of this.plugins) {
1574
1235
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1586,24 +1247,16 @@ export class Matterbridge extends EventEmitter {
1586
1247
  }
1587
1248
  this.frontend.wssSendRefreshRequired('plugins');
1588
1249
  }, 30 * 1000).unref();
1589
- // Setting reachability to true
1590
1250
  this.reachabilityTimeout = setTimeout(() => {
1591
1251
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1592
1252
  if (this.aggregatorNode)
1593
1253
  this.setAggregatorReachability(this.aggregatorNode, true);
1594
1254
  this.frontend.wssSendRefreshRequired('reachability');
1595
1255
  }, 60 * 1000).unref();
1596
- // Logger.get('LogServerNode').info(this.serverNode);
1597
1256
  this.emit('bridge_started');
1598
1257
  this.log.notice('Matterbridge bridge started successfully');
1599
1258
  }, 1000);
1600
1259
  }
1601
- /**
1602
- * Starts the Matterbridge in childbridge mode.
1603
- *
1604
- * @private
1605
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1606
- */
1607
1260
  async startChildbridge() {
1608
1261
  if (!this.matterStorageManager)
1609
1262
  throw new Error('No storage manager initialized');
@@ -1641,7 +1294,6 @@ export class Matterbridge extends EventEmitter {
1641
1294
  clearInterval(this.startMatterInterval);
1642
1295
  this.startMatterInterval = undefined;
1643
1296
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1644
- // Configure the plugins
1645
1297
  this.configureTimeout = setTimeout(async () => {
1646
1298
  for (const plugin of this.plugins) {
1647
1299
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1678,9 +1330,7 @@ export class Matterbridge extends EventEmitter {
1678
1330
  this.log.error(`Node storage context not found for plugin ${plg}${plugin.name}${er}`);
1679
1331
  continue;
1680
1332
  }
1681
- // Start the Matter server node
1682
- this.startServerNode(plugin.serverNode); // We don't await this, because the server node is started in the background
1683
- // Setting reachability to true
1333
+ this.startServerNode(plugin.serverNode);
1684
1334
  plugin.reachabilityTimeout = setTimeout(() => {
1685
1335
  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}`);
1686
1336
  if (plugin.type === 'DynamicPlatform' && plugin.aggregatorNode)
@@ -1688,241 +1338,19 @@ export class Matterbridge extends EventEmitter {
1688
1338
  this.frontend.wssSendRefreshRequired('reachability');
1689
1339
  }, 60 * 1000).unref();
1690
1340
  }
1691
- // Start the Matter server node of single devices in mode 'server'
1692
1341
  for (const device of this.devices.array()) {
1693
1342
  if (device.mode === 'server' && device.serverNode) {
1694
1343
  this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
1695
- this.startServerNode(device.serverNode); // We don't await this, because the server node is started in the background
1344
+ this.startServerNode(device.serverNode);
1696
1345
  }
1697
1346
  }
1698
- // Logger.get('LogServerNode').info(this.serverNode);
1699
1347
  this.emit('childbridge_started');
1700
1348
  this.log.notice('Matterbridge childbridge started successfully');
1701
1349
  }, 1000);
1702
1350
  }
1703
- /**
1704
- * Starts the Matterbridge controller.
1705
- *
1706
- * @private
1707
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1708
- */
1709
1351
  async startController() {
1710
- /*
1711
- if (!this.matterStorageManager) {
1712
- this.log.error('No storage manager initialized');
1713
- await this.cleanup('No storage manager initialized');
1714
- return;
1715
- }
1716
- this.log.info('Creating context: mattercontrollerContext');
1717
- this.controllerContext = this.matterStorageManager.createContext('mattercontrollerContext');
1718
- if (!this.controllerContext) {
1719
- this.log.error('No storage context mattercontrollerContext initialized');
1720
- await this.cleanup('No storage context mattercontrollerContext initialized');
1721
- return;
1722
- }
1723
-
1724
- this.log.debug('Starting matterbridge in mode', this.bridgeMode);
1725
- this.matterServer = await this.createMatterServer(this.storageManager);
1726
- this.log.info('Creating matter commissioning controller');
1727
- this.commissioningController = new CommissioningController({
1728
- autoConnect: false,
1729
- });
1730
- this.log.info('Adding matter commissioning controller to matter server');
1731
- await this.matterServer.addCommissioningController(this.commissioningController);
1732
-
1733
- this.log.info('Starting matter server');
1734
- await this.matterServer.start();
1735
- this.log.info('Matter server started');
1736
- const commissioningOptions: ControllerCommissioningFlowOptions = {
1737
- regulatoryLocation: GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor,
1738
- regulatoryCountryCode: 'XX',
1739
- };
1740
- const commissioningController = new CommissioningController({
1741
- environment: {
1742
- environment,
1743
- id: uniqueId,
1744
- },
1745
- autoConnect: false, // Do not auto connect to the commissioned nodes
1746
- adminFabricLabel,
1747
- });
1748
-
1749
- if (hasParameter('pairingcode')) {
1750
- this.log.info('Pairing device with pairingcode:', getParameter('pairingcode'));
1751
- const pairingCode = getParameter('pairingcode');
1752
- const ip = this.controllerContext.has('ip') ? this.controllerContext.get<string>('ip') : undefined;
1753
- const port = this.controllerContext.has('port') ? this.controllerContext.get<number>('port') : undefined;
1754
-
1755
- let longDiscriminator, setupPin, shortDiscriminator;
1756
- if (pairingCode !== undefined) {
1757
- const pairingCodeCodec = ManualPairingCodeCodec.decode(pairingCode);
1758
- shortDiscriminator = pairingCodeCodec.shortDiscriminator;
1759
- longDiscriminator = undefined;
1760
- setupPin = pairingCodeCodec.passcode;
1761
- this.log.info(`Data extracted from pairing code: ${Logger.toJSON(pairingCodeCodec)}`);
1762
- } else {
1763
- longDiscriminator = await this.controllerContext.get('longDiscriminator', 3840);
1764
- if (longDiscriminator > 4095) throw new Error('Discriminator value must be less than 4096');
1765
- setupPin = this.controllerContext.get('pin', 20202021);
1766
- }
1767
- if ((shortDiscriminator === undefined && longDiscriminator === undefined) || setupPin === undefined) {
1768
- throw new Error('Please specify the longDiscriminator of the device to commission with -longDiscriminator or provide a valid passcode with -passcode');
1769
- }
1770
-
1771
- const options = {
1772
- commissioning: commissioningOptions,
1773
- discovery: {
1774
- knownAddress: ip !== undefined && port !== undefined ? { ip, port, type: 'udp' } : undefined,
1775
- identifierData: longDiscriminator !== undefined ? { longDiscriminator } : shortDiscriminator !== undefined ? { shortDiscriminator } : {},
1776
- },
1777
- passcode: setupPin,
1778
- } as NodeCommissioningOptions;
1779
- this.log.info('Commissioning with options:', options);
1780
- const nodeId = await this.commissioningController.commissionNode(options);
1781
- this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1782
- this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1783
- } // (hasParameter('pairingcode'))
1784
-
1785
- if (hasParameter('unpairall')) {
1786
- this.log.info('***Commissioning controller unpairing all nodes...');
1787
- const nodeIds = this.commissioningController.getCommissionedNodes();
1788
- for (const nodeId of nodeIds) {
1789
- this.log.info('***Commissioning controller unpairing node:', nodeId);
1790
- await this.commissioningController.removeNode(nodeId);
1791
- }
1792
- return;
1793
- }
1794
-
1795
- if (hasParameter('discover')) {
1796
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1797
- // console.log(discover);
1798
- }
1799
-
1800
- if (!this.commissioningController.isCommissioned()) {
1801
- this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
1802
- return;
1803
- }
1804
-
1805
- const nodeIds = this.commissioningController.getCommissionedNodes();
1806
- this.log.info(`***Commissioning controller is commissioned ${this.commissioningController.isCommissioned()} and has ${nodeIds.length} nodes commisioned: `);
1807
- for (const nodeId of nodeIds) {
1808
- this.log.info(`***Connecting to commissioned node: ${nodeId}`);
1809
-
1810
- const node = await this.commissioningController.connectNode(nodeId, {
1811
- autoSubscribe: false,
1812
- attributeChangedCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, attributeName }, value }) =>
1813
- this.log.info(`***Commissioning controller attributeChangedCallback ${peerNodeId}: attribute ${nodeId}/${endpointId}/${clusterId}/${attributeName} changed to ${Logger.toJSON(value)}`),
1814
- eventTriggeredCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, eventName }, events }) =>
1815
- this.log.info(`***Commissioning controller eventTriggeredCallback ${peerNodeId}: Event ${nodeId}/${endpointId}/${clusterId}/${eventName} triggered with ${Logger.toJSON(events)}`),
1816
- stateInformationCallback: (peerNodeId, info) => {
1817
- switch (info) {
1818
- case NodeStateInformation.Connected:
1819
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} connected`);
1820
- break;
1821
- case NodeStateInformation.Disconnected:
1822
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} disconnected`);
1823
- break;
1824
- case NodeStateInformation.Reconnecting:
1825
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} reconnecting`);
1826
- break;
1827
- case NodeStateInformation.WaitingForDeviceDiscovery:
1828
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} waiting for device discovery`);
1829
- break;
1830
- case NodeStateInformation.StructureChanged:
1831
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} structure changed`);
1832
- break;
1833
- case NodeStateInformation.Decommissioned:
1834
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} decommissioned`);
1835
- break;
1836
- default:
1837
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} NodeStateInformation.${info}`);
1838
- break;
1839
- }
1840
- },
1841
- });
1842
-
1843
- node.logStructure();
1844
-
1845
- // Get the interaction client
1846
- this.log.info('Getting the interaction client');
1847
- const interactionClient = await node.getInteractionClient();
1848
- let cluster;
1849
- let attributes;
1850
-
1851
- // Log BasicInformationCluster
1852
- cluster = BasicInformationCluster;
1853
- attributes = await interactionClient.getMultipleAttributes({
1854
- attributes: [{ clusterId: cluster.id }],
1855
- });
1856
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1857
- attributes.forEach((attribute) => {
1858
- this.log.info(
1859
- `- 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}`,
1860
- );
1861
- });
1862
-
1863
- // Log PowerSourceCluster
1864
- cluster = PowerSourceCluster;
1865
- attributes = await interactionClient.getMultipleAttributes({
1866
- attributes: [{ clusterId: cluster.id }],
1867
- });
1868
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1869
- attributes.forEach((attribute) => {
1870
- this.log.info(
1871
- `- 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}`,
1872
- );
1873
- });
1874
-
1875
- // Log ThreadNetworkDiagnostics
1876
- cluster = ThreadNetworkDiagnosticsCluster;
1877
- attributes = await interactionClient.getMultipleAttributes({
1878
- attributes: [{ clusterId: cluster.id }],
1879
- });
1880
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1881
- attributes.forEach((attribute) => {
1882
- this.log.info(
1883
- `- 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}`,
1884
- );
1885
- });
1886
-
1887
- // Log SwitchCluster
1888
- cluster = SwitchCluster;
1889
- attributes = await interactionClient.getMultipleAttributes({
1890
- attributes: [{ clusterId: cluster.id }],
1891
- });
1892
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1893
- attributes.forEach((attribute) => {
1894
- this.log.info(
1895
- `- 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}`,
1896
- );
1897
- });
1898
-
1899
- this.log.info('Subscribing to all attributes and events');
1900
- await node.subscribeAllAttributesAndEvents({
1901
- ignoreInitialTriggers: false,
1902
- attributeChangedCallback: ({ path: { nodeId, clusterId, endpointId, attributeName }, version, value }) =>
1903
- this.log.info(
1904
- `***${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}`,
1905
- ),
1906
- eventTriggeredCallback: ({ path: { nodeId, clusterId, endpointId, eventName }, events }) => {
1907
- this.log.info(
1908
- `***${db}Commissioning controller eventTriggeredCallback: event ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${eventName}${db} triggered with ${debugStringify(events ?? { none: true })}`,
1909
- );
1910
- },
1911
- });
1912
- this.log.info('Subscribed to all attributes and events');
1913
- }
1914
- */
1915
1352
  }
1916
- /** */
1917
- /** Matter.js methods */
1918
- /** */
1919
- /**
1920
- * Starts the matter storage with name Matterbridge, create the matterbridge context and performs a backup.
1921
- *
1922
- * @returns {Promise<void>} - A promise that resolves when the storage is started.
1923
- */
1924
1353
  async startMatterStorage() {
1925
- // Setup Matter storage
1926
1354
  this.log.info(`Starting matter node storage...`);
1927
1355
  this.matterStorageService = this.environment.get(StorageService);
1928
1356
  this.log.info(`Matter node storage service created: ${this.matterStorageService.location}`);
@@ -1931,17 +1359,8 @@ export class Matterbridge extends EventEmitter {
1931
1359
  this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', bridge.code, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName);
1932
1360
  this.matterbridgeInformation.matterbridgeSerialNumber = await this.matterbridgeContext.get('serialNumber', '');
1933
1361
  this.log.info('Matter node storage started');
1934
- // Backup matter storage since it is created/opened correctly
1935
1362
  await this.backupMatterStorage(path.join(this.matterbridgeDirectory, this.matterStorageName), path.join(this.matterbridgeDirectory, this.matterStorageName + '.backup'));
1936
1363
  }
1937
- /**
1938
- * Makes a backup copy of the specified matter storage directory.
1939
- *
1940
- * @param {string} storageName - The name of the storage directory to be backed up.
1941
- * @param {string} backupName - The name of the backup directory to be created.
1942
- * @private
1943
- * @returns {Promise<void>} A promise that resolves when the has been done.
1944
- */
1945
1364
  async backupMatterStorage(storageName, backupName) {
1946
1365
  this.log.info('Creating matter node storage backup...');
1947
1366
  try {
@@ -1952,11 +1371,6 @@ export class Matterbridge extends EventEmitter {
1952
1371
  this.log.error(`Error creating matter node storage backup from ${storageName} to ${backupName}:`, error);
1953
1372
  }
1954
1373
  }
1955
- /**
1956
- * Stops the matter storage.
1957
- *
1958
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1959
- */
1960
1374
  async stopMatterStorage() {
1961
1375
  this.log.info('Closing matter node storage...');
1962
1376
  await this.matterStorageManager?.close();
@@ -1965,19 +1379,6 @@ export class Matterbridge extends EventEmitter {
1965
1379
  this.matterbridgeContext = undefined;
1966
1380
  this.log.info('Matter node storage closed');
1967
1381
  }
1968
- /**
1969
- * Creates a server node storage context.
1970
- *
1971
- * @param {string} pluginName - The name of the plugin.
1972
- * @param {string} deviceName - The name of the device.
1973
- * @param {DeviceTypeId} deviceType - The device type of the device.
1974
- * @param {number} vendorId - The vendor ID.
1975
- * @param {string} vendorName - The vendor name.
1976
- * @param {number} productId - The product ID.
1977
- * @param {string} productName - The product name.
1978
- * @param {string} [serialNumber] - The serial number of the device (optional).
1979
- * @returns {Promise<StorageContext>} The storage context for the commissioning server.
1980
- */
1981
1382
  async createServerNodeContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber) {
1982
1383
  const { randomBytes } = await import('node:crypto');
1983
1384
  if (!this.matterStorageService)
@@ -2011,15 +1412,6 @@ export class Matterbridge extends EventEmitter {
2011
1412
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2012
1413
  return storageContext;
2013
1414
  }
2014
- /**
2015
- * Creates a server node.
2016
- *
2017
- * @param {StorageContext} storageContext - The storage context for the server node.
2018
- * @param {number} [port] - The port number for the server node. Defaults to 5540.
2019
- * @param {number} [passcode] - The passcode for the server node. Defaults to 20242025.
2020
- * @param {number} [discriminator] - The discriminator for the server node. Defaults to 3850.
2021
- * @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created server node.
2022
- */
2023
1415
  async createServerNode(storageContext, port = 5540, passcode = 20242025, discriminator = 3850) {
2024
1416
  const storeId = await storageContext.get('storeId');
2025
1417
  this.log.notice(`Creating server node for ${storeId} on port ${port} with passcode ${passcode} and discriminator ${discriminator}...`);
@@ -2029,37 +1421,24 @@ export class Matterbridge extends EventEmitter {
2029
1421
  this.log.debug(`- uniqueId: ${await storageContext.get('uniqueId')}`);
2030
1422
  this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
2031
1423
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2032
- /**
2033
- * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
2034
- */
2035
1424
  const serverNode = await ServerNode.create({
2036
- // Required: Give the Node a unique ID which is used to store the state of this node
2037
1425
  id: storeId,
2038
- // Provide Network relevant configuration like the port
2039
- // Optional when operating only one device on a host, Default port is 5540
2040
1426
  network: {
2041
1427
  listeningAddressIpv4: this.ipv4address,
2042
1428
  listeningAddressIpv6: this.ipv6address,
2043
1429
  port,
2044
1430
  },
2045
- // Provide the certificate for the device
2046
1431
  operationalCredentials: {
2047
1432
  certification: this.certification,
2048
1433
  },
2049
- // Provide Commissioning relevant settings
2050
- // Optional for development/testing purposes
2051
1434
  commissioning: {
2052
1435
  passcode,
2053
1436
  discriminator,
2054
1437
  },
2055
- // Provide Node announcement settings
2056
- // Optional: If Ommitted some development defaults are used
2057
1438
  productDescription: {
2058
1439
  name: await storageContext.get('deviceName'),
2059
1440
  deviceType: DeviceTypeId(await storageContext.get('deviceType')),
2060
1441
  },
2061
- // Provide defaults for the BasicInformation cluster on the Root endpoint
2062
- // Optional: If Omitted some development defaults are used
2063
1442
  basicInformation: {
2064
1443
  vendorId: VendorId(await storageContext.get('vendorId')),
2065
1444
  vendorName: await storageContext.get('vendorName'),
@@ -2077,13 +1456,12 @@ export class Matterbridge extends EventEmitter {
2077
1456
  },
2078
1457
  });
2079
1458
  const sanitizeFabrics = (fabrics, resetSessions = false) => {
2080
- // New type of fabric information: Record<FabricIndex, ExposedFabricInformation>
2081
1459
  const sanitizedFabrics = this.sanitizeFabricInformations(Array.from(Object.values(fabrics)));
2082
1460
  this.log.info(`Fabrics: ${debugStringify(sanitizedFabrics)}`);
2083
1461
  if (this.bridgeMode === 'bridge') {
2084
1462
  this.matterbridgeFabricInformations = sanitizedFabrics;
2085
1463
  if (resetSessions)
2086
- this.matterbridgeSessionInformations = undefined; // Changed cause Invoke Matterbridge.operationalCredentials.updateFabricLabel is sent after the session is created
1464
+ this.matterbridgeSessionInformations = undefined;
2087
1465
  this.matterbridgePaired = true;
2088
1466
  }
2089
1467
  if (this.bridgeMode === 'childbridge') {
@@ -2091,22 +1469,16 @@ export class Matterbridge extends EventEmitter {
2091
1469
  if (plugin) {
2092
1470
  plugin.fabricInformations = sanitizedFabrics;
2093
1471
  if (resetSessions)
2094
- plugin.sessionInformations = undefined; // Changed cause Invoke Matterbridge.operationalCredentials.updateFabricLabel is sent after the session is created
1472
+ plugin.sessionInformations = undefined;
2095
1473
  plugin.paired = true;
2096
1474
  }
2097
1475
  }
2098
1476
  };
2099
- /**
2100
- * This event is triggered when the device is initially commissioned successfully.
2101
- * This means: It is added to the first fabric.
2102
- */
2103
1477
  serverNode.lifecycle.commissioned.on(() => {
2104
1478
  this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`);
2105
1479
  clearTimeout(this.endAdvertiseTimeout);
2106
1480
  });
2107
- /** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
2108
1481
  serverNode.lifecycle.decommissioned.on(() => this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`));
2109
- /** This event is triggered when the device went online. This means that it is discoverable in the network. */
2110
1482
  serverNode.lifecycle.online.on(async () => {
2111
1483
  this.log.notice(`Server node for ${storeId} is online`);
2112
1484
  if (!serverNode.lifecycle.isCommissioned) {
@@ -2145,7 +1517,6 @@ export class Matterbridge extends EventEmitter {
2145
1517
  }
2146
1518
  }
2147
1519
  }
2148
- // Set a timeout to show that advertising stops after 15 minutes if not commissioned
2149
1520
  this.startEndAdvertiseTimer(serverNode);
2150
1521
  }
2151
1522
  else {
@@ -2157,7 +1528,6 @@ export class Matterbridge extends EventEmitter {
2157
1528
  this.frontend.wssSendSnackbarMessage(`${storeId} is online`, 5, 'success');
2158
1529
  this.emit('online', storeId);
2159
1530
  });
2160
- /** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
2161
1531
  serverNode.lifecycle.offline.on(() => {
2162
1532
  this.log.notice(`Server node for ${storeId} is offline`);
2163
1533
  if (this.bridgeMode === 'bridge') {
@@ -2182,10 +1552,6 @@ export class Matterbridge extends EventEmitter {
2182
1552
  this.frontend.wssSendSnackbarMessage(`${storeId} is offline`, 5, 'warning');
2183
1553
  this.emit('offline', storeId);
2184
1554
  });
2185
- /**
2186
- * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
2187
- * information is needed.
2188
- */
2189
1555
  serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
2190
1556
  let action = '';
2191
1557
  switch (fabricAction) {
@@ -2216,24 +1582,16 @@ export class Matterbridge extends EventEmitter {
2216
1582
  }
2217
1583
  }
2218
1584
  };
2219
- /**
2220
- * This event is triggered when an operative new session was opened by a Controller.
2221
- * It is not triggered for the initial commissioning process, just afterwards for real connections.
2222
- */
2223
1585
  serverNode.events.sessions.opened.on((session) => {
2224
1586
  this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
2225
1587
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
2226
1588
  this.frontend.wssSendRefreshRequired('sessions');
2227
1589
  });
2228
- /**
2229
- * This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
2230
- */
2231
1590
  serverNode.events.sessions.closed.on((session) => {
2232
1591
  this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
2233
1592
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
2234
1593
  this.frontend.wssSendRefreshRequired('sessions');
2235
1594
  });
2236
- /** This event is triggered when a subscription gets added or removed on an operative session. */
2237
1595
  serverNode.events.sessions.subscriptionsChanged.on((session) => {
2238
1596
  this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
2239
1597
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
@@ -2242,11 +1600,6 @@ export class Matterbridge extends EventEmitter {
2242
1600
  this.log.info(`Created server node for ${storeId}`);
2243
1601
  return serverNode;
2244
1602
  }
2245
- /**
2246
- * Starts the 15 minutes timer to advice that advertising for the specified server node is ended.
2247
- *
2248
- * @param {ServerNode} [matterServerNode] - The server node to start.
2249
- */
2250
1603
  startEndAdvertiseTimer(matterServerNode) {
2251
1604
  if (this.endAdvertiseTimeout) {
2252
1605
  this.log.debug(`Clear ${matterServerNode.id} server node end advertise timer`);
@@ -2275,25 +1628,12 @@ export class Matterbridge extends EventEmitter {
2275
1628
  this.log.notice(`Advertising on server node for ${matterServerNode.id} stopped. Restart to commission.`);
2276
1629
  }, 15 * 60 * 1000).unref();
2277
1630
  }
2278
- /**
2279
- * Starts the specified server node.
2280
- *
2281
- * @param {ServerNode} [matterServerNode] - The server node to start.
2282
- * @returns {Promise<void>} A promise that resolves when the server node has started.
2283
- */
2284
1631
  async startServerNode(matterServerNode) {
2285
1632
  if (!matterServerNode)
2286
1633
  return;
2287
1634
  this.log.notice(`Starting ${matterServerNode.id} server node`);
2288
1635
  await matterServerNode.start();
2289
1636
  }
2290
- /**
2291
- * Stops the specified server node.
2292
- *
2293
- * @param {ServerNode} matterServerNode - The server node to stop.
2294
- * @param {number} [timeout] - The timeout in milliseconds for stopping the server node. Defaults to 30 seconds.
2295
- * @returns {Promise<void>} A promise that resolves when the server node has stopped.
2296
- */
2297
1637
  async stopServerNode(matterServerNode, timeout = 30000) {
2298
1638
  if (!matterServerNode)
2299
1639
  return;
@@ -2306,12 +1646,6 @@ export class Matterbridge extends EventEmitter {
2306
1646
  this.log.error(`Failed to close ${matterServerNode.id} server node: ${error instanceof Error ? error.message : error}`);
2307
1647
  }
2308
1648
  }
2309
- /**
2310
- * Advertises the specified server node.
2311
- *
2312
- * @param {ServerNode} [matterServerNode] - The server node to advertise.
2313
- * @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.
2314
- */
2315
1649
  async advertiseServerNode(matterServerNode) {
2316
1650
  if (matterServerNode) {
2317
1651
  await matterServerNode.env.get(DeviceCommissioner)?.allowBasicCommissioning();
@@ -2320,39 +1654,19 @@ export class Matterbridge extends EventEmitter {
2320
1654
  return { qrPairingCode, manualPairingCode };
2321
1655
  }
2322
1656
  }
2323
- /**
2324
- * Stop advertise the specified server node.
2325
- *
2326
- * @param {ServerNode} [matterServerNode] - The server node to advertise.
2327
- * @returns {Promise<void>} A promise that resolves when the server node has stopped advertising.
2328
- */
2329
1657
  async stopAdvertiseServerNode(matterServerNode) {
2330
1658
  if (matterServerNode && matterServerNode.lifecycle.isOnline) {
2331
1659
  await matterServerNode.env.get(DeviceCommissioner)?.endCommissioning();
2332
1660
  this.log.notice(`Stopped advertising for ${matterServerNode.id}`);
2333
1661
  }
2334
1662
  }
2335
- /**
2336
- * Creates an aggregator node with the specified storage context.
2337
- *
2338
- * @param {StorageContext} storageContext - The storage context for the aggregator node.
2339
- * @returns {Promise<Endpoint<AggregatorEndpoint>>} A promise that resolves to the created aggregator node.
2340
- */
2341
1663
  async createAggregatorNode(storageContext) {
2342
1664
  this.log.notice(`Creating ${await storageContext.get('storeId')} aggregator...`);
2343
1665
  const aggregatorNode = new Endpoint(AggregatorEndpoint, { id: `${await storageContext.get('storeId')}` });
2344
1666
  this.log.info(`Created ${await storageContext.get('storeId')} aggregator`);
2345
1667
  return aggregatorNode;
2346
1668
  }
2347
- /**
2348
- * Adds a MatterbridgeEndpoint to the specified plugin.
2349
- *
2350
- * @param {string} pluginName - The name of the plugin.
2351
- * @param {MatterbridgeEndpoint} device - The device to add as a bridged endpoint.
2352
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been added.
2353
- */
2354
1669
  async addBridgedEndpoint(pluginName, device) {
2355
- // Check if the plugin is registered
2356
1670
  const plugin = this.plugins.get(pluginName);
2357
1671
  if (!plugin) {
2358
1672
  this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
@@ -2372,7 +1686,6 @@ export class Matterbridge extends EventEmitter {
2372
1686
  }
2373
1687
  else if (this.bridgeMode === 'bridge') {
2374
1688
  if (device.mode === 'matter') {
2375
- // Register and add the device to the matterbridge server node
2376
1689
  this.log.debug(`Adding matter endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge server node...`);
2377
1690
  if (!this.serverNode) {
2378
1691
  this.log.error('Server node not found for Matterbridge');
@@ -2389,7 +1702,6 @@ export class Matterbridge extends EventEmitter {
2389
1702
  }
2390
1703
  }
2391
1704
  else {
2392
- // Register and add the device to the matterbridge aggregator node
2393
1705
  this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
2394
1706
  if (!this.aggregatorNode) {
2395
1707
  this.log.error('Aggregator node not found for Matterbridge');
@@ -2407,7 +1719,6 @@ export class Matterbridge extends EventEmitter {
2407
1719
  }
2408
1720
  }
2409
1721
  else if (this.bridgeMode === 'childbridge') {
2410
- // Register and add the device to the plugin server node
2411
1722
  if (plugin.type === 'AccessoryPlatform') {
2412
1723
  try {
2413
1724
  this.log.debug(`Creating endpoint ${dev}${device.deviceName}${db} for AccessoryPlatform plugin ${plg}${plugin.name}${db} server node`);
@@ -2431,12 +1742,10 @@ export class Matterbridge extends EventEmitter {
2431
1742
  return;
2432
1743
  }
2433
1744
  }
2434
- // Register and add the device to the plugin aggregator node
2435
1745
  if (plugin.type === 'DynamicPlatform') {
2436
1746
  try {
2437
1747
  this.log.debug(`Adding bridged endpoint ${dev}${device.deviceName}${db} for DynamicPlatform plugin ${plg}${plugin.name}${db} aggregator node`);
2438
1748
  await this.createDynamicPlugin(plugin);
2439
- // Fast plugins can add another device before the server node is ready, so we wait for the server node to be ready
2440
1749
  await waiter(`createDynamicPlugin(${plugin.name})`, () => plugin.serverNode?.hasParts === true);
2441
1750
  if (!plugin.aggregatorNode) {
2442
1751
  this.log.error(`Aggregator node not found for plugin ${plg}${plugin.name}${er}`);
@@ -2459,28 +1768,17 @@ export class Matterbridge extends EventEmitter {
2459
1768
  plugin.registeredDevices++;
2460
1769
  if (plugin.addedDevices !== undefined)
2461
1770
  plugin.addedDevices++;
2462
- // Add the device to the DeviceManager
2463
1771
  this.devices.set(device);
2464
- // Subscribe to the reachable$Changed event
2465
1772
  await this.subscribeAttributeChanged(plugin, device);
2466
1773
  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}`);
2467
1774
  }
2468
- /**
2469
- * Removes a MatterbridgeEndpoint from the specified plugin.
2470
- *
2471
- * @param {string} pluginName - The name of the plugin.
2472
- * @param {MatterbridgeEndpoint} device - The device to remove as a bridged endpoint.
2473
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been removed.
2474
- */
2475
1775
  async removeBridgedEndpoint(pluginName, device) {
2476
1776
  this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
2477
- // Check if the plugin is registered
2478
1777
  const plugin = this.plugins.get(pluginName);
2479
1778
  if (!plugin) {
2480
1779
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
2481
1780
  return;
2482
1781
  }
2483
- // Register and add the device to the matterbridge aggregator node
2484
1782
  if (this.bridgeMode === 'bridge') {
2485
1783
  if (!this.aggregatorNode) {
2486
1784
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator node not found`);
@@ -2495,7 +1793,6 @@ export class Matterbridge extends EventEmitter {
2495
1793
  }
2496
1794
  else if (this.bridgeMode === 'childbridge') {
2497
1795
  if (plugin.type === 'AccessoryPlatform') {
2498
- // Nothing to do here since the server node has no aggregator node but only the device itself
2499
1796
  }
2500
1797
  else if (plugin.type === 'DynamicPlatform') {
2501
1798
  if (!plugin.aggregatorNode) {
@@ -2510,21 +1807,8 @@ export class Matterbridge extends EventEmitter {
2510
1807
  if (plugin.addedDevices !== undefined)
2511
1808
  plugin.addedDevices--;
2512
1809
  }
2513
- // Remove the device from the DeviceManager
2514
1810
  this.devices.remove(device);
2515
1811
  }
2516
- /**
2517
- * Removes all bridged endpoints from the specified plugin.
2518
- *
2519
- * @param {string} pluginName - The name of the plugin.
2520
- * @param {number} [delay] - The delay in milliseconds between removing each bridged endpoint (default: 0).
2521
- * @returns {Promise<void>} A promise that resolves when all bridged endpoints have been removed.
2522
- *
2523
- * @remarks
2524
- * This method iterates through all devices in the DeviceManager and removes each bridged endpoint associated with the specified plugin.
2525
- * It also applies a delay between each removal if specified.
2526
- * The delay is useful to allow the controllers to receive a single subscription for each device removed.
2527
- */
2528
1812
  async removeAllBridgedEndpoints(pluginName, delay = 0) {
2529
1813
  this.log.debug(`Removing all bridged endpoints for plugin ${plg}${pluginName}${db}${delay > 0 ? ` with delay ${delay} ms` : ''}`);
2530
1814
  for (const device of this.devices.array().filter((device) => device.plugin === pluginName)) {
@@ -2535,15 +1819,6 @@ export class Matterbridge extends EventEmitter {
2535
1819
  if (delay > 0)
2536
1820
  await new Promise((resolve) => setTimeout(resolve, 2000));
2537
1821
  }
2538
- /**
2539
- * Subscribes to the attribute change event for the given device and plugin.
2540
- * Specifically, it listens for changes in the 'reachable' attribute of the
2541
- * BridgedDeviceBasicInformationServer cluster server of the bridged device or BasicInformationServer cluster server of server node.
2542
- *
2543
- * @param {RegisteredPlugin} plugin - The plugin associated with the device.
2544
- * @param {MatterbridgeEndpoint} device - The device to subscribe to attribute changes for.
2545
- * @returns {Promise<void>} A promise that resolves when the subscription is set up.
2546
- */
2547
1822
  async subscribeAttributeChanged(plugin, device) {
2548
1823
  this.log.info(`Subscribing attributes for endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) plugin ${plg}${plugin.name}${nf}`);
2549
1824
  if (this.bridgeMode === 'childbridge' && plugin.type === 'AccessoryPlatform' && plugin.serverNode) {
@@ -2559,12 +1834,6 @@ export class Matterbridge extends EventEmitter {
2559
1834
  });
2560
1835
  }
2561
1836
  }
2562
- /**
2563
- * Sanitizes the fabric information by converting bigint properties to strings because `res.json` doesn't support bigint.
2564
- *
2565
- * @param {ExposedFabricInformation[]} fabricInfo - The array of exposed fabric information objects.
2566
- * @returns {SanitizedExposedFabricInformation[]} An array of sanitized exposed fabric information objects.
2567
- */
2568
1837
  sanitizeFabricInformations(fabricInfo) {
2569
1838
  return fabricInfo.map((info) => {
2570
1839
  return {
@@ -2578,12 +1847,6 @@ export class Matterbridge extends EventEmitter {
2578
1847
  };
2579
1848
  });
2580
1849
  }
2581
- /**
2582
- * Sanitizes the session information by converting bigint properties to strings because `res.json` doesn't support bigint.
2583
- *
2584
- * @param {SessionsBehavior.Session[]} sessions - The array of session information objects.
2585
- * @returns {SanitizedSession[]} An array of sanitized session information objects.
2586
- */
2587
1850
  sanitizeSessionInformation(sessions) {
2588
1851
  return sessions
2589
1852
  .filter((session) => session.isPeerActive)
@@ -2610,21 +1873,7 @@ export class Matterbridge extends EventEmitter {
2610
1873
  };
2611
1874
  });
2612
1875
  }
2613
- /**
2614
- * Sets the reachability of the specified aggregator node bridged devices and trigger.
2615
- *
2616
- * @param {Endpoint<AggregatorEndpoint>} aggregatorNode - The aggregator node to set the reachability for.
2617
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2618
- */
2619
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2620
1876
  async setAggregatorReachability(aggregatorNode, reachable) {
2621
- /*
2622
- for (const child of aggregatorNode.parts) {
2623
- this.log.debug(`Setting reachability of ${(child as unknown as MatterbridgeEndpoint)?.deviceName} to ${reachable}`);
2624
- await child.setStateOf(BridgedDeviceBasicInformationServer, { reachable });
2625
- child.act((agent) => child.eventsOf(BridgedDeviceBasicInformationServer).reachableChanged.emit({ reachableNewValue: true }, agent.context));
2626
- }
2627
- */
2628
1877
  }
2629
1878
  getVendorIdName = (vendorId) => {
2630
1879
  if (!vendorId)
@@ -2661,11 +1910,13 @@ export class Matterbridge extends EventEmitter {
2661
1910
  case 5264:
2662
1911
  vendorName = '(Shelly)';
2663
1912
  break;
1913
+ case 0x1488:
1914
+ vendorName = '(ShortcutLabsFlic)';
1915
+ break;
2664
1916
  case 65521:
2665
- vendorName = '(MatterServer)';
1917
+ vendorName = '(MatterTest)';
2666
1918
  break;
2667
1919
  }
2668
1920
  return vendorName;
2669
1921
  };
2670
1922
  }
2671
- //# sourceMappingURL=matterbridge.js.map