matterbridge 3.2.8 → 3.2.9-dev-20250922-517cae7

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