matterbridge 3.2.9 → 3.3.0-dev-20250928-3d2b558

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 (291) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/dist/cli.js +2 -91
  3. package/dist/cliEmitter.js +0 -30
  4. package/dist/clusters/export.js +0 -2
  5. package/dist/defaultConfigSchema.js +0 -24
  6. package/dist/deviceManager.js +1 -94
  7. package/dist/devices/airConditioner.js +0 -57
  8. package/dist/devices/batteryStorage.js +1 -48
  9. package/dist/devices/cooktop.js +0 -55
  10. package/dist/devices/dishwasher.js +0 -57
  11. package/dist/devices/evse.js +10 -74
  12. package/dist/devices/export.js +0 -5
  13. package/dist/devices/extractorHood.js +0 -42
  14. package/dist/devices/heatPump.js +2 -50
  15. package/dist/devices/laundryDryer.js +3 -62
  16. package/dist/devices/laundryWasher.js +4 -70
  17. package/dist/devices/microwaveOven.js +5 -88
  18. package/dist/devices/oven.js +0 -85
  19. package/dist/devices/refrigerator.js +0 -102
  20. package/dist/devices/roboticVacuumCleaner.js +9 -100
  21. package/dist/devices/solarPower.js +0 -38
  22. package/dist/devices/speaker.js +0 -84
  23. package/dist/devices/temperatureControl.js +3 -25
  24. package/dist/devices/waterHeater.js +2 -82
  25. package/dist/dgram/coap.js +13 -126
  26. package/dist/dgram/dgram.js +2 -114
  27. package/dist/dgram/mb_coap.js +3 -41
  28. package/dist/dgram/mb_mdns.js +15 -80
  29. package/dist/dgram/mdns.js +137 -299
  30. package/dist/dgram/multicast.js +1 -62
  31. package/dist/dgram/unicast.js +0 -54
  32. package/dist/frontend.js +29 -418
  33. package/dist/frontendTypes.js +0 -45
  34. package/dist/globalMatterbridge.js +0 -47
  35. package/dist/helpers.js +0 -53
  36. package/dist/index.js +2 -31
  37. package/dist/logger/export.js +0 -1
  38. package/dist/matter/behaviors.js +0 -2
  39. package/dist/matter/clusters.js +0 -2
  40. package/dist/matter/devices.js +0 -2
  41. package/dist/matter/endpoints.js +0 -2
  42. package/dist/matter/export.js +0 -3
  43. package/dist/matter/types.js +0 -3
  44. package/dist/matterbridge.js +52 -785
  45. package/dist/matterbridgeAccessoryPlatform.js +0 -36
  46. package/dist/matterbridgeBehaviors.js +5 -65
  47. package/dist/matterbridgeDeviceTypes.js +17 -630
  48. package/dist/matterbridgeDynamicPlatform.js +0 -36
  49. package/dist/matterbridgeEndpoint.js +58 -1398
  50. package/dist/matterbridgeEndpointHelpers.js +12 -345
  51. package/dist/matterbridgePlatform.js +32 -326
  52. package/dist/matterbridgeTypes.js +0 -25
  53. package/dist/pluginManager.js +3 -249
  54. package/dist/shelly.js +7 -168
  55. package/dist/storage/export.js +0 -1
  56. package/dist/update.js +0 -69
  57. package/dist/utils/colorUtils.js +2 -97
  58. package/dist/utils/commandLine.js +0 -54
  59. package/dist/utils/copyDirectory.js +1 -38
  60. package/dist/utils/createDirectory.js +0 -33
  61. package/dist/utils/createZip.js +2 -47
  62. package/dist/utils/deepCopy.js +0 -39
  63. package/dist/utils/deepEqual.js +1 -72
  64. package/dist/utils/error.js +0 -41
  65. package/dist/utils/export.js +0 -1
  66. package/dist/utils/hex.js +0 -124
  67. package/dist/utils/isvalid.js +0 -101
  68. package/dist/utils/jestHelpers.js +3 -153
  69. package/dist/utils/network.js +5 -91
  70. package/dist/utils/spawn.js +0 -69
  71. package/dist/utils/wait.js +8 -60
  72. package/frontend/build/assets/index.js +7 -7
  73. package/frontend/build/assets/vendor_mui.js +23 -31
  74. package/frontend/build/assets/vendor_node_modules.js +33 -25
  75. package/frontend/build/assets/vendor_notistack.js +2 -2
  76. package/frontend/build/assets/vendor_qrcode.js +1 -1
  77. package/frontend/build/assets/vendor_rjsf.js +7 -7
  78. package/frontend/package-lock.json +401 -310
  79. package/frontend/package.json +9 -9
  80. package/npm-shrinkwrap.json +2 -2
  81. package/package.json +1 -2
  82. package/dist/cli.d.ts +0 -26
  83. package/dist/cli.d.ts.map +0 -1
  84. package/dist/cli.js.map +0 -1
  85. package/dist/cliEmitter.d.ts +0 -34
  86. package/dist/cliEmitter.d.ts.map +0 -1
  87. package/dist/cliEmitter.js.map +0 -1
  88. package/dist/clusters/export.d.ts +0 -2
  89. package/dist/clusters/export.d.ts.map +0 -1
  90. package/dist/clusters/export.js.map +0 -1
  91. package/dist/defaultConfigSchema.d.ts +0 -28
  92. package/dist/defaultConfigSchema.d.ts.map +0 -1
  93. package/dist/defaultConfigSchema.js.map +0 -1
  94. package/dist/deviceManager.d.ts +0 -112
  95. package/dist/deviceManager.d.ts.map +0 -1
  96. package/dist/deviceManager.js.map +0 -1
  97. package/dist/devices/airConditioner.d.ts +0 -98
  98. package/dist/devices/airConditioner.d.ts.map +0 -1
  99. package/dist/devices/airConditioner.js.map +0 -1
  100. package/dist/devices/batteryStorage.d.ts +0 -48
  101. package/dist/devices/batteryStorage.d.ts.map +0 -1
  102. package/dist/devices/batteryStorage.js.map +0 -1
  103. package/dist/devices/cooktop.d.ts +0 -60
  104. package/dist/devices/cooktop.d.ts.map +0 -1
  105. package/dist/devices/cooktop.js.map +0 -1
  106. package/dist/devices/dishwasher.d.ts +0 -71
  107. package/dist/devices/dishwasher.d.ts.map +0 -1
  108. package/dist/devices/dishwasher.js.map +0 -1
  109. package/dist/devices/evse.d.ts +0 -75
  110. package/dist/devices/evse.d.ts.map +0 -1
  111. package/dist/devices/evse.js.map +0 -1
  112. package/dist/devices/export.d.ts +0 -17
  113. package/dist/devices/export.d.ts.map +0 -1
  114. package/dist/devices/export.js.map +0 -1
  115. package/dist/devices/extractorHood.d.ts +0 -46
  116. package/dist/devices/extractorHood.d.ts.map +0 -1
  117. package/dist/devices/extractorHood.js.map +0 -1
  118. package/dist/devices/heatPump.d.ts +0 -47
  119. package/dist/devices/heatPump.d.ts.map +0 -1
  120. package/dist/devices/heatPump.js.map +0 -1
  121. package/dist/devices/laundryDryer.d.ts +0 -67
  122. package/dist/devices/laundryDryer.d.ts.map +0 -1
  123. package/dist/devices/laundryDryer.js.map +0 -1
  124. package/dist/devices/laundryWasher.d.ts +0 -81
  125. package/dist/devices/laundryWasher.d.ts.map +0 -1
  126. package/dist/devices/laundryWasher.js.map +0 -1
  127. package/dist/devices/microwaveOven.d.ts +0 -168
  128. package/dist/devices/microwaveOven.d.ts.map +0 -1
  129. package/dist/devices/microwaveOven.js.map +0 -1
  130. package/dist/devices/oven.d.ts +0 -105
  131. package/dist/devices/oven.d.ts.map +0 -1
  132. package/dist/devices/oven.js.map +0 -1
  133. package/dist/devices/refrigerator.d.ts +0 -118
  134. package/dist/devices/refrigerator.d.ts.map +0 -1
  135. package/dist/devices/refrigerator.js.map +0 -1
  136. package/dist/devices/roboticVacuumCleaner.d.ts +0 -112
  137. package/dist/devices/roboticVacuumCleaner.d.ts.map +0 -1
  138. package/dist/devices/roboticVacuumCleaner.js.map +0 -1
  139. package/dist/devices/solarPower.d.ts +0 -40
  140. package/dist/devices/solarPower.d.ts.map +0 -1
  141. package/dist/devices/solarPower.js.map +0 -1
  142. package/dist/devices/speaker.d.ts +0 -87
  143. package/dist/devices/speaker.d.ts.map +0 -1
  144. package/dist/devices/speaker.js.map +0 -1
  145. package/dist/devices/temperatureControl.d.ts +0 -166
  146. package/dist/devices/temperatureControl.d.ts.map +0 -1
  147. package/dist/devices/temperatureControl.js.map +0 -1
  148. package/dist/devices/waterHeater.d.ts +0 -111
  149. package/dist/devices/waterHeater.d.ts.map +0 -1
  150. package/dist/devices/waterHeater.js.map +0 -1
  151. package/dist/dgram/coap.d.ts +0 -205
  152. package/dist/dgram/coap.d.ts.map +0 -1
  153. package/dist/dgram/coap.js.map +0 -1
  154. package/dist/dgram/dgram.d.ts +0 -141
  155. package/dist/dgram/dgram.d.ts.map +0 -1
  156. package/dist/dgram/dgram.js.map +0 -1
  157. package/dist/dgram/mb_coap.d.ts +0 -24
  158. package/dist/dgram/mb_coap.d.ts.map +0 -1
  159. package/dist/dgram/mb_coap.js.map +0 -1
  160. package/dist/dgram/mb_mdns.d.ts +0 -24
  161. package/dist/dgram/mb_mdns.d.ts.map +0 -1
  162. package/dist/dgram/mb_mdns.js.map +0 -1
  163. package/dist/dgram/mdns.d.ts +0 -290
  164. package/dist/dgram/mdns.d.ts.map +0 -1
  165. package/dist/dgram/mdns.js.map +0 -1
  166. package/dist/dgram/multicast.d.ts +0 -67
  167. package/dist/dgram/multicast.d.ts.map +0 -1
  168. package/dist/dgram/multicast.js.map +0 -1
  169. package/dist/dgram/unicast.d.ts +0 -56
  170. package/dist/dgram/unicast.d.ts.map +0 -1
  171. package/dist/dgram/unicast.js.map +0 -1
  172. package/dist/frontend.d.ts +0 -232
  173. package/dist/frontend.d.ts.map +0 -1
  174. package/dist/frontend.js.map +0 -1
  175. package/dist/frontendTypes.d.ts +0 -514
  176. package/dist/frontendTypes.d.ts.map +0 -1
  177. package/dist/frontendTypes.js.map +0 -1
  178. package/dist/globalMatterbridge.d.ts +0 -59
  179. package/dist/globalMatterbridge.d.ts.map +0 -1
  180. package/dist/globalMatterbridge.js.map +0 -1
  181. package/dist/helpers.d.ts +0 -48
  182. package/dist/helpers.d.ts.map +0 -1
  183. package/dist/helpers.js.map +0 -1
  184. package/dist/index.d.ts +0 -33
  185. package/dist/index.d.ts.map +0 -1
  186. package/dist/index.js.map +0 -1
  187. package/dist/logger/export.d.ts +0 -2
  188. package/dist/logger/export.d.ts.map +0 -1
  189. package/dist/logger/export.js.map +0 -1
  190. package/dist/matter/behaviors.d.ts +0 -2
  191. package/dist/matter/behaviors.d.ts.map +0 -1
  192. package/dist/matter/behaviors.js.map +0 -1
  193. package/dist/matter/clusters.d.ts +0 -2
  194. package/dist/matter/clusters.d.ts.map +0 -1
  195. package/dist/matter/clusters.js.map +0 -1
  196. package/dist/matter/devices.d.ts +0 -2
  197. package/dist/matter/devices.d.ts.map +0 -1
  198. package/dist/matter/devices.js.map +0 -1
  199. package/dist/matter/endpoints.d.ts +0 -2
  200. package/dist/matter/endpoints.d.ts.map +0 -1
  201. package/dist/matter/endpoints.js.map +0 -1
  202. package/dist/matter/export.d.ts +0 -5
  203. package/dist/matter/export.d.ts.map +0 -1
  204. package/dist/matter/export.js.map +0 -1
  205. package/dist/matter/types.d.ts +0 -3
  206. package/dist/matter/types.d.ts.map +0 -1
  207. package/dist/matter/types.js.map +0 -1
  208. package/dist/matterbridge.d.ts +0 -444
  209. package/dist/matterbridge.d.ts.map +0 -1
  210. package/dist/matterbridge.js.map +0 -1
  211. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -42
  212. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  213. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  214. package/dist/matterbridgeBehaviors.d.ts +0 -1747
  215. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  216. package/dist/matterbridgeBehaviors.js.map +0 -1
  217. package/dist/matterbridgeDeviceTypes.d.ts +0 -761
  218. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  219. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  220. package/dist/matterbridgeDynamicPlatform.d.ts +0 -42
  221. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  222. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  223. package/dist/matterbridgeEndpoint.d.ts +0 -1534
  224. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  225. package/dist/matterbridgeEndpoint.js.map +0 -1
  226. package/dist/matterbridgeEndpointHelpers.d.ts +0 -407
  227. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  228. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  229. package/dist/matterbridgePlatform.d.ts +0 -365
  230. package/dist/matterbridgePlatform.d.ts.map +0 -1
  231. package/dist/matterbridgePlatform.js.map +0 -1
  232. package/dist/matterbridgeTypes.d.ts +0 -197
  233. package/dist/matterbridgeTypes.d.ts.map +0 -1
  234. package/dist/matterbridgeTypes.js.map +0 -1
  235. package/dist/pluginManager.d.ts +0 -270
  236. package/dist/pluginManager.d.ts.map +0 -1
  237. package/dist/pluginManager.js.map +0 -1
  238. package/dist/shelly.d.ts +0 -174
  239. package/dist/shelly.d.ts.map +0 -1
  240. package/dist/shelly.js.map +0 -1
  241. package/dist/storage/export.d.ts +0 -2
  242. package/dist/storage/export.d.ts.map +0 -1
  243. package/dist/storage/export.js.map +0 -1
  244. package/dist/update.d.ts +0 -75
  245. package/dist/update.d.ts.map +0 -1
  246. package/dist/update.js.map +0 -1
  247. package/dist/utils/colorUtils.d.ts +0 -99
  248. package/dist/utils/colorUtils.d.ts.map +0 -1
  249. package/dist/utils/colorUtils.js.map +0 -1
  250. package/dist/utils/commandLine.d.ts +0 -59
  251. package/dist/utils/commandLine.d.ts.map +0 -1
  252. package/dist/utils/commandLine.js.map +0 -1
  253. package/dist/utils/copyDirectory.d.ts +0 -33
  254. package/dist/utils/copyDirectory.d.ts.map +0 -1
  255. package/dist/utils/copyDirectory.js.map +0 -1
  256. package/dist/utils/createDirectory.d.ts +0 -34
  257. package/dist/utils/createDirectory.d.ts.map +0 -1
  258. package/dist/utils/createDirectory.js.map +0 -1
  259. package/dist/utils/createZip.d.ts +0 -39
  260. package/dist/utils/createZip.d.ts.map +0 -1
  261. package/dist/utils/createZip.js.map +0 -1
  262. package/dist/utils/deepCopy.d.ts +0 -32
  263. package/dist/utils/deepCopy.d.ts.map +0 -1
  264. package/dist/utils/deepCopy.js.map +0 -1
  265. package/dist/utils/deepEqual.d.ts +0 -54
  266. package/dist/utils/deepEqual.d.ts.map +0 -1
  267. package/dist/utils/deepEqual.js.map +0 -1
  268. package/dist/utils/error.d.ts +0 -44
  269. package/dist/utils/error.d.ts.map +0 -1
  270. package/dist/utils/error.js.map +0 -1
  271. package/dist/utils/export.d.ts +0 -13
  272. package/dist/utils/export.d.ts.map +0 -1
  273. package/dist/utils/export.js.map +0 -1
  274. package/dist/utils/hex.d.ts +0 -89
  275. package/dist/utils/hex.d.ts.map +0 -1
  276. package/dist/utils/hex.js.map +0 -1
  277. package/dist/utils/isvalid.d.ts +0 -103
  278. package/dist/utils/isvalid.d.ts.map +0 -1
  279. package/dist/utils/isvalid.js.map +0 -1
  280. package/dist/utils/jestHelpers.d.ts +0 -137
  281. package/dist/utils/jestHelpers.d.ts.map +0 -1
  282. package/dist/utils/jestHelpers.js.map +0 -1
  283. package/dist/utils/network.d.ts +0 -84
  284. package/dist/utils/network.d.ts.map +0 -1
  285. package/dist/utils/network.js.map +0 -1
  286. package/dist/utils/spawn.d.ts +0 -34
  287. package/dist/utils/spawn.d.ts.map +0 -1
  288. package/dist/utils/spawn.js.map +0 -1
  289. package/dist/utils/wait.d.ts +0 -54
  290. package/dist/utils/wait.d.ts.map +0 -1
  291. package/dist/utils/wait.js.map +0 -1
