matterbridge 3.3.4 → 3.3.5-dev-20251028-d89f93f

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 (305) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/broadcastServer.js +1 -92
  3. package/dist/broadcastServerTypes.js +0 -24
  4. package/dist/cli.js +1 -97
  5. package/dist/cliEmitter.js +0 -37
  6. package/dist/cliHistory.js +0 -38
  7. package/dist/clusters/export.js +0 -2
  8. package/dist/defaultConfigSchema.js +0 -24
  9. package/dist/deviceManager.js +8 -124
  10. package/dist/devices/airConditioner.js +0 -57
  11. package/dist/devices/batteryStorage.js +1 -48
  12. package/dist/devices/cooktop.js +0 -55
  13. package/dist/devices/dishwasher.js +0 -57
  14. package/dist/devices/evse.js +10 -74
  15. package/dist/devices/export.js +0 -5
  16. package/dist/devices/extractorHood.js +0 -42
  17. package/dist/devices/heatPump.js +2 -50
  18. package/dist/devices/laundryDryer.js +3 -62
  19. package/dist/devices/laundryWasher.js +4 -70
  20. package/dist/devices/microwaveOven.js +5 -88
  21. package/dist/devices/oven.js +0 -85
  22. package/dist/devices/refrigerator.js +0 -102
  23. package/dist/devices/roboticVacuumCleaner.js +9 -100
  24. package/dist/devices/solarPower.js +0 -38
  25. package/dist/devices/speaker.js +0 -84
  26. package/dist/devices/temperatureControl.js +3 -24
  27. package/dist/devices/waterHeater.js +2 -82
  28. package/dist/dgram/coap.js +13 -126
  29. package/dist/dgram/dgram.js +2 -114
  30. package/dist/dgram/mb_coap.js +3 -41
  31. package/dist/dgram/mb_mdns.js +15 -80
  32. package/dist/dgram/mdns.js +137 -299
  33. package/dist/dgram/multicast.js +1 -62
  34. package/dist/dgram/unicast.js +0 -54
  35. package/dist/frontend.js +165 -493
  36. package/dist/frontendTypes.js +0 -45
  37. package/dist/helpers.js +0 -53
  38. package/dist/index.js +0 -25
  39. package/dist/logger/export.js +0 -1
  40. package/dist/matter/behaviors.js +0 -2
  41. package/dist/matter/clusters.js +0 -2
  42. package/dist/matter/devices.js +0 -2
  43. package/dist/matter/endpoints.js +0 -2
  44. package/dist/matter/export.js +0 -3
  45. package/dist/matter/types.js +0 -3
  46. package/dist/matterbridge.js +53 -828
  47. package/dist/matterbridgeAccessoryPlatform.js +0 -37
  48. package/dist/matterbridgeBehaviors.js +5 -68
  49. package/dist/matterbridgeDeviceTypes.js +17 -638
  50. package/dist/matterbridgeDynamicPlatform.js +0 -37
  51. package/dist/matterbridgeEndpoint.js +52 -1402
  52. package/dist/matterbridgeEndpointHelpers.js +19 -464
  53. package/dist/matterbridgePlatform.js +1 -341
  54. package/dist/matterbridgeTypes.js +0 -26
  55. package/dist/pluginManager.js +11 -319
  56. package/dist/shelly.js +7 -168
  57. package/dist/storage/export.js +0 -1
  58. package/dist/update.js +0 -69
  59. package/dist/utils/colorUtils.js +2 -97
  60. package/dist/utils/commandLine.js +0 -60
  61. package/dist/utils/copyDirectory.js +1 -38
  62. package/dist/utils/createDirectory.js +0 -33
  63. package/dist/utils/createZip.js +2 -47
  64. package/dist/utils/deepCopy.js +0 -39
  65. package/dist/utils/deepEqual.js +1 -72
  66. package/dist/utils/error.js +0 -41
  67. package/dist/utils/export.js +0 -1
  68. package/dist/utils/format.js +0 -49
  69. package/dist/utils/hex.js +0 -124
  70. package/dist/utils/inspector.js +1 -69
  71. package/dist/utils/isvalid.js +0 -101
  72. package/dist/utils/jestHelpers.js +3 -153
  73. package/dist/utils/network.js +5 -96
  74. package/dist/utils/spawn.js +0 -71
  75. package/dist/utils/tracker.js +1 -64
  76. package/dist/utils/wait.js +8 -60
  77. package/frontend/build/assets/index.js +4 -4
  78. package/frontend/package.json +1 -1
  79. package/npm-shrinkwrap.json +2 -2
  80. package/package.json +1 -2
  81. package/dist/broadcastServer.d.ts +0 -112
  82. package/dist/broadcastServer.d.ts.map +0 -1
  83. package/dist/broadcastServer.js.map +0 -1
  84. package/dist/broadcastServerTypes.d.ts +0 -793
  85. package/dist/broadcastServerTypes.d.ts.map +0 -1
  86. package/dist/broadcastServerTypes.js.map +0 -1
  87. package/dist/cli.d.ts +0 -30
  88. package/dist/cli.d.ts.map +0 -1
  89. package/dist/cli.js.map +0 -1
  90. package/dist/cliEmitter.d.ts +0 -50
  91. package/dist/cliEmitter.d.ts.map +0 -1
  92. package/dist/cliEmitter.js.map +0 -1
  93. package/dist/cliHistory.d.ts +0 -48
  94. package/dist/cliHistory.d.ts.map +0 -1
  95. package/dist/cliHistory.js.map +0 -1
  96. package/dist/clusters/export.d.ts +0 -2
  97. package/dist/clusters/export.d.ts.map +0 -1
  98. package/dist/clusters/export.js.map +0 -1
  99. package/dist/defaultConfigSchema.d.ts +0 -28
  100. package/dist/defaultConfigSchema.d.ts.map +0 -1
  101. package/dist/defaultConfigSchema.js.map +0 -1
  102. package/dist/deviceManager.d.ts +0 -117
  103. package/dist/deviceManager.d.ts.map +0 -1
  104. package/dist/deviceManager.js.map +0 -1
  105. package/dist/devices/airConditioner.d.ts +0 -98
  106. package/dist/devices/airConditioner.d.ts.map +0 -1
  107. package/dist/devices/airConditioner.js.map +0 -1
  108. package/dist/devices/batteryStorage.d.ts +0 -48
  109. package/dist/devices/batteryStorage.d.ts.map +0 -1
  110. package/dist/devices/batteryStorage.js.map +0 -1
  111. package/dist/devices/cooktop.d.ts +0 -60
  112. package/dist/devices/cooktop.d.ts.map +0 -1
  113. package/dist/devices/cooktop.js.map +0 -1
  114. package/dist/devices/dishwasher.d.ts +0 -71
  115. package/dist/devices/dishwasher.d.ts.map +0 -1
  116. package/dist/devices/dishwasher.js.map +0 -1
  117. package/dist/devices/evse.d.ts +0 -76
  118. package/dist/devices/evse.d.ts.map +0 -1
  119. package/dist/devices/evse.js.map +0 -1
  120. package/dist/devices/export.d.ts +0 -17
  121. package/dist/devices/export.d.ts.map +0 -1
  122. package/dist/devices/export.js.map +0 -1
  123. package/dist/devices/extractorHood.d.ts +0 -46
  124. package/dist/devices/extractorHood.d.ts.map +0 -1
  125. package/dist/devices/extractorHood.js.map +0 -1
  126. package/dist/devices/heatPump.d.ts +0 -47
  127. package/dist/devices/heatPump.d.ts.map +0 -1
  128. package/dist/devices/heatPump.js.map +0 -1
  129. package/dist/devices/laundryDryer.d.ts +0 -67
  130. package/dist/devices/laundryDryer.d.ts.map +0 -1
  131. package/dist/devices/laundryDryer.js.map +0 -1
  132. package/dist/devices/laundryWasher.d.ts +0 -81
  133. package/dist/devices/laundryWasher.d.ts.map +0 -1
  134. package/dist/devices/laundryWasher.js.map +0 -1
  135. package/dist/devices/microwaveOven.d.ts +0 -168
  136. package/dist/devices/microwaveOven.d.ts.map +0 -1
  137. package/dist/devices/microwaveOven.js.map +0 -1
  138. package/dist/devices/oven.d.ts +0 -105
  139. package/dist/devices/oven.d.ts.map +0 -1
  140. package/dist/devices/oven.js.map +0 -1
  141. package/dist/devices/refrigerator.d.ts +0 -118
  142. package/dist/devices/refrigerator.d.ts.map +0 -1
  143. package/dist/devices/refrigerator.js.map +0 -1
  144. package/dist/devices/roboticVacuumCleaner.d.ts +0 -112
  145. package/dist/devices/roboticVacuumCleaner.d.ts.map +0 -1
  146. package/dist/devices/roboticVacuumCleaner.js.map +0 -1
  147. package/dist/devices/solarPower.d.ts +0 -40
  148. package/dist/devices/solarPower.d.ts.map +0 -1
  149. package/dist/devices/solarPower.js.map +0 -1
  150. package/dist/devices/speaker.d.ts +0 -87
  151. package/dist/devices/speaker.d.ts.map +0 -1
  152. package/dist/devices/speaker.js.map +0 -1
  153. package/dist/devices/temperatureControl.d.ts +0 -166
  154. package/dist/devices/temperatureControl.d.ts.map +0 -1
  155. package/dist/devices/temperatureControl.js.map +0 -1
  156. package/dist/devices/waterHeater.d.ts +0 -111
  157. package/dist/devices/waterHeater.d.ts.map +0 -1
  158. package/dist/devices/waterHeater.js.map +0 -1
  159. package/dist/dgram/coap.d.ts +0 -205
  160. package/dist/dgram/coap.d.ts.map +0 -1
  161. package/dist/dgram/coap.js.map +0 -1
  162. package/dist/dgram/dgram.d.ts +0 -141
  163. package/dist/dgram/dgram.d.ts.map +0 -1
  164. package/dist/dgram/dgram.js.map +0 -1
  165. package/dist/dgram/mb_coap.d.ts +0 -24
  166. package/dist/dgram/mb_coap.d.ts.map +0 -1
  167. package/dist/dgram/mb_coap.js.map +0 -1
  168. package/dist/dgram/mb_mdns.d.ts +0 -24
  169. package/dist/dgram/mb_mdns.d.ts.map +0 -1
  170. package/dist/dgram/mb_mdns.js.map +0 -1
  171. package/dist/dgram/mdns.d.ts +0 -290
  172. package/dist/dgram/mdns.d.ts.map +0 -1
  173. package/dist/dgram/mdns.js.map +0 -1
  174. package/dist/dgram/multicast.d.ts +0 -67
  175. package/dist/dgram/multicast.d.ts.map +0 -1
  176. package/dist/dgram/multicast.js.map +0 -1
  177. package/dist/dgram/unicast.d.ts +0 -56
  178. package/dist/dgram/unicast.d.ts.map +0 -1
  179. package/dist/dgram/unicast.js.map +0 -1
  180. package/dist/frontend.d.ts +0 -235
  181. package/dist/frontend.d.ts.map +0 -1
  182. package/dist/frontend.js.map +0 -1
  183. package/dist/frontendTypes.d.ts +0 -529
  184. package/dist/frontendTypes.d.ts.map +0 -1
  185. package/dist/frontendTypes.js.map +0 -1
  186. package/dist/helpers.d.ts +0 -48
  187. package/dist/helpers.d.ts.map +0 -1
  188. package/dist/helpers.js.map +0 -1
  189. package/dist/index.d.ts +0 -33
  190. package/dist/index.d.ts.map +0 -1
  191. package/dist/index.js.map +0 -1
  192. package/dist/logger/export.d.ts +0 -2
  193. package/dist/logger/export.d.ts.map +0 -1
  194. package/dist/logger/export.js.map +0 -1
  195. package/dist/matter/behaviors.d.ts +0 -2
  196. package/dist/matter/behaviors.d.ts.map +0 -1
  197. package/dist/matter/behaviors.js.map +0 -1
  198. package/dist/matter/clusters.d.ts +0 -2
  199. package/dist/matter/clusters.d.ts.map +0 -1
  200. package/dist/matter/clusters.js.map +0 -1
  201. package/dist/matter/devices.d.ts +0 -2
  202. package/dist/matter/devices.d.ts.map +0 -1
  203. package/dist/matter/devices.js.map +0 -1
  204. package/dist/matter/endpoints.d.ts +0 -2
  205. package/dist/matter/endpoints.d.ts.map +0 -1
  206. package/dist/matter/endpoints.js.map +0 -1
  207. package/dist/matter/export.d.ts +0 -5
  208. package/dist/matter/export.d.ts.map +0 -1
  209. package/dist/matter/export.js.map +0 -1
  210. package/dist/matter/types.d.ts +0 -3
  211. package/dist/matter/types.d.ts.map +0 -1
  212. package/dist/matter/types.js.map +0 -1
  213. package/dist/matterbridge.d.ts +0 -475
  214. package/dist/matterbridge.d.ts.map +0 -1
  215. package/dist/matterbridge.js.map +0 -1
  216. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -42
  217. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  218. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  219. package/dist/matterbridgeBehaviors.d.ts +0 -2404
  220. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  221. package/dist/matterbridgeBehaviors.js.map +0 -1
  222. package/dist/matterbridgeDeviceTypes.d.ts +0 -770
  223. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  224. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  225. package/dist/matterbridgeDynamicPlatform.d.ts +0 -42
  226. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  227. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  228. package/dist/matterbridgeEndpoint.d.ts +0 -1550
  229. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  230. package/dist/matterbridgeEndpoint.js.map +0 -1
  231. package/dist/matterbridgeEndpointHelpers.d.ts +0 -758
  232. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  233. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  234. package/dist/matterbridgePlatform.d.ts +0 -402
  235. package/dist/matterbridgePlatform.d.ts.map +0 -1
  236. package/dist/matterbridgePlatform.js.map +0 -1
  237. package/dist/matterbridgeTypes.d.ts +0 -226
  238. package/dist/matterbridgeTypes.d.ts.map +0 -1
  239. package/dist/matterbridgeTypes.js.map +0 -1
  240. package/dist/pluginManager.d.ts +0 -347
  241. package/dist/pluginManager.d.ts.map +0 -1
  242. package/dist/pluginManager.js.map +0 -1
  243. package/dist/shelly.d.ts +0 -174
  244. package/dist/shelly.d.ts.map +0 -1
  245. package/dist/shelly.js.map +0 -1
  246. package/dist/storage/export.d.ts +0 -2
  247. package/dist/storage/export.d.ts.map +0 -1
  248. package/dist/storage/export.js.map +0 -1
  249. package/dist/update.d.ts +0 -75
  250. package/dist/update.d.ts.map +0 -1
  251. package/dist/update.js.map +0 -1
  252. package/dist/utils/colorUtils.d.ts +0 -99
  253. package/dist/utils/colorUtils.d.ts.map +0 -1
  254. package/dist/utils/colorUtils.js.map +0 -1
  255. package/dist/utils/commandLine.d.ts +0 -66
  256. package/dist/utils/commandLine.d.ts.map +0 -1
  257. package/dist/utils/commandLine.js.map +0 -1
  258. package/dist/utils/copyDirectory.d.ts +0 -33
  259. package/dist/utils/copyDirectory.d.ts.map +0 -1
  260. package/dist/utils/copyDirectory.js.map +0 -1
  261. package/dist/utils/createDirectory.d.ts +0 -34
  262. package/dist/utils/createDirectory.d.ts.map +0 -1
  263. package/dist/utils/createDirectory.js.map +0 -1
  264. package/dist/utils/createZip.d.ts +0 -39
  265. package/dist/utils/createZip.d.ts.map +0 -1
  266. package/dist/utils/createZip.js.map +0 -1
  267. package/dist/utils/deepCopy.d.ts +0 -32
  268. package/dist/utils/deepCopy.d.ts.map +0 -1
  269. package/dist/utils/deepCopy.js.map +0 -1
  270. package/dist/utils/deepEqual.d.ts +0 -54
  271. package/dist/utils/deepEqual.d.ts.map +0 -1
  272. package/dist/utils/deepEqual.js.map +0 -1
  273. package/dist/utils/error.d.ts +0 -44
  274. package/dist/utils/error.d.ts.map +0 -1
  275. package/dist/utils/error.js.map +0 -1
  276. package/dist/utils/export.d.ts +0 -13
  277. package/dist/utils/export.d.ts.map +0 -1
  278. package/dist/utils/export.js.map +0 -1
  279. package/dist/utils/format.d.ts +0 -53
  280. package/dist/utils/format.d.ts.map +0 -1
  281. package/dist/utils/format.js.map +0 -1
  282. package/dist/utils/hex.d.ts +0 -89
  283. package/dist/utils/hex.d.ts.map +0 -1
  284. package/dist/utils/hex.js.map +0 -1
  285. package/dist/utils/inspector.d.ts +0 -87
  286. package/dist/utils/inspector.d.ts.map +0 -1
  287. package/dist/utils/inspector.js.map +0 -1
  288. package/dist/utils/isvalid.d.ts +0 -103
  289. package/dist/utils/isvalid.d.ts.map +0 -1
  290. package/dist/utils/isvalid.js.map +0 -1
  291. package/dist/utils/jestHelpers.d.ts +0 -139
  292. package/dist/utils/jestHelpers.d.ts.map +0 -1
  293. package/dist/utils/jestHelpers.js.map +0 -1
  294. package/dist/utils/network.d.ts +0 -101
  295. package/dist/utils/network.d.ts.map +0 -1
  296. package/dist/utils/network.js.map +0 -1
  297. package/dist/utils/spawn.d.ts +0 -35
  298. package/dist/utils/spawn.d.ts.map +0 -1
  299. package/dist/utils/spawn.js.map +0 -1
  300. package/dist/utils/tracker.d.ts +0 -108
  301. package/dist/utils/tracker.d.ts.map +0 -1
  302. package/dist/utils/tracker.js.map +0 -1
  303. package/dist/utils/wait.d.ts +0 -54
  304. package/dist/utils/wait.d.ts.map +0 -1
  305. package/dist/utils/wait.js.map +0 -1
