matterbridge 3.5.0 → 3.5.1-dev-20260122-6461be3

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 (330) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README-DOCKER.md +4 -2
  3. package/README.md +4 -1
  4. package/bin/mb_coap.js +1 -1
  5. package/bin/mb_mdns.js +1 -1
  6. package/dist/broadcastServer.d.ts +0 -115
  7. package/dist/broadcastServer.js +1 -119
  8. package/dist/broadcastServerTypes.d.ts +0 -43
  9. package/dist/broadcastServerTypes.js +0 -24
  10. package/dist/cli.d.ts +1 -26
  11. package/dist/cli.js +2 -102
  12. package/dist/cliEmitter.d.ts +0 -36
  13. package/dist/cliEmitter.js +0 -37
  14. package/dist/cliHistory.d.ts +0 -42
  15. package/dist/cliHistory.js +1 -39
  16. package/dist/clusters/export.d.ts +0 -1
  17. package/dist/clusters/export.js +0 -2
  18. package/dist/deviceManager.d.ts +0 -108
  19. package/dist/deviceManager.js +2 -114
  20. package/dist/devices/airConditioner.d.ts +0 -75
  21. package/dist/devices/airConditioner.js +0 -57
  22. package/dist/devices/batteryStorage.d.ts +0 -43
  23. package/dist/devices/batteryStorage.js +1 -48
  24. package/dist/devices/cooktop.d.ts +0 -55
  25. package/dist/devices/cooktop.js +0 -56
  26. package/dist/devices/dishwasher.d.ts +0 -55
  27. package/dist/devices/dishwasher.js +0 -57
  28. package/dist/devices/evse.d.ts +0 -57
  29. package/dist/devices/evse.js +10 -74
  30. package/dist/devices/export.d.ts +0 -1
  31. package/dist/devices/export.js +0 -5
  32. package/dist/devices/extractorHood.d.ts +0 -41
  33. package/dist/devices/extractorHood.js +0 -43
  34. package/dist/devices/heatPump.d.ts +0 -43
  35. package/dist/devices/heatPump.js +2 -50
  36. package/dist/devices/laundryDryer.d.ts +0 -58
  37. package/dist/devices/laundryDryer.js +3 -62
  38. package/dist/devices/laundryWasher.d.ts +0 -64
  39. package/dist/devices/laundryWasher.js +4 -70
  40. package/dist/devices/microwaveOven.d.ts +1 -77
  41. package/dist/devices/microwaveOven.js +5 -88
  42. package/dist/devices/oven.d.ts +0 -82
  43. package/dist/devices/oven.js +0 -85
  44. package/dist/devices/refrigerator.d.ts +0 -100
  45. package/dist/devices/refrigerator.js +0 -102
  46. package/dist/devices/roboticVacuumCleaner.d.ts +0 -83
  47. package/dist/devices/roboticVacuumCleaner.js +9 -100
  48. package/dist/devices/solarPower.d.ts +0 -36
  49. package/dist/devices/solarPower.js +0 -38
  50. package/dist/devices/speaker.d.ts +0 -79
  51. package/dist/devices/speaker.js +0 -84
  52. package/dist/devices/temperatureControl.d.ts +0 -21
  53. package/dist/devices/temperatureControl.js +3 -24
  54. package/dist/devices/waterHeater.d.ts +0 -74
  55. package/dist/devices/waterHeater.js +2 -82
  56. package/dist/frontend.d.ts +4 -187
  57. package/dist/frontend.js +89 -505
  58. package/dist/frontendTypes.d.ts +0 -57
  59. package/dist/frontendTypes.js +0 -45
  60. package/dist/helpers.d.ts +0 -43
  61. package/dist/helpers.js +1 -54
  62. package/dist/index.d.ts +0 -23
  63. package/dist/index.js +0 -25
  64. package/dist/jestutils/export.d.ts +0 -1
  65. package/dist/jestutils/export.js +0 -1
  66. package/dist/jestutils/jestHelpers.d.ts +0 -255
  67. package/dist/jestutils/jestHelpers.js +16 -379
  68. package/dist/logger/export.d.ts +0 -1
  69. package/dist/logger/export.js +0 -1
  70. package/dist/matter/behaviors.d.ts +0 -1
  71. package/dist/matter/behaviors.js +0 -2
  72. package/dist/matter/clusters.d.ts +0 -1
  73. package/dist/matter/clusters.js +0 -2
  74. package/dist/matter/devices.d.ts +0 -1
  75. package/dist/matter/devices.js +0 -2
  76. package/dist/matter/endpoints.d.ts +0 -1
  77. package/dist/matter/endpoints.js +0 -2
  78. package/dist/matter/export.d.ts +0 -1
  79. package/dist/matter/export.js +0 -2
  80. package/dist/matter/types.d.ts +0 -1
  81. package/dist/matter/types.js +0 -2
  82. package/dist/matterNode.d.ts +0 -258
  83. package/dist/matterNode.js +9 -364
  84. package/dist/matterbridge.d.ts +0 -362
  85. package/dist/matterbridge.js +75 -864
  86. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -36
  87. package/dist/matterbridgeAccessoryPlatform.js +0 -38
  88. package/dist/matterbridgeBehaviors.d.ts +0 -24
  89. package/dist/matterbridgeBehaviors.js +5 -68
  90. package/dist/matterbridgeDeviceTypes.d.ts +0 -649
  91. package/dist/matterbridgeDeviceTypes.js +6 -673
  92. package/dist/matterbridgeDynamicPlatform.d.ts +0 -36
  93. package/dist/matterbridgeDynamicPlatform.js +0 -38
  94. package/dist/matterbridgeEndpoint.d.ts +2 -1332
  95. package/dist/matterbridgeEndpoint.js +94 -1459
  96. package/dist/matterbridgeEndpointHelpers.d.ts +0 -425
  97. package/dist/matterbridgeEndpointHelpers.js +22 -487
  98. package/dist/matterbridgeEndpointTypes.d.ts +0 -70
  99. package/dist/matterbridgeEndpointTypes.js +0 -25
  100. package/dist/matterbridgePlatform.d.ts +0 -425
  101. package/dist/matterbridgePlatform.js +2 -453
  102. package/dist/matterbridgeTypes.d.ts +0 -46
  103. package/dist/matterbridgeTypes.js +0 -26
  104. package/dist/mb_coap.d.ts +1 -0
  105. package/dist/{dgram/mb_coap.js → mb_coap.js} +3 -41
  106. package/dist/mb_mdns.d.ts +1 -0
  107. package/dist/{dgram/mb_mdns.js → mb_mdns.js} +47 -81
  108. package/dist/pluginManager.d.ts +0 -305
  109. package/dist/pluginManager.js +8 -345
  110. package/dist/shelly.d.ts +0 -157
  111. package/dist/shelly.js +7 -178
  112. package/dist/spawn.d.ts +1 -0
  113. package/dist/{utils/spawn.js → spawn.js} +3 -73
  114. package/dist/storage/export.d.ts +0 -1
  115. package/dist/storage/export.js +0 -1
  116. package/dist/update.d.ts +0 -75
  117. package/dist/update.js +7 -100
  118. package/dist/utils/export.d.ts +1 -13
  119. package/dist/utils/export.js +1 -13
  120. package/dist/workerGlobalPrefix.d.ts +0 -24
  121. package/dist/workerGlobalPrefix.js +6 -40
  122. package/dist/workerTypes.d.ts +0 -25
  123. package/dist/workerTypes.js +0 -24
  124. package/dist/workers.d.ts +0 -61
  125. package/dist/workers.js +4 -68
  126. package/npm-shrinkwrap.json +80 -50
  127. package/package.json +8 -8
  128. package/dist/broadcastServer.d.ts.map +0 -1
  129. package/dist/broadcastServer.js.map +0 -1
  130. package/dist/broadcastServerTypes.d.ts.map +0 -1
  131. package/dist/broadcastServerTypes.js.map +0 -1
  132. package/dist/cli.d.ts.map +0 -1
  133. package/dist/cli.js.map +0 -1
  134. package/dist/cliEmitter.d.ts.map +0 -1
  135. package/dist/cliEmitter.js.map +0 -1
  136. package/dist/cliHistory.d.ts.map +0 -1
  137. package/dist/cliHistory.js.map +0 -1
  138. package/dist/clusters/export.d.ts.map +0 -1
  139. package/dist/clusters/export.js.map +0 -1
  140. package/dist/deviceManager.d.ts.map +0 -1
  141. package/dist/deviceManager.js.map +0 -1
  142. package/dist/devices/airConditioner.d.ts.map +0 -1
  143. package/dist/devices/airConditioner.js.map +0 -1
  144. package/dist/devices/batteryStorage.d.ts.map +0 -1
  145. package/dist/devices/batteryStorage.js.map +0 -1
  146. package/dist/devices/cooktop.d.ts.map +0 -1
  147. package/dist/devices/cooktop.js.map +0 -1
  148. package/dist/devices/dishwasher.d.ts.map +0 -1
  149. package/dist/devices/dishwasher.js.map +0 -1
  150. package/dist/devices/evse.d.ts.map +0 -1
  151. package/dist/devices/evse.js.map +0 -1
  152. package/dist/devices/export.d.ts.map +0 -1
  153. package/dist/devices/export.js.map +0 -1
  154. package/dist/devices/extractorHood.d.ts.map +0 -1
  155. package/dist/devices/extractorHood.js.map +0 -1
  156. package/dist/devices/heatPump.d.ts.map +0 -1
  157. package/dist/devices/heatPump.js.map +0 -1
  158. package/dist/devices/laundryDryer.d.ts.map +0 -1
  159. package/dist/devices/laundryDryer.js.map +0 -1
  160. package/dist/devices/laundryWasher.d.ts.map +0 -1
  161. package/dist/devices/laundryWasher.js.map +0 -1
  162. package/dist/devices/microwaveOven.d.ts.map +0 -1
  163. package/dist/devices/microwaveOven.js.map +0 -1
  164. package/dist/devices/oven.d.ts.map +0 -1
  165. package/dist/devices/oven.js.map +0 -1
  166. package/dist/devices/refrigerator.d.ts.map +0 -1
  167. package/dist/devices/refrigerator.js.map +0 -1
  168. package/dist/devices/roboticVacuumCleaner.d.ts.map +0 -1
  169. package/dist/devices/roboticVacuumCleaner.js.map +0 -1
  170. package/dist/devices/solarPower.d.ts.map +0 -1
  171. package/dist/devices/solarPower.js.map +0 -1
  172. package/dist/devices/speaker.d.ts.map +0 -1
  173. package/dist/devices/speaker.js.map +0 -1
  174. package/dist/devices/temperatureControl.d.ts.map +0 -1
  175. package/dist/devices/temperatureControl.js.map +0 -1
  176. package/dist/devices/waterHeater.d.ts.map +0 -1
  177. package/dist/devices/waterHeater.js.map +0 -1
  178. package/dist/dgram/coap.d.ts +0 -205
  179. package/dist/dgram/coap.d.ts.map +0 -1
  180. package/dist/dgram/coap.js +0 -365
  181. package/dist/dgram/coap.js.map +0 -1
  182. package/dist/dgram/dgram.d.ts +0 -144
  183. package/dist/dgram/dgram.d.ts.map +0 -1
  184. package/dist/dgram/dgram.js +0 -363
  185. package/dist/dgram/dgram.js.map +0 -1
  186. package/dist/dgram/mb_coap.d.ts +0 -24
  187. package/dist/dgram/mb_coap.d.ts.map +0 -1
  188. package/dist/dgram/mb_coap.js.map +0 -1
  189. package/dist/dgram/mb_mdns.d.ts +0 -24
  190. package/dist/dgram/mb_mdns.d.ts.map +0 -1
  191. package/dist/dgram/mb_mdns.js.map +0 -1
  192. package/dist/dgram/mdns.d.ts +0 -371
  193. package/dist/dgram/mdns.d.ts.map +0 -1
  194. package/dist/dgram/mdns.js +0 -934
  195. package/dist/dgram/mdns.js.map +0 -1
  196. package/dist/dgram/multicast.d.ts +0 -67
  197. package/dist/dgram/multicast.d.ts.map +0 -1
  198. package/dist/dgram/multicast.js +0 -179
  199. package/dist/dgram/multicast.js.map +0 -1
  200. package/dist/dgram/unicast.d.ts +0 -64
  201. package/dist/dgram/unicast.d.ts.map +0 -1
  202. package/dist/dgram/unicast.js +0 -100
  203. package/dist/dgram/unicast.js.map +0 -1
  204. package/dist/frontend.d.ts.map +0 -1
  205. package/dist/frontend.js.map +0 -1
  206. package/dist/frontendTypes.d.ts.map +0 -1
  207. package/dist/frontendTypes.js.map +0 -1
  208. package/dist/helpers.d.ts.map +0 -1
  209. package/dist/helpers.js.map +0 -1
  210. package/dist/index.d.ts.map +0 -1
  211. package/dist/index.js.map +0 -1
  212. package/dist/jestutils/export.d.ts.map +0 -1
  213. package/dist/jestutils/export.js.map +0 -1
  214. package/dist/jestutils/jestHelpers.d.ts.map +0 -1
  215. package/dist/jestutils/jestHelpers.js.map +0 -1
  216. package/dist/logger/export.d.ts.map +0 -1
  217. package/dist/logger/export.js.map +0 -1
  218. package/dist/matter/behaviors.d.ts.map +0 -1
  219. package/dist/matter/behaviors.js.map +0 -1
  220. package/dist/matter/clusters.d.ts.map +0 -1
  221. package/dist/matter/clusters.js.map +0 -1
  222. package/dist/matter/devices.d.ts.map +0 -1
  223. package/dist/matter/devices.js.map +0 -1
  224. package/dist/matter/endpoints.d.ts.map +0 -1
  225. package/dist/matter/endpoints.js.map +0 -1
  226. package/dist/matter/export.d.ts.map +0 -1
  227. package/dist/matter/export.js.map +0 -1
  228. package/dist/matter/types.d.ts.map +0 -1
  229. package/dist/matter/types.js.map +0 -1
  230. package/dist/matterNode.d.ts.map +0 -1
  231. package/dist/matterNode.js.map +0 -1
  232. package/dist/matterbridge.d.ts.map +0 -1
  233. package/dist/matterbridge.js.map +0 -1
  234. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  235. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  236. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  237. package/dist/matterbridgeBehaviors.js.map +0 -1
  238. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  239. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  240. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  241. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  242. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  243. package/dist/matterbridgeEndpoint.js.map +0 -1
  244. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  245. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  246. package/dist/matterbridgeEndpointTypes.d.ts.map +0 -1
  247. package/dist/matterbridgeEndpointTypes.js.map +0 -1
  248. package/dist/matterbridgePlatform.d.ts.map +0 -1
  249. package/dist/matterbridgePlatform.js.map +0 -1
  250. package/dist/matterbridgeTypes.d.ts.map +0 -1
  251. package/dist/matterbridgeTypes.js.map +0 -1
  252. package/dist/pluginManager.d.ts.map +0 -1
  253. package/dist/pluginManager.js.map +0 -1
  254. package/dist/shelly.d.ts.map +0 -1
  255. package/dist/shelly.js.map +0 -1
  256. package/dist/storage/export.d.ts.map +0 -1
  257. package/dist/storage/export.js.map +0 -1
  258. package/dist/update.d.ts.map +0 -1
  259. package/dist/update.js.map +0 -1
  260. package/dist/utils/colorUtils.d.ts +0 -101
  261. package/dist/utils/colorUtils.d.ts.map +0 -1
  262. package/dist/utils/colorUtils.js +0 -282
  263. package/dist/utils/colorUtils.js.map +0 -1
  264. package/dist/utils/commandLine.d.ts +0 -66
  265. package/dist/utils/commandLine.d.ts.map +0 -1
  266. package/dist/utils/commandLine.js +0 -123
  267. package/dist/utils/commandLine.js.map +0 -1
  268. package/dist/utils/copyDirectory.d.ts +0 -35
  269. package/dist/utils/copyDirectory.d.ts.map +0 -1
  270. package/dist/utils/copyDirectory.js +0 -76
  271. package/dist/utils/copyDirectory.js.map +0 -1
  272. package/dist/utils/createDirectory.d.ts +0 -34
  273. package/dist/utils/createDirectory.d.ts.map +0 -1
  274. package/dist/utils/createDirectory.js +0 -54
  275. package/dist/utils/createDirectory.js.map +0 -1
  276. package/dist/utils/createZip.d.ts +0 -39
  277. package/dist/utils/createZip.d.ts.map +0 -1
  278. package/dist/utils/createZip.js +0 -114
  279. package/dist/utils/createZip.js.map +0 -1
  280. package/dist/utils/deepCopy.d.ts +0 -32
  281. package/dist/utils/deepCopy.d.ts.map +0 -1
  282. package/dist/utils/deepCopy.js +0 -79
  283. package/dist/utils/deepCopy.js.map +0 -1
  284. package/dist/utils/deepEqual.d.ts +0 -54
  285. package/dist/utils/deepEqual.d.ts.map +0 -1
  286. package/dist/utils/deepEqual.js +0 -129
  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 +0 -54
  291. package/dist/utils/error.js.map +0 -1
  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 +0 -78
  297. package/dist/utils/format.js.map +0 -1
  298. package/dist/utils/hex.d.ts +0 -89
  299. package/dist/utils/hex.d.ts.map +0 -1
  300. package/dist/utils/hex.js +0 -242
  301. package/dist/utils/hex.js.map +0 -1
  302. package/dist/utils/inspector.d.ts +0 -87
  303. package/dist/utils/inspector.d.ts.map +0 -1
  304. package/dist/utils/inspector.js +0 -268
  305. package/dist/utils/inspector.js.map +0 -1
  306. package/dist/utils/isValid.d.ts +0 -103
  307. package/dist/utils/isValid.d.ts.map +0 -1
  308. package/dist/utils/isValid.js +0 -162
  309. package/dist/utils/isValid.js.map +0 -1
  310. package/dist/utils/network.d.ts +0 -141
  311. package/dist/utils/network.d.ts.map +0 -1
  312. package/dist/utils/network.js +0 -314
  313. package/dist/utils/network.js.map +0 -1
  314. package/dist/utils/spawn.d.ts +0 -33
  315. package/dist/utils/spawn.d.ts.map +0 -1
  316. package/dist/utils/spawn.js.map +0 -1
  317. package/dist/utils/tracker.d.ts +0 -108
  318. package/dist/utils/tracker.d.ts.map +0 -1
  319. package/dist/utils/tracker.js +0 -264
  320. package/dist/utils/tracker.js.map +0 -1
  321. package/dist/utils/wait.d.ts +0 -54
  322. package/dist/utils/wait.d.ts.map +0 -1
  323. package/dist/utils/wait.js +0 -125
  324. package/dist/utils/wait.js.map +0 -1
  325. package/dist/workerGlobalPrefix.d.ts.map +0 -1
  326. package/dist/workerGlobalPrefix.js.map +0 -1
  327. package/dist/workerTypes.d.ts.map +0 -1
  328. package/dist/workerTypes.js.map +0 -1
  329. package/dist/workers.d.ts.map +0 -1
  330. package/dist/workers.js.map +0 -1
