matterbridge 3.5.2 → 3.5.3-dev-20260202-e19e9b6

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 (280) hide show
  1. package/CHANGELOG.md +30 -1
  2. package/README-DOCKER.md +2 -2
  3. package/README.md +14 -9
  4. package/dist/broadcastServer.d.ts +0 -115
  5. package/dist/broadcastServer.js +0 -117
  6. package/dist/broadcastServerTypes.d.ts +0 -43
  7. package/dist/broadcastServerTypes.js +0 -24
  8. package/dist/checkUpdates.d.ts +0 -75
  9. package/dist/checkUpdates.js +1 -91
  10. package/dist/cli.d.ts +0 -24
  11. package/dist/cli.js +1 -97
  12. package/dist/cliEmitter.d.ts +0 -36
  13. package/dist/cliEmitter.js +0 -37
  14. package/dist/cliHistory.d.ts +0 -42
  15. package/dist/cliHistory.js +0 -38
  16. package/dist/clusters/export.d.ts +0 -1
  17. package/dist/clusters/export.js +0 -2
  18. package/dist/deviceManager.d.ts +0 -108
  19. package/dist/deviceManager.js +1 -114
  20. package/dist/devices/airConditioner.d.ts +0 -75
  21. package/dist/devices/airConditioner.js +0 -57
  22. package/dist/devices/basicVideoPlayer.d.ts +0 -58
  23. package/dist/devices/basicVideoPlayer.js +1 -56
  24. package/dist/devices/batteryStorage.d.ts +0 -43
  25. package/dist/devices/batteryStorage.js +1 -48
  26. package/dist/devices/castingVideoPlayer.d.ts +0 -63
  27. package/dist/devices/castingVideoPlayer.js +2 -65
  28. package/dist/devices/cooktop.d.ts +0 -55
  29. package/dist/devices/cooktop.js +0 -56
  30. package/dist/devices/dishwasher.d.ts +0 -55
  31. package/dist/devices/dishwasher.js +0 -57
  32. package/dist/devices/evse.d.ts +0 -57
  33. package/dist/devices/evse.js +10 -74
  34. package/dist/devices/export.d.ts +0 -1
  35. package/dist/devices/export.js +0 -5
  36. package/dist/devices/extractorHood.d.ts +0 -41
  37. package/dist/devices/extractorHood.js +0 -43
  38. package/dist/devices/heatPump.d.ts +0 -43
  39. package/dist/devices/heatPump.js +2 -50
  40. package/dist/devices/laundryDryer.d.ts +0 -58
  41. package/dist/devices/laundryDryer.js +3 -62
  42. package/dist/devices/laundryWasher.d.ts +0 -64
  43. package/dist/devices/laundryWasher.js +4 -70
  44. package/dist/devices/microwaveOven.d.ts +1 -77
  45. package/dist/devices/microwaveOven.js +5 -88
  46. package/dist/devices/oven.d.ts +0 -82
  47. package/dist/devices/oven.js +0 -85
  48. package/dist/devices/refrigerator.d.ts +0 -100
  49. package/dist/devices/refrigerator.js +0 -102
  50. package/dist/devices/roboticVacuumCleaner.d.ts +0 -83
  51. package/dist/devices/roboticVacuumCleaner.js +9 -100
  52. package/dist/devices/solarPower.d.ts +0 -36
  53. package/dist/devices/solarPower.js +0 -38
  54. package/dist/devices/speaker.d.ts +0 -79
  55. package/dist/devices/speaker.js +0 -84
  56. package/dist/devices/temperatureControl.d.ts +0 -21
  57. package/dist/devices/temperatureControl.js +3 -24
  58. package/dist/devices/waterHeater.d.ts +0 -74
  59. package/dist/devices/waterHeater.js +2 -82
  60. package/dist/dgram/export.d.ts +0 -1
  61. package/dist/dgram/export.js +0 -1
  62. package/dist/frontend.d.ts +0 -187
  63. package/dist/frontend.js +37 -498
  64. package/dist/frontendTypes.d.ts +0 -57
  65. package/dist/frontendTypes.js +0 -45
  66. package/dist/helpers.d.ts +0 -43
  67. package/dist/helpers.js +0 -54
  68. package/dist/index.d.ts +0 -23
  69. package/dist/index.js +0 -25
  70. package/dist/jestutils/export.d.ts +0 -1
  71. package/dist/jestutils/export.js +0 -1
  72. package/dist/jestutils/jestHelpers.d.ts +0 -255
  73. package/dist/jestutils/jestHelpers.js +15 -371
  74. package/dist/logger/export.d.ts +0 -1
  75. package/dist/logger/export.js +0 -1
  76. package/dist/matter/behaviors.d.ts +0 -1
  77. package/dist/matter/behaviors.js +0 -2
  78. package/dist/matter/clusters.d.ts +0 -1
  79. package/dist/matter/clusters.js +0 -2
  80. package/dist/matter/devices.d.ts +0 -1
  81. package/dist/matter/devices.js +0 -2
  82. package/dist/matter/endpoints.d.ts +0 -1
  83. package/dist/matter/endpoints.js +0 -2
  84. package/dist/matter/export.d.ts +0 -1
  85. package/dist/matter/export.js +0 -2
  86. package/dist/matter/types.d.ts +0 -1
  87. package/dist/matter/types.js +0 -2
  88. package/dist/matterNode.d.ts +0 -258
  89. package/dist/matterNode.js +8 -359
  90. package/dist/matterbridge.d.ts +0 -373
  91. package/dist/matterbridge.js +46 -854
  92. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -42
  93. package/dist/matterbridgeAccessoryPlatform.js +0 -50
  94. package/dist/matterbridgeBehaviors.d.ts +0 -24
  95. package/dist/matterbridgeBehaviors.js +5 -65
  96. package/dist/matterbridgeDeviceTypes.d.ts +0 -649
  97. package/dist/matterbridgeDeviceTypes.js +6 -673
  98. package/dist/matterbridgeDynamicPlatform.d.ts +0 -42
  99. package/dist/matterbridgeDynamicPlatform.js +0 -50
  100. package/dist/matterbridgeEndpoint.d.ts +0 -1369
  101. package/dist/matterbridgeEndpoint.js +54 -1507
  102. package/dist/matterbridgeEndpointHelpers.d.ts +0 -425
  103. package/dist/matterbridgeEndpointHelpers.js +20 -482
  104. package/dist/matterbridgeEndpointTypes.d.ts +0 -70
  105. package/dist/matterbridgeEndpointTypes.js +0 -25
  106. package/dist/matterbridgePlatform.d.ts +0 -434
  107. package/dist/matterbridgePlatform.js +1 -472
  108. package/dist/matterbridgePlatformTypes.d.ts +0 -29
  109. package/dist/matterbridgePlatformTypes.js +0 -24
  110. package/dist/matterbridgeTypes.d.ts +0 -46
  111. package/dist/matterbridgeTypes.js +0 -26
  112. package/dist/mb_coap.d.ts +0 -23
  113. package/dist/mb_coap.js +3 -41
  114. package/dist/mb_health.d.ts +0 -67
  115. package/dist/mb_health.js +0 -70
  116. package/dist/mb_mdns.d.ts +0 -23
  117. package/dist/mb_mdns.js +36 -94
  118. package/dist/pluginManager.d.ts +0 -305
  119. package/dist/pluginManager.js +5 -342
  120. package/dist/shelly.d.ts +0 -157
  121. package/dist/shelly.js +7 -178
  122. package/dist/spawn.d.ts +0 -32
  123. package/dist/spawn.js +1 -71
  124. package/dist/storage/export.d.ts +0 -1
  125. package/dist/storage/export.js +0 -1
  126. package/dist/utils/export.d.ts +0 -1
  127. package/dist/utils/export.js +0 -1
  128. package/dist/worker.d.ts +0 -61
  129. package/dist/worker.js +4 -65
  130. package/dist/workerCheckUpdates.d.ts +0 -24
  131. package/dist/workerCheckUpdates.js +5 -36
  132. package/dist/workerGlobalPrefix.d.ts +0 -24
  133. package/dist/workerGlobalPrefix.js +5 -36
  134. package/dist/workerTypes.d.ts +0 -25
  135. package/dist/workerTypes.js +0 -24
  136. package/frontend/build/assets/index.js +4 -4
  137. package/frontend/build/assets/vendor_emotion.js +1 -1
  138. package/frontend/build/assets/vendor_lodash.js +1 -1
  139. package/frontend/build/assets/vendor_mdi.js +1 -1
  140. package/frontend/build/assets/vendor_mui.js +22 -22
  141. package/frontend/build/assets/vendor_node_modules.js +20 -20
  142. package/frontend/build/assets/vendor_notistack.js +2 -2
  143. package/frontend/build/assets/vendor_qrcode.js +1 -1
  144. package/frontend/build/assets/vendor_rjsf.js +8 -8
  145. package/frontend/build/index.html +1 -1
  146. package/frontend/package.json +48 -47
  147. package/npm-shrinkwrap.json +77 -47
  148. package/package.json +7 -7
  149. package/dist/broadcastServer.d.ts.map +0 -1
  150. package/dist/broadcastServer.js.map +0 -1
  151. package/dist/broadcastServerTypes.d.ts.map +0 -1
  152. package/dist/broadcastServerTypes.js.map +0 -1
  153. package/dist/checkUpdates.d.ts.map +0 -1
  154. package/dist/checkUpdates.js.map +0 -1
  155. package/dist/cli.d.ts.map +0 -1
  156. package/dist/cli.js.map +0 -1
  157. package/dist/cliEmitter.d.ts.map +0 -1
  158. package/dist/cliEmitter.js.map +0 -1
  159. package/dist/cliHistory.d.ts.map +0 -1
  160. package/dist/cliHistory.js.map +0 -1
  161. package/dist/clusters/export.d.ts.map +0 -1
  162. package/dist/clusters/export.js.map +0 -1
  163. package/dist/deviceManager.d.ts.map +0 -1
  164. package/dist/deviceManager.js.map +0 -1
  165. package/dist/devices/airConditioner.d.ts.map +0 -1
  166. package/dist/devices/airConditioner.js.map +0 -1
  167. package/dist/devices/basicVideoPlayer.d.ts.map +0 -1
  168. package/dist/devices/basicVideoPlayer.js.map +0 -1
  169. package/dist/devices/batteryStorage.d.ts.map +0 -1
  170. package/dist/devices/batteryStorage.js.map +0 -1
  171. package/dist/devices/castingVideoPlayer.d.ts.map +0 -1
  172. package/dist/devices/castingVideoPlayer.js.map +0 -1
  173. package/dist/devices/cooktop.d.ts.map +0 -1
  174. package/dist/devices/cooktop.js.map +0 -1
  175. package/dist/devices/dishwasher.d.ts.map +0 -1
  176. package/dist/devices/dishwasher.js.map +0 -1
  177. package/dist/devices/evse.d.ts.map +0 -1
  178. package/dist/devices/evse.js.map +0 -1
  179. package/dist/devices/export.d.ts.map +0 -1
  180. package/dist/devices/export.js.map +0 -1
  181. package/dist/devices/extractorHood.d.ts.map +0 -1
  182. package/dist/devices/extractorHood.js.map +0 -1
  183. package/dist/devices/heatPump.d.ts.map +0 -1
  184. package/dist/devices/heatPump.js.map +0 -1
  185. package/dist/devices/laundryDryer.d.ts.map +0 -1
  186. package/dist/devices/laundryDryer.js.map +0 -1
  187. package/dist/devices/laundryWasher.d.ts.map +0 -1
  188. package/dist/devices/laundryWasher.js.map +0 -1
  189. package/dist/devices/microwaveOven.d.ts.map +0 -1
  190. package/dist/devices/microwaveOven.js.map +0 -1
  191. package/dist/devices/oven.d.ts.map +0 -1
  192. package/dist/devices/oven.js.map +0 -1
  193. package/dist/devices/refrigerator.d.ts.map +0 -1
  194. package/dist/devices/refrigerator.js.map +0 -1
  195. package/dist/devices/roboticVacuumCleaner.d.ts.map +0 -1
  196. package/dist/devices/roboticVacuumCleaner.js.map +0 -1
  197. package/dist/devices/solarPower.d.ts.map +0 -1
  198. package/dist/devices/solarPower.js.map +0 -1
  199. package/dist/devices/speaker.d.ts.map +0 -1
  200. package/dist/devices/speaker.js.map +0 -1
  201. package/dist/devices/temperatureControl.d.ts.map +0 -1
  202. package/dist/devices/temperatureControl.js.map +0 -1
  203. package/dist/devices/waterHeater.d.ts.map +0 -1
  204. package/dist/devices/waterHeater.js.map +0 -1
  205. package/dist/dgram/export.d.ts.map +0 -1
  206. package/dist/dgram/export.js.map +0 -1
  207. package/dist/frontend.d.ts.map +0 -1
  208. package/dist/frontend.js.map +0 -1
  209. package/dist/frontendTypes.d.ts.map +0 -1
  210. package/dist/frontendTypes.js.map +0 -1
  211. package/dist/helpers.d.ts.map +0 -1
  212. package/dist/helpers.js.map +0 -1
  213. package/dist/index.d.ts.map +0 -1
  214. package/dist/index.js.map +0 -1
  215. package/dist/jestutils/export.d.ts.map +0 -1
  216. package/dist/jestutils/export.js.map +0 -1
  217. package/dist/jestutils/jestHelpers.d.ts.map +0 -1
  218. package/dist/jestutils/jestHelpers.js.map +0 -1
  219. package/dist/logger/export.d.ts.map +0 -1
  220. package/dist/logger/export.js.map +0 -1
  221. package/dist/matter/behaviors.d.ts.map +0 -1
  222. package/dist/matter/behaviors.js.map +0 -1
  223. package/dist/matter/clusters.d.ts.map +0 -1
  224. package/dist/matter/clusters.js.map +0 -1
  225. package/dist/matter/devices.d.ts.map +0 -1
  226. package/dist/matter/devices.js.map +0 -1
  227. package/dist/matter/endpoints.d.ts.map +0 -1
  228. package/dist/matter/endpoints.js.map +0 -1
  229. package/dist/matter/export.d.ts.map +0 -1
  230. package/dist/matter/export.js.map +0 -1
  231. package/dist/matter/types.d.ts.map +0 -1
  232. package/dist/matter/types.js.map +0 -1
  233. package/dist/matterNode.d.ts.map +0 -1
  234. package/dist/matterNode.js.map +0 -1
  235. package/dist/matterbridge.d.ts.map +0 -1
  236. package/dist/matterbridge.js.map +0 -1
  237. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  238. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  239. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  240. package/dist/matterbridgeBehaviors.js.map +0 -1
  241. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  242. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  243. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  244. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  245. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  246. package/dist/matterbridgeEndpoint.js.map +0 -1
  247. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  248. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  249. package/dist/matterbridgeEndpointTypes.d.ts.map +0 -1
  250. package/dist/matterbridgeEndpointTypes.js.map +0 -1
  251. package/dist/matterbridgePlatform.d.ts.map +0 -1
  252. package/dist/matterbridgePlatform.js.map +0 -1
  253. package/dist/matterbridgePlatformTypes.d.ts.map +0 -1
  254. package/dist/matterbridgePlatformTypes.js.map +0 -1
  255. package/dist/matterbridgeTypes.d.ts.map +0 -1
  256. package/dist/matterbridgeTypes.js.map +0 -1
  257. package/dist/mb_coap.d.ts.map +0 -1
  258. package/dist/mb_coap.js.map +0 -1
  259. package/dist/mb_health.d.ts.map +0 -1
  260. package/dist/mb_health.js.map +0 -1
  261. package/dist/mb_mdns.d.ts.map +0 -1
  262. package/dist/mb_mdns.js.map +0 -1
  263. package/dist/pluginManager.d.ts.map +0 -1
  264. package/dist/pluginManager.js.map +0 -1
  265. package/dist/shelly.d.ts.map +0 -1
  266. package/dist/shelly.js.map +0 -1
  267. package/dist/spawn.d.ts.map +0 -1
  268. package/dist/spawn.js.map +0 -1
  269. package/dist/storage/export.d.ts.map +0 -1
  270. package/dist/storage/export.js.map +0 -1
  271. package/dist/utils/export.d.ts.map +0 -1
  272. package/dist/utils/export.js.map +0 -1
  273. package/dist/worker.d.ts.map +0 -1
  274. package/dist/worker.js.map +0 -1
  275. package/dist/workerCheckUpdates.d.ts.map +0 -1
  276. package/dist/workerCheckUpdates.js.map +0 -1
  277. package/dist/workerGlobalPrefix.d.ts.map +0 -1
  278. package/dist/workerGlobalPrefix.js.map +0 -1
  279. package/dist/workerTypes.d.ts.map +0 -1
  280. package/dist/workerTypes.js.map +0 -1