@@ -1,48 +1,19 @@
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
- // eslint-disable-next-line no-console
25
1
  if (process.argv.includes('--loader') || process.argv.includes('-loader'))
26
2
  console.log('\u001B[32mMatterbridge loaded.\u001B[40;0m');
27
- // Node.js modules
28
3
  import os from 'node:os';
29
4
  import path from 'node:path';
30
5
  import { promises as fs } from 'node:fs';
31
6
  import EventEmitter from 'node:events';
32
7
  import { inspect } from 'node:util';
33
- // AnsiLogger module
34
8
  import { AnsiLogger, UNDERLINE, UNDERLINEOFF, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN, nt, BLUE, or } from 'node-ansi-logger';
35
- // NodeStorage module
36
9
  import { NodeStorageManager } from 'node-persist-manager';
37
- // @matter
38
- import '@matter/nodejs'; // Set up Node.js environment for matter.js
10
+ import '@matter/nodejs';
39
11
  import { Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, UINT32_MAX, UINT16_MAX, Crypto, Environment, StorageService } from '@matter/general';
40
12
  import { FabricAction, PaseClient } from '@matter/protocol';
41
13
  import { Endpoint, ServerNode } from '@matter/node';
42
14
  import { DeviceTypeId, VendorId } from '@matter/types/datatype';
43
15
  import { AggregatorEndpoint } from '@matter/node/endpoints';
44
16
  import { BasicInformationServer } from '@matter/node/behaviors/basic-information';
45
- // Matterbridge
46
17
  import { getParameter, getIntParameter, hasParameter } from './utils/commandLine.js';
47
18
  import { copyDirectory } from './utils/copyDirectory.js';
48
19
  import { createDirectory } from './utils/createDirectory.js';
@@ -57,27 +28,19 @@ import { bridge } from './matterbridgeDeviceTypes.js';
57
28
  import { Frontend } from './frontend.js';
58
29
  import { addVirtualDevices } from './helpers.js';
59
30
  import { BroadcastServer } from './broadcastServer.js';
