matterbridge 3.1.7 → 3.1.8-dev-20250725-d6e57e3

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 (247) hide show
  1. package/CHANGELOG.md +15 -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/dishwasher.js +3 -78
  9. package/dist/devices/evse.js +10 -74
  10. package/dist/devices/export.js +0 -2
  11. package/dist/devices/extractorHood.js +0 -42
  12. package/dist/devices/heatPump.js +2 -50
  13. package/dist/devices/laundryDryer.js +6 -83
  14. package/dist/devices/laundryWasher.js +7 -91
  15. package/dist/devices/roboticVacuumCleaner.js +7 -93
  16. package/dist/devices/solarPower.js +0 -38
  17. package/dist/devices/waterHeater.js +2 -82
  18. package/dist/dgram/coap.js +13 -126
  19. package/dist/dgram/dgram.js +2 -113
  20. package/dist/dgram/mb_coap.js +3 -41
  21. package/dist/dgram/mb_mdns.js +13 -51
  22. package/dist/dgram/mdns.js +137 -298
  23. package/dist/dgram/multicast.js +1 -60
  24. package/dist/dgram/unicast.js +0 -54
  25. package/dist/frontend.js +21 -435
  26. package/dist/globalMatterbridge.js +0 -47
  27. package/dist/helpers.js +0 -53
  28. package/dist/index.js +1 -30
  29. package/dist/logger/export.js +0 -1
  30. package/dist/matter/behaviors.js +0 -2
  31. package/dist/matter/clusters.js +0 -2
  32. package/dist/matter/devices.js +0 -2
  33. package/dist/matter/endpoints.js +0 -2
  34. package/dist/matter/export.js +0 -3
  35. package/dist/matter/types.js +0 -3
  36. package/dist/matterbridge.js +55 -811
  37. package/dist/matterbridgeAccessoryPlatform.js +0 -36
  38. package/dist/matterbridgeBehaviors.js +5 -65
  39. package/dist/matterbridgeDeviceTypes.js +15 -579
  40. package/dist/matterbridgeDynamicPlatform.js +0 -36
  41. package/dist/matterbridgeEndpoint.js +54 -1214
  42. package/dist/matterbridgeEndpointHelpers.js +12 -344
  43. package/dist/matterbridgePlatform.js +0 -233
  44. package/dist/matterbridgeTypes.js +0 -25
  45. package/dist/pluginManager.js +3 -249
  46. package/dist/shelly.js +7 -168
  47. package/dist/storage/export.js +0 -1
  48. package/dist/update.js +0 -54
  49. package/dist/utils/colorUtils.js +2 -263
  50. package/dist/utils/commandLine.js +0 -54
  51. package/dist/utils/copyDirectory.js +1 -38
  52. package/dist/utils/createDirectory.js +0 -33
  53. package/dist/utils/createZip.js +2 -47
  54. package/dist/utils/deepCopy.js +0 -39
  55. package/dist/utils/deepEqual.js +1 -72
  56. package/dist/utils/error.js +0 -41
  57. package/dist/utils/export.js +0 -1
  58. package/dist/utils/hex.js +0 -58
  59. package/dist/utils/isvalid.js +0 -101
  60. package/dist/utils/network.js +5 -81
  61. package/dist/utils/spawn.js +0 -40
  62. package/dist/utils/wait.js +9 -62
  63. package/npm-shrinkwrap.json +2 -2
  64. package/package.json +1 -2
  65. package/dist/cli.d.ts +0 -26
  66. package/dist/cli.d.ts.map +0 -1
  67. package/dist/cli.js.map +0 -1
  68. package/dist/cliEmitter.d.ts +0 -34
  69. package/dist/cliEmitter.d.ts.map +0 -1
  70. package/dist/cliEmitter.js.map +0 -1
  71. package/dist/clusters/export.d.ts +0 -2
  72. package/dist/clusters/export.d.ts.map +0 -1
  73. package/dist/clusters/export.js.map +0 -1
  74. package/dist/defaultConfigSchema.d.ts +0 -28
  75. package/dist/defaultConfigSchema.d.ts.map +0 -1
  76. package/dist/defaultConfigSchema.js.map +0 -1
  77. package/dist/deviceManager.d.ts +0 -112
  78. package/dist/deviceManager.d.ts.map +0 -1
  79. package/dist/deviceManager.js.map +0 -1
  80. package/dist/devices/batteryStorage.d.ts +0 -48
  81. package/dist/devices/batteryStorage.d.ts.map +0 -1
  82. package/dist/devices/batteryStorage.js.map +0 -1
  83. package/dist/devices/dishwasher.d.ts +0 -91
  84. package/dist/devices/dishwasher.d.ts.map +0 -1
  85. package/dist/devices/dishwasher.js.map +0 -1
  86. package/dist/devices/evse.d.ts +0 -75
  87. package/dist/devices/evse.d.ts.map +0 -1
  88. package/dist/devices/evse.js.map +0 -1
  89. package/dist/devices/export.d.ts +0 -11
  90. package/dist/devices/export.d.ts.map +0 -1
  91. package/dist/devices/export.js.map +0 -1
  92. package/dist/devices/extractorHood.d.ts +0 -46
  93. package/dist/devices/extractorHood.d.ts.map +0 -1
  94. package/dist/devices/extractorHood.js.map +0 -1
  95. package/dist/devices/heatPump.d.ts +0 -47
  96. package/dist/devices/heatPump.d.ts.map +0 -1
  97. package/dist/devices/heatPump.js.map +0 -1
  98. package/dist/devices/laundryDryer.d.ts +0 -87
  99. package/dist/devices/laundryDryer.d.ts.map +0 -1
  100. package/dist/devices/laundryDryer.js.map +0 -1
  101. package/dist/devices/laundryWasher.d.ts +0 -242
  102. package/dist/devices/laundryWasher.d.ts.map +0 -1
  103. package/dist/devices/laundryWasher.js.map +0 -1
  104. package/dist/devices/roboticVacuumCleaner.d.ts +0 -112
  105. package/dist/devices/roboticVacuumCleaner.d.ts.map +0 -1
  106. package/dist/devices/roboticVacuumCleaner.js.map +0 -1
  107. package/dist/devices/solarPower.d.ts +0 -40
  108. package/dist/devices/solarPower.d.ts.map +0 -1
  109. package/dist/devices/solarPower.js.map +0 -1
  110. package/dist/devices/waterHeater.d.ts +0 -111
  111. package/dist/devices/waterHeater.d.ts.map +0 -1
  112. package/dist/devices/waterHeater.js.map +0 -1
  113. package/dist/dgram/coap.d.ts +0 -205
  114. package/dist/dgram/coap.d.ts.map +0 -1
  115. package/dist/dgram/coap.js.map +0 -1
  116. package/dist/dgram/dgram.d.ts +0 -140
  117. package/dist/dgram/dgram.d.ts.map +0 -1
  118. package/dist/dgram/dgram.js.map +0 -1
  119. package/dist/dgram/mb_coap.d.ts +0 -24
  120. package/dist/dgram/mb_coap.d.ts.map +0 -1
  121. package/dist/dgram/mb_coap.js.map +0 -1
  122. package/dist/dgram/mb_mdns.d.ts +0 -24
  123. package/dist/dgram/mb_mdns.d.ts.map +0 -1
  124. package/dist/dgram/mb_mdns.js.map +0 -1
  125. package/dist/dgram/mdns.d.ts +0 -288
  126. package/dist/dgram/mdns.d.ts.map +0 -1
  127. package/dist/dgram/mdns.js.map +0 -1
  128. package/dist/dgram/multicast.d.ts +0 -65
  129. package/dist/dgram/multicast.d.ts.map +0 -1
  130. package/dist/dgram/multicast.js.map +0 -1
  131. package/dist/dgram/unicast.d.ts +0 -56
  132. package/dist/dgram/unicast.d.ts.map +0 -1
  133. package/dist/dgram/unicast.js.map +0 -1
  134. package/dist/frontend.d.ts +0 -304
  135. package/dist/frontend.d.ts.map +0 -1
  136. package/dist/frontend.js.map +0 -1
  137. package/dist/globalMatterbridge.d.ts +0 -59
  138. package/dist/globalMatterbridge.d.ts.map +0 -1
  139. package/dist/globalMatterbridge.js.map +0 -1
  140. package/dist/helpers.d.ts +0 -48
  141. package/dist/helpers.d.ts.map +0 -1
  142. package/dist/helpers.js.map +0 -1
  143. package/dist/index.d.ts +0 -33
  144. package/dist/index.d.ts.map +0 -1
  145. package/dist/index.js.map +0 -1
  146. package/dist/logger/export.d.ts +0 -2
  147. package/dist/logger/export.d.ts.map +0 -1
  148. package/dist/logger/export.js.map +0 -1
  149. package/dist/matter/behaviors.d.ts +0 -2
  150. package/dist/matter/behaviors.d.ts.map +0 -1
  151. package/dist/matter/behaviors.js.map +0 -1
  152. package/dist/matter/clusters.d.ts +0 -2
  153. package/dist/matter/clusters.d.ts.map +0 -1
  154. package/dist/matter/clusters.js.map +0 -1
  155. package/dist/matter/devices.d.ts +0 -2
  156. package/dist/matter/devices.d.ts.map +0 -1
  157. package/dist/matter/devices.js.map +0 -1
  158. package/dist/matter/endpoints.d.ts +0 -2
  159. package/dist/matter/endpoints.d.ts.map +0 -1
  160. package/dist/matter/endpoints.js.map +0 -1
  161. package/dist/matter/export.d.ts +0 -5
  162. package/dist/matter/export.d.ts.map +0 -1
  163. package/dist/matter/export.js.map +0 -1
  164. package/dist/matter/types.d.ts +0 -3
  165. package/dist/matter/types.d.ts.map +0 -1
  166. package/dist/matter/types.js.map +0 -1
  167. package/dist/matterbridge.d.ts +0 -463
  168. package/dist/matterbridge.d.ts.map +0 -1
  169. package/dist/matterbridge.js.map +0 -1
  170. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -42
  171. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  172. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  173. package/dist/matterbridgeBehaviors.d.ts +0 -1351
  174. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  175. package/dist/matterbridgeBehaviors.js.map +0 -1
  176. package/dist/matterbridgeDeviceTypes.d.ts +0 -709
  177. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  178. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  179. package/dist/matterbridgeDynamicPlatform.d.ts +0 -42
  180. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  181. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  182. package/dist/matterbridgeEndpoint.d.ts +0 -1348
  183. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  184. package/dist/matterbridgeEndpoint.js.map +0 -1
  185. package/dist/matterbridgeEndpointHelpers.d.ts +0 -406
  186. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  187. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  188. package/dist/matterbridgePlatform.d.ts +0 -310
  189. package/dist/matterbridgePlatform.d.ts.map +0 -1
  190. package/dist/matterbridgePlatform.js.map +0 -1
  191. package/dist/matterbridgeTypes.d.ts +0 -195
  192. package/dist/matterbridgeTypes.d.ts.map +0 -1
  193. package/dist/matterbridgeTypes.js.map +0 -1
  194. package/dist/pluginManager.d.ts +0 -270
  195. package/dist/pluginManager.d.ts.map +0 -1
  196. package/dist/pluginManager.js.map +0 -1
  197. package/dist/shelly.d.ts +0 -174
  198. package/dist/shelly.d.ts.map +0 -1
  199. package/dist/shelly.js.map +0 -1
  200. package/dist/storage/export.d.ts +0 -2
  201. package/dist/storage/export.d.ts.map +0 -1
  202. package/dist/storage/export.js.map +0 -1
  203. package/dist/update.d.ts +0 -59
  204. package/dist/update.d.ts.map +0 -1
  205. package/dist/update.js.map +0 -1
  206. package/dist/utils/colorUtils.d.ts +0 -117
  207. package/dist/utils/colorUtils.d.ts.map +0 -1
  208. package/dist/utils/colorUtils.js.map +0 -1
  209. package/dist/utils/commandLine.d.ts +0 -59
  210. package/dist/utils/commandLine.d.ts.map +0 -1
  211. package/dist/utils/commandLine.js.map +0 -1
  212. package/dist/utils/copyDirectory.d.ts +0 -33
  213. package/dist/utils/copyDirectory.d.ts.map +0 -1
  214. package/dist/utils/copyDirectory.js.map +0 -1
  215. package/dist/utils/createDirectory.d.ts +0 -34
  216. package/dist/utils/createDirectory.d.ts.map +0 -1
  217. package/dist/utils/createDirectory.js.map +0 -1
  218. package/dist/utils/createZip.d.ts +0 -39
  219. package/dist/utils/createZip.d.ts.map +0 -1
  220. package/dist/utils/createZip.js.map +0 -1
  221. package/dist/utils/deepCopy.d.ts +0 -32
  222. package/dist/utils/deepCopy.d.ts.map +0 -1
  223. package/dist/utils/deepCopy.js.map +0 -1
  224. package/dist/utils/deepEqual.d.ts +0 -54
  225. package/dist/utils/deepEqual.d.ts.map +0 -1
  226. package/dist/utils/deepEqual.js.map +0 -1
  227. package/dist/utils/error.d.ts +0 -44
  228. package/dist/utils/error.d.ts.map +0 -1
  229. package/dist/utils/error.js.map +0 -1
  230. package/dist/utils/export.d.ts +0 -12
  231. package/dist/utils/export.d.ts.map +0 -1
  232. package/dist/utils/export.js.map +0 -1
  233. package/dist/utils/hex.d.ts +0 -49
  234. package/dist/utils/hex.d.ts.map +0 -1
  235. package/dist/utils/hex.js.map +0 -1
  236. package/dist/utils/isvalid.d.ts +0 -103
  237. package/dist/utils/isvalid.d.ts.map +0 -1
  238. package/dist/utils/isvalid.js.map +0 -1
  239. package/dist/utils/network.d.ts +0 -74
  240. package/dist/utils/network.d.ts.map +0 -1
  241. package/dist/utils/network.js.map +0 -1
  242. package/dist/utils/spawn.d.ts +0 -33
  243. package/dist/utils/spawn.d.ts.map +0 -1
  244. package/dist/utils/spawn.js.map +0 -1
  245. package/dist/utils/wait.d.ts +0 -56
  246. package/dist/utils/wait.d.ts.map +0 -1
  247. 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, BLUE } from 'node-ansi-logger';
