matterbridge 3.4.1 → 3.4.2-dev-20251202-c41a119

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 (326) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/broadcastServer.js +0 -112
  3. package/dist/broadcastServerTypes.js +0 -24
  4. package/dist/cli.js +1 -97
  5. package/dist/cliEmitter.js +0 -37
  6. package/dist/cliHistory.js +0 -38
  7. package/dist/clusters/export.js +0 -2
  8. package/dist/deviceManager.js +1 -113
  9. package/dist/devices/airConditioner.js +0 -57
  10. package/dist/devices/batteryStorage.js +1 -48
  11. package/dist/devices/cooktop.js +0 -56
  12. package/dist/devices/dishwasher.js +0 -57
  13. package/dist/devices/evse.js +10 -74
  14. package/dist/devices/export.js +0 -5
  15. package/dist/devices/extractorHood.js +0 -43
  16. package/dist/devices/heatPump.js +2 -50
  17. package/dist/devices/laundryDryer.js +3 -62
  18. package/dist/devices/laundryWasher.js +4 -70
  19. package/dist/devices/microwaveOven.js +5 -88
  20. package/dist/devices/oven.js +0 -85
  21. package/dist/devices/refrigerator.js +0 -102
  22. package/dist/devices/roboticVacuumCleaner.js +9 -100
  23. package/dist/devices/solarPower.js +0 -38
  24. package/dist/devices/speaker.js +0 -84
  25. package/dist/devices/temperatureControl.js +3 -24
  26. package/dist/devices/waterHeater.js +2 -82
  27. package/dist/dgram/coap.js +13 -126
  28. package/dist/dgram/dgram.js +2 -114
  29. package/dist/dgram/mb_coap.js +3 -41
  30. package/dist/dgram/mb_mdns.js +15 -80
  31. package/dist/dgram/mdns.js +137 -299
  32. package/dist/dgram/multicast.js +1 -62
  33. package/dist/dgram/unicast.js +0 -54
  34. package/dist/frontend.js +35 -455
  35. package/dist/frontendTypes.js +0 -45
  36. package/dist/helpers.js +0 -53
  37. package/dist/index.js +0 -25
  38. package/dist/jestutils/export.js +0 -1
  39. package/dist/jestutils/jestHelpers.js +13 -368
  40. package/dist/logger/export.js +0 -1
  41. package/dist/matter/behaviors.js +0 -2
  42. package/dist/matter/clusters.js +0 -2
  43. package/dist/matter/devices.js +0 -2
  44. package/dist/matter/endpoints.js +0 -2
  45. package/dist/matter/export.js +0 -3
  46. package/dist/matter/types.js +0 -3
  47. package/dist/matterNode.js +8 -369
  48. package/dist/matterbridge.js +46 -807
  49. package/dist/matterbridgeAccessoryPlatform.js +0 -38
  50. package/dist/matterbridgeBehaviors.js +5 -68
  51. package/dist/matterbridgeDeviceTypes.js +14 -635
  52. package/dist/matterbridgeDynamicPlatform.js +0 -38
  53. package/dist/matterbridgeEndpoint.js +53 -1444
  54. package/dist/matterbridgeEndpointHelpers.js +20 -483
  55. package/dist/matterbridgeEndpointTypes.js +0 -25
  56. package/dist/matterbridgePlatform.js +1 -450
  57. package/dist/matterbridgeTypes.js +0 -26
  58. package/dist/pluginManager.js +5 -341
  59. package/dist/shelly.js +7 -178
  60. package/dist/storage/export.js +0 -1
  61. package/dist/update.js +1 -93
  62. package/dist/utils/colorUtils.js +2 -97
  63. package/dist/utils/commandLine.js +0 -60
  64. package/dist/utils/copyDirectory.js +0 -37
  65. package/dist/utils/createDirectory.js +0 -33
  66. package/dist/utils/createZip.js +2 -47
  67. package/dist/utils/deepCopy.js +0 -39
  68. package/dist/utils/deepEqual.js +1 -72
  69. package/dist/utils/error.js +0 -42
  70. package/dist/utils/export.js +0 -1
  71. package/dist/utils/format.js +0 -49
  72. package/dist/utils/hex.js +0 -124
  73. package/dist/utils/inspector.js +1 -69
  74. package/dist/utils/isvalid.js +0 -101
  75. package/dist/utils/network.js +5 -96
  76. package/dist/utils/spawn.js +1 -71
  77. package/dist/utils/tracker.js +1 -64
  78. package/dist/utils/wait.js +8 -60
  79. package/dist/workerGlobalPrefix.js +5 -37
  80. package/dist/workerTypes.js +0 -24
  81. package/dist/workers.js +4 -68
  82. package/frontend/build/assets/index.js +4 -4
  83. package/frontend/build/assets/vendor_mui.js +1 -1
  84. package/frontend/package.json +1 -1
  85. package/npm-shrinkwrap.json +14 -10
  86. package/package.json +1 -2
  87. package/dist/broadcastServer.d.ts +0 -136
  88. package/dist/broadcastServer.d.ts.map +0 -1
  89. package/dist/broadcastServer.js.map +0 -1
  90. package/dist/broadcastServerTypes.d.ts +0 -841
  91. package/dist/broadcastServerTypes.d.ts.map +0 -1
  92. package/dist/broadcastServerTypes.js.map +0 -1
  93. package/dist/cli.d.ts +0 -30
  94. package/dist/cli.d.ts.map +0 -1
  95. package/dist/cli.js.map +0 -1
  96. package/dist/cliEmitter.d.ts +0 -50
  97. package/dist/cliEmitter.d.ts.map +0 -1
  98. package/dist/cliEmitter.js.map +0 -1
  99. package/dist/cliHistory.d.ts +0 -48
  100. package/dist/cliHistory.d.ts.map +0 -1
  101. package/dist/cliHistory.js.map +0 -1
  102. package/dist/clusters/export.d.ts +0 -2
  103. package/dist/clusters/export.d.ts.map +0 -1
  104. package/dist/clusters/export.js.map +0 -1
  105. package/dist/deviceManager.d.ts +0 -135
  106. package/dist/deviceManager.d.ts.map +0 -1
  107. package/dist/deviceManager.js.map +0 -1
  108. package/dist/devices/airConditioner.d.ts +0 -98
  109. package/dist/devices/airConditioner.d.ts.map +0 -1
  110. package/dist/devices/airConditioner.js.map +0 -1
  111. package/dist/devices/batteryStorage.d.ts +0 -48
  112. package/dist/devices/batteryStorage.d.ts.map +0 -1
  113. package/dist/devices/batteryStorage.js.map +0 -1
  114. package/dist/devices/cooktop.d.ts +0 -61
  115. package/dist/devices/cooktop.d.ts.map +0 -1
  116. package/dist/devices/cooktop.js.map +0 -1
  117. package/dist/devices/dishwasher.d.ts +0 -71
  118. package/dist/devices/dishwasher.d.ts.map +0 -1
  119. package/dist/devices/dishwasher.js.map +0 -1
  120. package/dist/devices/evse.d.ts +0 -76
  121. package/dist/devices/evse.d.ts.map +0 -1
  122. package/dist/devices/evse.js.map +0 -1
  123. package/dist/devices/export.d.ts +0 -17
  124. package/dist/devices/export.d.ts.map +0 -1
  125. package/dist/devices/export.js.map +0 -1
  126. package/dist/devices/extractorHood.d.ts +0 -46
  127. package/dist/devices/extractorHood.d.ts.map +0 -1
  128. package/dist/devices/extractorHood.js.map +0 -1
  129. package/dist/devices/heatPump.d.ts +0 -47
  130. package/dist/devices/heatPump.d.ts.map +0 -1
  131. package/dist/devices/heatPump.js.map +0 -1
  132. package/dist/devices/laundryDryer.d.ts +0 -67
  133. package/dist/devices/laundryDryer.d.ts.map +0 -1
  134. package/dist/devices/laundryDryer.js.map +0 -1
  135. package/dist/devices/laundryWasher.d.ts +0 -81
  136. package/dist/devices/laundryWasher.d.ts.map +0 -1
  137. package/dist/devices/laundryWasher.js.map +0 -1
  138. package/dist/devices/microwaveOven.d.ts +0 -168
  139. package/dist/devices/microwaveOven.d.ts.map +0 -1
  140. package/dist/devices/microwaveOven.js.map +0 -1
  141. package/dist/devices/oven.d.ts +0 -105
  142. package/dist/devices/oven.d.ts.map +0 -1
  143. package/dist/devices/oven.js.map +0 -1
  144. package/dist/devices/refrigerator.d.ts +0 -118
  145. package/dist/devices/refrigerator.d.ts.map +0 -1
  146. package/dist/devices/refrigerator.js.map +0 -1
  147. package/dist/devices/roboticVacuumCleaner.d.ts +0 -112
  148. package/dist/devices/roboticVacuumCleaner.d.ts.map +0 -1
  149. package/dist/devices/roboticVacuumCleaner.js.map +0 -1
  150. package/dist/devices/solarPower.d.ts +0 -40
  151. package/dist/devices/solarPower.d.ts.map +0 -1
  152. package/dist/devices/solarPower.js.map +0 -1
  153. package/dist/devices/speaker.d.ts +0 -87
  154. package/dist/devices/speaker.d.ts.map +0 -1
  155. package/dist/devices/speaker.js.map +0 -1
  156. package/dist/devices/temperatureControl.d.ts +0 -166
  157. package/dist/devices/temperatureControl.d.ts.map +0 -1
  158. package/dist/devices/temperatureControl.js.map +0 -1
  159. package/dist/devices/waterHeater.d.ts +0 -111
  160. package/dist/devices/waterHeater.d.ts.map +0 -1
  161. package/dist/devices/waterHeater.js.map +0 -1
  162. package/dist/dgram/coap.d.ts +0 -205
  163. package/dist/dgram/coap.d.ts.map +0 -1
  164. package/dist/dgram/coap.js.map +0 -1
  165. package/dist/dgram/dgram.d.ts +0 -141
  166. package/dist/dgram/dgram.d.ts.map +0 -1
  167. package/dist/dgram/dgram.js.map +0 -1
  168. package/dist/dgram/mb_coap.d.ts +0 -24
  169. package/dist/dgram/mb_coap.d.ts.map +0 -1
  170. package/dist/dgram/mb_coap.js.map +0 -1
  171. package/dist/dgram/mb_mdns.d.ts +0 -24
  172. package/dist/dgram/mb_mdns.d.ts.map +0 -1
  173. package/dist/dgram/mb_mdns.js.map +0 -1
  174. package/dist/dgram/mdns.d.ts +0 -290
  175. package/dist/dgram/mdns.d.ts.map +0 -1
  176. package/dist/dgram/mdns.js.map +0 -1
  177. package/dist/dgram/multicast.d.ts +0 -67
  178. package/dist/dgram/multicast.d.ts.map +0 -1
  179. package/dist/dgram/multicast.js.map +0 -1
  180. package/dist/dgram/unicast.d.ts +0 -56
  181. package/dist/dgram/unicast.d.ts.map +0 -1
  182. package/dist/dgram/unicast.js.map +0 -1
  183. package/dist/frontend.d.ts +0 -238
  184. package/dist/frontend.d.ts.map +0 -1
  185. package/dist/frontend.js.map +0 -1
  186. package/dist/frontendTypes.d.ts +0 -529
  187. package/dist/frontendTypes.d.ts.map +0 -1
  188. package/dist/frontendTypes.js.map +0 -1
  189. package/dist/helpers.d.ts +0 -48
  190. package/dist/helpers.d.ts.map +0 -1
  191. package/dist/helpers.js.map +0 -1
  192. package/dist/index.d.ts +0 -34
  193. package/dist/index.d.ts.map +0 -1
  194. package/dist/index.js.map +0 -1
  195. package/dist/jestutils/export.d.ts +0 -2
  196. package/dist/jestutils/export.d.ts.map +0 -1
  197. package/dist/jestutils/export.js.map +0 -1
  198. package/dist/jestutils/jestHelpers.d.ts +0 -340
  199. package/dist/jestutils/jestHelpers.d.ts.map +0 -1
  200. package/dist/jestutils/jestHelpers.js.map +0 -1
  201. package/dist/logger/export.d.ts +0 -2
  202. package/dist/logger/export.d.ts.map +0 -1
  203. package/dist/logger/export.js.map +0 -1
  204. package/dist/matter/behaviors.d.ts +0 -2
  205. package/dist/matter/behaviors.d.ts.map +0 -1
  206. package/dist/matter/behaviors.js.map +0 -1
  207. package/dist/matter/clusters.d.ts +0 -2
  208. package/dist/matter/clusters.d.ts.map +0 -1
  209. package/dist/matter/clusters.js.map +0 -1
  210. package/dist/matter/devices.d.ts +0 -2
  211. package/dist/matter/devices.d.ts.map +0 -1
  212. package/dist/matter/devices.js.map +0 -1
  213. package/dist/matter/endpoints.d.ts +0 -2
  214. package/dist/matter/endpoints.d.ts.map +0 -1
  215. package/dist/matter/endpoints.js.map +0 -1
  216. package/dist/matter/export.d.ts +0 -5
  217. package/dist/matter/export.d.ts.map +0 -1
  218. package/dist/matter/export.js.map +0 -1
  219. package/dist/matter/types.d.ts +0 -3
  220. package/dist/matter/types.d.ts.map +0 -1
  221. package/dist/matter/types.js.map +0 -1
  222. package/dist/matterNode.d.ts +0 -342
  223. package/dist/matterNode.d.ts.map +0 -1
  224. package/dist/matterNode.js.map +0 -1
  225. package/dist/matterbridge.d.ts +0 -493
  226. package/dist/matterbridge.d.ts.map +0 -1
  227. package/dist/matterbridge.js.map +0 -1
  228. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -41
  229. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  230. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  231. package/dist/matterbridgeBehaviors.d.ts +0 -2404
  232. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  233. package/dist/matterbridgeBehaviors.js.map +0 -1
  234. package/dist/matterbridgeDeviceTypes.d.ts +0 -698
  235. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  236. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  237. package/dist/matterbridgeDynamicPlatform.d.ts +0 -41
  238. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  239. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  240. package/dist/matterbridgeEndpoint.d.ts +0 -1507
  241. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  242. package/dist/matterbridgeEndpoint.js.map +0 -1
  243. package/dist/matterbridgeEndpointHelpers.d.ts +0 -787
  244. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  245. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  246. package/dist/matterbridgeEndpointTypes.d.ts +0 -166
  247. package/dist/matterbridgeEndpointTypes.d.ts.map +0 -1
  248. package/dist/matterbridgeEndpointTypes.js.map +0 -1
  249. package/dist/matterbridgePlatform.d.ts +0 -537
  250. package/dist/matterbridgePlatform.d.ts.map +0 -1
  251. package/dist/matterbridgePlatform.js.map +0 -1
  252. package/dist/matterbridgeTypes.d.ts +0 -251
  253. package/dist/matterbridgeTypes.d.ts.map +0 -1
  254. package/dist/matterbridgeTypes.js.map +0 -1
  255. package/dist/pluginManager.d.ts +0 -372
  256. package/dist/pluginManager.d.ts.map +0 -1
  257. package/dist/pluginManager.js.map +0 -1
  258. package/dist/shelly.d.ts +0 -181
  259. package/dist/shelly.d.ts.map +0 -1
  260. package/dist/shelly.js.map +0 -1
  261. package/dist/storage/export.d.ts +0 -2
  262. package/dist/storage/export.d.ts.map +0 -1
  263. package/dist/storage/export.js.map +0 -1
  264. package/dist/update.d.ts +0 -84
  265. package/dist/update.d.ts.map +0 -1
  266. package/dist/update.js.map +0 -1
  267. package/dist/utils/colorUtils.d.ts +0 -101
  268. package/dist/utils/colorUtils.d.ts.map +0 -1
  269. package/dist/utils/colorUtils.js.map +0 -1
  270. package/dist/utils/commandLine.d.ts +0 -66
  271. package/dist/utils/commandLine.d.ts.map +0 -1
  272. package/dist/utils/commandLine.js.map +0 -1
  273. package/dist/utils/copyDirectory.d.ts +0 -35
  274. package/dist/utils/copyDirectory.d.ts.map +0 -1
  275. package/dist/utils/copyDirectory.js.map +0 -1
  276. package/dist/utils/createDirectory.d.ts +0 -34
  277. package/dist/utils/createDirectory.d.ts.map +0 -1
  278. package/dist/utils/createDirectory.js.map +0 -1
  279. package/dist/utils/createZip.d.ts +0 -39
  280. package/dist/utils/createZip.d.ts.map +0 -1
  281. package/dist/utils/createZip.js.map +0 -1
  282. package/dist/utils/deepCopy.d.ts +0 -32
  283. package/dist/utils/deepCopy.d.ts.map +0 -1
  284. package/dist/utils/deepCopy.js.map +0 -1
  285. package/dist/utils/deepEqual.d.ts +0 -54
  286. package/dist/utils/deepEqual.d.ts.map +0 -1
  287. package/dist/utils/deepEqual.js.map +0 -1
  288. package/dist/utils/error.d.ts +0 -45
  289. package/dist/utils/error.d.ts.map +0 -1
  290. package/dist/utils/error.js.map +0 -1
  291. package/dist/utils/export.d.ts +0 -13
  292. package/dist/utils/export.d.ts.map +0 -1
  293. package/dist/utils/export.js.map +0 -1
  294. package/dist/utils/format.d.ts +0 -53
  295. package/dist/utils/format.d.ts.map +0 -1
  296. package/dist/utils/format.js.map +0 -1
  297. package/dist/utils/hex.d.ts +0 -89
  298. package/dist/utils/hex.d.ts.map +0 -1
  299. package/dist/utils/hex.js.map +0 -1
  300. package/dist/utils/inspector.d.ts +0 -87
  301. package/dist/utils/inspector.d.ts.map +0 -1
  302. package/dist/utils/inspector.js.map +0 -1
  303. package/dist/utils/isvalid.d.ts +0 -103
  304. package/dist/utils/isvalid.d.ts.map +0 -1
  305. package/dist/utils/isvalid.js.map +0 -1
  306. package/dist/utils/network.d.ts +0 -111
  307. package/dist/utils/network.d.ts.map +0 -1
  308. package/dist/utils/network.js.map +0 -1
  309. package/dist/utils/spawn.d.ts +0 -33
  310. package/dist/utils/spawn.d.ts.map +0 -1
  311. package/dist/utils/spawn.js.map +0 -1
  312. package/dist/utils/tracker.d.ts +0 -108
  313. package/dist/utils/tracker.d.ts.map +0 -1
  314. package/dist/utils/tracker.js.map +0 -1
  315. package/dist/utils/wait.d.ts +0 -54
  316. package/dist/utils/wait.d.ts.map +0 -1
  317. package/dist/utils/wait.js.map +0 -1
  318. package/dist/workerGlobalPrefix.d.ts +0 -25
  319. package/dist/workerGlobalPrefix.d.ts.map +0 -1
  320. package/dist/workerGlobalPrefix.js.map +0 -1
  321. package/dist/workerTypes.d.ts +0 -52
  322. package/dist/workerTypes.d.ts.map +0 -1
  323. package/dist/workerTypes.js.map +0 -1
  324. package/dist/workers.d.ts +0 -69
  325. package/dist/workers.d.ts.map +0 -1
  326. package/dist/workers.js.map +0 -1