60
- /**
61
- * Represents the Matterbridge application.
62
- */
63
31
  export class Matterbridge extends EventEmitter {
64
- /** Matterbridge system information */
65
32
  systemInformation = {
66
- // Network properties
67
33
  interfaceName: '',
68
34
  macAddress: '',
69
35
  ipv4Address: '',
70
36
  ipv6Address: '',
71
- // Node.js properties
72
37
  nodeVersion: '',
73
- // Fixed system properties
74
38
  hostname: '',
75
39
  user: '',
76
40
  osType: '',
77
41
  osRelease: '',
78
42
  osPlatform: '',
79
43
  osArch: '',
80
- // Cpu and memory properties
81
44
  totalMemory: '',
82
45
  freeMemory: '',
83
46
  systemUptime: '',
@@ -88,7 +51,6 @@ export class Matterbridge extends EventEmitter {
88
51
  heapTotal: '',
89
52
  heapUsed: '',
90
53
  };
91
- // Matterbridge settings
92
54
  homeDirectory = '';
93
55
  rootDirectory = '';
94
56
  matterbridgeDirectory = '';
@@ -103,15 +65,10 @@ export class Matterbridge extends EventEmitter {
103
65
  restartMode = '';
104
66
  virtualMode = 'outlet';
105
67
  profile = getParameter('profile');
106
- /** Matterbridge logger */
107
- log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
108
- /** Whether to log to a file */
68
+ log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
109
69
  fileLogger = false;
110
- /** Matter logger */
111
- matterLog = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
112
- /** Whether to log Matter to a file */
70
+ matterLog = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
113
71
  matterFileLogger = false;
114
- // Frontend settings
115
72
  readOnly = hasParameter('readonly') || hasParameter('shelly');
116
73
  shellyBoard = hasParameter('shelly');
117
74
  shellySysUpdate = false;
@@ -119,18 +76,12 @@ export class Matterbridge extends EventEmitter {
119
76
  restartRequired = false;
120
77
  fixedRestartRequired = false;
121
78
  updateRequired = false;
122
- // Managers
123
79
  plugins = new PluginManager(this);
124
80
  devices = new DeviceManager();
125
- // Frontend
126
81
  frontend = new Frontend(this);
127
- /** Matterbridge node storage manager created in the directory 'storage' in matterbridgeDirectory */
128
82
  nodeStorage;
129
- /** Matterbridge node context created with name 'matterbridge' */
130
83
  nodeContext;
131
- /** The main instance of the Matterbridge class (singleton) */
132
84
  static instance;
133
- // Instance properties
134
85
  shutdown = false;
135
86
  failCountLimit = hasParameter('shelly') ? 600 : 120;
136
87
  hasCleanupStarted = false;
@@ -145,32 +96,19 @@ export class Matterbridge extends EventEmitter {
145
96
  sigtermHandler;
146
97
  exceptionHandler;
147
98
  rejectionHandler;
148
- /** Matter environment default */
149
99
  environment = Environment.default;
150
- /** Matter storage service from environment default */
151
100
  matterStorageService;
152
- /** Matter storage manager created with name 'Matterbridge' */
153
101
  matterStorageManager;
154
- /** Matter matterbridge storage context created in the storage manager with name 'persist' */
155
102
  matterbridgeContext;
156
103
  controllerContext;
157
- /** Matter mdns interface e.g. 'eth0' or 'wlan0' or 'Wi-Fi' */
158
104
  mdnsInterface;
159
- /** Matter listeningAddressIpv4 address */
160
105
  ipv4Address;
161
- /** Matter listeningAddressIpv6 address */
162
106
  ipv6Address;
163
- /** Matter commissioning port */
164
- port; // first server node port
165
- /** Matter commissioning passcode */
166
- passcode; // first server node passcode
167
- /** Matter commissioning discriminator */
168
- discriminator; // first server node discriminator
169
- /** Matter device certification */
170
- certification; // device certification
171
- /** Matter server node in bridge mode */
107
+ port;
108
+ passcode;
109
+ discriminator;
110
+ certification;
172
111
  serverNode;
173
- /** Matter aggregator node in bridge mode */
174
112
  aggregatorNode;
175
113
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
176
114
  aggregatorVendorName = getParameter('vendorName') ?? 'Matterbridge';
@@ -179,17 +117,17 @@ export class Matterbridge extends EventEmitter {
179
117
  aggregatorDeviceType = DeviceTypeId(getIntParameter('deviceType') ?? bridge.code);
180
118
  aggregatorSerialNumber = getParameter('serialNumber');
181
119
  aggregatorUniqueId = getParameter('uniqueId');
182
- /** Advertising nodes map: time advertising started keyed by storeId */
183
120
  advertisingNodes = new Map();
184
- /** Broadcast server */
185
121
  server;
186
- /** We load asyncronously so is private */
187
122
  constructor() {
188
123
  super();
189
124
  this.log.logNameColor = '\x1b[38;5;115m';
190
125
  this.server = new BroadcastServer('matterbridge', this.log);
191
126
  this.server.on('broadcast_message', this.msgHandler.bind(this));
192
127
  }
128
+ destroy() {
129
+ this.server.close();
130
+ }
193
131
  async msgHandler(msg) {
194
132
  if (this.server.isWorkerRequest(msg, msg.type) && (msg.dst === 'all' || msg.dst === 'matterbridge')) {
195
133
  this.log.debug(`**Received broadcast request ${CYAN}${msg.type}${db} from ${CYAN}${msg.src}${db}: ${debugStringify(msg)}${db}`);
@@ -208,24 +146,16 @@ export class Matterbridge extends EventEmitter {
208
146
  if (this.server.isWorkerResponse(msg, msg.type)) {
209
147
  this.log.debug(`**Received broadcast response ${CYAN}${msg.type}${db} from ${CYAN}${msg.src}${db}: ${debugStringify(msg)}${db}`);
210
148
  switch (msg.type) {
149
+ case 'get_log_level':
150
+ case 'set_log_level':
151
+ break;
211
152
  default:
212
153
  this.log.debug(`Unknown broadcast response ${CYAN}${msg.type}${db} from ${CYAN}${msg.src}${db}`);
213
154
  }
214
155
  }
215
156
  }
216
- //* ************************************************************************************************************************************ */
217
- // loadInstance() and cleanup() methods */
218
- //* ************************************************************************************************************************************ */
219
- /**
220
- * Loads an instance of the Matterbridge class.
221
- * If an instance already exists, return that instance.
222
- *
223
- * @param {boolean} initialize - Whether to initialize the Matterbridge instance after loading. Defaults to false.
224
- * @returns {Matterbridge} A promise that resolves to the Matterbridge instance.
225
- */
226
157
  static async loadInstance(initialize = false) {
227
158
  if (!Matterbridge.instance) {
228
- // eslint-disable-next-line no-console
229
159
  if (hasParameter('debug'))
230
160
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
231
161
  Matterbridge.instance = new Matterbridge();
@@ -234,131 +164,62 @@ export class Matterbridge extends EventEmitter {
234
164
  }
235
165
  return Matterbridge.instance;
236
166
  }
237
- /**
238
- * Call cleanup() and dispose MdnsService. Will be removed since matter.js 0.15.6 dispose MdnsService.
239
- *
240
- * @param {number} [timeout] - The timeout duration to wait for the cleanup to complete in milliseconds. Default is 1000.
241
- * @param {number} [pause] - The pause duration after the cleanup in milliseconds. Default is 250.
242
- *
243
- * @deprecated This method is deprecated and is ONLY used for jest tests.
244
- */
245
167
  async destroyInstance(timeout = 1000, pause = 250) {
246
168
  this.log.info(`Destroy instance...`);
247
- // Save server nodes to close
248
- /*
249
- const servers: ServerNode<ServerNode.RootEndpoint>[] = [];
250
- if (this.bridgeMode === 'bridge') {
251
- if (this.serverNode) servers.push(this.serverNode);
252
- }
253
- if (this.bridgeMode === 'childbridge' && this.plugins !== undefined) {
254
- for (const plugin of this.plugins.array()) {
255
- if (plugin.serverNode) servers.push(plugin.serverNode);
256
- }
257
- }
258
- if (this.devices !== undefined) {
259
- for (const device of this.devices.array()) {
260
- if (device.mode === 'server' && device.serverNode) servers.push(device.serverNode);
261
- }
262
- }
263
- */
264
- // Let any already‐queued microtasks run first
265
- // await Promise.resolve();
266
- // Wait for the cleanup to finish
267
- // await wait(pause, 'destroyInstance start', true);
268
- // Cleanup
269
169
  await this.cleanup('destroying instance...', false, timeout);
270
- // Close servers mdns service
271
- /*
272
- this.log.info(`Dispose ${servers.length} MdnsService...`);
273
- for (const server of servers) {
274
- // await server.env.get(MdnsService)[Symbol.asyncDispose]();
275
- this.log.info(`Closed ${server.id} MdnsService`);
276
- }
277
- */
278
- // Let any already‐queued microtasks run first
279
- // await Promise.resolve();
280
- // Wait for the cleanup to finish
281
170
  if (pause)
282
171
  await wait(pause, 'destroyInstance stop', true);
283
172
  }
284
- /**
285
- * Initializes the Matterbridge application.
286
- *
287
- * @remarks
288
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
289
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
290
- * node version, registers signal handlers, initializes storage, and parses the command line.
291
- *
292
- * @returns {Promise<void>} A Promise that resolves when the initialization is complete.
293
- */
294
173
  async initialize() {
295
- // for (let i = 1; i <= 255; i++) console.log(`\x1b[38;5;${i}mColor: ${i}`);
296
- // Emit the initialize_started event
297
174
  this.emit('initialize_started');
298
- // Set the restart mode
299
175
  if (hasParameter('service'))
300
176
  this.restartMode = 'service';
301
177
  if (hasParameter('docker'))
302
178
  this.restartMode = 'docker';
303
- // Set the matterbridge home directory
304
179
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
305
180
  await createDirectory(this.homeDirectory, 'Matterbridge Home Directory', this.log);
306
- // Set the matterbridge directory
307
181
  this.matterbridgeDirectory = this.profile ? path.join(this.homeDirectory, '.matterbridge', 'profiles', this.profile) : path.join(this.homeDirectory, '.matterbridge');
308
182
  await createDirectory(this.matterbridgeDirectory, 'Matterbridge Directory', this.log);
309
183
  await createDirectory(path.join(this.matterbridgeDirectory, 'certs'), 'Matterbridge Frontend Certificate Directory', this.log);
310
184
  await createDirectory(path.join(this.matterbridgeDirectory, 'uploads'), 'Matterbridge Frontend Uploads Directory', this.log);
311
- // Set the matterbridge plugin directory
312
185
  this.matterbridgePluginDirectory = this.profile ? path.join(this.homeDirectory, 'Matterbridge', 'profiles', this.profile) : path.join(this.homeDirectory, 'Matterbridge');
313
186
  await createDirectory(this.matterbridgePluginDirectory, 'Matterbridge Plugin Directory', this.log);
314
- // Set the matterbridge cert directory
315
187
  this.matterbridgeCertDirectory = this.profile ? path.join(this.homeDirectory, '.mattercert', 'profiles', this.profile) : path.join(this.homeDirectory, '.mattercert');
316
188
  await createDirectory(this.matterbridgeCertDirectory, 'Matterbridge Matter Certificate Directory', this.log);
317
- // Set the matterbridge root directory
318
189
  const { fileURLToPath } = await import('node:url');
319
190
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
320
- this.rootDirectory = path.resolve(currentFileDirectory, '../'); // Adjust the path for dist directory
321
- // Setup the matter environment with default values
191
+ this.rootDirectory = path.resolve(currentFileDirectory, '../');
322
192
  this.environment.vars.set('log.level', MatterLogLevel.INFO);
323
193
  this.environment.vars.set('log.format', MatterLogFormat.ANSI);
324
194
  this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME));
325
195
  this.environment.vars.set('runtime.signals', false);
326
196
  this.environment.vars.set('runtime.exitcode', false);
327
- // Register process handlers
328
197
  this.registerProcessHandlers();
329
- // Initialize nodeStorage and nodeContext
330
198
  try {
331
199
  this.log.debug(`Creating node storage manager: ${CYAN}${NODE_STORAGE_DIR}${db}`);
332
200
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, NODE_STORAGE_DIR), writeQueue: false, expiredInterval: undefined, logging: false });
333
201
  this.log.debug('Creating node storage context for matterbridge');
334
202
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
335
- // TODO: Remove this code when node-persist-manager is updated
336
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
337
203
  const keys = (await this.nodeStorage?.storage.keys());
338
204
  for (const key of keys) {
339
205
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
340
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
341
206
  await this.nodeStorage?.storage.get(key);
342
207
  }
343
208
  const storages = await this.nodeStorage.getStorageNames();
344
209
  for (const storage of storages) {
345
210
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
346
211
  const nodeContext = await this.nodeStorage?.createStorage(storage);
347
- // TODO: Remove this code when node-persist-manager is updated
348
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
349
212
  const keys = (await nodeContext?.storage.keys());
350
213
  keys.forEach(async (key) => {
351
214
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
352
215
  await nodeContext?.get(key);
353
216
  });
354
217
  }
355
- // Creating a backup of the node storage since it is not corrupted
356
218
  this.log.debug('Creating node storage backup...');
357
219
  await copyDirectory(path.join(this.matterbridgeDirectory, NODE_STORAGE_DIR), path.join(this.matterbridgeDirectory, NODE_STORAGE_DIR + '.backup'));
358
220
  this.log.debug('Created node storage backup');
359
221
  }
360
222
  catch (error) {
361
- // Restoring the backup of the node storage since it is corrupted
362
223
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
363
224
  if (hasParameter('norestore')) {
364
225
  this.log.fatal(`The matterbridge storage is corrupted. Found -norestore parameter: exiting...`);
@@ -372,19 +233,14 @@ export class Matterbridge extends EventEmitter {
372
233
  if (!this.nodeStorage || !this.nodeContext) {
373
234
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
374
235
  }
375
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
376
236
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
377
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
378
237
  this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode')) ?? PaseClient.generateRandomPasscode(this.environment.get(Crypto));
379
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
380
238
  this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator')) ?? PaseClient.generateRandomDiscriminator(this.environment.get(Crypto));
381
- // Certificate management
382
239
  const pairingFilePath = path.join(this.matterbridgeCertDirectory, 'pairing.json');
383
240
  try {
384
241
  await fs.access(pairingFilePath, fs.constants.R_OK);
385
242
  const pairingFileContent = await fs.readFile(pairingFilePath, 'utf8');
386
243
  const pairingFileJson = JSON.parse(pairingFileContent);
387
- // Set the vendorId, vendorName, productId, productName, deviceType, serialNumber, uniqueId if they are present in the pairing file
388
244
  if (isValidNumber(pairingFileJson.vendorId)) {
389
245
  this.aggregatorVendorId = VendorId(pairingFileJson.vendorId);
390
246
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using vendorId ${CYAN}${this.aggregatorVendorId}${nf} from pairing file.`);
@@ -413,13 +269,11 @@ export class Matterbridge extends EventEmitter {
413
269
  this.aggregatorUniqueId = pairingFileJson.uniqueId;
414
270
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using uniqueId ${CYAN}${this.aggregatorUniqueId}${nf} from pairing file.`);
415
271
  }
416
- // Override the passcode and discriminator if they are present in the pairing file
417
272
  if (isValidNumber(pairingFileJson.passcode) && isValidNumber(pairingFileJson.discriminator)) {
418
273
  this.passcode = pairingFileJson.passcode;
419
274
  this.discriminator = pairingFileJson.discriminator;
420
275
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using passcode ${CYAN}${this.passcode}${nf} and discriminator ${CYAN}${this.discriminator}${nf} from pairing file.`);
421
276
  }
422
- // Set the certification for matter.js if it is present in the pairing file
423
277
  if (pairingFileJson.privateKey && pairingFileJson.certificate && pairingFileJson.intermediateCertificate && pairingFileJson.declaration) {
424
278
  const { hexToBuffer } = await import('./utils/hex.js');
425
279
  this.certification = {
@@ -434,43 +288,40 @@ export class Matterbridge extends EventEmitter {
434
288
  catch (error) {
435
289
  this.log.debug(`Pairing file ${CYAN}${pairingFilePath}${db} not found: ${error instanceof Error ? error.message : error}`);
436
290
  }
437
- // Store the passcode, discriminator and port in the node context
438
291
  await this.nodeContext.set('matterport', this.port);
439
292
  await this.nodeContext.set('matterpasscode', this.passcode);
440
293
  await this.nodeContext.set('matterdiscriminator', this.discriminator);
441
294
  this.log.debug(`Initializing server node for Matterbridge on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
442
- // Set matterbridge logger level (context: matterbridgeLogLevel)
443
295
  if (hasParameter('logger')) {
444
296
  const level = getParameter('logger');
445
297
  if (level === 'debug') {
446
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
298
+ this.log.logLevel = "debug";
447
299
  }
448
300
  else if (level === 'info') {
449
- this.log.logLevel = "info" /* LogLevel.INFO */;
301
+ this.log.logLevel = "info";
450
302
  }
451
303
  else if (level === 'notice') {
452
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
304
+ this.log.logLevel = "notice";
453
305
  }
454
306
  else if (level === 'warn') {
455
- this.log.logLevel = "warn" /* LogLevel.WARN */;
307
+ this.log.logLevel = "warn";
456
308
  }
457
309
  else if (level === 'error') {
458
- this.log.logLevel = "error" /* LogLevel.ERROR */;
310
+ this.log.logLevel = "error";
459
311
  }
460
312
  else if (level === 'fatal') {
461
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
313
+ this.log.logLevel = "fatal";
462
314
  }
463
315
  else {
464
316
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
465
- this.log.logLevel = "info" /* LogLevel.INFO */;
317
+ this.log.logLevel = "info";
466
318
  }
467
319
  }
468
320
  else {
469
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.shellyBoard ? "notice" /* LogLevel.NOTICE */ : "info" /* LogLevel.INFO */);
321
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.shellyBoard ? "notice" : "info");
470
322
  }
471
323
  this.frontend.logLevel = this.log.logLevel;
472
324
  MatterbridgeEndpoint.logLevel = this.log.logLevel;
473
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
474
325
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
475
326
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, MATTERBRIDGE_LOGGER_FILE), this.log.logLevel, true);
476
327
  this.fileLogger = true;
@@ -479,7 +330,6 @@ export class Matterbridge extends EventEmitter {
479
330
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.fileLogger}.`);
480
331
  if (this.profile !== undefined)
481
332
  this.log.debug(`Matterbridge profile: ${this.profile}.`);
482
- // Set matter.js logger level, format and logger (context: matterLogLevel)
483
333
  if (hasParameter('matterlogger')) {
484
334
  const level = getParameter('matterlogger');
485
335
  if (level === 'debug') {
@@ -509,13 +359,11 @@ export class Matterbridge extends EventEmitter {
509
359
  Logger.level = (await this.nodeContext.get('matterLogLevel', this.shellyBoard ? MatterLogLevel.NOTICE : MatterLogLevel.INFO));
510
360
  }
511
361
  Logger.format = MatterLogFormat.ANSI;
512
- // Create the logger for matter.js with file logging (context: matterFileLog)
513
362
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
514
363
  this.matterFileLogger = true;
515
364
  }
516
365
  Logger.destinations.default.write = this.createDestinationMatterLogger(this.matterFileLogger);
517
366
  this.log.debug(`Matter logLevel: ${Logger.level} fileLoger: ${this.matterFileLogger}.`);
518
- // Log network interfaces
519
367
  const networkInterfaces = os.networkInterfaces();
520
368
  const availableAddresses = Object.entries(networkInterfaces);
521
369
  const availableInterfaceNames = Object.keys(networkInterfaces);
@@ -528,7 +376,6 @@ export class Matterbridge extends EventEmitter {
528
376
  });
529
377
  }
530
378
  }
531
- // Set the interface to use for matter server node mdnsInterface
532
379
  if (hasParameter('mdnsinterface')) {
533
380
  this.mdnsInterface = getParameter('mdnsinterface');
534
381
  }
@@ -537,7 +384,6 @@ export class Matterbridge extends EventEmitter {
537
384
  if (this.mdnsInterface === '')
538
385
  this.mdnsInterface = undefined;
539
386
  }
540
- // Validate mdnsInterface
541
387
  if (this.mdnsInterface) {
542
388
  if (!availableInterfaceNames.includes(this.mdnsInterface)) {
543
389
  this.log.error(`Invalid mdnsinterface: ${this.mdnsInterface}. Available interfaces are: ${availableInterfaceNames.join(', ')}. Using all available interfaces.`);
@@ -550,7 +396,6 @@ export class Matterbridge extends EventEmitter {
550
396
  }
551
397
  if (this.mdnsInterface)
552
398
  this.environment.vars.set('mdns.networkInterface', this.mdnsInterface);
553
- // Set the listeningAddressIpv4 for the matter commissioning server
554
399
  if (hasParameter('ipv4address')) {
555
400
  this.ipv4Address = getParameter('ipv4address');
556
401
  }
@@ -559,7 +404,6 @@ export class Matterbridge extends EventEmitter {
559
404
  if (this.ipv4Address === '')
560
405
  this.ipv4Address = undefined;
561
406
  }
562
- // Validate ipv4address
563
407
  if (this.ipv4Address) {
564
408
  let isValid = false;
565
409
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -575,7 +419,6 @@ export class Matterbridge extends EventEmitter {
575
419
  await this.nodeContext.remove('matteripv4address');
576
420
  }
577
421
  }
578
- // Set the listeningAddressIpv6 for the matter commissioning server
579
422
  if (hasParameter('ipv6address')) {
580
423
  this.ipv6Address = getParameter('ipv6address');
581
424
  }
@@ -584,7 +427,6 @@ export class Matterbridge extends EventEmitter {
584
427
  if (this.ipv6Address === '')
585
428
  this.ipv6Address = undefined;
586
429
  }
587
- // Validate ipv6address
588
430
  if (this.ipv6Address) {
589
431
  let isValid = false;
590
432
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -593,7 +435,6 @@ export class Matterbridge extends EventEmitter {
593
435
  isValid = true;
594
436
  break;
595
437
  }
596
- /* istanbul ignore next */
597
438
  if (ifaces && ifaces.find((iface) => iface.scopeid && iface.scopeid > 0 && iface.address + '%' + (process.platform === 'win32' ? iface.scopeid : ifaceName) === this.ipv6Address)) {
598
439
  this.log.info(`Using ipv6address ${CYAN}${this.ipv6Address}${nf} on interface ${CYAN}${ifaceName}${nf} for the Matter server node.`);
599
440
  isValid = true;
@@ -606,7 +447,6 @@ export class Matterbridge extends EventEmitter {
606
447
  await this.nodeContext.remove('matteripv6address');
607
448
  }
608
449
  }
609
- // Initialize the virtual mode
610
450
  if (hasParameter('novirtual')) {
611
451
  this.virtualMode = 'disabled';
612
452
  await this.nodeContext.set('virtualmode', 'disabled');
@@ -615,17 +455,12 @@ export class Matterbridge extends EventEmitter {
615
455
  this.virtualMode = (await this.nodeContext.get('virtualmode', 'outlet'));
616
456
  }
617
457
  this.log.debug(`Virtual mode ${this.virtualMode}.`);
618
- // Initialize PluginManager
619
458
  this.plugins.logLevel = this.log.logLevel;
620
459
  await this.plugins.loadFromStorage();
621
- // Initialize DeviceManager
622
460
  this.devices.logLevel = this.log.logLevel;
623
- // Get the plugins from node storage and create the plugins node storage contexts
624
461
  for (const plugin of this.plugins) {
625
462
  const packageJson = await this.plugins.parse(plugin);
626
463
  if (packageJson === null && !hasParameter('add') && !hasParameter('remove') && !hasParameter('enable') && !hasParameter('disable') && !hasParameter('reset') && !hasParameter('factoryreset')) {
627
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
628
- // We don't do this when the add and other parameters are set because we shut down the process after adding the plugin
629
464
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
630
465
  try {
631
466
  const { spawnCommand } = await import('./utils/spawn.js');
@@ -648,7 +483,6 @@ export class Matterbridge extends EventEmitter {
648
483
  await plugin.nodeContext.set('description', plugin.description);
649
484
  await plugin.nodeContext.set('author', plugin.author);
650
485
  }
651
- // Log system info and create .matterbridge directory
652
486
  await this.logNodeAndSystemInfo();
653
487
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
654
488
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -656,7 +490,6 @@ export class Matterbridge extends EventEmitter {
656
490
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
657
491
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
658
492
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
659
- // Check node version and throw error
660
493
  const minNodeVersion = 20;
661
494
  const nodeVersion = process.versions.node;
662
495
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -664,18 +497,10 @@ export class Matterbridge extends EventEmitter {
664
497
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
665
498
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
666
499
  }
667
- // Parse command line
668
500
  await this.parseCommandLine();
669
- // Emit the initialize_completed event
670
501
  this.emit('initialize_completed');
671
502
  this.initialized = true;
672
503
  }
673
- /**
674
- * Parses the command line arguments and performs the corresponding actions.
675
- *
676
- * @private
677
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
678
- */
679
504
  async parseCommandLine() {
680
505
  if (hasParameter('list')) {
681
506
  this.log.info(`│ Registered plugins (${this.plugins.length})`);
@@ -691,19 +516,6 @@ export class Matterbridge extends EventEmitter {
691
516
  }
692
517
  index++;
693
518
  }
694
- /*
695
- const serializedRegisteredDevices = await this.nodeContext?.get<SerializedMatterbridgeEndpoint[]>('devices', []);
696
- this.log.info(`│ Registered devices (${serializedRegisteredDevices?.length})`);
697
- serializedRegisteredDevices?.forEach((device, index) => {
698
- if (index !== serializedRegisteredDevices.length - 1) {
699
- this.log.info(`├─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
700
- this.log.info(`│ └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
701
- } else {
702
- this.log.info(`└─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
703
- this.log.info(` └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
704
- }
705
- });
706
- */
707
519
  this.shutdown = true;
708
520
  return;
709
521
  }
@@ -753,10 +565,8 @@ export class Matterbridge extends EventEmitter {
753
565
  this.shutdown = true;
754
566
  return;
755
567
  }
756
- // Initialize frontend
757
568
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
758
569
  await this.frontend.start(getIntParameter('frontend'));
759
- // Start the matter storage and create the matterbridge context
760
570
  try {
761
571
  await this.startMatterStorage();
762
572
  if (this.aggregatorSerialNumber && this.aggregatorUniqueId && this.matterStorageService) {
@@ -770,21 +580,18 @@ export class Matterbridge extends EventEmitter {
770
580
  this.log.fatal(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
771
581
  throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
772
582
  }
773
- // Clear the matterbridge context if the reset parameter is set (bridge mode)
774
583
  if (hasParameter('reset') && getParameter('reset') === undefined) {
775
584
  this.initialized = true;
776
585
  await this.shutdownProcessAndReset();
777
586
  this.shutdown = true;
778
587
  return;
779
588
  }
780
- // Clear matterbridge plugin context if the reset parameter is set (childbridge mode)
781
589
  if (hasParameter('reset') && getParameter('reset') !== undefined) {
782
590
  this.log.debug(`Reset plugin ${getParameter('reset')}`);
783
591
  const plugin = this.plugins.get(getParameter('reset'));
784
592
  if (plugin) {
785
593
  const matterStorageManager = await this.matterStorageService?.open(plugin.name);
786
594
  if (!matterStorageManager) {
787
- /* istanbul ignore next */
788
595
  this.log.error(`Plugin ${plg}${plugin.name}${er} storageManager not found`);
789
596
  }
790
597
  else {
@@ -803,42 +610,35 @@ export class Matterbridge extends EventEmitter {
803
610
  this.shutdown = true;
804
611
  return;
805
612
  }
806
- // Check in 30 seconds the latest and dev versions of matterbridge and the plugins
807
613
  clearTimeout(this.checkUpdateTimeout);
808
614
  this.checkUpdateTimeout = setTimeout(async () => {
809
615
  const { checkUpdates } = await import('./update.js');
810
616
  checkUpdates(this);
811
617
  }, 30 * 1000).unref();
812
- // Check each 12 hours the latest and dev versions of matterbridge and the plugins
813
618
  clearInterval(this.checkUpdateInterval);
814
619
  this.checkUpdateInterval = setInterval(async () => {
815
620
  const { checkUpdates } = await import('./update.js');
816
621
  checkUpdates(this);
817
622
  }, 12 * 60 * 60 * 1000).unref();
818
- // Start the matterbridge in mode test
819
623
  if (hasParameter('test')) {
820
624
  this.bridgeMode = 'bridge';
821
625
  return;
822
626
  }
823
- // Start the matterbridge in mode controller
824
627
  if (hasParameter('controller')) {
825
628
  this.bridgeMode = 'controller';
826
629
  await this.startController();
827
630
  return;
828
631
  }
829
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
830
632
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
831
633
  this.log.info('Setting default matterbridge start mode to bridge');
832
634
  await this.nodeContext?.set('bridgeMode', 'bridge');
833
635
  }
834
- // Start matterbridge in bridge mode
835
636
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
836
637
  this.bridgeMode = 'bridge';
837
638
  this.log.debug(`Starting matterbridge in mode ${this.bridgeMode}`);
838
639
  await this.startBridge();
839
640
  return;
840
641
  }
841
- // Start matterbridge in childbridge mode
842
642
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
843
643
  this.bridgeMode = 'childbridge';
844
644
  this.log.debug(`Starting matterbridge in mode ${this.bridgeMode}`);
@@ -846,22 +646,10 @@ export class Matterbridge extends EventEmitter {
846
646
  return;
847
647
  }
848
648
  }
849
- /**
850
- * Asynchronously loads and starts the registered plugins.
851
- *
852
- * This method is responsible for initializing and starting all enabled plugins.
853
- * It ensures that each plugin is properly loaded and started before the bridge starts.
854
- *
855
- * @param {boolean} [wait] - If true, the method will wait for all plugins to be fully loaded and started before resolving.
856
- * @param {boolean} [start] - If true, the method will start the plugins after loading them.
857
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
858
- */
859
649
  async startPlugins(wait = false, start = true) {
860
- // Check, load and start the plugins
861
650
  for (const plugin of this.plugins) {
862
651
  plugin.configJson = await this.plugins.loadConfig(plugin);
863
652
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
864
- // Check if the plugin is available
865
653
  if (!(await this.plugins.resolve(plugin.path))) {
866
654
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
867
655
  plugin.enabled = false;
@@ -881,16 +669,10 @@ export class Matterbridge extends EventEmitter {
881
669
  if (wait)
882
670
  await this.plugins.load(plugin, start, 'Matterbridge is starting');
883
671
  else
884
- this.plugins.load(plugin, start, 'Matterbridge is starting'); // No await do it asyncronously
672
+ this.plugins.load(plugin, start, 'Matterbridge is starting');
885
673
  }
886
674
  this.frontend.wssSendRefreshRequired('plugins');
887
675
  }
888
- /**
889
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
890
- * - When an uncaught exception occurs, the exceptionHandler logs the error message and stack trace.
891
- * - When an unhandled promise rejection occurs, the rejectionHandler logs the reason and stack trace.
892
- * - When either of SIGINT and SIGTERM signals are received, the cleanup method is called with an appropriate message.
893
- */
894
676
  registerProcessHandlers() {
895
677
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
896
678
  process.removeAllListeners('uncaughtException');
@@ -917,9 +699,6 @@ export class Matterbridge extends EventEmitter {
917
699
  };
918
700
  process.on('SIGTERM', this.sigtermHandler);
919
701
  }
920
- /**
921
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
922
- */
923
702
  deregisterProcessHandlers() {
924
703
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
925
704
  if (this.exceptionHandler)
@@ -936,18 +715,13 @@ export class Matterbridge extends EventEmitter {
936
715
  process.off('SIGTERM', this.sigtermHandler);
937
716
  this.sigtermHandler = undefined;
938
717
  }
939
- /**
940
- * Logs the node and system information.
941
- */
942
718
  async logNodeAndSystemInfo() {
943
- // IP address information
944
719
  const networkInterfaces = os.networkInterfaces();
945
720
  this.systemInformation.interfaceName = '';
946
721
  this.systemInformation.ipv4Address = '';
947
722
  this.systemInformation.ipv6Address = '';
948
723
  this.systemInformation.macAddress = '';
949
724
  for (const [interfaceName, interfaceDetails] of Object.entries(networkInterfaces)) {
950
- // this.log.debug(`Checking interface: '${interfaceName}' for '${this.mdnsInterface}'`);
951
725
  if (this.mdnsInterface && interfaceName !== this.mdnsInterface)
952
726
  continue;
953
727
  if (!interfaceDetails) {
@@ -973,18 +747,16 @@ export class Matterbridge extends EventEmitter {
973
747
  break;
974
748
  }
975
749
  }
976
- // Node information
977
750
  this.systemInformation.nodeVersion = process.versions.node;
978
751
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
979
752
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
980
753
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
981
- // Host system information
982
754
  this.systemInformation.hostname = os.hostname();
983
755
  this.systemInformation.user = os.userInfo().username;
984
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
985
- this.systemInformation.osRelease = os.release(); // Kernel version
986
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
987
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
756
+ this.systemInformation.osType = os.type();
757
+ this.systemInformation.osRelease = os.release();
758
+ this.systemInformation.osPlatform = os.platform();
759
+ this.systemInformation.osArch = os.arch();
988
760
  this.systemInformation.totalMemory = formatBytes(os.totalmem());
989
761
  this.systemInformation.freeMemory = formatBytes(os.freemem());
990
762
  this.systemInformation.systemUptime = formatUptime(os.uptime());
@@ -994,7 +766,6 @@ export class Matterbridge extends EventEmitter {
994
766
  this.systemInformation.rss = formatBytes(process.memoryUsage().rss);
995
767
  this.systemInformation.heapTotal = formatBytes(process.memoryUsage().heapTotal);
996
768
  this.systemInformation.heapUsed = formatBytes(process.memoryUsage().heapUsed);
997
- // Log the system information
998
769
  this.log.debug('Host System Information:');
999
770
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
1000
771
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -1014,17 +785,14 @@ export class Matterbridge extends EventEmitter {
1014
785
  this.log.debug(`- RSS: ${this.systemInformation.rss}`);
1015
786
  this.log.debug(`- Heap Total: ${this.systemInformation.heapTotal}`);
1016
787
  this.log.debug(`- Heap Used: ${this.systemInformation.heapUsed}`);
1017
- // Log directories
1018
788
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
1019
789
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
1020
790
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
1021
791
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
1022
792
  this.log.debug(`Matterbridge Matter Certificate Directory: ${this.matterbridgeCertDirectory}`);
1023
- // Global node_modules directory
1024
793
  if (this.nodeContext)
1025
794
  this.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
1026
795
  if (this.globalModulesDirectory === '') {
1027
- // First run of Matterbridge so the node storage is empty
1028
796
  this.log.debug(`Getting global node_modules directory...`);
1029
797
  try {
1030
798
  const { getGlobalNodeModules } = await import('./utils/network.js');
@@ -1037,7 +805,6 @@ export class Matterbridge extends EventEmitter {
1037
805
  }
1038
806
  }
1039
807
  else {
1040
- // The global node_modules directory is already set in the node storage and we check if it is still valid
1041
808
  this.log.debug(`Checking global node_modules directory: ${this.globalModulesDirectory}`);
1042
809
  try {
1043
810
  const { getGlobalNodeModules } = await import('./utils/network.js');
@@ -1049,37 +816,25 @@ export class Matterbridge extends EventEmitter {
1049
816
  this.log.error(`Error checking global node_modules directory: ${error}`);
1050
817
  }
1051
818
  }
1052
- // Matterbridge version
1053
819
  this.log.debug(`Reading matterbridge package.json...`);
1054
820
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
1055
821
  this.matterbridgeVersion = this.matterbridgeLatestVersion = this.matterbridgeDevVersion = packageJson.version;
1056
822
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
1057
- // Matterbridge latest version (will be set in the checkUpdate function)
1058
823
  if (this.nodeContext)
1059
824
  this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', this.matterbridgeVersion);
1060
825
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
1061
- // Matterbridge dev version (will be set in the checkUpdate function)
1062
826
  if (this.nodeContext)
1063
827
  this.matterbridgeDevVersion = await this.nodeContext.get('matterbridgeDevVersion', this.matterbridgeVersion);
1064
828
  this.log.debug(`Matterbridge Dev Version: ${this.matterbridgeDevVersion}`);
1065
- // Frontend version
1066
829
  this.log.debug(`Reading frontend package.json...`);
1067
830
  const frontendPackageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'frontend/package.json'), 'utf8'));
1068
831
  this.frontendVersion = frontendPackageJson.version;
1069
832
  this.log.debug(`Frontend version ${CYAN}${this.frontendVersion}${db}`);
1070
- // Current working directory
1071
833
  const currentDir = process.cwd();
1072
834
  this.log.debug(`Current Working Directory: ${currentDir}`);
1073
- // Command line arguments (excluding 'node' and the script name)
1074
835
  const cmdArgs = process.argv.slice(2).join(' ');
1075
836
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
1076
837
  }
1077
- /**
1078
- * Set the logger logLevel for the Matterbridge classes and call onChangeLoggerLevel() for each plugin.
1079
- *
1080
- * @param {LogLevel} logLevel The logger logLevel to set.
1081
- * @returns {Promise<LogLevel>} A promise that resolves when the logLevel has been set.
1082
- */
1083
838
  async setLogLevel(logLevel) {
1084
839
  this.log.logLevel = logLevel;
1085
840
  this.frontend.logLevel = logLevel;
@@ -1089,87 +844,58 @@ export class Matterbridge extends EventEmitter {
1089
844
  for (const plugin of this.plugins) {
1090
845
  if (!plugin.platform || !plugin.platform.log || !plugin.platform.config)
1091
846
  continue;
1092
- plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : logLevel;
1093
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : logLevel);
1094
- }
1095
- // Set the global logger callback for the WebSocketServer to the common minimum logLevel
1096
- let callbackLogLevel = "notice" /* LogLevel.NOTICE */;
1097
- if (logLevel === "info" /* LogLevel.INFO */ || Logger.level === MatterLogLevel.INFO)
1098
- callbackLogLevel = "info" /* LogLevel.INFO */;
1099
- if (logLevel === "debug" /* LogLevel.DEBUG */ || Logger.level === MatterLogLevel.DEBUG)
1100
- callbackLogLevel = "debug" /* LogLevel.DEBUG */;
847
+ plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" : logLevel;
848
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" : logLevel);
849
+ }
850
+ let callbackLogLevel = "notice";
851
+ if (logLevel === "info" || Logger.level === MatterLogLevel.INFO)
852
+ callbackLogLevel = "info";
853
+ if (logLevel === "debug" || Logger.level === MatterLogLevel.DEBUG)
854
+ callbackLogLevel = "debug";
1101
855
  AnsiLogger.setGlobalCallbackLevel(callbackLogLevel);
1102
856
  this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
1103
857
  return logLevel;
1104
858
  }
1105
- /**
1106
- * Get the current logger logLevel.
1107
- *
1108
- * @returns {LogLevel} The current logger logLevel.
1109
- */
1110
859
  getLogLevel() {
1111
860
  return this.log.logLevel;
1112
861
  }
1113
- /**
1114
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
1115
- * It also logs to file (matter.log) if fileLogger is true.
1116
- *
1117
- * @param {boolean} fileLogger - Whether to log to file or not.
1118
- * @returns {Function} The MatterLogger function. \x1b[35m for violet \x1b[34m is blue
1119
- */
1120
862
  createDestinationMatterLogger(fileLogger) {
1121
- this.matterLog.logNameColor = '\x1b[34m'; // Blue matter.js Logger
863
+ this.matterLog.logNameColor = '\x1b[34m';
1122
864
  if (fileLogger) {
1123
865
  this.matterLog.logFilePath = path.join(this.matterbridgeDirectory, MATTER_LOGGER_FILE);
1124
866
  }
1125
867
  return (text, message) => {
1126
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1127
868
  const logger = text.slice(44, 44 + 20).trim();
1128
869
  const msg = text.slice(65);
1129
870
  this.matterLog.logName = logger;
1130
871
  switch (message.level) {
1131
872
  case MatterLogLevel.DEBUG:
1132
- this.matterLog.log("debug" /* LogLevel.DEBUG */, msg);
873
+ this.matterLog.log("debug", msg);
1133
874
  break;
1134
875
  case MatterLogLevel.INFO:
1135
- this.matterLog.log("info" /* LogLevel.INFO */, msg);
876
+ this.matterLog.log("info", msg);
1136
877
  break;
1137
878
  case MatterLogLevel.NOTICE:
1138
- this.matterLog.log("notice" /* LogLevel.NOTICE */, msg);
879
+ this.matterLog.log("notice", msg);
1139
880
  break;
1140
881
  case MatterLogLevel.WARN:
1141
- this.matterLog.log("warn" /* LogLevel.WARN */, msg);
882
+ this.matterLog.log("warn", msg);
1142
883
  break;
1143
884
  case MatterLogLevel.ERROR:
1144
- this.matterLog.log("error" /* LogLevel.ERROR */, msg);
885
+ this.matterLog.log("error", msg);
1145
886
  break;
1146
887
  case MatterLogLevel.FATAL:
1147
- this.matterLog.log("fatal" /* LogLevel.FATAL */, msg);
888
+ this.matterLog.log("fatal", msg);
1148
889
  break;
1149
890
  }
1150
891
  };
1151
892
  }
1152
- /**
1153
- * Restarts the process by exiting the current instance and loading a new instance (/api/restart).
1154
- *
1155
- * @returns {Promise<void>} A promise that resolves when the restart is completed.
1156
- */
1157
893
  async restartProcess() {
1158
894
  await this.cleanup('restarting...', true);
1159
895
  }
1160
- /**
1161
- * Shut down the process (/api/shutdown).
1162
- *
1163
- * @returns {Promise<void>} A promise that resolves when the shutdown is completed.
1164
- */
1165
896
  async shutdownProcess() {
1166
897
  await this.cleanup('shutting down...', false);
1167
898
  }
1168
- /**
1169
- * Update matterbridge and shut down the process (virtual device 'Update Matterbridge').
1170
- *
1171
- * @returns {Promise<void>} A promise that resolves when the update is completed.
1172
- */
1173
899
  async updateProcess() {
1174
900
  this.log.info('Updating matterbridge...');
1175
901
  try {
@@ -1183,13 +909,6 @@ export class Matterbridge extends EventEmitter {
1183
909
  this.frontend.wssSendRestartRequired();
1184
910
  await this.cleanup('updating...', false);
1185
911
  }
1186
- /**
1187
- * Unregister all devices and shut down the process (/api/unregister).
1188
- *
1189
- * @param {number} [timeout] - The timeout duration to wait for the message exchange to complete in milliseconds. Default is 1000.
1190
- *
1191
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1192
- */
1193
912
  async unregisterAndShutdownProcess(timeout = 1000) {
1194
913
  this.log.info('Unregistering all devices and shutting down...');
1195
914
  for (const plugin of this.plugins.array()) {
@@ -1201,71 +920,46 @@ export class Matterbridge extends EventEmitter {
1201
920
  await this.removeAllBridgedEndpoints(plugin.name, 100);
1202
921
  }
1203
922
  this.log.debug('Waiting for the MessageExchange to finish...');
1204
- await wait(timeout); // Wait for MessageExchange to finish
923
+ await wait(timeout);
1205
924
  this.log.debug('Cleaning up and shutting down...');
1206
925
  await this.cleanup('unregistered all devices and shutting down...', false, timeout);
1207
926
  }
1208
- /**
1209
- * Reset commissioning and shut down the process (/api/reset).
1210
- *
1211
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1212
- */
1213
927
  async shutdownProcessAndReset() {
1214
928
  await this.cleanup('shutting down with reset...', false);
1215
929
  }
1216
- /**
1217
- * Factory reset and shut down the process (/api/factory-reset).
1218
- *
1219
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1220
- */
1221
930
  async shutdownProcessAndFactoryReset() {
1222
931
  await this.cleanup('shutting down with factory reset...', false);
1223
932
  }
1224
- /**
1225
- * Cleans up the Matterbridge instance.
1226
- *
1227
- * @param {string} message - The cleanup message.
1228
- * @param {boolean} [restart] - Indicates whether to restart the instance after cleanup. Default is `false`.
1229
- * @param {number} [timeout] - The timeout duration to wait for the message exchange to complete in milliseconds. Default is 1000.
1230
- *
1231
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1232
- */
1233
933
  async cleanup(message, restart = false, timeout = 1000) {
1234
934
  if (this.initialized && !this.hasCleanupStarted) {
1235
935
  this.emit('cleanup_started');
1236
936
  this.hasCleanupStarted = true;
1237
937
  this.log.info(message);
1238
- // Clear the start matter interval
1239
938
  if (this.startMatterInterval) {
1240
939
  clearInterval(this.startMatterInterval);
1241
940
  this.startMatterInterval = undefined;
1242
941
  this.log.debug('Start matter interval cleared');
1243
942
  }
1244
- // Clear the check update timeout
1245
943
  if (this.checkUpdateTimeout) {
1246
944
  clearTimeout(this.checkUpdateTimeout);
1247
945
  this.checkUpdateTimeout = undefined;
1248
946
  this.log.debug('Check update timeout cleared');
1249
947
  }
1250
- // Clear the check update interval
1251
948
  if (this.checkUpdateInterval) {
1252
949
  clearInterval(this.checkUpdateInterval);
1253
950
  this.checkUpdateInterval = undefined;
1254
951
  this.log.debug('Check update interval cleared');
1255
952
  }
1256
- // Clear the configure timeout
1257
953
  if (this.configureTimeout) {
1258
954
  clearTimeout(this.configureTimeout);
1259
955
  this.configureTimeout = undefined;
1260
956
  this.log.debug('Matterbridge configure timeout cleared');
1261
957
  }
1262
- // Clear the reachability timeout
1263
958
  if (this.reachabilityTimeout) {
1264
959
  clearTimeout(this.reachabilityTimeout);
1265
960
  this.reachabilityTimeout = undefined;
1266
961
  this.log.debug('Matterbridge reachability timeout cleared');
1267
962
  }
1268
- // Call the shutdown method of each plugin and clear the plugins reachability timeout
1269
963
  for (const plugin of this.plugins) {
1270
964
  if (!plugin.enabled || plugin.error)
1271
965
  continue;
@@ -1276,7 +970,6 @@ export class Matterbridge extends EventEmitter {
1276
970
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1277
971
  }
1278
972
  }
1279
- // Stop matter server nodes
1280
973
  this.log.notice(`Stopping matter server nodes in ${this.bridgeMode} mode...`);
1281
974
  if (timeout > 0) {
1282
975
  this.log.debug(`Waiting ${timeout}ms for the MessageExchange to finish...`);
@@ -1303,7 +996,6 @@ export class Matterbridge extends EventEmitter {
1303
996
  }
1304
997
  }
1305
998
  this.log.notice('Stopped matter server nodes');
1306
- // Matter commisioning reset
1307
999
  if (message === 'shutting down with reset...') {
1308
1000
  this.log.info('Resetting Matterbridge commissioning information...');
1309
1001
  await this.matterStorageManager?.createContext('events')?.clearAll();
@@ -1313,7 +1005,6 @@ export class Matterbridge extends EventEmitter {
1313
1005
  await this.matterbridgeContext?.clearAll();
1314
1006
  this.log.info('Matter storage reset done! Remove the bridge from the controller.');
1315
1007
  }
1316
- // Unregister all devices
1317
1008
  if (message === 'unregistered all devices and shutting down...') {
1318
1009
  if (this.bridgeMode === 'bridge') {
1319
1010
  await this.matterStorageManager?.createContext('root')?.createContext('parts')?.createContext('Matterbridge')?.createContext('parts')?.clearAll();
@@ -1331,35 +1022,16 @@ export class Matterbridge extends EventEmitter {
1331
1022
  }
1332
1023
  this.log.info('Matter storage reset done!');
1333
1024
  }
1334
- // Stop matter storage
1335
1025
  await this.stopMatterStorage();
1336
- // Stop the frontend
1337
1026
  await this.frontend.stop();
1338
1027
  this.frontend.destroy();
1339
- // Close PluginManager and DeviceManager
1340
1028
  this.plugins.destroy();
1341
1029
  this.devices.destroy();
1342
- // Stop thread messaging server
1343
1030
  this.server.close();
1344
- // Close the matterbridge node storage and context
1345
1031
  if (this.nodeStorage && this.nodeContext) {
1346
- /*
1347
- TODO: Implement serialization of registered devices
1348
- this.log.info('Saving registered devices...');
1349
- const serializedRegisteredDevices: SerializedMatterbridgeEndpoint[] = [];
1350
- this.devices.forEach(async (device) => {
1351
- const serializedMatterbridgeDevice = MatterbridgeEndpoint.serialize(device);
1352
- this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1353
- if (serializedMatterbridgeDevice) serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1354
- });
1355
- await this.nodeContext.set<SerializedMatterbridgeEndpoint[]>('devices', serializedRegisteredDevices);
1356
- this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1357
- */
1358
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1359
1032
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1360
1033
  await this.nodeContext.close();
1361
1034
  this.nodeContext = undefined;
1362
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1363
1035
  for (const plugin of this.plugins) {
1364
1036
  if (plugin.nodeContext) {
1365
1037
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1376,10 +1048,8 @@ export class Matterbridge extends EventEmitter {
1376
1048
  }
1377
1049
  this.plugins.clear();
1378
1050
  this.devices.clear();
1379
- // Factory reset
1380
1051
  if (message === 'shutting down with factory reset...') {
1381
1052
  try {
1382
- // Delete matter storage directory with its subdirectories and backup
1383
1053
  const dir = path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME);
1384
1054
  this.log.info(`Removing matter storage directory: ${dir}`);
1385
1055
  await fs.rm(dir, { recursive: true });
@@ -1388,13 +1058,11 @@ export class Matterbridge extends EventEmitter {
1388
1058
  await fs.rm(backup, { recursive: true });
1389
1059
  }
1390
1060
  catch (error) {
1391
- // istanbul ignore next if
1392
1061
  if (error instanceof Error && error.code !== 'ENOENT') {
1393
1062
  this.log.error(`Error removing matter storage directory: ${error}`);
1394
1063
  }
1395
1064
  }
1396
1065
  try {
1397
- // Delete matterbridge storage directory with its subdirectories and backup
1398
1066
  const dir = path.join(this.matterbridgeDirectory, NODE_STORAGE_DIR);
1399
1067
  this.log.info(`Removing matterbridge storage directory: ${dir}`);
1400
1068
  await fs.rm(dir, { recursive: true });
@@ -1403,20 +1071,18 @@ export class Matterbridge extends EventEmitter {
1403
1071
  await fs.rm(backup, { recursive: true });
1404
1072
  }
1405
1073
  catch (error) {
1406
- // istanbul ignore next if
1407
1074
  if (error instanceof Error && error.code !== 'ENOENT') {
1408
1075
  this.log.error(`Error removing matterbridge storage directory: ${error}`);
1409
1076
  }
1410
1077
  }
1411
1078
  this.log.info('Factory reset done! Remove all paired fabrics from the controllers.');
1412
1079
  }
1413
- // Deregisters the process handlers
1414
1080
  this.deregisterProcessHandlers();
1415
1081
  if (restart) {
1416
1082
  if (message === 'updating...') {
1417
1083
  this.log.info('Cleanup completed. Updating...');
1418
1084
  Matterbridge.instance = undefined;
1419
- this.emit('update'); // Restart the process but the update has been done before. TODO move all updates to the cli
1085
+ this.emit('update');
1420
1086
  }
1421
1087
  else if (message === 'restarting...') {
1422
1088
  this.log.info('Cleanup completed. Restarting...');
@@ -1436,6 +1102,7 @@ export class Matterbridge extends EventEmitter {
1436
1102
  else {
1437
1103
  if (!this.initialized) {
1438
1104
  this.log.debug('Cleanup with instance not initialized...');
1105
+ this.destroy();
1439
1106
  this.frontend.destroy();
1440
1107
  this.plugins.destroy();
1441
1108
  this.devices.destroy();
@@ -1444,14 +1111,7 @@ export class Matterbridge extends EventEmitter {
1444
1111
  this.log.debug('Cleanup already started...');
1445
1112
  }
1446
1113
  }
1447
- /**
1448
- * Starts the Matterbridge in bridge mode.
1449
- *
1450
- * @private
1451
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1452
- */
1453
1114
  async startBridge() {
1454
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1455
1115
  if (!this.matterStorageManager)
1456
1116
  throw new Error('No storage manager initialized');
1457
1117
  if (!this.matterbridgeContext)
@@ -1490,16 +1150,13 @@ export class Matterbridge extends EventEmitter {
1490
1150
  clearInterval(this.startMatterInterval);
1491
1151
  this.startMatterInterval = undefined;
1492
1152
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1493
- // Start the Matter server node
1494
- this.startServerNode(this.serverNode); // We don't await this, because the server node is started in the background
1495
- // Start the Matter server node of single devices in mode 'server'
1153
+ this.startServerNode(this.serverNode);
1496
1154
  for (const device of this.devices.array()) {
1497
1155
  if (device.mode === 'server' && device.serverNode) {
1498
1156
  this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
1499
- this.startServerNode(device.serverNode); // We don't await this, because the server node is started in the background
1157
+ this.startServerNode(device.serverNode);
1500
1158
  }
1501
1159
  }
1502
- // Configure the plugins
1503
1160
  this.configureTimeout = setTimeout(async () => {
1504
1161
  for (const plugin of this.plugins.array()) {
1505
1162
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1517,40 +1174,28 @@ export class Matterbridge extends EventEmitter {
1517
1174
  }
1518
1175
  this.frontend.wssSendRefreshRequired('plugins');
1519
1176
  }, 30 * 1000).unref();
1520
- // Setting reachability to true
1521
1177
  this.reachabilityTimeout = setTimeout(() => {
1522
1178
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1523
1179
  if (this.aggregatorNode)
1524
1180
  this.setAggregatorReachability(this.aggregatorNode, true);
1525
1181
  }, 60 * 1000).unref();
1526
- // Logger.get('LogServerNode').info(this.serverNode);
1527
1182
  this.emit('bridge_started');
1528
1183
  this.log.notice('Matterbridge bridge started successfully');
1529
1184
  this.frontend.wssSendRefreshRequired('settings');
1530
1185
  this.frontend.wssSendRefreshRequired('plugins');
1531
1186
  }, this.startMatterIntervalMs);
1532
1187
  }
1533
- /**
1534
- * Starts the Matterbridge in childbridge mode.
1535
- *
1536
- * @param {number} [delay] - The delay before starting the childbridge. Default is 1000 milliseconds.
1537
- *
1538
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1539
- */
1540
1188
  async startChildbridge(delay = 1000) {
1541
1189
  if (!this.matterStorageManager)
1542
1190
  throw new Error('No storage manager initialized');
1543
- // Load with await all plugins but don't start them. We get the platform.type to pre-create server nodes for DynamicPlatform plugins
1544
1191
  this.log.debug('Loading all plugins in childbridge mode...');
1545
1192
  await this.startPlugins(true, false);
1546
- // Create server nodes for DynamicPlatform plugins and start all plugins in the background
1547
1193
  this.log.debug('Creating server nodes for DynamicPlatform plugins and starting all plugins in childbridge mode...');
1548
1194
  for (const plugin of this.plugins.array().filter((p) => p.enabled && !p.error)) {
1549
1195
  if (plugin.type === 'DynamicPlatform')
1550
1196
  await this.createDynamicPlugin(plugin);
1551
- this.plugins.start(plugin, 'Matterbridge is starting'); // Start the plugin in the background
1197
+ this.plugins.start(plugin, 'Matterbridge is starting');
1552
1198
  }
1553
- // Start the Matterbridge in childbridge mode when all plugins are loaded and started
1554
1199
  this.log.debug('Starting start matter interval in childbridge mode...');
1555
1200
  let failCount = 0;
1556
1201
  this.startMatterInterval = setInterval(async () => {
@@ -1584,9 +1229,8 @@ export class Matterbridge extends EventEmitter {
1584
1229
  clearInterval(this.startMatterInterval);
1585
1230
  this.startMatterInterval = undefined;
1586
1231
  if (delay > 0)
1587
- await wait(delay); // Wait for the specified delay to ensure all plugins server nodes are ready
1232
+ await wait(delay);
1588
1233
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1589
- // Configure the plugins
1590
1234
  this.configureTimeout = setTimeout(async () => {
1591
1235
  for (const plugin of this.plugins.array()) {
1592
1236
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1611,7 +1255,6 @@ export class Matterbridge extends EventEmitter {
1611
1255
  this.log.error(`Plugin ${plg}${plugin.name}${er} didn't register any devices to Matterbridge. Verify the plugin configuration.`);
1612
1256
  continue;
1613
1257
  }
1614
- // istanbul ignore next if cause is just a safety check
1615
1258
  if (!plugin.serverNode) {
1616
1259
  this.log.error(`Server node not found for plugin ${plg}${plugin.name}${er}`);
1617
1260
  continue;
@@ -1624,252 +1267,28 @@ export class Matterbridge extends EventEmitter {
1624
1267
  this.log.error(`Node storage context not found for plugin ${plg}${plugin.name}${er}`);
1625
1268
  continue;
1626
1269
  }
1627
- // Start the Matter server node
1628
- this.startServerNode(plugin.serverNode); // We don't await this, because the server node is started in the background
1629
- // Setting reachability to true
1270
+ this.startServerNode(plugin.serverNode);
1630
1271
  plugin.reachabilityTimeout = setTimeout(() => {
1631
1272
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${nf}`);
1632
1273
  if (plugin.type === 'DynamicPlatform' && plugin.aggregatorNode)
1633
1274
  this.setAggregatorReachability(plugin.aggregatorNode, true);
1634
1275
  }, 60 * 1000).unref();
1635
1276
  }
1636
- // Start the Matter server node of single devices in mode 'server'
1637
1277
  for (const device of this.devices.array()) {
1638
1278
  if (device.mode === 'server' && device.serverNode) {
1639
1279
  this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
1640
- this.startServerNode(device.serverNode); // We don't await this, because the server node is started in the background
1280
+ this.startServerNode(device.serverNode);
1641
1281
  }
1642
1282
  }
1643
- // Logger.get('LogServerNode').info(this.serverNode);
1644
1283
  this.emit('childbridge_started');
1645
1284
  this.log.notice('Matterbridge childbridge started successfully');
1646
1285
  this.frontend.wssSendRefreshRequired('settings');
1647
1286
  this.frontend.wssSendRefreshRequired('plugins');
1648
1287
  }, this.startMatterIntervalMs);
1649
1288
  }
1650
- /**
1651
- * Starts the Matterbridge controller.
1652
- *
1653
- * @private
1654
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1655
- */
1656
1289
  async startController() {
1657
- /*
1658
- if (!this.matterStorageManager) {
1659
- this.log.error('No storage manager initialized');
1660
- await this.cleanup('No storage manager initialized');
1661
- return;
1662
- }
1663
- this.log.info('Creating context: mattercontrollerContext');
1664
- this.controllerContext = this.matterStorageManager.createContext('mattercontrollerContext');
1665
- if (!this.controllerContext) {
1666
- this.log.error('No storage context mattercontrollerContext initialized');
1667
- await this.cleanup('No storage context mattercontrollerContext initialized');
1668
- return;
1669
- }
1670
-
1671
- this.log.debug('Starting matterbridge in mode', this.bridgeMode);
1672
- this.matterServer = await this.createMatterServer(this.storageManager);
1673
- this.log.info('Creating matter commissioning controller');
1674
- this.commissioningController = new CommissioningController({
1675
- autoConnect: false,
1676
- });
1677
- this.log.info('Adding matter commissioning controller to matter server');
1678
- await this.matterServer.addCommissioningController(this.commissioningController);
1679
-
1680
- this.log.info('Starting matter server');
1681
- await this.matterServer.start();
1682
- this.log.info('Matter server started');
1683
- const commissioningOptions: ControllerCommissioningFlowOptions = {
1684
- regulatoryLocation: GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor,
1685
- regulatoryCountryCode: 'XX',
1686
- };
1687
- const commissioningController = new CommissioningController({
1688
- environment: {
1689
- environment,
1690
- id: uniqueId,
1691
- },
1692
- autoConnect: false, // Do not auto connect to the commissioned nodes
1693
- adminFabricLabel,
1694
- });
1695
-
1696
- if (hasParameter('pairingcode')) {
1697
- this.log.info('Pairing device with pairingcode:', getParameter('pairingcode'));
1698
- const pairingCode = getParameter('pairingcode');
1699
- const ip = this.controllerContext.has('ip') ? this.controllerContext.get<string>('ip') : undefined;
1700
- const port = this.controllerContext.has('port') ? this.controllerContext.get<number>('port') : undefined;
1701
-
1702
- let longDiscriminator, setupPin, shortDiscriminator;
1703
- if (pairingCode !== undefined) {
1704
- const pairingCodeCodec = ManualPairingCodeCodec.decode(pairingCode);
1705
- shortDiscriminator = pairingCodeCodec.shortDiscriminator;
1706
- longDiscriminator = undefined;
1707
- setupPin = pairingCodeCodec.passcode;
1708
- this.log.info(`Data extracted from pairing code: ${Logger.toJSON(pairingCodeCodec)}`);
1709
- } else {
1710
- longDiscriminator = await this.controllerContext.get('longDiscriminator', 3840);
1711
- if (longDiscriminator > 4095) throw new Error('Discriminator value must be less than 4096');
1712
- setupPin = this.controllerContext.get('pin', 20202021);
1713
- }
1714
- if ((shortDiscriminator === undefined && longDiscriminator === undefined) || setupPin === undefined) {
1715
- throw new Error('Please specify the longDiscriminator of the device to commission with -longDiscriminator or provide a valid passcode with -passcode');
1716
- }
1717
-
1718
- const options = {
1719
- commissioning: commissioningOptions,
1720
- discovery: {
1721
- knownAddress: ip !== undefined && port !== undefined ? { ip, port, type: 'udp' } : undefined,
1722
- identifierData: longDiscriminator !== undefined ? { longDiscriminator } : shortDiscriminator !== undefined ? { shortDiscriminator } : {},
1723
- },
1724
- passcode: setupPin,
1725
- } as NodeCommissioningOptions;
1726
- this.log.info('Commissioning with options:', options);
1727
- const nodeId = await this.commissioningController.commissionNode(options);
1728
- this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1729
- this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1730
- } // (hasParameter('pairingcode'))
1731
-
1732
- if (hasParameter('unpairall')) {
1733
- this.log.info('***Commissioning controller unpairing all nodes...');
1734
- const nodeIds = this.commissioningController.getCommissionedNodes();
1735
- for (const nodeId of nodeIds) {
1736
- this.log.info('***Commissioning controller unpairing node:', nodeId);
1737
- await this.commissioningController.removeNode(nodeId);
1738
- }
1739
- return;
1740
- }
1741
-
1742
- if (hasParameter('discover')) {
1743
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1744
- // console.log(discover);
1745
- }
1746
-
1747
- if (!this.commissioningController.isCommissioned()) {
1748
- this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
1749
- return;
1750
- }
1751
-
1752
- const nodeIds = this.commissioningController.getCommissionedNodes();
1753
- this.log.info(`***Commissioning controller is commissioned ${this.commissioningController.isCommissioned()} and has ${nodeIds.length} nodes commisioned: `);
1754
- for (const nodeId of nodeIds) {
1755
- this.log.info(`***Connecting to commissioned node: ${nodeId}`);
1756
-
1757
- const node = await this.commissioningController.connectNode(nodeId, {
1758
- autoSubscribe: false,
1759
- attributeChangedCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, attributeName }, value }) =>
1760
- this.log.info(`***Commissioning controller attributeChangedCallback ${peerNodeId}: attribute ${nodeId}/${endpointId}/${clusterId}/${attributeName} changed to ${Logger.toJSON(value)}`),
1761
- eventTriggeredCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, eventName }, events }) =>
1762
- this.log.info(`***Commissioning controller eventTriggeredCallback ${peerNodeId}: Event ${nodeId}/${endpointId}/${clusterId}/${eventName} triggered with ${Logger.toJSON(events)}`),
1763
- stateInformationCallback: (peerNodeId, info) => {
1764
- switch (info) {
1765
- case NodeStateInformation.Connected:
1766
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} connected`);
1767
- break;
1768
- case NodeStateInformation.Disconnected:
1769
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} disconnected`);
1770
- break;
1771
- case NodeStateInformation.Reconnecting:
1772
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} reconnecting`);
1773
- break;
1774
- case NodeStateInformation.WaitingForDeviceDiscovery:
1775
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} waiting for device discovery`);
1776
- break;
1777
- case NodeStateInformation.StructureChanged:
1778
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} structure changed`);
1779
- break;
1780
- case NodeStateInformation.Decommissioned:
1781
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} decommissioned`);
1782
- break;
1783
- default:
1784
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} NodeStateInformation.${info}`);
1785
- break;
1786
- }
1787
- },
1788
- });
1789
-
1790
- node.logStructure();
1791
-
1792
- // Get the interaction client
1793
- this.log.info('Getting the interaction client');
1794
- const interactionClient = await node.getInteractionClient();
1795
- let cluster;
1796
- let attributes;
1797
-
1798
- // Log BasicInformationCluster
1799
- cluster = BasicInformationCluster;
1800
- attributes = await interactionClient.getMultipleAttributes({
1801
- attributes: [{ clusterId: cluster.id }],
1802
- });
1803
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1804
- attributes.forEach((attribute) => {
1805
- this.log.info(
1806
- `- 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}`,
1807
- );
1808
- });
1809
-
1810
- // Log PowerSourceCluster
1811
- cluster = PowerSourceCluster;
1812
- attributes = await interactionClient.getMultipleAttributes({
1813
- attributes: [{ clusterId: cluster.id }],
1814
- });
1815
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1816
- attributes.forEach((attribute) => {
1817
- this.log.info(
1818
- `- 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}`,
1819
- );
1820
- });
1821
-
1822
- // Log ThreadNetworkDiagnostics
1823
- cluster = ThreadNetworkDiagnosticsCluster;
1824
- attributes = await interactionClient.getMultipleAttributes({
1825
- attributes: [{ clusterId: cluster.id }],
1826
- });
1827
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1828
- attributes.forEach((attribute) => {
1829
- this.log.info(
1830
- `- 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}`,
1831
- );
1832
- });
1833
-
1834
- // Log SwitchCluster
1835
- cluster = SwitchCluster;
1836
- attributes = await interactionClient.getMultipleAttributes({
1837
- attributes: [{ clusterId: cluster.id }],
1838
- });
1839
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1840
- attributes.forEach((attribute) => {
1841
- this.log.info(
1842
- `- 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}`,
1843
- );
1844
- });
1845
-
1846
- this.log.info('Subscribing to all attributes and events');
1847
- await node.subscribeAllAttributesAndEvents({
1848
- ignoreInitialTriggers: false,
1849
- attributeChangedCallback: ({ path: { nodeId, clusterId, endpointId, attributeName }, version, value }) =>
1850
- this.log.info(
1851
- `***${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}`,
1852
- ),
1853
- eventTriggeredCallback: ({ path: { nodeId, clusterId, endpointId, eventName }, events }) => {
1854
- this.log.info(
1855
- `***${db}Commissioning controller eventTriggeredCallback: event ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${eventName}${db} triggered with ${debugStringify(events ?? { none: true })}`,
1856
- );
1857
- },
1858
- });
1859
- this.log.info('Subscribed to all attributes and events');
1860
- }
1861
- */
1862
1290
  }