@@ -1,42 +1,14 @@
1
- /**
2
- * This file contains the class Matterbridge.
3
- *
4
- * @file matterbridge.ts
5
- * @author Luca Liguori
6
- * @created 2023-12-29
7
- * @version 1.6.0
8
- * @license Apache-2.0
9
- *
10
- * Copyright 2023, 2024, 2025 Luca Liguori.
11
- *
12
- * Licensed under the Apache License, Version 2.0 (the "License");
13
- * you may not use this file except in compliance with the License.
14
- * You may obtain a copy of the License at
15
- *
16
- * http://www.apache.org/licenses/LICENSE-2.0
17
- *
18
- * Unless required by applicable law or agreed to in writing, software
19
- * distributed under the License is distributed on an "AS IS" BASIS,
20
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
- * See the License for the specific language governing permissions and
22
- * limitations under the License.
23
- */
24
- // Node.js modules
25
1
  import os from 'node:os';
26
2
  import path from 'node:path';
27
3
  import { promises as fs } from 'node:fs';
28
4
  import EventEmitter from 'node:events';
29
5
  import { inspect } from 'node:util';
30
- // AnsiLogger module
31
6
  import { AnsiLogger, UNDERLINE, UNDERLINEOFF, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN, nt, BLUE, or } from 'node-ansi-logger';
32
- // NodeStorage module
33
7
  import { NodeStorageManager } from 'node-persist-manager';
34
- // @matter
35
8
  import { DeviceTypeId, Endpoint, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageService, Environment, ServerNode, UINT32_MAX, UINT16_MAX, Crypto, } from '@matter/main';
36
9
  import { FabricAction, MdnsService, PaseClient } from '@matter/main/protocol';
37
10
  import { AggregatorEndpoint } from '@matter/main/endpoints';
38
11
  import { BasicInformationServer } from '@matter/main/behaviors/basic-information';
39
- // Matterbridge
40
12
  import { getParameter, getIntParameter, hasParameter, copyDirectory, isValidString, parseVersionString, isValidNumber, createDirectory } from './utils/export.js';
41
13
  import { withTimeout, waiter, wait } from './utils/wait.js';
42
14
  import { dev, plg, typ } from './matterbridgeTypes.js';
@@ -46,9 +18,6 @@ import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
46
18
  import { bridge } from './matterbridgeDeviceTypes.js';
47
19
  import { Frontend } from './frontend.js';
48
20
  import { addVirtualDevices } from './helpers.js';