@@ -1,48 +1,19 @@
1
- /**
2
- * This file contains the class Matterbridge.
3
- *
4
- * @file matterbridge.ts
5
- * @author Luca Liguori
6
- * @created 2023-12-29
7
- * @version 1.6.2
8
- * @license Apache-2.0
9
- *
10
- * Copyright 2023, 2024, 2025 Luca Liguori.
11
- *
12
- * Licensed under the Apache License, Version 2.0 (the "License");
13
- * you may not use this file except in compliance with the License.
14
- * You may obtain a copy of the License at
15
- *
16
- * http://www.apache.org/licenses/LICENSE-2.0
17
- *
18
- * Unless required by applicable law or agreed to in writing, software
19
- * distributed under the License is distributed on an "AS IS" BASIS,
20
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
- * See the License for the specific language governing permissions and
22
- * limitations under the License.
23
- */
24
- // eslint-disable-next-line no-console
25
1
  if (process.argv.includes('--loader') || process.argv.includes('-loader'))
26
2
  console.log('\u001B[32mMatterbridge loaded.\u001B[40;0m');
27
- // Node.js modules
28
3
  import os from 'node:os';
29
4
  import path from 'node:path';
30
5
  import fs from 'node:fs';
31
6
  import EventEmitter from 'node:events';
32
7
  import { inspect } from 'node:util';
33
- // AnsiLogger module
34
8
  import { AnsiLogger, UNDERLINE, UNDERLINEOFF, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN, nt, BLUE, or } from 'node-ansi-logger';
35
- // NodeStorage module
36
9
  import { NodeStorageManager } from 'node-persist-manager';
37
- // @matter
38
- import '@matter/nodejs'; // Set up Node.js environment for matter.js
10
+ import '@matter/nodejs';
39
11
  import { Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, UINT32_MAX, UINT16_MAX, Crypto, Environment, StorageService } from '@matter/general';
40
12
  import { FabricAction, PaseClient } from '@matter/protocol';
41
13
  import { Endpoint, ServerNode } from '@matter/node';
42
14
  import { DeviceTypeId, VendorId } from '@matter/types/datatype';
43
15
  import { AggregatorEndpoint } from '@matter/node/endpoints';
44
16
  import { BasicInformationServer } from '@matter/node/behaviors/basic-information';
45
- // Matterbridge
46
17
  import { getParameter, getIntParameter, hasParameter } from './utils/commandLine.js';
47
18
  import { copyDirectory } from './utils/copyDirectory.js';
48
19
  import { createDirectory } from './utils/createDirectory.js';
@@ -57,27 +28,19 @@ import { bridge } from './matterbridgeDeviceTypes.js';
57
28
  import { Frontend } from './frontend.js';
58
29
  import { addVirtualDevice, addVirtualDevices } from './helpers.js';
59
30
  import { BroadcastServer } from './broadcastServer.js';