1863
- /** */
1864
- /** Matter.js methods */
1865
- /** */
1866
- /**
1867
- * Starts the matter storage with name Matterbridge, create the matterbridge context and performs a backup.
1868
- *
1869
- * @returns {Promise<void>} - A promise that resolves when the storage is started.
1870
- */
1871
1291
  async startMatterStorage() {
1872
- // Setup Matter storage
1873
1292
  this.log.info(`Starting matter node storage...`);
1874
1293
  this.matterStorageService = this.environment.get(StorageService);
1875
1294
  this.log.info(`Matter node storage service created: ${this.matterStorageService.location}`);
@@ -1877,17 +1296,8 @@ export class Matterbridge extends EventEmitter {
1877
1296
  this.log.info('Matter node storage manager "Matterbridge" created');
1878
1297
  this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId);
1879
1298
  this.log.info('Matter node storage started');
1880
- // Backup matter storage since it is created/opened correctly
1881
1299
  await this.backupMatterStorage(path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME), path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME + '.backup'));
1882
1300
  }
1883
- /**
1884
- * Makes a backup copy of the specified matter storage directory.
1885
- *
1886
- * @param {string} storageName - The name of the storage directory to be backed up.
1887
- * @param {string} backupName - The name of the backup directory to be created.
1888
- * @private
1889
- * @returns {Promise<void>} A promise that resolves when the has been done.
1890
- */
1891
1301
  async backupMatterStorage(storageName, backupName) {
1892
1302
  this.log.info('Creating matter node storage backup...');
1893
1303
  try {
@@ -1898,11 +1308,6 @@ export class Matterbridge extends EventEmitter {
1898
1308
  this.log.error(`Error creating matter node storage backup from ${storageName} to ${backupName}:`, error);
1899
1309
  }
1900
1310
  }
1901
- /**
1902
- * Stops the matter storage.
1903
- *
1904
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1905
- */
1906
1311
  async stopMatterStorage() {
1907
1312
  this.log.info('Closing matter node storage...');
1908
1313
  await this.matterStorageManager?.close();
@@ -1911,20 +1316,6 @@ export class Matterbridge extends EventEmitter {
1911
1316
  this.matterbridgeContext = undefined;
1912
1317
  this.log.info('Matter node storage closed');
1913
1318
  }
1914
- /**
1915
- * Creates a server node storage context.
1916
- *
1917
- * @param {string} storeId - The storeId.
1918
- * @param {string} deviceName - The name of the device.
1919
- * @param {DeviceTypeId} deviceType - The device type of the device.
1920
- * @param {number} vendorId - The vendor ID.
1921
- * @param {string} vendorName - The vendor name.
1922
- * @param {number} productId - The product ID.
1923
- * @param {string} productName - The product name.
1924
- * @param {string} [serialNumber] - The serial number of the device (optional).
1925
- * @param {string} [uniqueId] - The unique ID of the device (optional).
1926
- * @returns {Promise<StorageContext>} The storage context for the commissioning server.
1927
- */
1928
1319
  async createServerNodeContext(storeId, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber, uniqueId) {
1929
1320
  const { randomBytes } = await import('node:crypto');
1930
1321
  if (!this.matterStorageService)
@@ -1964,15 +1355,6 @@ export class Matterbridge extends EventEmitter {
1964
1355
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
1965
1356
  return storageContext;
1966
1357
  }
1967
- /**
1968
- * Creates a server node.
1969
- *
1970
- * @param {StorageContext} storageContext - The storage context for the server node.
1971
- * @param {number} [port] - The port number for the server node. Defaults to 5540.
1972
- * @param {number} [passcode] - The passcode for the server node. Defaults to 20242025.
1973
- * @param {number} [discriminator] - The discriminator for the server node. Defaults to 3850.
1974
- * @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created server node.
1975
- */
1976
1358
  async createServerNode(storageContext, port = 5540, passcode = 20242025, discriminator = 3850) {
1977
1359
  const storeId = await storageContext.get('storeId');
1978
1360
  this.log.notice(`Creating server node for ${storeId} on port ${port} with passcode ${passcode} and discriminator ${discriminator}...`);
@@ -1982,37 +1364,24 @@ export class Matterbridge extends EventEmitter {
1982
1364
  this.log.debug(`- uniqueId: ${await storageContext.get('uniqueId')}`);
1983
1365
  this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
1984
1366
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
1985
- /**
1986
- * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
1987
- */
1988
1367
  const serverNode = await ServerNode.create({
1989
- // Required: Give the Node a unique ID which is used to store the state of this node
1990
1368
  id: storeId,
1991
- // Provide Network relevant configuration like the port
1992
- // Optional when operating only one device on a host, Default port is 5540
1993
1369
  network: {
1994
1370
  listeningAddressIpv4: this.ipv4Address,
1995
1371
  listeningAddressIpv6: this.ipv6Address,
1996
1372
  port,
1997
1373
  },
1998
- // Provide the certificate for the device
1999
1374
  operationalCredentials: {
2000
1375
  certification: this.certification,
2001
1376
  },
2002
- // Provide Commissioning relevant settings
2003
- // Optional for development/testing purposes
2004
1377
  commissioning: {
2005
1378
  passcode,
2006
1379
  discriminator,
2007
1380
  },
2008
- // Provide Node announcement settings
2009
- // Optional: If Ommitted some development defaults are used
2010
1381
  productDescription: {
2011
1382
  name: await storageContext.get('deviceName'),
2012
1383
  deviceType: DeviceTypeId(await storageContext.get('deviceType')),
2013
1384
  },
2014
- // Provide defaults for the BasicInformation cluster on the Root endpoint
2015
- // Optional: If Omitted some development defaults are used
2016
1385
  basicInformation: {
2017
1386
  vendorId: VendorId(await storageContext.get('vendorId')),
2018
1387
  vendorName: await storageContext.get('vendorName'),
@@ -2029,23 +1398,17 @@ export class Matterbridge extends EventEmitter {
2029
1398
  reachable: true,
2030
1399
  },
2031
1400
  });
2032
- /**
2033
- * This event is triggered when the device is initially commissioned successfully.
2034
- * This means: It is added to the first fabric.
2035
- */
2036
1401
  serverNode.lifecycle.commissioned.on(() => {
2037
1402
  this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`);
2038
1403
  this.advertisingNodes.delete(storeId);
2039
1404
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2040
1405
  });
2041
- /** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
2042
1406
  serverNode.lifecycle.decommissioned.on(() => {
2043
1407
  this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`);
2044
1408
  this.advertisingNodes.delete(storeId);
2045
1409
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2046
1410
  this.frontend.wssSendSnackbarMessage(`${storeId} is offline`, 5, 'warning');
2047
1411
  });
2048
- /** This event is triggered when the device went online. This means that it is discoverable in the network. */
2049
1412
  serverNode.lifecycle.online.on(async () => {
2050
1413
  this.log.notice(`Server node for ${storeId} is online`);
2051
1414
  if (!serverNode.lifecycle.isCommissioned) {
@@ -2056,16 +1419,13 @@ export class Matterbridge extends EventEmitter {
2056
1419
  this.log.notice(`Manual pairing code: ${manualPairingCode}`);
2057
1420
  }
2058
1421
  else {
2059
- // istanbul ignore next
2060
1422
  this.log.notice(`Server node for ${storeId} is already commissioned. Waiting for controllers to connect ...`);
2061
- // istanbul ignore next
2062
1423
  this.advertisingNodes.delete(storeId);
2063
1424
  }
2064
1425
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2065
1426
  this.frontend.wssSendSnackbarMessage(`${storeId} is online`, 5, 'success');
2066
1427
  this.emit('online', storeId);
2067
1428
  });
2068
- /** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
2069
1429
  serverNode.lifecycle.offline.on(() => {
2070
1430
  this.log.notice(`Server node for ${storeId} is offline`);
2071
1431
  this.advertisingNodes.delete(storeId);
@@ -2073,15 +1433,11 @@ export class Matterbridge extends EventEmitter {
2073
1433
  this.frontend.wssSendSnackbarMessage(`${storeId} is offline`, 5, 'warning');
2074
1434
  this.emit('offline', storeId);
2075
1435
  });
2076
- /**
2077
- * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
2078
- * information is needed.
2079
- */
2080
1436
  serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
2081
1437
  let action = '';
2082
1438
  switch (fabricAction) {
2083
1439
  case FabricAction.Added:
2084
- this.advertisingNodes.delete(storeId); // The advertising stops when a fabric is added
1440
+ this.advertisingNodes.delete(storeId);
2085
1441
  action = 'added';
2086
1442
  break;
2087
1443
  case FabricAction.Removed:
@@ -2094,22 +1450,14 @@ export class Matterbridge extends EventEmitter {
2094
1450
  this.log.notice(`Commissioned fabric index ${fabricIndex} ${action} on server node for ${storeId}: ${debugStringify(serverNode.state.commissioning.fabrics[fabricIndex])}`);
2095
1451
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2096
1452
  });
2097
- /**
2098
- * This event is triggered when an operative new session was opened by a Controller.
2099
- * It is not triggered for the initial commissioning process, just afterwards for real connections.
2100
- */
2101
1453
  serverNode.events.sessions.opened.on((session) => {
2102
1454
  this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
2103
1455
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2104
1456
  });
2105
- /**
2106
- * This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
2107
- */
2108
1457
  serverNode.events.sessions.closed.on((session) => {
2109
1458
  this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
2110
1459
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2111
1460
  });
2112
- /** This event is triggered when a subscription gets added or removed on an operative session. */
2113
1461
  serverNode.events.sessions.subscriptionsChanged.on((session) => {
2114
1462
  this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
2115
1463
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
@@ -2117,12 +1465,6 @@ export class Matterbridge extends EventEmitter {
2117
1465
  this.log.info(`Created server node for ${storeId}`);
2118
1466
  return serverNode;
2119
1467
  }
2120
- /**
2121
- * Gets the matter sanitized data of the specified server node.
2122
- *
2123
- * @param {ServerNode} [serverNode] - The server node to start.
2124
- * @returns {ApiMatter} The sanitized data of the server node.
2125
- */
2126
1468
  getServerNodeData(serverNode) {
2127
1469
  const advertiseTime = this.advertisingNodes.get(serverNode.id) || 0;
2128
1470
  return {
@@ -2139,25 +1481,12 @@ export class Matterbridge extends EventEmitter {
2139
1481
  serialNumber: serverNode.state.basicInformation.serialNumber,
2140
1482
  };
2141
1483
  }
2142
- /**
2143
- * Starts the specified server node.
2144
- *
2145
- * @param {ServerNode} [matterServerNode] - The server node to start.
2146
- * @returns {Promise<void>} A promise that resolves when the server node has started.
2147
- */
2148
1484
  async startServerNode(matterServerNode) {
2149
1485
  if (!matterServerNode)
2150
1486
  return;
2151
1487
  this.log.notice(`Starting ${matterServerNode.id} server node`);
2152
1488
  await matterServerNode.start();
2153
1489
  }
2154
- /**
2155
- * Stops the specified server node.
2156
- *
2157
- * @param {ServerNode} matterServerNode - The server node to stop.
2158
- * @param {number} [timeout] - The timeout in milliseconds for stopping the server node. Defaults to 30 seconds.
2159
- * @returns {Promise<void>} A promise that resolves when the server node has stopped.
2160
- */
2161
1490
  async stopServerNode(matterServerNode, timeout = 30000) {
2162
1491
  if (!matterServerNode)
2163
1492
  return;
@@ -2170,25 +1499,12 @@ export class Matterbridge extends EventEmitter {
2170
1499
  this.log.error(`Failed to close ${matterServerNode.id} server node: ${error instanceof Error ? error.message : error}`);
2171
1500
  }
2172
1501
  }
2173
- /**
2174
- * Creates an aggregator node with the specified storage context.
2175
- *
2176
- * @param {StorageContext} storageContext - The storage context for the aggregator node.
2177
- * @returns {Promise<Endpoint<AggregatorEndpoint>>} A promise that resolves to the created aggregator node.
2178
- */
2179
1502
  async createAggregatorNode(storageContext) {
2180
1503
  this.log.notice(`Creating ${await storageContext.get('storeId')} aggregator...`);
2181
1504
  const aggregatorNode = new Endpoint(AggregatorEndpoint, { id: `${await storageContext.get('storeId')}` });
2182
1505
  this.log.info(`Created ${await storageContext.get('storeId')} aggregator`);
2183
1506
  return aggregatorNode;
2184
1507
  }
2185
- /**
2186
- * Creates and configures the server node for an accessory plugin for a given device.
2187
- *
2188
- * @param {Plugin} plugin - The plugin to configure.
2189
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
2190
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
2191
- */
2192
1508
  async createAccessoryPlugin(plugin, device) {
2193
1509
  if (!plugin.locked && device.deviceType && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
2194
1510
  plugin.locked = true;
@@ -2200,12 +1516,6 @@ export class Matterbridge extends EventEmitter {
2200
1516
  await plugin.serverNode.add(device);
2201
1517
  }
2202
1518
  }
2203
- /**
2204
- * Creates and configures the server node and the aggregator node for a dynamic plugin.
2205
- *
2206
- * @param {Plugin} plugin - The plugin to configure.
2207
- * @returns {Promise<void>} A promise that resolves when the server node and the aggregator node for the dynamic plugin is created and configured.
2208
- */
2209
1519
  async createDynamicPlugin(plugin) {
2210
1520
  if (!plugin.locked) {
2211
1521
  plugin.locked = true;
@@ -2218,13 +1528,6 @@ export class Matterbridge extends EventEmitter {
2218
1528
  await plugin.serverNode.add(plugin.aggregatorNode);
2219
1529
  }
2220
1530
  }
2221
- /**
2222
- * Creates and configures the server node for a single not bridged device.
2223
- *
2224
- * @param {Plugin} plugin - The plugin to configure.
2225
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
2226
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
2227
- */
2228
1531
  async createDeviceServerNode(plugin, device) {
2229
1532
  if (device.mode === 'server' && !device.serverNode && device.deviceType && device.deviceName && device.vendorId && device.vendorName && device.productId && device.productName) {
2230
1533
  this.log.debug(`Creating device ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} server node...`);
@@ -2235,15 +1538,7 @@ export class Matterbridge extends EventEmitter {
2235
1538
  this.log.debug(`Added ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to server node`);
2236
1539
  }
2237
1540
  }
2238
- /**
2239
- * Adds a MatterbridgeEndpoint to the specified plugin.
2240
- *
2241
- * @param {string} pluginName - The name of the plugin.
2242
- * @param {MatterbridgeEndpoint} device - The device to add as a bridged endpoint.
2243
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been added.
2244
- */
2245
1541
  async addBridgedEndpoint(pluginName, device) {
2246
- // Check if the plugin is registered
2247
1542
  const plugin = this.plugins.get(pluginName);
2248
1543
  if (!plugin) {
2249
1544
  this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
@@ -2263,7 +1558,6 @@ export class Matterbridge extends EventEmitter {
2263
1558
  }
2264
1559
  else if (this.bridgeMode === 'bridge') {
2265
1560
  if (device.mode === 'matter') {
2266
- // Register and add the device to the matterbridge server node
2267
1561
  this.log.debug(`Adding matter endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge server node...`);
2268
1562
  if (!this.serverNode) {
2269
1563
  this.log.error('Server node not found for Matterbridge');
@@ -2280,7 +1574,6 @@ export class Matterbridge extends EventEmitter {
2280
1574
  }
2281
1575
  }
2282
1576
  else {
2283
- // Register and add the device to the matterbridge aggregator node
2284
1577
  this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
2285
1578
  if (!this.aggregatorNode) {
2286
1579
  this.log.error('Aggregator node not found for Matterbridge');
@@ -2298,7 +1591,6 @@ export class Matterbridge extends EventEmitter {
2298
1591
  }
2299
1592
  }
2300
1593
  else if (this.bridgeMode === 'childbridge') {
2301
- // Register and add the device to the plugin server node
2302
1594
  if (plugin.type === 'AccessoryPlatform') {
2303
1595
  try {
2304
1596
  this.log.debug(`Creating endpoint ${dev}${device.deviceName}${db} for AccessoryPlatform plugin ${plg}${plugin.name}${db} server node`);
@@ -2322,12 +1614,10 @@ export class Matterbridge extends EventEmitter {
2322
1614
  return;
2323
1615
  }
2324
1616
  }
2325
- // Register and add the device to the plugin aggregator node
2326
1617
  if (plugin.type === 'DynamicPlatform') {
2327
1618
  try {
2328
1619
  this.log.debug(`Adding bridged endpoint ${dev}${device.deviceName}${db} for DynamicPlatform plugin ${plg}${plugin.name}${db} aggregator node`);
2329
1620
  await this.createDynamicPlugin(plugin);
2330
- // Fast plugins can add another device before the server node is ready, so we wait for the server node to be ready
2331
1621
  await waiter(`createDynamicPlugin(${plugin.name})`, () => plugin.serverNode?.hasParts === true);
2332
1622
  if (!plugin.aggregatorNode) {
2333
1623
  this.log.error(`Aggregator node not found for plugin ${plg}${plugin.name}${er}`);
@@ -2348,28 +1638,17 @@ export class Matterbridge extends EventEmitter {
2348
1638
  }
2349
1639
  if (plugin.registeredDevices !== undefined)
2350
1640
  plugin.registeredDevices++;
2351
- // Add the device to the DeviceManager
2352
1641
  this.devices.set(device);
2353
- // Subscribe to the attributes changed event
2354
1642
  await this.subscribeAttributeChanged(plugin, device);
2355
1643
  this.log.info(`Added and registered bridged endpoint (${plugin.registeredDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) for plugin ${plg}${pluginName}${nf}`);
2356
1644
  }
2357
- /**
2358
- * Removes a MatterbridgeEndpoint from the specified plugin.
2359
- *
2360
- * @param {string} pluginName - The name of the plugin.
2361
- * @param {MatterbridgeEndpoint} device - The device to remove as a bridged endpoint.
2362
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been removed.
2363
- */
2364
1645
  async removeBridgedEndpoint(pluginName, device) {
2365
1646
  this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
2366
- // Check if the plugin is registered
2367
1647
  const plugin = this.plugins.get(pluginName);
2368
1648
  if (!plugin) {
2369
1649
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
2370
1650
  return;
2371
1651
  }
2372
- // Register and add the device to the matterbridge aggregator node
2373
1652
  if (this.bridgeMode === 'bridge') {
2374
1653
  if (!this.aggregatorNode) {
2375
1654
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator node not found`);
@@ -2382,7 +1661,6 @@ export class Matterbridge extends EventEmitter {
2382
1661
  }
2383
1662
  else if (this.bridgeMode === 'childbridge') {
2384
1663
  if (plugin.type === 'AccessoryPlatform') {
2385
- // Nothing to do here since the server node has no aggregator node but only the device itself
2386
1664
  }
2387
1665
  else if (plugin.type === 'DynamicPlatform') {
2388
1666
  if (!plugin.aggregatorNode) {
@@ -2395,21 +1673,8 @@ export class Matterbridge extends EventEmitter {
2395
1673
  if (plugin.registeredDevices !== undefined)
2396
1674
  plugin.registeredDevices--;
2397
1675
  }
2398
- // Remove the device from the DeviceManager
2399
1676
  this.devices.remove(device);
2400
1677
  }
2401
- /**
2402
- * Removes all bridged endpoints from the specified plugin.
2403
- *
2404
- * @param {string} pluginName - The name of the plugin.
2405
- * @param {number} [delay] - The delay in milliseconds between removing each bridged endpoint (default: 0).
2406
- * @returns {Promise<void>} A promise that resolves when all bridged endpoints have been removed.
2407
- *
2408
- * @remarks
2409
- * This method iterates through all devices in the DeviceManager and removes each bridged endpoint associated with the specified plugin.
2410
- * It also applies a delay between each removal if specified.
2411
- * The delay is useful to allow the controllers to receive a single subscription for each device removed.
2412
- */
2413
1678
  async removeAllBridgedEndpoints(pluginName, delay = 0) {
2414
1679
  this.log.debug(`Removing all bridged endpoints for plugin ${plg}${pluginName}${db}${delay > 0 ? ` with delay ${delay} ms` : ''}`);
2415
1680
  for (const device of this.devices.array().filter((device) => device.plugin === pluginName)) {
@@ -2420,24 +1685,13 @@ export class Matterbridge extends EventEmitter {
2420
1685
  if (delay > 0)
2421
1686
  await wait(2000);
2422
1687
  }
2423
- /**
2424
- * Subscribes to the attribute change event for the given device and plugin.
2425
- * Specifically, it listens for changes in the 'reachable' attribute of the
2426
- * BridgedDeviceBasicInformationServer cluster server of the bridged device or BasicInformationServer cluster server of server node.
2427
- *
2428
- * @param {Plugin} plugin - The plugin associated with the device.
2429
- * @param {MatterbridgeEndpoint} device - The device to subscribe to attribute changes for.
2430
- * @returns {Promise<void>} A promise that resolves when the subscription is set up.
2431
- */
2432
1688
  async subscribeAttributeChanged(plugin, device) {
2433
1689
  if (!plugin || !device || !device.plugin || !device.serialNumber || !device.uniqueId || !device.maybeNumber)
2434
1690
  return;
2435
1691
  this.log.info(`Subscribing attributes for endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) plugin ${plg}${plugin.name}${nf}`);
2436
- // Subscribe to the reachable$Changed event of the BasicInformationServer cluster server of the server node in childbridge mode
2437
1692
  if (this.bridgeMode === 'childbridge' && plugin.type === 'AccessoryPlatform' && plugin.serverNode) {
2438
1693
  plugin.serverNode.eventsOf(BasicInformationServer).reachable$Changed?.on((reachable) => {
2439
1694
  this.log.info(`Accessory endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) is ${reachable ? 'reachable' : 'unreachable'}`);
2440
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2441
1695
  this.frontend.wssSendAttributeChangedMessage(device.plugin, device.serialNumber, device.uniqueId, device.number, device.id, 'BasicInformation', 'reachable', reachable);
2442
1696
  });
2443
1697
  }
@@ -2487,7 +1741,6 @@ export class Matterbridge extends EventEmitter {
2487
1741
  this.log.debug(`Subscribing to endpoint ${or}${device.id}${db}:${or}${device.number}${db} attribute ${dev}${sub.cluster}${db}.${dev}${sub.attribute}${db} changes...`);
2488
1742
  await device.subscribeAttribute(sub.cluster, sub.attribute, (value) => {
2489
1743
  this.log.debug(`Bridged endpoint ${or}${device.id}${db}:${or}${device.number}${db} attribute ${dev}${sub.cluster}${db}.${dev}${sub.attribute}${db} changed to ${CYAN}${isValidObject(value) ? debugStringify(value) : value}${db}`);
2490
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2491
1744
  this.frontend.wssSendAttributeChangedMessage(device.plugin, device.serialNumber, device.uniqueId, device.number, device.id, sub.cluster, sub.attribute, value);
2492
1745
  });
2493
1746
  }
@@ -2496,19 +1749,12 @@ export class Matterbridge extends EventEmitter {
2496
1749
  this.log.debug(`Subscribing to child endpoint ${or}${child.id}${db}:${or}${child.number}${db} attribute ${dev}${sub.cluster}${db}.${dev}${sub.attribute}${db} changes...`);
2497
1750
  await child.subscribeAttribute(sub.cluster, sub.attribute, (value) => {
2498
1751
  this.log.debug(`Bridged child endpoint ${or}${child.id}${db}:${or}${child.number}${db} attribute ${dev}${sub.cluster}${db}.${dev}${sub.attribute}${db} changed to ${CYAN}${isValidObject(value) ? debugStringify(value) : value}${db}`);
2499
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2500
1752
  this.frontend.wssSendAttributeChangedMessage(device.plugin, device.serialNumber, device.uniqueId, child.number, child.id, sub.cluster, sub.attribute, value);
2501
1753
  });
2502
1754
  }
2503
1755
  }
2504
1756
  }
2505
1757
  }
2506
- /**
2507
- * Sanitizes the fabric information by converting bigint properties to strings because `res.json` doesn't support bigint.
2508
- *
2509
- * @param {ExposedFabricInformation[]} fabricInfo - The array of exposed fabric information objects.
2510
- * @returns {SanitizedExposedFabricInformation[]} An array of sanitized exposed fabric information objects.
2511
- */
2512
1758
  sanitizeFabricInformations(fabricInfo) {
2513
1759
  return fabricInfo.map((info) => {
2514
1760
  return {
@@ -2522,12 +1768,6 @@ export class Matterbridge extends EventEmitter {
2522
1768
  };
2523
1769
  });
2524
1770
  }
2525
- /**
2526
- * Sanitizes the session information by converting bigint properties to strings because `res.json` doesn't support bigint.
2527
- *
2528
- * @param {SessionsBehavior.Session[]} sessions - The array of session information objects.
2529
- * @returns {SanitizedSession[]} An array of sanitized session information objects.
2530
- */
2531
1771
  sanitizeSessionInformation(sessions) {
2532
1772
  return sessions
2533
1773
  .filter((session) => session.isPeerActive)
@@ -2554,21 +1794,7 @@ export class Matterbridge extends EventEmitter {
2554
1794
  };
2555
1795
  });
2556
1796
  }
2557
- /**
2558
- * Sets the reachability of the specified aggregator node bridged devices and trigger.
2559
- *
2560
- * @param {Endpoint<AggregatorEndpoint>} aggregatorNode - The aggregator node to set the reachability for.
2561
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2562
- */
2563
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2564
1797
  async setAggregatorReachability(aggregatorNode, reachable) {
2565
- /*
2566
- for (const child of aggregatorNode.parts) {
2567
- this.log.debug(`Setting reachability of ${(child as unknown as MatterbridgeEndpoint)?.deviceName} to ${reachable}`);
2568
- await child.setStateOf(BridgedDeviceBasicInformationServer, { reachable });
2569
- child.act((agent) => child.eventsOf(BridgedDeviceBasicInformationServer).reachableChanged.emit({ reachableNewValue: true }, agent.context));
2570
- }
2571
- */
2572
1798
  }
2573
1799
  getVendorIdName = (vendorId) => {
2574
1800
  if (!vendorId)
@@ -2608,11 +1834,10 @@ export class Matterbridge extends EventEmitter {
2608
1834
  case 0x1488:
2609
1835
  vendorName = '(ShortcutLabsFlic)';
2610
1836
  break;
2611
- case 65521: // 0xFFF1
1837
+ case 65521:
2612
1838
  vendorName = '(MatterTest)';
2613
1839
  break;
2614
1840
  }
2615
1841
  return vendorName;
2616
1842
  };
2617
1843
  }
2618
- //# sourceMappingURL=matterbridge.js.map