49
- /**
50
- * Represents the Matterbridge application.
51
- */
52
21
  export class Matterbridge extends EventEmitter {
53
22
  systemInformation = {
54
23
  interfaceName: '',
@@ -89,7 +58,7 @@ export class Matterbridge extends EventEmitter {
89
58
  shellySysUpdate: false,
90
59
  shellyMainUpdate: false,
91
60
  profile: getParameter('profile'),
92
- loggerLevel: "info" /* LogLevel.INFO */,
61
+ loggerLevel: "info",
93
62
  fileLogger: false,
94
63
  matterLoggerLevel: MatterLogLevel.INFO,
95
64
  matterFileLogger: false,
@@ -117,20 +86,16 @@ export class Matterbridge extends EventEmitter {
117
86
  profile = getParameter('profile');
118
87
  shutdown = false;
119
88
  failCountLimit = hasParameter('shelly') ? 600 : 120;
120
- // Matterbridge logger
121
- log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
89
+ log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
122
90
  matterbridgeLoggerFile = 'matterbridge.log';
123
- // Matter logger
124
- matterLog = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
91
+ matterLog = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
125
92
  matterLoggerFile = 'matter.log';
126
93
  plugins = new PluginManager(this);
127
94
  devices = new DeviceManager(this);
128
95
  frontend = new Frontend(this);
129
- // Matterbridge storage
130
96
  nodeStorageName = 'storage';
131
97
  nodeStorage;
132
98
  nodeContext;
133
- // Cleanup
134
99
  hasCleanupStarted = false;
135
100
  initialized = false;
136
101
  startMatterInterval;
@@ -143,23 +108,19 @@ export class Matterbridge extends EventEmitter {
143
108
  sigtermHandler;
144
109
  exceptionHandler;
145
110
  rejectionHandler;
146
- // Matter environment
147
111
  environment = Environment.default;
148
- // Matter storage
149
112
  matterStorageName = 'matterstorage';
150
113
  matterStorageService;
151
114
  matterStorageManager;
152
115
  matterbridgeContext;
153
116
  controllerContext;
154
- // Matter parameters
155
- mdnsInterface; // matter server node mdnsInterface: e.g. 'eth0' or 'wlan0' or 'WiFi'
156
- ipv4address; // matter server node listeningAddressIpv4
157
- ipv6address; // matter server node listeningAddressIpv6
158
- port; // first server node port
159
- passcode; // first server node passcode
160
- discriminator; // first server node discriminator
161
- certification; // device certification
162
- // Matter nodes
117
+ mdnsInterface;
118
+ ipv4address;
119
+ ipv6address;
120
+ port;
121
+ passcode;
122
+ discriminator;
123
+ certification;
163
124
  serverNode;
164
125
  aggregatorNode;
165
126
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
@@ -169,35 +130,18 @@ export class Matterbridge extends EventEmitter {
169
130
  aggregatorDeviceType = DeviceTypeId(getIntParameter('deviceType') ?? bridge.code);
170
131
  aggregatorSerialNumber = getParameter('serialNumber');
171
132
  aggregatorUniqueId = getParameter('uniqueId');
172
- /** Advertising nodes map: time advertising started keyed by storeId */
173
133
  advertisingNodes = new Map();
174
134
  static instance;
175
- // We load asyncronously so is private
176
135
  constructor() {
177
136
  super();
178
137
  this.log.logNameColor = '\x1b[38;5;115m';
179
138
  }
180
- /**
181
- * Retrieves the list of Matterbridge devices.
182
- *
183
- * @returns {MatterbridgeEndpoint[]} An array of MatterbridgeDevice objects.
184
- */
185
139
  getDevices() {
186
140
  return this.devices.array();
187
141
  }
188
- /**
189
- * Retrieves the list of registered plugins.
190
- *
191
- * @returns {RegisteredPlugin[]} An array of RegisteredPlugin objects.
192
- */
193
142
  getPlugins() {
194
143
  return this.plugins.array();
195
144
  }
196
- /**
197
- * Set the logger logLevel for the Matterbridge classes and call onChangeLoggerLevel() for each plugin.
198
- *
199
- * @param {LogLevel} logLevel The logger logLevel to set.
200
- */
201
145
  async setLogLevel(logLevel) {
202
146
  if (this.log)
203
147
  this.log.logLevel = logLevel;
@@ -211,31 +155,19 @@ export class Matterbridge extends EventEmitter {
211
155
  for (const plugin of this.plugins) {
212
156
  if (!plugin.platform || !plugin.platform.log || !plugin.platform.config)
213
157
  continue;
214
- plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel;
215
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel);
216
- }
217
- // Set the global logger callback for the WebSocketServer to the common minimum logLevel
218
- let callbackLogLevel = "notice" /* LogLevel.NOTICE */;
219
- if (this.matterbridgeInformation.loggerLevel === "info" /* LogLevel.INFO */ || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.INFO)
220
- callbackLogLevel = "info" /* LogLevel.INFO */;
221
- if (this.matterbridgeInformation.loggerLevel === "debug" /* LogLevel.DEBUG */ || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.DEBUG)
222
- callbackLogLevel = "debug" /* LogLevel.DEBUG */;
158
+ plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" : this.log.logLevel;
159
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" : this.log.logLevel);
160
+ }
161
+ let callbackLogLevel = "notice";
162
+ if (this.matterbridgeInformation.loggerLevel === "info" || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.INFO)
163
+ callbackLogLevel = "info";
164
+ if (this.matterbridgeInformation.loggerLevel === "debug" || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.DEBUG)
165
+ callbackLogLevel = "debug";
223
166
  AnsiLogger.setGlobalCallback(this.frontend.wssSendLogMessage.bind(this.frontend), callbackLogLevel);
224
167
  this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
225
168
  }
226
- //* ************************************************************************************************************************************ */
227
- // loadInstance() and cleanup() methods */
228
- //* ************************************************************************************************************************************ */
229
- /**
230
- * Loads an instance of the Matterbridge class.
231
- * If an instance already exists, return that instance.
232
- *
233
- * @param {boolean} initialize - Whether to initialize the Matterbridge instance after loading. Defaults to false.
234
- * @returns {Matterbridge} A promise that resolves to the Matterbridge instance.
235
- */
236
169
  static async loadInstance(initialize = false) {
237
170
  if (!Matterbridge.instance) {
238
- // eslint-disable-next-line no-console
239
171
  if (hasParameter('debug'))
240
172
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
241
173
  Matterbridge.instance = new Matterbridge();
@@ -244,17 +176,8 @@ export class Matterbridge extends EventEmitter {
244
176
  }
245
177
  return Matterbridge.instance;
246
178
  }
247
- /**
248
- * Call cleanup() and dispose MdnsService.
249
- *
250
- * @param {number} [timeout] - The timeout duration to wait for the cleanup to complete in milliseconds. Default is 1000.
251
- * @param {number} [pause] - The pause duration after the cleanup in milliseconds. Default is 250.
252
- *
253
- * @deprecated This method is deprecated and is ONLY used for jest tests.
254
- */
255
179
  async destroyInstance(timeout = 1000, pause = 250) {
256
180
  this.log.info(`Destroy instance...`);
257
- // Save server nodes to close
258
181
  const servers = [];
259
182
  if (this.bridgeMode === 'bridge') {
260
183
  if (this.serverNode)
@@ -272,106 +195,72 @@ export class Matterbridge extends EventEmitter {
272
195
  servers.push(device.serverNode);
273
196
  }
274
197
  }
275
- // Let any already‐queued microtasks run first
276
198
  await Promise.resolve();
277
- // Wait for the cleanup to finish
278
199
  await wait(pause, 'destroyInstance start', true);
279
- // Cleanup
280
200
  await this.cleanup('destroying instance...', false, timeout);
281
- // Close servers mdns service
282
201
  this.log.info(`Dispose ${servers.length} MdnsService...`);
283
202
  for (const server of servers) {
284
203
  await server.env.get(MdnsService)[Symbol.asyncDispose]();
285
204
  this.log.info(`Closed ${server.id} MdnsService`);
286
205
  }
287
- // Let any already‐queued microtasks run first
288
206
  await Promise.resolve();
289
- // Wait for the cleanup to finish
290
207
  await wait(pause, 'destroyInstance stop', true);
291
208
  }
292
- /**
293
- * Initializes the Matterbridge application.
294
- *
295
- * @remarks
296
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
297
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
298
- * node version, registers signal handlers, initializes storage, and parses the command line.
299
- *
300
- * @returns {Promise<void>} A Promise that resolves when the initialization is complete.
301
- */
302
209
  async initialize() {
303
- // for (let i = 1; i <= 255; i++) console.log(`\x1b[38;5;${i}mColor: ${i}`);
304
- // Emit the initialize_started event
305
210
  this.emit('initialize_started');
306
- // Set the restart mode
307
211
  if (hasParameter('service'))
308
212
  this.restartMode = 'service';
309
213
  if (hasParameter('docker'))
310
214
  this.restartMode = 'docker';
311
- // Set the matterbridge home directory
312
215
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
313
216
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
314
217
  await createDirectory(this.homeDirectory, 'Matterbridge Home Directory', this.log);
315
- // Set the matterbridge directory
316
218
  this.matterbridgeDirectory = this.profile ? path.join(this.homeDirectory, '.matterbridge', 'profiles', this.profile) : path.join(this.homeDirectory, '.matterbridge');
317
219
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
318
220
  await createDirectory(this.matterbridgeDirectory, 'Matterbridge Directory', this.log);
319
221
  await createDirectory(path.join(this.matterbridgeDirectory, 'certs'), 'Matterbridge Frontend Certificate Directory', this.log);
320
222
  await createDirectory(path.join(this.matterbridgeDirectory, 'uploads'), 'Matterbridge Frontend Uploads Directory', this.log);
321
- // Set the matterbridge plugin directory
322
223
  this.matterbridgePluginDirectory = this.profile ? path.join(this.homeDirectory, 'Matterbridge', 'profiles', this.profile) : path.join(this.homeDirectory, 'Matterbridge');
323
224
  this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
324
225
  await createDirectory(this.matterbridgePluginDirectory, 'Matterbridge Plugin Directory', this.log);
325
- // Set the matterbridge cert directory
326
226
  this.matterbridgeCertDirectory = this.profile ? path.join(this.homeDirectory, '.mattercert', 'profiles', this.profile) : path.join(this.homeDirectory, '.mattercert');
327
227
  this.matterbridgeInformation.matterbridgeCertDirectory = this.matterbridgeCertDirectory;
328
228
  await createDirectory(this.matterbridgeCertDirectory, 'Matterbridge Matter Certificate Directory', this.log);
329
- // Set the matterbridge root directory
330
229
  const { fileURLToPath } = await import('node:url');
331
230
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
332
231
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
333
232
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
334
- // Setup the matter environment
335
233
  this.environment.vars.set('log.level', MatterLogLevel.INFO);
336
234
  this.environment.vars.set('log.format', MatterLogFormat.ANSI);
337
235
  this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, this.matterStorageName));
338
236
  this.environment.vars.set('runtime.signals', false);
339
237
  this.environment.vars.set('runtime.exitcode', false);
340
- // Register process handlers
341
238
  this.registerProcessHandlers();
342
- // Initialize nodeStorage and nodeContext
343
239
  try {
344
240
  this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
345
241
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
346
242
  this.log.debug('Creating node storage context for matterbridge');
347
243
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
348
- // TODO: Remove this code when node-persist-manager is updated
349
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
350
244
  const keys = (await this.nodeStorage?.storage.keys());
351
245
  for (const key of keys) {
352
246
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
353
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
354
247
  await this.nodeStorage?.storage.get(key);
355
248
  }
356
249
  const storages = await this.nodeStorage.getStorageNames();
357
250
  for (const storage of storages) {
358
251
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
359
252
  const nodeContext = await this.nodeStorage?.createStorage(storage);
360
- // TODO: Remove this code when node-persist-manager is updated
361
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
362
253
  const keys = (await nodeContext?.storage.keys());
363
254
  keys.forEach(async (key) => {
364
255
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
365
256
  await nodeContext?.get(key);
366
257
  });
367
258
  }
368
- // Creating a backup of the node storage since it is not corrupted
369
259
  this.log.debug('Creating node storage backup...');
370
260
  await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
371
261
  this.log.debug('Created node storage backup');
372
262
  }
373
263
  catch (error) {
374
- // Restoring the backup of the node storage since it is corrupted
375
264
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
376
265
  if (hasParameter('norestore')) {
377
266
  this.log.fatal(`The matterbridge storage is corrupted. Found -norestore parameter: exiting...`);
@@ -385,19 +274,14 @@ export class Matterbridge extends EventEmitter {
385
274
  if (!this.nodeStorage || !this.nodeContext) {
386
275
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
387
276
  }
388
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
389
277
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
390
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
391
278
  this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode')) ?? PaseClient.generateRandomPasscode(this.environment.get(Crypto));
392
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
393
279
  this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator')) ?? PaseClient.generateRandomDiscriminator(this.environment.get(Crypto));
394
- // Certificate management
395
280
  const pairingFilePath = path.join(this.matterbridgeCertDirectory, 'pairing.json');
396
281
  try {
397
282
  await fs.access(pairingFilePath, fs.constants.R_OK);
398
283
  const pairingFileContent = await fs.readFile(pairingFilePath, 'utf8');
399
284
  const pairingFileJson = JSON.parse(pairingFileContent);
400
- // Set the vendorId, vendorName, productId, productName, deviceType, serialNumber, uniqueId if they are present in the pairing file
401
285
  if (isValidNumber(pairingFileJson.vendorId)) {
402
286
  this.aggregatorVendorId = VendorId(pairingFileJson.vendorId);
403
287
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using vendorId ${CYAN}${this.aggregatorVendorId}${nf} from pairing file.`);
@@ -426,13 +310,11 @@ export class Matterbridge extends EventEmitter {
426
310
  this.aggregatorUniqueId = pairingFileJson.uniqueId;
427
311
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using uniqueId ${CYAN}${this.aggregatorUniqueId}${nf} from pairing file.`);
428
312
  }
429
- // Override the passcode and discriminator if they are present in the pairing file
430
313
  if (isValidNumber(pairingFileJson.passcode) && isValidNumber(pairingFileJson.discriminator)) {
431
314
  this.passcode = pairingFileJson.passcode;
432
315
  this.discriminator = pairingFileJson.discriminator;
433
316
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using passcode ${CYAN}${this.passcode}${nf} and discriminator ${CYAN}${this.discriminator}${nf} from pairing file.`);
434
317
  }
435
- // Set the certification for matter.js if it is present in the pairing file
436
318
  if (pairingFileJson.privateKey && pairingFileJson.certificate && pairingFileJson.intermediateCertificate && pairingFileJson.declaration) {
437
319
  const { hexToBuffer } = await import('./utils/hex.js');
438
320
  this.certification = {
@@ -447,44 +329,41 @@ export class Matterbridge extends EventEmitter {
447
329
  catch (error) {
448
330
  this.log.debug(`Pairing file ${CYAN}${pairingFilePath}${db} not found: ${error instanceof Error ? error.message : error}`);
449
331
  }
450
- // Store the passcode, discriminator and port in the node context
451
332
  await this.nodeContext.set('matterport', this.port);
452
333
  await this.nodeContext.set('matterpasscode', this.passcode);
453
334
  await this.nodeContext.set('matterdiscriminator', this.discriminator);
454
335
  this.log.debug(`Initializing server node for Matterbridge on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
455
- // Set matterbridge logger level (context: matterbridgeLogLevel)
456
336
  if (hasParameter('logger')) {
457
337
  const level = getParameter('logger');
458
338
  if (level === 'debug') {
459
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
339
+ this.log.logLevel = "debug";
460
340
  }
461
341
  else if (level === 'info') {
462
- this.log.logLevel = "info" /* LogLevel.INFO */;
342
+ this.log.logLevel = "info";
463
343
  }
464
344
  else if (level === 'notice') {
465
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
345
+ this.log.logLevel = "notice";
466
346
  }
467
347
  else if (level === 'warn') {
468
- this.log.logLevel = "warn" /* LogLevel.WARN */;
348
+ this.log.logLevel = "warn";
469
349
  }
470
350
  else if (level === 'error') {
471
- this.log.logLevel = "error" /* LogLevel.ERROR */;
351
+ this.log.logLevel = "error";
472
352
  }
473
353
  else if (level === 'fatal') {
474
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
354
+ this.log.logLevel = "fatal";
475
355
  }
476
356
  else {
477
357
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
478
- this.log.logLevel = "info" /* LogLevel.INFO */;
358
+ this.log.logLevel = "info";
479
359
  }
480
360
  }
481
361
  else {
482
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.matterbridgeInformation.shellyBoard ? "notice" /* LogLevel.NOTICE */ : "info" /* LogLevel.INFO */);
362
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.matterbridgeInformation.shellyBoard ? "notice" : "info");
483
363
  }
484
364
  this.frontend.logLevel = this.log.logLevel;
485
365
  MatterbridgeEndpoint.logLevel = this.log.logLevel;
486
366
  this.matterbridgeInformation.loggerLevel = this.log.logLevel;
487
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
488
367
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
489
368
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbridgeLoggerFile), this.log.logLevel, true);
490
369
  this.matterbridgeInformation.fileLogger = true;
@@ -493,7 +372,6 @@ export class Matterbridge extends EventEmitter {
493
372
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
494
373
  if (this.profile !== undefined)
495
374
  this.log.debug(`Matterbridge profile: ${this.profile}.`);
496
- // Set matter.js logger level, format and logger (context: matterLogLevel)
497
375
  if (hasParameter('matterlogger')) {
498
376
  const level = getParameter('matterlogger');
499
377
  if (level === 'debug') {
@@ -523,14 +401,12 @@ export class Matterbridge extends EventEmitter {
523
401
  Logger.level = (await this.nodeContext.get('matterLogLevel', this.matterbridgeInformation.shellyBoard ? MatterLogLevel.NOTICE : MatterLogLevel.INFO));
524
402
  }
525
403
  Logger.format = MatterLogFormat.ANSI;
526
- // Create the logger for matter.js with file logging (context: matterFileLog)
527
404
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
528
405
  this.matterbridgeInformation.matterFileLogger = true;
529
406
  }
530
407
  Logger.destinations.default.write = this.createDestinationMatterLogger(this.matterbridgeInformation.matterFileLogger);
531
408
  this.matterbridgeInformation.matterLoggerLevel = Logger.level;
532
409
  this.log.debug(`Matter logLevel: ${Logger.level} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
533
- // Log network interfaces
534
410
  const networkInterfaces = os.networkInterfaces();
535
411
  const availableAddresses = Object.entries(networkInterfaces);
536
412
  const availableInterfaces = Object.keys(networkInterfaces);
@@ -543,7 +419,6 @@ export class Matterbridge extends EventEmitter {
543
419
  });
544
420
  }
545
421
  }
546
- // Set the interface to use for matter server node mdnsInterface
547
422
  if (hasParameter('mdnsinterface')) {
548
423
  this.mdnsInterface = getParameter('mdnsinterface');
549
424
  }
@@ -552,7 +427,6 @@ export class Matterbridge extends EventEmitter {
552
427
  if (this.mdnsInterface === '')
553
428
  this.mdnsInterface = undefined;
554
429
  }
555
- // Validate mdnsInterface
556
430
  if (this.mdnsInterface) {
557
431
  if (!availableInterfaces.includes(this.mdnsInterface)) {
558
432
  this.log.error(`Invalid mdnsinterface: ${this.mdnsInterface}. Available interfaces are: ${availableInterfaces.join(', ')}. Using all available interfaces.`);
@@ -565,7 +439,6 @@ export class Matterbridge extends EventEmitter {
565
439
  }
566
440
  if (this.mdnsInterface)
567
441
  this.environment.vars.set('mdns.networkInterface', this.mdnsInterface);
568
- // Set the listeningAddressIpv4 for the matter commissioning server
569
442
  if (hasParameter('ipv4address')) {
570
443
  this.ipv4address = getParameter('ipv4address');
571
444
  }
@@ -574,7 +447,6 @@ export class Matterbridge extends EventEmitter {
574
447
  if (this.ipv4address === '')
575
448
  this.ipv4address = undefined;
576
449
  }
577
- // Validate ipv4address
578
450
  if (this.ipv4address) {
579
451
  let isValid = false;
580
452
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -590,7 +462,6 @@ export class Matterbridge extends EventEmitter {
590
462
  await this.nodeContext.remove('matteripv4address');
591
463
  }
592
464
  }
593
- // Set the listeningAddressIpv6 for the matter commissioning server
594
465
  if (hasParameter('ipv6address')) {
595
466
  this.ipv6address = getParameter('ipv6address');
596
467
  }
@@ -599,7 +470,6 @@ export class Matterbridge extends EventEmitter {
599
470
  if (this.ipv6address === '')
600
471
  this.ipv6address = undefined;
601
472
  }
602
- // Validate ipv6address
603
473
  if (this.ipv6address) {
604
474
  let isValid = false;
605
475
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -608,7 +478,6 @@ export class Matterbridge extends EventEmitter {
608
478
  isValid = true;
609
479
  break;
610
480
  }
611
- /* istanbul ignore next */
612
481
  if (ifaces && ifaces.find((iface) => iface.scopeid && iface.scopeid > 0 && iface.address + '%' + (process.platform === 'win32' ? iface.scopeid : ifaceName) === this.ipv6address)) {
613
482
  this.log.info(`Using ipv6address ${CYAN}${this.ipv6address}${nf} on interface ${CYAN}${ifaceName}${nf} for the Matter server node.`);
614
483
  isValid = true;
@@ -621,7 +490,6 @@ export class Matterbridge extends EventEmitter {
621
490
  await this.nodeContext.remove('matteripv6address');
622
491
  }
623
492
  }
624
- // Initialize the virtual mode
625
493
  if (hasParameter('novirtual')) {
626
494
  this.matterbridgeInformation.virtualMode = 'disabled';
627
495
  await this.nodeContext.set('virtualmode', 'disabled');
@@ -630,17 +498,12 @@ export class Matterbridge extends EventEmitter {
630
498
  this.matterbridgeInformation.virtualMode = (await this.nodeContext.get('virtualmode', 'outlet'));
631
499
  }
632
500
  this.log.debug(`Virtual mode ${this.matterbridgeInformation.virtualMode}.`);
633
- // Initialize PluginManager
634
501
  this.plugins.logLevel = this.log.logLevel;
635
502
  await this.plugins.loadFromStorage();
636
- // Initialize DeviceManager
637
503
  this.devices.logLevel = this.log.logLevel;
638
- // Get the plugins from node storage and create the plugins node storage contexts
639
504
  for (const plugin of this.plugins) {
640
505
  const packageJson = await this.plugins.parse(plugin);
641
506
  if (packageJson === null && !hasParameter('add') && !hasParameter('remove') && !hasParameter('enable') && !hasParameter('disable') && !hasParameter('reset') && !hasParameter('factoryreset')) {
642
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
643
- // We don't do this when the add and other parameters are set because we shut down the process after adding the plugin
644
507
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
645
508
  try {
646
509
  const { spawnCommand } = await import('./utils/spawn.js');
@@ -663,7 +526,6 @@ export class Matterbridge extends EventEmitter {
663
526
  await plugin.nodeContext.set('description', plugin.description);
664
527
  await plugin.nodeContext.set('author', plugin.author);
665
528
  }
666
- // Log system info and create .matterbridge directory
667
529
  await this.logNodeAndSystemInfo();
668
530
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
669
531
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -671,7 +533,6 @@ export class Matterbridge extends EventEmitter {
671
533
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
672
534
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
673
535
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
674
- // Check node version and throw error
675
536
  const minNodeVersion = 18;
676
537
  const nodeVersion = process.versions.node;
677
538
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -679,18 +540,10 @@ export class Matterbridge extends EventEmitter {
679
540
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
680
541
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
681
542
  }
682
- // Parse command line
683
543
  await this.parseCommandLine();
684
- // Emit the initialize_completed event
685
544
  this.emit('initialize_completed');
686
545
  this.initialized = true;
687
546
  }
688
- /**
689
- * Parses the command line arguments and performs the corresponding actions.
690
- *
691
- * @private
692
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
693
- */
694
547
  async parseCommandLine() {
695
548
  if (hasParameter('help')) {
696
549
  this.log.info(`\nUsage: matterbridge [options]\n
@@ -752,19 +605,6 @@ export class Matterbridge extends EventEmitter {
752
605
  }
753
606
  index++;
754
607
  }
755
- /*
756
- const serializedRegisteredDevices = await this.nodeContext?.get<SerializedMatterbridgeEndpoint[]>('devices', []);
757
- this.log.info(`│ Registered devices (${serializedRegisteredDevices?.length})`);
758
- serializedRegisteredDevices?.forEach((device, index) => {
759
- if (index !== serializedRegisteredDevices.length - 1) {
760
- this.log.info(`├─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
761
- this.log.info(`│ └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
762
- } else {
763
- this.log.info(`└─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
764
- this.log.info(` └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
765
- }
766
- });
767
- */
768
608
  this.shutdown = true;
769
609
  return;
770
610
  }
@@ -814,10 +654,8 @@ export class Matterbridge extends EventEmitter {
814
654
  this.shutdown = true;
815
655
  return;
816
656
  }
817
- // Initialize frontend
818
657
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
819
658
  await this.frontend.start(getIntParameter('frontend'));
820
- // Start the matter storage and create the matterbridge context
821
659
  try {
822
660
  await this.startMatterStorage();
823
661
  if (this.aggregatorSerialNumber && this.aggregatorUniqueId && this.matterStorageService) {
@@ -833,21 +671,18 @@ export class Matterbridge extends EventEmitter {
833
671
  this.log.fatal(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
834
672
  throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
835
673
  }
836
- // Clear the matterbridge context if the reset parameter is set
837
674
  if (hasParameter('reset') && getParameter('reset') === undefined) {
838
675
  this.initialized = true;
839
676
  await this.shutdownProcessAndReset();
840
677
  this.shutdown = true;
841
678
  return;
842
679
  }
843
- // Clear matterbridge plugin context if the reset parameter is set
844
680
  if (hasParameter('reset') && getParameter('reset') !== undefined) {
845
681
  this.log.debug(`Reset plugin ${getParameter('reset')}`);
846
682
  const plugin = this.plugins.get(getParameter('reset'));
847
683
  if (plugin) {
848
684
  const matterStorageManager = await this.matterStorageService?.open(plugin.name);
849
685
  if (!matterStorageManager) {
850
- /* istanbul ignore next */
851
686
  this.log.error(`Plugin ${plg}${plugin.name}${er} storageManager not found`);
852
687
  }
853
688
  else {
@@ -866,44 +701,35 @@ export class Matterbridge extends EventEmitter {
866
701
  this.shutdown = true;
867
702
  return;
868
703
  }
869
- // Initialize frontend
870
- // if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined) await this.frontend.start(getIntParameter('frontend'));
871
- // Check in 30 seconds the latest and dev versions of matterbridge and the plugins
872
704
  clearTimeout(this.checkUpdateTimeout);
873
705
  this.checkUpdateTimeout = setTimeout(async () => {
874
706
  const { checkUpdates } = await import('./update.js');
875
707
  checkUpdates(this);
876
708
  }, 30 * 1000).unref();
877
- // Check each 12 hours the latest and dev versions of matterbridge and the plugins
878
709
  clearInterval(this.checkUpdateInterval);
879
710
  this.checkUpdateInterval = setInterval(async () => {
880
711
  const { checkUpdates } = await import('./update.js');
881
712
  checkUpdates(this);
882
713
  }, 12 * 60 * 60 * 1000).unref();
883
- // Start the matterbridge in mode test
884
714
  if (hasParameter('test')) {
885
715
  this.bridgeMode = 'bridge';
886
716
  return;
887
717
  }
888
- // Start the matterbridge in mode controller
889
718
  if (hasParameter('controller')) {
890
719
  this.bridgeMode = 'controller';
891
720
  await this.startController();
892
721
  return;
893
722
  }
894
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
895
723
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
896
724
  this.log.info('Setting default matterbridge start mode to bridge');
897
725
  await this.nodeContext?.set('bridgeMode', 'bridge');
898
726
  }
899
- // Start matterbridge in bridge mode
900
727
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
901
728
  this.bridgeMode = 'bridge';
902
729
  this.log.debug(`Starting matterbridge in mode ${this.bridgeMode}`);
903
730
  await this.startBridge();
904
731
  return;
905
732
  }
906
- // Start matterbridge in childbridge mode
907
733
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
908
734
  this.bridgeMode = 'childbridge';
909
735
  this.log.debug(`Starting matterbridge in mode ${this.bridgeMode}`);
@@ -911,22 +737,10 @@ export class Matterbridge extends EventEmitter {
911
737
  return;
912
738
  }
913
739
  }
914
- /**
915
- * Asynchronously loads and starts the registered plugins.
916
- *
917
- * This method is responsible for initializing and starting all enabled plugins.
918
- * It ensures that each plugin is properly loaded and started before the bridge starts.
919
- *
920
- * @param {boolean} [wait] - If true, the method will wait for all plugins to be fully loaded and started before resolving.
921
- * @param {boolean} [start] - If true, the method will start the plugins after loading them.
922
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
923
- */
924
740
  async startPlugins(wait = false, start = true) {
925
- // Check, load and start the plugins
926
741
  for (const plugin of this.plugins) {
927
742
  plugin.configJson = await this.plugins.loadConfig(plugin);
928
743
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
929
- // Check if the plugin is available
930
744
  if (!(await this.plugins.resolve(plugin.path))) {
931
745
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
932
746
  plugin.enabled = false;
@@ -946,14 +760,10 @@ export class Matterbridge extends EventEmitter {
946
760
  if (wait)
947
761
  await this.plugins.load(plugin, start, 'Matterbridge is starting');
948
762
  else
949
- this.plugins.load(plugin, start, 'Matterbridge is starting'); // No await do it asyncronously
763
+ this.plugins.load(plugin, start, 'Matterbridge is starting');
950
764
  }
951
765
  this.frontend.wssSendRefreshRequired('plugins');
952
766
  }
953
- /**
954
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
955
- * When either of these signals are received, the cleanup method is called with an appropriate message.
956
- */
957
767
  registerProcessHandlers() {
958
768
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
959
769
  process.removeAllListeners('uncaughtException');
@@ -980,9 +790,6 @@ export class Matterbridge extends EventEmitter {
980
790
  };
981
791
  process.on('SIGTERM', this.sigtermHandler);
982
792
  }
983
- /**
984
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
985
- */
986
793
  deregisterProcessHandlers() {
987
794
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
988
795
  if (this.exceptionHandler)
@@ -999,17 +806,12 @@ export class Matterbridge extends EventEmitter {
999
806
  process.off('SIGTERM', this.sigtermHandler);
1000
807
  this.sigtermHandler = undefined;
1001
808
  }
1002
- /**
1003
- * Logs the node and system information.
1004
- */
1005
809
  async logNodeAndSystemInfo() {
1006
- // IP address information
1007
810
  const networkInterfaces = os.networkInterfaces();
1008
811
  this.systemInformation.interfaceName = '';
1009
812
  this.systemInformation.ipv4Address = '';
1010
813
  this.systemInformation.ipv6Address = '';
1011
814
  for (const [interfaceName, interfaceDetails] of Object.entries(networkInterfaces)) {
1012
- // this.log.debug(`Checking interface: '${interfaceName}' for '${this.mdnsInterface}'`);
1013
815
  if (this.mdnsInterface && interfaceName !== this.mdnsInterface)
1014
816
  continue;
1015
817
  if (!interfaceDetails) {
@@ -1035,22 +837,19 @@ export class Matterbridge extends EventEmitter {
1035
837
  break;
1036
838
  }
1037
839
  }
1038
- // Node information
1039
840
  this.systemInformation.nodeVersion = process.versions.node;
1040
841
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
1041
842
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
1042
843
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
1043
- // Host system information
1044
844
  this.systemInformation.hostname = os.hostname();
1045
845
  this.systemInformation.user = os.userInfo().username;
1046
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
1047
- this.systemInformation.osRelease = os.release(); // Kernel version
1048
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
1049
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
1050
- this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
1051
- this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
1052
- this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours'; // Convert to hours
1053
- // Log the system information
846
+ this.systemInformation.osType = os.type();
847
+ this.systemInformation.osRelease = os.release();
848
+ this.systemInformation.osPlatform = os.platform();
849
+ this.systemInformation.osArch = os.arch();
850
+ this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
851
+ this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
852
+ this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours';
1054
853
  this.log.debug('Host System Information:');
1055
854
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
1056
855
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -1066,17 +865,14 @@ export class Matterbridge extends EventEmitter {
1066
865
  this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
1067
866
  this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
1068
867
  this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
1069
- // Log directories
1070
868
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
1071
869
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
1072
870
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
1073
871
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
1074
872
  this.log.debug(`Matterbridge Matter Certificate Directory: ${this.matterbridgeCertDirectory}`);
1075
- // Global node_modules directory
1076
873
  if (this.nodeContext)
1077
874
  this.globalModulesDirectory = this.matterbridgeInformation.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
1078
875
  if (this.globalModulesDirectory === '') {
1079
- // First run of Matterbridge so the node storage is empty
1080
876
  this.log.debug(`Getting global node_modules directory...`);
1081
877
  try {
1082
878
  const { getGlobalNodeModules } = await import('./utils/network.js');
@@ -1089,7 +885,6 @@ export class Matterbridge extends EventEmitter {
1089
885
  }
1090
886
  }
1091
887
  else {
1092
- // The global node_modules directory is already set in the node storage and we check if it is still valid
1093
888
  this.log.debug(`Checking global node_modules directory: ${this.globalModulesDirectory}`);
1094
889
  try {
1095
890
  const { getGlobalNodeModules } = await import('./utils/network.js');
@@ -1101,86 +896,58 @@ export class Matterbridge extends EventEmitter {
1101
896
  this.log.error(`Error checking global node_modules directory: ${error}`);
1102
897
  }
1103
898
  }
1104
- // Matterbridge version
1105
899
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
1106
900
  this.matterbridgeVersion = this.matterbridgeLatestVersion = this.matterbridgeDevVersion = packageJson.version;
1107
901
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeInformation.matterbridgeLatestVersion = this.matterbridgeInformation.matterbridgeDevVersion = packageJson.version;
1108
902
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
1109
- // Matterbridge latest version (will be set in the checkUpdate function)
1110
903
  if (this.nodeContext)
1111
904
  this.matterbridgeLatestVersion = this.matterbridgeInformation.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', this.matterbridgeVersion);
1112
905
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
1113
- // Matterbridge dev version (will be set in the checkUpdate function)
1114
906
  if (this.nodeContext)
1115
907
  this.matterbridgeDevVersion = this.matterbridgeInformation.matterbridgeDevVersion = await this.nodeContext.get('matterbridgeDevVersion', this.matterbridgeVersion);
1116
908
  this.log.debug(`Matterbridge Dev Version: ${this.matterbridgeDevVersion}`);
1117
- // Current working directory
1118
909
  const currentDir = process.cwd();
1119
910
  this.log.debug(`Current Working Directory: ${currentDir}`);
1120
- // Command line arguments (excluding 'node' and the script name)
1121
911
  const cmdArgs = process.argv.slice(2).join(' ');
1122
912
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
1123
913
  }
1124
- /**
1125
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
1126
- * It also logs to file (matter.log) if fileLogger is true.
1127
- *
1128
- * @param {boolean} fileLogger - Whether to log to file or not.
1129
- * @returns {Function} The MatterLogger function. \x1b[35m for violet \x1b[34m is blue
1130
- */
1131
914
  createDestinationMatterLogger(fileLogger) {
1132
- this.matterLog.logNameColor = '\x1b[34m'; // Blue matter.js Logger
915
+ this.matterLog.logNameColor = '\x1b[34m';
1133
916
  if (fileLogger) {
1134
917
  this.matterLog.logFilePath = path.join(this.matterbridgeDirectory, this.matterLoggerFile);
1135
918
  }
1136
919
  return (text, message) => {
1137
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1138
920
  const logger = text.slice(44, 44 + 20).trim();
1139
921
  const msg = text.slice(65);
1140
922
  this.matterLog.logName = logger;
1141
923
  switch (message.level) {
1142
924
  case MatterLogLevel.DEBUG:
1143
- this.matterLog.log("debug" /* LogLevel.DEBUG */, msg);
925
+ this.matterLog.log("debug", msg);
1144
926
  break;
1145
927
  case MatterLogLevel.INFO:
1146
- this.matterLog.log("info" /* LogLevel.INFO */, msg);
928
+ this.matterLog.log("info", msg);
1147
929
  break;
1148
930
  case MatterLogLevel.NOTICE:
1149
- this.matterLog.log("notice" /* LogLevel.NOTICE */, msg);
931
+ this.matterLog.log("notice", msg);
1150
932
  break;
1151
933
  case MatterLogLevel.WARN:
1152
- this.matterLog.log("warn" /* LogLevel.WARN */, msg);
934
+ this.matterLog.log("warn", msg);
1153
935
  break;
1154
936
  case MatterLogLevel.ERROR:
1155
- this.matterLog.log("error" /* LogLevel.ERROR */, msg);
937
+ this.matterLog.log("error", msg);
1156
938
  break;
1157
939
  case MatterLogLevel.FATAL:
1158
- this.matterLog.log("fatal" /* LogLevel.FATAL */, msg);
940
+ this.matterLog.log("fatal", msg);
1159
941
  break;
1160
942
  }
1161
943
  };
1162
944
  }
1163
- /**
1164
- * Restarts the process by exiting the current instance and loading a new instance (/api/restart).
1165
- *
1166
- * @returns {Promise<void>} A promise that resolves when the restart is completed.
1167
- */
1168
945
  async restartProcess() {
1169
946
  await this.cleanup('restarting...', true);
1170
947
  }
1171
- /**
1172
- * Shut down the process (/api/shutdown).
1173
- *
1174
- * @returns {Promise<void>} A promise that resolves when the shutdown is completed.
1175
- */
1176
948
  async shutdownProcess() {
1177
949
  await this.cleanup('shutting down...', false);
1178
950
  }
1179
- /**
1180
- * Update matterbridge and shut down the process (virtual device 'Update Matterbridge').
1181
- *
1182
- * @returns {Promise<void>} A promise that resolves when the update is completed.
1183
- */
1184
951
  async updateProcess() {
1185
952
  this.log.info('Updating matterbridge...');
1186
953
  try {
@@ -1194,13 +961,6 @@ export class Matterbridge extends EventEmitter {
1194
961
  this.frontend.wssSendRestartRequired();
1195
962
  await this.cleanup('updating...', false);
1196
963
  }
1197
- /**
1198
- * Unregister all devices and shut down the process (/api/unregister).
1199
- *
1200
- * @param {number} [timeout] - The timeout duration to wait for the message exchange to complete in milliseconds. Default is 1000.
1201
- *
1202
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1203
- */
1204
964
  async unregisterAndShutdownProcess(timeout = 1000) {
1205
965
  this.log.info('Unregistering all devices and shutting down...');
1206
966
  for (const plugin of this.plugins.array()) {
@@ -1212,71 +972,46 @@ export class Matterbridge extends EventEmitter {
1212
972
  await this.removeAllBridgedEndpoints(plugin.name, 100);
1213
973
  }
1214
974
  this.log.debug('Waiting for the MessageExchange to finish...');
1215
- await wait(timeout); // Wait for MessageExchange to finish
975
+ await wait(timeout);
1216
976
  this.log.debug('Cleaning up and shutting down...');
1217
977
  await this.cleanup('unregistered all devices and shutting down...', false, timeout);
1218
978
  }
1219
- /**
1220
- * Reset commissioning and shut down the process (/api/reset).
1221
- *
1222
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1223
- */
1224
979
  async shutdownProcessAndReset() {
1225
980
  await this.cleanup('shutting down with reset...', false);
1226
981
  }
1227
- /**
1228
- * Factory reset and shut down the process (/api/factory-reset).
1229
- *
1230
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1231
- */
1232
982
  async shutdownProcessAndFactoryReset() {
1233
983
  await this.cleanup('shutting down with factory reset...', false);
1234
984
  }
1235
- /**
1236
- * Cleans up the Matterbridge instance.
1237
- *
1238
- * @param {string} message - The cleanup message.
1239
- * @param {boolean} [restart] - Indicates whether to restart the instance after cleanup. Default is `false`.
1240
- * @param {number} [timeout] - The timeout duration to wait for the message exchange to complete in milliseconds. Default is 1000.
1241
- *
1242
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1243
- */
1244
985
  async cleanup(message, restart = false, timeout = 1000) {
1245
986
  if (this.initialized && !this.hasCleanupStarted) {
1246
987
  this.emit('cleanup_started');
1247
988
  this.hasCleanupStarted = true;
1248
989
  this.log.info(message);
1249
- // Clear the start matter interval
1250
990
  if (this.startMatterInterval) {
1251
991
  clearInterval(this.startMatterInterval);
1252
992
  this.startMatterInterval = undefined;
1253
993
  this.log.debug('Start matter interval cleared');
1254
994
  }
1255
- // Clear the check update timeout
1256
995
  if (this.checkUpdateTimeout) {
1257
996
  clearTimeout(this.checkUpdateTimeout);
1258
997
  this.checkUpdateTimeout = undefined;
1259
998
  this.log.debug('Check update timeout cleared');
1260
999
  }
1261
- // Clear the check update interval
1262
1000
  if (this.checkUpdateInterval) {
1263
1001
  clearInterval(this.checkUpdateInterval);
1264
1002
  this.checkUpdateInterval = undefined;
1265
1003
  this.log.debug('Check update interval cleared');
1266
1004
  }
1267
- // Clear the configure timeout
1268
1005
  if (this.configureTimeout) {
1269
1006
  clearTimeout(this.configureTimeout);
1270
1007
  this.configureTimeout = undefined;
1271
1008
  this.log.debug('Matterbridge configure timeout cleared');
1272
1009
  }
1273
- // Clear the reachability timeout
1274
1010
  if (this.reachabilityTimeout) {
1275
1011
  clearTimeout(this.reachabilityTimeout);
1276
1012
  this.reachabilityTimeout = undefined;
1277
1013
  this.log.debug('Matterbridge reachability timeout cleared');
1278
1014
  }
1279
- // Call the shutdown method of each plugin and clear the plugins reachability timeout
1280
1015
  for (const plugin of this.plugins) {
1281
1016
  if (!plugin.enabled || plugin.error)
1282
1017
  continue;
@@ -1287,7 +1022,6 @@ export class Matterbridge extends EventEmitter {
1287
1022
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1288
1023
  }
1289
1024
  }
1290
- // Stop matter server nodes
1291
1025
  this.log.notice(`Stopping matter server nodes in ${this.bridgeMode} mode...`);
1292
1026
  this.log.debug('Waiting for the MessageExchange to finish...');
1293
1027
  await wait(timeout, 'Waiting for the MessageExchange to finish...', true);
@@ -1312,7 +1046,6 @@ export class Matterbridge extends EventEmitter {
1312
1046
  }
1313
1047
  }
1314
1048
  this.log.notice('Stopped matter server nodes');
1315
- // Matter commisioning reset
1316
1049
  if (message === 'shutting down with reset...') {
1317
1050
  this.log.info('Resetting Matterbridge commissioning information...');
1318
1051
  await this.matterStorageManager?.createContext('events')?.clearAll();
@@ -1322,7 +1055,6 @@ export class Matterbridge extends EventEmitter {
1322
1055
  await this.matterbridgeContext?.clearAll();
1323
1056
  this.log.info('Matter storage reset done! Remove the bridge from the controller.');
1324
1057
  }
1325
- // Unregister all devices
1326
1058
  if (message === 'unregistered all devices and shutting down...') {
1327
1059
  if (this.bridgeMode === 'bridge') {
1328
1060
  await this.matterStorageManager?.createContext('root')?.createContext('parts')?.createContext('Matterbridge')?.createContext('parts')?.clearAll();
@@ -1340,29 +1072,12 @@ export class Matterbridge extends EventEmitter {
1340
1072
  }
1341
1073
  this.log.info('Matter storage reset done!');
1342
1074
  }
1343
- // Stop matter storage
1344
1075
  await this.stopMatterStorage();
1345
- // Stop the frontend
1346
1076
  await this.frontend.stop();
1347
- // Close the matterbridge node storage and context
1348
1077
  if (this.nodeStorage && this.nodeContext) {
1349
- /*
1350
- TODO: Implement serialization of registered devices in edge mode
1351
- this.log.info('Saving registered devices...');
1352
- const serializedRegisteredDevices: SerializedMatterbridgeEndpoint[] = [];
1353
- this.devices.forEach(async (device) => {
1354
- const serializedMatterbridgeDevice = MatterbridgeEndpoint.serialize(device);
1355
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1356
- if (serializedMatterbridgeDevice) serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1357
- });
1358
- await this.nodeContext.set<SerializedMatterbridgeEndpoint[]>('devices', serializedRegisteredDevices);
1359
- this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1360
- */
1361
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1362
1078
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1363
1079
  await this.nodeContext.close();
1364
1080
  this.nodeContext = undefined;
1365
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1366
1081
  for (const plugin of this.plugins) {
1367
1082
  if (plugin.nodeContext) {
1368
1083
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1379,10 +1094,8 @@ export class Matterbridge extends EventEmitter {
1379
1094
  }
1380
1095
  this.plugins.clear();
1381
1096
  this.devices.clear();
1382
- // Factory reset
1383
1097
  if (message === 'shutting down with factory reset...') {
1384
1098
  try {
1385
- // Delete matter storage directory with its subdirectories and backup
1386
1099
  const dir = path.join(this.matterbridgeDirectory, this.matterStorageName);
1387
1100
  this.log.info(`Removing matter storage directory: ${dir}`);
1388
1101
  await fs.rm(dir, { recursive: true });
@@ -1391,13 +1104,11 @@ export class Matterbridge extends EventEmitter {
1391
1104
  await fs.rm(backup, { recursive: true });
1392
1105
  }
1393
1106
  catch (error) {
1394
- // istanbul ignore next if
1395
1107
  if (error instanceof Error && error.code !== 'ENOENT') {
1396
1108
  this.log.error(`Error removing matter storage directory: ${error}`);
1397
1109
  }
1398
1110
  }
1399
1111
  try {
1400
- // Delete matterbridge storage directory with its subdirectories and backup
1401
1112
  const dir = path.join(this.matterbridgeDirectory, this.nodeStorageName);
1402
1113
  this.log.info(`Removing matterbridge storage directory: ${dir}`);
1403
1114
  await fs.rm(dir, { recursive: true });
@@ -1406,20 +1117,18 @@ export class Matterbridge extends EventEmitter {
1406
1117
  await fs.rm(backup, { recursive: true });
1407
1118
  }
1408
1119
  catch (error) {
1409
- // istanbul ignore next if
1410
1120
  if (error instanceof Error && error.code !== 'ENOENT') {
1411
1121
  this.log.error(`Error removing matterbridge storage directory: ${error}`);
1412
1122
  }
1413
1123
  }
1414
1124
  this.log.info('Factory reset done! Remove all paired fabrics from the controllers.');
1415
1125
  }
1416
- // Deregisters the process handlers
1417
1126
  this.deregisterProcessHandlers();
1418
1127
  if (restart) {
1419
1128
  if (message === 'updating...') {
1420
1129
  this.log.info('Cleanup completed. Updating...');
1421
1130
  Matterbridge.instance = undefined;
1422
- this.emit('update'); // Restart the process but the update has been done before. TODO move all updates to the cli
1131
+ this.emit('update');
1423
1132
  }
1424
1133
  else if (message === 'restarting...') {
1425
1134
  this.log.info('Cleanup completed. Restarting...');
@@ -1440,13 +1149,6 @@ export class Matterbridge extends EventEmitter {
1440
1149
  this.log.debug('Cleanup already started...');
1441
1150
  }
1442
1151
  }
1443
- /**
1444
- * Creates and configures the server node for a single not bridged device.
1445
- *
1446
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1447
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
1448
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
1449
- */
1450
1152
  async createDeviceServerNode(plugin, device) {
1451
1153
  if (device.mode === 'server' && !device.serverNode && device.deviceType && device.deviceName && device.vendorId && device.vendorName && device.productId && device.productName) {
1452
1154
  this.log.debug(`Creating device ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} server node...`);
@@ -1457,13 +1159,6 @@ export class Matterbridge extends EventEmitter {
1457
1159
  this.log.debug(`Added ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to server node`);
1458
1160
  }
1459
1161
  }
1460
- /**
1461
- * Creates and configures the server node for an accessory plugin for a given device.
1462
- *
1463
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1464
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
1465
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
1466
- */
1467
1162
  async createAccessoryPlugin(plugin, device) {
1468
1163
  if (!plugin.locked && device.deviceType && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
1469
1164
  plugin.locked = true;
@@ -1474,12 +1169,6 @@ export class Matterbridge extends EventEmitter {
1474
1169
  await plugin.serverNode.add(device);
1475
1170
  }
1476
1171
  }
1477
- /**
1478
- * Creates and configures the server node and the aggregator node for a dynamic plugin.
1479
- *
1480
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1481
- * @returns {Promise<void>} A promise that resolves when the server node and the aggregator node for the dynamic plugin is created and configured.
1482
- */
1483
1172
  async createDynamicPlugin(plugin) {
1484
1173
  if (!plugin.locked) {
1485
1174
  plugin.locked = true;
@@ -1489,14 +1178,7 @@ export class Matterbridge extends EventEmitter {
1489
1178
  await plugin.serverNode.add(plugin.aggregatorNode);
1490
1179
  }
1491
1180
  }
1492
- /**
1493
- * Starts the Matterbridge in bridge mode.
1494
- *
1495
- * @private
1496
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1497
- */
1498
1181
  async startBridge() {
1499
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1500
1182
  if (!this.matterStorageManager)
1501
1183
  throw new Error('No storage manager initialized');
1502
1184
  if (!this.matterbridgeContext)
@@ -1535,16 +1217,13 @@ export class Matterbridge extends EventEmitter {
1535
1217
  clearInterval(this.startMatterInterval);
1536
1218
  this.startMatterInterval = undefined;
1537
1219
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1538
- // Start the Matter server node
1539
- this.startServerNode(this.serverNode); // We don't await this, because the server node is started in the background
1540
- // Start the Matter server node of single devices in mode 'server'
1220
+ this.startServerNode(this.serverNode);
1541
1221
  for (const device of this.devices.array()) {
1542
1222
  if (device.mode === 'server' && device.serverNode) {
1543
1223
  this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
1544
- this.startServerNode(device.serverNode); // We don't await this, because the server node is started in the background
1224
+ this.startServerNode(device.serverNode);
1545
1225
  }
1546
1226
  }
1547
- // Configure the plugins
1548
1227
  this.configureTimeout = setTimeout(async () => {
1549
1228
  for (const plugin of this.plugins.array()) {
1550
1229
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1562,40 +1241,28 @@ export class Matterbridge extends EventEmitter {
1562
1241
  }
1563
1242
  this.frontend.wssSendRefreshRequired('plugins');
1564
1243
  }, 30 * 1000).unref();
1565
- // Setting reachability to true
1566
1244
  this.reachabilityTimeout = setTimeout(() => {
1567
1245
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1568
1246
  if (this.aggregatorNode)
1569
1247
  this.setAggregatorReachability(this.aggregatorNode, true);
1570
1248
  }, 60 * 1000).unref();
1571
- // Logger.get('LogServerNode').info(this.serverNode);
1572
1249
  this.emit('bridge_started');
1573
1250
  this.log.notice('Matterbridge bridge started successfully');
1574
1251
  this.frontend.wssSendRefreshRequired('settings');
1575
1252
  this.frontend.wssSendRefreshRequired('plugins');
1576
1253
  }, this.startMatterIntervalMs);
1577
1254
  }
1578
- /**
1579
- * Starts the Matterbridge in childbridge mode.
1580
- *
1581
- * @param {number} [delay] - The delay before starting the childbridge. Default is 1000 milliseconds.
1582
- *
1583
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1584
- */
1585
1255
  async startChildbridge(delay = 1000) {
1586
1256
  if (!this.matterStorageManager)
1587
1257
  throw new Error('No storage manager initialized');
1588
- // Load with await all plugins but don't start them. We get the platform.type to pre-create server nodes for DynamicPlatform plugins
1589
1258
  this.log.debug('Loading all plugins in childbridge mode...');
1590
1259
  await this.startPlugins(true, false);
1591
- // Create server nodes for DynamicPlatform plugins and start all plugins in the background
1592
1260
  this.log.debug('Creating server nodes for DynamicPlatform plugins and starting all plugins in childbridge mode...');
1593
1261
  for (const plugin of this.plugins.array().filter((p) => p.enabled && !p.error)) {
1594
1262
  if (plugin.type === 'DynamicPlatform')
1595
1263
  await this.createDynamicPlugin(plugin);
1596
- this.plugins.start(plugin, 'Matterbridge is starting'); // Start the plugin in the background
1264
+ this.plugins.start(plugin, 'Matterbridge is starting');
1597
1265
  }
1598
- // Start the Matterbridge in childbridge mode when all plugins are loaded and started
1599
1266
  this.log.debug('Starting start matter interval in childbridge mode...');
1600
1267
  let failCount = 0;
1601
1268
  this.startMatterInterval = setInterval(async () => {
@@ -1629,9 +1296,8 @@ export class Matterbridge extends EventEmitter {
1629
1296
  clearInterval(this.startMatterInterval);
1630
1297
  this.startMatterInterval = undefined;
1631
1298
  if (delay > 0)
1632
- await wait(delay); // Wait for the specified delay to ensure all plugins server nodes are ready
1299
+ await wait(delay);
1633
1300
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1634
- // Configure the plugins
1635
1301
  this.configureTimeout = setTimeout(async () => {
1636
1302
  for (const plugin of this.plugins.array()) {
1637
1303
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1656,7 +1322,6 @@ export class Matterbridge extends EventEmitter {
1656
1322
  this.log.error(`Plugin ${plg}${plugin.name}${er} didn't register any devices to Matterbridge. Verify the plugin configuration.`);
1657
1323
  continue;
1658
1324
  }
1659
- // istanbul ignore next if cause is just a safety check
1660
1325
  if (!plugin.serverNode) {
1661
1326
  this.log.error(`Server node not found for plugin ${plg}${plugin.name}${er}`);
1662
1327
  continue;
@@ -1669,252 +1334,28 @@ export class Matterbridge extends EventEmitter {
1669
1334
  this.log.error(`Node storage context not found for plugin ${plg}${plugin.name}${er}`);
1670
1335
  continue;
1671
1336
  }
1672
- // Start the Matter server node
1673
- this.startServerNode(plugin.serverNode); // We don't await this, because the server node is started in the background
1674
- // Setting reachability to true
1337
+ this.startServerNode(plugin.serverNode);
1675
1338
  plugin.reachabilityTimeout = setTimeout(() => {
1676
- this.log.info(`Setting reachability to true for ${plg}${plugin.name}${nf} type ${plugin.type} server node ${plugin.serverNode !== undefined} aggregator node ${plugin.aggregatorNode !== undefined} device ${plugin.device !== undefined}`);
1339
+ this.log.info(`Setting reachability to true for ${plg}${plugin.name}${nf}`);
1677
1340
  if (plugin.type === 'DynamicPlatform' && plugin.aggregatorNode)
1678
1341
  this.setAggregatorReachability(plugin.aggregatorNode, true);
1679
1342
  }, 60 * 1000).unref();
1680
1343
  }
1681
- // Start the Matter server node of single devices in mode 'server'
1682
1344
  for (const device of this.devices.array()) {
1683
1345
  if (device.mode === 'server' && device.serverNode) {
1684
1346
  this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
1685
- this.startServerNode(device.serverNode); // We don't await this, because the server node is started in the background
1347
+ this.startServerNode(device.serverNode);
1686
1348
  }
1687
1349
  }
1688
- // Logger.get('LogServerNode').info(this.serverNode);
1689
1350
  this.emit('childbridge_started');
1690
1351
  this.log.notice('Matterbridge childbridge started successfully');
1691
1352
  this.frontend.wssSendRefreshRequired('settings');
1692
1353
  this.frontend.wssSendRefreshRequired('plugins');
1693
1354
  }, this.startMatterIntervalMs);
1694
1355
  }
1695
- /**
1696
- * Starts the Matterbridge controller.
1697
- *
1698
- * @private
1699
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1700
- */
1701
1356
  async startController() {
1702
- /*
1703
- if (!this.matterStorageManager) {
1704
- this.log.error('No storage manager initialized');
1705
- await this.cleanup('No storage manager initialized');
1706
- return;
1707
- }
1708
- this.log.info('Creating context: mattercontrollerContext');
1709
- this.controllerContext = this.matterStorageManager.createContext('mattercontrollerContext');
1710
- if (!this.controllerContext) {
1711
- this.log.error('No storage context mattercontrollerContext initialized');
1712
- await this.cleanup('No storage context mattercontrollerContext initialized');
1713
- return;
1714
- }
1715
-
1716
- this.log.debug('Starting matterbridge in mode', this.bridgeMode);
1717
- this.matterServer = await this.createMatterServer(this.storageManager);
1718
- this.log.info('Creating matter commissioning controller');
1719
- this.commissioningController = new CommissioningController({
1720
- autoConnect: false,
1721
- });
1722
- this.log.info('Adding matter commissioning controller to matter server');
1723
- await this.matterServer.addCommissioningController(this.commissioningController);
1724
-
1725
- this.log.info('Starting matter server');
1726
- await this.matterServer.start();
1727
- this.log.info('Matter server started');
1728
- const commissioningOptions: ControllerCommissioningFlowOptions = {
1729
- regulatoryLocation: GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor,
1730
- regulatoryCountryCode: 'XX',
1731
- };
1732
- const commissioningController = new CommissioningController({
1733
- environment: {
1734
- environment,
1735
- id: uniqueId,
1736
- },
1737
- autoConnect: false, // Do not auto connect to the commissioned nodes
1738
- adminFabricLabel,
1739
- });
1740
-
1741
- if (hasParameter('pairingcode')) {
1742
- this.log.info('Pairing device with pairingcode:', getParameter('pairingcode'));
1743
- const pairingCode = getParameter('pairingcode');
1744
- const ip = this.controllerContext.has('ip') ? this.controllerContext.get<string>('ip') : undefined;
1745
- const port = this.controllerContext.has('port') ? this.controllerContext.get<number>('port') : undefined;
1746
-
1747
- let longDiscriminator, setupPin, shortDiscriminator;
1748
- if (pairingCode !== undefined) {
1749
- const pairingCodeCodec = ManualPairingCodeCodec.decode(pairingCode);
1750
- shortDiscriminator = pairingCodeCodec.shortDiscriminator;
1751
- longDiscriminator = undefined;
1752
- setupPin = pairingCodeCodec.passcode;
1753
- this.log.info(`Data extracted from pairing code: ${Logger.toJSON(pairingCodeCodec)}`);
1754
- } else {
1755
- longDiscriminator = await this.controllerContext.get('longDiscriminator', 3840);
1756
- if (longDiscriminator > 4095) throw new Error('Discriminator value must be less than 4096');
1757
- setupPin = this.controllerContext.get('pin', 20202021);
1758
- }
1759
- if ((shortDiscriminator === undefined && longDiscriminator === undefined) || setupPin === undefined) {
1760
- throw new Error('Please specify the longDiscriminator of the device to commission with -longDiscriminator or provide a valid passcode with -passcode');
1761
- }
1762
-
1763
- const options = {
1764
- commissioning: commissioningOptions,
1765
- discovery: {
1766
- knownAddress: ip !== undefined && port !== undefined ? { ip, port, type: 'udp' } : undefined,
1767
- identifierData: longDiscriminator !== undefined ? { longDiscriminator } : shortDiscriminator !== undefined ? { shortDiscriminator } : {},
1768
- },
1769
- passcode: setupPin,
1770
- } as NodeCommissioningOptions;
1771
- this.log.info('Commissioning with options:', options);
1772
- const nodeId = await this.commissioningController.commissionNode(options);
1773
- this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1774
- this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1775
- } // (hasParameter('pairingcode'))
1776
-
1777
- if (hasParameter('unpairall')) {
1778
- this.log.info('***Commissioning controller unpairing all nodes...');
1779
- const nodeIds = this.commissioningController.getCommissionedNodes();
1780
- for (const nodeId of nodeIds) {
1781
- this.log.info('***Commissioning controller unpairing node:', nodeId);
1782
- await this.commissioningController.removeNode(nodeId);
1783
- }
1784
- return;
1785
- }
1786
-
1787
- if (hasParameter('discover')) {
1788
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1789
- // console.log(discover);
1790
- }
1791
-
1792
- if (!this.commissioningController.isCommissioned()) {
1793
- this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
1794
- return;
1795
- }
1796
-
1797
- const nodeIds = this.commissioningController.getCommissionedNodes();
1798
- this.log.info(`***Commissioning controller is commissioned ${this.commissioningController.isCommissioned()} and has ${nodeIds.length} nodes commisioned: `);
1799
- for (const nodeId of nodeIds) {
1800
- this.log.info(`***Connecting to commissioned node: ${nodeId}`);
1801
-
1802
- const node = await this.commissioningController.connectNode(nodeId, {
1803
- autoSubscribe: false,
1804
- attributeChangedCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, attributeName }, value }) =>
1805
- this.log.info(`***Commissioning controller attributeChangedCallback ${peerNodeId}: attribute ${nodeId}/${endpointId}/${clusterId}/${attributeName} changed to ${Logger.toJSON(value)}`),
1806
- eventTriggeredCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, eventName }, events }) =>
1807
- this.log.info(`***Commissioning controller eventTriggeredCallback ${peerNodeId}: Event ${nodeId}/${endpointId}/${clusterId}/${eventName} triggered with ${Logger.toJSON(events)}`),
1808
- stateInformationCallback: (peerNodeId, info) => {
1809
- switch (info) {
1810
- case NodeStateInformation.Connected:
1811
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} connected`);
1812
- break;
1813
- case NodeStateInformation.Disconnected:
1814
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} disconnected`);
1815
- break;
1816
- case NodeStateInformation.Reconnecting:
1817
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} reconnecting`);
1818
- break;
1819
- case NodeStateInformation.WaitingForDeviceDiscovery:
1820
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} waiting for device discovery`);
1821
- break;
1822
- case NodeStateInformation.StructureChanged:
1823
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} structure changed`);
1824
- break;
1825
- case NodeStateInformation.Decommissioned:
1826
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} decommissioned`);
1827
- break;
1828
- default:
1829
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} NodeStateInformation.${info}`);
1830
- break;
1831
- }
1832
- },
1833
- });
1834
-
1835
- node.logStructure();
1836
-
1837
- // Get the interaction client
1838
- this.log.info('Getting the interaction client');
1839
- const interactionClient = await node.getInteractionClient();
1840
- let cluster;
1841
- let attributes;
1842
-
1843
- // Log BasicInformationCluster
1844
- cluster = BasicInformationCluster;
1845
- attributes = await interactionClient.getMultipleAttributes({
1846
- attributes: [{ clusterId: cluster.id }],
1847
- });
1848
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1849
- attributes.forEach((attribute) => {
1850
- this.log.info(
1851
- `- 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}`,
1852
- );
1853
- });
1854
-
1855
- // Log PowerSourceCluster
1856
- cluster = PowerSourceCluster;
1857
- attributes = await interactionClient.getMultipleAttributes({
1858
- attributes: [{ clusterId: cluster.id }],
1859
- });
1860
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1861
- attributes.forEach((attribute) => {
1862
- this.log.info(
1863
- `- 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}`,
1864
- );
1865
- });
1866
-
1867
- // Log ThreadNetworkDiagnostics
1868
- cluster = ThreadNetworkDiagnosticsCluster;
1869
- attributes = await interactionClient.getMultipleAttributes({
1870
- attributes: [{ clusterId: cluster.id }],
1871
- });
1872
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1873
- attributes.forEach((attribute) => {
1874
- this.log.info(
1875
- `- 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}`,
1876
- );
1877
- });
1878
-
1879
- // Log SwitchCluster
1880
- cluster = SwitchCluster;
1881
- attributes = await interactionClient.getMultipleAttributes({
1882
- attributes: [{ clusterId: cluster.id }],
1883
- });
1884
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1885
- attributes.forEach((attribute) => {
1886
- this.log.info(
1887
- `- 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}`,
1888
- );
1889
- });
1890
-
1891
- this.log.info('Subscribing to all attributes and events');
1892
- await node.subscribeAllAttributesAndEvents({
1893
- ignoreInitialTriggers: false,
1894
- attributeChangedCallback: ({ path: { nodeId, clusterId, endpointId, attributeName }, version, value }) =>
1895
- this.log.info(
1896
- `***${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}`,
1897
- ),
1898
- eventTriggeredCallback: ({ path: { nodeId, clusterId, endpointId, eventName }, events }) => {
1899
- this.log.info(
1900
- `***${db}Commissioning controller eventTriggeredCallback: event ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${eventName}${db} triggered with ${debugStringify(events ?? { none: true })}`,
1901
- );
1902
- },
1903
- });
1904
- this.log.info('Subscribed to all attributes and events');
1905
- }
1906
- */
1907
1357
  }
1908
- /** */
1909
- /** Matter.js methods */
1910
- /** */
1911
- /**
1912
- * Starts the matter storage with name Matterbridge, create the matterbridge context and performs a backup.
1913
- *
1914
- * @returns {Promise<void>} - A promise that resolves when the storage is started.
1915
- */
1916
1358
  async startMatterStorage() {
1917
- // Setup Matter storage
1918
1359
  this.log.info(`Starting matter node storage...`);
1919
1360
  this.matterStorageService = this.environment.get(StorageService);
1920
1361
  this.log.info(`Matter node storage service created: ${this.matterStorageService.location}`);
@@ -1922,17 +1363,8 @@ export class Matterbridge extends EventEmitter {
1922
1363
  this.log.info('Matter node storage manager "Matterbridge" created');
1923
1364
  this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId);
1924
1365
  this.log.info('Matter node storage started');
1925
- // Backup matter storage since it is created/opened correctly
1926
1366
  await this.backupMatterStorage(path.join(this.matterbridgeDirectory, this.matterStorageName), path.join(this.matterbridgeDirectory, this.matterStorageName + '.backup'));
1927
1367
  }
1928
- /**
1929
- * Makes a backup copy of the specified matter storage directory.
1930
- *
1931
- * @param {string} storageName - The name of the storage directory to be backed up.
1932
- * @param {string} backupName - The name of the backup directory to be created.
1933
- * @private
1934
- * @returns {Promise<void>} A promise that resolves when the has been done.
1935
- */
1936
1368
  async backupMatterStorage(storageName, backupName) {
1937
1369
  this.log.info('Creating matter node storage backup...');
1938
1370
  try {
@@ -1943,11 +1375,6 @@ export class Matterbridge extends EventEmitter {
1943
1375
  this.log.error(`Error creating matter node storage backup from ${storageName} to ${backupName}:`, error);
1944
1376
  }
1945
1377
  }
1946
- /**
1947
- * Stops the matter storage.
1948
- *
1949
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1950
- */
1951
1378
  async stopMatterStorage() {
1952
1379
  this.log.info('Closing matter node storage...');
1953
1380
  await this.matterStorageManager?.close();
@@ -1956,20 +1383,6 @@ export class Matterbridge extends EventEmitter {
1956
1383
  this.matterbridgeContext = undefined;
1957
1384
  this.log.info('Matter node storage closed');
1958
1385
  }
1959
- /**
1960
- * Creates a server node storage context.
1961
- *
1962
- * @param {string} storeId - The storeId.
1963
- * @param {string} deviceName - The name of the device.
1964
- * @param {DeviceTypeId} deviceType - The device type of the device.
1965
- * @param {number} vendorId - The vendor ID.
1966
- * @param {string} vendorName - The vendor name.
1967
- * @param {number} productId - The product ID.
1968
- * @param {string} productName - The product name.
1969
- * @param {string} [serialNumber] - The serial number of the device (optional).
1970
- * @param {string} [uniqueId] - The unique ID of the device (optional).
1971
- * @returns {Promise<StorageContext>} The storage context for the commissioning server.
1972
- */
1973
1386
  async createServerNodeContext(storeId, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber, uniqueId) {
1974
1387
  const { randomBytes } = await import('node:crypto');
1975
1388
  if (!this.matterStorageService)
@@ -2009,15 +1422,6 @@ export class Matterbridge extends EventEmitter {
2009
1422
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2010
1423
  return storageContext;
2011
1424
  }
2012
- /**
2013
- * Creates a server node.
2014
- *
2015
- * @param {StorageContext} storageContext - The storage context for the server node.
2016
- * @param {number} [port] - The port number for the server node. Defaults to 5540.
2017
- * @param {number} [passcode] - The passcode for the server node. Defaults to 20242025.
2018
- * @param {number} [discriminator] - The discriminator for the server node. Defaults to 3850.
2019
- * @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created server node.
2020
- */
2021
1425
  async createServerNode(storageContext, port = 5540, passcode = 20242025, discriminator = 3850) {
2022
1426
  const storeId = await storageContext.get('storeId');
2023
1427
  this.log.notice(`Creating server node for ${storeId} on port ${port} with passcode ${passcode} and discriminator ${discriminator}...`);
@@ -2027,37 +1431,24 @@ export class Matterbridge extends EventEmitter {
2027
1431
  this.log.debug(`- uniqueId: ${await storageContext.get('uniqueId')}`);
2028
1432
  this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
2029
1433
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2030
- /**
2031
- * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
2032
- */
2033
1434
  const serverNode = await ServerNode.create({
2034
- // Required: Give the Node a unique ID which is used to store the state of this node
2035
1435
  id: storeId,
2036
- // Provide Network relevant configuration like the port
2037
- // Optional when operating only one device on a host, Default port is 5540
2038
1436
  network: {
2039
1437
  listeningAddressIpv4: this.ipv4address,
2040
1438
  listeningAddressIpv6: this.ipv6address,
2041
1439
  port,
2042
1440
  },
2043
- // Provide the certificate for the device
2044
1441
  operationalCredentials: {
2045
1442
  certification: this.certification,
2046
1443
  },
2047
- // Provide Commissioning relevant settings
2048
- // Optional for development/testing purposes
2049
1444
  commissioning: {
2050
1445
  passcode,
2051
1446
  discriminator,
2052
1447
  },
2053
- // Provide Node announcement settings
2054
- // Optional: If Ommitted some development defaults are used
2055
1448
  productDescription: {
2056
1449
  name: await storageContext.get('deviceName'),
2057
1450
  deviceType: DeviceTypeId(await storageContext.get('deviceType')),
2058
1451
  },
2059
- // Provide defaults for the BasicInformation cluster on the Root endpoint
2060
- // Optional: If Omitted some development defaults are used
2061
1452
  basicInformation: {
2062
1453
  vendorId: VendorId(await storageContext.get('vendorId')),
2063
1454
  vendorName: await storageContext.get('vendorName'),
@@ -2074,23 +1465,17 @@ export class Matterbridge extends EventEmitter {
2074
1465
  reachable: true,
2075
1466
  },
2076
1467
  });
2077
- /**
2078
- * This event is triggered when the device is initially commissioned successfully.
2079
- * This means: It is added to the first fabric.
2080
- */
2081
1468
  serverNode.lifecycle.commissioned.on(() => {
2082
1469
  this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`);
2083
1470
  this.advertisingNodes.delete(storeId);
2084
1471
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2085
1472
  });
2086
- /** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
2087
1473
  serverNode.lifecycle.decommissioned.on(() => {
2088
1474
  this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`);
2089
1475
  this.advertisingNodes.delete(storeId);
2090
1476
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2091
1477
  this.frontend.wssSendSnackbarMessage(`${storeId} is offline`, 5, 'warning');
2092
1478
  });
2093
- /** This event is triggered when the device went online. This means that it is discoverable in the network. */
2094
1479
  serverNode.lifecycle.online.on(async () => {
2095
1480
  this.log.notice(`Server node for ${storeId} is online`);
2096
1481
  if (!serverNode.lifecycle.isCommissioned) {
@@ -2101,16 +1486,13 @@ export class Matterbridge extends EventEmitter {
2101
1486
  this.log.notice(`Manual pairing code: ${manualPairingCode}`);
2102
1487
  }
2103
1488
  else {
2104
- // istanbul ignore next
2105
1489
  this.log.notice(`Server node for ${storeId} is already commissioned. Waiting for controllers to connect ...`);
2106
- // istanbul ignore next
2107
1490
  this.advertisingNodes.delete(storeId);
2108
1491
  }
2109
1492
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2110
1493
  this.frontend.wssSendSnackbarMessage(`${storeId} is online`, 5, 'success');
2111
1494
  this.emit('online', storeId);
2112
1495
  });
2113
- /** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
2114
1496
  serverNode.lifecycle.offline.on(() => {
2115
1497
  this.log.notice(`Server node for ${storeId} is offline`);
2116
1498
  this.advertisingNodes.delete(storeId);
@@ -2118,15 +1500,11 @@ export class Matterbridge extends EventEmitter {
2118
1500
  this.frontend.wssSendSnackbarMessage(`${storeId} is offline`, 5, 'warning');
2119
1501
  this.emit('offline', storeId);
2120
1502
  });
2121
- /**
2122
- * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
2123
- * information is needed.
2124
- */
2125
1503
  serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
2126
1504
  let action = '';
2127
1505
  switch (fabricAction) {
2128
1506
  case FabricAction.Added:
2129
- this.advertisingNodes.delete(storeId); // The advertising stops when a fabric is added
1507
+ this.advertisingNodes.delete(storeId);
2130
1508
  action = 'added';
2131
1509
  break;
2132
1510
  case FabricAction.Removed:
@@ -2139,22 +1517,14 @@ export class Matterbridge extends EventEmitter {
2139
1517
  this.log.notice(`Commissioned fabric index ${fabricIndex} ${action} on server node for ${storeId}: ${debugStringify(serverNode.state.commissioning.fabrics[fabricIndex])}`);
2140
1518
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2141
1519
  });
2142
- /**
2143
- * This event is triggered when an operative new session was opened by a Controller.
2144
- * It is not triggered for the initial commissioning process, just afterwards for real connections.
2145
- */
2146
1520
  serverNode.events.sessions.opened.on((session) => {
2147
1521
  this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
2148
1522
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2149
1523
  });
2150
- /**
2151
- * This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
2152
- */
2153
1524
  serverNode.events.sessions.closed.on((session) => {
2154
1525
  this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
2155
1526
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2156
1527
  });
2157
- /** This event is triggered when a subscription gets added or removed on an operative session. */
2158
1528
  serverNode.events.sessions.subscriptionsChanged.on((session) => {
2159
1529
  this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
2160
1530
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
@@ -2162,12 +1532,6 @@ export class Matterbridge extends EventEmitter {
2162
1532
  this.log.info(`Created server node for ${storeId}`);
2163
1533
  return serverNode;
2164
1534
  }
2165
- /**
2166
- * Gets the matter sanitized data of the specified server node.
2167
- *
2168
- * @param {ServerNode} [serverNode] - The server node to start.
2169
- * @returns {ApiMatter} The sanitized data of the server node.
2170
- */
2171
1535
  getServerNodeData(serverNode) {
2172
1536
  const advertiseTime = this.advertisingNodes.get(serverNode.id) || 0;
2173
1537
  return {
@@ -2184,25 +1548,12 @@ export class Matterbridge extends EventEmitter {
2184
1548
  serialNumber: serverNode.state.basicInformation.serialNumber,
2185
1549
  };
2186
1550
  }
2187
- /**
2188
- * Starts the specified server node.
2189
- *
2190
- * @param {ServerNode} [matterServerNode] - The server node to start.
2191
- * @returns {Promise<void>} A promise that resolves when the server node has started.
2192
- */
2193
1551
  async startServerNode(matterServerNode) {
2194
1552
  if (!matterServerNode)
2195
1553
  return;
2196
1554
  this.log.notice(`Starting ${matterServerNode.id} server node`);
2197
1555
  await matterServerNode.start();
2198
1556
  }
2199
- /**
2200
- * Stops the specified server node.
2201
- *
2202
- * @param {ServerNode} matterServerNode - The server node to stop.
2203
- * @param {number} [timeout] - The timeout in milliseconds for stopping the server node. Defaults to 30 seconds.
2204
- * @returns {Promise<void>} A promise that resolves when the server node has stopped.
2205
- */
2206
1557
  async stopServerNode(matterServerNode, timeout = 30000) {
2207
1558
  if (!matterServerNode)
2208
1559
  return;
@@ -2215,27 +1566,13 @@ export class Matterbridge extends EventEmitter {
2215
1566
  this.log.error(`Failed to close ${matterServerNode.id} server node: ${error instanceof Error ? error.message : error}`);
2216
1567
  }
2217
1568
  }
2218
- /**
2219
- * Creates an aggregator node with the specified storage context.
2220
- *
2221
- * @param {StorageContext} storageContext - The storage context for the aggregator node.
2222
- * @returns {Promise<Endpoint<AggregatorEndpoint>>} A promise that resolves to the created aggregator node.
2223
- */
2224
1569
  async createAggregatorNode(storageContext) {
2225
1570
  this.log.notice(`Creating ${await storageContext.get('storeId')} aggregator...`);
2226
1571
  const aggregatorNode = new Endpoint(AggregatorEndpoint, { id: `${await storageContext.get('storeId')}` });
2227
1572
  this.log.info(`Created ${await storageContext.get('storeId')} aggregator`);
2228
1573
  return aggregatorNode;
2229
1574
  }
2230
- /**
2231
- * Adds a MatterbridgeEndpoint to the specified plugin.
2232
- *
2233
- * @param {string} pluginName - The name of the plugin.
2234
- * @param {MatterbridgeEndpoint} device - The device to add as a bridged endpoint.
2235
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been added.
2236
- */
2237
1575
  async addBridgedEndpoint(pluginName, device) {
2238
- // Check if the plugin is registered
2239
1576
  const plugin = this.plugins.get(pluginName);
2240
1577
  if (!plugin) {
2241
1578
  this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
@@ -2255,7 +1592,6 @@ export class Matterbridge extends EventEmitter {
2255
1592
  }
2256
1593
  else if (this.bridgeMode === 'bridge') {
2257
1594
  if (device.mode === 'matter') {
2258
- // Register and add the device to the matterbridge server node
2259
1595
  this.log.debug(`Adding matter endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge server node...`);
2260
1596
  if (!this.serverNode) {
2261
1597
  this.log.error('Server node not found for Matterbridge');
@@ -2272,7 +1608,6 @@ export class Matterbridge extends EventEmitter {
2272
1608
  }
2273
1609
  }
2274
1610
  else {
2275
- // Register and add the device to the matterbridge aggregator node
2276
1611
  this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
2277
1612
  if (!this.aggregatorNode) {
2278
1613
  this.log.error('Aggregator node not found for Matterbridge');
@@ -2290,7 +1625,6 @@ export class Matterbridge extends EventEmitter {
2290
1625
  }
2291
1626
  }
2292
1627
  else if (this.bridgeMode === 'childbridge') {
2293
- // Register and add the device to the plugin server node
2294
1628
  if (plugin.type === 'AccessoryPlatform') {
2295
1629
  try {
2296
1630
  this.log.debug(`Creating endpoint ${dev}${device.deviceName}${db} for AccessoryPlatform plugin ${plg}${plugin.name}${db} server node`);
@@ -2314,12 +1648,10 @@ export class Matterbridge extends EventEmitter {
2314
1648
  return;
2315
1649
  }
2316
1650
  }
2317
- // Register and add the device to the plugin aggregator node
2318
1651
  if (plugin.type === 'DynamicPlatform') {
2319
1652
  try {
2320
1653
  this.log.debug(`Adding bridged endpoint ${dev}${device.deviceName}${db} for DynamicPlatform plugin ${plg}${plugin.name}${db} aggregator node`);
2321
1654
  await this.createDynamicPlugin(plugin);
2322
- // Fast plugins can add another device before the server node is ready, so we wait for the server node to be ready
2323
1655
  await waiter(`createDynamicPlugin(${plugin.name})`, () => plugin.serverNode?.hasParts === true);
2324
1656
  if (!plugin.aggregatorNode) {
2325
1657
  this.log.error(`Aggregator node not found for plugin ${plg}${plugin.name}${er}`);
@@ -2340,28 +1672,17 @@ export class Matterbridge extends EventEmitter {
2340
1672
  }
2341
1673
  if (plugin.registeredDevices !== undefined)
2342
1674
  plugin.registeredDevices++;
2343
- // Add the device to the DeviceManager
2344
1675
  this.devices.set(device);
2345
- // Subscribe to the attributes changed event
2346
1676
  await this.subscribeAttributeChanged(plugin, device);
2347
1677
  this.log.info(`Added and registered bridged endpoint (${plugin.registeredDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) for plugin ${plg}${pluginName}${nf}`);
2348
1678
  }
2349
- /**
2350
- * Removes a MatterbridgeEndpoint from the specified plugin.
2351
- *
2352
- * @param {string} pluginName - The name of the plugin.
2353
- * @param {MatterbridgeEndpoint} device - The device to remove as a bridged endpoint.
2354
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been removed.
2355
- */
2356
1679
  async removeBridgedEndpoint(pluginName, device) {
2357
1680
  this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
2358
- // Check if the plugin is registered
2359
1681
  const plugin = this.plugins.get(pluginName);
2360
1682
  if (!plugin) {
2361
1683
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
2362
1684
  return;
2363
1685
  }
2364
- // Register and add the device to the matterbridge aggregator node
2365
1686
  if (this.bridgeMode === 'bridge') {
2366
1687
  if (!this.aggregatorNode) {
2367
1688
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator node not found`);
@@ -2374,7 +1695,6 @@ export class Matterbridge extends EventEmitter {
2374
1695
  }
2375
1696
  else if (this.bridgeMode === 'childbridge') {
2376
1697
  if (plugin.type === 'AccessoryPlatform') {
2377
- // Nothing to do here since the server node has no aggregator node but only the device itself
2378
1698
  }
2379
1699
  else if (plugin.type === 'DynamicPlatform') {
2380
1700
  if (!plugin.aggregatorNode) {
@@ -2387,21 +1707,8 @@ export class Matterbridge extends EventEmitter {
2387
1707
  if (plugin.registeredDevices !== undefined)
2388
1708
  plugin.registeredDevices--;
2389
1709
  }
2390
- // Remove the device from the DeviceManager
2391
1710
  this.devices.remove(device);
2392
1711
  }
2393
- /**
2394
- * Removes all bridged endpoints from the specified plugin.
2395
- *
2396
- * @param {string} pluginName - The name of the plugin.
2397
- * @param {number} [delay] - The delay in milliseconds between removing each bridged endpoint (default: 0).
2398
- * @returns {Promise<void>} A promise that resolves when all bridged endpoints have been removed.
2399
- *
2400
- * @remarks
2401
- * This method iterates through all devices in the DeviceManager and removes each bridged endpoint associated with the specified plugin.
2402
- * It also applies a delay between each removal if specified.
2403
- * The delay is useful to allow the controllers to receive a single subscription for each device removed.
2404
- */
2405
1712
  async removeAllBridgedEndpoints(pluginName, delay = 0) {
2406
1713
  this.log.debug(`Removing all bridged endpoints for plugin ${plg}${pluginName}${db}${delay > 0 ? ` with delay ${delay} ms` : ''}`);
2407
1714
  for (const device of this.devices.array().filter((device) => device.plugin === pluginName)) {
@@ -2412,24 +1719,13 @@ export class Matterbridge extends EventEmitter {
2412
1719
  if (delay > 0)
2413
1720
  await wait(2000);
2414
1721
  }
2415
- /**
2416
- * Subscribes to the attribute change event for the given device and plugin.
2417
- * Specifically, it listens for changes in the 'reachable' attribute of the
2418
- * BridgedDeviceBasicInformationServer cluster server of the bridged device or BasicInformationServer cluster server of server node.
2419
- *
2420
- * @param {RegisteredPlugin} plugin - The plugin associated with the device.
2421
- * @param {MatterbridgeEndpoint} device - The device to subscribe to attribute changes for.
2422
- * @returns {Promise<void>} A promise that resolves when the subscription is set up.
2423
- */
2424
1722
  async subscribeAttributeChanged(plugin, device) {
2425
1723
  if (!plugin || !device || !device.plugin || !device.serialNumber || !device.uniqueId || !device.maybeNumber)
2426
1724
  return;
2427
1725
  this.log.info(`Subscribing attributes for endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) plugin ${plg}${plugin.name}${nf}`);
2428
- // Subscribe to the reachable$Changed event of the BasicInformationServer cluster server of the server node in childbridge mode
2429
1726
  if (this.bridgeMode === 'childbridge' && plugin.type === 'AccessoryPlatform' && plugin.serverNode) {
2430
1727
  plugin.serverNode.eventsOf(BasicInformationServer).reachable$Changed?.on((reachable) => {
2431
1728
  this.log.info(`Accessory endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) is ${reachable ? 'reachable' : 'unreachable'}`);
2432
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2433
1729
  this.frontend.wssSendAttributeChangedMessage(device.plugin, device.serialNumber, device.uniqueId, device.number, device.id, 'BasicInformation', 'reachable', reachable);
2434
1730
  });
2435
1731
  }
@@ -2469,7 +1765,6 @@ export class Matterbridge extends EventEmitter {
2469
1765
  this.log.debug(`Subscribing to endpoint ${or}${device.id}${db}:${or}${device.number}${db} attribute ${dev}${sub.cluster}${db}.${dev}${sub.attribute}${db} changes...`);
2470
1766
  await device.subscribeAttribute(sub.cluster, sub.attribute, (value) => {
2471
1767
  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}${value}${db}`);
2472
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2473
1768
  this.frontend.wssSendAttributeChangedMessage(device.plugin, device.serialNumber, device.uniqueId, device.number, device.id, sub.cluster, sub.attribute, value);
2474
1769
  });
2475
1770
  }
@@ -2479,7 +1774,6 @@ export class Matterbridge extends EventEmitter {
2479
1774
  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...`);
2480
1775
  await child.subscribeAttribute(sub.cluster, sub.attribute, (value) => {
2481
1776
  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}${value}${db}`);
2482
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2483
1777
  this.frontend.wssSendAttributeChangedMessage(device.plugin, device.serialNumber, device.uniqueId, child.number, child.id, sub.cluster, sub.attribute, value);
2484
1778
  });
2485
1779
  }
@@ -2487,12 +1781,6 @@ export class Matterbridge extends EventEmitter {
2487
1781
  }
2488
1782
  }
2489
1783
  }
2490
- /**
2491
- * Sanitizes the fabric information by converting bigint properties to strings because `res.json` doesn't support bigint.
2492
- *
2493
- * @param {ExposedFabricInformation[]} fabricInfo - The array of exposed fabric information objects.
2494
- * @returns {SanitizedExposedFabricInformation[]} An array of sanitized exposed fabric information objects.
2495
- */
2496
1784
  sanitizeFabricInformations(fabricInfo) {
2497
1785
  return fabricInfo.map((info) => {
2498
1786
  return {
@@ -2506,12 +1794,6 @@ export class Matterbridge extends EventEmitter {
2506
1794
  };
2507
1795
  });
2508
1796
  }
2509
- /**
2510
- * Sanitizes the session information by converting bigint properties to strings because `res.json` doesn't support bigint.
2511
- *
2512
- * @param {SessionsBehavior.Session[]} sessions - The array of session information objects.
2513
- * @returns {SanitizedSession[]} An array of sanitized session information objects.
2514
- */
2515
1797
  sanitizeSessionInformation(sessions) {
2516
1798
  return sessions
2517
1799
  .filter((session) => session.isPeerActive)
@@ -2538,21 +1820,7 @@ export class Matterbridge extends EventEmitter {
2538
1820
  };
2539
1821
  });
2540
1822
  }
2541
- /**
2542
- * Sets the reachability of the specified aggregator node bridged devices and trigger.
2543
- *
2544
- * @param {Endpoint<AggregatorEndpoint>} aggregatorNode - The aggregator node to set the reachability for.
2545
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2546
- */
2547
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2548
1823
  async setAggregatorReachability(aggregatorNode, reachable) {
2549
- /*
2550
- for (const child of aggregatorNode.parts) {
2551
- this.log.debug(`Setting reachability of ${(child as unknown as MatterbridgeEndpoint)?.deviceName} to ${reachable}`);
2552
- await child.setStateOf(BridgedDeviceBasicInformationServer, { reachable });
2553
- child.act((agent) => child.eventsOf(BridgedDeviceBasicInformationServer).reachableChanged.emit({ reachableNewValue: true }, agent.context));
2554
- }
2555
- */
2556
1824
  }
2557
1825
  getVendorIdName = (vendorId) => {
2558
1826
  if (!vendorId)
@@ -2592,11 +1860,10 @@ export class Matterbridge extends EventEmitter {
2592
1860
  case 0x1488:
2593
1861
  vendorName = '(ShortcutLabsFlic)';
2594
1862
  break;
2595
- case 65521: // 0xFFF1
1863
+ case 65521:
2596
1864
  vendorName = '(MatterTest)';
2597
1865
  break;
2598
1866
  }
2599
1867
  return vendorName;
2600
1868
  };
2601
1869
  }
2602
- //# sourceMappingURL=matterbridge.js.map