32
- // NodeStorage module
33
7
  import { NodeStorageManager } from 'node-persist-manager';
34
- // @matter
35
8
  import { DeviceTypeId, Endpoint, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageService, Environment, ServerNode, UINT32_MAX, UINT16_MAX, Crypto, } from '@matter/main';
36
9
  import { DeviceCommissioner, FabricAction, MdnsService, PaseClient } from '@matter/main/protocol';
37
10
  import { AggregatorEndpoint } from '@matter/main/endpoints';
38
11
  import { BasicInformationServer } from '@matter/main/behaviors/basic-information';
39
12
  import { BridgedDeviceBasicInformationServer } from '@matter/main/behaviors/bridged-device-basic-information';
40
- // Matterbridge
41
13
  import { getParameter, getIntParameter, hasParameter, copyDirectory, isValidString, parseVersionString, isValidNumber, createDirectory } from './utils/export.js';
42
14
  import { withTimeout, waiter, wait } from './utils/wait.js';
43
15
  import { dev, plg, typ } from './matterbridgeTypes.js';
@@ -47,9 +19,6 @@ import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
47
19
  import { bridge } from './matterbridgeDeviceTypes.js';
48
20
  import { Frontend } from './frontend.js';
49
21
  import { addVirtualDevices } from './helpers.js';
