matterbridge 3.4.3 → 3.4.4-dev-20251215-216dfc3

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 +22 -0
  2. package/dist/broadcastServer.js +0 -119
  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 +14 -371
  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 -811
  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 +54 -1445
  54. package/dist/matterbridgeEndpointHelpers.js +20 -483
  55. package/dist/matterbridgeEndpointTypes.js +0 -25
  56. package/dist/matterbridgePlatform.js +1 -451
  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_node_modules.js +1 -1
  84. package/frontend/package.json +1 -1
  85. package/npm-shrinkwrap.json +5 -5
  86. package/package.json +1 -2
  87. package/dist/broadcastServer.d.ts +0 -144
  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 -345
  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 -492
  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 -539
  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';
@@ -56,27 +27,19 @@ import { bridge } from './matterbridgeDeviceTypes.js';
56
27
  import { Frontend } from './frontend.js';
57
28
  import { addVirtualDevice, addVirtualDevices } from './helpers.js';
58
29
  import { BroadcastServer } from './broadcastServer.js';
59
- /**
60
- * Represents the Matterbridge application.
61
- */
62
30
  export class Matterbridge extends EventEmitter {
63
- /** Matterbridge system information */
64
31
  systemInformation = {
65
- // Network properties
66
32
  interfaceName: '',
67
33
  macAddress: '',
68
34
  ipv4Address: '',
69
35
  ipv6Address: '',
70
- // Node.js properties
71
36
  nodeVersion: '',
72
- // Fixed system properties
73
37
  hostname: '',
74
38
  user: '',
75
39
  osType: '',
76
40
  osRelease: '',
77
41
  osPlatform: '',
78
42
  osArch: '',
79
- // Cpu and memory properties
80
43
  totalMemory: '',
81
44
  freeMemory: '',
82
45
  systemUptime: '',
@@ -87,7 +50,6 @@ export class Matterbridge extends EventEmitter {
87
50
  heapTotal: '',
88
51
  heapUsed: '',
89
52
  };
90
- // Matterbridge settings
91
53
  homeDirectory = '';
92
54
  rootDirectory = '';
93
55
  matterbridgeDirectory = '';
@@ -102,19 +64,12 @@ export class Matterbridge extends EventEmitter {
102
64
  restartMode = '';
103
65
  virtualMode = 'outlet';
104
66
  profile = getParameter('profile');
105
- /** Matterbridge logger */
106
- log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
107
- /** Matterbridge logger level */
67
+ log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
108
68
  logLevel = this.log.logLevel;
109
- /** Whether to log to a file */
110
69
  fileLogger = false;
111
- /** Matter logger */
112
- matterLog = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
113
- /** Matter logger level */
70
+ matterLog = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
114
71
  matterLogLevel = this.matterLog.logLevel;
115
- /** Whether to log Matter to a file */
116
72
  matterFileLogger = false;
117
- // Frontend settings
118
73
  readOnly = hasParameter('readonly') || hasParameter('shelly');
119
74
  shellyBoard = hasParameter('shelly');
120
75
  shellySysUpdate = false;
@@ -122,18 +77,12 @@ export class Matterbridge extends EventEmitter {
122
77
  restartRequired = false;
123
78
  fixedRestartRequired = false;
124
79
  updateRequired = false;
125
- // Managers
126
80
  plugins = new PluginManager(this);
127
81
  devices = new DeviceManager();
128
- // Frontend
129
82
  frontend = new Frontend(this);
130
- /** Matterbridge node storage manager created in the directory 'storage' in matterbridgeDirectory */
131
83
  nodeStorage;
132
- /** Matterbridge node context created with name 'matterbridge' */
133
84
  nodeContext;
134
- /** The main instance of the Matterbridge class (singleton) */
135
85
  static instance;
136
- // Instance properties
137
86
  shutdown = false;
138
87
  failCountLimit = hasParameter('shelly') ? 600 : 120;
139
88
  hasCleanupStarted = false;
@@ -148,32 +97,19 @@ export class Matterbridge extends EventEmitter {
148
97
  sigtermHandler;
149
98
  exceptionHandler;
150
99
  rejectionHandler;
151
- /** Matter environment default */
152
100
  environment = Environment.default;
153
- /** Matter storage service from environment default */
154
101
  matterStorageService;
155
- /** Matter storage manager created with name 'Matterbridge' */
156
102
  matterStorageManager;
157
- /** Matter matterbridge storage context created in the storage manager with name 'persist' */
158
103
  matterbridgeContext;
159
104
  controllerContext;
160
- /** Matter mdns interface e.g. 'eth0' or 'wlan0' or 'Wi-Fi' */
161
105
  mdnsInterface;
162
- /** Matter listeningAddressIpv4 address */
163
106
  ipv4Address;
164
- /** Matter listeningAddressIpv6 address */
165
107
  ipv6Address;
166
- /** Matter commissioning port */
167
- port; // first server node port
168
- /** Matter commissioning passcode */
169
- passcode; // first server node passcode
170
- /** Matter commissioning discriminator */
171
- discriminator; // first server node discriminator
172
- /** Matter device certification */
173
- certification; // device certification
174
- /** Matter server node in bridge mode */
108
+ port;
109
+ passcode;
110
+ discriminator;
111
+ certification;
175
112
  serverNode;
176
- /** Matter aggregator node in bridge mode */
177
113
  aggregatorNode;
178
114
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
179
115
  aggregatorVendorName = getParameter('vendorName') ?? 'Matterbridge';
@@ -182,12 +118,9 @@ export class Matterbridge extends EventEmitter {
182
118
  aggregatorDeviceType = DeviceTypeId(getIntParameter('deviceType') ?? bridge.code);
183
119
  aggregatorSerialNumber = getParameter('serialNumber');
184
120
  aggregatorUniqueId = getParameter('uniqueId');
185
- /** Advertising nodes map: time advertising started keyed by storeId */
186
121
  advertisingNodes = new Map();
187
- /** Broadcast server */
188
122
  server;
189
123
  verbose = hasParameter('verbose');
190
- /** We load asyncronously so is private */
191
124
  constructor() {
192
125
  super();
193
126
  this.log.logNameColor = '\x1b[38;5;115m';
@@ -238,19 +171,8 @@ export class Matterbridge extends EventEmitter {
238
171
  }
239
172
  }
240
173
  }
241
- //* ************************************************************************************************************************************ */
242
- // loadInstance() and cleanup() methods */
243
- //* ************************************************************************************************************************************ */
244
- /**
245
- * Loads an instance of the Matterbridge class.
246
- * If an instance already exists, return that instance.
247
- *
248
- * @param {boolean} initialize - Whether to initialize the Matterbridge instance after loading. Defaults to false.
249
- * @returns {Matterbridge} A promise that resolves to the Matterbridge instance.
250
- */
251
174
  static async loadInstance(initialize = false) {
252
175
  if (!Matterbridge.instance) {
253
- // eslint-disable-next-line no-console
254
176
  if (hasParameter('debug'))
255
177
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
256
178
  Matterbridge.instance = new Matterbridge();
@@ -259,84 +181,56 @@ export class Matterbridge extends EventEmitter {
259
181
  }
260
182
  return Matterbridge.instance;
261
183
  }
262
- /**
263
- * Initializes the Matterbridge application.
264
- *
265
- * @remarks
266
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
267
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
268
- * node version, registers signal handlers, initializes storage, and parses the command line.
269
- *
270
- * @returns {Promise<void>} A Promise that resolves when the initialization is complete.
271
- */
272
184
  async initialize() {
273
- // for (let i = 1; i <= 255; i++) console.log(`\x1b[38;5;${i}mColor: ${i}`);
274
- // Emit the initialize_started event
275
185
  this.emit('initialize_started');
276
- // Set the restart mode
277
186
  if (hasParameter('service'))
278
187
  this.restartMode = 'service';
279
188
  if (hasParameter('docker'))
280
189
  this.restartMode = 'docker';
281
- // Set the matterbridge home directory
282
190
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
283
191
  await createDirectory(this.homeDirectory, 'Matterbridge Home Directory', this.log);
284
- // Set the matterbridge directory
285
192
  this.matterbridgeDirectory = this.profile ? path.join(this.homeDirectory, '.matterbridge', 'profiles', this.profile) : path.join(this.homeDirectory, '.matterbridge');
286
193
  await createDirectory(this.matterbridgeDirectory, 'Matterbridge Directory', this.log);
287
194
  await createDirectory(path.join(this.matterbridgeDirectory, 'certs'), 'Matterbridge Frontend Certificate Directory', this.log);
288
195
  await createDirectory(path.join(this.matterbridgeDirectory, 'uploads'), 'Matterbridge Frontend Uploads Directory', this.log);
289
- // Set the matterbridge plugin directory
290
196
  this.matterbridgePluginDirectory = this.profile ? path.join(this.homeDirectory, 'Matterbridge', 'profiles', this.profile) : path.join(this.homeDirectory, 'Matterbridge');
291
197
  await createDirectory(this.matterbridgePluginDirectory, 'Matterbridge Plugin Directory', this.log);
292
- // Set the matterbridge cert directory
293
198
  this.matterbridgeCertDirectory = this.profile ? path.join(this.homeDirectory, '.mattercert', 'profiles', this.profile) : path.join(this.homeDirectory, '.mattercert');
294
199
  await createDirectory(this.matterbridgeCertDirectory, 'Matterbridge Matter Certificate Directory', this.log);
295
- // Set the matterbridge root directory
296
200
  const { fileURLToPath } = await import('node:url');
297
201
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
298
- this.rootDirectory = path.resolve(currentFileDirectory, '../'); // Adjust the path for dist directory
299
- // Setup the matter environment with default values
202
+ this.rootDirectory = path.resolve(currentFileDirectory, '../');
300
203
  this.environment.vars.set('log.level', MatterLogLevel.INFO);
301
204
  this.environment.vars.set('log.format', MatterLogFormat.ANSI);
302
205
  this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME));
303
206
  this.environment.vars.set('runtime.signals', false);
304
207
  this.environment.vars.set('runtime.exitcode', false);
305
- // Register process handlers
306
208
  this.registerProcessHandlers();
307
- // Initialize nodeStorage and nodeContext
308
209
  try {
309
210
  this.log.debug(`Creating node storage manager: ${CYAN}${NODE_STORAGE_DIR}${db}`);
310
211
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, NODE_STORAGE_DIR), writeQueue: false, expiredInterval: undefined, logging: false });
311
212
  this.log.debug('Creating node storage context for matterbridge');
312
213
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
313
- // TODO: Remove this code when node-persist-manager is updated
314
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
315
214
  const keys = (await this.nodeStorage?.storage.keys());
316
215
  for (const key of keys) {
317
216
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
318
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
319
217
  await this.nodeStorage?.storage.get(key);
320
218
  }
321
219
  const storages = await this.nodeStorage.getStorageNames();
322
220
  for (const storage of storages) {
323
221
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
324
222
  const nodeContext = await this.nodeStorage?.createStorage(storage);
325
- // TODO: Remove this code when node-persist-manager is updated
326
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
327
223
  const keys = (await nodeContext?.storage.keys());
328
224
  keys.forEach(async (key) => {
329
225
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
330
226
  await nodeContext?.get(key);
331
227
  });
332
228
  }
333
- // Creating a backup of the node storage since it is not corrupted
334
229
  this.log.debug('Creating node storage backup...');
335
230
  await copyDirectory(path.join(this.matterbridgeDirectory, NODE_STORAGE_DIR), path.join(this.matterbridgeDirectory, NODE_STORAGE_DIR + '.backup'));
336
231
  this.log.debug('Created node storage backup');
337
232
  }
338
233
  catch (error) {
339
- // Restoring the backup of the node storage since it is corrupted
340
234
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
341
235
  if (hasParameter('norestore')) {
342
236
  this.log.fatal(`The matterbridge storage is corrupted. Found -norestore parameter: exiting...`);
@@ -350,19 +244,14 @@ export class Matterbridge extends EventEmitter {
350
244
  if (!this.nodeStorage || !this.nodeContext) {
351
245
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
352
246
  }
353
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
354
247
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
355
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
356
248
  this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode')) ?? PaseClient.generateRandomPasscode(this.environment.get(Crypto));
357
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
358
249
  this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator')) ?? PaseClient.generateRandomDiscriminator(this.environment.get(Crypto));
359
- // Certificate management
360
250
  const pairingFilePath = path.join(this.matterbridgeCertDirectory, 'pairing.json');
361
251
  try {
362
252
  await fs.promises.access(pairingFilePath, fs.constants.R_OK);
363
253
  const pairingFileContent = await fs.promises.readFile(pairingFilePath, 'utf8');
364
254
  const pairingFileJson = JSON.parse(pairingFileContent);
365
- // Set the vendorId, vendorName, productId, productName, deviceType, serialNumber, uniqueId if they are present in the pairing file
366
255
  if (isValidNumber(pairingFileJson.vendorId)) {
367
256
  this.aggregatorVendorId = VendorId(pairingFileJson.vendorId);
368
257
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using vendorId ${CYAN}${this.aggregatorVendorId}${nf} from pairing file.`);
@@ -391,13 +280,11 @@ export class Matterbridge extends EventEmitter {
391
280
  this.aggregatorUniqueId = pairingFileJson.uniqueId;
392
281
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using uniqueId ${CYAN}${this.aggregatorUniqueId}${nf} from pairing file.`);
393
282
  }
394
- // Override the passcode and discriminator if they are present in the pairing file
395
283
  if (isValidNumber(pairingFileJson.passcode) && isValidNumber(pairingFileJson.discriminator)) {
396
284
  this.passcode = pairingFileJson.passcode;
397
285
  this.discriminator = pairingFileJson.discriminator;
398
286
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using passcode ${CYAN}${this.passcode}${nf} and discriminator ${CYAN}${this.discriminator}${nf} from pairing file.`);
399
287
  }
400
- // Set the certification for matter.js if it is present in the pairing file
401
288
  if (pairingFileJson.privateKey && pairingFileJson.certificate && pairingFileJson.intermediateCertificate && pairingFileJson.declaration) {
402
289
  const { hexToBuffer } = await import('./utils/hex.js');
403
290
  this.certification = {
@@ -412,44 +299,41 @@ export class Matterbridge extends EventEmitter {
412
299
  catch (error) {
413
300
  this.log.debug(`Pairing file ${CYAN}${pairingFilePath}${db} not found: ${error instanceof Error ? error.message : error}`);
414
301
  }
415
- // Store the passcode, discriminator and port in the node context
416
302
  await this.nodeContext.set('matterport', this.port);
417
303
  await this.nodeContext.set('matterpasscode', this.passcode);
418
304
  await this.nodeContext.set('matterdiscriminator', this.discriminator);
419
305
  this.log.debug(`Initializing server node for Matterbridge on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
420
- // Set matterbridge logger level (context: matterbridgeLogLevel)
421
306
  if (hasParameter('logger')) {
422
307
  const level = getParameter('logger');
423
308
  if (level === 'debug') {
424
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
309
+ this.log.logLevel = "debug";
425
310
  }
426
311
  else if (level === 'info') {
427
- this.log.logLevel = "info" /* LogLevel.INFO */;
312
+ this.log.logLevel = "info";
428
313
  }
429
314
  else if (level === 'notice') {
430
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
315
+ this.log.logLevel = "notice";
431
316
  }
432
317
  else if (level === 'warn') {
433
- this.log.logLevel = "warn" /* LogLevel.WARN */;
318
+ this.log.logLevel = "warn";
434
319
  }
435
320
  else if (level === 'error') {
436
- this.log.logLevel = "error" /* LogLevel.ERROR */;
321
+ this.log.logLevel = "error";
437
322
  }
438
323
  else if (level === 'fatal') {
439
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
324
+ this.log.logLevel = "fatal";
440
325
  }
441
326
  else {
442
327
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
443
- this.log.logLevel = "info" /* LogLevel.INFO */;
328
+ this.log.logLevel = "info";
444
329
  }
445
330
  }
446
331
  else {
447
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.shellyBoard ? "notice" /* LogLevel.NOTICE */ : "info" /* LogLevel.INFO */);
332
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.shellyBoard ? "notice" : "info");
448
333
  }
449
334
  this.logLevel = this.log.logLevel;
450
335
  this.frontend.logLevel = this.log.logLevel;
451
336
  MatterbridgeEndpoint.logLevel = this.log.logLevel;
452
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
453
337
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
454
338
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, MATTERBRIDGE_LOGGER_FILE), this.log.logLevel, true);
455
339
  this.fileLogger = true;
@@ -458,7 +342,6 @@ export class Matterbridge extends EventEmitter {
458
342
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.fileLogger}.`);
459
343
  if (this.profile !== undefined)
460
344
  this.log.debug(`Matterbridge profile: ${this.profile}.`);
461
- // Set matter.js logger level, format and logger (context: matterLogLevel)
462
345
  if (hasParameter('matterlogger')) {
463
346
  const level = getParameter('matterlogger');
464
347
  if (level === 'debug') {
@@ -489,13 +372,11 @@ export class Matterbridge extends EventEmitter {
489
372
  }
490
373
  Logger.format = MatterLogFormat.ANSI;
491
374
  this.matterLogLevel = MatterLogLevel.names[Logger.level];
492
- // Create the logger for matter.js with file logging (context: matterFileLog)
493
375
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
494
376
  this.matterFileLogger = true;
495
377
  }
496
378
  Logger.destinations.default.write = this.createDestinationMatterLogger(this.matterFileLogger);
497
379
  this.log.debug(`Matter logLevel: ${this.matterLogLevel} fileLoger: ${this.matterFileLogger}.`);
498
- // Log network interfaces
499
380
  const networkInterfaces = os.networkInterfaces();
500
381
  const availableAddresses = Object.entries(networkInterfaces);
501
382
  const availableInterfaceNames = Object.keys(networkInterfaces);
@@ -508,7 +389,6 @@ export class Matterbridge extends EventEmitter {
508
389
  });
509
390
  }
510
391
  }
511
- // Set the interface to use for matter server node mdnsInterface
512
392
  if (hasParameter('mdnsinterface')) {
513
393
  this.mdnsInterface = getParameter('mdnsinterface');
514
394
  }
@@ -517,7 +397,6 @@ export class Matterbridge extends EventEmitter {
517
397
  if (this.mdnsInterface === '')
518
398
  this.mdnsInterface = undefined;
519
399
  }
520
- // Validate mdnsInterface
521
400
  if (this.mdnsInterface) {
522
401
  if (!availableInterfaceNames.includes(this.mdnsInterface)) {
523
402
  this.log.error(`Invalid mdnsinterface: ${this.mdnsInterface}. Available interfaces are: ${availableInterfaceNames.join(', ')}. Using all available interfaces.`);
@@ -530,7 +409,6 @@ export class Matterbridge extends EventEmitter {
530
409
  }
531
410
  if (this.mdnsInterface)
532
411
  this.environment.vars.set('mdns.networkInterface', this.mdnsInterface);
533
- // Set the listeningAddressIpv4 for the matter commissioning server
534
412
  if (hasParameter('ipv4address')) {
535
413
  this.ipv4Address = getParameter('ipv4address');
536
414
  }
@@ -539,7 +417,6 @@ export class Matterbridge extends EventEmitter {
539
417
  if (this.ipv4Address === '')
540
418
  this.ipv4Address = undefined;
541
419
  }
542
- // Validate ipv4address
543
420
  if (this.ipv4Address) {
544
421
  let isValid = false;
545
422
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -555,7 +432,6 @@ export class Matterbridge extends EventEmitter {
555
432
  await this.nodeContext.remove('matteripv4address');
556
433
  }
557
434
  }
558
- // Set the listeningAddressIpv6 for the matter commissioning server
559
435
  if (hasParameter('ipv6address')) {
560
436
  this.ipv6Address = getParameter('ipv6address');
561
437
  }
@@ -564,7 +440,6 @@ export class Matterbridge extends EventEmitter {
564
440
  if (this.ipv6Address === '')
565
441
  this.ipv6Address = undefined;
566
442
  }
567
- // Validate ipv6address
568
443
  if (this.ipv6Address) {
569
444
  let isValid = false;
570
445
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -573,7 +448,6 @@ export class Matterbridge extends EventEmitter {
573
448
  isValid = true;
574
449
  break;
575
450
  }
576
- /* istanbul ignore next */
577
451
  if (ifaces && ifaces.find((iface) => iface.scopeid && iface.scopeid > 0 && iface.address + '%' + (process.platform === 'win32' ? iface.scopeid : ifaceName) === this.ipv6Address)) {
578
452
  this.log.info(`Using ipv6address ${CYAN}${this.ipv6Address}${nf} on interface ${CYAN}${ifaceName}${nf} for the Matter server node.`);
579
453
  isValid = true;
@@ -586,7 +460,6 @@ export class Matterbridge extends EventEmitter {
586
460
  await this.nodeContext.remove('matteripv6address');
587
461
  }
588
462
  }
589
- // Initialize the virtual mode
590
463
  if (hasParameter('novirtual')) {
591
464
  this.virtualMode = 'disabled';
592
465
  await this.nodeContext.set('virtualmode', 'disabled');
@@ -595,15 +468,10 @@ export class Matterbridge extends EventEmitter {
595
468
  this.virtualMode = (await this.nodeContext.get('virtualmode', 'outlet'));
596
469
  }
597
470
  this.log.debug(`Virtual mode ${this.virtualMode}.`);
598
- // Initialize PluginManager
599
471
  this.plugins.logLevel = this.log.logLevel;
600
472
  await this.plugins.loadFromStorage();
601
- // Initialize DeviceManager
602
473
  this.devices.logLevel = this.log.logLevel;
603
- // Get the plugins from node storage and create the plugins node storage contexts
604
474
  for (const plugin of this.plugins) {
605
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
606
- // We don't do this when the add and other shutdown parameters are set because we shut down the process after adding the plugin
607
475
  if (!fs.existsSync(plugin.path) && !hasParameter('add') && !hasParameter('remove') && !hasParameter('enable') && !hasParameter('disable') && !hasParameter('reset') && !hasParameter('factoryreset')) {
608
476
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm...`);
609
477
  const { spawnCommand } = await import('./utils/spawn.js');
@@ -633,7 +501,6 @@ export class Matterbridge extends EventEmitter {
633
501
  await plugin.nodeContext.set('description', plugin.description);
634
502
  await plugin.nodeContext.set('author', plugin.author);
635
503
  }
636
- // Log system info and create .matterbridge directory
637
504
  await this.logNodeAndSystemInfo();
638
505
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
639
506
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -641,7 +508,6 @@ export class Matterbridge extends EventEmitter {
641
508
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
642
509
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
643
510
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
644
- // Check node version and throw error
645
511
  const minNodeVersion = 20;
646
512
  const nodeVersion = process.versions.node;
647
513
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -649,18 +515,10 @@ export class Matterbridge extends EventEmitter {
649
515
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
650
516
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
651
517
  }
652
- // Parse command line
653
518
  await this.parseCommandLine();
654
- // Emit the initialize_completed event
655
519
  this.emit('initialize_completed');
656
520
  this.initialized = true;
657
521
  }
658
- /**
659
- * Parses the command line arguments and performs the corresponding actions.
660
- *
661
- * @private
662
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
663
- */
664
522
  async parseCommandLine() {
665
523
  if (hasParameter('list')) {
666
524
  this.log.info(`│ Registered plugins (${this.plugins.length})`);
@@ -676,19 +534,6 @@ export class Matterbridge extends EventEmitter {
676
534
  }
677
535
  index++;
678
536
  }
679
- /*
680
- const serializedRegisteredDevices = await this.nodeContext?.get<SerializedMatterbridgeEndpoint[]>('devices', []);
681
- this.log.info(`│ Registered devices (${serializedRegisteredDevices?.length})`);
682
- serializedRegisteredDevices?.forEach((device, index) => {
683
- if (index !== serializedRegisteredDevices.length - 1) {
684
- this.log.info(`├─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
685
- this.log.info(`│ └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
686
- } else {
687
- this.log.info(`└─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
688
- this.log.info(` └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
689
- }
690
- });
691
- */
692
537
  this.shutdown = true;
693
538
  return;
694
539
  }
@@ -738,10 +583,8 @@ export class Matterbridge extends EventEmitter {
738
583
  this.shutdown = true;
739
584
  return;
740
585
  }
741
- // Initialize frontend
742
586
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
743
587
  await this.frontend.start(getIntParameter('frontend'));
744
- // Start the matter storage and create the matterbridge context
745
588
  try {
746
589
  await this.startMatterStorage();
747
590
  if (this.aggregatorSerialNumber && this.aggregatorUniqueId && this.matterStorageService) {
@@ -755,21 +598,18 @@ export class Matterbridge extends EventEmitter {
755
598
  this.log.fatal(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
756
599
  throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
757
600
  }
758
- // Clear the matterbridge context if the reset parameter is set (bridge mode)
759
601
  if (hasParameter('reset') && getParameter('reset') === undefined) {
760
602
  this.initialized = true;
761
603
  await this.shutdownProcessAndReset();
762
604
  this.shutdown = true;
763
605
  return;
764
606
  }
765
- // Clear matterbridge plugin context if the reset parameter is set (childbridge mode)
766
607
  if (hasParameter('reset') && getParameter('reset') !== undefined) {
767
608
  this.log.debug(`Reset plugin ${getParameter('reset')}`);
768
609
  const plugin = this.plugins.get(getParameter('reset'));
769
610
  if (plugin) {
770
611
  const matterStorageManager = await this.matterStorageService?.open(plugin.name);
771
612
  if (!matterStorageManager) {
772
- /* istanbul ignore next */
773
613
  this.log.error(`Plugin ${plg}${plugin.name}${er} storageManager not found`);
774
614
  }
775
615
  else {
@@ -788,56 +628,47 @@ export class Matterbridge extends EventEmitter {
788
628
  this.shutdown = true;
789
629
  return;
790
630
  }
791
- // Check in 5 minutes the latest and dev versions of matterbridge and the plugins
792
631
  clearTimeout(this.checkUpdateTimeout);
793
632
  this.checkUpdateTimeout = setTimeout(async () => {
794
633
  const { checkUpdates } = await import('./update.js');
795
634
  checkUpdates(this);
796
635
  }, 300 * 1000).unref();
797
- // Check each 12 hours the latest and dev versions of matterbridge and the plugins
798
636
  clearInterval(this.checkUpdateInterval);
799
637
  this.checkUpdateInterval = setInterval(async () => {
800
638
  const { checkUpdates } = await import('./update.js');
801
639
  checkUpdates(this);
802
640
  }, 12 * 60 * 60 * 1000).unref();
803
- // Start the matterbridge in mode test
804
641
  if (hasParameter('test')) {
805
642
  this.bridgeMode = 'bridge';
806
643
  return;
807
644
  }
808
- // Start the matterbridge in mode controller
809
645
  if (hasParameter('controller')) {
810
646
  this.bridgeMode = 'controller';
811
647
  await this.startController();
812
648
  return;
813
649
  }
814
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
815
650
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
816
651
  this.log.info('Setting default matterbridge start mode to bridge');
817
652
  await this.nodeContext?.set('bridgeMode', 'bridge');
818
653
  }
819
- // Wait delay if specified (default 2 minutes) and the system uptime is less than 5 minutes. It solves race conditions on system startup.
820
654
  if (hasParameter('delay') && os.uptime() <= 60 * 5) {
821
655
  const { wait } = await import('./utils/wait.js');
822
656
  const delay = getIntParameter('delay') || 120;
823
657
  this.log.warn('Delay switch found with system uptime less then 5 minutes. Waiting for ' + delay + ' seconds before starting matterbridge...');
824
658
  await wait(delay * 1000, 'Race condition delay', true);
825
659
  }
826
- // Wait delay if specified (default 2 minutes). It solves race conditions on docker compose startup.
827
660
  if (hasParameter('fixed_delay')) {
828
661
  const { wait } = await import('./utils/wait.js');
829
662
  const delay = getIntParameter('fixed_delay') || 120;
830
663
  this.log.warn('Fixed delay switch found. Waiting for ' + delay + ' seconds before starting matterbridge...');
831
664
  await wait(delay * 1000, 'Fixed race condition delay', true);
832
665
  }
833
- // Start matterbridge in bridge mode
834
666
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
835
667
  this.bridgeMode = 'bridge';
836
668
  this.log.debug(`Starting matterbridge in mode ${this.bridgeMode}`);
837
669
  await this.startBridge();
838
670
  return;
839
671
  }
840
- // Start matterbridge in childbridge mode
841
672
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
842
673
  this.bridgeMode = 'childbridge';
843
674
  this.log.debug(`Starting matterbridge in mode ${this.bridgeMode}`);
@@ -845,22 +676,10 @@ export class Matterbridge extends EventEmitter {
845
676
  return;
846
677
  }
847
678
  }
848
- /**
849
- * Asynchronously loads and starts the registered plugins.
850
- *
851
- * This method is responsible for initializing and starting all enabled plugins.
852
- * It ensures that each plugin is properly loaded and started before the bridge starts.
853
- *
854
- * @param {boolean} [wait] - If true, the method will wait for all plugins to be fully loaded and started before resolving. Defaults to false.
855
- * @param {boolean} [start] - If true, the method will start the plugins after loading them. Defaults to true.
856
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
857
- */
858
679
  async startPlugins(wait = false, start = true) {
859
- // Check, load and start the plugins
860
680
  for (const plugin of this.plugins) {
861
681
  plugin.configJson = await this.plugins.loadConfig(plugin);
862
682
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
863
- // Check if the plugin is available
864
683
  if (!(await this.plugins.resolve(plugin.path))) {
865
684
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
866
685
  plugin.enabled = false;
@@ -880,16 +699,10 @@ export class Matterbridge extends EventEmitter {
880
699
  if (wait)
881
700
  await this.plugins.load(plugin, start, 'Matterbridge is starting');
882
701
  else
883
- this.plugins.load(plugin, start, 'Matterbridge is starting'); // No await do it asyncronously
702
+ this.plugins.load(plugin, start, 'Matterbridge is starting');
884
703
  }
885
704
  this.frontend.wssSendRefreshRequired('plugins');
886
705
  }
887
- /**
888
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
889
- * - When an uncaught exception occurs, the exceptionHandler logs the error message and stack trace.
890
- * - When an unhandled promise rejection occurs, the rejectionHandler logs the reason and stack trace.
891
- * - When either of SIGINT and SIGTERM signals are received, the cleanup method is called with an appropriate message.
892
- */
893
706
  registerProcessHandlers() {
894
707
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
895
708
  process.removeAllListeners('uncaughtException');
@@ -916,9 +729,6 @@ export class Matterbridge extends EventEmitter {
916
729
  };
917
730
  process.on('SIGTERM', this.sigtermHandler);
918
731
  }
919
- /**
920
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
921
- */
922
732
  deregisterProcessHandlers() {
923
733
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
924
734
  if (this.exceptionHandler)
@@ -935,18 +745,13 @@ export class Matterbridge extends EventEmitter {
935
745
  process.off('SIGTERM', this.sigtermHandler);
936
746
  this.sigtermHandler = undefined;
937
747
  }
938
- /**
939
- * Logs the node and system information.
940
- */
941
748
  async logNodeAndSystemInfo() {
942
- // IP address information
943
749
  const networkInterfaces = os.networkInterfaces();
944
750
  this.systemInformation.interfaceName = '';
945
751
  this.systemInformation.ipv4Address = '';
946
752
  this.systemInformation.ipv6Address = '';
947
753
  this.systemInformation.macAddress = '';
948
754
  for (const [interfaceName, interfaceDetails] of Object.entries(networkInterfaces)) {
949
- // this.log.debug(`Checking interface: '${interfaceName}' for '${this.mdnsInterface}'`);
950
755
  if (this.mdnsInterface && interfaceName !== this.mdnsInterface)
951
756
  continue;
952
757
  if (!interfaceDetails) {
@@ -972,18 +777,16 @@ export class Matterbridge extends EventEmitter {
972
777
  break;
973
778
  }
974
779
  }
975
- // Node information
976
780
  this.systemInformation.nodeVersion = process.versions.node;
977
781
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
978
782
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
979
783
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
980
- // Host system information
981
784
  this.systemInformation.hostname = os.hostname();
982
785
  this.systemInformation.user = os.userInfo().username;
983
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
984
- this.systemInformation.osRelease = os.release(); // Kernel version
985
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
986
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
786
+ this.systemInformation.osType = os.type();
787
+ this.systemInformation.osRelease = os.release();
788
+ this.systemInformation.osPlatform = os.platform();
789
+ this.systemInformation.osArch = os.arch();
987
790
  this.systemInformation.totalMemory = formatBytes(os.totalmem());
988
791
  this.systemInformation.freeMemory = formatBytes(os.freemem());
989
792
  this.systemInformation.systemUptime = formatUptime(os.uptime());
@@ -993,7 +796,6 @@ export class Matterbridge extends EventEmitter {
993
796
  this.systemInformation.rss = formatBytes(process.memoryUsage().rss);
994
797
  this.systemInformation.heapTotal = formatBytes(process.memoryUsage().heapTotal);
995
798
  this.systemInformation.heapUsed = formatBytes(process.memoryUsage().heapUsed);
996
- // Log the system information
997
799
  this.log.debug('Host System Information:');
998
800
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
999
801
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -1013,17 +815,14 @@ export class Matterbridge extends EventEmitter {
1013
815
  this.log.debug(`- RSS: ${this.systemInformation.rss}`);
1014
816
  this.log.debug(`- Heap Total: ${this.systemInformation.heapTotal}`);
1015
817
  this.log.debug(`- Heap Used: ${this.systemInformation.heapUsed}`);
1016
- // Log directories
1017
818
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
1018
819
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
1019
820
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
1020
821
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
1021
822
  this.log.debug(`Matterbridge Matter Certificate Directory: ${this.matterbridgeCertDirectory}`);
1022
- // Global node_modules directory
1023
823
  if (this.nodeContext)
1024
824
  this.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
1025
825
  if (this.globalModulesDirectory === '') {
1026
- // First run of Matterbridge so the node storage is empty
1027
826
  this.log.debug(`Getting global node_modules directory...`);
1028
827
  try {
1029
828
  const { getGlobalNodeModules } = await import('./utils/network.js');
@@ -1036,42 +835,29 @@ export class Matterbridge extends EventEmitter {
1036
835
  }
1037
836
  }
1038
837
  else {
1039
- // The global node_modules directory is already set in the node storage and we check if it is still valid
1040
838
  this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
1041
839
  const { createESMWorker } = await import('./workers.js');
1042
840
  createESMWorker('NpmGlobalPrefix', path.join(this.rootDirectory, 'dist/workerGlobalPrefix.js'));
1043
841
  }
1044
- // Matterbridge version
1045
842
  this.log.debug(`Reading matterbridge package.json...`);
1046
843
  const packageJson = JSON.parse(await fs.promises.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
1047
844
  this.matterbridgeVersion = this.matterbridgeLatestVersion = this.matterbridgeDevVersion = packageJson.version;
1048
845
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
1049
- // Matterbridge latest version (will be set in the checkUpdate function)
1050
846
  if (this.nodeContext)
1051
847
  this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', this.matterbridgeVersion);
1052
848
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
1053
- // Matterbridge dev version (will be set in the checkUpdate function)
1054
849
  if (this.nodeContext)
1055
850
  this.matterbridgeDevVersion = await this.nodeContext.get('matterbridgeDevVersion', this.matterbridgeVersion);
1056
851
  this.log.debug(`Matterbridge Dev Version: ${this.matterbridgeDevVersion}`);
1057
- // Frontend version
1058
852
  this.log.debug(`Reading frontend package.json...`);
1059
853
  const frontendPackageJson = JSON.parse(await fs.promises.readFile(path.join(this.rootDirectory, 'frontend/package.json'), 'utf8'));
1060
854
  this.frontendVersion = frontendPackageJson.version;
1061
855
  this.log.debug(`Frontend version ${CYAN}${this.frontendVersion}${db}`);
1062
- // Current working directory
1063
856
  const currentDir = process.cwd();
1064
857
  this.log.debug(`Current Working Directory: ${currentDir}`);
1065
- // Command line arguments (excluding 'node' and the script name)
1066
858
  const cmdArgs = process.argv.slice(2).join(' ');
1067
859
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
1068
860
  }
1069
- /**
1070
- * Set the logger logLevel for the Matterbridge classes and call onChangeLoggerLevel() for each plugin.
1071
- *
1072
- * @param {LogLevel} logLevel The logger logLevel to set.
1073
- * @returns {Promise<LogLevel>} A promise that resolves when the logLevel has been set.
1074
- */
1075
861
  async setLogLevel(logLevel) {
1076
862
  this.logLevel = logLevel;
1077
863
  this.log.logLevel = logLevel;
@@ -1082,87 +868,58 @@ export class Matterbridge extends EventEmitter {
1082
868
  for (const plugin of this.plugins) {
1083
869
  if (!plugin.platform || !plugin.platform.log || !plugin.platform.config)
1084
870
  continue;
1085
- plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : logLevel;
1086
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : logLevel);
1087
- }
1088
- // Set the global logger callback for the WebSocketServer to the common minimum logLevel
1089
- let callbackLogLevel = "notice" /* LogLevel.NOTICE */;
1090
- if (logLevel === "info" /* LogLevel.INFO */ || Logger.level === MatterLogLevel.INFO)
1091
- callbackLogLevel = "info" /* LogLevel.INFO */;
1092
- if (logLevel === "debug" /* LogLevel.DEBUG */ || Logger.level === MatterLogLevel.DEBUG)
1093
- callbackLogLevel = "debug" /* LogLevel.DEBUG */;
871
+ plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" : logLevel;
872
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" : logLevel);
873
+ }
874
+ let callbackLogLevel = "notice";
875
+ if (logLevel === "info" || Logger.level === MatterLogLevel.INFO)
876
+ callbackLogLevel = "info";
877
+ if (logLevel === "debug" || Logger.level === MatterLogLevel.DEBUG)
878
+ callbackLogLevel = "debug";
1094
879
  AnsiLogger.setGlobalCallbackLevel(callbackLogLevel);
1095
880
  this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
1096
881
  return logLevel;
1097
882
  }
1098
- /**
1099
- * Get the current logger logLevel.
1100
- *
1101
- * @returns {LogLevel} The current logger logLevel.
1102
- */
1103
883
  getLogLevel() {
1104
884
  return this.log.logLevel;
1105
885
  }
1106
- /**
1107
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
1108
- * It also logs to file (matter.log) if fileLogger is true.
1109
- *
1110
- * @param {boolean} fileLogger - Whether to log to file or not.
1111
- * @returns {Function} The MatterLogger function. \x1b[35m for violet \x1b[34m is blue
1112
- */
1113
886
  createDestinationMatterLogger(fileLogger) {
1114
- this.matterLog.logNameColor = '\x1b[34m'; // Blue matter.js Logger
887
+ this.matterLog.logNameColor = '\x1b[34m';
1115
888
  if (fileLogger) {
1116
889
  this.matterLog.logFilePath = path.join(this.matterbridgeDirectory, MATTER_LOGGER_FILE);
1117
890
  }
1118
891
  return (text, message) => {
1119
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1120
892
  const logger = text.slice(44, 44 + 20).trim();
1121
893
  const msg = text.slice(65);
1122
894
  this.matterLog.logName = logger;
1123
895
  switch (message.level) {
1124
896
  case MatterLogLevel.DEBUG:
1125
- this.matterLog.log("debug" /* LogLevel.DEBUG */, msg);
897
+ this.matterLog.log("debug", msg);
1126
898
  break;
1127
899
  case MatterLogLevel.INFO:
1128
- this.matterLog.log("info" /* LogLevel.INFO */, msg);
900
+ this.matterLog.log("info", msg);
1129
901
  break;
1130
902
  case MatterLogLevel.NOTICE:
1131
- this.matterLog.log("notice" /* LogLevel.NOTICE */, msg);
903
+ this.matterLog.log("notice", msg);
1132
904
  break;
1133
905
  case MatterLogLevel.WARN:
1134
- this.matterLog.log("warn" /* LogLevel.WARN */, msg);
906
+ this.matterLog.log("warn", msg);
1135
907
  break;
1136
908
  case MatterLogLevel.ERROR:
1137
- this.matterLog.log("error" /* LogLevel.ERROR */, msg);
909
+ this.matterLog.log("error", msg);
1138
910
  break;
1139
911
  case MatterLogLevel.FATAL:
1140
- this.matterLog.log("fatal" /* LogLevel.FATAL */, msg);
912
+ this.matterLog.log("fatal", msg);
1141
913
  break;
1142
914
  }
1143
915
  };
1144
916
  }
1145
- /**
1146
- * Restarts the process by exiting the current instance and loading a new instance (/api/restart).
1147
- *
1148
- * @returns {Promise<void>} A promise that resolves when the restart is completed.
1149
- */
1150
917
  async restartProcess() {
1151
918
  await this.cleanup('restarting...', true);
1152
919
  }
1153
- /**
1154
- * Shut down the process (/api/shutdown).
1155
- *
1156
- * @returns {Promise<void>} A promise that resolves when the shutdown is completed.
1157
- */
1158
920
  async shutdownProcess() {
1159
921
  await this.cleanup('shutting down...', false);
1160
922
  }
1161
- /**
1162
- * Update matterbridge and shut down the process (virtual device 'Update Matterbridge').
1163
- *
1164
- * @returns {Promise<void>} A promise that resolves when the update is completed.
1165
- */
1166
923
  async updateProcess() {
1167
924
  this.log.info('Updating matterbridge...');
1168
925
  const { spawnCommand } = await import('./utils/spawn.js');
@@ -1175,13 +932,6 @@ export class Matterbridge extends EventEmitter {
1175
932
  this.frontend.wssSendRestartRequired();
1176
933
  await this.cleanup('updating...', false);
1177
934
  }
1178
- /**
1179
- * Unregister all devices and shut down the process (/api/unregister).
1180
- *
1181
- * @param {number} [timeout] - The timeout duration to wait for the message exchange to complete in milliseconds. Default is 1000.
1182
- *
1183
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1184
- */
1185
935
  async unregisterAndShutdownProcess(timeout = 1000) {
1186
936
  const { wait } = await import('./utils/wait.js');
1187
937
  this.log.info('Unregistering all devices and shutting down...');
@@ -1194,71 +944,46 @@ export class Matterbridge extends EventEmitter {
1194
944
  await this.removeAllBridgedEndpoints(plugin.name, 100);
1195
945
  }
1196
946
  this.log.debug('Waiting for the MessageExchange to finish...');
1197
- await wait(timeout); // Wait for MessageExchange to finish
947
+ await wait(timeout);
1198
948
  this.log.debug('Cleaning up and shutting down...');
1199
949
  await this.cleanup('unregistered all devices and shutting down...', false, timeout);
1200
950
  }
1201
- /**
1202
- * Reset commissioning and shut down the process (/api/reset).
1203
- *
1204
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1205
- */
1206
951
  async shutdownProcessAndReset() {
1207
952
  await this.cleanup('shutting down with reset...', false);
1208
953
  }
1209
- /**
1210
- * Factory reset and shut down the process (/api/factory-reset).
1211
- *
1212
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1213
- */
1214
954
  async shutdownProcessAndFactoryReset() {
1215
955
  await this.cleanup('shutting down with factory reset...', false);
1216
956
  }
1217
- /**
1218
- * Cleans up the Matterbridge instance.
1219
- *
1220
- * @param {string} message - The cleanup message.
1221
- * @param {boolean} [restart] - Indicates whether to restart the instance after cleanup. Default is `false`.
1222
- * @param {number} [pause] - The pause in ms to wait for the message exchange to complete in milliseconds. Default is 1000.
1223
- *
1224
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1225
- */
1226
957
  async cleanup(message, restart = false, pause = 1000) {
1227
958
  if (this.initialized && !this.hasCleanupStarted) {
1228
959
  this.emit('cleanup_started');
1229
960
  this.hasCleanupStarted = true;
1230
961
  this.log.info(message);
1231
- // Clear the start matter interval
1232
962
  if (this.startMatterInterval) {
1233
963
  clearInterval(this.startMatterInterval);
1234
964
  this.startMatterInterval = undefined;
1235
965
  this.log.debug('Start matter interval cleared');
1236
966
  }
1237
- // Clear the check update timeout
1238
967
  if (this.checkUpdateTimeout) {
1239
968
  clearTimeout(this.checkUpdateTimeout);
1240
969
  this.checkUpdateTimeout = undefined;
1241
970
  this.log.debug('Check update timeout cleared');
1242
971
  }
1243
- // Clear the check update interval
1244
972
  if (this.checkUpdateInterval) {
1245
973
  clearInterval(this.checkUpdateInterval);
1246
974
  this.checkUpdateInterval = undefined;
1247
975
  this.log.debug('Check update interval cleared');
1248
976
  }
1249
- // Clear the configure timeout
1250
977
  if (this.configureTimeout) {
1251
978
  clearTimeout(this.configureTimeout);
1252
979
  this.configureTimeout = undefined;
1253
980
  this.log.debug('Matterbridge configure timeout cleared');
1254
981
  }
1255
- // Clear the reachability timeout
1256
982
  if (this.reachabilityTimeout) {
1257
983
  clearTimeout(this.reachabilityTimeout);
1258
984
  this.reachabilityTimeout = undefined;
1259
985
  this.log.debug('Matterbridge reachability timeout cleared');
1260
986
  }
1261
- // Call the shutdown method of each plugin and clear the plugins reachability timeout
1262
987
  for (const plugin of this.plugins) {
1263
988
  if (!plugin.enabled || plugin.error)
1264
989
  continue;
@@ -1269,7 +994,6 @@ export class Matterbridge extends EventEmitter {
1269
994
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1270
995
  }
1271
996
  }
1272
- // Stop matter server nodes
1273
997
  this.log.notice(`Stopping matter server nodes in ${this.bridgeMode} mode...`);
1274
998
  if (pause > 0) {
1275
999
  const { wait } = await import('./utils/wait.js');
@@ -1297,7 +1021,6 @@ export class Matterbridge extends EventEmitter {
1297
1021
  }
1298
1022
  }
1299
1023
  this.log.notice('Stopped matter server nodes');
1300
- // Matter commisioning reset
1301
1024
  if (message === 'shutting down with reset...') {
1302
1025
  this.log.info('Resetting Matterbridge commissioning information...');
1303
1026
  await this.matterStorageManager?.createContext('events')?.clearAll();
@@ -1307,7 +1030,6 @@ export class Matterbridge extends EventEmitter {
1307
1030
  await this.matterbridgeContext?.clearAll();
1308
1031
  this.log.info('Matter storage reset done! Remove the bridge from the controller.');
1309
1032
  }
1310
- // Unregister all devices
1311
1033
  if (message === 'unregistered all devices and shutting down...') {
1312
1034
  if (this.bridgeMode === 'bridge') {
1313
1035
  await this.matterStorageManager?.createContext('root')?.createContext('parts')?.createContext('Matterbridge')?.createContext('parts')?.clearAll();
@@ -1325,35 +1047,16 @@ export class Matterbridge extends EventEmitter {
1325
1047
  }
1326
1048
  this.log.info('Matter storage reset done!');
1327
1049
  }
1328
- // Stop matter storage
1329
1050
  await this.stopMatterStorage();
1330
- // Stop the frontend
1331
1051
  await this.frontend.stop();
1332
1052
  this.frontend.destroy();
1333
- // Close PluginManager and DeviceManager
1334
1053
  this.plugins.destroy();
1335
1054
  this.devices.destroy();
1336
- // Stop thread messaging server
1337
1055
  this.server.close();
1338
- // Close the matterbridge node storage and context
1339
1056
  if (this.nodeStorage && this.nodeContext) {
1340
- /*
1341
- TODO: Implement serialization of registered devices
1342
- this.log.info('Saving registered devices...');
1343
- const serializedRegisteredDevices: SerializedMatterbridgeEndpoint[] = [];
1344
- this.devices.forEach(async (device) => {
1345
- const serializedMatterbridgeDevice = MatterbridgeEndpoint.serialize(device);
1346
- this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1347
- if (serializedMatterbridgeDevice) serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1348
- });
1349
- await this.nodeContext.set<SerializedMatterbridgeEndpoint[]>('devices', serializedRegisteredDevices);
1350
- this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1351
- */
1352
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1353
1057
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1354
1058
  await this.nodeContext.close();
1355
1059
  this.nodeContext = undefined;
1356
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1357
1060
  for (const plugin of this.plugins) {
1358
1061
  if (plugin.nodeContext) {
1359
1062
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1370,10 +1073,8 @@ export class Matterbridge extends EventEmitter {
1370
1073
  }
1371
1074
  this.plugins.clear();
1372
1075
  this.devices.clear();
1373
- // Factory reset
1374
1076
  if (message === 'shutting down with factory reset...') {
1375
1077
  try {
1376
- // Delete matter storage directory with its subdirectories and backup
1377
1078
  const dir = path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME);
1378
1079
  this.log.info(`Removing matter storage directory: ${dir}`);
1379
1080
  await fs.promises.rm(dir, { recursive: true });
@@ -1382,13 +1083,11 @@ export class Matterbridge extends EventEmitter {
1382
1083
  await fs.promises.rm(backup, { recursive: true });
1383
1084
  }
1384
1085
  catch (error) {
1385
- // istanbul ignore next if
1386
1086
  if (error instanceof Error && error.code !== 'ENOENT') {
1387
1087
  this.log.error(`Error removing matter storage directory: ${error}`);
1388
1088
  }
1389
1089
  }
1390
1090
  try {
1391
- // Delete matterbridge storage directory with its subdirectories and backup
1392
1091
  const dir = path.join(this.matterbridgeDirectory, NODE_STORAGE_DIR);
1393
1092
  this.log.info(`Removing matterbridge storage directory: ${dir}`);
1394
1093
  await fs.promises.rm(dir, { recursive: true });
@@ -1397,20 +1096,18 @@ export class Matterbridge extends EventEmitter {
1397
1096
  await fs.promises.rm(backup, { recursive: true });
1398
1097
  }
1399
1098
  catch (error) {
1400
- // istanbul ignore next if
1401
1099
  if (error instanceof Error && error.code !== 'ENOENT') {
1402
1100
  this.log.error(`Error removing matterbridge storage directory: ${error}`);
1403
1101
  }
1404
1102
  }
1405
1103
  this.log.info('Factory reset done! Remove all paired fabrics from the controllers.');
1406
1104
  }
1407
- // Deregisters the process handlers
1408
1105
  this.deregisterProcessHandlers();
1409
1106
  if (restart) {
1410
1107
  if (message === 'updating...') {
1411
1108
  this.log.info('Cleanup completed. Updating...');
1412
1109
  Matterbridge.instance = undefined;
1413
- this.emit('update'); // Restart the process but the update has been done before. TODO move all updates to the cli
1110
+ this.emit('update');
1414
1111
  }
1415
1112
  else if (message === 'restarting...') {
1416
1113
  this.log.info('Cleanup completed. Restarting...');
@@ -1439,14 +1136,7 @@ export class Matterbridge extends EventEmitter {
1439
1136
  this.log.debug('Cleanup already started...');
1440
1137
  }
1441
1138
  }
1442
- /**
1443
- * Starts the Matterbridge in bridge mode.
1444
- *
1445
- * @private
1446
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1447
- */
1448
1139
  async startBridge() {
1449
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1450
1140
  if (!this.matterStorageManager)
1451
1141
  throw new Error('No storage manager initialized');
1452
1142
  if (!this.matterbridgeContext)
@@ -1459,7 +1149,6 @@ export class Matterbridge extends EventEmitter {
1459
1149
  this.log.debug('Starting start matter interval in bridge mode...');
1460
1150
  let failCount = 0;
1461
1151
  this.startMatterInterval = setInterval(async () => {
1462
- // istanbul ignore if cause is just a logging statement
1463
1152
  if (failCount && failCount % 10 === 0) {
1464
1153
  this.frontend.wssSendSnackbarMessage(`The bridge is still starting...`, 10, 'info');
1465
1154
  this.frontend.wssSendRefreshRequired('plugins');
@@ -1492,16 +1181,13 @@ export class Matterbridge extends EventEmitter {
1492
1181
  clearInterval(this.startMatterInterval);
1493
1182
  this.startMatterInterval = undefined;
1494
1183
  this.log.debug('Cleared startMatterInterval interval in bridge mode');
1495
- // Start the Matter server node
1496
- this.startServerNode(this.serverNode); // We don't await this, because the server node is started in the background
1497
- // Start the Matter server node of single devices in mode 'server'
1184
+ this.startServerNode(this.serverNode);
1498
1185
  for (const device of this.devices.array()) {
1499
1186
  if (device.mode === 'server' && device.serverNode) {
1500
1187
  this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
1501
- this.startServerNode(device.serverNode); // We don't await this, because the server node is started in the background
1188
+ this.startServerNode(device.serverNode);
1502
1189
  }
1503
1190
  }
1504
- // Configure the plugins
1505
1191
  this.configureTimeout = setTimeout(async () => {
1506
1192
  for (const plugin of this.plugins.array()) {
1507
1193
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1519,45 +1205,32 @@ export class Matterbridge extends EventEmitter {
1519
1205
  }
1520
1206
  this.frontend.wssSendRefreshRequired('plugins');
1521
1207
  }, 30 * 1000).unref();
1522
- // Setting reachability to true
1523
1208
  this.reachabilityTimeout = setTimeout(() => {
1524
1209
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1525
1210
  if (this.aggregatorNode)
1526
1211
  this.setAggregatorReachability(this.aggregatorNode, true);
1527
1212
  }, 60 * 1000).unref();
1528
- // Logger.get('LogServerNode').info(this.serverNode);
1529
1213
  this.emit('bridge_started');
1530
1214
  this.log.notice('Matterbridge bridge started successfully');
1531
1215
  this.frontend.wssSendRefreshRequired('settings');
1532
1216
  this.frontend.wssSendRefreshRequired('plugins');
1533
1217
  }, Number(process.env['MATTERBRIDGE_START_MATTER_INTERVAL_MS']) || this.startMatterIntervalMs);
1534
1218
  }
1535
- /**
1536
- * Starts the Matterbridge in childbridge mode.
1537
- *
1538
- * @param {number} [delay] - The delay before starting the childbridge. Default is 1000 milliseconds.
1539
- *
1540
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1541
- */
1542
1219
  async startChildbridge(delay = 1000) {
1543
1220
  if (!this.matterStorageManager)
1544
1221
  throw new Error('No storage manager initialized');
1545
1222
  const { wait } = await import('./utils/wait.js');
1546
- // Load with await all plugins but don't start them. We get the platform.type to pre-create server nodes for DynamicPlatform plugins
1547
1223
  this.log.debug('Loading all plugins in childbridge mode...');
1548
1224
  await this.startPlugins(true, false);
1549
- // Create server nodes for DynamicPlatform plugins and start all plugins in the background
1550
1225
  this.log.debug('Creating server nodes for DynamicPlatform plugins and starting all plugins in childbridge mode...');
1551
1226
  for (const plugin of this.plugins.array().filter((p) => p.enabled && !p.error)) {
1552
1227
  if (plugin.type === 'DynamicPlatform')
1553
1228
  await this.createDynamicPlugin(plugin);
1554
- this.plugins.start(plugin, 'Matterbridge is starting'); // Start the plugin in the background
1229
+ this.plugins.start(plugin, 'Matterbridge is starting');
1555
1230
  }
1556
- // Start the Matterbridge in childbridge mode when all plugins are loaded and started
1557
1231
  this.log.debug('Starting start matter interval in childbridge mode...');
1558
1232
  let failCount = 0;
1559
1233
  this.startMatterInterval = setInterval(async () => {
1560
- // istanbul ignore if cause is just a logging statement
1561
1234
  if (failCount && failCount % 10 === 0) {
1562
1235
  this.frontend.wssSendSnackbarMessage(`The bridge is still starting...`, 10, 'info');
1563
1236
  this.frontend.wssSendRefreshRequired('plugins');
@@ -1594,9 +1267,8 @@ export class Matterbridge extends EventEmitter {
1594
1267
  clearInterval(this.startMatterInterval);
1595
1268
  this.startMatterInterval = undefined;
1596
1269
  if (delay > 0)
1597
- await wait(Number(process.env['MATTERBRIDGE_PAUSE_MATTER_INTERVAL_MS']) || delay); // Wait for the specified delay to ensure all plugins server nodes are ready
1270
+ await wait(Number(process.env['MATTERBRIDGE_PAUSE_MATTER_INTERVAL_MS']) || delay);
1598
1271
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1599
- // Configure the plugins
1600
1272
  this.configureTimeout = setTimeout(async () => {
1601
1273
  for (const plugin of this.plugins.array()) {
1602
1274
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1621,7 +1293,6 @@ export class Matterbridge extends EventEmitter {
1621
1293
  this.log.error(`Plugin ${plg}${plugin.name}${er} didn't register any devices to Matterbridge. Verify the plugin configuration.`);
1622
1294
  continue;
1623
1295
  }
1624
- // istanbul ignore next if cause is just a safety check
1625
1296
  if (!plugin.serverNode) {
1626
1297
  this.log.error(`Server node not found for plugin ${plg}${plugin.name}${er}`);
1627
1298
  continue;
@@ -1634,252 +1305,28 @@ export class Matterbridge extends EventEmitter {
1634
1305
  this.log.error(`Node storage context not found for plugin ${plg}${plugin.name}${er}`);
1635
1306
  continue;
1636
1307
  }
1637
- // Start the Matter server node
1638
- this.startServerNode(plugin.serverNode); // We don't await this, because the server node is started in the background
1639
- // Setting reachability to true
1308
+ this.startServerNode(plugin.serverNode);
1640
1309
  plugin.reachabilityTimeout = setTimeout(() => {
1641
1310
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${nf}`);
1642
1311
  if (plugin.type === 'DynamicPlatform' && plugin.aggregatorNode)
1643
1312
  this.setAggregatorReachability(plugin.aggregatorNode, true);
1644
1313
  }, 60 * 1000).unref();
1645
1314
  }
1646
- // Start the Matter server node of single devices in mode 'server'
1647
1315
  for (const device of this.devices.array()) {
1648
1316
  if (device.mode === 'server' && device.serverNode) {
1649
1317
  this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
1650
- this.startServerNode(device.serverNode); // We don't await this, because the server node is started in the background
1318
+ this.startServerNode(device.serverNode);
1651
1319
  }
1652
1320
  }
1653
- // Logger.get('LogServerNode').info(this.serverNode);
1654
1321
  this.emit('childbridge_started');
1655
1322
  this.log.notice('Matterbridge childbridge started successfully');
1656
1323
  this.frontend.wssSendRefreshRequired('settings');
1657
1324
  this.frontend.wssSendRefreshRequired('plugins');
1658
1325
  }, Number(process.env['MATTERBRIDGE_START_MATTER_INTERVAL_MS']) || this.startMatterIntervalMs);
1659
1326
  }
1660
- /**
1661
- * Starts the Matterbridge controller.
1662
- *
1663
- * @private
1664
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1665
- */
1666
1327
  async startController() {
1667
- /*
1668
- if (!this.matterStorageManager) {
1669
- this.log.error('No storage manager initialized');
1670
- await this.cleanup('No storage manager initialized');
1671
- return;
1672
- }
1673
- this.log.info('Creating context: mattercontrollerContext');
1674
- this.controllerContext = this.matterStorageManager.createContext('mattercontrollerContext');
1675
- if (!this.controllerContext) {
1676
- this.log.error('No storage context mattercontrollerContext initialized');
1677
- await this.cleanup('No storage context mattercontrollerContext initialized');
1678
- return;
1679
- }
1680
-
1681
- this.log.debug('Starting matterbridge in mode', this.bridgeMode);
1682
- this.matterServer = await this.createMatterServer(this.storageManager);
1683
- this.log.info('Creating matter commissioning controller');
1684
- this.commissioningController = new CommissioningController({
1685
- autoConnect: false,
1686
- });
1687
- this.log.info('Adding matter commissioning controller to matter server');
1688
- await this.matterServer.addCommissioningController(this.commissioningController);
1689
-
1690
- this.log.info('Starting matter server');
1691
- await this.matterServer.start();
1692
- this.log.info('Matter server started');
1693
- const commissioningOptions: ControllerCommissioningFlowOptions = {
1694
- regulatoryLocation: GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor,
1695
- regulatoryCountryCode: 'XX',
1696
- };
1697
- const commissioningController = new CommissioningController({
1698
- environment: {
1699
- environment,
1700
- id: uniqueId,
1701
- },
1702
- autoConnect: false, // Do not auto connect to the commissioned nodes
1703
- adminFabricLabel,
1704
- });
1705
-
1706
- if (hasParameter('pairingcode')) {
1707
- this.log.info('Pairing device with pairingcode:', getParameter('pairingcode'));
1708
- const pairingCode = getParameter('pairingcode');
1709
- const ip = this.controllerContext.has('ip') ? this.controllerContext.get<string>('ip') : undefined;
1710
- const port = this.controllerContext.has('port') ? this.controllerContext.get<number>('port') : undefined;
1711
-
1712
- let longDiscriminator, setupPin, shortDiscriminator;
1713
- if (pairingCode !== undefined) {
1714
- const pairingCodeCodec = ManualPairingCodeCodec.decode(pairingCode);
1715
- shortDiscriminator = pairingCodeCodec.shortDiscriminator;
1716
- longDiscriminator = undefined;
1717
- setupPin = pairingCodeCodec.passcode;
1718
- this.log.info(`Data extracted from pairing code: ${Logger.toJSON(pairingCodeCodec)}`);
1719
- } else {
1720
- longDiscriminator = await this.controllerContext.get('longDiscriminator', 3840);
1721
- if (longDiscriminator > 4095) throw new Error('Discriminator value must be less than 4096');
1722
- setupPin = this.controllerContext.get('pin', 20202021);
1723
- }
1724
- if ((shortDiscriminator === undefined && longDiscriminator === undefined) || setupPin === undefined) {
1725
- throw new Error('Please specify the longDiscriminator of the device to commission with -longDiscriminator or provide a valid passcode with -passcode');
1726
- }
1727
-
1728
- const options = {
1729
- commissioning: commissioningOptions,
1730
- discovery: {
1731
- knownAddress: ip !== undefined && port !== undefined ? { ip, port, type: 'udp' } : undefined,
1732
- identifierData: longDiscriminator !== undefined ? { longDiscriminator } : shortDiscriminator !== undefined ? { shortDiscriminator } : {},
1733
- },
1734
- passcode: setupPin,
1735
- } as NodeCommissioningOptions;
1736
- this.log.info('Commissioning with options:', options);
1737
- const nodeId = await this.commissioningController.commissionNode(options);
1738
- this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1739
- this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1740
- } // (hasParameter('pairingcode'))
1741
-
1742
- if (hasParameter('unpairall')) {
1743
- this.log.info('***Commissioning controller unpairing all nodes...');
1744
- const nodeIds = this.commissioningController.getCommissionedNodes();
1745
- for (const nodeId of nodeIds) {
1746
- this.log.info('***Commissioning controller unpairing node:', nodeId);
1747
- await this.commissioningController.removeNode(nodeId);
1748
- }
1749
- return;
1750
- }
1751
-
1752
- if (hasParameter('discover')) {
1753
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1754
- // console.log(discover);
1755
- }
1756
-
1757
- if (!this.commissioningController.isCommissioned()) {
1758
- this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
1759
- return;
1760
- }
1761
-
1762
- const nodeIds = this.commissioningController.getCommissionedNodes();
1763
- this.log.info(`***Commissioning controller is commissioned ${this.commissioningController.isCommissioned()} and has ${nodeIds.length} nodes commisioned: `);
1764
- for (const nodeId of nodeIds) {
1765
- this.log.info(`***Connecting to commissioned node: ${nodeId}`);
1766
-
1767
- const node = await this.commissioningController.connectNode(nodeId, {
1768
- autoSubscribe: false,
1769
- attributeChangedCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, attributeName }, value }) =>
1770
- this.log.info(`***Commissioning controller attributeChangedCallback ${peerNodeId}: attribute ${nodeId}/${endpointId}/${clusterId}/${attributeName} changed to ${Logger.toJSON(value)}`),
1771
- eventTriggeredCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, eventName }, events }) =>
1772
- this.log.info(`***Commissioning controller eventTriggeredCallback ${peerNodeId}: Event ${nodeId}/${endpointId}/${clusterId}/${eventName} triggered with ${Logger.toJSON(events)}`),
1773
- stateInformationCallback: (peerNodeId, info) => {
1774
- switch (info) {
1775
- case NodeStateInformation.Connected:
1776
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} connected`);
1777
- break;
1778
- case NodeStateInformation.Disconnected:
1779
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} disconnected`);
1780
- break;
1781
- case NodeStateInformation.Reconnecting:
1782
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} reconnecting`);
1783
- break;
1784
- case NodeStateInformation.WaitingForDeviceDiscovery:
1785
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} waiting for device discovery`);
1786
- break;
1787
- case NodeStateInformation.StructureChanged:
1788
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} structure changed`);
1789
- break;
1790
- case NodeStateInformation.Decommissioned:
1791
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} decommissioned`);
1792
- break;
1793
- default:
1794
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} NodeStateInformation.${info}`);
1795
- break;
1796
- }
1797
- },
1798
- });
1799
-
1800
- node.logStructure();
1801
-
1802
- // Get the interaction client
1803
- this.log.info('Getting the interaction client');
1804
- const interactionClient = await node.getInteractionClient();
1805
- let cluster;
1806
- let attributes;
1807
-
1808
- // Log BasicInformationCluster
1809
- cluster = BasicInformationCluster;
1810
- attributes = await interactionClient.getMultipleAttributes({
1811
- attributes: [{ clusterId: cluster.id }],
1812
- });
1813
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1814
- attributes.forEach((attribute) => {
1815
- this.log.info(
1816
- `- 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}`,
1817
- );
1818
- });
1819
-
1820
- // Log PowerSourceCluster
1821
- cluster = PowerSourceCluster;
1822
- attributes = await interactionClient.getMultipleAttributes({
1823
- attributes: [{ clusterId: cluster.id }],
1824
- });
1825
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1826
- attributes.forEach((attribute) => {
1827
- this.log.info(
1828
- `- 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}`,
1829
- );
1830
- });
1831
-
1832
- // Log ThreadNetworkDiagnostics
1833
- cluster = ThreadNetworkDiagnosticsCluster;
1834
- attributes = await interactionClient.getMultipleAttributes({
1835
- attributes: [{ clusterId: cluster.id }],
1836
- });
1837
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1838
- attributes.forEach((attribute) => {
1839
- this.log.info(
1840
- `- 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}`,
1841
- );
1842
- });
1843
-
1844
- // Log SwitchCluster
1845
- cluster = SwitchCluster;
1846
- attributes = await interactionClient.getMultipleAttributes({
1847
- attributes: [{ clusterId: cluster.id }],
1848
- });
1849
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1850
- attributes.forEach((attribute) => {
1851
- this.log.info(
1852
- `- 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}`,
1853
- );
1854
- });
1855
-
1856
- this.log.info('Subscribing to all attributes and events');
1857
- await node.subscribeAllAttributesAndEvents({
1858
- ignoreInitialTriggers: false,
1859
- attributeChangedCallback: ({ path: { nodeId, clusterId, endpointId, attributeName }, version, value }) =>
1860
- this.log.info(
1861
- `***${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}`,
1862
- ),
1863
- eventTriggeredCallback: ({ path: { nodeId, clusterId, endpointId, eventName }, events }) => {
1864
- this.log.info(
1865
- `***${db}Commissioning controller eventTriggeredCallback: event ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${eventName}${db} triggered with ${debugStringify(events ?? { none: true })}`,
1866
- );
1867
- },
1868
- });
1869
- this.log.info('Subscribed to all attributes and events');
1870
- }
1871
- */
1872
1328
  }
1873
- /** */
1874
- /** Matter.js methods */
1875
- /** */
1876
- /**
1877
- * Starts the matter storage with name Matterbridge, create the matterbridge context and performs a backup.
1878
- *
1879
- * @returns {Promise<void>} - A promise that resolves when the storage is started.
1880
- */
1881
1329
  async startMatterStorage() {
1882
- // Setup Matter storage
1883
1330
  this.log.info(`Starting matter node storage...`);
1884
1331
  this.matterStorageService = this.environment.get(StorageService);
1885
1332
  this.log.info(`Matter node storage service created: ${this.matterStorageService.location}`);
@@ -1887,17 +1334,8 @@ export class Matterbridge extends EventEmitter {
1887
1334
  this.log.info('Matter node storage manager "Matterbridge" created');
1888
1335
  this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId);
1889
1336
  this.log.info('Matter node storage started');
1890
- // Backup matter storage since it is created/opened correctly
1891
1337
  await this.backupMatterStorage(path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME), path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME + '.backup'));
1892
1338
  }
1893
- /**
1894
- * Makes a backup copy of the specified matter storage directory.
1895
- *
1896
- * @param {string} storageName - The name of the storage directory to be backed up.
1897
- * @param {string} backupName - The name of the backup directory to be created.
1898
- * @private
1899
- * @returns {Promise<void>} A promise that resolves when the has been done.
1900
- */
1901
1339
  async backupMatterStorage(storageName, backupName) {
1902
1340
  this.log.info('Creating matter node storage backup...');
1903
1341
  try {
@@ -1908,11 +1346,6 @@ export class Matterbridge extends EventEmitter {
1908
1346
  this.log.error(`Error creating matter node storage backup from ${storageName} to ${backupName}:`, error);
1909
1347
  }
1910
1348
  }
1911
- /**
1912
- * Stops the matter storage.
1913
- *
1914
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1915
- */
1916
1349
  async stopMatterStorage() {
1917
1350
  this.log.info('Closing matter node storage...');
1918
1351
  await this.matterStorageManager?.close();
@@ -1921,20 +1354,6 @@ export class Matterbridge extends EventEmitter {
1921
1354
  this.matterbridgeContext = undefined;
1922
1355
  this.log.info('Matter node storage closed');
1923
1356
  }
1924
- /**
1925
- * Creates a server node storage context.
1926
- *
1927
- * @param {string} storeId - The storeId.
1928
- * @param {string} deviceName - The name of the device.
1929
- * @param {DeviceTypeId} deviceType - The device type of the device.
1930
- * @param {number} vendorId - The vendor ID.
1931
- * @param {string} vendorName - The vendor name.
1932
- * @param {number} productId - The product ID.
1933
- * @param {string} productName - The product name.
1934
- * @param {string} [serialNumber] - The serial number of the device (optional).
1935
- * @param {string} [uniqueId] - The unique ID of the device (optional).
1936
- * @returns {Promise<StorageContext>} The storage context for the commissioning server.
1937
- */
1938
1357
  async createServerNodeContext(storeId, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber, uniqueId) {
1939
1358
  const { randomBytes } = await import('node:crypto');
1940
1359
  if (!this.matterStorageService)
@@ -1974,15 +1393,6 @@ export class Matterbridge extends EventEmitter {
1974
1393
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
1975
1394
  return storageContext;
1976
1395
  }
1977
- /**
1978
- * Creates a server node.
1979
- *
1980
- * @param {StorageContext} storageContext - The storage context for the server node.
1981
- * @param {number} [port] - The port number for the server node. Defaults to 5540.
1982
- * @param {number} [passcode] - The passcode for the server node. Defaults to 20242025.
1983
- * @param {number} [discriminator] - The discriminator for the server node. Defaults to 3850.
1984
- * @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created server node.
1985
- */
1986
1396
  async createServerNode(storageContext, port = 5540, passcode = 20242025, discriminator = 3850) {
1987
1397
  const storeId = await storageContext.get('storeId');
1988
1398
  this.log.notice(`Creating server node for ${storeId} on port ${port} with passcode ${passcode} and discriminator ${discriminator}...`);
@@ -1992,35 +1402,25 @@ export class Matterbridge extends EventEmitter {
1992
1402
  this.log.debug(`- uniqueId: ${await storageContext.get('uniqueId')}`);
1993
1403
  this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
1994
1404
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
1995
- /**
1996
- * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
1997
- */
1998
1405
  const serverNode = await ServerNode.create({
1999
- // Required: Give the Node a unique ID which is used to store the state of this node
2000
1406
  id: storeId,
2001
- // Environment to run the server node in
2002
1407
  environment: this.environment,
2003
- // Provide Network relevant configuration like the port
2004
1408
  network: {
2005
1409
  listeningAddressIpv4: this.ipv4Address,
2006
1410
  listeningAddressIpv6: this.ipv6Address,
2007
1411
  port,
2008
1412
  },
2009
- // Provide the certificate for the device
2010
1413
  operationalCredentials: {
2011
1414
  certification: this.certification,
2012
1415
  },
2013
- // Provide Commissioning relevant settings
2014
1416
  commissioning: {
2015
1417
  passcode,
2016
1418
  discriminator,
2017
1419
  },
2018
- // Provide Node announcement settings
2019
1420
  productDescription: {
2020
1421
  name: await storageContext.get('deviceName'),
2021
1422
  deviceType: DeviceTypeId(await storageContext.get('deviceType')),
2022
1423
  },
2023
- // Provide defaults for the BasicInformation cluster on the Root endpoint
2024
1424
  basicInformation: {
2025
1425
  vendorId: VendorId(await storageContext.get('vendorId')),
2026
1426
  vendorName: await storageContext.get('vendorName'),
@@ -2037,23 +1437,17 @@ export class Matterbridge extends EventEmitter {
2037
1437
  reachable: true,
2038
1438
  },
2039
1439
  });
2040
- /**
2041
- * This event is triggered when the device is initially commissioned successfully.
2042
- * This means: It is added to the first fabric.
2043
- */
2044
1440
  serverNode.lifecycle.commissioned.on(() => {
2045
1441
  this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`);
2046
1442
  this.advertisingNodes.delete(storeId);
2047
1443
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2048
1444
  });
2049
- /** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
2050
1445
  serverNode.lifecycle.decommissioned.on(() => {
2051
1446
  this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`);
2052
1447
  this.advertisingNodes.delete(storeId);
2053
1448
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2054
1449
  this.frontend.wssSendSnackbarMessage(`${storeId} is offline`, 5, 'warning');
2055
1450
  });
2056
- /** This event is triggered when the device went online. This means that it is discoverable in the network. */
2057
1451
  serverNode.lifecycle.online.on(async () => {
2058
1452
  this.log.notice(`Server node for ${storeId} is online`);
2059
1453
  if (!serverNode.lifecycle.isCommissioned) {
@@ -2064,16 +1458,13 @@ export class Matterbridge extends EventEmitter {
2064
1458
  this.log.notice(`Manual pairing code: ${manualPairingCode}`);
2065
1459
  }
2066
1460
  else {
2067
- // istanbul ignore next
2068
1461
  this.log.notice(`Server node for ${storeId} is already commissioned. Waiting for controllers to connect ...`);
2069
- // istanbul ignore next
2070
1462
  this.advertisingNodes.delete(storeId);
2071
1463
  }
2072
1464
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2073
1465
  this.frontend.wssSendSnackbarMessage(`${storeId} is online`, 5, 'success');
2074
1466
  this.emit('online', storeId);
2075
1467
  });
2076
- /** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
2077
1468
  serverNode.lifecycle.offline.on(() => {
2078
1469
  this.log.notice(`Server node for ${storeId} is offline`);
2079
1470
  this.advertisingNodes.delete(storeId);
@@ -2081,15 +1472,11 @@ export class Matterbridge extends EventEmitter {
2081
1472
  this.frontend.wssSendSnackbarMessage(`${storeId} is offline`, 5, 'warning');
2082
1473
  this.emit('offline', storeId);
2083
1474
  });
2084
- /**
2085
- * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
2086
- * information is needed.
2087
- */
2088
1475
  serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
2089
1476
  let action = '';
2090
1477
  switch (fabricAction) {
2091
1478
  case FabricAction.Added:
2092
- this.advertisingNodes.delete(storeId); // The advertising stops when a fabric is added
1479
+ this.advertisingNodes.delete(storeId);
2093
1480
  action = 'added';
2094
1481
  break;
2095
1482
  case FabricAction.Removed:
@@ -2102,22 +1489,14 @@ export class Matterbridge extends EventEmitter {
2102
1489
  this.log.notice(`Commissioned fabric index ${fabricIndex} ${action} on server node for ${storeId}: ${debugStringify(serverNode.state.commissioning.fabrics[fabricIndex])}`);
2103
1490
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2104
1491
  });
2105
- /**
2106
- * This event is triggered when an operative new session was opened by a Controller.
2107
- * It is not triggered for the initial commissioning process, just afterwards for real connections.
2108
- */
2109
1492
  serverNode.events.sessions.opened.on((session) => {
2110
1493
  this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
2111
1494
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2112
1495
  });
2113
- /**
2114
- * This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
2115
- */
2116
1496
  serverNode.events.sessions.closed.on((session) => {
2117
1497
  this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
2118
1498
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2119
1499
  });
2120
- /** This event is triggered when a subscription gets added or removed on an operative session. */
2121
1500
  serverNode.events.sessions.subscriptionsChanged.on((session) => {
2122
1501
  this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
2123
1502
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
@@ -2125,12 +1504,6 @@ export class Matterbridge extends EventEmitter {
2125
1504
  this.log.info(`Created server node for ${storeId}`);
2126
1505
  return serverNode;
2127
1506
  }
2128
- /**
2129
- * Gets the matter sanitized data of the specified server node.
2130
- *
2131
- * @param {ServerNode} [serverNode] - The server node to start.
2132
- * @returns {ApiMatter} The sanitized data of the server node.
2133
- */
2134
1507
  getServerNodeData(serverNode) {
2135
1508
  const advertiseTime = this.advertisingNodes.get(serverNode.id) || 0;
2136
1509
  return {
@@ -2147,25 +1520,12 @@ export class Matterbridge extends EventEmitter {
2147
1520
  serialNumber: serverNode.state.basicInformation.serialNumber,
2148
1521
  };
2149
1522
  }
2150
- /**
2151
- * Starts the specified server node.
2152
- *
2153
- * @param {ServerNode} [matterServerNode] - The server node to start.
2154
- * @returns {Promise<void>} A promise that resolves when the server node has started.
2155
- */
2156
1523
  async startServerNode(matterServerNode) {
2157
1524
  if (!matterServerNode)
2158
1525
  return;
2159
1526
  this.log.notice(`Starting ${matterServerNode.id} server node`);
2160
1527
  await matterServerNode.start();
2161
1528
  }
2162
- /**
2163
- * Stops the specified server node.
2164
- *
2165
- * @param {ServerNode} matterServerNode - The server node to stop.
2166
- * @param {number} [timeout] - The timeout in milliseconds for stopping the server node. Defaults to 30 seconds.
2167
- * @returns {Promise<void>} A promise that resolves when the server node has stopped.
2168
- */
2169
1529
  async stopServerNode(matterServerNode, timeout = 30000) {
2170
1530
  const { withTimeout } = await import('./utils/wait.js');
2171
1531
  if (!matterServerNode)
@@ -2179,25 +1539,12 @@ export class Matterbridge extends EventEmitter {
2179
1539
  this.log.error(`Failed to close ${matterServerNode.id} server node: ${error instanceof Error ? error.message : error}`);
2180
1540
  }
2181
1541
  }
2182
- /**
2183
- * Creates an aggregator node with the specified storage context.
2184
- *
2185
- * @param {StorageContext} storageContext - The storage context for the aggregator node.
2186
- * @returns {Promise<Endpoint<AggregatorEndpoint>>} A promise that resolves to the created aggregator node.
2187
- */
2188
1542
  async createAggregatorNode(storageContext) {
2189
1543
  this.log.notice(`Creating ${await storageContext.get('storeId')} aggregator...`);
2190
1544
  const aggregatorNode = new Endpoint(AggregatorEndpoint, { id: `${await storageContext.get('storeId')}` });
2191
1545
  this.log.info(`Created ${await storageContext.get('storeId')} aggregator`);
2192
1546
  return aggregatorNode;
2193
1547
  }
2194
- /**
2195
- * Creates and configures the server node for an accessory plugin for a given device.
2196
- *
2197
- * @param {Plugin} plugin - The plugin to configure.
2198
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
2199
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
2200
- */
2201
1548
  async createAccessoryPlugin(plugin, device) {
2202
1549
  if (!plugin.locked && device.deviceType && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
2203
1550
  plugin.locked = true;
@@ -2209,12 +1556,6 @@ export class Matterbridge extends EventEmitter {
2209
1556
  await plugin.serverNode.add(device);
2210
1557
  }
2211
1558
  }
2212
- /**
2213
- * Creates and configures the server node and the aggregator node for a dynamic plugin.
2214
- *
2215
- * @param {Plugin} plugin - The plugin to configure.
2216
- * @returns {Promise<void>} A promise that resolves when the server node and the aggregator node for the dynamic plugin is created and configured.
2217
- */
2218
1559
  async createDynamicPlugin(plugin) {
2219
1560
  if (!plugin.locked) {
2220
1561
  plugin.locked = true;
@@ -2227,13 +1568,6 @@ export class Matterbridge extends EventEmitter {
2227
1568
  await plugin.serverNode.add(plugin.aggregatorNode);
2228
1569
  }
2229
1570
  }
2230
- /**
2231
- * Creates and configures the server node for a single not bridged device.
2232
- *
2233
- * @param {Plugin} plugin - The plugin to configure.
2234
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
2235
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
2236
- */
2237
1571
  async createDeviceServerNode(plugin, device) {
2238
1572
  if (device.mode === 'server' && !device.serverNode && device.deviceType && device.deviceName && device.vendorId && device.vendorName && device.productId && device.productName) {
2239
1573
  this.log.debug(`Creating device ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} server node...`);
@@ -2244,16 +1578,8 @@ export class Matterbridge extends EventEmitter {
2244
1578
  this.log.debug(`Added ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to server node`);
2245
1579
  }
2246
1580
  }
2247
- /**
2248
- * Adds a MatterbridgeEndpoint to the specified plugin.
2249
- *
2250
- * @param {string} pluginName - The name of the plugin.
2251
- * @param {MatterbridgeEndpoint} device - The device to add as a bridged endpoint.
2252
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been added.
2253
- */
2254
1581
  async addBridgedEndpoint(pluginName, device) {
2255
1582
  const { waiter } = await import('./utils/wait.js');
2256
- // Check if the plugin is registered
2257
1583
  const plugin = this.plugins.get(pluginName);
2258
1584
  if (!plugin) {
2259
1585
  this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
@@ -2273,7 +1599,6 @@ export class Matterbridge extends EventEmitter {
2273
1599
  }
2274
1600
  else if (this.bridgeMode === 'bridge') {
2275
1601
  if (device.mode === 'matter') {
2276
- // Register and add the device to the matterbridge server node
2277
1602
  this.log.debug(`Adding matter endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge server node...`);
2278
1603
  if (!this.serverNode) {
2279
1604
  this.log.error('Server node not found for Matterbridge');
@@ -2290,7 +1615,6 @@ export class Matterbridge extends EventEmitter {
2290
1615
  }
2291
1616
  }
2292
1617
  else {
2293
- // Register and add the device to the matterbridge aggregator node
2294
1618
  this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
2295
1619
  if (!this.aggregatorNode) {
2296
1620
  this.log.error('Aggregator node not found for Matterbridge');
@@ -2308,7 +1632,6 @@ export class Matterbridge extends EventEmitter {
2308
1632
  }
2309
1633
  }
2310
1634
  else if (this.bridgeMode === 'childbridge') {
2311
- // Register and add the device to the plugin server node
2312
1635
  if (plugin.type === 'AccessoryPlatform') {
2313
1636
  try {
2314
1637
  this.log.debug(`Creating endpoint ${dev}${device.deviceName}${db} for AccessoryPlatform plugin ${plg}${plugin.name}${db} server node`);
@@ -2332,12 +1655,10 @@ export class Matterbridge extends EventEmitter {
2332
1655
  return;
2333
1656
  }
2334
1657
  }
2335
- // Register and add the device to the plugin aggregator node
2336
1658
  if (plugin.type === 'DynamicPlatform') {
2337
1659
  try {
2338
1660
  this.log.debug(`Adding bridged endpoint ${dev}${device.deviceName}${db} for DynamicPlatform plugin ${plg}${plugin.name}${db} aggregator node`);
2339
1661
  await this.createDynamicPlugin(plugin);
2340
- // Fast plugins can add another device before the server node is ready, so we wait for the server node to be ready
2341
1662
  await waiter(`createDynamicPlugin(${plugin.name})`, () => plugin.serverNode?.hasParts === true);
2342
1663
  if (!plugin.aggregatorNode) {
2343
1664
  this.log.error(`Aggregator node not found for plugin ${plg}${plugin.name}${er}`);
@@ -2358,28 +1679,17 @@ export class Matterbridge extends EventEmitter {
2358
1679
  }
2359
1680
  if (plugin.registeredDevices !== undefined)
2360
1681
  plugin.registeredDevices++;
2361
- // Add the device to the DeviceManager
2362
1682
  this.devices.set(device);
2363
- // Subscribe to the attributes changed event
2364
1683
  await this.subscribeAttributeChanged(plugin, device);
2365
1684
  this.log.info(`Added and registered bridged endpoint (${plugin.registeredDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) for plugin ${plg}${pluginName}${nf}`);
2366
1685
  }
2367
- /**
2368
- * Removes a MatterbridgeEndpoint from the specified plugin.
2369
- *
2370
- * @param {string} pluginName - The name of the plugin.
2371
- * @param {MatterbridgeEndpoint} device - The device to remove as a bridged endpoint.
2372
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been removed.
2373
- */
2374
1686
  async removeBridgedEndpoint(pluginName, device) {
2375
1687
  this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
2376
- // Check if the plugin is registered
2377
1688
  const plugin = this.plugins.get(pluginName);
2378
1689
  if (!plugin) {
2379
1690
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
2380
1691
  return;
2381
1692
  }
2382
- // Unregister and remove the device from the matterbridge aggregator node
2383
1693
  if (this.bridgeMode === 'bridge') {
2384
1694
  if (!this.aggregatorNode) {
2385
1695
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator node not found`);
@@ -2392,10 +1702,8 @@ export class Matterbridge extends EventEmitter {
2392
1702
  }
2393
1703
  else if (this.bridgeMode === 'childbridge') {
2394
1704
  if (plugin.type === 'AccessoryPlatform') {
2395
- // Nothing to do here since the server node has no aggregator node but only the device itself
2396
1705
  }
2397
1706
  else if (plugin.type === 'DynamicPlatform') {
2398
- // Unregister and remove the device from the plugin aggregator node
2399
1707
  if (!plugin.aggregatorNode) {
2400
1708
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator node not found`);
2401
1709
  return;
@@ -2406,21 +1714,8 @@ export class Matterbridge extends EventEmitter {
2406
1714
  if (plugin.registeredDevices !== undefined)
2407
1715
  plugin.registeredDevices--;
2408
1716
  }
2409
- // Remove the device from the DeviceManager
2410
1717
  this.devices.remove(device);
2411
1718
  }
2412
- /**
2413
- * Removes all bridged endpoints from the specified plugin.
2414
- *
2415
- * @param {string} pluginName - The name of the plugin.
2416
- * @param {number} [delay] - The delay in milliseconds between removing each bridged endpoint (default: 0).
2417
- * @returns {Promise<void>} A promise that resolves when all bridged endpoints have been removed.
2418
- *
2419
- * @remarks
2420
- * This method iterates through all devices in the DeviceManager and removes each bridged endpoint associated with the specified plugin.
2421
- * It also applies a delay between each removal if specified.
2422
- * The delay is useful to allow the controllers to receive a single subscription for each device removed.
2423
- */
2424
1719
  async removeAllBridgedEndpoints(pluginName, delay = 0) {
2425
1720
  const { wait } = await import('./utils/wait.js');
2426
1721
  this.log.debug(`Removing all bridged endpoints for plugin ${plg}${pluginName}${db}${delay > 0 ? ` with delay ${delay} ms` : ''}`);
@@ -2432,28 +1727,8 @@ export class Matterbridge extends EventEmitter {
2432
1727
  if (delay > 0)
2433
1728
  await wait(2000);
2434
1729
  }
2435
- /**
2436
- * Registers a virtual device.
2437
- * Virtual devices are only supported in bridge mode and childbridge mode with a DynamicPlatform.
2438
- *
2439
- * The virtual device is created as an instance of `Endpoint` with the provided device type.
2440
- * When the virtual device is turned on, the provided callback function is executed.
2441
- * The onOff state of the virtual device always reverts to false when the device is turned on.
2442
- *
2443
- * @param { string } pluginName - The name of the plugin to register the virtual device under.
2444
- * @param { string } name - The name of the virtual device.
2445
- * @param { 'light' | 'outlet' | 'switch' | 'mounted_switch' } type - The type of the virtual device.
2446
- * @param { () => Promise<void> } callback - The callback to call when the virtual device is turned on.
2447
- *
2448
- * @returns {Promise<boolean>} A promise that resolves to true if the virtual device was successfully registered, false otherwise.
2449
- *
2450
- * @remarks
2451
- * The virtual devices don't show up in the device list of the frontend.
2452
- * Type 'switch' is not supported by Alexa and 'mounted_switch' is not supported by Apple Home.
2453
- */
2454
1730
  async addVirtualEndpoint(pluginName, name, type, callback) {
2455
1731
  this.log.debug(`Adding virtual endpoint ${plg}${pluginName}${db}:${dev}${name}${db}...`);
2456
- // Check if the plugin is registered
2457
1732
  const plugin = this.plugins.get(pluginName);
2458
1733
  if (!plugin) {
2459
1734
  this.log.error(`Error adding virtual endpoint ${dev}${name}${er} for plugin ${plg}${pluginName}${er}: plugin not found`);
@@ -2480,24 +1755,13 @@ export class Matterbridge extends EventEmitter {
2480
1755
  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.`);
2481
1756
  return false;
2482
1757
  }
2483
- /**
2484
- * Subscribes to the attribute change event for the given device and plugin.
2485
- * Specifically, it listens for changes in the 'reachable' attribute of the
2486
- * BridgedDeviceBasicInformationServer cluster server of the bridged device or BasicInformationServer cluster server of server node.
2487
- *
2488
- * @param {Plugin} plugin - The plugin associated with the device.
2489
- * @param {MatterbridgeEndpoint} device - The device to subscribe to attribute changes for.
2490
- * @returns {Promise<void>} A promise that resolves when the subscription is set up.
2491
- */
2492
1758
  async subscribeAttributeChanged(plugin, device) {
2493
1759
  if (!plugin || !device || !device.plugin || !device.serialNumber || !device.uniqueId || !device.maybeNumber)
2494
1760
  return;
2495
1761
  this.log.info(`Subscribing attributes for endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) plugin ${plg}${plugin.name}${nf}`);
2496
- // Subscribe to the reachable$Changed event of the BasicInformationServer cluster server of the server node in childbridge mode
2497
1762
  if (this.bridgeMode === 'childbridge' && plugin.type === 'AccessoryPlatform' && plugin.serverNode) {
2498
1763
  plugin.serverNode.eventsOf(BasicInformationServer).reachable$Changed?.on((reachable) => {
2499
1764
  this.log.info(`Accessory endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) is ${reachable ? 'reachable' : 'unreachable'}`);
2500
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2501
1765
  this.frontend.wssSendAttributeChangedMessage(device.plugin, device.serialNumber, device.uniqueId, device.number, device.id, 'BasicInformation', 'reachable', reachable);
2502
1766
  });
2503
1767
  }
@@ -2547,7 +1811,6 @@ export class Matterbridge extends EventEmitter {
2547
1811
  this.log.debug(`Subscribing to endpoint ${or}${device.id}${db}:${or}${device.number}${db} attribute ${dev}${sub.cluster}${db}.${dev}${sub.attribute}${db} changes...`);
2548
1812
  await device.subscribeAttribute(sub.cluster, sub.attribute, (value) => {
2549
1813
  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}`);
2550
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2551
1814
  this.frontend.wssSendAttributeChangedMessage(device.plugin, device.serialNumber, device.uniqueId, device.number, device.id, sub.cluster, sub.attribute, value);
2552
1815
  });
2553
1816
  }
@@ -2556,19 +1819,12 @@ export class Matterbridge extends EventEmitter {
2556
1819
  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...`);
2557
1820
  await child.subscribeAttribute(sub.cluster, sub.attribute, (value) => {
2558
1821
  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}`);
2559
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2560
1822
  this.frontend.wssSendAttributeChangedMessage(device.plugin, device.serialNumber, device.uniqueId, child.number, child.id, sub.cluster, sub.attribute, value);
2561
1823
  });
2562
1824
  }
2563
1825
  }
2564
1826
  }
2565
1827
  }
2566
- /**
2567
- * Sanitizes the fabric information by converting bigint properties to strings because `res.json` doesn't support bigint.
2568
- *
2569
- * @param {ExposedFabricInformation[]} fabricInfo - The array of exposed fabric information objects.
2570
- * @returns {SanitizedExposedFabricInformation[]} An array of sanitized exposed fabric information objects.
2571
- */
2572
1828
  sanitizeFabricInformations(fabricInfo) {
2573
1829
  return fabricInfo.map((info) => {
2574
1830
  return {
@@ -2582,12 +1838,6 @@ export class Matterbridge extends EventEmitter {
2582
1838
  };
2583
1839
  });
2584
1840
  }
2585
- /**
2586
- * Sanitizes the session information by converting bigint properties to strings because `res.json` doesn't support bigint.
2587
- *
2588
- * @param {SessionsBehavior.Session[]} sessions - The array of session information objects.
2589
- * @returns {SanitizedSession[]} An array of sanitized session information objects.
2590
- */
2591
1841
  sanitizeSessionInformation(sessions) {
2592
1842
  return sessions
2593
1843
  .filter((session) => session.isPeerActive)
@@ -2614,21 +1864,7 @@ export class Matterbridge extends EventEmitter {
2614
1864
  };
2615
1865
  });
2616
1866
  }
2617
- /**
2618
- * Sets the reachability of the specified aggregator node bridged devices and trigger.
2619
- *
2620
- * @param {Endpoint<AggregatorEndpoint>} aggregatorNode - The aggregator node to set the reachability for.
2621
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2622
- */
2623
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2624
1867
  async setAggregatorReachability(aggregatorNode, reachable) {
2625
- /*
2626
- for (const child of aggregatorNode.parts) {
2627
- this.log.debug(`Setting reachability of ${(child as unknown as MatterbridgeEndpoint)?.deviceName} to ${reachable}`);
2628
- await child.setStateOf(BridgedDeviceBasicInformationServer, { reachable });
2629
- child.act((agent) => child.eventsOf(BridgedDeviceBasicInformationServer).reachableChanged.emit({ reachableNewValue: true }, agent.context));
2630
- }
2631
- */
2632
1868
  }
2633
1869
  getVendorIdName = (vendorId) => {
2634
1870
  if (!vendorId)
@@ -2668,11 +1904,10 @@ export class Matterbridge extends EventEmitter {
2668
1904
  case 0x1488:
2669
1905
  vendorName = '(ShortcutLabsFlic)';
2670
1906
  break;
2671
- case 65521: // 0xFFF1
1907
+ case 65521:
2672
1908
  vendorName = '(MatterTest)';
2673
1909
  break;
2674
1910
  }
2675
1911
  return vendorName;
2676
1912
  };
2677
1913
  }
2678
- //# sourceMappingURL=matterbridge.js.map