60
- /**
61
- * Represents the Matterbridge application.
62
- */
63
31
  export class Matterbridge extends EventEmitter {
64
- /** Matterbridge system information */
65
32
  systemInformation = {
66
- // Network properties
67
33
  interfaceName: '',
68
34
  macAddress: '',
69
35
  ipv4Address: '',
70
36
  ipv6Address: '',
71
- // Node.js properties
72
37
  nodeVersion: '',
73
- // Fixed system properties
74
38
  hostname: '',
75
39
  user: '',
76
40
  osType: '',
77
41
  osRelease: '',
78
42
  osPlatform: '',
79
43
  osArch: '',
80
- // Cpu and memory properties
81
44
  totalMemory: '',
82
45
  freeMemory: '',
83
46
  systemUptime: '',
@@ -88,7 +51,6 @@ export class Matterbridge extends EventEmitter {
88
51
  heapTotal: '',
89
52
  heapUsed: '',
90
53
  };
91
- // Matterbridge settings
92
54
  homeDirectory = '';
93
55
  rootDirectory = '';
94
56
  matterbridgeDirectory = '';
@@ -103,19 +65,12 @@ export class Matterbridge extends EventEmitter {
103
65
  restartMode = '';
104
66
  virtualMode = 'outlet';
105
67
  profile = getParameter('profile');
106
- /** Matterbridge logger */
107
- log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
108
- /** Matterbridge logger level */
68
+ log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
109
69
  logLevel = this.log.logLevel;
110
- /** Whether to log to a file */
111
70
  fileLogger = false;
112
- /** Matter logger */
113
- matterLog = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
114
- /** Matter logger level */
71
+ matterLog = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
115
72
  matterLogLevel = this.matterLog.logLevel;
116
- /** Whether to log Matter to a file */
117
73
  matterFileLogger = false;
118
- // Frontend settings
119
74
  readOnly = hasParameter('readonly') || hasParameter('shelly');
120
75
  shellyBoard = hasParameter('shelly');
121
76
  shellySysUpdate = false;
@@ -123,18 +78,12 @@ export class Matterbridge extends EventEmitter {
123
78
  restartRequired = false;
124
79
  fixedRestartRequired = false;
125
80
  updateRequired = false;
126
- // Managers
127
81
  plugins = new PluginManager(this);
128
82
  devices = new DeviceManager();
129
- // Frontend
130
83
  frontend = new Frontend(this);
131
- /** Matterbridge node storage manager created in the directory 'storage' in matterbridgeDirectory */
132
84
  nodeStorage;
133
- /** Matterbridge node context created with name 'matterbridge' */
134
85
  nodeContext;
135
- /** The main instance of the Matterbridge class (singleton) */
136
86
  static instance;
137
- // Instance properties
138
87
  shutdown = false;
139
88
  failCountLimit = hasParameter('shelly') ? 600 : 120;
140
89
  hasCleanupStarted = false;
@@ -149,32 +98,19 @@ export class Matterbridge extends EventEmitter {
149
98
  sigtermHandler;
150
99
  exceptionHandler;
151
100
  rejectionHandler;
152
- /** Matter environment default */
153
101
  environment = Environment.default;
154
- /** Matter storage service from environment default */
155
102
  matterStorageService;
156
- /** Matter storage manager created with name 'Matterbridge' */
157
103
  matterStorageManager;
158
- /** Matter matterbridge storage context created in the storage manager with name 'persist' */
159
104
  matterbridgeContext;
160
105
  controllerContext;
161
- /** Matter mdns interface e.g. 'eth0' or 'wlan0' or 'Wi-Fi' */
162
106
  mdnsInterface;
163
- /** Matter listeningAddressIpv4 address */
164
107
  ipv4Address;
165
- /** Matter listeningAddressIpv6 address */
166
108
  ipv6Address;
167
- /** Matter commissioning port */
168
- port; // first server node port
169
- /** Matter commissioning passcode */
170
- passcode; // first server node passcode
171
- /** Matter commissioning discriminator */
172
- discriminator; // first server node discriminator
173
- /** Matter device certification */
174
- certification; // device certification
175
- /** Matter server node in bridge mode */
109
+ port;
110
+ passcode;
111
+ discriminator;
112
+ certification;
176
113
  serverNode;
177
- /** Matter aggregator node in bridge mode */
178
114
  aggregatorNode;
179
115
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
180
116
  aggregatorVendorName = getParameter('vendorName') ?? 'Matterbridge';
@@ -183,13 +119,10 @@ export class Matterbridge extends EventEmitter {
183
119
  aggregatorDeviceType = DeviceTypeId(getIntParameter('deviceType') ?? bridge.code);
184
120
  aggregatorSerialNumber = getParameter('serialNumber');
185
121
  aggregatorUniqueId = getParameter('uniqueId');
186
- /** Advertising nodes map: time advertising started keyed by storeId */
187
122
  advertisingNodes = new Map();
188
- /** Broadcast server */
189
123
  server;
190
124
  debug = hasParameter('debug') || hasParameter('verbose');
191
125
  verbose = hasParameter('verbose');
192
- /** We load asyncronously so is private */
193
126
  constructor() {
194
127
  super();
195
128
  this.log.logNameColor = '\x1b[38;5;115m';
@@ -240,19 +173,8 @@ export class Matterbridge extends EventEmitter {
240
173
  }
241
174
  }
242
175
  }
243
- //* ************************************************************************************************************************************ */
244
- // loadInstance() and cleanup() methods */
245
- //* ************************************************************************************************************************************ */
246
- /**
247
- * Loads an instance of the Matterbridge class.
248
- * If an instance already exists, return that instance.
249
- *
250
- * @param {boolean} initialize - Whether to initialize the Matterbridge instance after loading. Defaults to false.
251
- * @returns {Matterbridge} A promise that resolves to the Matterbridge instance.
252
- */
253
176
  static async loadInstance(initialize = false) {
254
177
  if (!Matterbridge.instance) {
255
- // eslint-disable-next-line no-console
256
178
  if (hasParameter('debug'))
257
179
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
258
180
  Matterbridge.instance = new Matterbridge();
@@ -261,84 +183,56 @@ export class Matterbridge extends EventEmitter {
261
183
  }
262
184
  return Matterbridge.instance;
263
185
  }
264
- /**
265
- * Initializes the Matterbridge application.
266
- *
267
- * @remarks
268
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
269
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
270
- * node version, registers signal handlers, initializes storage, and parses the command line.
271
- *
272
- * @returns {Promise<void>} A Promise that resolves when the initialization is complete.
273
- */
274
186
  async initialize() {
275
- // for (let i = 1; i <= 255; i++) console.log(`\x1b[38;5;${i}mColor: ${i}`);
276
- // Emit the initialize_started event
277
187
  this.emit('initialize_started');
278
- // Set the restart mode
279
188
  if (hasParameter('service'))
280
189
  this.restartMode = 'service';
281
190
  if (hasParameter('docker'))
282
191
  this.restartMode = 'docker';
283
- // Set the matterbridge home directory
284
192
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
285
193
  await createDirectory(this.homeDirectory, 'Matterbridge Home Directory', this.log);
286
- // Set the matterbridge directory
287
194
  this.matterbridgeDirectory = this.profile ? path.join(this.homeDirectory, '.matterbridge', 'profiles', this.profile) : path.join(this.homeDirectory, '.matterbridge');
288
195
  await createDirectory(this.matterbridgeDirectory, 'Matterbridge Directory', this.log);
289
196
  await createDirectory(path.join(this.matterbridgeDirectory, 'certs'), 'Matterbridge Frontend Certificate Directory', this.log);
290
197
  await createDirectory(path.join(this.matterbridgeDirectory, 'uploads'), 'Matterbridge Frontend Uploads Directory', this.log);
291
- // Set the matterbridge plugin directory
292
198
  this.matterbridgePluginDirectory = this.profile ? path.join(this.homeDirectory, 'Matterbridge', 'profiles', this.profile) : path.join(this.homeDirectory, 'Matterbridge');
293
199
  await createDirectory(this.matterbridgePluginDirectory, 'Matterbridge Plugin Directory', this.log);
294
- // Set the matterbridge cert directory
295
200
  this.matterbridgeCertDirectory = this.profile ? path.join(this.homeDirectory, '.mattercert', 'profiles', this.profile) : path.join(this.homeDirectory, '.mattercert');
296
201
  await createDirectory(this.matterbridgeCertDirectory, 'Matterbridge Matter Certificate Directory', this.log);
297
- // Set the matterbridge root directory
298
202
  const { fileURLToPath } = await import('node:url');
299
203
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
300
- this.rootDirectory = path.resolve(currentFileDirectory, '../'); // Adjust the path for dist directory
301
- // Setup the matter environment with default values
204
+ this.rootDirectory = path.resolve(currentFileDirectory, '../');
302
205
  this.environment.vars.set('log.level', MatterLogLevel.INFO);
303
206
  this.environment.vars.set('log.format', MatterLogFormat.ANSI);
304
207
  this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME));
305
208
  this.environment.vars.set('runtime.signals', false);
306
209
  this.environment.vars.set('runtime.exitcode', false);
307
- // Register process handlers
308
210
  this.registerProcessHandlers();
309
- // Initialize nodeStorage and nodeContext
310
211
  try {
311
212
  this.log.debug(`Creating node storage manager: ${CYAN}${NODE_STORAGE_DIR}${db}`);
312
213
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, NODE_STORAGE_DIR), writeQueue: false, expiredInterval: undefined, logging: false });
313
214
  this.log.debug('Creating node storage context for matterbridge');
314
215
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
315
- // TODO: Remove this code when node-persist-manager is updated
316
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
317
216
  const keys = (await this.nodeStorage?.storage.keys());
318
217
  for (const key of keys) {
319
218
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
320
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
321
219
  await this.nodeStorage?.storage.get(key);
322
220
  }
323
221
  const storages = await this.nodeStorage.getStorageNames();
324
222
  for (const storage of storages) {
325
223
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
326
224
  const nodeContext = await this.nodeStorage?.createStorage(storage);
327
- // TODO: Remove this code when node-persist-manager is updated
328
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
329
225
  const keys = (await nodeContext?.storage.keys());
330
226
  keys.forEach(async (key) => {
331
227
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
332
228
  await nodeContext?.get(key);
333
229
  });
334
230
  }
335
- // Creating a backup of the node storage since it is not corrupted
336
231
  this.log.debug('Creating node storage backup...');
337
232
  await copyDirectory(path.join(this.matterbridgeDirectory, NODE_STORAGE_DIR), path.join(this.matterbridgeDirectory, NODE_STORAGE_DIR + '.backup'));
338
233
  this.log.debug('Created node storage backup');
339
234
  }
340
235
  catch (error) {
341
- // Restoring the backup of the node storage since it is corrupted
342
236
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
343
237
  if (hasParameter('norestore')) {
344
238
  this.log.fatal(`The matterbridge storage is corrupted. Found -norestore parameter: exiting...`);
@@ -352,19 +246,14 @@ export class Matterbridge extends EventEmitter {
352
246
  if (!this.nodeStorage || !this.nodeContext) {
353
247
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
354
248
  }
355
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
356
249
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
357
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
358
250
  this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode')) ?? PaseClient.generateRandomPasscode(this.environment.get(Crypto));
359
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
360
251
  this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator')) ?? PaseClient.generateRandomDiscriminator(this.environment.get(Crypto));
361
- // Certificate management
362
252
  const pairingFilePath = path.join(this.matterbridgeCertDirectory, 'pairing.json');
363
253
  try {
364
254
  await fs.promises.access(pairingFilePath, fs.constants.R_OK);
365
255
  const pairingFileContent = await fs.promises.readFile(pairingFilePath, 'utf8');
366
256
  const pairingFileJson = JSON.parse(pairingFileContent);
367
- // Set the vendorId, vendorName, productId, productName, deviceType, serialNumber, uniqueId if they are present in the pairing file
368
257
  if (isValidNumber(pairingFileJson.vendorId)) {
369
258
  this.aggregatorVendorId = VendorId(pairingFileJson.vendorId);
370
259
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using vendorId ${CYAN}${this.aggregatorVendorId}${nf} from pairing file.`);
@@ -393,13 +282,11 @@ export class Matterbridge extends EventEmitter {
393
282
  this.aggregatorUniqueId = pairingFileJson.uniqueId;
394
283
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using uniqueId ${CYAN}${this.aggregatorUniqueId}${nf} from pairing file.`);
395
284
  }
396
- // Override the passcode and discriminator if they are present in the pairing file
397
285
  if (isValidNumber(pairingFileJson.passcode) && isValidNumber(pairingFileJson.discriminator)) {
398
286
  this.passcode = pairingFileJson.passcode;
399
287
  this.discriminator = pairingFileJson.discriminator;
400
288
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using passcode ${CYAN}${this.passcode}${nf} and discriminator ${CYAN}${this.discriminator}${nf} from pairing file.`);
401
289
  }
402
- // Set the certification for matter.js if it is present in the pairing file
403
290
  if (pairingFileJson.privateKey && pairingFileJson.certificate && pairingFileJson.intermediateCertificate && pairingFileJson.declaration) {
404
291
  const { hexToBuffer } = await import('./utils/hex.js');
405
292
  this.certification = {
@@ -414,44 +301,41 @@ export class Matterbridge extends EventEmitter {
414
301
  catch (error) {
415
302
  this.log.debug(`Pairing file ${CYAN}${pairingFilePath}${db} not found: ${error instanceof Error ? error.message : error}`);
416
303
  }
417
- // Store the passcode, discriminator and port in the node context
418
304
  await this.nodeContext.set('matterport', this.port);
419
305
  await this.nodeContext.set('matterpasscode', this.passcode);
420
306
  await this.nodeContext.set('matterdiscriminator', this.discriminator);
421
307
  this.log.debug(`Initializing server node for Matterbridge on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
422
- // Set matterbridge logger level (context: matterbridgeLogLevel)
423
308
  if (hasParameter('logger')) {
424
309
  const level = getParameter('logger');
425
310
  if (level === 'debug') {
426
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
311
+ this.log.logLevel = "debug";
427
312
  }
428
313
  else if (level === 'info') {
429
- this.log.logLevel = "info" /* LogLevel.INFO */;
314
+ this.log.logLevel = "info";
430
315
  }
431
316
  else if (level === 'notice') {
432
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
317
+ this.log.logLevel = "notice";
433
318
  }
434
319
  else if (level === 'warn') {
435
- this.log.logLevel = "warn" /* LogLevel.WARN */;
320
+ this.log.logLevel = "warn";
436
321
  }
437
322
  else if (level === 'error') {
438
- this.log.logLevel = "error" /* LogLevel.ERROR */;
323
+ this.log.logLevel = "error";
439
324
  }
440
325
  else if (level === 'fatal') {
441
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
326
+ this.log.logLevel = "fatal";
442
327
  }
443
328
  else {
444
329
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
445
- this.log.logLevel = "info" /* LogLevel.INFO */;
330
+ this.log.logLevel = "info";
446
331
  }
447
332
  }
448
333
  else {
449
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.shellyBoard ? "notice" /* LogLevel.NOTICE */ : "info" /* LogLevel.INFO */);
334
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.shellyBoard ? "notice" : "info");
450
335
  }
451
336
  this.logLevel = this.log.logLevel;
452
337
  this.frontend.logLevel = this.log.logLevel;
453
338
  MatterbridgeEndpoint.logLevel = this.log.logLevel;
454
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
455
339
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
456
340
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, MATTERBRIDGE_LOGGER_FILE), this.log.logLevel, true);
457
341
  this.fileLogger = true;
@@ -460,7 +344,6 @@ export class Matterbridge extends EventEmitter {
460
344
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.fileLogger}.`);
461
345
  if (this.profile !== undefined)
462
346
  this.log.debug(`Matterbridge profile: ${this.profile}.`);
463
- // Set matter.js logger level, format and logger (context: matterLogLevel)
464
347
  if (hasParameter('matterlogger')) {
465
348
  const level = getParameter('matterlogger');
466
349
  if (level === 'debug') {
@@ -491,13 +374,11 @@ export class Matterbridge extends EventEmitter {
491
374
  }
492
375
  Logger.format = MatterLogFormat.ANSI;
493
376
  this.matterLogLevel = MatterLogLevel.names[Logger.level];
494
- // Create the logger for matter.js with file logging (context: matterFileLog)
495
377
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
496
378
  this.matterFileLogger = true;
497
379
  }
498
380
  Logger.destinations.default.write = this.createDestinationMatterLogger(this.matterFileLogger);
499
381
  this.log.debug(`Matter logLevel: ${this.matterLogLevel} fileLoger: ${this.matterFileLogger}.`);
500
- // Log network interfaces
501
382
  const networkInterfaces = os.networkInterfaces();
502
383
  const availableAddresses = Object.entries(networkInterfaces);
503
384
  const availableInterfaceNames = Object.keys(networkInterfaces);
@@ -510,7 +391,6 @@ export class Matterbridge extends EventEmitter {
510
391
  });
511
392
  }
512
393
  }
513
- // Set the interface to use for matter server node mdnsInterface
514
394
  if (hasParameter('mdnsinterface')) {
515
395
  this.mdnsInterface = getParameter('mdnsinterface');
516
396
  }
@@ -519,7 +399,6 @@ export class Matterbridge extends EventEmitter {
519
399
  if (this.mdnsInterface === '')
520
400
  this.mdnsInterface = undefined;
521
401
  }
522
- // Validate mdnsInterface
523
402
  if (this.mdnsInterface) {
524
403
  if (!availableInterfaceNames.includes(this.mdnsInterface)) {
525
404
  this.log.error(`Invalid mdnsinterface: ${this.mdnsInterface}. Available interfaces are: ${availableInterfaceNames.join(', ')}. Using all available interfaces.`);
@@ -532,7 +411,6 @@ export class Matterbridge extends EventEmitter {
532
411
  }
533
412
  if (this.mdnsInterface)
534
413
  this.environment.vars.set('mdns.networkInterface', this.mdnsInterface);
535
- // Set the listeningAddressIpv4 for the matter commissioning server
536
414
  if (hasParameter('ipv4address')) {
537
415
  this.ipv4Address = getParameter('ipv4address');
538
416
  }
@@ -541,7 +419,6 @@ export class Matterbridge extends EventEmitter {
541
419
  if (this.ipv4Address === '')
542
420
  this.ipv4Address = undefined;
543
421
  }
544
- // Validate ipv4address
545
422
  if (this.ipv4Address) {
546
423
  let isValid = false;
547
424
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -557,7 +434,6 @@ export class Matterbridge extends EventEmitter {
557
434
  await this.nodeContext.remove('matteripv4address');
558
435
  }
559
436
  }
560
- // Set the listeningAddressIpv6 for the matter commissioning server
561
437
  if (hasParameter('ipv6address')) {
562
438
  this.ipv6Address = getParameter('ipv6address');
563
439
  }
@@ -566,7 +442,6 @@ export class Matterbridge extends EventEmitter {
566
442
  if (this.ipv6Address === '')
567
443
  this.ipv6Address = undefined;
568
444
  }
569
- // Validate ipv6address
570
445
  if (this.ipv6Address) {
571
446
  let isValid = false;
572
447
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -575,7 +450,6 @@ export class Matterbridge extends EventEmitter {
575
450
  isValid = true;
576
451
  break;
577
452
  }
578
- /* istanbul ignore next */
579
453
  if (ifaces && ifaces.find((iface) => iface.scopeid && iface.scopeid > 0 && iface.address + '%' + (process.platform === 'win32' ? iface.scopeid : ifaceName) === this.ipv6Address)) {
580
454
  this.log.info(`Using ipv6address ${CYAN}${this.ipv6Address}${nf} on interface ${CYAN}${ifaceName}${nf} for the Matter server node.`);
581
455
  isValid = true;
@@ -588,7 +462,6 @@ export class Matterbridge extends EventEmitter {
588
462
  await this.nodeContext.remove('matteripv6address');
589
463
  }
590
464
  }
591
- // Initialize the virtual mode
592
465
  if (hasParameter('novirtual')) {
593
466
  this.virtualMode = 'disabled';
594
467
  await this.nodeContext.set('virtualmode', 'disabled');
@@ -597,15 +470,10 @@ export class Matterbridge extends EventEmitter {
597
470
  this.virtualMode = (await this.nodeContext.get('virtualmode', 'outlet'));
598
471
  }
599
472
  this.log.debug(`Virtual mode ${this.virtualMode}.`);
600
- // Initialize PluginManager
601
473
  this.plugins.logLevel = this.log.logLevel;
602
474
  await this.plugins.loadFromStorage();
603
- // Initialize DeviceManager
604
475
  this.devices.logLevel = this.log.logLevel;
605
- // Get the plugins from node storage and create the plugins node storage contexts
606
476
  for (const plugin of this.plugins) {
607
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
608
- // We don't do this when the add and other shutdown parameters are set because we shut down the process after adding the plugin
609
477
  if (!fs.existsSync(plugin.path) && !hasParameter('add') && !hasParameter('remove') && !hasParameter('enable') && !hasParameter('disable') && !hasParameter('reset') && !hasParameter('factoryreset')) {
610
478
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm...`);
611
479
  const { spawnCommand } = await import('./utils/spawn.js');
@@ -635,7 +503,6 @@ export class Matterbridge extends EventEmitter {
635
503
  await plugin.nodeContext.set('description', plugin.description);
636
504
  await plugin.nodeContext.set('author', plugin.author);
637
505
  }
638
- // Log system info and create .matterbridge directory
639
506
  await this.logNodeAndSystemInfo();
640
507
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
641
508
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -643,7 +510,6 @@ export class Matterbridge extends EventEmitter {
643
510
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
644
511
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
645
512
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
646
- // Check node version and throw error
647
513
  const minNodeVersion = 20;
648
514
  const nodeVersion = process.versions.node;
649
515
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -651,18 +517,10 @@ export class Matterbridge extends EventEmitter {
651
517
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
652
518
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
653
519
  }
654
- // Parse command line
655
520
  await this.parseCommandLine();
656
- // Emit the initialize_completed event
657
521
  this.emit('initialize_completed');
658
522
  this.initialized = true;
659
523
  }
660
- /**
661
- * Parses the command line arguments and performs the corresponding actions.
662
- *
663
- * @private
664
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
665
- */
666
524
  async parseCommandLine() {
667
525
  if (hasParameter('list')) {
668
526
  this.log.info(`│ Registered plugins (${this.plugins.length})`);
@@ -678,19 +536,6 @@ export class Matterbridge extends EventEmitter {
678
536
  }
679
537
  index++;
680
538
  }
681
- /*
682
- const serializedRegisteredDevices = await this.nodeContext?.get<SerializedMatterbridgeEndpoint[]>('devices', []);
683
- this.log.info(`│ Registered devices (${serializedRegisteredDevices?.length})`);
684
- serializedRegisteredDevices?.forEach((device, index) => {
685
- if (index !== serializedRegisteredDevices.length - 1) {
686
- this.log.info(`├─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
687
- this.log.info(`│ └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
688
- } else {
689
- this.log.info(`└─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
690
- this.log.info(` └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
691
- }
692
- });
693
- */
694
539
  this.shutdown = true;
695
540
  return;
696
541
  }
@@ -740,10 +585,8 @@ export class Matterbridge extends EventEmitter {
740
585
  this.shutdown = true;
741
586
  return;
742
587
  }
743
- // Initialize frontend
744
588
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
745
589
  await this.frontend.start(getIntParameter('frontend'));
746
- // Start the matter storage and create the matterbridge context
747
590
  try {
748
591
  await this.startMatterStorage();
749
592
  if (this.aggregatorSerialNumber && this.aggregatorUniqueId && this.matterStorageService) {
@@ -757,21 +600,18 @@ export class Matterbridge extends EventEmitter {
757
600
  this.log.fatal(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
758
601
  throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
759
602
  }
760
- // Clear the matterbridge context if the reset parameter is set (bridge mode)
761
603
  if (hasParameter('reset') && getParameter('reset') === undefined) {
762
604
  this.initialized = true;
763
605
  await this.shutdownProcessAndReset();
764
606
  this.shutdown = true;
765
607
  return;
766
608
  }
767
- // Clear matterbridge plugin context if the reset parameter is set (childbridge mode)
768
609
  if (hasParameter('reset') && getParameter('reset') !== undefined) {
769
610
  this.log.debug(`Reset plugin ${getParameter('reset')}`);
770
611
  const plugin = this.plugins.get(getParameter('reset'));
771
612
  if (plugin) {
772
613
  const matterStorageManager = await this.matterStorageService?.open(plugin.name);
773
614
  if (!matterStorageManager) {
774
- /* istanbul ignore next */
775
615
  this.log.error(`Plugin ${plg}${plugin.name}${er} storageManager not found`);
776
616
  }
777
617
  else {
@@ -790,42 +630,35 @@ export class Matterbridge extends EventEmitter {
790
630
  this.shutdown = true;
791
631
  return;
792
632
  }
793
- // Check in 5 minutes the latest and dev versions of matterbridge and the plugins
794
633
  clearTimeout(this.checkUpdateTimeout);
795
634
  this.checkUpdateTimeout = setTimeout(async () => {
796
635
  const { checkUpdates } = await import('./update.js');
797
636
  checkUpdates(this);
798
637
  }, 300 * 1000).unref();
799
- // Check each 12 hours the latest and dev versions of matterbridge and the plugins
800
638
  clearInterval(this.checkUpdateInterval);
801
639
  this.checkUpdateInterval = setInterval(async () => {
802
640
  const { checkUpdates } = await import('./update.js');
803
641
  checkUpdates(this);
804
642
  }, 12 * 60 * 60 * 1000).unref();
805
- // Start the matterbridge in mode test
806
643
  if (hasParameter('test')) {
807
644
  this.bridgeMode = 'bridge';
808
645
  return;
809
646
  }
810
- // Start the matterbridge in mode controller
811
647
  if (hasParameter('controller')) {
812
648
  this.bridgeMode = 'controller';
813
649
  await this.startController();
814
650
  return;
815
651
  }
816
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
817
652
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
818
653
  this.log.info('Setting default matterbridge start mode to bridge');
819
654
  await this.nodeContext?.set('bridgeMode', 'bridge');
820
655
  }
821
- // Start matterbridge in bridge mode
822
656
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
823
657
  this.bridgeMode = 'bridge';
824
658
  this.log.debug(`Starting matterbridge in mode ${this.bridgeMode}`);
825
659
  await this.startBridge();
826
660
  return;
827
661
  }
828
- // Start matterbridge in childbridge mode
829
662
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
830
663
  this.bridgeMode = 'childbridge';
831
664
  this.log.debug(`Starting matterbridge in mode ${this.bridgeMode}`);
@@ -833,22 +666,10 @@ export class Matterbridge extends EventEmitter {
833
666
  return;
834
667
  }
835
668
  }
836
- /**
837
- * Asynchronously loads and starts the registered plugins.
838
- *
839
- * This method is responsible for initializing and starting all enabled plugins.
840
- * It ensures that each plugin is properly loaded and started before the bridge starts.
841
- *
842
- * @param {boolean} [wait] - If true, the method will wait for all plugins to be fully loaded and started before resolving. Defaults to false.
843
- * @param {boolean} [start] - If true, the method will start the plugins after loading them. Defaults to true.
844
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
845
- */
846
669
  async startPlugins(wait = false, start = true) {
847
- // Check, load and start the plugins
848
670
  for (const plugin of this.plugins) {
849
671
  plugin.configJson = await this.plugins.loadConfig(plugin);
850
672
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
851
- // Check if the plugin is available
852
673
  if (!(await this.plugins.resolve(plugin.path))) {
853
674
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
854
675
  plugin.enabled = false;
@@ -868,16 +689,10 @@ export class Matterbridge extends EventEmitter {
868
689
  if (wait)
869
690
  await this.plugins.load(plugin, start, 'Matterbridge is starting');
870
691
  else
871
- this.plugins.load(plugin, start, 'Matterbridge is starting'); // No await do it asyncronously
692
+ this.plugins.load(plugin, start, 'Matterbridge is starting');
872
693
  }
873
694
  this.frontend.wssSendRefreshRequired('plugins');
874
695
  }
875
- /**
876
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
877
- * - When an uncaught exception occurs, the exceptionHandler logs the error message and stack trace.
878
- * - When an unhandled promise rejection occurs, the rejectionHandler logs the reason and stack trace.
879
- * - When either of SIGINT and SIGTERM signals are received, the cleanup method is called with an appropriate message.
880
- */
881
696
  registerProcessHandlers() {
882
697
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
883
698
  process.removeAllListeners('uncaughtException');
@@ -904,9 +719,6 @@ export class Matterbridge extends EventEmitter {
904
719
  };
905
720
  process.on('SIGTERM', this.sigtermHandler);
906
721
  }
907
- /**
908
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
909
- */
910
722
  deregisterProcessHandlers() {
911
723
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
912
724
  if (this.exceptionHandler)
@@ -923,18 +735,13 @@ export class Matterbridge extends EventEmitter {
923
735
  process.off('SIGTERM', this.sigtermHandler);
924
736
  this.sigtermHandler = undefined;
925
737
  }
926
- /**
927
- * Logs the node and system information.
928
- */
929
738
  async logNodeAndSystemInfo() {
930
- // IP address information
931
739
  const networkInterfaces = os.networkInterfaces();
932
740
  this.systemInformation.interfaceName = '';
933
741
  this.systemInformation.ipv4Address = '';
934
742
  this.systemInformation.ipv6Address = '';
935
743
  this.systemInformation.macAddress = '';
936
744
  for (const [interfaceName, interfaceDetails] of Object.entries(networkInterfaces)) {
937
- // this.log.debug(`Checking interface: '${interfaceName}' for '${this.mdnsInterface}'`);
938
745
  if (this.mdnsInterface && interfaceName !== this.mdnsInterface)
939
746
  continue;
940
747
  if (!interfaceDetails) {
@@ -960,18 +767,16 @@ export class Matterbridge extends EventEmitter {
960
767
  break;
961
768
  }
962
769
  }
963
- // Node information
964
770
  this.systemInformation.nodeVersion = process.versions.node;
965
771
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
966
772
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
967
773
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
968
- // Host system information
969
774
  this.systemInformation.hostname = os.hostname();
970
775
  this.systemInformation.user = os.userInfo().username;
971
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
972
- this.systemInformation.osRelease = os.release(); // Kernel version
973
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
974
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
776
+ this.systemInformation.osType = os.type();
777
+ this.systemInformation.osRelease = os.release();
778
+ this.systemInformation.osPlatform = os.platform();
779
+ this.systemInformation.osArch = os.arch();
975
780
  this.systemInformation.totalMemory = formatBytes(os.totalmem());
976
781
  this.systemInformation.freeMemory = formatBytes(os.freemem());
977
782
  this.systemInformation.systemUptime = formatUptime(os.uptime());
@@ -981,7 +786,6 @@ export class Matterbridge extends EventEmitter {
981
786
  this.systemInformation.rss = formatBytes(process.memoryUsage().rss);
982
787
  this.systemInformation.heapTotal = formatBytes(process.memoryUsage().heapTotal);
983
788
  this.systemInformation.heapUsed = formatBytes(process.memoryUsage().heapUsed);
984
- // Log the system information
985
789
  this.log.debug('Host System Information:');
986
790
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
987
791
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -1001,17 +805,14 @@ export class Matterbridge extends EventEmitter {
1001
805
  this.log.debug(`- RSS: ${this.systemInformation.rss}`);
1002
806
  this.log.debug(`- Heap Total: ${this.systemInformation.heapTotal}`);
1003
807
  this.log.debug(`- Heap Used: ${this.systemInformation.heapUsed}`);
1004
- // Log directories
1005
808
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
1006
809
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
1007
810
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
1008
811
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
1009
812
  this.log.debug(`Matterbridge Matter Certificate Directory: ${this.matterbridgeCertDirectory}`);
1010
- // Global node_modules directory
1011
813
  if (this.nodeContext)
1012
814
  this.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
1013
815
  if (this.globalModulesDirectory === '') {
1014
- // First run of Matterbridge so the node storage is empty
1015
816
  this.log.debug(`Getting global node_modules directory...`);
1016
817
  try {
1017
818
  const { getGlobalNodeModules } = await import('./utils/network.js');
@@ -1024,42 +825,29 @@ export class Matterbridge extends EventEmitter {
1024
825
  }
1025
826
  }
1026
827
  else {
1027
- // The global node_modules directory is already set in the node storage and we check if it is still valid
1028
828
  this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
1029
829
  const { createESMWorker } = await import('./workers.js');
1030
830
  createESMWorker('NpmGlobalPrefix', path.join(this.rootDirectory, 'dist/workerGlobalPrefix.js'));
1031
831
  }
1032
- // Matterbridge version
1033
832
  this.log.debug(`Reading matterbridge package.json...`);
1034
833
  const packageJson = JSON.parse(await fs.promises.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
1035
834
  this.matterbridgeVersion = this.matterbridgeLatestVersion = this.matterbridgeDevVersion = packageJson.version;
1036
835
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
1037
- // Matterbridge latest version (will be set in the checkUpdate function)
1038
836
  if (this.nodeContext)
1039
837
  this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', this.matterbridgeVersion);
1040
838
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
1041
- // Matterbridge dev version (will be set in the checkUpdate function)
1042
839
  if (this.nodeContext)
1043
840
  this.matterbridgeDevVersion = await this.nodeContext.get('matterbridgeDevVersion', this.matterbridgeVersion);
1044
841
  this.log.debug(`Matterbridge Dev Version: ${this.matterbridgeDevVersion}`);
1045
- // Frontend version
1046
842
  this.log.debug(`Reading frontend package.json...`);
1047
843
  const frontendPackageJson = JSON.parse(await fs.promises.readFile(path.join(this.rootDirectory, 'frontend/package.json'), 'utf8'));
1048
844
  this.frontendVersion = frontendPackageJson.version;
1049
845
  this.log.debug(`Frontend version ${CYAN}${this.frontendVersion}${db}`);
1050
- // Current working directory
1051
846
  const currentDir = process.cwd();
1052
847
  this.log.debug(`Current Working Directory: ${currentDir}`);
1053
- // Command line arguments (excluding 'node' and the script name)
1054
848
  const cmdArgs = process.argv.slice(2).join(' ');
1055
849
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
1056
850
  }
1057
- /**
1058
- * Set the logger logLevel for the Matterbridge classes and call onChangeLoggerLevel() for each plugin.
1059
- *
1060
- * @param {LogLevel} logLevel The logger logLevel to set.
1061
- * @returns {Promise<LogLevel>} A promise that resolves when the logLevel has been set.
1062
- */
1063
851
  async setLogLevel(logLevel) {
1064
852
  this.logLevel = logLevel;
1065
853
  this.log.logLevel = logLevel;
@@ -1070,87 +858,58 @@ export class Matterbridge extends EventEmitter {
1070
858
  for (const plugin of this.plugins) {
1071
859
  if (!plugin.platform || !plugin.platform.log || !plugin.platform.config)
1072
860
  continue;
1073
- plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : logLevel;
1074
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : logLevel);
1075
- }
1076
- // Set the global logger callback for the WebSocketServer to the common minimum logLevel
1077
- let callbackLogLevel = "notice" /* LogLevel.NOTICE */;
1078
- if (logLevel === "info" /* LogLevel.INFO */ || Logger.level === MatterLogLevel.INFO)
1079
- callbackLogLevel = "info" /* LogLevel.INFO */;
1080
- if (logLevel === "debug" /* LogLevel.DEBUG */ || Logger.level === MatterLogLevel.DEBUG)
1081
- callbackLogLevel = "debug" /* LogLevel.DEBUG */;
861
+ plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" : logLevel;
862
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" : logLevel);
863
+ }
864
+ let callbackLogLevel = "notice";
865
+ if (logLevel === "info" || Logger.level === MatterLogLevel.INFO)
866
+ callbackLogLevel = "info";
867
+ if (logLevel === "debug" || Logger.level === MatterLogLevel.DEBUG)
868
+ callbackLogLevel = "debug";
1082
869
  AnsiLogger.setGlobalCallbackLevel(callbackLogLevel);
1083
870
  this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
1084
871
  return logLevel;
1085
872
  }
1086
- /**
1087
- * Get the current logger logLevel.
1088
- *
1089
- * @returns {LogLevel} The current logger logLevel.
1090
- */
1091
873
  getLogLevel() {
1092
874
  return this.log.logLevel;
1093
875
  }
1094
- /**
1095
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
1096
- * It also logs to file (matter.log) if fileLogger is true.
1097
- *
1098
- * @param {boolean} fileLogger - Whether to log to file or not.
1099
- * @returns {Function} The MatterLogger function. \x1b[35m for violet \x1b[34m is blue
1100
- */
1101
876
  createDestinationMatterLogger(fileLogger) {
1102
- this.matterLog.logNameColor = '\x1b[34m'; // Blue matter.js Logger
877
+ this.matterLog.logNameColor = '\x1b[34m';
1103
878
  if (fileLogger) {
1104
879
  this.matterLog.logFilePath = path.join(this.matterbridgeDirectory, MATTER_LOGGER_FILE);
1105
880
  }
1106
881
  return (text, message) => {
1107
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1108
882
  const logger = text.slice(44, 44 + 20).trim();
1109
883
  const msg = text.slice(65);
1110
884
  this.matterLog.logName = logger;
1111
885
  switch (message.level) {
1112
886
  case MatterLogLevel.DEBUG:
1113
- this.matterLog.log("debug" /* LogLevel.DEBUG */, msg);
887
+ this.matterLog.log("debug", msg);
1114
888
  break;
1115
889
  case MatterLogLevel.INFO:
1116
- this.matterLog.log("info" /* LogLevel.INFO */, msg);
890
+ this.matterLog.log("info", msg);
1117
891
  break;
1118
892
  case MatterLogLevel.NOTICE:
1119
- this.matterLog.log("notice" /* LogLevel.NOTICE */, msg);
893
+ this.matterLog.log("notice", msg);
1120
894
  break;
1121
895
  case MatterLogLevel.WARN:
1122
- this.matterLog.log("warn" /* LogLevel.WARN */, msg);
896
+ this.matterLog.log("warn", msg);
1123
897
  break;
1124
898
  case MatterLogLevel.ERROR:
1125
- this.matterLog.log("error" /* LogLevel.ERROR */, msg);
899
+ this.matterLog.log("error", msg);
1126
900
  break;
1127
901
  case MatterLogLevel.FATAL:
1128
- this.matterLog.log("fatal" /* LogLevel.FATAL */, msg);
902
+ this.matterLog.log("fatal", msg);
1129
903
  break;
1130
904
  }
1131
905
  };
1132
906
  }
1133
- /**
1134
- * Restarts the process by exiting the current instance and loading a new instance (/api/restart).
1135
- *
1136
- * @returns {Promise<void>} A promise that resolves when the restart is completed.
1137
- */
1138
907
  async restartProcess() {
1139
908
  await this.cleanup('restarting...', true);
1140
909
  }
1141
- /**
1142
- * Shut down the process (/api/shutdown).
1143
- *
1144
- * @returns {Promise<void>} A promise that resolves when the shutdown is completed.
1145
- */
1146
910
  async shutdownProcess() {
1147
911
  await this.cleanup('shutting down...', false);
1148
912
  }
1149
- /**
1150
- * Update matterbridge and shut down the process (virtual device 'Update Matterbridge').
1151
- *
1152
- * @returns {Promise<void>} A promise that resolves when the update is completed.
1153
- */
1154
913
  async updateProcess() {
1155
914
  this.log.info('Updating matterbridge...');
1156
915
  const { spawnCommand } = await import('./utils/spawn.js');
@@ -1163,13 +922,6 @@ export class Matterbridge extends EventEmitter {
1163
922
  this.frontend.wssSendRestartRequired();
1164
923
  await this.cleanup('updating...', false);
1165
924
  }
1166
- /**
1167
- * Unregister all devices and shut down the process (/api/unregister).
1168
- *
1169
- * @param {number} [timeout] - The timeout duration to wait for the message exchange to complete in milliseconds. Default is 1000.
1170
- *
1171
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1172
- */
1173
925
  async unregisterAndShutdownProcess(timeout = 1000) {
1174
926
  this.log.info('Unregistering all devices and shutting down...');
1175
927
  for (const plugin of this.plugins.array()) {
@@ -1181,71 +933,46 @@ export class Matterbridge extends EventEmitter {
1181
933
  await this.removeAllBridgedEndpoints(plugin.name, 100);
1182
934
  }
1183
935
  this.log.debug('Waiting for the MessageExchange to finish...');
1184
- await wait(timeout); // Wait for MessageExchange to finish
936
+ await wait(timeout);
1185
937
  this.log.debug('Cleaning up and shutting down...');
1186
938
  await this.cleanup('unregistered all devices and shutting down...', false, timeout);
1187
939
  }
1188
- /**
1189
- * Reset commissioning and shut down the process (/api/reset).
1190
- *
1191
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1192
- */
1193
940
  async shutdownProcessAndReset() {
1194
941
  await this.cleanup('shutting down with reset...', false);
1195
942
  }
1196
- /**
1197
- * Factory reset and shut down the process (/api/factory-reset).
1198
- *
1199
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1200
- */
1201
943
  async shutdownProcessAndFactoryReset() {
1202
944
  await this.cleanup('shutting down with factory reset...', false);
1203
945
  }
1204
- /**
1205
- * Cleans up the Matterbridge instance.
1206
- *
1207
- * @param {string} message - The cleanup message.
1208
- * @param {boolean} [restart] - Indicates whether to restart the instance after cleanup. Default is `false`.
1209
- * @param {number} [pause] - The pause in ms to wait for the message exchange to complete in milliseconds. Default is 1000.
1210
- *
1211
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1212
- */
1213
946
  async cleanup(message, restart = false, pause = 1000) {
1214
947
  if (this.initialized && !this.hasCleanupStarted) {
1215
948
  this.emit('cleanup_started');
1216
949
  this.hasCleanupStarted = true;
1217
950
  this.log.info(message);
1218
- // Clear the start matter interval
1219
951
  if (this.startMatterInterval) {
1220
952
  clearInterval(this.startMatterInterval);
1221
953
  this.startMatterInterval = undefined;
1222
954
  this.log.debug('Start matter interval cleared');
1223
955
  }
1224
- // Clear the check update timeout
1225
956
  if (this.checkUpdateTimeout) {
1226
957
  clearTimeout(this.checkUpdateTimeout);
1227
958
  this.checkUpdateTimeout = undefined;
1228
959
  this.log.debug('Check update timeout cleared');
1229
960
  }
1230
- // Clear the check update interval
1231
961
  if (this.checkUpdateInterval) {
1232
962
  clearInterval(this.checkUpdateInterval);
1233
963
  this.checkUpdateInterval = undefined;
1234
964
  this.log.debug('Check update interval cleared');
1235
965
  }
1236
- // Clear the configure timeout
1237
966
  if (this.configureTimeout) {
1238
967
  clearTimeout(this.configureTimeout);
1239
968
  this.configureTimeout = undefined;
1240
969
  this.log.debug('Matterbridge configure timeout cleared');
1241
970
  }
1242
- // Clear the reachability timeout
1243
971
  if (this.reachabilityTimeout) {
1244
972
  clearTimeout(this.reachabilityTimeout);
1245
973
  this.reachabilityTimeout = undefined;
1246
974
  this.log.debug('Matterbridge reachability timeout cleared');
1247
975
  }
1248
- // Call the shutdown method of each plugin and clear the plugins reachability timeout
1249
976
  for (const plugin of this.plugins) {
1250
977
  if (!plugin.enabled || plugin.error)
1251
978
  continue;
@@ -1256,7 +983,6 @@ export class Matterbridge extends EventEmitter {
1256
983
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1257
984
  }
1258
985
  }
1259
- // Stop matter server nodes
1260
986
  this.log.notice(`Stopping matter server nodes in ${this.bridgeMode} mode...`);
1261
987
  if (pause > 0) {
1262
988
  this.log.debug(`Waiting ${pause}ms for the MessageExchange to finish...`);
@@ -1283,7 +1009,6 @@ export class Matterbridge extends EventEmitter {
1283
1009
  }
1284
1010
  }
1285
1011
  this.log.notice('Stopped matter server nodes');
1286
- // Matter commisioning reset
1287
1012
  if (message === 'shutting down with reset...') {
1288
1013
  this.log.info('Resetting Matterbridge commissioning information...');
1289
1014
  await this.matterStorageManager?.createContext('events')?.clearAll();
@@ -1293,7 +1018,6 @@ export class Matterbridge extends EventEmitter {
1293
1018
  await this.matterbridgeContext?.clearAll();
1294
1019
  this.log.info('Matter storage reset done! Remove the bridge from the controller.');
1295
1020
  }
1296
- // Unregister all devices
1297
1021
  if (message === 'unregistered all devices and shutting down...') {
1298
1022
  if (this.bridgeMode === 'bridge') {
1299
1023
  await this.matterStorageManager?.createContext('root')?.createContext('parts')?.createContext('Matterbridge')?.createContext('parts')?.clearAll();
@@ -1311,35 +1035,16 @@ export class Matterbridge extends EventEmitter {
1311
1035
  }
1312
1036
  this.log.info('Matter storage reset done!');
1313
1037
  }
1314
- // Stop matter storage
1315
1038
  await this.stopMatterStorage();
1316
- // Stop the frontend
1317
1039
  await this.frontend.stop();
1318
1040
  this.frontend.destroy();
1319
- // Close PluginManager and DeviceManager
1320
1041
  this.plugins.destroy();
1321
1042
  this.devices.destroy();
1322
- // Stop thread messaging server
1323
1043
  this.server.close();
1324
- // Close the matterbridge node storage and context
1325
1044
  if (this.nodeStorage && this.nodeContext) {
1326
- /*
1327
- TODO: Implement serialization of registered devices
1328
- this.log.info('Saving registered devices...');
1329
- const serializedRegisteredDevices: SerializedMatterbridgeEndpoint[] = [];
1330
- this.devices.forEach(async (device) => {
1331
- const serializedMatterbridgeDevice = MatterbridgeEndpoint.serialize(device);
1332
- this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1333
- if (serializedMatterbridgeDevice) serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1334
- });
1335
- await this.nodeContext.set<SerializedMatterbridgeEndpoint[]>('devices', serializedRegisteredDevices);
1336
- this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1337
- */
1338
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1339
1045
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1340
1046
  await this.nodeContext.close();
1341
1047
  this.nodeContext = undefined;
1342
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1343
1048
  for (const plugin of this.plugins) {
1344
1049
  if (plugin.nodeContext) {
1345
1050
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1356,10 +1061,8 @@ export class Matterbridge extends EventEmitter {
1356
1061
  }
1357
1062
  this.plugins.clear();
1358
1063
  this.devices.clear();
1359
- // Factory reset
1360
1064
  if (message === 'shutting down with factory reset...') {
1361
1065
  try {
1362
- // Delete matter storage directory with its subdirectories and backup
1363
1066
  const dir = path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME);
1364
1067
  this.log.info(`Removing matter storage directory: ${dir}`);
1365
1068
  await fs.promises.rm(dir, { recursive: true });
@@ -1368,13 +1071,11 @@ export class Matterbridge extends EventEmitter {
1368
1071
  await fs.promises.rm(backup, { recursive: true });
1369
1072
  }
1370
1073
  catch (error) {
1371
- // istanbul ignore next if
1372
1074
  if (error instanceof Error && error.code !== 'ENOENT') {
1373
1075
  this.log.error(`Error removing matter storage directory: ${error}`);
1374
1076
  }
1375
1077
  }
1376
1078
  try {
1377
- // Delete matterbridge storage directory with its subdirectories and backup
1378
1079
  const dir = path.join(this.matterbridgeDirectory, NODE_STORAGE_DIR);
1379
1080
  this.log.info(`Removing matterbridge storage directory: ${dir}`);
1380
1081
  await fs.promises.rm(dir, { recursive: true });
@@ -1383,20 +1084,18 @@ export class Matterbridge extends EventEmitter {
1383
1084
  await fs.promises.rm(backup, { recursive: true });
1384
1085
  }
1385
1086
  catch (error) {
1386
- // istanbul ignore next if
1387
1087
  if (error instanceof Error && error.code !== 'ENOENT') {
1388
1088
  this.log.error(`Error removing matterbridge storage directory: ${error}`);
1389
1089
  }
1390
1090
  }
1391
1091
  this.log.info('Factory reset done! Remove all paired fabrics from the controllers.');
1392
1092
  }
1393
- // Deregisters the process handlers
1394
1093
  this.deregisterProcessHandlers();
1395
1094
  if (restart) {
1396
1095
  if (message === 'updating...') {
1397
1096
  this.log.info('Cleanup completed. Updating...');
1398
1097
  Matterbridge.instance = undefined;
1399
- this.emit('update'); // Restart the process but the update has been done before. TODO move all updates to the cli
1098
+ this.emit('update');
1400
1099
  }
1401
1100
  else if (message === 'restarting...') {
1402
1101
  this.log.info('Cleanup completed. Restarting...');
@@ -1425,14 +1124,7 @@ export class Matterbridge extends EventEmitter {
1425
1124
  this.log.debug('Cleanup already started...');
1426
1125
  }
1427
1126
  }
1428
- /**
1429
- * Starts the Matterbridge in bridge mode.
1430
- *
1431
- * @private
1432
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1433
- */
1434
1127
  async startBridge() {
1435
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1436
1128
  if (!this.matterStorageManager)
1437
1129
  throw new Error('No storage manager initialized');
1438
1130
  if (!this.matterbridgeContext)
@@ -1471,16 +1163,13 @@ export class Matterbridge extends EventEmitter {
1471
1163
  clearInterval(this.startMatterInterval);
1472
1164
  this.startMatterInterval = undefined;
1473
1165
  this.log.debug('Cleared startMatterInterval interval in bridge mode');
1474
- // Start the Matter server node
1475
- this.startServerNode(this.serverNode); // We don't await this, because the server node is started in the background
1476
- // Start the Matter server node of single devices in mode 'server'
1166
+ this.startServerNode(this.serverNode);
1477
1167
  for (const device of this.devices.array()) {
1478
1168
  if (device.mode === 'server' && device.serverNode) {
1479
1169
  this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
1480
- this.startServerNode(device.serverNode); // We don't await this, because the server node is started in the background
1170
+ this.startServerNode(device.serverNode);
1481
1171
  }
1482
1172
  }
1483
- // Configure the plugins
1484
1173
  this.configureTimeout = setTimeout(async () => {
1485
1174
  for (const plugin of this.plugins.array()) {
1486
1175
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1498,40 +1187,28 @@ export class Matterbridge extends EventEmitter {
1498
1187
  }
1499
1188
  this.frontend.wssSendRefreshRequired('plugins');
1500
1189
  }, 30 * 1000).unref();
1501
- // Setting reachability to true
1502
1190
  this.reachabilityTimeout = setTimeout(() => {
1503
1191
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1504
1192
  if (this.aggregatorNode)
1505
1193
  this.setAggregatorReachability(this.aggregatorNode, true);
1506
1194
  }, 60 * 1000).unref();
1507
- // Logger.get('LogServerNode').info(this.serverNode);
1508
1195
  this.emit('bridge_started');
1509
1196
  this.log.notice('Matterbridge bridge started successfully');
1510
1197
  this.frontend.wssSendRefreshRequired('settings');
1511
1198
  this.frontend.wssSendRefreshRequired('plugins');
1512
1199
  }, Number(process.env['MATTERBRIDGE_START_MATTER_INTERVAL_MS']) || this.startMatterIntervalMs);
1513
1200
  }
1514
- /**
1515
- * Starts the Matterbridge in childbridge mode.
1516
- *
1517
- * @param {number} [delay] - The delay before starting the childbridge. Default is 1000 milliseconds.
1518
- *
1519
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1520
- */
1521
1201
  async startChildbridge(delay = 1000) {
1522
1202
  if (!this.matterStorageManager)
1523
1203
  throw new Error('No storage manager initialized');
1524
- // Load with await all plugins but don't start them. We get the platform.type to pre-create server nodes for DynamicPlatform plugins
1525
1204
  this.log.debug('Loading all plugins in childbridge mode...');
1526
1205
  await this.startPlugins(true, false);
1527
- // Create server nodes for DynamicPlatform plugins and start all plugins in the background
1528
1206
  this.log.debug('Creating server nodes for DynamicPlatform plugins and starting all plugins in childbridge mode...');
1529
1207
  for (const plugin of this.plugins.array().filter((p) => p.enabled && !p.error)) {
1530
1208
  if (plugin.type === 'DynamicPlatform')
1531
1209
  await this.createDynamicPlugin(plugin);
1532
- this.plugins.start(plugin, 'Matterbridge is starting'); // Start the plugin in the background
1210
+ this.plugins.start(plugin, 'Matterbridge is starting');
1533
1211
  }
1534
- // Start the Matterbridge in childbridge mode when all plugins are loaded and started
1535
1212
  this.log.debug('Starting start matter interval in childbridge mode...');
1536
1213
  let failCount = 0;
1537
1214
  this.startMatterInterval = setInterval(async () => {
@@ -1565,9 +1242,8 @@ export class Matterbridge extends EventEmitter {
1565
1242
  clearInterval(this.startMatterInterval);
1566
1243
  this.startMatterInterval = undefined;
1567
1244
  if (delay > 0)
1568
- await wait(Number(process.env['MATTERBRIDGE_PAUSE_MATTER_INTERVAL_MS']) || delay); // Wait for the specified delay to ensure all plugins server nodes are ready
1245
+ await wait(Number(process.env['MATTERBRIDGE_PAUSE_MATTER_INTERVAL_MS']) || delay);
1569
1246
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1570
- // Configure the plugins
1571
1247
  this.configureTimeout = setTimeout(async () => {
1572
1248
  for (const plugin of this.plugins.array()) {
1573
1249
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1592,7 +1268,6 @@ export class Matterbridge extends EventEmitter {
1592
1268
  this.log.error(`Plugin ${plg}${plugin.name}${er} didn't register any devices to Matterbridge. Verify the plugin configuration.`);
1593
1269
  continue;
1594
1270
  }
1595
- // istanbul ignore next if cause is just a safety check
1596
1271
  if (!plugin.serverNode) {
1597
1272
  this.log.error(`Server node not found for plugin ${plg}${plugin.name}${er}`);
1598
1273
  continue;
@@ -1605,252 +1280,28 @@ export class Matterbridge extends EventEmitter {
1605
1280
  this.log.error(`Node storage context not found for plugin ${plg}${plugin.name}${er}`);
1606
1281
  continue;
1607
1282
  }
1608
- // Start the Matter server node
1609
- this.startServerNode(plugin.serverNode); // We don't await this, because the server node is started in the background
1610
- // Setting reachability to true
1283
+ this.startServerNode(plugin.serverNode);
1611
1284
  plugin.reachabilityTimeout = setTimeout(() => {
1612
1285
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${nf}`);
1613
1286
  if (plugin.type === 'DynamicPlatform' && plugin.aggregatorNode)
1614
1287
  this.setAggregatorReachability(plugin.aggregatorNode, true);
1615
1288
  }, 60 * 1000).unref();
1616
1289
  }
1617
- // Start the Matter server node of single devices in mode 'server'
1618
1290
  for (const device of this.devices.array()) {
1619
1291
  if (device.mode === 'server' && device.serverNode) {
1620
1292
  this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
1621
- this.startServerNode(device.serverNode); // We don't await this, because the server node is started in the background
1293
+ this.startServerNode(device.serverNode);
1622
1294
  }
1623
1295
  }
1624
- // Logger.get('LogServerNode').info(this.serverNode);
1625
1296
  this.emit('childbridge_started');
1626
1297
  this.log.notice('Matterbridge childbridge started successfully');
1627
1298
  this.frontend.wssSendRefreshRequired('settings');
1628
1299
  this.frontend.wssSendRefreshRequired('plugins');
1629
1300
  }, Number(process.env['MATTERBRIDGE_START_MATTER_INTERVAL_MS']) || this.startMatterIntervalMs);
1630
1301
  }
1631
- /**
1632
- * Starts the Matterbridge controller.
1633
- *
1634
- * @private
1635
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1636
- */
1637
1302
  async startController() {
1638
- /*
1639
- if (!this.matterStorageManager) {
1640
- this.log.error('No storage manager initialized');
1641
- await this.cleanup('No storage manager initialized');
1642
- return;
1643
- }
1644
- this.log.info('Creating context: mattercontrollerContext');
1645
- this.controllerContext = this.matterStorageManager.createContext('mattercontrollerContext');
1646
- if (!this.controllerContext) {
1647
- this.log.error('No storage context mattercontrollerContext initialized');
1648
- await this.cleanup('No storage context mattercontrollerContext initialized');
1649
- return;
1650
- }
1651
-
1652
- this.log.debug('Starting matterbridge in mode', this.bridgeMode);
1653
- this.matterServer = await this.createMatterServer(this.storageManager);
1654
- this.log.info('Creating matter commissioning controller');
1655
- this.commissioningController = new CommissioningController({
1656
- autoConnect: false,
1657
- });
1658
- this.log.info('Adding matter commissioning controller to matter server');
1659
- await this.matterServer.addCommissioningController(this.commissioningController);
1660
-
1661
- this.log.info('Starting matter server');
1662
- await this.matterServer.start();
1663
- this.log.info('Matter server started');
1664
- const commissioningOptions: ControllerCommissioningFlowOptions = {
1665
- regulatoryLocation: GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor,
1666
- regulatoryCountryCode: 'XX',
1667
- };
1668
- const commissioningController = new CommissioningController({
1669
- environment: {
1670
- environment,
1671
- id: uniqueId,
1672
- },
1673
- autoConnect: false, // Do not auto connect to the commissioned nodes
1674
- adminFabricLabel,
1675
- });
1676
-
1677
- if (hasParameter('pairingcode')) {
1678
- this.log.info('Pairing device with pairingcode:', getParameter('pairingcode'));
1679
- const pairingCode = getParameter('pairingcode');
1680
- const ip = this.controllerContext.has('ip') ? this.controllerContext.get<string>('ip') : undefined;
1681
- const port = this.controllerContext.has('port') ? this.controllerContext.get<number>('port') : undefined;
1682
-
1683
- let longDiscriminator, setupPin, shortDiscriminator;
1684
- if (pairingCode !== undefined) {
1685
- const pairingCodeCodec = ManualPairingCodeCodec.decode(pairingCode);
1686
- shortDiscriminator = pairingCodeCodec.shortDiscriminator;
1687
- longDiscriminator = undefined;
1688
- setupPin = pairingCodeCodec.passcode;
1689
- this.log.info(`Data extracted from pairing code: ${Logger.toJSON(pairingCodeCodec)}`);
1690
- } else {
1691
- longDiscriminator = await this.controllerContext.get('longDiscriminator', 3840);
1692
- if (longDiscriminator > 4095) throw new Error('Discriminator value must be less than 4096');
1693
- setupPin = this.controllerContext.get('pin', 20202021);
1694
- }
1695
- if ((shortDiscriminator === undefined && longDiscriminator === undefined) || setupPin === undefined) {
1696
- throw new Error('Please specify the longDiscriminator of the device to commission with -longDiscriminator or provide a valid passcode with -passcode');
1697
- }
1698
-
1699
- const options = {
1700
- commissioning: commissioningOptions,
1701
- discovery: {
1702
- knownAddress: ip !== undefined && port !== undefined ? { ip, port, type: 'udp' } : undefined,
1703
- identifierData: longDiscriminator !== undefined ? { longDiscriminator } : shortDiscriminator !== undefined ? { shortDiscriminator } : {},
1704
- },
1705
- passcode: setupPin,
1706
- } as NodeCommissioningOptions;
1707
- this.log.info('Commissioning with options:', options);
1708
- const nodeId = await this.commissioningController.commissionNode(options);
1709
- this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1710
- this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1711
- } // (hasParameter('pairingcode'))
1712
-
1713
- if (hasParameter('unpairall')) {
1714
- this.log.info('***Commissioning controller unpairing all nodes...');
1715
- const nodeIds = this.commissioningController.getCommissionedNodes();
1716
- for (const nodeId of nodeIds) {
1717
- this.log.info('***Commissioning controller unpairing node:', nodeId);
1718
- await this.commissioningController.removeNode(nodeId);
1719
- }
1720
- return;
1721
- }
1722
-
1723
- if (hasParameter('discover')) {
1724
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1725
- // console.log(discover);
1726
- }
1727
-
1728
- if (!this.commissioningController.isCommissioned()) {
1729
- this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
1730
- return;
1731
- }
1732
-
1733
- const nodeIds = this.commissioningController.getCommissionedNodes();
1734
- this.log.info(`***Commissioning controller is commissioned ${this.commissioningController.isCommissioned()} and has ${nodeIds.length} nodes commisioned: `);
1735
- for (const nodeId of nodeIds) {
1736
- this.log.info(`***Connecting to commissioned node: ${nodeId}`);
1737
-
1738
- const node = await this.commissioningController.connectNode(nodeId, {
1739
- autoSubscribe: false,
1740
- attributeChangedCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, attributeName }, value }) =>
1741
- this.log.info(`***Commissioning controller attributeChangedCallback ${peerNodeId}: attribute ${nodeId}/${endpointId}/${clusterId}/${attributeName} changed to ${Logger.toJSON(value)}`),
1742
- eventTriggeredCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, eventName }, events }) =>
1743
- this.log.info(`***Commissioning controller eventTriggeredCallback ${peerNodeId}: Event ${nodeId}/${endpointId}/${clusterId}/${eventName} triggered with ${Logger.toJSON(events)}`),
1744
- stateInformationCallback: (peerNodeId, info) => {
1745
- switch (info) {
1746
- case NodeStateInformation.Connected:
1747
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} connected`);
1748
- break;
1749
- case NodeStateInformation.Disconnected:
1750
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} disconnected`);
1751
- break;
1752
- case NodeStateInformation.Reconnecting:
1753
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} reconnecting`);
1754
- break;
1755
- case NodeStateInformation.WaitingForDeviceDiscovery:
1756
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} waiting for device discovery`);
1757
- break;
1758
- case NodeStateInformation.StructureChanged:
1759
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} structure changed`);
1760
- break;
1761
- case NodeStateInformation.Decommissioned:
1762
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} decommissioned`);
1763
- break;
1764
- default:
1765
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} NodeStateInformation.${info}`);
1766
- break;
1767
- }
1768
- },
1769
- });
1770
-
1771
- node.logStructure();
1772
-
1773
- // Get the interaction client
1774
- this.log.info('Getting the interaction client');
1775
- const interactionClient = await node.getInteractionClient();
1776
- let cluster;
1777
- let attributes;
1778
-
1779
- // Log BasicInformationCluster
1780
- cluster = BasicInformationCluster;
1781
- attributes = await interactionClient.getMultipleAttributes({
1782
- attributes: [{ clusterId: cluster.id }],
1783
- });
1784
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1785
- attributes.forEach((attribute) => {
1786
- this.log.info(
1787
- `- 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}`,
1788
- );
1789
- });
1790
-
1791
- // Log PowerSourceCluster
1792
- cluster = PowerSourceCluster;
1793
- attributes = await interactionClient.getMultipleAttributes({
1794
- attributes: [{ clusterId: cluster.id }],
1795
- });
1796
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1797
- attributes.forEach((attribute) => {
1798
- this.log.info(
1799
- `- 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}`,
1800
- );
1801
- });
1802
-
1803
- // Log ThreadNetworkDiagnostics
1804
- cluster = ThreadNetworkDiagnosticsCluster;
1805
- attributes = await interactionClient.getMultipleAttributes({
1806
- attributes: [{ clusterId: cluster.id }],
1807
- });
1808
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1809
- attributes.forEach((attribute) => {
1810
- this.log.info(
1811
- `- 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}`,
1812
- );
1813
- });
1814
-
1815
- // Log SwitchCluster
1816
- cluster = SwitchCluster;
1817
- attributes = await interactionClient.getMultipleAttributes({
1818
- attributes: [{ clusterId: cluster.id }],
1819
- });
1820
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1821
- attributes.forEach((attribute) => {
1822
- this.log.info(
1823
- `- 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}`,
1824
- );
1825
- });
1826
-
1827
- this.log.info('Subscribing to all attributes and events');
1828
- await node.subscribeAllAttributesAndEvents({
1829
- ignoreInitialTriggers: false,
1830
- attributeChangedCallback: ({ path: { nodeId, clusterId, endpointId, attributeName }, version, value }) =>
1831
- this.log.info(
1832
- `***${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}`,
1833
- ),
1834
- eventTriggeredCallback: ({ path: { nodeId, clusterId, endpointId, eventName }, events }) => {
1835
- this.log.info(
1836
- `***${db}Commissioning controller eventTriggeredCallback: event ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${eventName}${db} triggered with ${debugStringify(events ?? { none: true })}`,
1837
- );
1838
- },
1839
- });
1840
- this.log.info('Subscribed to all attributes and events');
1841
- }
1842
- */
1843
1303
  }
1844
- /** */
1845
- /** Matter.js methods */
1846
- /** */
1847
- /**
1848
- * Starts the matter storage with name Matterbridge, create the matterbridge context and performs a backup.
1849
- *
1850
- * @returns {Promise<void>} - A promise that resolves when the storage is started.
1851
- */
1852
1304
  async startMatterStorage() {
1853
- // Setup Matter storage
1854
1305
  this.log.info(`Starting matter node storage...`);
1855
1306
  this.matterStorageService = this.environment.get(StorageService);
1856
1307
  this.log.info(`Matter node storage service created: ${this.matterStorageService.location}`);
@@ -1858,17 +1309,8 @@ export class Matterbridge extends EventEmitter {
1858
1309
  this.log.info('Matter node storage manager "Matterbridge" created');
1859
1310
  this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId);
1860
1311
  this.log.info('Matter node storage started');
1861
- // Backup matter storage since it is created/opened correctly
1862
1312
  await this.backupMatterStorage(path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME), path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME + '.backup'));
1863
1313
  }
1864
- /**
1865
- * Makes a backup copy of the specified matter storage directory.
1866
- *
1867
- * @param {string} storageName - The name of the storage directory to be backed up.
1868
- * @param {string} backupName - The name of the backup directory to be created.
1869
- * @private
1870
- * @returns {Promise<void>} A promise that resolves when the has been done.
1871
- */
1872
1314
  async backupMatterStorage(storageName, backupName) {
1873
1315
  this.log.info('Creating matter node storage backup...');
1874
1316
  try {
@@ -1879,11 +1321,6 @@ export class Matterbridge extends EventEmitter {
1879
1321
  this.log.error(`Error creating matter node storage backup from ${storageName} to ${backupName}:`, error);
1880
1322
  }
1881
1323
  }
1882
- /**
1883
- * Stops the matter storage.
1884
- *
1885
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1886
- */
1887
1324
  async stopMatterStorage() {
1888
1325
  this.log.info('Closing matter node storage...');
1889
1326
  await this.matterStorageManager?.close();
@@ -1892,20 +1329,6 @@ export class Matterbridge extends EventEmitter {
1892
1329
  this.matterbridgeContext = undefined;
1893
1330
  this.log.info('Matter node storage closed');
1894
1331
  }
1895
- /**
1896
- * Creates a server node storage context.
1897
- *
1898
- * @param {string} storeId - The storeId.
1899
- * @param {string} deviceName - The name of the device.
1900
- * @param {DeviceTypeId} deviceType - The device type of the device.
1901
- * @param {number} vendorId - The vendor ID.
1902
- * @param {string} vendorName - The vendor name.
1903
- * @param {number} productId - The product ID.
1904
- * @param {string} productName - The product name.
1905
- * @param {string} [serialNumber] - The serial number of the device (optional).
1906
- * @param {string} [uniqueId] - The unique ID of the device (optional).
1907
- * @returns {Promise<StorageContext>} The storage context for the commissioning server.
1908
- */
1909
1332
  async createServerNodeContext(storeId, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber, uniqueId) {
1910
1333
  const { randomBytes } = await import('node:crypto');
1911
1334
  if (!this.matterStorageService)
@@ -1945,15 +1368,6 @@ export class Matterbridge extends EventEmitter {
1945
1368
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
1946
1369
  return storageContext;
1947
1370
  }
1948
- /**
1949
- * Creates a server node.
1950
- *
1951
- * @param {StorageContext} storageContext - The storage context for the server node.
1952
- * @param {number} [port] - The port number for the server node. Defaults to 5540.
1953
- * @param {number} [passcode] - The passcode for the server node. Defaults to 20242025.
1954
- * @param {number} [discriminator] - The discriminator for the server node. Defaults to 3850.
1955
- * @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created server node.
1956
- */
1957
1371
  async createServerNode(storageContext, port = 5540, passcode = 20242025, discriminator = 3850) {
1958
1372
  const storeId = await storageContext.get('storeId');
1959
1373
  this.log.notice(`Creating server node for ${storeId} on port ${port} with passcode ${passcode} and discriminator ${discriminator}...`);
@@ -1963,35 +1377,25 @@ export class Matterbridge extends EventEmitter {
1963
1377
  this.log.debug(`- uniqueId: ${await storageContext.get('uniqueId')}`);
1964
1378
  this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
1965
1379
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
1966
- /**
1967
- * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
1968
- */
1969
1380
  const serverNode = await ServerNode.create({
1970
- // Required: Give the Node a unique ID which is used to store the state of this node
1971
1381
  id: storeId,
1972
- // Environment to run the server node in
1973
1382
  environment: this.environment,
1974
- // Provide Network relevant configuration like the port
1975
1383
  network: {
1976
1384
  listeningAddressIpv4: this.ipv4Address,
1977
1385
  listeningAddressIpv6: this.ipv6Address,
1978
1386
  port,
1979
1387
  },
1980
- // Provide the certificate for the device
1981
1388
  operationalCredentials: {
1982
1389
  certification: this.certification,
1983
1390
  },
1984
- // Provide Commissioning relevant settings
1985
1391
  commissioning: {
1986
1392
  passcode,
1987
1393
  discriminator,
1988
1394
  },
1989
- // Provide Node announcement settings
1990
1395
  productDescription: {
1991
1396
  name: await storageContext.get('deviceName'),
1992
1397
  deviceType: DeviceTypeId(await storageContext.get('deviceType')),
1993
1398
  },
1994
- // Provide defaults for the BasicInformation cluster on the Root endpoint
1995
1399
  basicInformation: {
1996
1400
  vendorId: VendorId(await storageContext.get('vendorId')),
1997
1401
  vendorName: await storageContext.get('vendorName'),
@@ -2008,23 +1412,17 @@ export class Matterbridge extends EventEmitter {
2008
1412
  reachable: true,
2009
1413
  },
2010
1414
  });
2011
- /**
2012
- * This event is triggered when the device is initially commissioned successfully.
2013
- * This means: It is added to the first fabric.
2014
- */
2015
1415
  serverNode.lifecycle.commissioned.on(() => {
2016
1416
  this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`);
2017
1417
  this.advertisingNodes.delete(storeId);
2018
1418
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2019
1419
  });
2020
- /** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
2021
1420
  serverNode.lifecycle.decommissioned.on(() => {
2022
1421
  this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`);
2023
1422
  this.advertisingNodes.delete(storeId);
2024
1423
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2025
1424
  this.frontend.wssSendSnackbarMessage(`${storeId} is offline`, 5, 'warning');
2026
1425
  });
2027
- /** This event is triggered when the device went online. This means that it is discoverable in the network. */
2028
1426
  serverNode.lifecycle.online.on(async () => {
2029
1427
  this.log.notice(`Server node for ${storeId} is online`);
2030
1428
  if (!serverNode.lifecycle.isCommissioned) {
@@ -2035,16 +1433,13 @@ export class Matterbridge extends EventEmitter {
2035
1433
  this.log.notice(`Manual pairing code: ${manualPairingCode}`);
2036
1434
  }
2037
1435
  else {
2038
- // istanbul ignore next
2039
1436
  this.log.notice(`Server node for ${storeId} is already commissioned. Waiting for controllers to connect ...`);
2040
- // istanbul ignore next
2041
1437
  this.advertisingNodes.delete(storeId);
2042
1438
  }
2043
1439
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2044
1440
  this.frontend.wssSendSnackbarMessage(`${storeId} is online`, 5, 'success');
2045
1441
  this.emit('online', storeId);
2046
1442
  });
2047
- /** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
2048
1443
  serverNode.lifecycle.offline.on(() => {
2049
1444
  this.log.notice(`Server node for ${storeId} is offline`);
2050
1445
  this.advertisingNodes.delete(storeId);
@@ -2052,15 +1447,11 @@ export class Matterbridge extends EventEmitter {
2052
1447
  this.frontend.wssSendSnackbarMessage(`${storeId} is offline`, 5, 'warning');
2053
1448
  this.emit('offline', storeId);
2054
1449
  });
2055
- /**
2056
- * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
2057
- * information is needed.
2058
- */
2059
1450
  serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
2060
1451
  let action = '';
2061
1452
  switch (fabricAction) {
2062
1453
  case FabricAction.Added:
2063
- this.advertisingNodes.delete(storeId); // The advertising stops when a fabric is added
1454
+ this.advertisingNodes.delete(storeId);
2064
1455
  action = 'added';
2065
1456
  break;
2066
1457
  case FabricAction.Removed:
@@ -2073,22 +1464,14 @@ export class Matterbridge extends EventEmitter {
2073
1464
  this.log.notice(`Commissioned fabric index ${fabricIndex} ${action} on server node for ${storeId}: ${debugStringify(serverNode.state.commissioning.fabrics[fabricIndex])}`);
2074
1465
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2075
1466
  });
2076
- /**
2077
- * This event is triggered when an operative new session was opened by a Controller.
2078
- * It is not triggered for the initial commissioning process, just afterwards for real connections.
2079
- */
2080
1467
  serverNode.events.sessions.opened.on((session) => {
2081
1468
  this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
2082
1469
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2083
1470
  });
2084
- /**
2085
- * This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
2086
- */
2087
1471
  serverNode.events.sessions.closed.on((session) => {
2088
1472
  this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
2089
1473
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2090
1474
  });
2091
- /** This event is triggered when a subscription gets added or removed on an operative session. */
2092
1475
  serverNode.events.sessions.subscriptionsChanged.on((session) => {
2093
1476
  this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
2094
1477
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
@@ -2096,12 +1479,6 @@ export class Matterbridge extends EventEmitter {
2096
1479
  this.log.info(`Created server node for ${storeId}`);
2097
1480
  return serverNode;
2098
1481
  }
2099
- /**
2100
- * Gets the matter sanitized data of the specified server node.
2101
- *
2102
- * @param {ServerNode} [serverNode] - The server node to start.
2103
- * @returns {ApiMatter} The sanitized data of the server node.
2104
- */
2105
1482
  getServerNodeData(serverNode) {
2106
1483
  const advertiseTime = this.advertisingNodes.get(serverNode.id) || 0;
2107
1484
  return {
@@ -2118,25 +1495,12 @@ export class Matterbridge extends EventEmitter {
2118
1495
  serialNumber: serverNode.state.basicInformation.serialNumber,
2119
1496
  };
2120
1497
  }
2121
- /**
2122
- * Starts the specified server node.
2123
- *
2124
- * @param {ServerNode} [matterServerNode] - The server node to start.
2125
- * @returns {Promise<void>} A promise that resolves when the server node has started.
2126
- */
2127
1498
  async startServerNode(matterServerNode) {
2128
1499
  if (!matterServerNode)
2129
1500
  return;
2130
1501
  this.log.notice(`Starting ${matterServerNode.id} server node`);
2131
1502
  await matterServerNode.start();
2132
1503
  }
2133
- /**
2134
- * Stops the specified server node.
2135
- *
2136
- * @param {ServerNode} matterServerNode - The server node to stop.
2137
- * @param {number} [timeout] - The timeout in milliseconds for stopping the server node. Defaults to 30 seconds.
2138
- * @returns {Promise<void>} A promise that resolves when the server node has stopped.
2139
- */
2140
1504
  async stopServerNode(matterServerNode, timeout = 30000) {
2141
1505
  if (!matterServerNode)
2142
1506
  return;
@@ -2149,25 +1513,12 @@ export class Matterbridge extends EventEmitter {
2149
1513
  this.log.error(`Failed to close ${matterServerNode.id} server node: ${error instanceof Error ? error.message : error}`);
2150
1514
  }
2151
1515
  }
2152
- /**
2153
- * Creates an aggregator node with the specified storage context.
2154
- *
2155
- * @param {StorageContext} storageContext - The storage context for the aggregator node.
2156
- * @returns {Promise<Endpoint<AggregatorEndpoint>>} A promise that resolves to the created aggregator node.
2157
- */
2158
1516
  async createAggregatorNode(storageContext) {
2159
1517
  this.log.notice(`Creating ${await storageContext.get('storeId')} aggregator...`);
2160
1518
  const aggregatorNode = new Endpoint(AggregatorEndpoint, { id: `${await storageContext.get('storeId')}` });
2161
1519
  this.log.info(`Created ${await storageContext.get('storeId')} aggregator`);
2162
1520
  return aggregatorNode;
2163
1521
  }
2164
- /**
2165
- * Creates and configures the server node for an accessory plugin for a given device.
2166
- *
2167
- * @param {Plugin} plugin - The plugin to configure.
2168
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
2169
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
2170
- */
2171
1522
  async createAccessoryPlugin(plugin, device) {
2172
1523
  if (!plugin.locked && device.deviceType && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
2173
1524
  plugin.locked = true;
@@ -2179,12 +1530,6 @@ export class Matterbridge extends EventEmitter {
2179
1530
  await plugin.serverNode.add(device);
2180
1531
  }
2181
1532
  }
2182
- /**
2183
- * Creates and configures the server node and the aggregator node for a dynamic plugin.
2184
- *
2185
- * @param {Plugin} plugin - The plugin to configure.
2186
- * @returns {Promise<void>} A promise that resolves when the server node and the aggregator node for the dynamic plugin is created and configured.
2187
- */
2188
1533
  async createDynamicPlugin(plugin) {
2189
1534
  if (!plugin.locked) {
2190
1535
  plugin.locked = true;
@@ -2197,13 +1542,6 @@ export class Matterbridge extends EventEmitter {
2197
1542
  await plugin.serverNode.add(plugin.aggregatorNode);
2198
1543
  }
2199
1544
  }
2200
- /**
2201
- * Creates and configures the server node for a single not bridged device.
2202
- *
2203
- * @param {Plugin} plugin - The plugin to configure.
2204
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
2205
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
2206
- */
2207
1545
  async createDeviceServerNode(plugin, device) {
2208
1546
  if (device.mode === 'server' && !device.serverNode && device.deviceType && device.deviceName && device.vendorId && device.vendorName && device.productId && device.productName) {
2209
1547
  this.log.debug(`Creating device ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} server node...`);
@@ -2214,15 +1552,7 @@ export class Matterbridge extends EventEmitter {
2214
1552
  this.log.debug(`Added ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to server node`);
2215
1553
  }
2216
1554
  }
2217
- /**
2218
- * Adds a MatterbridgeEndpoint to the specified plugin.
2219
- *
2220
- * @param {string} pluginName - The name of the plugin.
2221
- * @param {MatterbridgeEndpoint} device - The device to add as a bridged endpoint.
2222
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been added.
2223
- */
2224
1555
  async addBridgedEndpoint(pluginName, device) {
2225
- // Check if the plugin is registered
2226
1556
  const plugin = this.plugins.get(pluginName);
2227
1557
  if (!plugin) {
2228
1558
  this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
@@ -2242,7 +1572,6 @@ export class Matterbridge extends EventEmitter {
2242
1572
  }
2243
1573
  else if (this.bridgeMode === 'bridge') {
2244
1574
  if (device.mode === 'matter') {
2245
- // Register and add the device to the matterbridge server node
2246
1575
  this.log.debug(`Adding matter endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge server node...`);
2247
1576
  if (!this.serverNode) {
2248
1577
  this.log.error('Server node not found for Matterbridge');
@@ -2259,7 +1588,6 @@ export class Matterbridge extends EventEmitter {
2259
1588
  }
2260
1589
  }
2261
1590
  else {
2262
- // Register and add the device to the matterbridge aggregator node
2263
1591
  this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
2264
1592
  if (!this.aggregatorNode) {
2265
1593
  this.log.error('Aggregator node not found for Matterbridge');
@@ -2277,7 +1605,6 @@ export class Matterbridge extends EventEmitter {
2277
1605
  }
2278
1606
  }
2279
1607
  else if (this.bridgeMode === 'childbridge') {
2280
- // Register and add the device to the plugin server node
2281
1608
  if (plugin.type === 'AccessoryPlatform') {
2282
1609
  try {
2283
1610
  this.log.debug(`Creating endpoint ${dev}${device.deviceName}${db} for AccessoryPlatform plugin ${plg}${plugin.name}${db} server node`);
@@ -2301,12 +1628,10 @@ export class Matterbridge extends EventEmitter {
2301
1628
  return;
2302
1629
  }
2303
1630
  }
2304
- // Register and add the device to the plugin aggregator node
2305
1631
  if (plugin.type === 'DynamicPlatform') {
2306
1632
  try {
2307
1633
  this.log.debug(`Adding bridged endpoint ${dev}${device.deviceName}${db} for DynamicPlatform plugin ${plg}${plugin.name}${db} aggregator node`);
2308
1634
  await this.createDynamicPlugin(plugin);
2309
- // Fast plugins can add another device before the server node is ready, so we wait for the server node to be ready
2310
1635
  await waiter(`createDynamicPlugin(${plugin.name})`, () => plugin.serverNode?.hasParts === true);
2311
1636
  if (!plugin.aggregatorNode) {
2312
1637
  this.log.error(`Aggregator node not found for plugin ${plg}${plugin.name}${er}`);
@@ -2327,28 +1652,17 @@ export class Matterbridge extends EventEmitter {
2327
1652
  }
2328
1653
  if (plugin.registeredDevices !== undefined)
2329
1654
  plugin.registeredDevices++;
2330
- // Add the device to the DeviceManager
2331
1655
  this.devices.set(device);
2332
- // Subscribe to the attributes changed event
2333
1656
  await this.subscribeAttributeChanged(plugin, device);
2334
1657
  this.log.info(`Added and registered bridged endpoint (${plugin.registeredDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) for plugin ${plg}${pluginName}${nf}`);
2335
1658
  }
2336
- /**
2337
- * Removes a MatterbridgeEndpoint from the specified plugin.
2338
- *
2339
- * @param {string} pluginName - The name of the plugin.
2340
- * @param {MatterbridgeEndpoint} device - The device to remove as a bridged endpoint.
2341
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been removed.
2342
- */
2343
1659
  async removeBridgedEndpoint(pluginName, device) {
2344
1660
  this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
2345
- // Check if the plugin is registered
2346
1661
  const plugin = this.plugins.get(pluginName);
2347
1662
  if (!plugin) {
2348
1663
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
2349
1664
  return;
2350
1665
  }
2351
- // Unregister and remove the device from the matterbridge aggregator node
2352
1666
  if (this.bridgeMode === 'bridge') {
2353
1667
  if (!this.aggregatorNode) {
2354
1668
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator node not found`);
@@ -2361,10 +1675,8 @@ export class Matterbridge extends EventEmitter {
2361
1675
  }
2362
1676
  else if (this.bridgeMode === 'childbridge') {
2363
1677
  if (plugin.type === 'AccessoryPlatform') {
2364
- // Nothing to do here since the server node has no aggregator node but only the device itself
2365
1678
  }
2366
1679
  else if (plugin.type === 'DynamicPlatform') {
2367
- // Unregister and remove the device from the plugin aggregator node
2368
1680
  if (!plugin.aggregatorNode) {
2369
1681
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator node not found`);
2370
1682
  return;
@@ -2375,21 +1687,8 @@ export class Matterbridge extends EventEmitter {
2375
1687
  if (plugin.registeredDevices !== undefined)
2376
1688
  plugin.registeredDevices--;
2377
1689
  }
2378
- // Remove the device from the DeviceManager
2379
1690
  this.devices.remove(device);
2380
1691
  }
2381
- /**
2382
- * Removes all bridged endpoints from the specified plugin.
2383
- *
2384
- * @param {string} pluginName - The name of the plugin.
2385
- * @param {number} [delay] - The delay in milliseconds between removing each bridged endpoint (default: 0).
2386
- * @returns {Promise<void>} A promise that resolves when all bridged endpoints have been removed.
2387
- *
2388
- * @remarks
2389
- * This method iterates through all devices in the DeviceManager and removes each bridged endpoint associated with the specified plugin.
2390
- * It also applies a delay between each removal if specified.
2391
- * The delay is useful to allow the controllers to receive a single subscription for each device removed.
2392
- */
2393
1692
  async removeAllBridgedEndpoints(pluginName, delay = 0) {
2394
1693
  this.log.debug(`Removing all bridged endpoints for plugin ${plg}${pluginName}${db}${delay > 0 ? ` with delay ${delay} ms` : ''}`);
2395
1694
  for (const device of this.devices.array().filter((device) => device.plugin === pluginName)) {
@@ -2400,28 +1699,8 @@ export class Matterbridge extends EventEmitter {
2400
1699
  if (delay > 0)
2401
1700
  await wait(2000);
2402
1701
  }
2403
- /**
2404
- * Registers a virtual device.
2405
- * Virtual devices are only supported in bridge mode and childbridge mode with a DynamicPlatform.
2406
- *
2407
- * The virtual device is created as an instance of `Endpoint` with the provided device type.
2408
- * When the virtual device is turned on, the provided callback function is executed.
2409
- * The onOff state of the virtual device always reverts to false when the device is turned on.
2410
- *
2411
- * @param { string } pluginName - The name of the plugin to register the virtual device under.
2412
- * @param { string } name - The name of the virtual device.
2413
- * @param { 'light' | 'outlet' | 'switch' | 'mounted_switch' } type - The type of the virtual device.
2414
- * @param { () => Promise<void> } callback - The callback to call when the virtual device is turned on.
2415
- *
2416
- * @returns {Promise<boolean>} A promise that resolves to true if the virtual device was successfully registered, false otherwise.
2417
- *
2418
- * @remarks
2419
- * The virtual devices don't show up in the device list of the frontend.
2420
- * Type 'switch' is not supported by Alexa and 'mounted_switch' is not supported by Apple Home.
2421
- */
2422
1702
  async addVirtualEndpoint(pluginName, name, type, callback) {
2423
1703
  this.log.debug(`Adding virtual endpoint ${plg}${pluginName}${db}:${dev}${name}${db}...`);
2424
- // Check if the plugin is registered
2425
1704
  const plugin = this.plugins.get(pluginName);
2426
1705
  if (!plugin) {
2427
1706
  this.log.error(`Error adding virtual endpoint ${dev}${name}${er} for plugin ${plg}${pluginName}${er}: plugin not found`);
@@ -2448,24 +1727,13 @@ export class Matterbridge extends EventEmitter {
2448
1727
  this.log.error(`Virtual endpoint ${dev}${name}${er} for plugin ${plg}${pluginName}${er} not created. Virtual endpoints are only supported in bridge mode and childbridge mode with a DynamicPlatform.`);
2449
1728
  return false;
2450
1729
  }
2451
- /**
2452
- * Subscribes to the attribute change event for the given device and plugin.
2453
- * Specifically, it listens for changes in the 'reachable' attribute of the
2454
- * BridgedDeviceBasicInformationServer cluster server of the bridged device or BasicInformationServer cluster server of server node.
2455
- *
2456
- * @param {Plugin} plugin - The plugin associated with the device.
2457
- * @param {MatterbridgeEndpoint} device - The device to subscribe to attribute changes for.
2458
- * @returns {Promise<void>} A promise that resolves when the subscription is set up.
2459
- */
2460
1730
  async subscribeAttributeChanged(plugin, device) {
2461
1731
  if (!plugin || !device || !device.plugin || !device.serialNumber || !device.uniqueId || !device.maybeNumber)
2462
1732
  return;
2463
1733
  this.log.info(`Subscribing attributes for endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) plugin ${plg}${plugin.name}${nf}`);
2464
- // Subscribe to the reachable$Changed event of the BasicInformationServer cluster server of the server node in childbridge mode
2465
1734
  if (this.bridgeMode === 'childbridge' && plugin.type === 'AccessoryPlatform' && plugin.serverNode) {
2466
1735
  plugin.serverNode.eventsOf(BasicInformationServer).reachable$Changed?.on((reachable) => {
2467
1736
  this.log.info(`Accessory endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) is ${reachable ? 'reachable' : 'unreachable'}`);
2468
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2469
1737
  this.frontend.wssSendAttributeChangedMessage(device.plugin, device.serialNumber, device.uniqueId, device.number, device.id, 'BasicInformation', 'reachable', reachable);
2470
1738
  });
2471
1739
  }
@@ -2515,7 +1783,6 @@ export class Matterbridge extends EventEmitter {
2515
1783
  this.log.debug(`Subscribing to endpoint ${or}${device.id}${db}:${or}${device.number}${db} attribute ${dev}${sub.cluster}${db}.${dev}${sub.attribute}${db} changes...`);
2516
1784
  await device.subscribeAttribute(sub.cluster, sub.attribute, (value) => {
2517
1785
  this.log.debug(`Bridged endpoint ${or}${device.id}${db}:${or}${device.number}${db} attribute ${dev}${sub.cluster}${db}.${dev}${sub.attribute}${db} changed to ${CYAN}${isValidObject(value) ? debugStringify(value) : value}${db}`);
2518
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2519
1786
  this.frontend.wssSendAttributeChangedMessage(device.plugin, device.serialNumber, device.uniqueId, device.number, device.id, sub.cluster, sub.attribute, value);
2520
1787
  });
2521
1788
  }
@@ -2524,19 +1791,12 @@ export class Matterbridge extends EventEmitter {
2524
1791
  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...`);
2525
1792
  await child.subscribeAttribute(sub.cluster, sub.attribute, (value) => {
2526
1793
  this.log.debug(`Bridged child endpoint ${or}${child.id}${db}:${or}${child.number}${db} attribute ${dev}${sub.cluster}${db}.${dev}${sub.attribute}${db} changed to ${CYAN}${isValidObject(value) ? debugStringify(value) : value}${db}`);
2527
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2528
1794
  this.frontend.wssSendAttributeChangedMessage(device.plugin, device.serialNumber, device.uniqueId, child.number, child.id, sub.cluster, sub.attribute, value);
2529
1795
  });
2530
1796
  }
2531
1797
  }
2532
1798
  }
2533
1799
  }
2534
- /**
2535
- * Sanitizes the fabric information by converting bigint properties to strings because `res.json` doesn't support bigint.
2536
- *
2537
- * @param {ExposedFabricInformation[]} fabricInfo - The array of exposed fabric information objects.
2538
- * @returns {SanitizedExposedFabricInformation[]} An array of sanitized exposed fabric information objects.
2539
- */
2540
1800
  sanitizeFabricInformations(fabricInfo) {
2541
1801
  return fabricInfo.map((info) => {
2542
1802
  return {
@@ -2550,12 +1810,6 @@ export class Matterbridge extends EventEmitter {
2550
1810
  };
2551
1811
  });
2552
1812
  }
2553
- /**
2554
- * Sanitizes the session information by converting bigint properties to strings because `res.json` doesn't support bigint.
2555
- *
2556
- * @param {SessionsBehavior.Session[]} sessions - The array of session information objects.
2557
- * @returns {SanitizedSession[]} An array of sanitized session information objects.
2558
- */
2559
1813
  sanitizeSessionInformation(sessions) {
2560
1814
  return sessions
2561
1815
  .filter((session) => session.isPeerActive)
@@ -2582,21 +1836,7 @@ export class Matterbridge extends EventEmitter {
2582
1836
  };
2583
1837
  });
2584
1838
  }
2585
- /**
2586
- * Sets the reachability of the specified aggregator node bridged devices and trigger.
2587
- *
2588
- * @param {Endpoint<AggregatorEndpoint>} aggregatorNode - The aggregator node to set the reachability for.
2589
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2590
- */
2591
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2592
1839
  async setAggregatorReachability(aggregatorNode, reachable) {
2593
- /*
2594
- for (const child of aggregatorNode.parts) {
2595
- this.log.debug(`Setting reachability of ${(child as unknown as MatterbridgeEndpoint)?.deviceName} to ${reachable}`);
2596
- await child.setStateOf(BridgedDeviceBasicInformationServer, { reachable });
2597
- child.act((agent) => child.eventsOf(BridgedDeviceBasicInformationServer).reachableChanged.emit({ reachableNewValue: true }, agent.context));
2598
- }
2599
- */
2600
1840
  }
2601
1841
  getVendorIdName = (vendorId) => {
2602
1842
  if (!vendorId)
@@ -2636,11 +1876,10 @@ export class Matterbridge extends EventEmitter {
2636
1876
  case 0x1488:
2637
1877
  vendorName = '(ShortcutLabsFlic)';
2638
1878
  break;
2639
- case 65521: // 0xFFF1
1879
+ case 65521:
2640
1880
  vendorName = '(MatterTest)';
2641
1881
  break;
2642
1882
  }
2643
1883
  return vendorName;
2644
1884
  };
2645
1885
  }
2646
- //# sourceMappingURL=matterbridge.js.map