50
- /**
51
- * Represents the Matterbridge application.
52
- */
53
22
  export class Matterbridge extends EventEmitter {
54
23
  systemInformation = {
55
24
  interfaceName: '',
@@ -98,7 +67,7 @@ export class Matterbridge extends EventEmitter {
98
67
  shellySysUpdate: false,
99
68
  shellyMainUpdate: false,
100
69
  profile: getParameter('profile'),
101
- loggerLevel: "info" /* LogLevel.INFO */,
70
+ loggerLevel: "info",
102
71
  fileLogger: false,
103
72
  matterLoggerLevel: MatterLogLevel.INFO,
104
73
  matterFileLogger: false,
@@ -125,18 +94,15 @@ export class Matterbridge extends EventEmitter {
125
94
  profile = getParameter('profile');
126
95
  shutdown = false;
127
96
  failCountLimit = hasParameter('shelly') ? 600 : 120;
128
- // Matterbridge log files
129
- log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
97
+ log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
130
98
  matterbridgeLoggerFile = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
131
99
  matterLoggerFile = 'matter' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
132
100
  plugins = new PluginManager(this);
133
101
  devices = new DeviceManager(this);
134
102
  frontend = new Frontend(this);
135
- // Matterbridge storage
136
103
  nodeStorageName = 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
137
104
  nodeStorage;
138
105
  nodeContext;
139
- // Cleanup
140
106
  hasCleanupStarted = false;
141
107
  initialized = false;
142
108
  execRunningCount = 0;
@@ -151,23 +117,19 @@ export class Matterbridge extends EventEmitter {
151
117
  sigtermHandler;
152
118
  exceptionHandler;
153
119
  rejectionHandler;
154
- // Matter environment
155
120
  environment = Environment.default;
156
- // Matter storage
157
121
  matterStorageName = 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
158
122
  matterStorageService;
159
123
  matterStorageManager;
160
124
  matterbridgeContext;
161
125
  controllerContext;
162
- // Matter parameters
163
- mdnsInterface; // matter server node mdnsInterface: e.g. 'eth0' or 'wlan0' or 'WiFi'
164
- ipv4address; // matter server node listeningAddressIpv4
165
- ipv6address; // matter server node listeningAddressIpv6
166
- port; // first server node port
167
- passcode; // first server node passcode
168
- discriminator; // first server node discriminator
169
- certification; // device certification
170
- // Matter nodes
126
+ mdnsInterface;
127
+ ipv4address;
128
+ ipv6address;
129
+ port;
130
+ passcode;
131
+ discriminator;
132
+ certification;
171
133
  serverNode;
172
134
  aggregatorNode;
173
135
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
@@ -178,31 +140,15 @@ export class Matterbridge extends EventEmitter {
178
140
  aggregatorSerialNumber = getParameter('serialNumber');
179
141
  aggregatorUniqueId = getParameter('uniqueId');
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,105 +202,72 @@ 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 wait(pause, 'destroyInstance start', true);
284
- // Cleanup
285
207
  await this.cleanup('destroying instance...', false, timeout);
286
- // Close servers mdns service
287
208
  this.log.info(`Dispose ${servers.length} MdnsService...`);
288
209
  for (const server of servers) {
289
210
  await server.env.get(MdnsService)[Symbol.asyncDispose]();
290
211
  this.log.info(`Closed ${server.id} MdnsService`);
291
212
  }
292
- // Let any already‐queued microtasks run first
293
213
  await Promise.resolve();
294
- // Wait for the cleanup to finish
295
214
  await wait(pause, 'destroyInstance stop', true);
296
215
  }
297
- /**
298
- * Initializes the Matterbridge application.
299
- *
300
- * @remarks
301
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
302
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
303
- * node version, registers signal handlers, initializes storage, and parses the command line.
304
- *
305
- * @returns {Promise<void>} A Promise that resolves when the initialization is complete.
306
- */
307
216
  async initialize() {
308
- // Emit the initialize_started event
309
217
  this.emit('initialize_started');
310
- // Set the restart mode
311
218
  if (hasParameter('service'))
312
219
  this.restartMode = 'service';
313
220
  if (hasParameter('docker'))
314
221
  this.restartMode = 'docker';
315
- // Set the matterbridge home directory
316
222
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
317
223
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
318
224
  await createDirectory(this.homeDirectory, 'Matterbridge Home Directory', this.log);
319
- // Set the matterbridge directory
320
225
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
321
226
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
322
227
  await createDirectory(this.matterbridgeDirectory, 'Matterbridge Directory', this.log);
323
228
  await createDirectory(path.join(this.matterbridgeDirectory, 'certs'), 'Matterbridge Frontend Certificate Directory', this.log);
324
229
  await createDirectory(path.join(this.matterbridgeDirectory, 'uploads'), 'Matterbridge Frontend Uploads Directory', this.log);
325
- // Set the matterbridge plugin directory
326
230
  this.matterbridgePluginDirectory = path.join(this.homeDirectory, 'Matterbridge');
327
231
  this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
328
232
  await createDirectory(this.matterbridgePluginDirectory, 'Matterbridge Plugin Directory', this.log);
329
- // Set the matterbridge cert directory
330
233
  this.matterbridgeCertDirectory = path.join(this.homeDirectory, '.mattercert');
331
234
  this.matterbridgeInformation.matterbridgeCertDirectory = this.matterbridgeCertDirectory;
332
235
  await createDirectory(this.matterbridgeCertDirectory, 'Matterbridge Matter Certificate Directory', this.log);
333
- // Set the matterbridge root directory
334
236
  const { fileURLToPath } = await import('node:url');
335
237
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
336
238
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
337
239
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
338
- // Setup the matter environment
339
240
  this.environment.vars.set('log.level', MatterLogLevel.INFO);
340
241
  this.environment.vars.set('log.format', MatterLogFormat.ANSI);
341
242
  this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, this.matterStorageName));
342
243
  this.environment.vars.set('runtime.signals', false);
343
244
  this.environment.vars.set('runtime.exitcode', false);
344
- // Register process handlers
345
245
  this.registerProcessHandlers();
346
- // Initialize nodeStorage and nodeContext
347
246
  try {
348
247
  this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
349
248
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
350
249
  this.log.debug('Creating node storage context for matterbridge');
351
250
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
352
- // TODO: Remove this code when node-persist-manager is updated
353
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
354
251
  const keys = (await this.nodeStorage?.storage.keys());
355
252
  for (const key of keys) {
356
253
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
357
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
358
254
  await this.nodeStorage?.storage.get(key);
359
255
  }
360
256
  const storages = await this.nodeStorage.getStorageNames();
361
257
  for (const storage of storages) {
362
258
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
363
259
  const nodeContext = await this.nodeStorage?.createStorage(storage);
364
- // TODO: Remove this code when node-persist-manager is updated
365
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
366
260
  const keys = (await nodeContext?.storage.keys());
367
261
  keys.forEach(async (key) => {
368
262
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
369
263
  await nodeContext?.get(key);
370
264
  });
371
265
  }
372
- // Creating a backup of the node storage since it is not corrupted
373
266
  this.log.debug('Creating node storage backup...');
374
267
  await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
375
268
  this.log.debug('Created node storage backup');
376
269
  }
377
270
  catch (error) {
378
- // Restoring the backup of the node storage since it is corrupted
379
271
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
380
272
  if (hasParameter('norestore')) {
381
273
  this.log.fatal(`The matterbridge storage is corrupted. Found -norestore parameter: exiting...`);
@@ -389,20 +281,14 @@ export class Matterbridge extends EventEmitter {
389
281
  if (!this.nodeStorage || !this.nodeContext) {
390
282
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
391
283
  }
392
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
393
284
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
394
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
395
285
  this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode')) ?? PaseClient.generateRandomPasscode(this.environment.get(Crypto));
396
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
397
286
  this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator')) ?? PaseClient.generateRandomDiscriminator(this.environment.get(Crypto));
398
- // Certificate management
399
287
  const pairingFilePath = path.join(this.matterbridgeCertDirectory, 'pairing.json');
400
288
  try {
401
- // eslint-disable-next-line n/no-unsupported-features/node-builtins
402
289
  await fs.access(pairingFilePath, fs.constants.R_OK);
403
290
  const pairingFileContent = await fs.readFile(pairingFilePath, 'utf8');
404
291
  const pairingFileJson = JSON.parse(pairingFileContent);
405
- // Set the vendorId, vendorName, productId, productName, deviceType, serialNumber, uniqueId if they are present in the pairing file
406
292
  if (isValidNumber(pairingFileJson.vendorId)) {
407
293
  this.aggregatorVendorId = VendorId(pairingFileJson.vendorId);
408
294
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using vendorId ${CYAN}${this.aggregatorVendorId}${nf} from pairing file.`);
@@ -431,23 +317,18 @@ export class Matterbridge extends EventEmitter {
431
317
  this.aggregatorUniqueId = pairingFileJson.uniqueId;
432
318
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using uniqueId ${CYAN}${this.aggregatorUniqueId}${nf} from pairing file.`);
433
319
  }
434
- // Override the passcode and discriminator if they are present in the pairing file
435
320
  if (isValidNumber(pairingFileJson.passcode) && isValidNumber(pairingFileJson.discriminator)) {
436
321
  this.passcode = pairingFileJson.passcode;
437
322
  this.discriminator = pairingFileJson.discriminator;
438
323
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using passcode ${CYAN}${this.passcode}${nf} and discriminator ${CYAN}${this.discriminator}${nf} from pairing file.`);
439
324
  }
440
- // Set the certification for matter.js if it is present in the pairing file
441
325
  if (pairingFileJson.privateKey && pairingFileJson.certificate && pairingFileJson.intermediateCertificate && pairingFileJson.declaration) {
442
- const hexStringToUint8Array = (hexString) => {
443
- const matches = hexString.match(/.{1,2}/g);
444
- return matches ? new Uint8Array(matches.map((byte) => parseInt(byte, 16))) : new Uint8Array();
445
- };
326
+ const { hexToBuffer } = await import('./utils/hex.js');
446
327
  this.certification = {
447
- privateKey: hexStringToUint8Array(pairingFileJson.privateKey),
448
- certificate: hexStringToUint8Array(pairingFileJson.certificate),
449
- intermediateCertificate: hexStringToUint8Array(pairingFileJson.intermediateCertificate),
450
- declaration: hexStringToUint8Array(pairingFileJson.declaration),
328
+ privateKey: hexToBuffer(pairingFileJson.privateKey),
329
+ certificate: hexToBuffer(pairingFileJson.certificate),
330
+ intermediateCertificate: hexToBuffer(pairingFileJson.intermediateCertificate),
331
+ declaration: hexToBuffer(pairingFileJson.declaration),
451
332
  };
452
333
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using privateKey, certificate, intermediateCertificate and declaration from pairing file.`);
453
334
  }
@@ -455,44 +336,41 @@ export class Matterbridge extends EventEmitter {
455
336
  catch (error) {
456
337
  this.log.debug(`Pairing file ${CYAN}${pairingFilePath}${db} not found: ${error instanceof Error ? error.message : error}`);
457
338
  }
458
- // Store the passcode, discriminator and port in the node context
459
339
  await this.nodeContext.set('matterport', this.port);
460
340
  await this.nodeContext.set('matterpasscode', this.passcode);
461
341
  await this.nodeContext.set('matterdiscriminator', this.discriminator);
462
342
  this.log.debug(`Initializing server node for Matterbridge on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
463
- // Set matterbridge logger level (context: matterbridgeLogLevel)
464
343
  if (hasParameter('logger')) {
465
344
  const level = getParameter('logger');
466
345
  if (level === 'debug') {
467
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
346
+ this.log.logLevel = "debug";
468
347
  }
469
348
  else if (level === 'info') {
470
- this.log.logLevel = "info" /* LogLevel.INFO */;
349
+ this.log.logLevel = "info";
471
350
  }
472
351
  else if (level === 'notice') {
473
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
352
+ this.log.logLevel = "notice";
474
353
  }
475
354
  else if (level === 'warn') {
476
- this.log.logLevel = "warn" /* LogLevel.WARN */;
355
+ this.log.logLevel = "warn";
477
356
  }
478
357
  else if (level === 'error') {
479
- this.log.logLevel = "error" /* LogLevel.ERROR */;
358
+ this.log.logLevel = "error";
480
359
  }
481
360
  else if (level === 'fatal') {
482
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
361
+ this.log.logLevel = "fatal";
483
362
  }
484
363
  else {
485
364
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
486
- this.log.logLevel = "info" /* LogLevel.INFO */;
365
+ this.log.logLevel = "info";
487
366
  }
488
367
  }
489
368
  else {
490
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.matterbridgeInformation.shellyBoard ? "notice" /* LogLevel.NOTICE */ : "info" /* LogLevel.INFO */);
369
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.matterbridgeInformation.shellyBoard ? "notice" : "info");
491
370
  }
492
371
  this.frontend.logLevel = this.log.logLevel;
493
372
  MatterbridgeEndpoint.logLevel = this.log.logLevel;
494
373
  this.matterbridgeInformation.loggerLevel = this.log.logLevel;
495
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
496
374
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
497
375
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbridgeLoggerFile), this.log.logLevel, true);
498
376
  this.matterbridgeInformation.fileLogger = true;
@@ -501,7 +379,6 @@ export class Matterbridge extends EventEmitter {
501
379
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
502
380
  if (this.profile !== undefined)
503
381
  this.log.debug(`Matterbridge profile: ${this.profile}.`);
504
- // Set matter.js logger level, format and logger (context: matterLogLevel)
505
382
  if (hasParameter('matterlogger')) {
506
383
  const level = getParameter('matterlogger');
507
384
  if (level === 'debug') {
@@ -532,9 +409,7 @@ export class Matterbridge extends EventEmitter {
532
409
  }
533
410
  Logger.format = MatterLogFormat.ANSI;
534
411
  Logger.setLogger('default', this.createMatterLogger());
535
- // Logger.destinations.default.write = this.createMatterLogger();
536
412
  this.matterbridgeInformation.matterLoggerLevel = Logger.level;
537
- // Create the file logger for matter.js (context: matterFileLog)
538
413
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
539
414
  this.matterbridgeInformation.matterFileLogger = true;
540
415
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
@@ -543,9 +418,7 @@ export class Matterbridge extends EventEmitter {
543
418
  });
544
419
  }
545
420
  this.log.debug(`Matter logLevel: ${Logger.level} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
546
- // Log network interfaces
547
421
  const networkInterfaces = os.networkInterfaces();
548
- // console.log(`Network interfaces:`, networkInterfaces);
549
422
  const availableAddresses = Object.entries(networkInterfaces);
550
423
  const availableInterfaces = Object.keys(networkInterfaces);
551
424
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -557,7 +430,6 @@ export class Matterbridge extends EventEmitter {
557
430
  });
558
431
  }
559
432
  }
560
- // Set the interface to use for matter server node mdnsInterface
561
433
  if (hasParameter('mdnsinterface')) {
562
434
  this.mdnsInterface = getParameter('mdnsinterface');
563
435
  }
@@ -566,7 +438,6 @@ export class Matterbridge extends EventEmitter {
566
438
  if (this.mdnsInterface === '')
567
439
  this.mdnsInterface = undefined;
568
440
  }
569
- // Validate mdnsInterface
570
441
  if (this.mdnsInterface) {
571
442
  if (!availableInterfaces.includes(this.mdnsInterface)) {
572
443
  this.log.error(`Invalid mdnsinterface: ${this.mdnsInterface}. Available interfaces are: ${availableInterfaces.join(', ')}. Using all available interfaces.`);
@@ -579,7 +450,6 @@ export class Matterbridge extends EventEmitter {
579
450
  }
580
451
  if (this.mdnsInterface)
581
452
  this.environment.vars.set('mdns.networkInterface', this.mdnsInterface);
582
- // Set the listeningAddressIpv4 for the matter commissioning server
583
453
  if (hasParameter('ipv4address')) {
584
454
  this.ipv4address = getParameter('ipv4address');
585
455
  }
@@ -588,7 +458,6 @@ export class Matterbridge extends EventEmitter {
588
458
  if (this.ipv4address === '')
589
459
  this.ipv4address = undefined;
590
460
  }
591
- // Validate ipv4address
592
461
  if (this.ipv4address) {
593
462
  let isValid = false;
594
463
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -604,7 +473,6 @@ export class Matterbridge extends EventEmitter {
604
473
  await this.nodeContext.remove('matteripv4address');
605
474
  }
606
475
  }
607
- // Set the listeningAddressIpv6 for the matter commissioning server
608
476
  if (hasParameter('ipv6address')) {
609
477
  this.ipv6address = getParameter('ipv6address');
610
478
  }
@@ -613,7 +481,6 @@ export class Matterbridge extends EventEmitter {
613
481
  if (this.ipv6address === '')
614
482
  this.ipv6address = undefined;
615
483
  }
616
- // Validate ipv6address
617
484
  if (this.ipv6address) {
618
485
  let isValid = false;
619
486
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -622,7 +489,6 @@ export class Matterbridge extends EventEmitter {
622
489
  isValid = true;
623
490
  break;
624
491
  }
625
- /* istanbul ignore next */
626
492
  if (ifaces && ifaces.find((iface) => iface.scopeid && iface.scopeid > 0 && iface.address + '%' + (process.platform === 'win32' ? iface.scopeid : ifaceName) === this.ipv6address)) {
627
493
  this.log.info(`Using ipv6address ${CYAN}${this.ipv6address}${nf} on interface ${CYAN}${ifaceName}${nf} for the Matter server node.`);
628
494
  isValid = true;
@@ -635,7 +501,6 @@ export class Matterbridge extends EventEmitter {
635
501
  await this.nodeContext.remove('matteripv6address');
636
502
  }
637
503
  }
638
- // Initialize the virtual mode
639
504
  if (hasParameter('novirtual')) {
640
505
  this.matterbridgeInformation.virtualMode = 'disabled';
641
506
  await this.nodeContext.set('virtualmode', 'disabled');
@@ -644,17 +509,12 @@ export class Matterbridge extends EventEmitter {
644
509
  this.matterbridgeInformation.virtualMode = (await this.nodeContext.get('virtualmode', 'outlet'));
645
510
  }
646
511
  this.log.debug(`Virtual mode ${this.matterbridgeInformation.virtualMode}.`);
647
- // Initialize PluginManager
648
512
  this.plugins.logLevel = this.log.logLevel;
649
513
  await this.plugins.loadFromStorage();
650
- // Initialize DeviceManager
651
514
  this.devices.logLevel = this.log.logLevel;
652
- // Get the plugins from node storage and create the plugins node storage contexts
653
515
  for (const plugin of this.plugins) {
654
516
  const packageJson = await this.plugins.parse(plugin);
655
517
  if (packageJson === null && !hasParameter('add') && !hasParameter('remove') && !hasParameter('enable') && !hasParameter('disable') && !hasParameter('reset') && !hasParameter('factoryreset')) {
656
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
657
- // We don't do this when the add and other parameters are set because we shut down the process after adding the plugin
658
518
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
659
519
  try {
660
520
  const { spawnCommand } = await import('./utils/spawn.js');
@@ -677,7 +537,6 @@ export class Matterbridge extends EventEmitter {
677
537
  await plugin.nodeContext.set('description', plugin.description);
678
538
  await plugin.nodeContext.set('author', plugin.author);
679
539
  }
680
- // Log system info and create .matterbridge directory
681
540
  await this.logNodeAndSystemInfo();
682
541
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
683
542
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -685,7 +544,6 @@ export class Matterbridge extends EventEmitter {
685
544
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
686
545
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
687
546
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
688
- // Check node version and throw error
689
547
  const minNodeVersion = 18;
690
548
  const nodeVersion = process.versions.node;
691
549
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -693,18 +551,10 @@ export class Matterbridge extends EventEmitter {
693
551
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
694
552
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
695
553
  }
696
- // Parse command line
697
554
  await this.parseCommandLine();
698
- // Emit the initialize_completed event
699
555
  this.emit('initialize_completed');
700
556
  this.initialized = true;
701
557
  }
702
- /**
703
- * Parses the command line arguments and performs the corresponding actions.
704
- *
705
- * @private
706
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
707
- */
708
558
  async parseCommandLine() {
709
559
  if (hasParameter('help')) {
710
560
  this.log.info(`\nUsage: matterbridge [options]\n
@@ -766,19 +616,6 @@ export class Matterbridge extends EventEmitter {
766
616
  }
767
617
  index++;
768
618
  }
769
- /*
770
- const serializedRegisteredDevices = await this.nodeContext?.get<SerializedMatterbridgeEndpoint[]>('devices', []);
771
- this.log.info(`│ Registered devices (${serializedRegisteredDevices?.length})`);
772
- serializedRegisteredDevices?.forEach((device, index) => {
773
- if (index !== serializedRegisteredDevices.length - 1) {
774
- this.log.info(`├─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
775
- this.log.info(`│ └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
776
- } else {
777
- this.log.info(`└─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
778
- this.log.info(` └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
779
- }
780
- });
781
- */
782
619
  this.shutdown = true;
783
620
  return;
784
621
  }
@@ -828,7 +665,6 @@ export class Matterbridge extends EventEmitter {
828
665
  this.shutdown = true;
829
666
  return;
830
667
  }
831
- // Start the matter storage and create the matterbridge context
832
668
  try {
833
669
  await this.startMatterStorage();
834
670
  if (this.aggregatorSerialNumber && this.aggregatorUniqueId && this.matterStorageService) {
@@ -845,21 +681,18 @@ export class Matterbridge extends EventEmitter {
845
681
  this.log.fatal(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
846
682
  throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
847
683
  }
848
- // Clear the matterbridge context if the reset parameter is set
849
684
  if (hasParameter('reset') && getParameter('reset') === undefined) {
850
685
  this.initialized = true;
851
686
  await this.shutdownProcessAndReset();
852
687
  this.shutdown = true;
853
688
  return;
854
689
  }
855
- // Clear matterbridge plugin context if the reset parameter is set
856
690
  if (hasParameter('reset') && getParameter('reset') !== undefined) {
857
691
  this.log.debug(`Reset plugin ${getParameter('reset')}`);
858
692
  const plugin = this.plugins.get(getParameter('reset'));
859
693
  if (plugin) {
860
694
  const matterStorageManager = await this.matterStorageService?.open(plugin.name);
861
695
  if (!matterStorageManager) {
862
- /* istanbul ignore next */
863
696
  this.log.error(`Plugin ${plg}${plugin.name}${er} storageManager not found`);
864
697
  }
865
698
  else {
@@ -878,39 +711,32 @@ export class Matterbridge extends EventEmitter {
878
711
  this.shutdown = true;
879
712
  return;
880
713
  }
881
- // Initialize frontend
882
714
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
883
715
  await this.frontend.start(getIntParameter('frontend'));
884
- // Check in 30 seconds the latest and dev versions of matterbridge and the plugins
885
716
  clearTimeout(this.checkUpdateTimeout);
886
717
  this.checkUpdateTimeout = setTimeout(async () => {
887
718
  const { checkUpdates } = await import('./update.js');
888
719
  checkUpdates(this);
889
720
  }, 30 * 1000).unref();
890
- // Check each 12 hours the latest and dev versions of matterbridge and the plugins
891
721
  clearInterval(this.checkUpdateInterval);
892
722
  this.checkUpdateInterval = setInterval(async () => {
893
723
  const { checkUpdates } = await import('./update.js');
894
724
  checkUpdates(this);
895
725
  }, 12 * 60 * 60 * 1000).unref();
896
- // Start the matterbridge in mode test
897
726
  if (hasParameter('test')) {
898
727
  this.bridgeMode = 'bridge';
899
728
  MatterbridgeEndpoint.bridgeMode = 'bridge';
900
729
  return;
901
730
  }
902
- // Start the matterbridge in mode controller
903
731
  if (hasParameter('controller')) {
904
732
  this.bridgeMode = 'controller';
905
733
  await this.startController();
906
734
  return;
907
735
  }
908
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
909
736
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
910
737
  this.log.info('Setting default matterbridge start mode to bridge');
911
738
  await this.nodeContext?.set('bridgeMode', 'bridge');
912
739
  }
913
- // Start matterbridge in bridge mode
914
740
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
915
741
  this.bridgeMode = 'bridge';
916
742
  MatterbridgeEndpoint.bridgeMode = 'bridge';
@@ -918,7 +744,6 @@ export class Matterbridge extends EventEmitter {
918
744
  await this.startBridge();
919
745
  return;
920
746
  }
921
- // Start matterbridge in childbridge mode
922
747
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
923
748
  this.bridgeMode = 'childbridge';
924
749
  MatterbridgeEndpoint.bridgeMode = 'childbridge';
@@ -927,20 +752,10 @@ export class Matterbridge extends EventEmitter {
927
752
  return;
928
753
  }
929
754
  }
930
- /**
931
- * Asynchronously loads and starts the registered plugins.
932
- *
933
- * This method is responsible for initializing and starting all enabled plugins.
934
- * It ensures that each plugin is properly loaded and started before the bridge starts.
935
- *
936
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
937
- */
938
755
  async startPlugins() {
939
- // Check, load and start the plugins
940
756
  for (const plugin of this.plugins) {
941
757
  plugin.configJson = await this.plugins.loadConfig(plugin);
942
758
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
943
- // Check if the plugin is available
944
759
  if (!(await this.plugins.resolve(plugin.path))) {
945
760
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
946
761
  plugin.enabled = false;
@@ -958,14 +773,10 @@ export class Matterbridge extends EventEmitter {
958
773
  plugin.configured = false;
959
774
  plugin.registeredDevices = undefined;
960
775
  plugin.addedDevices = undefined;
961
- this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
776
+ this.plugins.load(plugin, true, 'Matterbridge is starting');
962
777
  }
963
778
  this.frontend.wssSendRefreshRequired('plugins');
964
779
  }
965
- /**
966
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
967
- * When either of these signals are received, the cleanup method is called with an appropriate message.
968
- */
969
780
  registerProcessHandlers() {
970
781
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
971
782
  process.removeAllListeners('uncaughtException');
@@ -992,9 +803,6 @@ export class Matterbridge extends EventEmitter {
992
803
  };
993
804
  process.on('SIGTERM', this.sigtermHandler);
994
805
  }
995
- /**
996
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
997
- */
998
806
  deregisterProcessHandlers() {
999
807
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
1000
808
  if (this.exceptionHandler)
@@ -1011,17 +819,12 @@ export class Matterbridge extends EventEmitter {
1011
819
  process.off('SIGTERM', this.sigtermHandler);
1012
820
  this.sigtermHandler = undefined;
1013
821
  }
1014
- /**
1015
- * Logs the node and system information.
1016
- */
1017
822
  async logNodeAndSystemInfo() {
1018
- // IP address information
1019
823
  const networkInterfaces = os.networkInterfaces();
1020
824
  this.systemInformation.interfaceName = '';
1021
825
  this.systemInformation.ipv4Address = '';
1022
826
  this.systemInformation.ipv6Address = '';
1023
827
  for (const [interfaceName, interfaceDetails] of Object.entries(networkInterfaces)) {
1024
- // this.log.debug(`Checking interface: '${interfaceName}' for '${this.mdnsInterface}'`);
1025
828
  if (this.mdnsInterface && interfaceName !== this.mdnsInterface)
1026
829
  continue;
1027
830
  if (!interfaceDetails) {
@@ -1047,22 +850,19 @@ export class Matterbridge extends EventEmitter {
1047
850
  break;
1048
851
  }
1049
852
  }
1050
- // Node information
1051
853
  this.systemInformation.nodeVersion = process.versions.node;
1052
854
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
1053
855
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
1054
856
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
1055
- // Host system information
1056
857
  this.systemInformation.hostname = os.hostname();
1057
858
  this.systemInformation.user = os.userInfo().username;
1058
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
1059
- this.systemInformation.osRelease = os.release(); // Kernel version
1060
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
1061
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
1062
- this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
1063
- this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
1064
- this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours'; // Convert to hours
1065
- // Log the system information
859
+ this.systemInformation.osType = os.type();
860
+ this.systemInformation.osRelease = os.release();
861
+ this.systemInformation.osPlatform = os.platform();
862
+ this.systemInformation.osArch = os.arch();
863
+ this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
864
+ this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
865
+ this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours';
1066
866
  this.log.debug('Host System Information:');
1067
867
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
1068
868
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -1078,17 +878,14 @@ export class Matterbridge extends EventEmitter {
1078
878
  this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
1079
879
  this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
1080
880
  this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
1081
- // Log directories
1082
881
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
1083
882
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
1084
883
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
1085
884
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
1086
885
  this.log.debug(`Matterbridge Matter Certificate Directory: ${this.matterbridgeCertDirectory}`);
1087
- // Global node_modules directory
1088
886
  if (this.nodeContext)
1089
887
  this.globalModulesDirectory = this.matterbridgeInformation.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
1090
888
  if (this.globalModulesDirectory === '') {
1091
- // First run of Matterbridge so the node storage is empty
1092
889
  try {
1093
890
  const { getGlobalNodeModules } = await import('./utils/network.js');
1094
891
  this.execRunningCount++;
@@ -1098,87 +895,55 @@ export class Matterbridge extends EventEmitter {
1098
895
  await this.nodeContext?.set('globalModulesDirectory', this.globalModulesDirectory);
1099
896
  }
1100
897
  catch (error) {
1101
- // istanbul ignore next
1102
898
  this.log.error(`Error getting global node_modules directory: ${error}`);
1103
899
  }
1104
900
  }
1105
901
  else
1106
902
  this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
1107
- /* removed cause is too expensive for the shelly board and not really needed. Why should the globalModulesDirectory change?
1108
- else {
1109
- this.getGlobalNodeModules()
1110
- .then(async (globalModulesDirectory) => {
1111
- this.globalModulesDirectory = globalModulesDirectory;
1112
- this.matterbridgeInformation.globalModulesDirectory = this.globalModulesDirectory;
1113
- this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
1114
- await this.nodeContext?.set<string>('globalModulesDirectory', this.globalModulesDirectory);
1115
- })
1116
- .catch((error) => {
1117
- this.log.error(`Error getting global node_modules directory: ${error}`);
1118
- });
1119
- }*/
1120
- // Matterbridge version
1121
903
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
1122
904
  this.matterbridgeVersion = this.matterbridgeLatestVersion = this.matterbridgeDevVersion = packageJson.version;
1123
905
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeInformation.matterbridgeLatestVersion = this.matterbridgeInformation.matterbridgeDevVersion = packageJson.version;
1124
906
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
1125
- // Matterbridge latest version (will be set in the checkUpdate function)
1126
907
  if (this.nodeContext)
1127
908
  this.matterbridgeLatestVersion = this.matterbridgeInformation.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', this.matterbridgeVersion);
1128
909
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
1129
- // Matterbridge dev version (will be set in the checkUpdate function)
1130
910
  if (this.nodeContext)
1131
911
  this.matterbridgeDevVersion = this.matterbridgeInformation.matterbridgeDevVersion = await this.nodeContext.get('matterbridgeDevVersion', this.matterbridgeVersion);
1132
912
  this.log.debug(`Matterbridge Dev Version: ${this.matterbridgeDevVersion}`);
1133
- // Current working directory
1134
913
  const currentDir = process.cwd();
1135
914
  this.log.debug(`Current Working Directory: ${currentDir}`);
1136
- // Command line arguments (excluding 'node' and the script name)
1137
915
  const cmdArgs = process.argv.slice(2).join(' ');
1138
916
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
1139
917
  }
1140
- /**
1141
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
1142
- *
1143
- * @returns {Function} The MatterLogger function.
1144
- */
1145
918
  createMatterLogger() {
1146
- const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
919
+ const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
1147
920
  return (level, formattedLog) => {
1148
921
  const logger = formattedLog.slice(44, 44 + 20).trim();
1149
922
  const message = formattedLog.slice(65);
1150
923
  matterLogger.logName = logger;
1151
924
  switch (level) {
1152
925
  case MatterLogLevel.DEBUG:
1153
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
926
+ matterLogger.log("debug", message);
1154
927
  break;
1155
928
  case MatterLogLevel.INFO:
1156
- matterLogger.log("info" /* LogLevel.INFO */, message);
929
+ matterLogger.log("info", message);
1157
930
  break;
1158
931
  case MatterLogLevel.NOTICE:
1159
- matterLogger.log("notice" /* LogLevel.NOTICE */, message);
932
+ matterLogger.log("notice", message);
1160
933
  break;
1161
934
  case MatterLogLevel.WARN:
1162
- matterLogger.log("warn" /* LogLevel.WARN */, message);
935
+ matterLogger.log("warn", message);
1163
936
  break;
1164
937
  case MatterLogLevel.ERROR:
1165
- matterLogger.log("error" /* LogLevel.ERROR */, message);
938
+ matterLogger.log("error", message);
1166
939
  break;
1167
940
  case MatterLogLevel.FATAL:
1168
- matterLogger.log("fatal" /* LogLevel.FATAL */, message);
941
+ matterLogger.log("fatal", message);
1169
942
  break;
1170
943
  }
1171
944
  };
1172
945
  }
1173
- /**
1174
- * Creates a Matter File Logger.
1175
- *
1176
- * @param {string} filePath - The path to the log file.
1177
- * @param {boolean} [unlink] - Whether to unlink the log file before creating a new one.
1178
- * @returns {Function} - A function that logs formatted messages to the log file.
1179
- */
1180
946
  async createMatterFileLogger(filePath, unlink = false) {
1181
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1182
947
  let fileSize = 0;
1183
948
  if (unlink) {
1184
949
  try {
@@ -1189,12 +954,10 @@ export class Matterbridge extends EventEmitter {
1189
954
  }
1190
955
  }
1191
956
  return async (level, formattedLog) => {
1192
- /* istanbul ignore if */
1193
957
  if (fileSize > 100000000) {
1194
- return; // Stop logging if the file size is greater than 100MB
958
+ return;
1195
959
  }
1196
960
  fileSize += formattedLog.length;
1197
- /* istanbul ignore if */
1198
961
  if (fileSize > 100000000) {
1199
962
  await fs.appendFile(filePath, `Logging on file has been stopped because the file size is greater than 100MB.` + os.EOL);
1200
963
  return;
@@ -1227,27 +990,12 @@ export class Matterbridge extends EventEmitter {
1227
990
  }
1228
991
  };
1229
992
  }
1230
- /**
1231
- * Restarts the process by exiting the current instance and loading a new instance (/api/restart).
1232
- *
1233
- * @returns {Promise<void>} A promise that resolves when the restart is completed.
1234
- */
1235
993
  async restartProcess() {
1236
994
  await this.cleanup('restarting...', true);
1237
995
  }
1238
- /**
1239
- * Shut down the process (/api/shutdown).
1240
- *
1241
- * @returns {Promise<void>} A promise that resolves when the shutdown is completed.
1242
- */
1243
996
  async shutdownProcess() {
1244
997
  await this.cleanup('shutting down...', false);
1245
998
  }
1246
- /**
1247
- * Update matterbridge and shut down the process (virtual device 'Update Matterbridge').
1248
- *
1249
- * @returns {Promise<void>} A promise that resolves when the update is completed.
1250
- */
1251
999
  async updateProcess() {
1252
1000
  this.log.info('Updating matterbridge...');
1253
1001
  try {
@@ -1261,13 +1009,6 @@ export class Matterbridge extends EventEmitter {
1261
1009
  this.frontend.wssSendRestartRequired();
1262
1010
  await this.cleanup('updating...', false);
1263
1011
  }
1264
- /**
1265
- * Unregister all devices and shut down the process (/api/unregister).
1266
- *
1267
- * @param {number} [timeout] - The timeout duration to wait for the message exchange to complete in milliseconds. Default is 1000.
1268
- *
1269
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1270
- */
1271
1012
  async unregisterAndShutdownProcess(timeout = 1000) {
1272
1013
  this.log.info('Unregistering all devices and shutting down...');
1273
1014
  for (const plugin of this.plugins.array()) {
@@ -1281,71 +1022,46 @@ export class Matterbridge extends EventEmitter {
1281
1022
  await this.removeAllBridgedEndpoints(plugin.name, 100);
1282
1023
  }
1283
1024
  this.log.debug('Waiting for the MessageExchange to finish...');
1284
- await wait(timeout); // Wait for MessageExchange to finish
1025
+ await wait(timeout);
1285
1026
  this.log.debug('Cleaning up and shutting down...');
1286
1027
  await this.cleanup('unregistered all devices and shutting down...', false, timeout);
1287
1028
  }
1288
- /**
1289
- * Reset commissioning and shut down the process (/api/reset).
1290
- *
1291
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1292
- */
1293
1029
  async shutdownProcessAndReset() {
1294
1030
  await this.cleanup('shutting down with reset...', false);
1295
1031
  }
1296
- /**
1297
- * Factory reset and shut down the process (/api/factory-reset).
1298
- *
1299
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1300
- */
1301
1032
  async shutdownProcessAndFactoryReset() {
1302
1033
  await this.cleanup('shutting down with factory reset...', false);
1303
1034
  }
1304
- /**
1305
- * Cleans up the Matterbridge instance.
1306
- *
1307
- * @param {string} message - The cleanup message.
1308
- * @param {boolean} [restart] - Indicates whether to restart the instance after cleanup. Default is `false`.
1309
- * @param {number} [timeout] - The timeout duration to wait for the message exchange to complete in milliseconds. Default is 1000.
1310
- *
1311
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1312
- */
1313
1035
  async cleanup(message, restart = false, timeout = 1000) {
1314
1036
  if (this.initialized && !this.hasCleanupStarted) {
1315
1037
  this.emit('cleanup_started');
1316
1038
  this.hasCleanupStarted = true;
1317
1039
  this.log.info(message);
1318
- // Clear the start matter interval
1319
1040
  if (this.startMatterInterval) {
1320
1041
  clearInterval(this.startMatterInterval);
1321
1042
  this.startMatterInterval = undefined;
1322
1043
  this.log.debug('Start matter interval cleared');
1323
1044
  }
1324
- // Clear the check update timeout
1325
1045
  if (this.checkUpdateTimeout) {
1326
1046
  clearTimeout(this.checkUpdateTimeout);
1327
1047
  this.checkUpdateTimeout = undefined;
1328
1048
  this.log.debug('Check update timeout cleared');
1329
1049
  }
1330
- // Clear the check update interval
1331
1050
  if (this.checkUpdateInterval) {
1332
1051
  clearInterval(this.checkUpdateInterval);
1333
1052
  this.checkUpdateInterval = undefined;
1334
1053
  this.log.debug('Check update interval cleared');
1335
1054
  }
1336
- // Clear the configure timeout
1337
1055
  if (this.configureTimeout) {
1338
1056
  clearTimeout(this.configureTimeout);
1339
1057
  this.configureTimeout = undefined;
1340
1058
  this.log.debug('Matterbridge configure timeout cleared');
1341
1059
  }
1342
- // Clear the reachability timeout
1343
1060
  if (this.reachabilityTimeout) {
1344
1061
  clearTimeout(this.reachabilityTimeout);
1345
1062
  this.reachabilityTimeout = undefined;
1346
1063
  this.log.debug('Matterbridge reachability timeout cleared');
1347
1064
  }
1348
- // Call the shutdown method of each plugin and clear the plugins reachability timeout
1349
1065
  for (const plugin of this.plugins) {
1350
1066
  if (!plugin.enabled || plugin.error)
1351
1067
  continue;
@@ -1356,7 +1072,6 @@ export class Matterbridge extends EventEmitter {
1356
1072
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1357
1073
  }
1358
1074
  }
1359
- // Stop matter server nodes
1360
1075
  this.log.notice(`Stopping matter server nodes in ${this.bridgeMode} mode...`);
1361
1076
  this.log.debug('Waiting for the MessageExchange to finish...');
1362
1077
  await wait(timeout, 'Waiting for the MessageExchange to finish...', true);
@@ -1381,7 +1096,6 @@ export class Matterbridge extends EventEmitter {
1381
1096
  }
1382
1097
  }
1383
1098
  this.log.notice('Stopped matter server nodes');
1384
- // Matter commisioning reset
1385
1099
  if (message === 'shutting down with reset...') {
1386
1100
  this.log.info('Resetting Matterbridge commissioning information...');
1387
1101
  await this.matterStorageManager?.createContext('events')?.clearAll();
@@ -1391,7 +1105,6 @@ export class Matterbridge extends EventEmitter {
1391
1105
  await this.matterbridgeContext?.clearAll();
1392
1106
  this.log.info('Matter storage reset done! Remove the bridge from the controller.');
1393
1107
  }
1394
- // Unregister all devices
1395
1108
  if (message === 'unregistered all devices and shutting down...') {
1396
1109
  if (this.bridgeMode === 'bridge') {
1397
1110
  await this.matterStorageManager?.createContext('root')?.createContext('parts')?.createContext('Matterbridge')?.createContext('parts')?.clearAll();
@@ -1409,36 +1122,18 @@ export class Matterbridge extends EventEmitter {
1409
1122
  }
1410
1123
  this.log.info('Matter storage reset done!');
1411
1124
  }
1412
- // Stop matter storage
1413
1125
  await this.stopMatterStorage();
1414
- // Stop the frontend
1415
1126
  await this.frontend.stop();
1416
- // Remove the matterfilelogger
1417
1127
  try {
1418
1128
  Logger.removeLogger('matterfilelogger');
1419
1129
  }
1420
1130
  catch (error) {
1421
1131
  this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${db}: ${error instanceof Error ? error.message : String(error)}`);
1422
1132
  }
1423
- // Close the matterbridge node storage and context
1424
1133
  if (this.nodeStorage && this.nodeContext) {
1425
- /*
1426
- TODO: Implement serialization of registered devices in edge mode
1427
- this.log.info('Saving registered devices...');
1428
- const serializedRegisteredDevices: SerializedMatterbridgeEndpoint[] = [];
1429
- this.devices.forEach(async (device) => {
1430
- const serializedMatterbridgeDevice = MatterbridgeEndpoint.serialize(device);
1431
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1432
- if (serializedMatterbridgeDevice) serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1433
- });
1434
- await this.nodeContext.set<SerializedMatterbridgeEndpoint[]>('devices', serializedRegisteredDevices);
1435
- this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1436
- */
1437
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1438
1134
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1439
1135
  await this.nodeContext.close();
1440
1136
  this.nodeContext = undefined;
1441
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1442
1137
  for (const plugin of this.plugins) {
1443
1138
  if (plugin.nodeContext) {
1444
1139
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1455,10 +1150,8 @@ export class Matterbridge extends EventEmitter {
1455
1150
  }
1456
1151
  this.plugins.clear();
1457
1152
  this.devices.clear();
1458
- // Factory reset
1459
1153
  if (message === 'shutting down with factory reset...') {
1460
1154
  try {
1461
- // Delete matter storage directory with its subdirectories and backup
1462
1155
  const dir = path.join(this.matterbridgeDirectory, this.matterStorageName);
1463
1156
  this.log.info(`Removing matter storage directory: ${dir}`);
1464
1157
  await fs.rm(dir, { recursive: true });
@@ -1467,13 +1160,11 @@ export class Matterbridge extends EventEmitter {
1467
1160
  await fs.rm(backup, { recursive: true });
1468
1161
  }
1469
1162
  catch (error) {
1470
- // istanbul ignore next if
1471
1163
  if (error instanceof Error && error.code !== 'ENOENT') {
1472
1164
  this.log.error(`Error removing matter storage directory: ${error}`);
1473
1165
  }
1474
1166
  }
1475
1167
  try {
1476
- // Delete matterbridge storage directory with its subdirectories and backup
1477
1168
  const dir = path.join(this.matterbridgeDirectory, this.nodeStorageName);
1478
1169
  this.log.info(`Removing matterbridge storage directory: ${dir}`);
1479
1170
  await fs.rm(dir, { recursive: true });
@@ -1482,20 +1173,18 @@ export class Matterbridge extends EventEmitter {
1482
1173
  await fs.rm(backup, { recursive: true });
1483
1174
  }
1484
1175
  catch (error) {
1485
- // istanbul ignore next if
1486
1176
  if (error instanceof Error && error.code !== 'ENOENT') {
1487
1177
  this.log.error(`Error removing matterbridge storage directory: ${error}`);
1488
1178
  }
1489
1179
  }
1490
1180
  this.log.info('Factory reset done! Remove all paired fabrics from the controllers.');
1491
1181
  }
1492
- // Deregisters the process handlers
1493
1182
  this.deregisterProcessHandlers();
1494
1183
  if (restart) {
1495
1184
  if (message === 'updating...') {
1496
1185
  this.log.info('Cleanup completed. Updating...');
1497
1186
  Matterbridge.instance = undefined;
1498
- this.emit('update'); // Restart the process but the update has been done before. TODO move all updates to the cli
1187
+ this.emit('update');
1499
1188
  }
1500
1189
  else if (message === 'restarting...') {
1501
1190
  this.log.info('Cleanup completed. Restarting...');
@@ -1516,13 +1205,6 @@ export class Matterbridge extends EventEmitter {
1516
1205
  this.log.debug('Cleanup already started...');
1517
1206
  }
1518
1207
  }
1519
- /**
1520
- * Creates and configures the server node for a single not bridged device.
1521
- *
1522
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1523
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
1524
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
1525
- */
1526
1208
  async createDeviceServerNode(plugin, device) {
1527
1209
  if (device.mode === 'server' && !device.serverNode && device.deviceType && device.deviceName && device.vendorId && device.vendorName && device.productId && device.productName) {
1528
1210
  this.log.debug(`Creating device ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} server node...`);
@@ -1533,13 +1215,6 @@ export class Matterbridge extends EventEmitter {
1533
1215
  this.log.debug(`Added ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to server node`);
1534
1216
  }
1535
1217
  }
1536
- /**
1537
- * Creates and configures the server node for an accessory plugin for a given device.
1538
- *
1539
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1540
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
1541
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
1542
- */
1543
1218
  async createAccessoryPlugin(plugin, device) {
1544
1219
  if (!plugin.locked && device.deviceType && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
1545
1220
  plugin.locked = true;
@@ -1551,12 +1226,6 @@ export class Matterbridge extends EventEmitter {
1551
1226
  await plugin.serverNode.add(device);
1552
1227
  }
1553
1228
  }
1554
- /**
1555
- * Creates and configures the server node and the aggregator node for a dynamic plugin.
1556
- *
1557
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1558
- * @returns {Promise<void>} A promise that resolves when the server node and the aggregator node for the dynamic plugin is created and configured.
1559
- */
1560
1229
  async createDynamicPlugin(plugin) {
1561
1230
  if (!plugin.locked) {
1562
1231
  plugin.locked = true;
@@ -1567,14 +1236,7 @@ export class Matterbridge extends EventEmitter {
1567
1236
  await plugin.serverNode.add(plugin.aggregatorNode);
1568
1237
  }
1569
1238
  }
1570
- /**
1571
- * Starts the Matterbridge in bridge mode.
1572
- *
1573
- * @private
1574
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1575
- */
1576
1239
  async startBridge() {
1577
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1578
1240
  if (!this.matterStorageManager)
1579
1241
  throw new Error('No storage manager initialized');
1580
1242
  if (!this.matterbridgeContext)
@@ -1613,16 +1275,13 @@ export class Matterbridge extends EventEmitter {
1613
1275
  clearInterval(this.startMatterInterval);
1614
1276
  this.startMatterInterval = undefined;
1615
1277
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1616
- // Start the Matter server node
1617
- this.startServerNode(this.serverNode); // We don't await this, because the server node is started in the background
1618
- // Start the Matter server node of single devices in mode 'server'
1278
+ this.startServerNode(this.serverNode);
1619
1279
  for (const device of this.devices.array()) {
1620
1280
  if (device.mode === 'server' && device.serverNode) {
1621
1281
  this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
1622
- this.startServerNode(device.serverNode); // We don't await this, because the server node is started in the background
1282
+ this.startServerNode(device.serverNode);
1623
1283
  }
1624
1284
  }
1625
- // Configure the plugins
1626
1285
  this.configureTimeout = setTimeout(async () => {
1627
1286
  for (const plugin of this.plugins.array()) {
1628
1287
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1640,25 +1299,16 @@ export class Matterbridge extends EventEmitter {
1640
1299
  }
1641
1300
  this.frontend.wssSendRefreshRequired('plugins');
1642
1301
  }, 30 * 1000).unref();
1643
- // Setting reachability to true
1644
1302
  this.reachabilityTimeout = setTimeout(() => {
1645
1303
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1646
1304
  if (this.aggregatorNode)
1647
1305
  this.setAggregatorReachability(this.aggregatorNode, true);
1648
1306
  this.frontend.wssSendRefreshRequired('reachability');
1649
1307
  }, 60 * 1000).unref();
1650
- // Logger.get('LogServerNode').info(this.serverNode);
1651
1308
  this.emit('bridge_started');
1652
1309
  this.log.notice('Matterbridge bridge started successfully');
1653
1310
  }, this.startMatterIntervalMs);
1654
1311
  }
1655
- /**
1656
- * Starts the Matterbridge in childbridge mode.
1657
- *
1658
- * @param {number} [delay] - The delay before starting the childbridge. Default is 1000 milliseconds.
1659
- *
1660
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1661
- */
1662
1312
  async startChildbridge(delay = 1000) {
1663
1313
  if (!this.matterStorageManager)
1664
1314
  throw new Error('No storage manager initialized');
@@ -1696,9 +1346,8 @@ export class Matterbridge extends EventEmitter {
1696
1346
  clearInterval(this.startMatterInterval);
1697
1347
  this.startMatterInterval = undefined;
1698
1348
  if (delay > 0)
1699
- await wait(delay); // Wait for the specified delay to ensure all plugins server nodes are ready
1349
+ await wait(delay);
1700
1350
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1701
- // Configure the plugins
1702
1351
  this.configureTimeout = setTimeout(async () => {
1703
1352
  for (const plugin of this.plugins.array()) {
1704
1353
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1735,9 +1384,7 @@ export class Matterbridge extends EventEmitter {
1735
1384
  this.log.error(`Node storage context not found for plugin ${plg}${plugin.name}${er}`);
1736
1385
  continue;
1737
1386
  }
1738
- // Start the Matter server node
1739
- this.startServerNode(plugin.serverNode); // We don't await this, because the server node is started in the background
1740
- // Setting reachability to true
1387
+ this.startServerNode(plugin.serverNode);
1741
1388
  plugin.reachabilityTimeout = setTimeout(() => {
1742
1389
  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}`);
1743
1390
  if (plugin.type === 'DynamicPlatform' && plugin.aggregatorNode)
@@ -1745,241 +1392,19 @@ export class Matterbridge extends EventEmitter {
1745
1392
  this.frontend.wssSendRefreshRequired('reachability');
1746
1393
  }, 60 * 1000).unref();
1747
1394
  }
1748
- // Start the Matter server node of single devices in mode 'server'
1749
1395
  for (const device of this.devices.array()) {
1750
1396
  if (device.mode === 'server' && device.serverNode) {
1751
1397
  this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
1752
- this.startServerNode(device.serverNode); // We don't await this, because the server node is started in the background
1398
+ this.startServerNode(device.serverNode);
1753
1399
  }
1754
1400
  }
1755
- // Logger.get('LogServerNode').info(this.serverNode);
1756
1401
  this.emit('childbridge_started');
1757
1402
  this.log.notice('Matterbridge childbridge started successfully');
1758
1403
  }, this.startMatterIntervalMs);
1759
1404
  }
1760
- /**
1761
- * Starts the Matterbridge controller.
1762
- *
1763
- * @private
1764
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1765
- */
1766
1405
  async startController() {
1767
- /*
1768
- if (!this.matterStorageManager) {
1769
- this.log.error('No storage manager initialized');
1770
- await this.cleanup('No storage manager initialized');
1771
- return;
1772
- }
1773
- this.log.info('Creating context: mattercontrollerContext');
1774
- this.controllerContext = this.matterStorageManager.createContext('mattercontrollerContext');
1775
- if (!this.controllerContext) {
1776
- this.log.error('No storage context mattercontrollerContext initialized');
1777
- await this.cleanup('No storage context mattercontrollerContext initialized');
1778
- return;
1779
- }
1780
-
1781
- this.log.debug('Starting matterbridge in mode', this.bridgeMode);
1782
- this.matterServer = await this.createMatterServer(this.storageManager);
1783
- this.log.info('Creating matter commissioning controller');
1784
- this.commissioningController = new CommissioningController({
1785
- autoConnect: false,
1786
- });
1787
- this.log.info('Adding matter commissioning controller to matter server');
1788
- await this.matterServer.addCommissioningController(this.commissioningController);
1789
-
1790
- this.log.info('Starting matter server');
1791
- await this.matterServer.start();
1792
- this.log.info('Matter server started');
1793
- const commissioningOptions: ControllerCommissioningFlowOptions = {
1794
- regulatoryLocation: GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor,
1795
- regulatoryCountryCode: 'XX',
1796
- };
1797
- const commissioningController = new CommissioningController({
1798
- environment: {
1799
- environment,
1800
- id: uniqueId,
1801
- },
1802
- autoConnect: false, // Do not auto connect to the commissioned nodes
1803
- adminFabricLabel,
1804
- });
1805
-
1806
- if (hasParameter('pairingcode')) {
1807
- this.log.info('Pairing device with pairingcode:', getParameter('pairingcode'));
1808
- const pairingCode = getParameter('pairingcode');
1809
- const ip = this.controllerContext.has('ip') ? this.controllerContext.get<string>('ip') : undefined;
1810
- const port = this.controllerContext.has('port') ? this.controllerContext.get<number>('port') : undefined;
1811
-
1812
- let longDiscriminator, setupPin, shortDiscriminator;
1813
- if (pairingCode !== undefined) {
1814
- const pairingCodeCodec = ManualPairingCodeCodec.decode(pairingCode);
1815
- shortDiscriminator = pairingCodeCodec.shortDiscriminator;
1816
- longDiscriminator = undefined;
1817
- setupPin = pairingCodeCodec.passcode;
1818
- this.log.info(`Data extracted from pairing code: ${Logger.toJSON(pairingCodeCodec)}`);
1819
- } else {
1820
- longDiscriminator = await this.controllerContext.get('longDiscriminator', 3840);
1821
- if (longDiscriminator > 4095) throw new Error('Discriminator value must be less than 4096');
1822
- setupPin = this.controllerContext.get('pin', 20202021);
1823
- }
1824
- if ((shortDiscriminator === undefined && longDiscriminator === undefined) || setupPin === undefined) {
1825
- throw new Error('Please specify the longDiscriminator of the device to commission with -longDiscriminator or provide a valid passcode with -passcode');
1826
- }
1827
-
1828
- const options = {
1829
- commissioning: commissioningOptions,
1830
- discovery: {
1831
- knownAddress: ip !== undefined && port !== undefined ? { ip, port, type: 'udp' } : undefined,
1832
- identifierData: longDiscriminator !== undefined ? { longDiscriminator } : shortDiscriminator !== undefined ? { shortDiscriminator } : {},
1833
- },
1834
- passcode: setupPin,
1835
- } as NodeCommissioningOptions;
1836
- this.log.info('Commissioning with options:', options);
1837
- const nodeId = await this.commissioningController.commissionNode(options);
1838
- this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1839
- this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1840
- } // (hasParameter('pairingcode'))
1841
-
1842
- if (hasParameter('unpairall')) {
1843
- this.log.info('***Commissioning controller unpairing all nodes...');
1844
- const nodeIds = this.commissioningController.getCommissionedNodes();
1845
- for (const nodeId of nodeIds) {
1846
- this.log.info('***Commissioning controller unpairing node:', nodeId);
1847
- await this.commissioningController.removeNode(nodeId);
1848
- }
1849
- return;
1850
- }
1851
-
1852
- if (hasParameter('discover')) {
1853
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1854
- // console.log(discover);
1855
- }
1856
-
1857
- if (!this.commissioningController.isCommissioned()) {
1858
- this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
1859
- return;
1860
- }
1861
-
1862
- const nodeIds = this.commissioningController.getCommissionedNodes();
1863
- this.log.info(`***Commissioning controller is commissioned ${this.commissioningController.isCommissioned()} and has ${nodeIds.length} nodes commisioned: `);
1864
- for (const nodeId of nodeIds) {
1865
- this.log.info(`***Connecting to commissioned node: ${nodeId}`);
1866
-
1867
- const node = await this.commissioningController.connectNode(nodeId, {
1868
- autoSubscribe: false,
1869
- attributeChangedCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, attributeName }, value }) =>
1870
- this.log.info(`***Commissioning controller attributeChangedCallback ${peerNodeId}: attribute ${nodeId}/${endpointId}/${clusterId}/${attributeName} changed to ${Logger.toJSON(value)}`),
1871
- eventTriggeredCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, eventName }, events }) =>
1872
- this.log.info(`***Commissioning controller eventTriggeredCallback ${peerNodeId}: Event ${nodeId}/${endpointId}/${clusterId}/${eventName} triggered with ${Logger.toJSON(events)}`),
1873
- stateInformationCallback: (peerNodeId, info) => {
1874
- switch (info) {
1875
- case NodeStateInformation.Connected:
1876
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} connected`);
1877
- break;
1878
- case NodeStateInformation.Disconnected:
1879
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} disconnected`);
1880
- break;
1881
- case NodeStateInformation.Reconnecting:
1882
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} reconnecting`);
1883
- break;
1884
- case NodeStateInformation.WaitingForDeviceDiscovery:
1885
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} waiting for device discovery`);
1886
- break;
1887
- case NodeStateInformation.StructureChanged:
1888
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} structure changed`);
1889
- break;
1890
- case NodeStateInformation.Decommissioned:
1891
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} decommissioned`);
1892
- break;
1893
- default:
1894
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} NodeStateInformation.${info}`);
1895
- break;
1896
- }
1897
- },
1898
- });
1899
-
1900
- node.logStructure();
1901
-
1902
- // Get the interaction client
1903
- this.log.info('Getting the interaction client');
1904
- const interactionClient = await node.getInteractionClient();
1905
- let cluster;
1906
- let attributes;
1907
-
1908
- // Log BasicInformationCluster
1909
- cluster = BasicInformationCluster;
1910
- attributes = await interactionClient.getMultipleAttributes({
1911
- attributes: [{ clusterId: cluster.id }],
1912
- });
1913
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1914
- attributes.forEach((attribute) => {
1915
- this.log.info(
1916
- `- 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}`,
1917
- );
1918
- });
1919
-
1920
- // Log PowerSourceCluster
1921
- cluster = PowerSourceCluster;
1922
- attributes = await interactionClient.getMultipleAttributes({
1923
- attributes: [{ clusterId: cluster.id }],
1924
- });
1925
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1926
- attributes.forEach((attribute) => {
1927
- this.log.info(
1928
- `- 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}`,
1929
- );
1930
- });
1931
-
1932
- // Log ThreadNetworkDiagnostics
1933
- cluster = ThreadNetworkDiagnosticsCluster;
1934
- attributes = await interactionClient.getMultipleAttributes({
1935
- attributes: [{ clusterId: cluster.id }],
1936
- });
1937
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1938
- attributes.forEach((attribute) => {
1939
- this.log.info(
1940
- `- 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}`,
1941
- );
1942
- });
1943
-
1944
- // Log SwitchCluster
1945
- cluster = SwitchCluster;
1946
- attributes = await interactionClient.getMultipleAttributes({
1947
- attributes: [{ clusterId: cluster.id }],
1948
- });
1949
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1950
- attributes.forEach((attribute) => {
1951
- this.log.info(
1952
- `- 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}`,
1953
- );
1954
- });
1955
-
1956
- this.log.info('Subscribing to all attributes and events');
1957
- await node.subscribeAllAttributesAndEvents({
1958
- ignoreInitialTriggers: false,
1959
- attributeChangedCallback: ({ path: { nodeId, clusterId, endpointId, attributeName }, version, value }) =>
1960
- this.log.info(
1961
- `***${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}`,
1962
- ),
1963
- eventTriggeredCallback: ({ path: { nodeId, clusterId, endpointId, eventName }, events }) => {
1964
- this.log.info(
1965
- `***${db}Commissioning controller eventTriggeredCallback: event ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${eventName}${db} triggered with ${debugStringify(events ?? { none: true })}`,
1966
- );
1967
- },
1968
- });
1969
- this.log.info('Subscribed to all attributes and events');
1970
- }
1971
- */
1972
1406
  }
1973
- /** */
1974
- /** Matter.js methods */
1975
- /** */
1976
- /**
1977
- * Starts the matter storage with name Matterbridge, create the matterbridge context and performs a backup.
1978
- *
1979
- * @returns {Promise<void>} - A promise that resolves when the storage is started.
1980
- */
1981
1407
  async startMatterStorage() {
1982
- // Setup Matter storage
1983
1408
  this.log.info(`Starting matter node storage...`);
1984
1409
  this.matterStorageService = this.environment.get(StorageService);
1985
1410
  this.log.info(`Matter node storage service created: ${this.matterStorageService.location}`);
@@ -1988,17 +1413,8 @@ export class Matterbridge extends EventEmitter {
1988
1413
  this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId);
1989
1414
  this.matterbridgeInformation.matterbridgeSerialNumber = await this.matterbridgeContext.get('serialNumber', '');
1990
1415
  this.log.info('Matter node storage started');
1991
- // Backup matter storage since it is created/opened correctly
1992
1416
  await this.backupMatterStorage(path.join(this.matterbridgeDirectory, this.matterStorageName), path.join(this.matterbridgeDirectory, this.matterStorageName + '.backup'));
1993
1417
  }
1994
- /**
1995
- * Makes a backup copy of the specified matter storage directory.
1996
- *
1997
- * @param {string} storageName - The name of the storage directory to be backed up.
1998
- * @param {string} backupName - The name of the backup directory to be created.
1999
- * @private
2000
- * @returns {Promise<void>} A promise that resolves when the has been done.
2001
- */
2002
1418
  async backupMatterStorage(storageName, backupName) {
2003
1419
  this.log.info('Creating matter node storage backup...');
2004
1420
  try {
@@ -2009,11 +1425,6 @@ export class Matterbridge extends EventEmitter {
2009
1425
  this.log.error(`Error creating matter node storage backup from ${storageName} to ${backupName}:`, error);
2010
1426
  }
2011
1427
  }
2012
- /**
2013
- * Stops the matter storage.
2014
- *
2015
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
2016
- */
2017
1428
  async stopMatterStorage() {
2018
1429
  this.log.info('Closing matter node storage...');
2019
1430
  await this.matterStorageManager?.close();
@@ -2022,20 +1433,6 @@ export class Matterbridge extends EventEmitter {
2022
1433
  this.matterbridgeContext = undefined;
2023
1434
  this.log.info('Matter node storage closed');
2024
1435
  }
2025
- /**
2026
- * Creates a server node storage context.
2027
- *
2028
- * @param {string} pluginName - The name of the plugin.
2029
- * @param {string} deviceName - The name of the device.
2030
- * @param {DeviceTypeId} deviceType - The device type of the device.
2031
- * @param {number} vendorId - The vendor ID.
2032
- * @param {string} vendorName - The vendor name.
2033
- * @param {number} productId - The product ID.
2034
- * @param {string} productName - The product name.
2035
- * @param {string} [serialNumber] - The serial number of the device (optional).
2036
- * @param {string} [uniqueId] - The unique ID of the device (optional).
2037
- * @returns {Promise<StorageContext>} The storage context for the commissioning server.
2038
- */
2039
1436
  async createServerNodeContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber, uniqueId) {
2040
1437
  const { randomBytes } = await import('node:crypto');
2041
1438
  if (!this.matterStorageService)
@@ -2069,15 +1466,6 @@ export class Matterbridge extends EventEmitter {
2069
1466
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2070
1467
  return storageContext;
2071
1468
  }
2072
- /**
2073
- * Creates a server node.
2074
- *
2075
- * @param {StorageContext} storageContext - The storage context for the server node.
2076
- * @param {number} [port] - The port number for the server node. Defaults to 5540.
2077
- * @param {number} [passcode] - The passcode for the server node. Defaults to 20242025.
2078
- * @param {number} [discriminator] - The discriminator for the server node. Defaults to 3850.
2079
- * @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created server node.
2080
- */
2081
1469
  async createServerNode(storageContext, port = 5540, passcode = 20242025, discriminator = 3850) {
2082
1470
  const storeId = await storageContext.get('storeId');
2083
1471
  this.log.notice(`Creating server node for ${storeId} on port ${port} with passcode ${passcode} and discriminator ${discriminator}...`);
@@ -2087,37 +1475,24 @@ export class Matterbridge extends EventEmitter {
2087
1475
  this.log.debug(`- uniqueId: ${await storageContext.get('uniqueId')}`);
2088
1476
  this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
2089
1477
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2090
- /**
2091
- * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
2092
- */
2093
1478
  const serverNode = await ServerNode.create({
2094
- // Required: Give the Node a unique ID which is used to store the state of this node
2095
1479
  id: storeId,
2096
- // Provide Network relevant configuration like the port
2097
- // Optional when operating only one device on a host, Default port is 5540
2098
1480
  network: {
2099
1481
  listeningAddressIpv4: this.ipv4address,
2100
1482
  listeningAddressIpv6: this.ipv6address,
2101
1483
  port,
2102
1484
  },
2103
- // Provide the certificate for the device
2104
1485
  operationalCredentials: {
2105
1486
  certification: this.certification,
2106
1487
  },
2107
- // Provide Commissioning relevant settings
2108
- // Optional for development/testing purposes
2109
1488
  commissioning: {
2110
1489
  passcode,
2111
1490
  discriminator,
2112
1491
  },
2113
- // Provide Node announcement settings
2114
- // Optional: If Ommitted some development defaults are used
2115
1492
  productDescription: {
2116
1493
  name: await storageContext.get('deviceName'),
2117
1494
  deviceType: DeviceTypeId(await storageContext.get('deviceType')),
2118
1495
  },
2119
- // Provide defaults for the BasicInformation cluster on the Root endpoint
2120
- // Optional: If Omitted some development defaults are used
2121
1496
  basicInformation: {
2122
1497
  vendorId: VendorId(await storageContext.get('vendorId')),
2123
1498
  vendorName: await storageContext.get('vendorName'),
@@ -2134,20 +1509,14 @@ export class Matterbridge extends EventEmitter {
2134
1509
  reachable: true,
2135
1510
  },
2136
1511
  });
2137
- /**
2138
- * This event is triggered when the device is initially commissioned successfully.
2139
- * This means: It is added to the first fabric.
2140
- */
2141
1512
  serverNode.lifecycle.commissioned.on(() => {
2142
1513
  this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`);
2143
1514
  clearTimeout(this.endAdvertiseTimeout);
2144
1515
  });
2145
- /** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
2146
1516
  serverNode.lifecycle.decommissioned.on(() => {
2147
1517
  this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`);
2148
1518
  clearTimeout(this.endAdvertiseTimeout);
2149
1519
  });
2150
- /** This event is triggered when the device went online. This means that it is discoverable in the network. */
2151
1520
  serverNode.lifecycle.online.on(async () => {
2152
1521
  this.log.notice(`Server node for ${storeId} is online`);
2153
1522
  if (!serverNode.lifecycle.isCommissioned) {
@@ -2155,11 +1524,9 @@ export class Matterbridge extends EventEmitter {
2155
1524
  const { qrPairingCode, manualPairingCode } = serverNode.state.commissioning.pairingCodes;
2156
1525
  this.log.notice(`QR Code URL: https://project-chip.github.io/connectedhomeip/qrcode.html?data=${qrPairingCode}`);
2157
1526
  this.log.notice(`Manual pairing code: ${manualPairingCode}`);
2158
- // Set a timeout to show that advertising stops after 15 minutes if not commissioned
2159
1527
  this.startEndAdvertiseTimer(serverNode);
2160
1528
  }
2161
1529
  else {
2162
- // istanbul ignore next
2163
1530
  this.log.notice(`Server node for ${storeId} is already commissioned. Waiting for controllers to connect ...`);
2164
1531
  }
2165
1532
  this.frontend.wssSendRefreshRequired('plugins');
@@ -2167,19 +1534,14 @@ export class Matterbridge extends EventEmitter {
2167
1534
  this.frontend.wssSendSnackbarMessage(`${storeId} is online`, 5, 'success');
2168
1535
  this.emit('online', storeId);
2169
1536
  });
2170
- /** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
2171
1537
  serverNode.lifecycle.offline.on(() => {
2172
1538
  this.log.notice(`Server node for ${storeId} is offline`);
2173
- this.matterbridgeInformation.matterbridgeEndAdvertise = true; // Set the end advertise flag to true, so the frontend won't show the QR code anymore
1539
+ this.matterbridgeInformation.matterbridgeEndAdvertise = true;
2174
1540
  this.frontend.wssSendRefreshRequired('plugins');
2175
1541
  this.frontend.wssSendRefreshRequired('settings');
2176
1542
  this.frontend.wssSendSnackbarMessage(`${storeId} is offline`, 5, 'warning');
2177
1543
  this.emit('offline', storeId);
2178
1544
  });
2179
- /**
2180
- * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
2181
- * information is needed.
2182
- */
2183
1545
  serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
2184
1546
  let action = '';
2185
1547
  switch (fabricAction) {
@@ -2196,22 +1558,14 @@ export class Matterbridge extends EventEmitter {
2196
1558
  this.log.notice(`Commissioned fabric index ${fabricIndex} ${action} on server node for ${storeId}: ${debugStringify(serverNode.state.commissioning.fabrics[fabricIndex])}`);
2197
1559
  this.frontend.wssSendRefreshRequired('fabrics');
2198
1560
  });
2199
- /**
2200
- * This event is triggered when an operative new session was opened by a Controller.
2201
- * It is not triggered for the initial commissioning process, just afterwards for real connections.
2202
- */
2203
1561
  serverNode.events.sessions.opened.on((session) => {
2204
1562
  this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
2205
1563
  this.frontend.wssSendRefreshRequired('sessions');
2206
1564
  });
2207
- /**
2208
- * This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
2209
- */
2210
1565
  serverNode.events.sessions.closed.on((session) => {
2211
1566
  this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
2212
1567
  this.frontend.wssSendRefreshRequired('sessions');
2213
1568
  });
2214
- /** This event is triggered when a subscription gets added or removed on an operative session. */
2215
1569
  serverNode.events.sessions.subscriptionsChanged.on((session) => {
2216
1570
  this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
2217
1571
  this.frontend.wssSendRefreshRequired('sessions');
@@ -2219,11 +1573,6 @@ export class Matterbridge extends EventEmitter {
2219
1573
  this.log.info(`Created server node for ${storeId}`);
2220
1574
  return serverNode;
2221
1575
  }
2222
- /**
2223
- * Starts the 15 minutes timer to advice that advertising for the specified server node is ended.
2224
- *
2225
- * @param {ServerNode} [matterServerNode] - The server node to start.
2226
- */
2227
1576
  startEndAdvertiseTimer(matterServerNode) {
2228
1577
  if (this.endAdvertiseTimeout) {
2229
1578
  this.log.debug(`Clear ${matterServerNode.id} server node end advertise timer`);
@@ -2242,25 +1591,12 @@ export class Matterbridge extends EventEmitter {
2242
1591
  this.log.notice(`Advertising on server node for ${matterServerNode.id} stopped. Restart to commission.`);
2243
1592
  }, 15 * 60 * 1000).unref();
2244
1593
  }
2245
- /**
2246
- * Starts the specified server node.
2247
- *
2248
- * @param {ServerNode} [matterServerNode] - The server node to start.
2249
- * @returns {Promise<void>} A promise that resolves when the server node has started.
2250
- */
2251
1594
  async startServerNode(matterServerNode) {
2252
1595
  if (!matterServerNode)
2253
1596
  return;
2254
1597
  this.log.notice(`Starting ${matterServerNode.id} server node`);
2255
1598
  await matterServerNode.start();
2256
1599
  }
2257
- /**
2258
- * Stops the specified server node.
2259
- *
2260
- * @param {ServerNode} matterServerNode - The server node to stop.
2261
- * @param {number} [timeout] - The timeout in milliseconds for stopping the server node. Defaults to 30 seconds.
2262
- * @returns {Promise<void>} A promise that resolves when the server node has stopped.
2263
- */
2264
1600
  async stopServerNode(matterServerNode, timeout = 30000) {
2265
1601
  if (!matterServerNode)
2266
1602
  return;
@@ -2273,12 +1609,6 @@ export class Matterbridge extends EventEmitter {
2273
1609
  this.log.error(`Failed to close ${matterServerNode.id} server node: ${error instanceof Error ? error.message : error}`);
2274
1610
  }
2275
1611
  }
2276
- /**
2277
- * Advertises the specified server node.
2278
- *
2279
- * @param {ServerNode} [matterServerNode] - The server node to advertise.
2280
- * @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.
2281
- */
2282
1612
  async advertiseServerNode(matterServerNode) {
2283
1613
  if (matterServerNode) {
2284
1614
  await matterServerNode.env.get(DeviceCommissioner)?.allowBasicCommissioning();
@@ -2287,39 +1617,19 @@ export class Matterbridge extends EventEmitter {
2287
1617
  return { qrPairingCode, manualPairingCode };
2288
1618
  }
2289
1619
  }
2290
- /**
2291
- * Stop advertise the specified server node.
2292
- *
2293
- * @param {ServerNode} [matterServerNode] - The server node to advertise.
2294
- * @returns {Promise<void>} A promise that resolves when the server node has stopped advertising.
2295
- */
2296
1620
  async stopAdvertiseServerNode(matterServerNode) {
2297
1621
  if (matterServerNode && matterServerNode.lifecycle.isOnline) {
2298
1622
  await matterServerNode.env.get(DeviceCommissioner)?.endCommissioning();
2299
1623
  this.log.notice(`Stopped advertising for ${matterServerNode.id}`);
2300
1624
  }
2301
1625
  }
2302
- /**
2303
- * Creates an aggregator node with the specified storage context.
2304
- *
2305
- * @param {StorageContext} storageContext - The storage context for the aggregator node.
2306
- * @returns {Promise<Endpoint<AggregatorEndpoint>>} A promise that resolves to the created aggregator node.
2307
- */
2308
1626
  async createAggregatorNode(storageContext) {
2309
1627
  this.log.notice(`Creating ${await storageContext.get('storeId')} aggregator...`);
2310
1628
  const aggregatorNode = new Endpoint(AggregatorEndpoint, { id: `${await storageContext.get('storeId')}` });
2311
1629
  this.log.info(`Created ${await storageContext.get('storeId')} aggregator`);
2312
1630
  return aggregatorNode;
2313
1631
  }
2314
- /**
2315
- * Adds a MatterbridgeEndpoint to the specified plugin.
2316
- *
2317
- * @param {string} pluginName - The name of the plugin.
2318
- * @param {MatterbridgeEndpoint} device - The device to add as a bridged endpoint.
2319
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been added.
2320
- */
2321
1632
  async addBridgedEndpoint(pluginName, device) {
2322
- // Check if the plugin is registered
2323
1633
  const plugin = this.plugins.get(pluginName);
2324
1634
  if (!plugin) {
2325
1635
  this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
@@ -2339,7 +1649,6 @@ export class Matterbridge extends EventEmitter {
2339
1649
  }
2340
1650
  else if (this.bridgeMode === 'bridge') {
2341
1651
  if (device.mode === 'matter') {
2342
- // Register and add the device to the matterbridge server node
2343
1652
  this.log.debug(`Adding matter endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge server node...`);
2344
1653
  if (!this.serverNode) {
2345
1654
  this.log.error('Server node not found for Matterbridge');
@@ -2356,7 +1665,6 @@ export class Matterbridge extends EventEmitter {
2356
1665
  }
2357
1666
  }
2358
1667
  else {
2359
- // Register and add the device to the matterbridge aggregator node
2360
1668
  this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
2361
1669
  if (!this.aggregatorNode) {
2362
1670
  this.log.error('Aggregator node not found for Matterbridge');
@@ -2374,7 +1682,6 @@ export class Matterbridge extends EventEmitter {
2374
1682
  }
2375
1683
  }
2376
1684
  else if (this.bridgeMode === 'childbridge') {
2377
- // Register and add the device to the plugin server node
2378
1685
  if (plugin.type === 'AccessoryPlatform') {
2379
1686
  try {
2380
1687
  this.log.debug(`Creating endpoint ${dev}${device.deviceName}${db} for AccessoryPlatform plugin ${plg}${plugin.name}${db} server node`);
@@ -2398,12 +1705,10 @@ export class Matterbridge extends EventEmitter {
2398
1705
  return;
2399
1706
  }
2400
1707
  }
2401
- // Register and add the device to the plugin aggregator node
2402
1708
  if (plugin.type === 'DynamicPlatform') {
2403
1709
  try {
2404
1710
  this.log.debug(`Adding bridged endpoint ${dev}${device.deviceName}${db} for DynamicPlatform plugin ${plg}${plugin.name}${db} aggregator node`);
2405
1711
  await this.createDynamicPlugin(plugin);
2406
- // Fast plugins can add another device before the server node is ready, so we wait for the server node to be ready
2407
1712
  await waiter(`createDynamicPlugin(${plugin.name})`, () => plugin.serverNode?.hasParts === true);
2408
1713
  if (!plugin.aggregatorNode) {
2409
1714
  this.log.error(`Aggregator node not found for plugin ${plg}${plugin.name}${er}`);
@@ -2426,28 +1731,17 @@ export class Matterbridge extends EventEmitter {
2426
1731
  plugin.registeredDevices++;
2427
1732
  if (plugin.addedDevices !== undefined)
2428
1733
  plugin.addedDevices++;
2429
- // Add the device to the DeviceManager
2430
1734
  this.devices.set(device);
2431
- // Subscribe to the reachable$Changed event
2432
1735
  await this.subscribeAttributeChanged(plugin, device);
2433
1736
  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}`);
2434
1737
  }
2435
- /**
2436
- * Removes a MatterbridgeEndpoint from the specified plugin.
2437
- *
2438
- * @param {string} pluginName - The name of the plugin.
2439
- * @param {MatterbridgeEndpoint} device - The device to remove as a bridged endpoint.
2440
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been removed.
2441
- */
2442
1738
  async removeBridgedEndpoint(pluginName, device) {
2443
1739
  this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
2444
- // Check if the plugin is registered
2445
1740
  const plugin = this.plugins.get(pluginName);
2446
1741
  if (!plugin) {
2447
1742
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
2448
1743
  return;
2449
1744
  }
2450
- // Register and add the device to the matterbridge aggregator node
2451
1745
  if (this.bridgeMode === 'bridge') {
2452
1746
  if (!this.aggregatorNode) {
2453
1747
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator node not found`);
@@ -2462,7 +1756,6 @@ export class Matterbridge extends EventEmitter {
2462
1756
  }
2463
1757
  else if (this.bridgeMode === 'childbridge') {
2464
1758
  if (plugin.type === 'AccessoryPlatform') {
2465
- // Nothing to do here since the server node has no aggregator node but only the device itself
2466
1759
  }
2467
1760
  else if (plugin.type === 'DynamicPlatform') {
2468
1761
  if (!plugin.aggregatorNode) {
@@ -2477,21 +1770,8 @@ export class Matterbridge extends EventEmitter {
2477
1770
  if (plugin.addedDevices !== undefined)
2478
1771
  plugin.addedDevices--;
2479
1772
  }
2480
- // Remove the device from the DeviceManager
2481
1773
  this.devices.remove(device);
2482
1774
  }
2483
- /**
2484
- * Removes all bridged endpoints from the specified plugin.
2485
- *
2486
- * @param {string} pluginName - The name of the plugin.
2487
- * @param {number} [delay] - The delay in milliseconds between removing each bridged endpoint (default: 0).
2488
- * @returns {Promise<void>} A promise that resolves when all bridged endpoints have been removed.
2489
- *
2490
- * @remarks
2491
- * This method iterates through all devices in the DeviceManager and removes each bridged endpoint associated with the specified plugin.
2492
- * It also applies a delay between each removal if specified.
2493
- * The delay is useful to allow the controllers to receive a single subscription for each device removed.
2494
- */
2495
1775
  async removeAllBridgedEndpoints(pluginName, delay = 0) {
2496
1776
  this.log.debug(`Removing all bridged endpoints for plugin ${plg}${pluginName}${db}${delay > 0 ? ` with delay ${delay} ms` : ''}`);
2497
1777
  for (const device of this.devices.array().filter((device) => device.plugin === pluginName)) {
@@ -2502,15 +1782,6 @@ export class Matterbridge extends EventEmitter {
2502
1782
  if (delay > 0)
2503
1783
  await wait(2000);
2504
1784
  }
2505
- /**
2506
- * Subscribes to the attribute change event for the given device and plugin.
2507
- * Specifically, it listens for changes in the 'reachable' attribute of the
2508
- * BridgedDeviceBasicInformationServer cluster server of the bridged device or BasicInformationServer cluster server of server node.
2509
- *
2510
- * @param {RegisteredPlugin} plugin - The plugin associated with the device.
2511
- * @param {MatterbridgeEndpoint} device - The device to subscribe to attribute changes for.
2512
- * @returns {Promise<void>} A promise that resolves when the subscription is set up.
2513
- */
2514
1785
  async subscribeAttributeChanged(plugin, device) {
2515
1786
  this.log.info(`Subscribing attributes for endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) plugin ${plg}${plugin.name}${nf}`);
2516
1787
  if (this.bridgeMode === 'childbridge' && plugin.type === 'AccessoryPlatform' && plugin.serverNode) {
@@ -2526,12 +1797,6 @@ export class Matterbridge extends EventEmitter {
2526
1797
  });
2527
1798
  }
2528
1799
  }
2529
- /**
2530
- * Sanitizes the fabric information by converting bigint properties to strings because `res.json` doesn't support bigint.
2531
- *
2532
- * @param {ExposedFabricInformation[]} fabricInfo - The array of exposed fabric information objects.
2533
- * @returns {SanitizedExposedFabricInformation[]} An array of sanitized exposed fabric information objects.
2534
- */
2535
1800
  sanitizeFabricInformations(fabricInfo) {
2536
1801
  return fabricInfo.map((info) => {
2537
1802
  return {
@@ -2545,12 +1810,6 @@ export class Matterbridge extends EventEmitter {
2545
1810
  };
2546
1811
  });
2547
1812
  }
2548
- /**
2549
- * Sanitizes the session information by converting bigint properties to strings because `res.json` doesn't support bigint.
2550
- *
2551
- * @param {SessionsBehavior.Session[]} sessions - The array of session information objects.
2552
- * @returns {SanitizedSession[]} An array of sanitized session information objects.
2553
- */
2554
1813
  sanitizeSessionInformation(sessions) {
2555
1814
  return sessions
2556
1815
  .filter((session) => session.isPeerActive)
@@ -2577,21 +1836,7 @@ export class Matterbridge extends EventEmitter {
2577
1836
  };
2578
1837
  });
2579
1838
  }
2580
- /**
2581
- * Sets the reachability of the specified aggregator node bridged devices and trigger.
2582
- *
2583
- * @param {Endpoint<AggregatorEndpoint>} aggregatorNode - The aggregator node to set the reachability for.
2584
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2585
- */
2586
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2587
1839
  async setAggregatorReachability(aggregatorNode, reachable) {
2588
- /*
2589
- for (const child of aggregatorNode.parts) {
2590
- this.log.debug(`Setting reachability of ${(child as unknown as MatterbridgeEndpoint)?.deviceName} to ${reachable}`);
2591
- await child.setStateOf(BridgedDeviceBasicInformationServer, { reachable });
2592
- child.act((agent) => child.eventsOf(BridgedDeviceBasicInformationServer).reachableChanged.emit({ reachableNewValue: true }, agent.context));
2593
- }
2594
- */
2595
1840
  }
2596
1841
  getVendorIdName = (vendorId) => {
2597
1842
  if (!vendorId)
@@ -2631,11 +1876,10 @@ export class Matterbridge extends EventEmitter {
2631
1876
  case 0x1488:
2632
1877
  vendorName = '(ShortcutLabsFlic)';
2633
1878
  break;
2634
- case 65521: // 0xFFF1
1879
+ case 65521:
2635
1880
  vendorName = '(MatterTest)';
2636
1881
  break;
2637
1882
  }
2638
1883
  return vendorName;
2639
1884
  };
2640
1885
  }
2641
- //# sourceMappingURL=matterbridge.js.map