@@ -1,53 +1,20 @@
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, { unlinkSync } 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 { 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
- import { getParameter, getIntParameter, hasParameter } from './utils/commandLine.js';
47
- import { copyDirectory } from './utils/copyDirectory.js';
48
- import { createDirectory } from './utils/createDirectory.js';
49
- import { isValidString, parseVersionString, isValidNumber, isValidObject } from './utils/isValid.js';
50
- import { formatBytes, formatPercent, formatUptime } from './utils/format.js';
17
+ import { copyDirectory, createDirectory, formatBytes, formatPercent, formatUptime, getIntParameter, getParameter, hasParameter, isValidNumber, isValidObject, isValidString, parseVersionString } from '@matterbridge/utils';
51
18
  import { dev, MATTER_LOGGER_FILE, MATTER_STORAGE_NAME, MATTERBRIDGE_LOGGER_FILE, NODE_STORAGE_DIR, plg, typ } from './matterbridgeTypes.js';
52
19
  import { PluginManager } from './pluginManager.js';
53
20
  import { DeviceManager } from './deviceManager.js';
@@ -56,27 +23,19 @@ import { bridge } from './matterbridgeDeviceTypes.js';
56
23
  import { Frontend } from './frontend.js';
57
24
  import { addVirtualDevice, addVirtualDevices } from './helpers.js';
58
25
  import { BroadcastServer } from './broadcastServer.js';
59
- /**
60
- * Represents the Matterbridge application.
61
- */
62
26
  export class Matterbridge extends EventEmitter {
63
- /** Matterbridge system information */
64
27
  systemInformation = {
65
- // Network properties
66
28
  interfaceName: '',
67
29
  macAddress: '',
68
30
  ipv4Address: '',
69
31
  ipv6Address: '',
70
- // Node.js properties
71
32
  nodeVersion: '',
72
- // Fixed system properties
73
33
  hostname: '',
74
34
  user: '',
75
35
  osType: '',
76
36
  osRelease: '',
77
37
  osPlatform: '',
78
38
  osArch: '',
79
- // Cpu and memory properties
80
39
  totalMemory: '',
81
40
  freeMemory: '',
82
41
  systemUptime: '',
@@ -87,66 +46,39 @@ export class Matterbridge extends EventEmitter {
87
46
  heapTotal: '',
88
47
  heapUsed: '',
89
48
  };
90
- // Matterbridge settings
91
- /** It indicates the home directory of the Matterbridge application. The home directory is the base directory where Matterbridge creates the matterbridge directories (os.homedir() if not overridden). */
92
49
  homeDirectory = '';
93
- /** It indicates the root directory of the Matterbridge application. The root directory is the directory where Matterbridge is executed. */
94
50
  rootDirectory = '';
95
- /** It indicates where the directory .matterbridge is located. */
96
51
  matterbridgeDirectory = '';
97
- /** It indicates where the directory Matterbridge is located. */
98
52
  matterbridgePluginDirectory = '';
99
- /** It indicates where the directory .mattercert is located. */
100
53
  matterbridgeCertDirectory = '';
101
- /** It indicates the global modules directory for npm. */
102
54
  globalModulesDirectory = '';
103
55
  matterbridgeVersion = '';
104
56
  matterbridgeLatestVersion = '';
105
57
  matterbridgeDevVersion = '';
106
58
  frontendVersion = '';
107
- /** It indicates the mode of the Matterbridge instance. It can be 'bridge', 'childbridge', 'controller' or ''. */
108
59
  bridgeMode = '';
109
- /** It indicates the restart mode of the Matterbridge instance. It can be 'service', 'docker' or ''. */
110
60
  restartMode = '';
111
- /** It indicates whether virtual mode is enabled and its type. The virtual mode control the creation of "Update matterbridge" and "Restart matterbridge" endpoints. */
112
61
  virtualMode = 'outlet';
113
- /** It indicates the Matterbridge profile in use. */
114
62
  profile = getParameter('profile');
115
- /** Matterbridge logger */
116
- log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
117
- /** Matterbridge logger level */
63
+ log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
118
64
  logLevel = this.log.logLevel;
119
- /** Whether to log to a file */
120
65
  fileLogger = false;
121
- /** Matter logger */
122
- matterLog = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
123
- /** Matter logger level */
66
+ matterLog = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
124
67
  matterLogLevel = this.matterLog.logLevel;
125
- /** Whether to log Matter to a file */
126
68
  matterFileLogger = false;
127
- // Frontend settings
128
69
  readOnly = hasParameter('readonly') || hasParameter('shelly');
129
70
  shellyBoard = hasParameter('shelly');
130
71
  shellySysUpdate = false;
131
72
  shellyMainUpdate = false;
132
- /** It indicates whether a restart is required. It can be unset in childbridge mode by restarting the plugin that triggered the restart. */
133
73
  restartRequired = false;
134
- /** It indicates whether a fixed restart is required. It cannot be unset once set. */
135
74
  fixedRestartRequired = false;
136
- /** It indicates whether an update is available. */
137
75
  updateRequired = false;
138
- // Managers
139
76
  plugins = new PluginManager(this);
140
77
  devices = new DeviceManager();
141
- // Frontend
142
78
  frontend = new Frontend(this);
143
- /** Matterbridge node storage manager created in the directory 'storage' in matterbridgeDirectory */
144
79
  nodeStorage;
145
- /** Matterbridge node context created with name 'matterbridge' */
146
80
  nodeContext;
147
- /** The main instance of the Matterbridge class (singleton) */
148
81
  static instance;
149
- // Instance properties
150
82
  shutdown = false;
151
83
  failCountLimit = hasParameter('shelly') ? 600 : 120;
152
84
  hasCleanupStarted = false;
@@ -161,32 +93,19 @@ export class Matterbridge extends EventEmitter {
161
93
  sigtermHandler;
162
94
  exceptionHandler;
163
95
  rejectionHandler;
164
- /** Matter environment default */
165
96
  environment = Environment.default;
166
- /** Matter storage service from environment default */
167
97
  matterStorageService;
168
- /** Matter storage manager created with name 'Matterbridge' */
169
98
  matterStorageManager;
170
- /** Matter matterbridge storage context created in the storage manager with name 'persist' */
171
99
  matterbridgeContext;
172
100
  controllerContext;
173
- /** Matter mdns interface e.g. 'eth0' or 'wlan0' or 'Wi-Fi' */
174
101
  mdnsInterface;
175
- /** Matter listeningAddressIpv4 address */
176
102
  ipv4Address;
177
- /** Matter listeningAddressIpv6 address */
178
103
  ipv6Address;
179
- /** Matter commissioning port */
180
- port; // first server node port
181
- /** Matter commissioning passcode */
182
- passcode; // first server node passcode
183
- /** Matter commissioning discriminator */
184
- discriminator; // first server node discriminator
185
- /** Matter device certification */
186
- certification; // device certification
187
- /** Matter server node in bridge mode */
104
+ port;
105
+ passcode;
106
+ discriminator;
107
+ certification;
188
108
  serverNode;
189
- /** Matter aggregator node in bridge mode */
190
109
  aggregatorNode;
191
110
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
192
111
  aggregatorVendorName = getParameter('vendorName') ?? 'Matterbridge';
@@ -195,12 +114,9 @@ export class Matterbridge extends EventEmitter {
195
114
  aggregatorDeviceType = DeviceTypeId(getIntParameter('deviceType') ?? bridge.code);
196
115
  aggregatorSerialNumber = getParameter('serialNumber');
197
116
  aggregatorUniqueId = getParameter('uniqueId');
198
- /** Advertising nodes map: time advertising started keyed by storeId */
199
117
  advertisingNodes = new Map();
200
- /** Broadcast server */
201
118
  server;
202
119
  verbose = hasParameter('verbose');
203
- /** We load asyncronously so is private */
204
120
  constructor() {
205
121
  super();
206
122
  this.log.logNameColor = '\x1b[38;5;115m';
@@ -251,19 +167,8 @@ export class Matterbridge extends EventEmitter {
251
167
  }
252
168
  }
253
169
  }
254
- //* ************************************************************************************************************************************ */
255
- // loadInstance() and cleanup() methods */
256
- //* ************************************************************************************************************************************ */
257
- /**
258
- * Loads an instance of the Matterbridge class.
259
- * If an instance already exists, return that instance.
260
- *
261
- * @param {boolean} initialize - Whether to initialize the Matterbridge instance after loading. Defaults to false.
262
- * @returns {Matterbridge} A promise that resolves to the Matterbridge instance.
263
- */
264
170
  static async loadInstance(initialize = false) {
265
171
  if (!Matterbridge.instance) {
266
- // eslint-disable-next-line no-console
267
172
  if (hasParameter('debug'))
268
173
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
269
174
  Matterbridge.instance = new Matterbridge();
@@ -272,84 +177,56 @@ export class Matterbridge extends EventEmitter {
272
177
  }
273
178
  return Matterbridge.instance;
274
179
  }
275
- /**
276
- * Initializes the Matterbridge application.
277
- *
278
- * @remarks
279
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
280
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
281
- * node version, registers signal handlers, initializes storage, and parses the command line.
282
- *
283
- * @returns {Promise<void>} A Promise that resolves when the initialization is complete.
284
- */
285
180
  async initialize() {
286
- // for (let i = 1; i <= 255; i++) console.log(`\x1b[38;5;${i}mColor: ${i}`);
287
- // Emit the initialize_started event
288
181
  this.emit('initialize_started');
289
- // Set the restart mode
290
182
  if (hasParameter('service'))
291
183
  this.restartMode = 'service';
292
184
  if (hasParameter('docker'))
293
185
  this.restartMode = 'docker';
294
- // Set the matterbridge home directory
295
186
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
296
187
  await createDirectory(this.homeDirectory, 'Matterbridge Home Directory', this.log);
297
- // Set the matterbridge directory
298
188
  this.matterbridgeDirectory = this.profile ? path.join(this.homeDirectory, '.matterbridge', 'profiles', this.profile) : path.join(this.homeDirectory, '.matterbridge');
299
189
  await createDirectory(this.matterbridgeDirectory, 'Matterbridge Directory', this.log);
300
190
  await createDirectory(path.join(this.matterbridgeDirectory, 'certs'), 'Matterbridge Frontend Certificate Directory', this.log);
301
191
  await createDirectory(path.join(this.matterbridgeDirectory, 'uploads'), 'Matterbridge Frontend Uploads Directory', this.log);
302
- // Set the matterbridge plugin directory
303
192
  this.matterbridgePluginDirectory = this.profile ? path.join(this.homeDirectory, 'Matterbridge', 'profiles', this.profile) : path.join(this.homeDirectory, 'Matterbridge');
304
193
  await createDirectory(this.matterbridgePluginDirectory, 'Matterbridge Plugin Directory', this.log);
305
- // Set the matterbridge cert directory
306
194
  this.matterbridgeCertDirectory = this.profile ? path.join(this.homeDirectory, '.mattercert', 'profiles', this.profile) : path.join(this.homeDirectory, '.mattercert');
307
195
  await createDirectory(this.matterbridgeCertDirectory, 'Matterbridge Matter Certificate Directory', this.log);
308
- // Set the matterbridge root directory
309
196
  const { fileURLToPath } = await import('node:url');
310
197
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
311
- this.rootDirectory = path.resolve(currentFileDirectory, '../'); // Adjust the path for dist directory
312
- // Setup the matter environment with default values
198
+ this.rootDirectory = path.resolve(currentFileDirectory, '../');
313
199
  this.environment.vars.set('log.level', MatterLogLevel.INFO);
314
200
  this.environment.vars.set('log.format', MatterLogFormat.ANSI);
315
201
  this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME));
316
202
  this.environment.vars.set('runtime.signals', false);
317
203
  this.environment.vars.set('runtime.exitcode', false);
318
- // Register process handlers
319
204
  this.registerProcessHandlers();
320
- // Initialize nodeStorage and nodeContext
321
205
  try {
322
206
  this.log.debug(`Creating node storage manager: ${CYAN}${NODE_STORAGE_DIR}${db}`);
323
207
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, NODE_STORAGE_DIR), writeQueue: false, expiredInterval: undefined, logging: false });
324
208
  this.log.debug('Creating node storage context for matterbridge');
325
209
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
326
- // TODO: Remove this code when node-persist-manager is updated
327
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
328
210
  const keys = (await this.nodeStorage?.storage.keys());
329
211
  for (const key of keys) {
330
212
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
331
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
332
213
  await this.nodeStorage?.storage.get(key);
333
214
  }
334
215
  const storages = await this.nodeStorage.getStorageNames();
335
216
  for (const storage of storages) {
336
217
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
337
218
  const nodeContext = await this.nodeStorage?.createStorage(storage);
338
- // TODO: Remove this code when node-persist-manager is updated
339
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
340
219
  const keys = (await nodeContext?.storage.keys());
341
220
  keys.forEach(async (key) => {
342
221
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
343
222
  await nodeContext?.get(key);
344
223
  });
345
224
  }
346
- // Creating a backup of the node storage since it is not corrupted
347
225
  this.log.debug('Creating node storage backup...');
348
226
  await copyDirectory(path.join(this.matterbridgeDirectory, NODE_STORAGE_DIR), path.join(this.matterbridgeDirectory, NODE_STORAGE_DIR + '.backup'));
349
227
  this.log.debug('Created node storage backup');
350
228
  }
351
229
  catch (error) {
352
- // Restoring the backup of the node storage since it is corrupted
353
230
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
354
231
  if (hasParameter('norestore')) {
355
232
  this.log.fatal(`The matterbridge storage is corrupted. Found -norestore parameter: exiting...`);
@@ -363,19 +240,14 @@ export class Matterbridge extends EventEmitter {
363
240
  if (!this.nodeStorage || !this.nodeContext) {
364
241
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
365
242
  }
366
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
367
243
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
368
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
369
244
  this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode')) ?? PaseClient.generateRandomPasscode(this.environment.get(Crypto));
370
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
371
245
  this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator')) ?? PaseClient.generateRandomDiscriminator(this.environment.get(Crypto));
372
- // Certificate management
373
246
  const pairingFilePath = path.join(this.matterbridgeCertDirectory, 'pairing.json');
374
247
  try {
375
248
  await fs.promises.access(pairingFilePath, fs.constants.R_OK);
376
249
  const pairingFileContent = await fs.promises.readFile(pairingFilePath, 'utf8');
377
250
  const pairingFileJson = JSON.parse(pairingFileContent);
378
- // Set the vendorId, vendorName, productId, productName, deviceType, serialNumber, uniqueId if they are present in the pairing file
379
251
  if (isValidNumber(pairingFileJson.vendorId)) {
380
252
  this.aggregatorVendorId = VendorId(pairingFileJson.vendorId);
381
253
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using vendorId ${CYAN}${this.aggregatorVendorId}${nf} from pairing file.`);
@@ -404,15 +276,13 @@ export class Matterbridge extends EventEmitter {
404
276
  this.aggregatorUniqueId = pairingFileJson.uniqueId;
405
277
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using uniqueId ${CYAN}${this.aggregatorUniqueId}${nf} from pairing file.`);
406
278
  }
407
- // Override the passcode and discriminator if they are present in the pairing file
408
279
  if (isValidNumber(pairingFileJson.passcode) && isValidNumber(pairingFileJson.discriminator)) {
409
280
  this.passcode = pairingFileJson.passcode;
410
281
  this.discriminator = pairingFileJson.discriminator;
411
282
  this.log.info(`Pairing file ${CYAN}${pairingFilePath}${nf} found. Using passcode ${CYAN}${this.passcode}${nf} and discriminator ${CYAN}${this.discriminator}${nf} from pairing file.`);
412
283
  }
413
- // Set the certification for matter.js if it is present in the pairing file
414
284
  if (pairingFileJson.privateKey && pairingFileJson.certificate && pairingFileJson.intermediateCertificate && pairingFileJson.declaration) {
415
- const { hexToBuffer } = await import('./utils/hex.js');
285
+ const { hexToBuffer } = await import('@matterbridge/utils');
416
286
  this.certification = {
417
287
  privateKey: hexToBuffer(pairingFileJson.privateKey),
418
288
  certificate: hexToBuffer(pairingFileJson.certificate),
@@ -425,44 +295,41 @@ export class Matterbridge extends EventEmitter {
425
295
  catch (error) {
426
296
  this.log.debug(`Pairing file ${CYAN}${pairingFilePath}${db} not found: ${error instanceof Error ? error.message : error}`);
427
297
  }
428
- // Store the passcode, discriminator and port in the node context
429
298
  await this.nodeContext.set('matterport', this.port);
430
299
  await this.nodeContext.set('matterpasscode', this.passcode);
431
300
  await this.nodeContext.set('matterdiscriminator', this.discriminator);
432
301
  this.log.debug(`Initializing server node for Matterbridge on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
433
- // Set matterbridge logger level (context: matterbridgeLogLevel)
434
302
  if (hasParameter('logger')) {
435
303
  const level = getParameter('logger');
436
304
  if (level === 'debug') {
437
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
305
+ this.log.logLevel = "debug";
438
306
  }
439
307
  else if (level === 'info') {
440
- this.log.logLevel = "info" /* LogLevel.INFO */;
308
+ this.log.logLevel = "info";
441
309
  }
442
310
  else if (level === 'notice') {
443
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
311
+ this.log.logLevel = "notice";
444
312
  }
445
313
  else if (level === 'warn') {
446
- this.log.logLevel = "warn" /* LogLevel.WARN */;
314
+ this.log.logLevel = "warn";
447
315
  }
448
316
  else if (level === 'error') {
449
- this.log.logLevel = "error" /* LogLevel.ERROR */;
317
+ this.log.logLevel = "error";
450
318
  }
451
319
  else if (level === 'fatal') {
452
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
320
+ this.log.logLevel = "fatal";
453
321
  }
454
322
  else {
455
323
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
456
- this.log.logLevel = "info" /* LogLevel.INFO */;
324
+ this.log.logLevel = "info";
457
325
  }
458
326
  }
459
327
  else {
460
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.shellyBoard ? "notice" /* LogLevel.NOTICE */ : "info" /* LogLevel.INFO */);
328
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.shellyBoard ? "notice" : "info");
461
329
  }
462
330
  this.logLevel = this.log.logLevel;
463
331
  this.frontend.logLevel = this.log.logLevel;
464
332
  MatterbridgeEndpoint.logLevel = this.log.logLevel;
465
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
466
333
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
467
334
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, MATTERBRIDGE_LOGGER_FILE), this.log.logLevel, true);
468
335
  this.fileLogger = true;
@@ -471,7 +338,6 @@ export class Matterbridge extends EventEmitter {
471
338
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.fileLogger}.`);
472
339
  if (this.profile !== undefined)
473
340
  this.log.debug(`Matterbridge profile: ${this.profile}.`);
474
- // Set matter.js logger level, format and logger (context: matterLogLevel)
475
341
  if (hasParameter('matterlogger')) {
476
342
  const level = getParameter('matterlogger');
477
343
  if (level === 'debug') {
@@ -502,13 +368,11 @@ export class Matterbridge extends EventEmitter {
502
368
  }
503
369
  Logger.format = MatterLogFormat.ANSI;
504
370
  this.matterLogLevel = MatterLogLevel.names[Logger.level];
505
- // Create the logger for matter.js with file logging (context: matterFileLog)
506
371
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
507
372
  this.matterFileLogger = true;
508
373
  }
509
374
  Logger.destinations.default.write = this.createDestinationMatterLogger(this.matterFileLogger);
510
375
  this.log.debug(`Matter logLevel: ${this.matterLogLevel} fileLoger: ${this.matterFileLogger}.`);
511
- // Log network interfaces
512
376
  const networkInterfaces = os.networkInterfaces();
513
377
  const availableAddresses = Object.entries(networkInterfaces);
514
378
  const availableInterfaceNames = Object.keys(networkInterfaces);
@@ -521,7 +385,6 @@ export class Matterbridge extends EventEmitter {
521
385
  });
522
386
  }
523
387
  }
524
- // Set the interface to use for matter server node mdnsInterface
525
388
  if (hasParameter('mdnsinterface')) {
526
389
  this.mdnsInterface = getParameter('mdnsinterface');
527
390
  }
@@ -530,7 +393,6 @@ export class Matterbridge extends EventEmitter {
530
393
  if (this.mdnsInterface === '')
531
394
  this.mdnsInterface = undefined;
532
395
  }
533
- // Validate mdnsInterface
534
396
  if (this.mdnsInterface) {
535
397
  if (!availableInterfaceNames.includes(this.mdnsInterface)) {
536
398
  this.log.error(`Invalid mdnsinterface: ${this.mdnsInterface}. Available interfaces are: ${availableInterfaceNames.join(', ')}. Using all available interfaces.`);
@@ -543,7 +405,6 @@ export class Matterbridge extends EventEmitter {
543
405
  }
544
406
  if (this.mdnsInterface)
545
407
  this.environment.vars.set('mdns.networkInterface', this.mdnsInterface);
546
- // Set the listeningAddressIpv4 for the matter commissioning server
547
408
  if (hasParameter('ipv4address')) {
548
409
  this.ipv4Address = getParameter('ipv4address');
549
410
  }
@@ -552,7 +413,6 @@ export class Matterbridge extends EventEmitter {
552
413
  if (this.ipv4Address === '')
553
414
  this.ipv4Address = undefined;
554
415
  }
555
- // Validate ipv4address
556
416
  if (this.ipv4Address) {
557
417
  let isValid = false;
558
418
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -568,7 +428,6 @@ export class Matterbridge extends EventEmitter {
568
428
  await this.nodeContext.remove('matteripv4address');
569
429
  }
570
430
  }
571
- // Set the listeningAddressIpv6 for the matter commissioning server
572
431
  if (hasParameter('ipv6address')) {
573
432
  this.ipv6Address = getParameter('ipv6address');
574
433
  }
@@ -577,7 +436,6 @@ export class Matterbridge extends EventEmitter {
577
436
  if (this.ipv6Address === '')
578
437
  this.ipv6Address = undefined;
579
438
  }
580
- // Validate ipv6address
581
439
  if (this.ipv6Address) {
582
440
  let isValid = false;
583
441
  for (const [ifaceName, ifaces] of availableAddresses) {
@@ -586,7 +444,6 @@ export class Matterbridge extends EventEmitter {
586
444
  isValid = true;
587
445
  break;
588
446
  }
589
- /* istanbul ignore next */
590
447
  if (ifaces && ifaces.find((iface) => iface.scopeid && iface.scopeid > 0 && iface.address + '%' + (process.platform === 'win32' ? iface.scopeid : ifaceName) === this.ipv6Address)) {
591
448
  this.log.info(`Using ipv6address ${CYAN}${this.ipv6Address}${nf} on interface ${CYAN}${ifaceName}${nf} for the Matter server node.`);
592
449
  isValid = true;
@@ -599,7 +456,6 @@ export class Matterbridge extends EventEmitter {
599
456
  await this.nodeContext.remove('matteripv6address');
600
457
  }
601
458
  }
602
- // Initialize the virtual mode
603
459
  if (hasParameter('novirtual')) {
604
460
  this.virtualMode = 'disabled';
605
461
  await this.nodeContext.set('virtualmode', 'disabled');
@@ -608,18 +464,13 @@ export class Matterbridge extends EventEmitter {
608
464
  this.virtualMode = (await this.nodeContext.get('virtualmode', 'outlet'));
609
465
  }
610
466
  this.log.debug(`Virtual mode ${this.virtualMode}.`);
611
- // Initialize PluginManager
612
467
  this.plugins.logLevel = this.log.logLevel;
613
468
  await this.plugins.loadFromStorage();
614
- // Initialize DeviceManager
615
469
  this.devices.logLevel = this.log.logLevel;
616
- // Get the plugins from node storage and create the plugins node storage contexts
617
470
  for (const plugin of this.plugins) {
618
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
619
- // We don't do this when the add and other shutdown parameters are set because we shut down the process after adding the plugin
620
471
  if (!fs.existsSync(plugin.path) && !hasParameter('add') && !hasParameter('remove') && !hasParameter('enable') && !hasParameter('disable') && !hasParameter('reset') && !hasParameter('factoryreset')) {
621
472
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm...`);
622
- const { spawnCommand } = await import('./utils/spawn.js');
473
+ const { spawnCommand } = await import('./spawn.js');
623
474
  if (await spawnCommand('npm', ['install', '-g', `${plugin.name}${plugin.version.includes('-dev-') ? '@dev' : ''}`, '--omit=dev', '--verbose'], 'install', plugin.name)) {
624
475
  this.log.info(`Plugin ${plg}${plugin.name}${nf} reinstalled.`);
625
476
  plugin.error = false;
@@ -646,7 +497,6 @@ export class Matterbridge extends EventEmitter {
646
497
  await plugin.nodeContext.set('description', plugin.description);
647
498
  await plugin.nodeContext.set('author', plugin.author);
648
499
  }
649
- // Log system info and create .matterbridge directory
650
500
  await this.logNodeAndSystemInfo();
651
501
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
652
502
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -654,7 +504,6 @@ export class Matterbridge extends EventEmitter {
654
504
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
655
505
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
656
506
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
657
- // Check node version and throw error
658
507
  const minNodeVersion = 20;
659
508
  const nodeVersion = process.versions.node;
660
509
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -662,18 +511,10 @@ export class Matterbridge extends EventEmitter {
662
511
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
663
512
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
664
513
  }
665
- // Parse command line
666
514
  await this.parseCommandLine();
667
- // Emit the initialize_completed event
668
515
  this.emit('initialize_completed');
669
516
  this.initialized = true;
670
517
  }
671
- /**
672
- * Parses the command line arguments and performs the corresponding actions.
673
- *
674
- * @private
675
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
676
- */
677
518
  async parseCommandLine() {
678
519
  if (hasParameter('list')) {
679
520
  this.log.info(`│ Registered plugins (${this.plugins.length})`);
@@ -689,19 +530,6 @@ export class Matterbridge extends EventEmitter {
689
530
  }
690
531
  index++;
691
532
  }
692
- /*
693
- const serializedRegisteredDevices = await this.nodeContext?.get<SerializedMatterbridgeEndpoint[]>('devices', []);
694
- this.log.info(`│ Registered devices (${serializedRegisteredDevices?.length})`);
695
- serializedRegisteredDevices?.forEach((device, index) => {
696
- if (index !== serializedRegisteredDevices.length - 1) {
697
- this.log.info(`├─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
698
- this.log.info(`│ └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
699
- } else {
700
- this.log.info(`└─┬─ plugin ${plg}${device.pluginName}${nf} device: ${dev}${device.deviceName}${nf} uniqueId: ${YELLOW}${device.uniqueId}${nf}`);
701
- this.log.info(` └─ endpoint ${RED}${device.endpoint}${nf} ${typ}${device.endpointName}${nf} ${debugStringify(device.clusterServersId)}`);
702
- }
703
- });
704
- */
705
533
  this.shutdown = true;
706
534
  return;
707
535
  }
@@ -716,7 +544,7 @@ export class Matterbridge extends EventEmitter {
716
544
  return;
717
545
  }
718
546
  if (hasParameter('loginterfaces')) {
719
- const { logInterfaces } = await import('./utils/network.js');
547
+ const { logInterfaces } = await import('@matterbridge/utils');
720
548
  logInterfaces();
721
549
  this.shutdown = true;
722
550
  return;
@@ -751,10 +579,8 @@ export class Matterbridge extends EventEmitter {
751
579
  this.shutdown = true;
752
580
  return;
753
581
  }
754
- // Initialize frontend
755
582
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
756
583
  await this.frontend.start(getIntParameter('frontend'));
757
- // Start the matter storage and create the matterbridge context
758
584
  try {
759
585
  await this.startMatterStorage();
760
586
  if (this.aggregatorSerialNumber && this.aggregatorUniqueId && this.matterStorageService) {
@@ -768,21 +594,18 @@ export class Matterbridge extends EventEmitter {
768
594
  this.log.fatal(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
769
595
  throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
770
596
  }
771
- // Clear the matterbridge context if the reset parameter is set (bridge mode)
772
597
  if (hasParameter('reset') && getParameter('reset') === undefined) {
773
598
  this.initialized = true;
774
599
  await this.shutdownProcessAndReset();
775
600
  this.shutdown = true;
776
601
  return;
777
602
  }
778
- // Clear matterbridge plugin context if the reset parameter is set (childbridge mode)
779
603
  if (hasParameter('reset') && getParameter('reset') !== undefined) {
780
604
  this.log.debug(`Reset plugin ${getParameter('reset')}`);
781
605
  const plugin = this.plugins.get(getParameter('reset'));
782
606
  if (plugin) {
783
607
  const matterStorageManager = await this.matterStorageService?.open(plugin.name);
784
608
  if (!matterStorageManager) {
785
- /* istanbul ignore next */
786
609
  this.log.error(`Plugin ${plg}${plugin.name}${er} storageManager not found`);
787
610
  }
788
611
  else {
@@ -801,56 +624,47 @@ export class Matterbridge extends EventEmitter {
801
624
  this.shutdown = true;
802
625
  return;
803
626
  }
804
- // Check in 5 minutes the latest and dev versions of matterbridge and the plugins
805
627
  clearTimeout(this.checkUpdateTimeout);
806
628
  this.checkUpdateTimeout = setTimeout(async () => {
807
629
  const { checkUpdates } = await import('./update.js');
808
630
  checkUpdates(this);
809
631
  }, 300 * 1000).unref();
810
- // Check each 12 hours the latest and dev versions of matterbridge and the plugins
811
632
  clearInterval(this.checkUpdateInterval);
812
633
  this.checkUpdateInterval = setInterval(async () => {
813
634
  const { checkUpdates } = await import('./update.js');
814
635
  checkUpdates(this);
815
636
  }, 12 * 60 * 60 * 1000).unref();
816
- // Start the matterbridge in mode test
817
637
  if (hasParameter('test')) {
818
638
  this.bridgeMode = 'bridge';
819
639
  return;
820
640
  }
821
- // Start the matterbridge in mode controller
822
641
  if (hasParameter('controller')) {
823
642
  this.bridgeMode = 'controller';
824
643
  await this.startController();
825
644
  return;
826
645
  }
827
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
828
646
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
829
647
  this.log.info('Setting default matterbridge start mode to bridge');
830
648
  await this.nodeContext?.set('bridgeMode', 'bridge');
831
649
  }
832
- // Wait delay if specified (default 2 minutes) and the system uptime is less than 5 minutes. It solves race conditions on system startup.
833
650
  if (hasParameter('delay') && os.uptime() <= 60 * 5) {
834
- const { wait } = await import('./utils/wait.js');
651
+ const { wait } = await import('@matterbridge/utils');
835
652
  const delay = getIntParameter('delay') || 120;
836
653
  this.log.warn('Delay switch found with system uptime less then 5 minutes. Waiting for ' + delay + ' seconds before starting matterbridge...');
837
654
  await wait(delay * 1000, 'Race condition delay', true);
838
655
  }
839
- // Wait delay if specified (default 2 minutes). It solves race conditions on docker compose startup.
840
656
  if (hasParameter('fixed_delay')) {
841
- const { wait } = await import('./utils/wait.js');
657
+ const { wait } = await import('@matterbridge/utils');
842
658
  const delay = getIntParameter('fixed_delay') || 120;
843
659
  this.log.warn('Fixed delay switch found. Waiting for ' + delay + ' seconds before starting matterbridge...');
844
660
  await wait(delay * 1000, 'Fixed race condition delay', true);
845
661
  }
846
- // Start matterbridge in bridge mode
847
662
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
848
663
  this.bridgeMode = 'bridge';
849
664
  this.log.debug(`Starting matterbridge in mode ${this.bridgeMode}`);
850
665
  await this.startBridge();
851
666
  return;
852
667
  }
853
- // Start matterbridge in childbridge mode
854
668
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
855
669
  this.bridgeMode = 'childbridge';
856
670
  this.log.debug(`Starting matterbridge in mode ${this.bridgeMode}`);
@@ -858,22 +672,10 @@ export class Matterbridge extends EventEmitter {
858
672
  return;
859
673
  }
860
674
  }
861
- /**
862
- * Asynchronously loads and starts the registered plugins.
863
- *
864
- * This method is responsible for initializing and starting all enabled plugins.
865
- * It ensures that each plugin is properly loaded and started before the bridge starts.
866
- *
867
- * @param {boolean} [wait] - If true, the method will wait for all plugins to be fully loaded and started before resolving. Defaults to false.
868
- * @param {boolean} [start] - If true, the method will start the plugins after loading them. Defaults to true.
869
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
870
- */
871
675
  async startPlugins(wait = false, start = true) {
872
- // Check, load and start the plugins
873
676
  for (const plugin of this.plugins) {
874
677
  plugin.configJson = await this.plugins.loadConfig(plugin);
875
678
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
876
- // Check if the plugin is available
877
679
  if (!(await this.plugins.resolve(plugin.path))) {
878
680
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
879
681
  plugin.enabled = false;
@@ -893,16 +695,10 @@ export class Matterbridge extends EventEmitter {
893
695
  if (wait)
894
696
  await this.plugins.load(plugin, start, 'Matterbridge is starting');
895
697
  else
896
- this.plugins.load(plugin, start, 'Matterbridge is starting'); // No await do it asyncronously
698
+ this.plugins.load(plugin, start, 'Matterbridge is starting');
897
699
  }
898
700
  this.frontend.wssSendRefreshRequired('plugins');
899
701
  }
900
- /**
901
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
902
- * - When an uncaught exception occurs, the exceptionHandler logs the error message and stack trace.
903
- * - When an unhandled promise rejection occurs, the rejectionHandler logs the reason and stack trace.
904
- * - When either of SIGINT and SIGTERM signals are received, the cleanup method is called with an appropriate message.
905
- */
906
702
  registerProcessHandlers() {
907
703
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
908
704
  process.removeAllListeners('uncaughtException');
@@ -929,9 +725,6 @@ export class Matterbridge extends EventEmitter {
929
725
  };
930
726
  process.on('SIGTERM', this.sigtermHandler);
931
727
  }
932
- /**
933
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
934
- */
935
728
  deregisterProcessHandlers() {
936
729
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
937
730
  if (this.exceptionHandler)
@@ -948,20 +741,7 @@ export class Matterbridge extends EventEmitter {
948
741
  process.off('SIGTERM', this.sigtermHandler);
949
742
  this.sigtermHandler = undefined;
950
743
  }
951
- /**
952
- * Logs the node and system information.
953
- *
954
- * @remarks
955
- * This method retrieves and logs various details about the host system, including:
956
- * - IP address information (IPv4, IPv6, MAC address)
957
- * - Node.js version
958
- * - Hostname and user information
959
- * - Operating system details (type, release, platform, architecture)
960
- * - Memory usage statistics
961
- * - Uptime information for both the system and the process
962
- */
963
744
  async logNodeAndSystemInfo() {
964
- // IP address information
965
745
  const excludedInterfaceNamePattern = /(tailscale|wireguard|openvpn|zerotier|hamachi|\bwg\d+\b|\btun\d+\b|\btap\d+\b|\butun\d+\b|docker|podman|\bveth[a-z0-9]*\b|\bbr-[a-z0-9]+\b|cni|kube|flannel|calico|virbr\d*\b|vmware|vmnet\d*\b|virtualbox|vboxnet\d*\b|teredo|isatap)/i;
966
746
  const networkInterfaces = os.networkInterfaces();
967
747
  this.systemInformation.interfaceName = '';
@@ -995,18 +775,16 @@ export class Matterbridge extends EventEmitter {
995
775
  break;
996
776
  }
997
777
  }
998
- // Node information
999
778
  this.systemInformation.nodeVersion = process.versions.node;
1000
779
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
1001
780
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
1002
781
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
1003
- // Host system information
1004
782
  this.systemInformation.hostname = os.hostname();
1005
783
  this.systemInformation.user = os.userInfo().username;
1006
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
1007
- this.systemInformation.osRelease = os.release(); // Kernel version
1008
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
1009
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
784
+ this.systemInformation.osType = os.type();
785
+ this.systemInformation.osRelease = os.release();
786
+ this.systemInformation.osPlatform = os.platform();
787
+ this.systemInformation.osArch = os.arch();
1010
788
  this.systemInformation.totalMemory = formatBytes(os.totalmem());
1011
789
  this.systemInformation.freeMemory = formatBytes(os.freemem());
1012
790
  this.systemInformation.systemUptime = formatUptime(os.uptime());
@@ -1016,7 +794,6 @@ export class Matterbridge extends EventEmitter {
1016
794
  this.systemInformation.rss = formatBytes(process.memoryUsage().rss);
1017
795
  this.systemInformation.heapTotal = formatBytes(process.memoryUsage().heapTotal);
1018
796
  this.systemInformation.heapUsed = formatBytes(process.memoryUsage().heapUsed);
1019
- // Log the system information
1020
797
  this.log.debug('Host System Information:');
1021
798
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
1022
799
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -1036,20 +813,17 @@ export class Matterbridge extends EventEmitter {
1036
813
  this.log.debug(`- RSS: ${this.systemInformation.rss}`);
1037
814
  this.log.debug(`- Heap Total: ${this.systemInformation.heapTotal}`);
1038
815
  this.log.debug(`- Heap Used: ${this.systemInformation.heapUsed}`);
1039
- // Log directories
1040
816
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
1041
817
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
1042
818
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
1043
819
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
1044
820
  this.log.debug(`Matterbridge Matter Certificate Directory: ${this.matterbridgeCertDirectory}`);
1045
- // Global node_modules directory
1046
821
  if (this.nodeContext)
1047
822
  this.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
1048
823
  if (this.globalModulesDirectory === '') {
1049
- // First run of Matterbridge so the node storage is empty
1050
824
  this.log.debug(`Getting global node_modules directory...`);
1051
825
  try {
1052
- const { getGlobalNodeModules } = await import('./utils/network.js');
826
+ const { getGlobalNodeModules } = await import('@matterbridge/utils');
1053
827
  this.globalModulesDirectory = await getGlobalNodeModules();
1054
828
  this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
1055
829
  await this.nodeContext?.set('globalModulesDirectory', this.globalModulesDirectory);
@@ -1059,42 +833,29 @@ export class Matterbridge extends EventEmitter {
1059
833
  }
1060
834
  }
1061
835
  else {
1062
- // The global node_modules directory is already set in the node storage and we check if it is still valid
1063
836
  this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
1064
837
  const { createESMWorker } = await import('./workers.js');
1065
838
  createESMWorker('NpmGlobalPrefix', path.join(this.rootDirectory, 'dist/workerGlobalPrefix.js'));
1066
839
  }
1067
- // Matterbridge version
1068
840
  this.log.debug(`Reading matterbridge package.json...`);
1069
841
  const packageJson = JSON.parse(await fs.promises.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
1070
842
  this.matterbridgeVersion = this.matterbridgeLatestVersion = this.matterbridgeDevVersion = packageJson.version;
1071
843
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
1072
- // Matterbridge latest version (will be set in the checkUpdate function)
1073
844
  if (this.nodeContext)
1074
845
  this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', this.matterbridgeVersion);
1075
846
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
1076
- // Matterbridge dev version (will be set in the checkUpdate function)
1077
847
  if (this.nodeContext)
1078
848
  this.matterbridgeDevVersion = await this.nodeContext.get('matterbridgeDevVersion', this.matterbridgeVersion);
1079
849
  this.log.debug(`Matterbridge Dev Version: ${this.matterbridgeDevVersion}`);
1080
- // Frontend version
1081
850
  this.log.debug(`Reading frontend package.json...`);
1082
851
  const frontendPackageJson = JSON.parse(await fs.promises.readFile(path.join(this.rootDirectory, 'frontend/package.json'), 'utf8'));
1083
852
  this.frontendVersion = frontendPackageJson.version;
1084
853
  this.log.debug(`Frontend version ${CYAN}${this.frontendVersion}${db}`);
1085
- // Current working directory
1086
854
  const currentDir = process.cwd();
1087
855
  this.log.debug(`Current Working Directory: ${currentDir}`);
1088
- // Command line arguments (excluding 'node' and the script name)
1089
856
  const cmdArgs = process.argv.slice(2).join(' ');
1090
857
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
1091
858
  }
1092
- /**
1093
- * Set the logger logLevel for the Matterbridge classes and call onChangeLoggerLevel() for each plugin.
1094
- *
1095
- * @param {LogLevel} logLevel The logger logLevel to set.
1096
- * @returns {Promise<LogLevel>} A promise that resolves when the logLevel has been set.
1097
- */
1098
859
  async setLogLevel(logLevel) {
1099
860
  this.logLevel = logLevel;
1100
861
  this.log.logLevel = logLevel;
@@ -1108,90 +869,61 @@ export class Matterbridge extends EventEmitter {
1108
869
  continue;
1109
870
  if (plugin.platform.config.debug === true)
1110
871
  pluginDebug = true;
1111
- plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : logLevel;
1112
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : logLevel);
1113
- }
1114
- // Set the global logger callback for the WebSocketServer to the common minimum logLevel
1115
- let callbackLogLevel = "notice" /* LogLevel.NOTICE */;
1116
- if (logLevel === "info" /* LogLevel.INFO */ || Logger.level === MatterLogLevel.INFO)
1117
- callbackLogLevel = "info" /* LogLevel.INFO */;
1118
- if (logLevel === "debug" /* LogLevel.DEBUG */ || Logger.level === MatterLogLevel.DEBUG || pluginDebug)
1119
- callbackLogLevel = "debug" /* LogLevel.DEBUG */;
872
+ plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" : logLevel;
873
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" : logLevel);
874
+ }
875
+ let callbackLogLevel = "notice";
876
+ if (logLevel === "info" || Logger.level === MatterLogLevel.INFO)
877
+ callbackLogLevel = "info";
878
+ if (logLevel === "debug" || Logger.level === MatterLogLevel.DEBUG || pluginDebug)
879
+ callbackLogLevel = "debug";
1120
880
  AnsiLogger.setGlobalCallbackLevel(callbackLogLevel);
1121
881
  this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
1122
882
  return logLevel;
1123
883
  }
1124
- /**
1125
- * Get the current logger logLevel.
1126
- *
1127
- * @returns {LogLevel} The current logger logLevel.
1128
- */
1129
884
  getLogLevel() {
1130
885
  return this.log.logLevel;
1131
886
  }
1132
- /**
1133
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
1134
- * It also logs to file (matter.log) if fileLogger is true.
1135
- *
1136
- * @param {boolean} fileLogger - Whether to log to file or not.
1137
- * @returns {Function} The MatterLogger function. \x1b[35m for violet \x1b[34m is blue
1138
- */
1139
887
  createDestinationMatterLogger(fileLogger) {
1140
- this.matterLog.logNameColor = '\x1b[34m'; // Blue matter.js Logger
888
+ this.matterLog.logNameColor = '\x1b[34m';
1141
889
  if (fileLogger) {
1142
890
  this.matterLog.logFilePath = path.join(this.matterbridgeDirectory, MATTER_LOGGER_FILE);
1143
891
  }
1144
892
  return (text, message) => {
1145
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1146
893
  const logger = text.slice(44, 44 + 20).trim();
1147
894
  const msg = text.slice(65);
1148
895
  this.matterLog.logName = logger;
1149
896
  switch (message.level) {
1150
897
  case MatterLogLevel.DEBUG:
1151
- this.matterLog.log("debug" /* LogLevel.DEBUG */, msg);
898
+ this.matterLog.log("debug", msg);
1152
899
  break;
1153
900
  case MatterLogLevel.INFO:
1154
- this.matterLog.log("info" /* LogLevel.INFO */, msg);
901
+ this.matterLog.log("info", msg);
1155
902
  break;
1156
903
  case MatterLogLevel.NOTICE:
1157
- this.matterLog.log("notice" /* LogLevel.NOTICE */, msg);
904
+ this.matterLog.log("notice", msg);
1158
905
  break;
1159
906
  case MatterLogLevel.WARN:
1160
- this.matterLog.log("warn" /* LogLevel.WARN */, msg);
907
+ this.matterLog.log("warn", msg);
1161
908
  break;
1162
909
  case MatterLogLevel.ERROR:
1163
- this.matterLog.log("error" /* LogLevel.ERROR */, msg);
910
+ this.matterLog.log("error", msg);
1164
911
  break;
1165
912
  case MatterLogLevel.FATAL:
1166
- this.matterLog.log("fatal" /* LogLevel.FATAL */, msg);
913
+ this.matterLog.log("fatal", msg);
1167
914
  break;
1168
915
  }
1169
916
  };
1170
917
  }
1171
- /**
1172
- * Restarts the process by exiting the current instance and loading a new instance (/api/restart).
1173
- *
1174
- * @returns {Promise<void>} A promise that resolves when the restart is completed.
1175
- */
1176
918
  async restartProcess() {
1177
919
  await this.cleanup('restarting...', true);
1178
920
  }
1179
- /**
1180
- * Shut down the process (/api/shutdown).
1181
- *
1182
- * @returns {Promise<void>} A promise that resolves when the shutdown is completed.
1183
- */
1184
921
  async shutdownProcess() {
1185
922
  await this.cleanup('shutting down...', false);
1186
923
  }
1187
- /**
1188
- * Update matterbridge and shut down the process (virtual device 'Update Matterbridge').
1189
- *
1190
- * @returns {Promise<void>} A promise that resolves when the update is completed.
1191
- */
1192
924
  async updateProcess() {
1193
925
  this.log.info('Updating matterbridge...');
1194
- const { spawnCommand } = await import('./utils/spawn.js');
926
+ const { spawnCommand } = await import('./spawn.js');
1195
927
  if (await spawnCommand('npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose'], 'install', 'matterbridge')) {
1196
928
  this.log.info('Matterbridge has been updated. Full restart required.');
1197
929
  }
@@ -1201,15 +933,8 @@ export class Matterbridge extends EventEmitter {
1201
933
  this.frontend.wssSendRestartRequired();
1202
934
  await this.cleanup('updating...', false);
1203
935
  }
1204
- /**
1205
- * Unregister all devices and shut down the process (/api/unregister).
1206
- *
1207
- * @param {number} [timeout] - The timeout duration to wait for the message exchange to complete in milliseconds. Default is 1000.
1208
- *
1209
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1210
- */
1211
936
  async unregisterAndShutdownProcess(timeout = 1000) {
1212
- const { wait } = await import('./utils/wait.js');
937
+ const { wait } = await import('@matterbridge/utils');
1213
938
  this.log.info('Unregistering all devices and shutting down...');
1214
939
  for (const plugin of this.plugins.array()) {
1215
940
  if (plugin.error || !plugin.enabled)
@@ -1220,71 +945,46 @@ export class Matterbridge extends EventEmitter {
1220
945
  await this.removeAllBridgedEndpoints(plugin.name, 100);
1221
946
  }
1222
947
  this.log.debug('Waiting for the MessageExchange to finish...');
1223
- await wait(timeout); // Wait for MessageExchange to finish
948
+ await wait(timeout);
1224
949
  this.log.debug('Cleaning up and shutting down...');
1225
950
  await this.cleanup('unregistered all devices and shutting down...', false, timeout);
1226
951
  }
1227
- /**
1228
- * Reset commissioning and shut down the process (/api/reset).
1229
- *
1230
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1231
- */
1232
952
  async shutdownProcessAndReset() {
1233
953
  await this.cleanup('shutting down with reset...', false);
1234
954
  }
1235
- /**
1236
- * Factory reset and shut down the process (/api/factory-reset).
1237
- *
1238
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1239
- */
1240
955
  async shutdownProcessAndFactoryReset() {
1241
956
  await this.cleanup('shutting down with factory reset...', false);
1242
957
  }
1243
- /**
1244
- * Cleans up the Matterbridge instance.
1245
- *
1246
- * @param {string} message - The cleanup message.
1247
- * @param {boolean} [restart] - Indicates whether to restart the instance after cleanup. Default is `false`.
1248
- * @param {number} [pause] - The pause in ms to wait for the message exchange to complete in milliseconds. Default is 1000.
1249
- *
1250
- * @returns {Promise<void>} A promise that resolves when the cleanup is completed.
1251
- */
1252
958
  async cleanup(message, restart = false, pause = 1000) {
1253
959
  if (this.initialized && !this.hasCleanupStarted) {
1254
960
  this.emit('cleanup_started');
1255
961
  this.hasCleanupStarted = true;
1256
962
  this.log.info(message);
1257
- // Clear the start matter interval
1258
963
  if (this.startMatterInterval) {
1259
964
  clearInterval(this.startMatterInterval);
1260
965
  this.startMatterInterval = undefined;
1261
966
  this.log.debug('Start matter interval cleared');
1262
967
  }
1263
- // Clear the check update timeout
1264
968
  if (this.checkUpdateTimeout) {
1265
969
  clearTimeout(this.checkUpdateTimeout);
1266
970
  this.checkUpdateTimeout = undefined;
1267
971
  this.log.debug('Check update timeout cleared');
1268
972
  }
1269
- // Clear the check update interval
1270
973
  if (this.checkUpdateInterval) {
1271
974
  clearInterval(this.checkUpdateInterval);
1272
975
  this.checkUpdateInterval = undefined;
1273
976
  this.log.debug('Check update interval cleared');
1274
977
  }
1275
- // Clear the configure timeout
1276
978
  if (this.configureTimeout) {
1277
979
  clearTimeout(this.configureTimeout);
1278
980
  this.configureTimeout = undefined;
1279
981
  this.log.debug('Matterbridge configure timeout cleared');
1280
982
  }
1281
- // Clear the reachability timeout
1282
983
  if (this.reachabilityTimeout) {
1283
984
  clearTimeout(this.reachabilityTimeout);
1284
985
  this.reachabilityTimeout = undefined;
1285
986
  this.log.debug('Matterbridge reachability timeout cleared');
1286
987
  }
1287
- // Call the shutdown method of each plugin and clear the plugins reachability timeout
1288
988
  for (const plugin of this.plugins) {
1289
989
  if (!plugin.enabled || plugin.error)
1290
990
  continue;
@@ -1295,10 +995,9 @@ export class Matterbridge extends EventEmitter {
1295
995
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1296
996
  }
1297
997
  }
1298
- // Stop matter server nodes
1299
998
  this.log.notice(`Stopping matter server nodes in ${this.bridgeMode} mode...`);
1300
999
  if (pause > 0) {
1301
- const { wait } = await import('./utils/wait.js');
1000
+ const { wait } = await import('@matterbridge/utils');
1302
1001
  this.log.debug(`Waiting ${pause}ms for the MessageExchange to finish...`);
1303
1002
  await wait(pause, `Waiting ${pause}ms for the MessageExchange to finish...`, false);
1304
1003
  }
@@ -1323,7 +1022,6 @@ export class Matterbridge extends EventEmitter {
1323
1022
  }
1324
1023
  }
1325
1024
  this.log.notice('Stopped matter server nodes');
1326
- // Matter commisioning reset
1327
1025
  if (message === 'shutting down with reset...') {
1328
1026
  this.log.info('Resetting Matterbridge commissioning information...');
1329
1027
  await this.matterStorageManager?.createContext('events')?.clearAll();
@@ -1333,7 +1031,6 @@ export class Matterbridge extends EventEmitter {
1333
1031
  await this.matterbridgeContext?.clearAll();
1334
1032
  this.log.info('Matter storage reset done! Remove the bridge from the controller.');
1335
1033
  }
1336
- // Unregister all devices
1337
1034
  if (message === 'unregistered all devices and shutting down...') {
1338
1035
  if (this.bridgeMode === 'bridge') {
1339
1036
  await this.matterStorageManager?.createContext('root')?.createContext('parts')?.createContext('Matterbridge')?.createContext('parts')?.clearAll();
@@ -1351,14 +1048,7 @@ export class Matterbridge extends EventEmitter {
1351
1048
  }
1352
1049
  this.log.info('Matter storage reset done!');
1353
1050
  }
1354
- // Stop matter storage
1355
1051
  await this.stopMatterStorage();
1356
- /**
1357
- * Unlink a file safely, ignoring errors.
1358
- *
1359
- * @param {string} path - The path to the file to unlink.
1360
- * @param {AnsiLogger} log - The logger to use for logging.
1361
- */
1362
1052
  function unlinkSafe(path, log) {
1363
1053
  try {
1364
1054
  log.debug(`Removing ${path}...`);
@@ -1366,15 +1056,12 @@ export class Matterbridge extends EventEmitter {
1366
1056
  log.debug(`Removed ${path}`);
1367
1057
  }
1368
1058
  catch {
1369
- // Ignore errors if the file does not exist
1370
1059
  }
1371
1060
  }
1372
- // Remove the resumption records for Matterbridge (bridge mode)
1373
1061
  this.log.debug(`Cleaning matter storage context for ${GREEN}Matterbridge${db}...`);
1374
1062
  unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME, 'Matterbridge', 'sessions.resumptionRecords'), this.log);
1375
1063
  unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME, 'Matterbridge', 'root.subscriptions.subscriptions'), this.log);
1376
1064
  for (const plugin of this.plugins.array()) {
1377
- // Remove the resumption records for the plugins (childbridge mode)
1378
1065
  this.log.debug(`Cleaning matter storage context for plugin ${plg}${plugin.name}${db}...`);
1379
1066
  unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME, plugin.name, 'sessions.resumptionRecords'), this.log);
1380
1067
  unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME, plugin.name, 'root.subscriptions.subscriptions'), this.log);
@@ -1382,38 +1069,19 @@ export class Matterbridge extends EventEmitter {
1382
1069
  for (const device of this.devices.array().filter((d) => d.mode === 'server')) {
1383
1070
  if (!device.deviceName)
1384
1071
  continue;
1385
- // Remove the resumption records for the server mode devices
1386
1072
  this.log.debug(`Cleaning matter storage context for server node device ${dev}${device.deviceName}${db}...`);
1387
1073
  unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME, device.deviceName.replace(/[ .]/g, ''), 'sessions.resumptionRecords'), this.log);
1388
1074
  unlinkSafe(path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME, device.deviceName.replace(/[ .]/g, ''), 'root.subscriptions.subscriptions'), this.log);
1389
1075
  }
1390
- // Stop the frontend
1391
1076
  await this.frontend.stop();
1392
1077
  this.frontend.destroy();
1393
- // Close PluginManager and DeviceManager
1394
1078
  this.plugins.destroy();
1395
1079
  this.devices.destroy();
1396
- // Stop thread messaging server
1397
1080
  this.server.close();
1398
- // Close the matterbridge node storage and context
1399
1081
  if (this.nodeStorage && this.nodeContext) {
1400
- /*
1401
- TODO: Implement serialization of registered devices
1402
- this.log.info('Saving registered devices...');
1403
- const serializedRegisteredDevices: SerializedMatterbridgeEndpoint[] = [];
1404
- this.devices.forEach(async (device) => {
1405
- const serializedMatterbridgeDevice = MatterbridgeEndpoint.serialize(device);
1406
- this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1407
- if (serializedMatterbridgeDevice) serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1408
- });
1409
- await this.nodeContext.set<SerializedMatterbridgeEndpoint[]>('devices', serializedRegisteredDevices);
1410
- this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1411
- */
1412
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1413
1082
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1414
1083
  await this.nodeContext.close();
1415
1084
  this.nodeContext = undefined;
1416
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1417
1085
  for (const plugin of this.plugins) {
1418
1086
  if (plugin.nodeContext) {
1419
1087
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1430,10 +1098,8 @@ export class Matterbridge extends EventEmitter {
1430
1098
  }
1431
1099
  this.plugins.clear();
1432
1100
  this.devices.clear();
1433
- // Factory reset
1434
1101
  if (message === 'shutting down with factory reset...') {
1435
1102
  try {
1436
- // Delete matter storage directory with its subdirectories and backup
1437
1103
  const dir = path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME);
1438
1104
  this.log.info(`Removing matter storage directory: ${dir}`);
1439
1105
  await fs.promises.rm(dir, { recursive: true });
@@ -1442,13 +1108,11 @@ export class Matterbridge extends EventEmitter {
1442
1108
  await fs.promises.rm(backup, { recursive: true });
1443
1109
  }
1444
1110
  catch (error) {
1445
- // istanbul ignore next if
1446
1111
  if (error instanceof Error && error.code !== 'ENOENT') {
1447
1112
  this.log.error(`Error removing matter storage directory: ${error}`);
1448
1113
  }
1449
1114
  }
1450
1115
  try {
1451
- // Delete matterbridge storage directory with its subdirectories and backup
1452
1116
  const dir = path.join(this.matterbridgeDirectory, NODE_STORAGE_DIR);
1453
1117
  this.log.info(`Removing matterbridge storage directory: ${dir}`);
1454
1118
  await fs.promises.rm(dir, { recursive: true });
@@ -1457,20 +1121,18 @@ export class Matterbridge extends EventEmitter {
1457
1121
  await fs.promises.rm(backup, { recursive: true });
1458
1122
  }
1459
1123
  catch (error) {
1460
- // istanbul ignore next if
1461
1124
  if (error instanceof Error && error.code !== 'ENOENT') {
1462
1125
  this.log.error(`Error removing matterbridge storage directory: ${error}`);
1463
1126
  }
1464
1127
  }
1465
1128
  this.log.info('Factory reset done! Remove all paired fabrics from the controllers.');
1466
1129
  }
1467
- // Deregisters the process handlers
1468
1130
  this.deregisterProcessHandlers();
1469
1131
  if (restart) {
1470
1132
  if (message === 'updating...') {
1471
1133
  this.log.info('Cleanup completed. Updating...');
1472
1134
  Matterbridge.instance = undefined;
1473
- this.emit('update'); // Restart the process but the update has been done before. TODO move all updates to the cli
1135
+ this.emit('update');
1474
1136
  }
1475
1137
  else if (message === 'restarting...') {
1476
1138
  this.log.info('Cleanup completed. Restarting...');
@@ -1499,14 +1161,7 @@ export class Matterbridge extends EventEmitter {
1499
1161
  this.log.debug('Cleanup already started...');
1500
1162
  }
1501
1163
  }
1502
- /**
1503
- * Starts the Matterbridge in bridge mode.
1504
- *
1505
- * @private
1506
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1507
- */
1508
1164
  async startBridge() {
1509
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1510
1165
  if (!this.matterStorageManager)
1511
1166
  throw new Error('No storage manager initialized');
1512
1167
  if (!this.matterbridgeContext)
@@ -1520,7 +1175,6 @@ export class Matterbridge extends EventEmitter {
1520
1175
  this.frontend.wssSendSnackbarMessage(`The bridge is starting...`, 0, 'info');
1521
1176
  let failCount = 0;
1522
1177
  this.startMatterInterval = setInterval(async () => {
1523
- // istanbul ignore if cause is just a logging statement
1524
1178
  if (failCount && failCount % 10 === 0) {
1525
1179
  this.frontend.wssSendSnackbarMessage(`The bridge is still starting...`, 10, 'info');
1526
1180
  this.frontend.wssSendRefreshRequired('plugins');
@@ -1554,16 +1208,13 @@ export class Matterbridge extends EventEmitter {
1554
1208
  clearInterval(this.startMatterInterval);
1555
1209
  this.startMatterInterval = undefined;
1556
1210
  this.log.debug('Cleared startMatterInterval interval in bridge mode');
1557
- // Start the Matter server node
1558
- this.startServerNode(this.serverNode); // We don't await this, because the server node is started in the background
1559
- // Start the Matter server node of single devices in mode 'server'
1211
+ this.startServerNode(this.serverNode);
1560
1212
  for (const device of this.devices.array()) {
1561
1213
  if (device.mode === 'server' && device.serverNode) {
1562
1214
  this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
1563
- this.startServerNode(device.serverNode); // We don't await this, because the server node is started in the background
1215
+ this.startServerNode(device.serverNode);
1564
1216
  }
1565
1217
  }
1566
- // Configure the plugins
1567
1218
  this.configureTimeout = setTimeout(async () => {
1568
1219
  for (const plugin of this.plugins.array()) {
1569
1220
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1581,13 +1232,11 @@ export class Matterbridge extends EventEmitter {
1581
1232
  }
1582
1233
  this.frontend.wssSendRefreshRequired('plugins');
1583
1234
  }, 30 * 1000).unref();
1584
- // Setting reachability to true
1585
1235
  this.reachabilityTimeout = setTimeout(() => {
1586
1236
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1587
1237
  if (this.aggregatorNode)
1588
1238
  this.setAggregatorReachability(this.aggregatorNode, true);
1589
1239
  }, 60 * 1000).unref();
1590
- // Logger.get('LogServerNode').info(this.serverNode);
1591
1240
  this.emit('bridge_started');
1592
1241
  this.log.notice('Matterbridge bridge started successfully');
1593
1242
  this.frontend.wssSendRefreshRequired('settings');
@@ -1595,33 +1244,22 @@ export class Matterbridge extends EventEmitter {
1595
1244
  this.frontend.wssSendCloseSnackbarMessage(`The bridge is starting...`);
1596
1245
  }, Number(process.env['MATTERBRIDGE_START_MATTER_INTERVAL_MS']) || this.startMatterIntervalMs);
1597
1246
  }
1598
- /**
1599
- * Starts the Matterbridge in childbridge mode.
1600
- *
1601
- * @param {number} [delay] - The delay before starting the childbridge. Default is 1000 milliseconds.
1602
- *
1603
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1604
- */
1605
1247
  async startChildbridge(delay = 1000) {
1606
1248
  if (!this.matterStorageManager)
1607
1249
  throw new Error('No storage manager initialized');
1608
- const { wait } = await import('./utils/wait.js');
1609
- // Load with await all plugins but don't start them. We get the platform.type to pre-create server nodes for DynamicPlatform plugins
1250
+ const { wait } = await import('@matterbridge/utils');
1610
1251
  this.log.debug('Loading all plugins in childbridge mode...');
1611
1252
  await this.startPlugins(true, false);
1612
- // Create server nodes for DynamicPlatform plugins and start all plugins in the background
1613
1253
  this.log.debug('Creating server nodes for DynamicPlatform plugins and starting all plugins in childbridge mode...');
1614
1254
  for (const plugin of this.plugins.array().filter((p) => p.enabled && !p.error)) {
1615
1255
  if (plugin.type === 'DynamicPlatform')
1616
1256
  await this.createDynamicPlugin(plugin);
1617
- this.plugins.start(plugin, 'Matterbridge is starting'); // Start the plugin in the background
1257
+ this.plugins.start(plugin, 'Matterbridge is starting');
1618
1258
  }
1619
- // Start the Matterbridge in childbridge mode when all plugins are loaded and started
1620
1259
  this.log.debug('Starting start matter interval in childbridge mode...');
1621
1260
  this.frontend.wssSendSnackbarMessage(`The bridge is starting...`, 0, 'info');
1622
1261
  let failCount = 0;
1623
1262
  this.startMatterInterval = setInterval(async () => {
1624
- // istanbul ignore if cause is just a logging statement
1625
1263
  if (failCount && failCount % 10 === 0) {
1626
1264
  this.frontend.wssSendSnackbarMessage(`The bridge is still starting...`, 10, 'info');
1627
1265
  this.frontend.wssSendRefreshRequired('plugins');
@@ -1659,9 +1297,8 @@ export class Matterbridge extends EventEmitter {
1659
1297
  clearInterval(this.startMatterInterval);
1660
1298
  this.startMatterInterval = undefined;
1661
1299
  if (delay > 0)
1662
- await wait(Number(process.env['MATTERBRIDGE_PAUSE_MATTER_INTERVAL_MS']) || delay); // Wait for the specified delay to ensure all plugins server nodes are ready
1300
+ await wait(Number(process.env['MATTERBRIDGE_PAUSE_MATTER_INTERVAL_MS']) || delay);
1663
1301
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1664
- // Configure the plugins
1665
1302
  this.configureTimeout = setTimeout(async () => {
1666
1303
  for (const plugin of this.plugins.array()) {
1667
1304
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1686,7 +1323,6 @@ export class Matterbridge extends EventEmitter {
1686
1323
  this.log.error(`Plugin ${plg}${plugin.name}${er} didn't register any devices to Matterbridge. Verify the plugin configuration.`);
1687
1324
  continue;
1688
1325
  }
1689
- // istanbul ignore next if cause is just a safety check
1690
1326
  if (!plugin.serverNode) {
1691
1327
  this.log.error(`Server node not found for plugin ${plg}${plugin.name}${er}`);
1692
1328
  continue;
@@ -1699,23 +1335,19 @@ export class Matterbridge extends EventEmitter {
1699
1335
  this.log.error(`Node storage context not found for plugin ${plg}${plugin.name}${er}`);
1700
1336
  continue;
1701
1337
  }
1702
- // Start the Matter server node
1703
- this.startServerNode(plugin.serverNode); // We don't await this, because the server node is started in the background
1704
- // Setting reachability to true
1338
+ this.startServerNode(plugin.serverNode);
1705
1339
  plugin.reachabilityTimeout = setTimeout(() => {
1706
1340
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${nf}`);
1707
1341
  if (plugin.type === 'DynamicPlatform' && plugin.aggregatorNode)
1708
1342
  this.setAggregatorReachability(plugin.aggregatorNode, true);
1709
1343
  }, 60 * 1000).unref();
1710
1344
  }
1711
- // Start the Matter server node of single devices in mode 'server'
1712
1345
  for (const device of this.devices.array()) {
1713
1346
  if (device.mode === 'server' && device.serverNode) {
1714
1347
  this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
1715
- this.startServerNode(device.serverNode); // We don't await this, because the server node is started in the background
1348
+ this.startServerNode(device.serverNode);
1716
1349
  }
1717
1350
  }
1718
- // Logger.get('LogServerNode').info(this.serverNode);
1719
1351
  this.emit('childbridge_started');
1720
1352
  this.log.notice('Matterbridge childbridge started successfully');
1721
1353
  this.frontend.wssSendRefreshRequired('settings');
@@ -1723,229 +1355,9 @@ export class Matterbridge extends EventEmitter {
1723
1355
  this.frontend.wssSendCloseSnackbarMessage(`The bridge is starting...`);
1724
1356
  }, Number(process.env['MATTERBRIDGE_START_MATTER_INTERVAL_MS']) || this.startMatterIntervalMs);
1725
1357
  }
1726
- /**
1727
- * Starts the Matterbridge controller.
1728
- *
1729
- * @private
1730
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1731
- */
1732
1358
  async startController() {
1733
- /*
1734
- if (!this.matterStorageManager) {
1735
- this.log.error('No storage manager initialized');
1736
- await this.cleanup('No storage manager initialized');
1737
- return;
1738
- }
1739
- this.log.info('Creating context: mattercontrollerContext');
1740
- this.controllerContext = this.matterStorageManager.createContext('mattercontrollerContext');
1741
- if (!this.controllerContext) {
1742
- this.log.error('No storage context mattercontrollerContext initialized');
1743
- await this.cleanup('No storage context mattercontrollerContext initialized');
1744
- return;
1745
- }
1746
-
1747
- this.log.debug('Starting matterbridge in mode', this.bridgeMode);
1748
- this.matterServer = await this.createMatterServer(this.storageManager);
1749
- this.log.info('Creating matter commissioning controller');
1750
- this.commissioningController = new CommissioningController({
1751
- autoConnect: false,
1752
- });
1753
- this.log.info('Adding matter commissioning controller to matter server');
1754
- await this.matterServer.addCommissioningController(this.commissioningController);
1755
-
1756
- this.log.info('Starting matter server');
1757
- await this.matterServer.start();
1758
- this.log.info('Matter server started');
1759
- const commissioningOptions: ControllerCommissioningFlowOptions = {
1760
- regulatoryLocation: GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor,
1761
- regulatoryCountryCode: 'XX',
1762
- };
1763
- const commissioningController = new CommissioningController({
1764
- environment: {
1765
- environment,
1766
- id: uniqueId,
1767
- },
1768
- autoConnect: false, // Do not auto connect to the commissioned nodes
1769
- adminFabricLabel,
1770
- });
1771
-
1772
- if (hasParameter('pairingcode')) {
1773
- this.log.info('Pairing device with pairingcode:', getParameter('pairingcode'));
1774
- const pairingCode = getParameter('pairingcode');
1775
- const ip = this.controllerContext.has('ip') ? this.controllerContext.get<string>('ip') : undefined;
1776
- const port = this.controllerContext.has('port') ? this.controllerContext.get<number>('port') : undefined;
1777
-
1778
- let longDiscriminator, setupPin, shortDiscriminator;
1779
- if (pairingCode !== undefined) {
1780
- const pairingCodeCodec = ManualPairingCodeCodec.decode(pairingCode);
1781
- shortDiscriminator = pairingCodeCodec.shortDiscriminator;
1782
- longDiscriminator = undefined;
1783
- setupPin = pairingCodeCodec.passcode;
1784
- this.log.info(`Data extracted from pairing code: ${Logger.toJSON(pairingCodeCodec)}`);
1785
- } else {
1786
- longDiscriminator = await this.controllerContext.get('longDiscriminator', 3840);
1787
- if (longDiscriminator > 4095) throw new Error('Discriminator value must be less than 4096');
1788
- setupPin = this.controllerContext.get('pin', 20202021);
1789
- }
1790
- if ((shortDiscriminator === undefined && longDiscriminator === undefined) || setupPin === undefined) {
1791
- throw new Error('Please specify the longDiscriminator of the device to commission with -longDiscriminator or provide a valid passcode with -passcode');
1792
- }
1793
-
1794
- const options = {
1795
- commissioning: commissioningOptions,
1796
- discovery: {
1797
- knownAddress: ip !== undefined && port !== undefined ? { ip, port, type: 'udp' } : undefined,
1798
- identifierData: longDiscriminator !== undefined ? { longDiscriminator } : shortDiscriminator !== undefined ? { shortDiscriminator } : {},
1799
- },
1800
- passcode: setupPin,
1801
- } as NodeCommissioningOptions;
1802
- this.log.info('Commissioning with options:', options);
1803
- const nodeId = await this.commissioningController.commissionNode(options);
1804
- this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1805
- this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1806
- } // (hasParameter('pairingcode'))
1807
-
1808
- if (hasParameter('unpairall')) {
1809
- this.log.info('***Commissioning controller unpairing all nodes...');
1810
- const nodeIds = this.commissioningController.getCommissionedNodes();
1811
- for (const nodeId of nodeIds) {
1812
- this.log.info('***Commissioning controller unpairing node:', nodeId);
1813
- await this.commissioningController.removeNode(nodeId);
1814
- }
1815
- return;
1816
- }
1817
-
1818
- if (hasParameter('discover')) {
1819
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1820
- // console.log(discover);
1821
- }
1822
-
1823
- if (!this.commissioningController.isCommissioned()) {
1824
- this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
1825
- return;
1826
- }
1827
-
1828
- const nodeIds = this.commissioningController.getCommissionedNodes();
1829
- this.log.info(`***Commissioning controller is commissioned ${this.commissioningController.isCommissioned()} and has ${nodeIds.length} nodes commisioned: `);
1830
- for (const nodeId of nodeIds) {
1831
- this.log.info(`***Connecting to commissioned node: ${nodeId}`);
1832
-
1833
- const node = await this.commissioningController.connectNode(nodeId, {
1834
- autoSubscribe: false,
1835
- attributeChangedCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, attributeName }, value }) =>
1836
- this.log.info(`***Commissioning controller attributeChangedCallback ${peerNodeId}: attribute ${nodeId}/${endpointId}/${clusterId}/${attributeName} changed to ${Logger.toJSON(value)}`),
1837
- eventTriggeredCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, eventName }, events }) =>
1838
- this.log.info(`***Commissioning controller eventTriggeredCallback ${peerNodeId}: Event ${nodeId}/${endpointId}/${clusterId}/${eventName} triggered with ${Logger.toJSON(events)}`),
1839
- stateInformationCallback: (peerNodeId, info) => {
1840
- switch (info) {
1841
- case NodeStateInformation.Connected:
1842
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} connected`);
1843
- break;
1844
- case NodeStateInformation.Disconnected:
1845
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} disconnected`);
1846
- break;
1847
- case NodeStateInformation.Reconnecting:
1848
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} reconnecting`);
1849
- break;
1850
- case NodeStateInformation.WaitingForDeviceDiscovery:
1851
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} waiting for device discovery`);
1852
- break;
1853
- case NodeStateInformation.StructureChanged:
1854
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} structure changed`);
1855
- break;
1856
- case NodeStateInformation.Decommissioned:
1857
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} decommissioned`);
1858
- break;
1859
- default:
1860
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} NodeStateInformation.${info}`);
1861
- break;
1862
- }
1863
- },
1864
- });
1865
-
1866
- node.logStructure();
1867
-
1868
- // Get the interaction client
1869
- this.log.info('Getting the interaction client');
1870
- const interactionClient = await node.getInteractionClient();
1871
- let cluster;
1872
- let attributes;
1873
-
1874
- // Log BasicInformationCluster
1875
- cluster = BasicInformationCluster;
1876
- attributes = await interactionClient.getMultipleAttributes({
1877
- attributes: [{ clusterId: cluster.id }],
1878
- });
1879
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1880
- attributes.forEach((attribute) => {
1881
- this.log.info(
1882
- `- 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}`,
1883
- );
1884
- });
1885
-
1886
- // Log PowerSourceCluster
1887
- cluster = PowerSourceCluster;
1888
- attributes = await interactionClient.getMultipleAttributes({
1889
- attributes: [{ clusterId: cluster.id }],
1890
- });
1891
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1892
- attributes.forEach((attribute) => {
1893
- this.log.info(
1894
- `- 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}`,
1895
- );
1896
- });
1897
-
1898
- // Log ThreadNetworkDiagnostics
1899
- cluster = ThreadNetworkDiagnosticsCluster;
1900
- attributes = await interactionClient.getMultipleAttributes({
1901
- attributes: [{ clusterId: cluster.id }],
1902
- });
1903
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1904
- attributes.forEach((attribute) => {
1905
- this.log.info(
1906
- `- 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}`,
1907
- );
1908
- });
1909
-
1910
- // Log SwitchCluster
1911
- cluster = SwitchCluster;
1912
- attributes = await interactionClient.getMultipleAttributes({
1913
- attributes: [{ clusterId: cluster.id }],
1914
- });
1915
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1916
- attributes.forEach((attribute) => {
1917
- this.log.info(
1918
- `- 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}`,
1919
- );
1920
- });
1921
-
1922
- this.log.info('Subscribing to all attributes and events');
1923
- await node.subscribeAllAttributesAndEvents({
1924
- ignoreInitialTriggers: false,
1925
- attributeChangedCallback: ({ path: { nodeId, clusterId, endpointId, attributeName }, version, value }) =>
1926
- this.log.info(
1927
- `***${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}`,
1928
- ),
1929
- eventTriggeredCallback: ({ path: { nodeId, clusterId, endpointId, eventName }, events }) => {
1930
- this.log.info(
1931
- `***${db}Commissioning controller eventTriggeredCallback: event ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${eventName}${db} triggered with ${debugStringify(events ?? { none: true })}`,
1932
- );
1933
- },
1934
- });
1935
- this.log.info('Subscribed to all attributes and events');
1936
- }
1937
- */
1938
1359
  }
1939
- /** */
1940
- /** Matter.js methods */
1941
- /** */
1942
- /**
1943
- * Starts the matter storage with name Matterbridge, create the matterbridge context and performs a backup.
1944
- *
1945
- * @returns {Promise<void>} - A promise that resolves when the storage is started.
1946
- */
1947
1360
  async startMatterStorage() {
1948
- // Setup Matter storage
1949
1361
  this.log.info(`Starting matter node storage...`);
1950
1362
  this.matterStorageService = this.environment.get(StorageService);
1951
1363
  this.log.info(`Matter node storage service created: ${this.matterStorageService.location}`);
@@ -1953,17 +1365,8 @@ export class Matterbridge extends EventEmitter {
1953
1365
  this.log.info('Matter node storage manager "Matterbridge" created');
1954
1366
  this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId);
1955
1367
  this.log.info('Matter node storage started');
1956
- // Backup matter storage since it is created/opened correctly
1957
1368
  await this.backupMatterStorage(path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME), path.join(this.matterbridgeDirectory, MATTER_STORAGE_NAME + '.backup'));
1958
1369
  }
1959
- /**
1960
- * Makes a backup copy of the specified matter storage directory.
1961
- *
1962
- * @param {string} storageName - The name of the storage directory to be backed up.
1963
- * @param {string} backupName - The name of the backup directory to be created.
1964
- * @private
1965
- * @returns {Promise<void>} A promise that resolves when the has been done.
1966
- */
1967
1370
  async backupMatterStorage(storageName, backupName) {
1968
1371
  this.log.info('Creating matter node storage backup...');
1969
1372
  try {
@@ -1974,11 +1377,6 @@ export class Matterbridge extends EventEmitter {
1974
1377
  this.log.error(`Error creating matter node storage backup from ${storageName} to ${backupName}:`, error);
1975
1378
  }
1976
1379
  }
1977
- /**
1978
- * Stops the matter storage.
1979
- *
1980
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1981
- */
1982
1380
  async stopMatterStorage() {
1983
1381
  this.log.info('Closing matter node storage...');
1984
1382
  await this.matterStorageManager?.close();
@@ -1987,20 +1385,6 @@ export class Matterbridge extends EventEmitter {
1987
1385
  this.matterbridgeContext = undefined;
1988
1386
  this.log.info('Matter node storage closed');
1989
1387
  }
1990
- /**
1991
- * Creates a server node storage context.
1992
- *
1993
- * @param {string} storeId - The storeId.
1994
- * @param {string} deviceName - The name of the device.
1995
- * @param {DeviceTypeId} deviceType - The device type of the device.
1996
- * @param {number} vendorId - The vendor ID.
1997
- * @param {string} vendorName - The vendor name.
1998
- * @param {number} productId - The product ID.
1999
- * @param {string} productName - The product name.
2000
- * @param {string} [serialNumber] - The serial number of the device (optional).
2001
- * @param {string} [uniqueId] - The unique ID of the device (optional).
2002
- * @returns {Promise<StorageContext>} The storage context for the commissioning server.
2003
- */
2004
1388
  async createServerNodeContext(storeId, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber, uniqueId) {
2005
1389
  const { randomBytes } = await import('node:crypto');
2006
1390
  if (!this.matterStorageService)
@@ -2036,57 +1420,49 @@ export class Matterbridge extends EventEmitter {
2036
1420
  this.log.debug(`- nodeLabel: ${await storageContext.get('nodeLabel')}`);
2037
1421
  this.log.debug(`- serialNumber: ${await storageContext.get('serialNumber')}`);
2038
1422
  this.log.debug(`- uniqueId: ${await storageContext.get('uniqueId')}`);
2039
- this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
2040
- this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
1423
+ this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')}`);
1424
+ this.log.debug(`- softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
1425
+ this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')}`);
1426
+ this.log.debug(`- hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2041
1427
  return storageContext;
2042
1428
  }
2043
- /**
2044
- * Creates a server node.
2045
- *
2046
- * @param {StorageContext} storageContext - The storage context for the server node.
2047
- * @param {number} [port] - The port number for the server node. Defaults to 5540.
2048
- * @param {number} [passcode] - The passcode for the server node. Defaults to 20242025.
2049
- * @param {number} [discriminator] - The discriminator for the server node. Defaults to 3850.
2050
- * @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created server node.
2051
- */
2052
1429
  async createServerNode(storageContext, port = 5540, passcode = 20242025, discriminator = 3850) {
2053
1430
  const storeId = await storageContext.get('storeId');
2054
1431
  this.log.notice(`Creating server node for ${storeId} on port ${port} with passcode ${passcode} and discriminator ${discriminator}...`);
1432
+ this.log.debug(`- storeId: ${await storageContext.get('storeId')}`);
2055
1433
  this.log.debug(`- deviceName: ${await storageContext.get('deviceName')}`);
2056
1434
  this.log.debug(`- deviceType: ${await storageContext.get('deviceType')}(0x${(await storageContext.get('deviceType'))?.toString(16).padStart(4, '0')})`);
1435
+ this.log.debug(`- vendorId: ${await storageContext.get('vendorId')}`);
1436
+ this.log.debug(`- vendorName: ${await storageContext.get('vendorName')}`);
1437
+ this.log.debug(`- productId: ${await storageContext.get('productId')}`);
1438
+ this.log.debug(`- productName: ${await storageContext.get('productName')}`);
1439
+ this.log.debug(`- productLabel: ${await storageContext.get('productLabel')}`);
1440
+ this.log.debug(`- nodeLabel: ${await storageContext.get('nodeLabel')}`);
2057
1441
  this.log.debug(`- serialNumber: ${await storageContext.get('serialNumber')}`);
2058
1442
  this.log.debug(`- uniqueId: ${await storageContext.get('uniqueId')}`);
2059
- this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
2060
- this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2061
- /**
2062
- * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
2063
- */
1443
+ this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')}`);
1444
+ this.log.debug(`- softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
1445
+ this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')}`);
1446
+ this.log.debug(`- hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
2064
1447
  const serverNode = await ServerNode.create({
2065
- // Required: Give the Node a unique ID which is used to store the state of this node
2066
1448
  id: storeId,
2067
- // Environment to run the server node in
2068
1449
  environment: this.environment,
2069
- // Provide Network relevant configuration like the port
2070
1450
  network: {
2071
1451
  listeningAddressIpv4: this.ipv4Address,
2072
1452
  listeningAddressIpv6: this.ipv6Address,
2073
1453
  port,
2074
1454
  },
2075
- // Provide the certificate for the device
2076
1455
  operationalCredentials: {
2077
1456
  certification: this.certification,
2078
1457
  },
2079
- // Provide Commissioning relevant settings
2080
1458
  commissioning: {
2081
1459
  passcode,
2082
1460
  discriminator,
2083
1461
  },
2084
- // Provide Node announcement settings
2085
1462
  productDescription: {
2086
1463
  name: await storageContext.get('deviceName'),
2087
1464
  deviceType: DeviceTypeId(await storageContext.get('deviceType')),
2088
1465
  },
2089
- // Provide defaults for the BasicInformation cluster on the Root endpoint
2090
1466
  basicInformation: {
2091
1467
  nodeLabel: await storageContext.get('nodeLabel'),
2092
1468
  vendorId: VendorId(await storageContext.get('vendorId')),
@@ -2103,23 +1479,17 @@ export class Matterbridge extends EventEmitter {
2103
1479
  reachable: true,
2104
1480
  },
2105
1481
  });
2106
- /**
2107
- * This event is triggered when the device is initially commissioned successfully.
2108
- * This means: It is added to the first fabric.
2109
- */
2110
1482
  serverNode.lifecycle.commissioned.on(() => {
2111
1483
  this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`);
2112
1484
  this.advertisingNodes.delete(storeId);
2113
1485
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2114
1486
  });
2115
- /** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
2116
1487
  serverNode.lifecycle.decommissioned.on(() => {
2117
1488
  this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`);
2118
1489
  this.advertisingNodes.delete(storeId);
2119
1490
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2120
1491
  this.frontend.wssSendSnackbarMessage(`${storeId} is offline`, 5, 'warning');
2121
1492
  });
2122
- /** This event is triggered when the device went online. This means that it is discoverable in the network. */
2123
1493
  serverNode.lifecycle.online.on(async () => {
2124
1494
  this.log.notice(`Server node for ${storeId} is online`);
2125
1495
  if (!serverNode.lifecycle.isCommissioned) {
@@ -2130,16 +1500,13 @@ export class Matterbridge extends EventEmitter {
2130
1500
  this.log.notice(`Manual pairing code: ${manualPairingCode}`);
2131
1501
  }
2132
1502
  else {
2133
- // istanbul ignore next
2134
1503
  this.log.notice(`Server node for ${storeId} is already commissioned. Waiting for controllers to connect ...`);
2135
- // istanbul ignore next
2136
1504
  this.advertisingNodes.delete(storeId);
2137
1505
  }
2138
1506
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2139
1507
  this.frontend.wssSendSnackbarMessage(`${storeId} is online`, 5, 'success');
2140
1508
  this.emit('online', storeId);
2141
1509
  });
2142
- /** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
2143
1510
  serverNode.lifecycle.offline.on(() => {
2144
1511
  this.log.notice(`Server node for ${storeId} is offline`);
2145
1512
  this.advertisingNodes.delete(storeId);
@@ -2147,15 +1514,11 @@ export class Matterbridge extends EventEmitter {
2147
1514
  this.frontend.wssSendSnackbarMessage(`${storeId} is offline`, 5, 'warning');
2148
1515
  this.emit('offline', storeId);
2149
1516
  });
2150
- /**
2151
- * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
2152
- * information is needed.
2153
- */
2154
1517
  serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
2155
1518
  let action = '';
2156
1519
  switch (fabricAction) {
2157
1520
  case 'added':
2158
- this.advertisingNodes.delete(storeId); // The advertising stops when a fabric is added
1521
+ this.advertisingNodes.delete(storeId);
2159
1522
  action = 'added';
2160
1523
  break;
2161
1524
  case 'deleted':
@@ -2168,22 +1531,14 @@ export class Matterbridge extends EventEmitter {
2168
1531
  this.log.notice(`Commissioned fabric index ${fabricIndex} ${action} on server node for ${storeId}: ${debugStringify(serverNode.state.commissioning.fabrics[fabricIndex])}`);
2169
1532
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2170
1533
  });
2171
- /**
2172
- * This event is triggered when an operative new session was opened by a Controller.
2173
- * It is not triggered for the initial commissioning process, just afterwards for real connections.
2174
- */
2175
1534
  serverNode.events.sessions.opened.on((session) => {
2176
1535
  this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
2177
1536
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2178
1537
  });
2179
- /**
2180
- * This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
2181
- */
2182
1538
  serverNode.events.sessions.closed.on((session) => {
2183
1539
  this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
2184
1540
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
2185
1541
  });
2186
- /** This event is triggered when a subscription gets added or removed on an operative session. */
2187
1542
  serverNode.events.sessions.subscriptionsChanged.on((session) => {
2188
1543
  this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
2189
1544
  this.frontend.wssSendRefreshRequired('matter', { matter: { ...this.getServerNodeData(serverNode) } });
@@ -2191,12 +1546,6 @@ export class Matterbridge extends EventEmitter {
2191
1546
  this.log.info(`Created server node for ${storeId}`);
2192
1547
  return serverNode;
2193
1548
  }
2194
- /**
2195
- * Gets the matter sanitized data of the specified server node.
2196
- *
2197
- * @param {ServerNode} [serverNode] - The server node to start.
2198
- * @returns {ApiMatter} The sanitized data of the server node.
2199
- */
2200
1549
  getServerNodeData(serverNode) {
2201
1550
  const advertiseTime = this.advertisingNodes.get(serverNode.id) || 0;
2202
1551
  return {
@@ -2213,27 +1562,14 @@ export class Matterbridge extends EventEmitter {
2213
1562
  serialNumber: serverNode.state.basicInformation.serialNumber,
2214
1563
  };
2215
1564
  }
2216
- /**
2217
- * Starts the specified server node.
2218
- *
2219
- * @param {ServerNode} [matterServerNode] - The server node to start.
2220
- * @returns {Promise<void>} A promise that resolves when the server node has started.
2221
- */
2222
1565
  async startServerNode(matterServerNode) {
2223
1566
  if (!matterServerNode)
2224
1567
  return;
2225
1568
  this.log.notice(`Starting ${matterServerNode.id} server node`);
2226
1569
  await matterServerNode.start();
2227
1570
  }
2228
- /**
2229
- * Stops the specified server node.
2230
- *
2231
- * @param {ServerNode} matterServerNode - The server node to stop.
2232
- * @param {number} [timeout] - The timeout in milliseconds for stopping the server node. Defaults to 10 seconds.
2233
- * @returns {Promise<void>} A promise that resolves when the server node has stopped.
2234
- */
2235
1571
  async stopServerNode(matterServerNode, timeout = 10000) {
2236
- const { withTimeout } = await import('./utils/wait.js');
1572
+ const { withTimeout } = await import('@matterbridge/utils');
2237
1573
  if (!matterServerNode)
2238
1574
  return;
2239
1575
  this.log.notice(`Closing ${matterServerNode.id} server node`);
@@ -2245,25 +1581,12 @@ export class Matterbridge extends EventEmitter {
2245
1581
  this.log.error(`Failed to close ${matterServerNode.id} server node: ${error instanceof Error ? error.message : error}`);
2246
1582
  }
2247
1583
  }
2248
- /**
2249
- * Creates an aggregator node with the specified storage context.
2250
- *
2251
- * @param {StorageContext} storageContext - The storage context for the aggregator node.
2252
- * @returns {Promise<Endpoint<AggregatorEndpoint>>} A promise that resolves to the created aggregator node.
2253
- */
2254
1584
  async createAggregatorNode(storageContext) {
2255
1585
  this.log.notice(`Creating ${await storageContext.get('storeId')} aggregator...`);
2256
1586
  const aggregatorNode = new Endpoint(AggregatorEndpoint, { id: `${await storageContext.get('storeId')}` });
2257
1587
  this.log.info(`Created ${await storageContext.get('storeId')} aggregator`);
2258
1588
  return aggregatorNode;
2259
1589
  }
2260
- /**
2261
- * Creates and configures the server node for an accessory plugin for a given device.
2262
- *
2263
- * @param {Plugin} plugin - The plugin to configure.
2264
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
2265
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
2266
- */
2267
1590
  async createAccessoryPlugin(plugin, device) {
2268
1591
  if (!plugin.locked && device.deviceType && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
2269
1592
  plugin.locked = true;
@@ -2275,12 +1598,6 @@ export class Matterbridge extends EventEmitter {
2275
1598
  await plugin.serverNode.add(device);
2276
1599
  }
2277
1600
  }
2278
- /**
2279
- * Creates and configures the server node and the aggregator node for a dynamic plugin.
2280
- *
2281
- * @param {Plugin} plugin - The plugin to configure.
2282
- * @returns {Promise<void>} A promise that resolves when the server node and the aggregator node for the dynamic plugin is created and configured.
2283
- */
2284
1601
  async createDynamicPlugin(plugin) {
2285
1602
  if (!plugin.locked) {
2286
1603
  plugin.locked = true;
@@ -2293,13 +1610,6 @@ export class Matterbridge extends EventEmitter {
2293
1610
  await plugin.serverNode.add(plugin.aggregatorNode);
2294
1611
  }
2295
1612
  }
2296
- /**
2297
- * Creates and configures the server node for a single not bridged device.
2298
- *
2299
- * @param {Plugin} plugin - The plugin to configure.
2300
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
2301
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
2302
- */
2303
1613
  async createDeviceServerNode(plugin, device) {
2304
1614
  if (device.mode === 'server' && !device.serverNode && device.deviceType && device.deviceName && device.vendorId && device.vendorName && device.productId && device.productName) {
2305
1615
  this.log.debug(`Creating device ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} server node...`);
@@ -2310,16 +1620,8 @@ export class Matterbridge extends EventEmitter {
2310
1620
  this.log.debug(`Added ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to server node`);
2311
1621
  }
2312
1622
  }
2313
- /**
2314
- * Adds a MatterbridgeEndpoint to the specified plugin.
2315
- *
2316
- * @param {string} pluginName - The name of the plugin.
2317
- * @param {MatterbridgeEndpoint} device - The device to add as a bridged endpoint.
2318
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been added.
2319
- */
2320
1623
  async addBridgedEndpoint(pluginName, device) {
2321
- const { waiter } = await import('./utils/wait.js');
2322
- // Check if the plugin is registered
1624
+ const { waiter } = await import('@matterbridge/utils');
2323
1625
  const plugin = this.plugins.get(pluginName);
2324
1626
  if (!plugin) {
2325
1627
  this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
@@ -2339,7 +1641,6 @@ export class Matterbridge extends EventEmitter {
2339
1641
  }
2340
1642
  else if (this.bridgeMode === 'bridge') {
2341
1643
  if (device.mode === 'matter') {
2342
- // Register and add the device to the matterbridge server node
2343
1644
  this.log.debug(`Adding matter endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge server node...`);
2344
1645
  if (!this.serverNode) {
2345
1646
  this.log.error('Server node not found for Matterbridge');
@@ -2356,7 +1657,6 @@ export class Matterbridge extends EventEmitter {
2356
1657
  }
2357
1658
  }
2358
1659
  else {
2359
- // Register and add the device to the matterbridge aggregator node
2360
1660
  this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
2361
1661
  if (!this.aggregatorNode) {
2362
1662
  this.log.error('Aggregator node not found for Matterbridge');
@@ -2374,7 +1674,6 @@ export class Matterbridge extends EventEmitter {
2374
1674
  }
2375
1675
  }
2376
1676
  else if (this.bridgeMode === 'childbridge') {
2377
- // Register and add the device to the plugin server node
2378
1677
  if (plugin.type === 'AccessoryPlatform') {
2379
1678
  try {
2380
1679
  this.log.debug(`Creating endpoint ${dev}${device.deviceName}${db} for AccessoryPlatform plugin ${plg}${plugin.name}${db} server node`);
@@ -2398,12 +1697,10 @@ export class Matterbridge extends EventEmitter {
2398
1697
  return;
2399
1698
  }
2400
1699
  }
2401
- // Register and add the device to the plugin aggregator node
2402
1700
  if (plugin.type === 'DynamicPlatform') {
2403
1701
  try {
2404
1702
  this.log.debug(`Adding bridged endpoint ${dev}${device.deviceName}${db} for DynamicPlatform plugin ${plg}${plugin.name}${db} aggregator node`);
2405
1703
  await this.createDynamicPlugin(plugin);
2406
- // Fast plugins can add another device before the server node is ready, so we wait for the server node to be ready
2407
1704
  await waiter(`createDynamicPlugin(${plugin.name})`, () => plugin.serverNode?.hasParts === true);
2408
1705
  if (!plugin.aggregatorNode) {
2409
1706
  this.log.error(`Aggregator node not found for plugin ${plg}${plugin.name}${er}`);
@@ -2424,22 +1721,12 @@ export class Matterbridge extends EventEmitter {
2424
1721
  }
2425
1722
  if (plugin.registeredDevices !== undefined)
2426
1723
  plugin.registeredDevices++;
2427
- // Add the device to the DeviceManager
2428
1724
  this.devices.set(device);
2429
- // Subscribe to the attributes changed event
2430
1725
  await this.subscribeAttributeChanged(plugin, device);
2431
1726
  this.log.info(`Added and registered bridged endpoint (${plugin.registeredDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) for plugin ${plg}${pluginName}${nf}`);
2432
1727
  }
2433
- /**
2434
- * Removes a MatterbridgeEndpoint from the specified plugin.
2435
- *
2436
- * @param {string} pluginName - The name of the plugin.
2437
- * @param {MatterbridgeEndpoint} device - The device to remove as a bridged endpoint.
2438
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been removed.
2439
- */
2440
1728
  async removeBridgedEndpoint(pluginName, device) {
2441
1729
  this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
2442
- // Check if the plugin is registered
2443
1730
  const plugin = this.plugins.get(pluginName);
2444
1731
  if (!plugin) {
2445
1732
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
@@ -2449,7 +1736,6 @@ export class Matterbridge extends EventEmitter {
2449
1736
  this.log.info(`Removed mode server bridged endpoint(${plugin.registeredDevices}) ${dev}${device.deviceName}${nf} (${zb}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
2450
1737
  }
2451
1738
  else if (this.bridgeMode === 'bridge') {
2452
- // Unregister and remove the device from the matterbridge aggregator node
2453
1739
  if (!this.aggregatorNode) {
2454
1740
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator node not found`);
2455
1741
  return;
@@ -2461,10 +1747,8 @@ export class Matterbridge extends EventEmitter {
2461
1747
  }
2462
1748
  else if (this.bridgeMode === 'childbridge') {
2463
1749
  if (plugin.type === 'AccessoryPlatform') {
2464
- // Nothing to do here since the server node has no aggregator node but only the device itself
2465
1750
  }
2466
1751
  else if (plugin.type === 'DynamicPlatform') {
2467
- // Unregister and remove the device from the plugin aggregator node
2468
1752
  if (!plugin.aggregatorNode) {
2469
1753
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator node not found`);
2470
1754
  return;
@@ -2475,23 +1759,10 @@ export class Matterbridge extends EventEmitter {
2475
1759
  if (plugin.registeredDevices !== undefined)
2476
1760
  plugin.registeredDevices--;
2477
1761
  }
2478
- // Remove the device from the DeviceManager
2479
1762
  this.devices.remove(device);
2480
1763
  }
2481
- /**
2482
- * Removes all bridged endpoints from the specified plugin.
2483
- *
2484
- * @param {string} pluginName - The name of the plugin.
2485
- * @param {number} [delay] - The delay in milliseconds between removing each bridged endpoint (default: 0).
2486
- * @returns {Promise<void>} A promise that resolves when all bridged endpoints have been removed.
2487
- *
2488
- * @remarks
2489
- * This method iterates through all devices in the DeviceManager and removes each bridged endpoint associated with the specified plugin.
2490
- * It also applies a delay between each removal if specified.
2491
- * The delay is useful to allow the controllers to receive a single subscription for each device removed.
2492
- */
2493
1764
  async removeAllBridgedEndpoints(pluginName, delay = 0) {
2494
- const { wait } = await import('./utils/wait.js');
1765
+ const { wait } = await import('@matterbridge/utils');
2495
1766
  this.log.debug(`Removing all bridged endpoints for plugin ${plg}${pluginName}${db}${delay > 0 ? ` with delay ${delay} ms` : ''}`);
2496
1767
  for (const device of this.devices.array().filter((device) => device.plugin === pluginName)) {
2497
1768
  await this.removeBridgedEndpoint(pluginName, device);
@@ -2501,28 +1772,8 @@ export class Matterbridge extends EventEmitter {
2501
1772
  if (delay > 0)
2502
1773
  await wait(2000);
2503
1774
  }
2504
- /**
2505
- * Registers a virtual device.
2506
- * Virtual devices are only supported in bridge mode and childbridge mode with a DynamicPlatform.
2507
- *
2508
- * The virtual device is created as an instance of `Endpoint` with the provided device type.
2509
- * When the virtual device is turned on, the provided callback function is executed.
2510
- * The onOff state of the virtual device always reverts to false when the device is turned on.
2511
- *
2512
- * @param { string } pluginName - The name of the plugin to register the virtual device under.
2513
- * @param { string } name - The name of the virtual device.
2514
- * @param { 'light' | 'outlet' | 'switch' | 'mounted_switch' } type - The type of the virtual device.
2515
- * @param { () => Promise<void> } callback - The callback to call when the virtual device is turned on.
2516
- *
2517
- * @returns {Promise<boolean>} A promise that resolves to true if the virtual device was successfully registered, false otherwise.
2518
- *
2519
- * @remarks
2520
- * The virtual devices don't show up in the device list of the frontend.
2521
- * Type 'switch' is not supported by Alexa and 'mounted_switch' is not supported by Apple Home.
2522
- */
2523
1775
  async addVirtualEndpoint(pluginName, name, type, callback) {
2524
1776
  this.log.debug(`Adding virtual endpoint ${plg}${pluginName}${db}:${dev}${name}${db}...`);
2525
- // Check if the plugin is registered
2526
1777
  const plugin = this.plugins.get(pluginName);
2527
1778
  if (!plugin) {
2528
1779
  this.log.error(`Error adding virtual endpoint ${dev}${name}${er} for plugin ${plg}${pluginName}${er}: plugin not found`);
@@ -2549,24 +1800,13 @@ export class Matterbridge extends EventEmitter {
2549
1800
  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.`);
2550
1801
  return false;
2551
1802
  }
2552
- /**
2553
- * Subscribes to the attribute change event for the given device and plugin.
2554
- * Specifically, it listens for changes in the 'reachable' attribute of the
2555
- * BridgedDeviceBasicInformationServer cluster server of the bridged device or BasicInformationServer cluster server of server node.
2556
- *
2557
- * @param {Plugin} plugin - The plugin associated with the device.
2558
- * @param {MatterbridgeEndpoint} device - The device to subscribe to attribute changes for.
2559
- * @returns {Promise<void>} A promise that resolves when the subscription is set up.
2560
- */
2561
1803
  async subscribeAttributeChanged(plugin, device) {
2562
1804
  if (!plugin || !device || !device.plugin || !device.serialNumber || !device.uniqueId || !device.maybeNumber)
2563
1805
  return;
2564
1806
  this.log.info(`Subscribing attributes for endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) plugin ${plg}${plugin.name}${nf}`);
2565
- // Subscribe to the reachable$Changed event of the BasicInformationServer cluster server of the server node in childbridge mode
2566
1807
  if (this.bridgeMode === 'childbridge' && plugin.type === 'AccessoryPlatform' && plugin.serverNode) {
2567
1808
  plugin.serverNode.eventsOf(BasicInformationServer).reachable$Changed?.on((reachable) => {
2568
1809
  this.log.info(`Accessory endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) is ${reachable ? 'reachable' : 'unreachable'}`);
2569
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2570
1810
  this.frontend.wssSendAttributeChangedMessage(device.plugin, device.serialNumber, device.uniqueId, device.number, device.id, 'BasicInformation', 'reachable', reachable);
2571
1811
  });
2572
1812
  }
@@ -2616,7 +1856,6 @@ export class Matterbridge extends EventEmitter {
2616
1856
  this.log.debug(`Subscribing to endpoint ${or}${device.id}${db}:${or}${device.number}${db} attribute ${dev}${sub.cluster}${db}.${dev}${sub.attribute}${db} changes...`);
2617
1857
  await device.subscribeAttribute(sub.cluster, sub.attribute, (value) => {
2618
1858
  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}`);
2619
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2620
1859
  this.frontend.wssSendAttributeChangedMessage(device.plugin, device.serialNumber, device.uniqueId, device.number, device.id, sub.cluster, sub.attribute, value);
2621
1860
  });
2622
1861
  }
@@ -2625,19 +1864,12 @@ export class Matterbridge extends EventEmitter {
2625
1864
  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...`);
2626
1865
  await child.subscribeAttribute(sub.cluster, sub.attribute, (value) => {
2627
1866
  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}`);
2628
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2629
1867
  this.frontend.wssSendAttributeChangedMessage(device.plugin, device.serialNumber, device.uniqueId, child.number, child.id, sub.cluster, sub.attribute, value);
2630
1868
  });
2631
1869
  }
2632
1870
  }
2633
1871
  }
2634
1872
  }
2635
- /**
2636
- * Sanitizes the fabric information by converting bigint properties to strings because `res.json` doesn't support bigint.
2637
- *
2638
- * @param {ExposedFabricInformation[]} fabricInfo - The array of exposed fabric information objects.
2639
- * @returns {SanitizedExposedFabricInformation[]} An array of sanitized exposed fabric information objects.
2640
- */
2641
1873
  sanitizeFabricInformations(fabricInfo) {
2642
1874
  return fabricInfo.map((info) => {
2643
1875
  return {
@@ -2651,12 +1883,6 @@ export class Matterbridge extends EventEmitter {
2651
1883
  };
2652
1884
  });
2653
1885
  }
2654
- /**
2655
- * Sanitizes the session information by converting bigint properties to strings because `res.json` doesn't support bigint.
2656
- *
2657
- * @param {SessionsBehavior.Session[]} sessions - The array of session information objects.
2658
- * @returns {SanitizedSession[]} An array of sanitized session information objects.
2659
- */
2660
1886
  sanitizeSessionInformation(sessions) {
2661
1887
  return sessions
2662
1888
  .filter((session) => session.isPeerActive)
@@ -2683,21 +1909,7 @@ export class Matterbridge extends EventEmitter {
2683
1909
  };
2684
1910
  });
2685
1911
  }
2686
- /**
2687
- * Sets the reachability of the specified aggregator node bridged devices and trigger.
2688
- *
2689
- * @param {Endpoint<AggregatorEndpoint>} aggregatorNode - The aggregator node to set the reachability for.
2690
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2691
- */
2692
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2693
1912
  async setAggregatorReachability(aggregatorNode, reachable) {
2694
- /*
2695
- for (const child of aggregatorNode.parts) {
2696
- this.log.debug(`Setting reachability of ${(child as unknown as MatterbridgeEndpoint)?.deviceName} to ${reachable}`);
2697
- await child.setStateOf(BridgedDeviceBasicInformationServer, { reachable });
2698
- child.act((agent) => child.eventsOf(BridgedDeviceBasicInformationServer).reachableChanged.emit({ reachableNewValue: true }, agent.context));
2699
- }
2700
- */
2701
1913
  }
2702
1914
  getVendorIdName = (vendorId) => {
2703
1915
  if (!vendorId)
@@ -2737,11 +1949,10 @@ export class Matterbridge extends EventEmitter {
2737
1949
  case 0x1488:
2738
1950
  vendorName = '(ShortcutLabsFlic)';
2739
1951
  break;
2740
- case 65521: // 0xFFF1
1952
+ case 65521:
2741
1953
  vendorName = '(MatterTest)';
2742
1954
  break;
2743
1955
  }
2744
1956
  return vendorName;
2745
1957
  };
2746
1958
  }
2747
- //# sourceMappingURL=matterbridge.js.map