@@ -1,35 +1,8 @@
1
- /**
2
- * This file contains the class MatterNode.
3
- *
4
- * @file matterNode.ts
5
- * @author Luca Liguori
6
- * @created 2025-10-01
7
- * @version 1.0.0
8
- * @license Apache-2.0
9
- *
10
- * Copyright 2025, 2026, 2027 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 modules
25
1
  import path from 'node:path';
26
2
  import fs from 'node:fs';
27
3
  import EventEmitter from 'node:events';
28
- // AnsiLogger module
29
4
  import { AnsiLogger, BLUE, CYAN, db, debugStringify, er, nf, or, zb } from 'node-ansi-logger';
30
- // Node persist manager module
31
5
  import { NodeStorageManager } from 'node-persist-manager';
32
- // @matter
33
6
  import '@matter/nodejs';
34
7
  import { Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, StorageService, UINT32_MAX, UINT16_MAX, Environment } from '@matter/general';
35
8
  import { MdnsService } from '@matter/protocol';
@@ -38,7 +11,6 @@ import { ServerNode, Endpoint } from '@matter/node';
38
11
  import { AggregatorEndpoint } from '@matter/node/endpoints/aggregator';
39
12
  import { BasicInformationServer } from '@matter/node/behaviors/basic-information';
40
13
  import { BridgedDeviceBasicInformationServer } from '@matter/node/behaviors/bridged-device-basic-information';
41
- // Matterbridge
42
14
  import { copyDirectory, getIntParameter, getParameter, hasParameter, inspectError, isValidNumber, isValidString, parseVersionString, wait, withTimeout } from '@matterbridge/utils';
43
15
  import { dev, MATTER_LOGGER_FILE, MATTER_STORAGE_NAME, plg, NODE_STORAGE_DIR, MATTERBRIDGE_LOGGER_FILE } from './matterbridgeTypes.js';
44
16
  import { bridge } from './matterbridgeDeviceTypes.js';
@@ -46,48 +18,27 @@ import { BroadcastServer } from './broadcastServer.js';
46
18
  import { toBaseDevice } from './deviceManager.js';
47
19
  import { PluginManager } from './pluginManager.js';
48
20
  import { addVirtualDevice } from './helpers.js';
49
- /**
50
- * Represents the Matter class.
51
- */
52
21
  export class MatterNode extends EventEmitter {
53
22
  matterbridge;
54
23
  pluginName;
55
24
  device;
56
- /** Matterbridge logger */
57
- log = new AnsiLogger({ logName: 'MatterNode', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
58
- /** Matter logger */
59
- matterLog = new AnsiLogger({ logName: 'MatterNode', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
60
- /** Matter environment default */
25
+ log = new AnsiLogger({ logName: 'MatterNode', logTimestampFormat: 4, logLevel: "debug" });
26
+ matterLog = new AnsiLogger({ logName: 'MatterNode', logTimestampFormat: 4, logLevel: "debug" });
61
27
  environment = Environment.default;
62
- /** Matter storage id */
63
28
  storeId;
64
- /** Matter mdns service from environment default */
65
29
  matterMdnsService;
66
- /** Matter storage service from environment default */
67
30
  matterStorageService;
68
- /** Matter storage manager created with name 'Matterbridge' */
69
31
  matterStorageManager;
70
- /** Matter storage context created in the storage manager with name 'persist' */
71
32
  matterStorageContext;
72
- /** Matter mdns interface name e.g. 'eth0' or 'wlan0' or 'Wi-Fi' */
73
33
  mdnsInterface;
74
- /** Matter listeningAddressIpv4 address */
75
34
  ipv4Address;
76
- /** Matter listeningAddressIpv6 address */
77
35
  ipv6Address;
78
- /** Matter commissioning port It is incremented in childbridge mode. */
79
36
  port;
80
- /** Matter commissioning passcode. It is incremented in childbridge mode. */
81
37
  passcode;
82
- /** Matter commissioning discriminator. It is incremented in childbridge mode. */
83
38
  discriminator;
84
- /** Matter device certification */
85
39
  certification;
86
- /** Matter server node */
87
40
  serverNode;
88
- /** Matter aggregator node */
89
41
  aggregatorNode;
90
- // Default values for the aggregator node
91
42
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
92
43
  aggregatorVendorName = getParameter('vendorName') ?? 'Matterbridge';
93
44
  aggregatorProductId = getIntParameter('productId') ?? 0x8000;
@@ -95,23 +46,12 @@ export class MatterNode extends EventEmitter {
95
46
  aggregatorDeviceType = DeviceTypeId(getIntParameter('deviceType') ?? bridge.code);
96
47
  aggregatorSerialNumber = getParameter('serialNumber');
97
48
  aggregatorUniqueId = getParameter('uniqueId');
98
- /** Advertising nodes map: time advertising started keyed by storeId */
99
49
  advertisingNodes = new Map();
100
- /** Plugins */
101
50
  pluginManager;
102
- /** Dependant MatterNodes keyed by device id */
103
51
  dependantMatterNodes = new Map();
104
- /** Broadcast server */
105
52
  server;
106
53
  debug = hasParameter('debug') || hasParameter('verbose');
107
54
  verbose = hasParameter('verbose');
108
- /**
109
- * Creates an instance of the Matter class.
110
- *
111
- * @param {SharedMatterbridge} matterbridge - The shared matterbridge instance.
112
- * @param {PluginName} [pluginName] - The plugin name (optional). If not provided, it is assumed to be the main matter node instance and all plugins are included.
113
- * @param {MatterbridgeEndpoint} [device] - The matterbridge endpoint device (optional). It is used to create a server mode device.
114
- */
115
55
  constructor(matterbridge, pluginName, device) {
116
56
  super();
117
57
  this.matterbridge = matterbridge;
@@ -120,25 +60,19 @@ export class MatterNode extends EventEmitter {
120
60
  this.log.logNameColor = '\x1b[38;5;65m';
121
61
  if (this.debug)
122
62
  this.log.debug(`MatterNode ${this.pluginName ? 'for plugin ' + this.pluginName : 'bridge'} loading...`);
123
- // Setup Matter parameters
124
63
  this.port = matterbridge.port;
125
64
  this.passcode = matterbridge.passcode;
126
65
  this.discriminator = matterbridge.discriminator;
127
- // Setup the broadcast server
128
66
  this.server = new BroadcastServer('matter', this.log);
129
67
  this.server.on('broadcast_message', this.msgHandler.bind(this));
130
68
  if (this.verbose)
131
69
  this.log.debug(`BroadcastServer is ready`);
132
- // Ensure the matterbridge directory exists
133
70
  fs.mkdirSync(matterbridge.matterbridgeDirectory, { recursive: true });
134
- // Setup the plugin manager with thread server closed
135
71
  this.pluginManager = new PluginManager(this.matterbridge);
136
- this.pluginManager.logLevel = this.debug ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */;
137
- // @ts-expect-error access private property
72
+ this.pluginManager.logLevel = this.debug ? "debug" : "info";
138
73
  this.pluginManager.server.close();
139
74
  if (this.verbose)
140
75
  this.log.debug(`PluginManager is ready`);
141
- // Setup the matter environment
142
76
  this.environment.vars.set('log.level', MatterLogLevel.DEBUG);
143
77
  this.environment.vars.set('log.format', MatterLogFormat.ANSI);
144
78
  this.environment.vars.set('path.root', path.join(matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME));
@@ -146,18 +80,15 @@ export class MatterNode extends EventEmitter {
146
80
  this.environment.vars.set('runtime.exitcode', false);
147
81
  if (this.verbose)
148
82
  this.log.debug(`Matter Environment is ready`);
149
- // Ensure MdnsService is registered in the default environment
150
83
  this.matterMdnsService = new MdnsService(this.environment);
151
84
  setImmediate(async () => {
152
85
  await this.matterMdnsService?.construction.ready;
153
86
  if (this.verbose)
154
87
  this.log.debug(`Matter MdnsService is ready`);
155
88
  });
156
- // Setup the matterbridge logger
157
89
  if (this.matterbridge.fileLogger) {
158
90
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, MATTERBRIDGE_LOGGER_FILE), this.matterbridge.logLevel);
159
91
  }
160
- // Setup the matter logger
161
92
  Logger.destinations.default.write = this.createDestinationMatterLogger();
162
93
  const levels = ['debug', 'info', 'notice', 'warn', 'error', 'fatal'];
163
94
  if (this.verbose)
@@ -165,11 +96,6 @@ export class MatterNode extends EventEmitter {
165
96
  if (this.debug)
166
97
  this.log.debug(`MatterNode ${this.pluginName ? 'for plugin ' + this.pluginName : 'bridge'} loaded`);
167
98
  }
168
- /**
169
- * Handles incoming messages from the broadcast server.
170
- *
171
- * @param {WorkerMessage} msg - The incoming message.
172
- */
173
99
  async msgHandler(msg) {
174
100
  if (this.server.isWorkerRequest(msg) && (msg.dst === 'all' || msg.dst === 'matter')) {
175
101
  if (this.verbose)
@@ -200,17 +126,9 @@ export class MatterNode extends EventEmitter {
200
126
  }
201
127
  }
202
128
  }
203
- /**
204
- * Destroys the Matter instance.
205
- * It closes the mDNS service and the broadcast server.
206
- *
207
- * @param {boolean} closeMdns - Whether to close the mDNS service. Default is true.
208
- * @returns {Promise<void>} A promise that resolves when the instance is destroyed.
209
- */
210
129
  async destroy(closeMdns = true) {
211
130
  if (this.verbose)
212
131
  this.log.debug(`Destroying MatterNode instance for ${this.storeId}...`);
213
- // Close mDNS service
214
132
  if (closeMdns) {
215
133
  if (this.verbose)
216
134
  this.log.debug(`Closing Matter MdnsService for ${this.storeId}...`);
@@ -218,26 +136,18 @@ export class MatterNode extends EventEmitter {
218
136
  if (this.verbose)
219
137
  this.log.debug(`Closed Matter MdnsService for ${this.storeId}`);
220
138
  }
221
- // Close the plugin manager
222
139
  this.pluginManager.destroy();
223
- // Close the broadcast server
224
140
  this.server.close();
225
- // Yield to the Node.js event loop to allow all resources to be released
226
141
  await this.yieldToNode();
227
142
  if (this.verbose)
228
143
  this.log.debug(`Destroyed MatterNode instance for ${this.storeId}`);
229
144
  }
230
145
  async create() {
231
146
  this.log.info('Creating Matter node...');
232
- // Start matter storage
233
147
  await this.startMatterStorage();
234
- // Load plugins from storage
235
- // @ts-expect-error access private property
236
148
  this.pluginManager.matterbridge.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridge.matterbridgeDirectory, NODE_STORAGE_DIR), writeQueue: false, expiredInterval: undefined, logging: false });
237
- // @ts-expect-error access private property
238
149
  this.pluginManager.matterbridge.nodeContext = await this.pluginManager.matterbridge.nodeStorage.createStorage('matterbridge');
239
150
  await this.pluginManager.loadFromStorage();
240
- // Create Matter node for a server mode device
241
151
  if (this.pluginName && this.device && this.device.deviceName) {
242
152
  this.log.debug(`Creating MatterNode instance for server node device ${CYAN}${this.device.deviceName}${db}...`);
243
153
  await this.createDeviceServerNode(this.pluginName, this.device);
@@ -248,7 +158,6 @@ export class MatterNode extends EventEmitter {
248
158
  if (!this.pluginName) {
249
159
  this.log.debug('Creating MatterNode instance for all plugins...');
250
160
  await this.createMatterbridgeServerNode();
251
- // Load all enabled plugins
252
161
  this.log.debug('Loading all plugins...');
253
162
  const loadPromises = [];
254
163
  for (const plugin of this.pluginManager.array().filter((p) => p.enabled)) {
@@ -261,7 +170,6 @@ export class MatterNode extends EventEmitter {
261
170
  }
262
171
  else {
263
172
  this.log.debug(`Creating MatterNode instance for plugin ${CYAN}${this.pluginName}${db}...`);
264
- // Load only the specified plugin
265
173
  this.log.debug(`Loading plugin ${CYAN}${this.pluginName}${db}...`);
266
174
  await this.pluginManager.load(this.pluginName);
267
175
  this.log.debug(`Loaded plugin ${CYAN}${this.pluginName}${db}`);
@@ -275,16 +183,13 @@ export class MatterNode extends EventEmitter {
275
183
  if (!this.serverNode && !this.pluginName)
276
184
  throw new Error('Matter server node not created yet. Call create() first.');
277
185
  this.log.info('Starting MatterNode...');
278
- // Start Matter node for a server mode device
279
186
  if (this.pluginName && this.device && this.device.deviceName) {
280
- // Start the server node
281
187
  this.log.debug(`Starting MatterNode for server device ${this.pluginName}:${this.device.deviceName}...`);
282
188
  await this.startServerNode();
283
189
  this.log.debug(`Started MatterNode for server device ${this.pluginName}:${this.device.deviceName}`);
284
190
  return;
285
191
  }
286
192
  if (!this.pluginName) {
287
- // Start all loaded plugins
288
193
  this.log.debug('Starting all plugins...');
289
194
  const startPromises = [];
290
195
  for (const plugin of this.pluginManager.array().filter((p) => p.enabled && p.loaded)) {
@@ -292,11 +197,9 @@ export class MatterNode extends EventEmitter {
292
197
  }
293
198
  await Promise.all(startPromises);
294
199
  this.log.debug('Started all plugins');
295
- // Start the server node
296
200
  this.log.debug('Starting MatterNode for all plugins...');
297
201
  await this.startServerNode();
298
202
  this.log.debug('Started MatterNode for all plugins');
299
- // Configure all loaded plugins
300
203
  this.log.debug('Configuring all plugins...');
301
204
  const configurePromises = [];
302
205
  for (const plugin of this.pluginManager.array().filter((p) => p.enabled && p.started)) {
@@ -306,16 +209,12 @@ export class MatterNode extends EventEmitter {
306
209
  this.log.debug('Configured all plugins');
307
210
  }
308
211
  else {
309
- // Start the loaded plugin
310
212
  await this.pluginManager.start(this.pluginName, 'Starting MatterNode');
311
- // Start the server node
312
213
  this.log.debug(`Starting MatterNode for plugin ${this.pluginName}...`);
313
214
  await this.startServerNode();
314
215
  this.log.debug(`Started MatterNode for plugin ${this.pluginName}`);
315
- // Configure the plugin
316
216
  await this.pluginManager.configure(this.pluginName);
317
217
  }
318
- // Start the dependant MatterNodes
319
218
  this.log.debug(`Starting dependant MatterNodes...`);
320
219
  for (const dependantMatterNode of this.dependantMatterNodes.values()) {
321
220
  await dependantMatterNode.start();
@@ -328,15 +227,13 @@ export class MatterNode extends EventEmitter {
328
227
  if (!this.serverNode)
329
228
  throw new Error('Matter server node not created yet. Call create() first.');
330
229
  this.log.info('Stopping MatterNode...');
331
- // Stop Matter node for a server mode device
332
230
  if (this.pluginName && this.device && this.device.deviceName) {
333
- // Stop the server node
334
231
  this.log.debug(`Stopping MatterNode for server device ${this.pluginName}:${this.device.deviceName}...`);
335
232
  await this.stopServerNode();
336
233
  this.serverNode = undefined;
337
234
  this.aggregatorNode = undefined;
338
235
  await this.stopMatterStorage();
339
- await this.destroy(false); // Do not close mDNS since it is shared
236
+ await this.destroy(false);
340
237
  this.log.debug(`Stopped MatterNode for server device ${this.pluginName}:${this.device.deviceName}`);
341
238
  this.log.info('Stopped MatterNode');
342
239
  await this.yieldToNode();
@@ -356,7 +253,6 @@ export class MatterNode extends EventEmitter {
356
253
  await this.pluginManager.shutdown(this.pluginName, 'Stopping MatterNode');
357
254
  this.log.debug(`Stopped plugin ${this.pluginName}`);
358
255
  }
359
- // Stop the dependant MatterNodes
360
256
  this.log.debug(`Stopping dependant MatterNodes...`);
361
257
  for (const dependantMatterNode of this.dependantMatterNodes.values()) {
362
258
  await dependantMatterNode.stop();
@@ -369,46 +265,24 @@ export class MatterNode extends EventEmitter {
369
265
  this.log.info('Stopped MatterNode');
370
266
  await this.yieldToNode();
371
267
  }
372
- /**
373
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (console and frontend).
374
- * It also logs to file (matter.log) if fileLogger is true.
375
- *
376
- * @returns {Function} The MatterLogger function. \x1b[35m for violet \x1b[34m is blue
377
- */
378
268
  createDestinationMatterLogger() {
379
- this.matterLog.logNameColor = '\x1b[34m'; // Blue matter.js Logger
269
+ this.matterLog.logNameColor = '\x1b[34m';
380
270
  if (this.matterbridge.matterFileLogger) {
381
271
  this.matterLog.logFilePath = path.join(this.matterbridge.matterbridgeDirectory, MATTER_LOGGER_FILE);
382
272
  }
383
273
  return (text, message) => {
384
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
385
274
  const logger = text.slice(44, 44 + 20).trim();
386
275
  const msg = text.slice(65);
387
276
  this.matterLog.logName = logger;
388
277
  this.matterLog.log(MatterLogLevel.names[message.level], msg);
389
278
  };
390
279
  }
391
- /**
392
- * Starts the matter storage with name Matterbridge and performs a backup.
393
- *
394
- * @returns {Promise<void>} - A promise that resolves when the storage is started.
395
- */
396
280
  async startMatterStorage() {
397
- // Setup Matter storage
398
281
  this.log.info(`Starting matter node storage...`);
399
282
  this.matterStorageService = this.environment.get(StorageService);
400
283
  this.log.info(`Started matter node storage in ${CYAN}${this.matterStorageService.location}${nf}`);
401
- // Backup matter storage since it is created/opened correctly
402
284
  await this.backupMatterStorage(path.join(this.matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME), path.join(this.matterbridge.matterbridgeDirectory, MATTER_STORAGE_NAME + '.backup'));
403
285
  }
404
- /**
405
- * Makes a backup copy of the specified matter storage directory.
406
- *
407
- * @param {string} storageName - The name of the storage directory to be backed up.
408
- * @param {string} backupName - The name of the backup directory to be created.
409
- * @private
410
- * @returns {Promise<void>} A promise that resolves when the has been done.
411
- */
412
286
  async backupMatterStorage(storageName, backupName) {
413
287
  this.log.info(`Creating matter node storage backup from ${CYAN}${storageName}${nf} to ${CYAN}${backupName}${nf}...`);
414
288
  try {
@@ -416,7 +290,6 @@ export class MatterNode extends EventEmitter {
416
290
  this.log.info('Created matter node storage backup');
417
291
  }
418
292
  catch (error) {
419
- // istanbul ignore next if
420
293
  if (error instanceof Error && error?.code === 'ENOENT') {
421
294
  this.log.info(`No matter node storage found to backup from ${CYAN}${storageName}${nf} to ${CYAN}${backupName}${nf}`);
422
295
  }
@@ -425,11 +298,6 @@ export class MatterNode extends EventEmitter {
425
298
  }
426
299
  }
427
300
  }
428
- /**
429
- * Stops the matter storage.
430
- *
431
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
432
- */
433
301
  async stopMatterStorage() {
434
302
  this.log.info('Closing matter node storage...');
435
303
  await this.matterStorageManager?.close();
@@ -439,21 +307,6 @@ export class MatterNode extends EventEmitter {
439
307
  this.log.info('Closed matter node storage');
440
308
  this.emit('closed');
441
309
  }
442
- /**
443
- * Creates a server node storage context.
444
- *
445
- * @param {string} storeId - The storeId.
446
- * @param {string} deviceName - The name of the device.
447
- * @param {DeviceTypeId} deviceType - The device type of the device.
448
- * @param {VendorId} vendorId - The vendor ID.
449
- * @param {string} vendorName - The vendor name.
450
- * @param {number} productId - The product ID.
451
- * @param {string} productName - The product name.
452
- * @param {string} [serialNumber] - The serial number of the device (optional).
453
- * @param {string} [uniqueId] - The unique ID of the device (optional).
454
- * @returns {Promise<StorageContext>} The storage context for the commissioning server.
455
- * @throws {Error} If the storage service is not initialized.
456
- */
457
310
  async createServerNodeContext(storeId, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber, uniqueId) {
458
311
  if (!this.matterStorageService) {
459
312
  throw new Error('No storage service initialized');
@@ -496,52 +349,33 @@ export class MatterNode extends EventEmitter {
496
349
  this.log.debug(`- hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
497
350
  return storageContext;
498
351
  }
499
- /**
500
- * Creates a server node.
501
- *
502
- * @param {number} [port] - The port number for the server node. Defaults to 5540.
503
- * @param {number} [passcode] - The passcode for the server node. Defaults to 20242025.
504
- * @param {number} [discriminator] - The discriminator for the server node. Defaults to 3850.
505
- * @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created server node.
506
- * @throws {Error} If the matter storage context is not created yet.
507
- */
508
352
  async createServerNode(port = 5540, passcode = 20252026, discriminator = 3850) {
509
353
  if (!this.matterStorageContext) {
510
354
  throw new Error('Matter server node context not created yet. Call createServerNodeContext() first.');
511
355
  }
512
356
  const storeId = await this.matterStorageContext.get('storeId');
513
357
  this.log.notice(`Creating server node for ${storeId} on port ${port} with passcode ${passcode} and discriminator ${discriminator}...`);
514
- /**
515
- * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
516
- */
517
358
  const serverNode = await ServerNode.create({
518
- // Required: Give the Node a unique ID which is used to store the state of this node
519
359
  id: storeId,
520
- // Provide the environment to run this node in
521
360
  environment: this.environment,
522
- // Provide Network relevant configuration like the port
523
361
  network: {
524
362
  listeningAddressIpv4: this.ipv4Address,
525
363
  listeningAddressIpv6: this.ipv6Address,
526
364
  port,
527
365
  },
528
- // Provide the certificate for the device
529
366
  operationalCredentials: {
530
367
  certification: this.certification,
531
368
  },
532
- // Provide Commissioning relevant settings
533
369
  commissioning: {
534
370
  passcode,
535
371
  discriminator,
536
372
  },
537
- // Provide Node announcement settings
538
373
  productDescription: {
539
374
  name: await this.matterStorageContext.get('deviceName'),
540
375
  deviceType: DeviceTypeId(await this.matterStorageContext.get('deviceType')),
541
376
  vendorId: VendorId(await this.matterStorageContext.get('vendorId')),
542
377
  productId: await this.matterStorageContext.get('productId'),
543
378
  },
544
- // Provide defaults for the BasicInformation cluster on the Root endpoint
545
379
  basicInformation: {
546
380
  vendorId: VendorId(await this.matterStorageContext.get('vendorId')),
547
381
  vendorName: await this.matterStorageContext.get('vendorName'),
@@ -558,23 +392,17 @@ export class MatterNode extends EventEmitter {
558
392
  reachable: true,
559
393
  },
560
394
  });
561
- /**
562
- * This event is triggered when the device is initially commissioned successfully.
563
- * This means: It is added to the first fabric.
564
- */
565
395
  serverNode.lifecycle.commissioned.on(() => {
566
396
  this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`);
567
397
  this.advertisingNodes.delete(storeId);
568
398
  this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
569
399
  });
570
- /** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
571
400
  serverNode.lifecycle.decommissioned.on(() => {
572
401
  this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`);
573
402
  this.advertisingNodes.delete(storeId);
574
403
  this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
575
404
  this.server.request({ type: 'frontend_snackbarmessage', src: 'matter', dst: 'frontend', params: { message: `${storeId} is offline`, timeout: 5, severity: 'warning' } });
576
405
  });
577
- /** This event is triggered when the device went online. This means that it is discoverable in the network. */
578
406
  serverNode.lifecycle.online.on(async () => {
579
407
  this.log.notice(`Server node for ${storeId} is online`);
580
408
  if (!serverNode.lifecycle.isCommissioned) {
@@ -592,7 +420,6 @@ export class MatterNode extends EventEmitter {
592
420
  this.server.request({ type: 'frontend_snackbarmessage', src: 'matter', dst: 'frontend', params: { message: `${storeId} is online`, timeout: 5, severity: 'success' } });
593
421
  this.emit('online', storeId);
594
422
  });
595
- /** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
596
423
  serverNode.lifecycle.offline.on(() => {
597
424
  this.log.notice(`Server node for ${storeId} is offline`);
598
425
  this.advertisingNodes.delete(storeId);
@@ -600,15 +427,11 @@ export class MatterNode extends EventEmitter {
600
427
  this.server.request({ type: 'frontend_snackbarmessage', src: 'matter', dst: 'frontend', params: { message: `${storeId} is offline`, timeout: 5, severity: 'warning' } });
601
428
  this.emit('offline', storeId);
602
429
  });
603
- /**
604
- * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
605
- * information is needed.
606
- */
607
430
  serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
608
431
  let action = '';
609
432
  switch (fabricAction) {
610
433
  case 'added':
611
- this.advertisingNodes.delete(storeId); // The advertising stops when a fabric is added
434
+ this.advertisingNodes.delete(storeId);
612
435
  action = 'added';
613
436
  break;
614
437
  case 'deleted':
@@ -621,22 +444,14 @@ export class MatterNode extends EventEmitter {
621
444
  this.log.notice(`Commissioned fabric index ${fabricIndex} ${action} on server node for ${storeId}: ${debugStringify(serverNode.state.commissioning.fabrics[fabricIndex])}`);
622
445
  this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
623
446
  });
624
- /**
625
- * This event is triggered when an operative new session was opened by a Controller.
626
- * It is not triggered for the initial commissioning process, just afterwards for real connections.
627
- */
628
447
  serverNode.events.sessions.opened.on((session) => {
629
448
  this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
630
449
  this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
631
450
  });
632
- /**
633
- * This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
634
- */
635
451
  serverNode.events.sessions.closed.on((session) => {
636
452
  this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
637
453
  this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
638
454
  });
639
- /** This event is triggered when a subscription gets added or removed on an operative session. */
640
455
  serverNode.events.sessions.subscriptionsChanged.on((session) => {
641
456
  this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
642
457
  this.server.request({ type: 'frontend_refreshrequired', src: 'matter', dst: 'frontend', params: { changed: 'matter', matter: { ...this.getServerNodeData(serverNode) } } });
@@ -645,12 +460,6 @@ export class MatterNode extends EventEmitter {
645
460
  this.log.info(`Created server node for ${this.storeId}`);
646
461
  return serverNode;
647
462
  }
648
- /**
649
- * Gets the matter serializable data of the specified server node.
650
- *
651
- * @param {ServerNode} [serverNode] - The server node to start.
652
- * @returns {ApiMatter} The serializable data of the server node.
653
- */
654
463
  getServerNodeData(serverNode) {
655
464
  const advertiseTime = this.advertisingNodes.get(serverNode.id) || 0;
656
465
  return {
@@ -667,13 +476,6 @@ export class MatterNode extends EventEmitter {
667
476
  serialNumber: serverNode.state.basicInformation.serialNumber,
668
477
  };
669
478
  }
670
- /**
671
- * Starts the specified server node.
672
- *
673
- * @param {number} [timeout] - The timeout in milliseconds for starting the server node. Defaults to 30 seconds.
674
- * @returns {Promise<void>} A promise that resolves when the server node has started.
675
- * @throws {Error} If the server node is not created yet.
676
- */
677
479
  async startServerNode(timeout = 30000) {
678
480
  if (!this.serverNode) {
679
481
  throw new Error('Matter server node not created yet. Call create() first.');
@@ -684,17 +486,9 @@ export class MatterNode extends EventEmitter {
684
486
  this.log.notice(`Started ${this.serverNode.id} server node`);
685
487
  }
686
488
  catch (error) {
687
- // istanbul ignore next
688
489
  this.log.error(`Failed to start ${this.serverNode.id} server node: ${error instanceof Error ? error.message : error}`);
689
490
  }
690
491
  }
691
- /**
692
- * Stops the specified server node.
693
- *
694
- * @param {number} [timeout] - The timeout in milliseconds for stopping the server node. Defaults to 30 seconds.
695
- * @returns {Promise<void>} A promise that resolves when the server node has stopped.
696
- * @throws {Error} If the server node is not created yet.
697
- */
698
492
  async stopServerNode(timeout = 30000) {
699
493
  if (!this.serverNode) {
700
494
  throw new Error('Matter server node not created yet. Call create() first.');
@@ -705,16 +499,9 @@ export class MatterNode extends EventEmitter {
705
499
  this.log.info(`Closed ${this.serverNode.id} server node`);
706
500
  }
707
501
  catch (error) {
708
- // istanbul ignore next
709
502
  this.log.error(`Failed to close ${this.serverNode.id} server node: ${error instanceof Error ? error.message : error}`);
710
503
  }
711
504
  }
712
- /**
713
- * Creates an aggregator node with the specified storage context.
714
- *
715
- * @returns {Promise<Endpoint<AggregatorEndpoint>>} A promise that resolves to the created aggregator node.
716
- * @throws {Error} If the matter storage context is not created yet.
717
- */
718
505
  async createAggregatorNode() {
719
506
  if (!this.matterStorageContext) {
720
507
  throw new Error('Matter server node context not created yet. Call createServerNodeContext() first.');
@@ -724,16 +511,9 @@ export class MatterNode extends EventEmitter {
724
511
  this.log.info(`Created ${await this.matterStorageContext.get('storeId')} aggregator`);
725
512
  return aggregatorNode;
726
513
  }
727
- /**
728
- * Creates the matterbridge server node.
729
- *
730
- * @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created matterbridge server node.
731
- */
732
514
  async createMatterbridgeServerNode() {
733
515
  this.log.debug(`Creating ${plg}Matterbridge${db} server node...`);
734
- this.matterStorageContext = await this.createServerNodeContext('Matterbridge', // storeId
735
- 'Matterbridge', // deviceName
736
- this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId);
516
+ this.matterStorageContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', this.aggregatorDeviceType, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName, this.aggregatorSerialNumber, this.aggregatorUniqueId);
737
517
  this.serverNode = await this.createServerNode(this.port ? this.port++ : undefined, this.passcode ? this.passcode++ : undefined, this.discriminator ? this.discriminator++ : undefined);
738
518
  this.aggregatorNode = await this.createAggregatorNode();
739
519
  this.log.debug(`Adding ${plg}Matterbridge${db} aggregator node...`);
@@ -744,13 +524,6 @@ export class MatterNode extends EventEmitter {
744
524
  this.log.debug(`Created ${plg}Matterbridge${db} server node`);
745
525
  return this.serverNode;
746
526
  }
747
- /**
748
- * Creates and configures the server node for an accessory plugin for a given device.
749
- *
750
- * @param {Plugin | PluginName} plugin - The plugin to configure.
751
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
752
- * @returns {Promise<ServerNode<ServerNode.RootEndpoint> | undefined>} A promise that resolves to the server node for the accessory plugin.
753
- */
754
527
  async createAccessoryPlugin(plugin, device) {
755
528
  if (typeof plugin === 'string') {
756
529
  const _plugin = this.pluginManager.get(plugin);
@@ -772,12 +545,6 @@ export class MatterNode extends EventEmitter {
772
545
  }
773
546
  return this.serverNode;
774
547
  }
775
- /**
776
- * Creates and configures the server node and the aggregator node for a dynamic plugin.
777
- *
778
- * @param {Plugin | PluginName} plugin - The plugin to configure.
779
- * @returns {Promise<ServerNode<ServerNode.RootEndpoint> | undefined>} A promise that resolves to the server node for the dynamic plugin.
780
- */
781
548
  async createDynamicPlugin(plugin) {
782
549
  if (typeof plugin === 'string') {
783
550
  const _plugin = this.pluginManager.get(plugin);
@@ -801,13 +568,6 @@ export class MatterNode extends EventEmitter {
801
568
  }
802
569
  return this.serverNode;
803
570
  }
804
- /**
805
- * Creates and configures the server node for a single not bridged device.
806
- *
807
- * @param {Plugin | PluginName} plugin - The plugin to configure.
808
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
809
- * @returns {Promise<ServerNode<ServerNode.RootEndpoint> | undefined>} A promise that resolves to the server node for the device with mode server.
810
- */
811
571
  async createDeviceServerNode(plugin, device) {
812
572
  if (typeof plugin === 'string') {
813
573
  const _plugin = this.pluginManager.get(plugin);
@@ -828,22 +588,13 @@ export class MatterNode extends EventEmitter {
828
588
  }
829
589
  return this.serverNode;
830
590
  }
831
- /**
832
- * Adds a MatterbridgeEndpoint to the specified plugin.
833
- *
834
- * @param {string} pluginName - The name of the plugin.
835
- * @param {MatterbridgeEndpoint} device - The device to add as a bridged endpoint.
836
- * @returns {Promise<MatterbridgeEndpoint | undefined>} A promise that resolves to the added bridged endpoint, or undefined if there was an error.
837
- */
838
591
  async addBridgedEndpoint(pluginName, device) {
839
- // Check if the plugin is registered
840
592
  const plugin = this.pluginManager.get(pluginName);
841
593
  if (!plugin)
842
594
  throw new Error(`Error adding bridged endpoint ${plg}${pluginName}${er}:${dev}${device.deviceName}${er} (${zb}${device.name}${er}): plugin not found`);
843
595
  if (device.mode === 'server') {
844
596
  try {
845
597
  this.log.debug(`Creating MatterNode for device ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
846
- // Create the MatterNode to manage the device
847
598
  const matterNode = new MatterNode(this.matterbridge, pluginName, device);
848
599
  matterNode.port = this.port ? this.port++ : undefined;
849
600
  matterNode.passcode = this.passcode ? this.passcode++ : undefined;
@@ -859,7 +610,6 @@ export class MatterNode extends EventEmitter {
859
610
  }
860
611
  else if (this.matterbridge.bridgeMode === 'bridge') {
861
612
  if (device.mode === 'matter') {
862
- // Register and add the device to the Matter server node
863
613
  this.log.debug(`Adding matter endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
864
614
  if (!this.serverNode)
865
615
  throw new Error(`Server node not found for matter endpoint ${plg}${pluginName}${er}:${dev}${device.deviceName}${er} (${zb}${device.name}${er})`);
@@ -872,7 +622,6 @@ export class MatterNode extends EventEmitter {
872
622
  }
873
623
  }
874
624
  else {
875
- // Register and add the device to the Matter aggregator node
876
625
  this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
877
626
  if (!this.aggregatorNode)
878
627
  throw new Error(`Aggregator node not found for endpoint ${plg}${pluginName}${er}:${dev}${device.deviceName}${er} (${zb}${device.name}${er})`);
@@ -886,7 +635,6 @@ export class MatterNode extends EventEmitter {
886
635
  }
887
636
  }
888
637
  else if (this.matterbridge.bridgeMode === 'childbridge') {
889
- // Register and add the device to the plugin server node
890
638
  if (plugin.type === 'AccessoryPlatform') {
891
639
  try {
892
640
  this.log.debug(`Adding accessory endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
@@ -902,12 +650,10 @@ export class MatterNode extends EventEmitter {
902
650
  return;
903
651
  }
904
652
  }
905
- // Register and add the device to the plugin aggregator node
906
653
  if (plugin.type === 'DynamicPlatform') {
907
654
  try {
908
655
  this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
909
656
  if (!this.serverNode) {
910
- // Fast plugins can add another device before the server node is ready, so we wait for the server node to be ready
911
657
  await this.createDynamicPlugin(plugin);
912
658
  }
913
659
  if (device.mode === 'matter')
@@ -923,30 +669,19 @@ export class MatterNode extends EventEmitter {
923
669
  }
924
670
  if (plugin.registeredDevices !== undefined)
925
671
  plugin.registeredDevices++;
926
- // Add the device to the DeviceManager
927
672
  await device.construction.ready;
928
673
  await this.server.fetch({ type: 'devices_set', src: this.server.name, dst: 'devices', params: { device: toBaseDevice(device) } });
929
- // Subscribe to the attributes changed event
930
674
  await this.subscribeAttributeChanged(plugin, device);
931
675
  this.log.info(`Added endpoint #${plugin.registeredDevices} ${plg}${pluginName}${nf}:${dev}${device.deviceName}${nf} (${zb}${device.name}${nf})`);
932
676
  await this.yieldToNode(10);
933
677
  return device;
934
678
  }
935
- /**
936
- * Removes a MatterbridgeEndpoint from the specified plugin.
937
- *
938
- * @param {string} pluginName - The name of the plugin.
939
- * @param {MatterbridgeEndpoint} device - The device to remove as a bridged endpoint.
940
- * @returns {Promise<MatterbridgeEndpoint | undefined>} A promise that resolves to the removed bridged endpoint, or undefined if there was an error.
941
- */
942
679
  async removeBridgedEndpoint(pluginName, device) {
943
680
  this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db})...`);
944
- // Check if the plugin is registered
945
681
  const plugin = this.pluginManager.get(pluginName);
946
682
  if (!plugin)
947
683
  throw new Error(`Error removing bridged endpoint ${plg}${pluginName}${er}:${dev}${device.deviceName}${er} (${zb}${device.name}${er}): plugin not found`);
948
684
  if (device.serverNode) {
949
- // TODO: Close and remove the MatterNode managing the device
950
685
  }
951
686
  else if (this.matterbridge.bridgeMode === 'bridge') {
952
687
  if (!this.aggregatorNode)
@@ -968,25 +703,11 @@ export class MatterNode extends EventEmitter {
968
703
  this.log.info(`Removed bridged endpoint #${plugin.registeredDevices} ${plg}${pluginName}${nf}:${dev}${device.deviceName}${nf} (${zb}${device.name}${nf})`);
969
704
  if (plugin.registeredDevices !== undefined)
970
705
  plugin.registeredDevices--;
971
- // Remove the device from the DeviceManager
972
706
  await this.server.fetch({ type: 'devices_remove', src: this.server.name, dst: 'devices', params: { device: toBaseDevice(device) } });
973
707
  await this.yieldToNode(10);
974
708
  return device;
975
709
  }
976
- /**
977
- * Removes all bridged endpoints from the specified plugin.
978
- *
979
- * @param {string} pluginName - The name of the plugin.
980
- * @param {number} [delay] - The delay in milliseconds between removing each bridged endpoint (default: 0).
981
- * @returns {Promise<void>} A promise that resolves when all bridged endpoints have been removed.
982
- *
983
- * @remarks
984
- * This method iterates through all devices in the DeviceManager and removes each bridged endpoint associated with the specified plugin.
985
- * It also applies a delay between each removal if specified.
986
- * The delay is useful to allow the controllers to receive a single subscription for each device removed.
987
- */
988
710
  async removeAllBridgedEndpoints(pluginName, delay = 0) {
989
- // Check if the plugin is registered
990
711
  const plugin = this.pluginManager.get(pluginName);
991
712
  if (!plugin)
992
713
  throw new Error(`Error removing all bridged endpoints for plugin ${plg}${pluginName}${er}: plugin not found`);
@@ -1001,7 +722,6 @@ export class MatterNode extends EventEmitter {
1001
722
  this.log.info(`Removed bridged endpoint #${plugin.registeredDevices} ${plg}${pluginName}${nf}:${dev}${device.deviceName}${nf} (${zb}${endpoint?.name}${nf})`);
1002
723
  if (plugin.registeredDevices !== undefined)
1003
724
  plugin.registeredDevices--;
1004
- // Remove the device from the DeviceManager
1005
725
  await this.server.fetch({ type: 'devices_remove', src: this.server.name, dst: 'devices', params: { device: toBaseDevice(device) } });
1006
726
  await this.yieldToNode(10);
1007
727
  if (delay > 0)
@@ -1010,25 +730,6 @@ export class MatterNode extends EventEmitter {
1010
730
  if (delay > 0)
1011
731
  await wait(Number(process.env['MATTERBRIDGE_REMOVE_ALL_ENDPOINT_TIMEOUT_MS']) || 2000);
1012
732
  }
1013
- /**
1014
- * Registers a virtual device with the Matterbridge platform.
1015
- * Virtual devices are only supported in bridge mode and childbridge mode with a DynamicPlatform.
1016
- *
1017
- * The virtual device is created as an instance of `Endpoint` with the provided device type.
1018
- * When the virtual device is turned on, the provided callback function is executed.
1019
- * The onOff state of the virtual device always reverts to false when the device is turned on.
1020
- *
1021
- * @param {string} pluginName - The name of the plugin.
1022
- * @param { string } name - The name of the virtual device.
1023
- * @param { 'light' | 'outlet' | 'switch' | 'mounted_switch' } type - The type of the virtual device.
1024
- * @param { () => Promise<void> } callback - The callback to call when the virtual device is turned on.
1025
- *
1026
- * @returns {Promise<boolean>} A promise that resolves to true if the virtual device was successfully registered, false otherwise.
1027
- *
1028
- * @remarks
1029
- * The virtual devices don't show up in the device list of the frontend.
1030
- * Type 'switch' is not supported by Alexa and 'mounted_switch' is not supported by Apple Home.
1031
- */
1032
733
  async addVirtualEndpoint(pluginName, name, type, callback) {
1033
734
  this.log.debug(`Creating virtual device ${plg}${pluginName}${db}:${dev}${name}${db}...`);
1034
735
  const plugin = this.pluginManager.get(pluginName);
@@ -1053,20 +754,10 @@ export class MatterNode extends EventEmitter {
1053
754
  await this.yieldToNode(10);
1054
755
  return true;
1055
756
  }
1056
- /**
1057
- * Subscribes to the attribute change event for the given device and plugin.
1058
- * Specifically, it listens for changes in the 'reachable' attribute of the
1059
- * BridgedDeviceBasicInformationServer cluster server of the bridged device or BasicInformationServer cluster server of server node.
1060
- *
1061
- * @param {Plugin} plugin - The plugin associated with the device.
1062
- * @param {MatterbridgeEndpoint} device - The device to subscribe to attribute changes for.
1063
- * @returns {Promise<void>} A promise that resolves when the subscription is set up.
1064
- */
1065
757
  async subscribeAttributeChanged(plugin, device) {
1066
758
  if (!plugin || !device || !device.plugin || !device.serialNumber || !device.uniqueId || !device.maybeNumber)
1067
759
  return;
1068
760
  this.log.debug(`Subscribing attributes for endpoint ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db}:${or}${device.id}${db}:${or}${device.number}${db} (${zb}${device.name}${db})`);
1069
- // Subscribe to the reachable$Changed event of the BasicInformationServer cluster server of the server node in childbridge mode
1070
761
  if (this.matterbridge.bridgeMode === 'childbridge' && plugin.type === 'AccessoryPlatform' && this.serverNode) {
1071
762
  this.serverNode.eventsOf(BasicInformationServer).reachable$Changed?.on((reachable) => {
1072
763
  this.log.debug(`Accessory endpoint ${plg}${plugin.name}${nf}:${dev}${device.deviceName}${nf}:${or}${device.id}${nf}:${or}${device.number}${nf} is ${reachable ? 'reachable' : 'unreachable'}`);
@@ -1074,7 +765,6 @@ export class MatterNode extends EventEmitter {
1074
765
  type: 'frontend_attributechanged',
1075
766
  src: 'matter',
1076
767
  dst: 'frontend',
1077
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1078
768
  params: { plugin: device.plugin, serialNumber: device.serialNumber, uniqueId: device.uniqueId, number: device.number, id: device.id, cluster: 'BasicInformation', attribute: 'reachable', value: reachable },
1079
769
  });
1080
770
  });
@@ -1127,7 +817,6 @@ export class MatterNode extends EventEmitter {
1127
817
  type: 'frontend_attributechanged',
1128
818
  src: 'matter',
1129
819
  dst: 'frontend',
1130
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1131
820
  params: { plugin: device.plugin, serialNumber: device.serialNumber, uniqueId: device.uniqueId, number: device.number, id: device.id, cluster: sub.cluster, attribute: sub.attribute, value: value },
1132
821
  });
1133
822
  });
@@ -1141,7 +830,6 @@ export class MatterNode extends EventEmitter {
1141
830
  type: 'frontend_attributechanged',
1142
831
  src: 'matter',
1143
832
  dst: 'frontend',
1144
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
1145
833
  params: { plugin: device.plugin, serialNumber: device.serialNumber, uniqueId: device.uniqueId, number: child.number, id: child.id, cluster: sub.cluster, attribute: sub.attribute, value: value },
1146
834
  });
1147
835
  });
@@ -1149,12 +837,6 @@ export class MatterNode extends EventEmitter {
1149
837
  }
1150
838
  }
1151
839
  }
1152
- /**
1153
- * Sanitizes the fabric information by converting bigint properties to strings because `res.json` doesn't support bigint.
1154
- *
1155
- * @param {ExposedFabricInformation[]} fabricInfo - The array of exposed fabric information objects.
1156
- * @returns {SanitizedExposedFabricInformation[]} An array of sanitized exposed fabric information objects.
1157
- */
1158
840
  sanitizeFabricInformations(fabricInfo) {
1159
841
  return fabricInfo.map((info) => {
1160
842
  return {
@@ -1168,12 +850,6 @@ export class MatterNode extends EventEmitter {
1168
850
  };
1169
851
  });
1170
852
  }
1171
- /**
1172
- * Sanitizes the session information by converting bigint properties to strings because `res.json` doesn't support bigint.
1173
- *
1174
- * @param {SessionsBehavior.Session[]} sessions - The array of session information objects.
1175
- * @returns {SanitizedSession[]} An array of sanitized session information objects.
1176
- */
1177
853
  sanitizeSessionInformation(sessions) {
1178
854
  return sessions
1179
855
  .filter((session) => session.isPeerActive)
@@ -1200,21 +876,10 @@ export class MatterNode extends EventEmitter {
1200
876
  };
1201
877
  });
1202
878
  }
1203
- /**
1204
- * Sets the reachability of the specified server node and trigger the corresponding event.
1205
- *
1206
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
1207
- */
1208
879
  async setServerReachability(reachable) {
1209
880
  await this.serverNode?.setStateOf(BasicInformationServer, { reachable });
1210
881
  this.serverNode?.act((agent) => this.serverNode?.eventsOf(BasicInformationServer).reachableChanged?.emit({ reachableNewValue: reachable }, agent.context));
1211
882
  }
1212
- /**
1213
- * Sets the reachability of the specified aggregator node bridged devices and trigger.
1214
- *
1215
- * @param {Endpoint<AggregatorEndpoint>} aggregatorNode - The aggregator node to set the reachability for.
1216
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
1217
- */
1218
883
  async setAggregatorReachability(aggregatorNode, reachable) {
1219
884
  for (const child of aggregatorNode.parts) {
1220
885
  this.log.debug(`Setting reachability of ${child?.deviceName} to ${reachable}`);
@@ -1260,35 +925,19 @@ export class MatterNode extends EventEmitter {
1260
925
  case 0x1488:
1261
926
  vendorName = '(ShortcutLabsFlic)';
1262
927
  break;
1263
- case 65521: // 0xFFF1
928
+ case 65521:
1264
929
  vendorName = '(MatterTest)';
1265
930
  break;
1266
931
  }
1267
932
  return vendorName;
1268
933
  };
1269
- /**
1270
- * Yield to the Node.js event loop:
1271
- * 1. Flushes the current microtask queue (Promise/async continuations queued so far).
1272
- * 2. Yields one macrotask turn (setImmediate) and then its microtasks.
1273
- * 3. Waits a bit (setTimeout) to allow other macrotasks to run.
1274
- *
1275
- * This does **not** guarantee that every promise in the process is settled,
1276
- * but it gives all already-scheduled work a very good chance to run before continuing.
1277
- *
1278
- * @param {number} [timeout] - Optional timeout in milliseconds to wait after yielding. Default is 100 ms (minimum 10 ms).
1279
- * @returns {Promise<void>}
1280
- */
1281
934
  async yieldToNode(timeout = 100) {
1282
- // 1. Let all currently queued microtasks run
1283
935
  await Promise.resolve();
1284
- // 2. Yield to the next event-loop turn (macrotask + its microtasks)
1285
936
  await new Promise((resolve) => {
1286
937
  setImmediate(resolve);
1287
938
  });
1288
- // 3. Pause a bit to allow other macrotasks to run
1289
939
  await new Promise((resolve) => {
1290
940
  setTimeout(resolve, Math.min(timeout, 10));
1291
941
  });
1292
942
  }
1293
943
  }
1294
- //# sourceMappingURL=matterNode.js.map