matterbridge 2.2.4 → 2.2.5-dev.3

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 (288) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/cli.js +2 -37
  3. package/dist/cluster/export.js +0 -2
  4. package/dist/defaultConfigSchema.js +0 -23
  5. package/dist/deviceManager.js +1 -94
  6. package/dist/frontend.js +70 -334
  7. package/dist/index.js +1 -28
  8. package/dist/logger/export.js +0 -1
  9. package/dist/matter/behaviors.js +0 -2
  10. package/dist/matter/clusters.js +0 -2
  11. package/dist/matter/devices.js +0 -2
  12. package/dist/matter/endpoints.js +0 -2
  13. package/dist/matter/export.js +0 -2
  14. package/dist/matter/types.js +0 -2
  15. package/dist/matterbridge.js +46 -743
  16. package/dist/matterbridgeAccessoryPlatform.js +0 -33
  17. package/dist/matterbridgeBehaviors.js +1 -32
  18. package/dist/matterbridgeDeviceTypes.js +11 -112
  19. package/dist/matterbridgeDynamicPlatform.js +0 -33
  20. package/dist/matterbridgeEndpoint.js +6 -690
  21. package/dist/matterbridgeEndpointHelpers.js +9 -118
  22. package/dist/matterbridgePlatform.js +13 -185
  23. package/dist/matterbridgeTypes.js +0 -24
  24. package/dist/pluginManager.js +7 -230
  25. package/dist/shelly.js +6 -121
  26. package/dist/storage/export.js +0 -1
  27. package/dist/update.js +0 -45
  28. package/dist/utils/colorUtils.js +2 -205
  29. package/dist/utils/copyDirectory.js +1 -37
  30. package/dist/utils/createZip.js +2 -42
  31. package/dist/utils/deepCopy.js +0 -40
  32. package/dist/utils/deepEqual.js +1 -65
  33. package/dist/utils/export.js +0 -1
  34. package/dist/utils/isvalid.js +0 -86
  35. package/dist/utils/network.js +5 -77
  36. package/dist/utils/parameter.js +0 -41
  37. package/dist/utils/wait.js +5 -48
  38. package/frontend/build/asset-manifest.json +80 -64
  39. package/frontend/build/index.html +1 -1
  40. package/frontend/build/static/css/main.ea7910e9.css +2 -0
  41. package/frontend/build/static/css/main.ea7910e9.css.map +1 -0
  42. package/frontend/build/static/js/453.d855a71b.chunk.js +2 -0
  43. package/frontend/build/static/js/{453.abd36b29.chunk.js.map → 453.d855a71b.chunk.js.map} +1 -1
  44. package/frontend/build/static/js/main.b42b0a2a.js +115 -0
  45. package/frontend/build/static/js/{main.4a12038d.js.LICENSE.txt → main.b42b0a2a.js.LICENSE.txt} +12 -27
  46. package/frontend/build/static/js/{main.4a12038d.js.map → main.b42b0a2a.js.map} +1 -1
  47. package/frontend/build/static/media/roboto-cyrillic-300-normal.44340549d94d10899346.woff +0 -0
  48. package/frontend/build/static/media/roboto-cyrillic-300-normal.89d0351bce4bc857dba6.woff2 +0 -0
  49. package/frontend/build/static/media/roboto-cyrillic-400-normal.86d5c52f4588f9f221d7.woff2 +0 -0
  50. package/frontend/build/static/media/roboto-cyrillic-400-normal.d67ac585bb6a05dbf71c.woff +0 -0
  51. package/frontend/build/static/media/roboto-cyrillic-500-normal.1fb2c6d685bfb888cfa3.woff2 +0 -0
  52. package/frontend/build/static/media/roboto-cyrillic-500-normal.36f79cc7e73a69da4438.woff +0 -0
  53. package/frontend/build/static/media/roboto-cyrillic-700-normal.e00802373a2c2db6b30d.woff +0 -0
  54. package/frontend/build/static/media/roboto-cyrillic-700-normal.fd3dfdd6cb1a9175b63d.woff2 +0 -0
  55. package/frontend/build/static/media/roboto-cyrillic-ext-300-normal.a80c0d0719b1acb8f731.woff +0 -0
  56. package/frontend/build/static/media/roboto-cyrillic-ext-300-normal.b9d87b04a9119d8d2fdf.woff2 +0 -0
  57. package/frontend/build/static/media/roboto-cyrillic-ext-400-normal.31476620b88eec076438.woff2 +0 -0
  58. package/frontend/build/static/media/roboto-cyrillic-ext-400-normal.5e3f232f89080810567d.woff +0 -0
  59. package/frontend/build/static/media/roboto-cyrillic-ext-500-normal.634ee2238bf30f362d52.woff2 +0 -0
  60. package/frontend/build/static/media/roboto-cyrillic-ext-500-normal.d6c661248da2fde17768.woff +0 -0
  61. package/frontend/build/static/media/roboto-cyrillic-ext-700-normal.361cdfd3a3f9c4bb09ca.woff2 +0 -0
  62. package/frontend/build/static/media/roboto-cyrillic-ext-700-normal.6b08bc756cd72f5af9e8.woff +0 -0
  63. package/frontend/build/static/media/roboto-greek-300-normal.8300b541aa89b8301a6f.woff +0 -0
  64. package/frontend/build/static/media/roboto-greek-300-normal.fdd1f928a606aa116a44.woff2 +0 -0
  65. package/frontend/build/static/media/roboto-greek-400-normal.98a717d5a38e77c0f657.woff2 +0 -0
  66. package/frontend/build/static/media/roboto-greek-400-normal.ecd8572d631f20ff5bd5.woff +0 -0
  67. package/frontend/build/static/media/roboto-greek-500-normal.4fe733bc436afc295c24.woff +0 -0
  68. package/frontend/build/static/media/roboto-greek-500-normal.5c8100481d4e784afbf2.woff2 +0 -0
  69. package/frontend/build/static/media/roboto-greek-700-normal.d23e03cf87ba44e5af6f.woff +0 -0
  70. package/frontend/build/static/media/roboto-greek-700-normal.d7dfd0b02cd8311e2a97.woff2 +0 -0
  71. package/frontend/build/static/media/roboto-greek-ext-300-normal.60729cafbded24073dfb.woff +0 -0
  72. package/frontend/build/static/media/roboto-greek-ext-300-normal.a88b77bb10633a8045e3.woff2 +0 -0
  73. package/frontend/build/static/media/roboto-greek-ext-400-normal.2d5875b032a1cca91eb2.woff2 +0 -0
  74. package/frontend/build/static/media/roboto-greek-ext-400-normal.a0baf7d6726d8f751a27.woff +0 -0
  75. package/frontend/build/static/media/roboto-greek-ext-500-normal.1964239c2800b6bd7e39.woff +0 -0
  76. package/frontend/build/static/media/roboto-greek-ext-500-normal.bef9c15c7164d6435aad.woff2 +0 -0
  77. package/frontend/build/static/media/roboto-greek-ext-700-normal.1aff9f4cd71608489b9a.woff +0 -0
  78. package/frontend/build/static/media/roboto-greek-ext-700-normal.eb28a447335ba6d54fcb.woff2 +0 -0
  79. package/frontend/build/static/media/roboto-latin-300-normal.cb14f8e80cc69ddbac34.woff +0 -0
  80. package/frontend/build/static/media/roboto-latin-300-normal.db56943a88e4852343ae.woff2 +0 -0
  81. package/frontend/build/static/media/roboto-latin-400-normal.50a0a61e29c19a2f05cb.woff +0 -0
  82. package/frontend/build/static/media/roboto-latin-400-normal.df1be0be92f6f19b8115.woff2 +0 -0
  83. package/frontend/build/static/media/roboto-latin-500-normal.599f66a60bdf974e578e.woff2 +0 -0
  84. package/frontend/build/static/media/roboto-latin-500-normal.c320def131b39bceabd8.woff +0 -0
  85. package/frontend/build/static/media/roboto-latin-700-normal.bcfbe8accc968a375a8e.woff +0 -0
  86. package/frontend/build/static/media/roboto-latin-700-normal.c4d6cab43bec89049809.woff2 +0 -0
  87. package/frontend/build/static/media/roboto-latin-ext-300-normal.6ddd1cfdbc5e74bcdab8.woff +0 -0
  88. package/frontend/build/static/media/roboto-latin-ext-300-normal.948c05192b1e64d931b1.woff2 +0 -0
  89. package/frontend/build/static/media/roboto-latin-ext-400-normal.0f86a30ca7e981fcfc99.woff2 +0 -0
  90. package/frontend/build/static/media/roboto-latin-ext-400-normal.2bfbba2d51a85c8702dd.woff +0 -0
  91. package/frontend/build/static/media/roboto-latin-ext-500-normal.8f02573e78730021ef49.woff2 +0 -0
  92. package/frontend/build/static/media/roboto-latin-ext-500-normal.aecaab4c4da2bf91377a.woff +0 -0
  93. package/frontend/build/static/media/roboto-latin-ext-700-normal.2d3c3ba6fe2d9c1026a5.woff +0 -0
  94. package/frontend/build/static/media/roboto-latin-ext-700-normal.8e656eff240311c6050a.woff2 +0 -0
  95. package/frontend/build/static/media/roboto-math-300-normal.90364ecfad5101ceb1a0.woff +0 -0
  96. package/frontend/build/static/media/roboto-math-300-normal.acc9c7c1d1fe3a1c7d44.woff2 +0 -0
  97. package/frontend/build/static/media/roboto-math-400-normal.3d3a272e5233c5fb1969.woff +0 -0
  98. package/frontend/build/static/media/roboto-math-400-normal.b60d9fba1e21da7497e6.woff2 +0 -0
  99. package/frontend/build/static/media/roboto-math-500-normal.41db483cb764343fca71.woff2 +0 -0
  100. package/frontend/build/static/media/roboto-math-500-normal.c3014a611cd9d8fa6252.woff +0 -0
  101. package/frontend/build/static/media/roboto-math-700-normal.a6fde3ddcb1629fd58b7.woff +0 -0
  102. package/frontend/build/static/media/roboto-math-700-normal.f6f4b54add6ab9d60a0f.woff2 +0 -0
  103. package/frontend/build/static/media/roboto-symbols-300-normal.52cdf8344b378f0c4580.woff +0 -0
  104. package/frontend/build/static/media/roboto-symbols-300-normal.616638ec44336b3da884.woff2 +0 -0
  105. package/frontend/build/static/media/roboto-symbols-400-normal.bb5b5d1459beb07bd3d5.woff2 +0 -0
  106. package/frontend/build/static/media/roboto-symbols-400-normal.f4f7e3bd8264f1a640cb.woff +0 -0
  107. package/frontend/build/static/media/roboto-symbols-500-normal.09b674875029289fd9a7.woff +0 -0
  108. package/frontend/build/static/media/roboto-symbols-500-normal.a5457b0ec984fd4cc8da.woff2 +0 -0
  109. package/frontend/build/static/media/roboto-symbols-700-normal.017e476ef02f62144169.woff +0 -0
  110. package/frontend/build/static/media/roboto-symbols-700-normal.634070e045ac99822c21.woff2 +0 -0
  111. package/frontend/build/static/media/roboto-vietnamese-300-normal.53f399e4522b647bafa7.woff +0 -0
  112. package/frontend/build/static/media/roboto-vietnamese-300-normal.6f0bf63e956c09377ef8.woff2 +0 -0
  113. package/frontend/build/static/media/roboto-vietnamese-400-normal.1cffe58e71a9109191a2.woff +0 -0
  114. package/frontend/build/static/media/roboto-vietnamese-400-normal.b1b8baa94fbcaa57d098.woff2 +0 -0
  115. package/frontend/build/static/media/roboto-vietnamese-500-normal.148734d63bd96c6e964f.woff2 +0 -0
  116. package/frontend/build/static/media/roboto-vietnamese-500-normal.72dbf2a25dd55b80b137.woff +0 -0
  117. package/frontend/build/static/media/roboto-vietnamese-700-normal.44a103f706f3ffe6a041.woff2 +0 -0
  118. package/frontend/build/static/media/roboto-vietnamese-700-normal.fa58a041a3336692af1e.woff +0 -0
  119. package/npm-shrinkwrap.json +2 -2
  120. package/package.json +1 -2
  121. package/dist/cli.d.ts +0 -29
  122. package/dist/cli.d.ts.map +0 -1
  123. package/dist/cli.js.map +0 -1
  124. package/dist/cluster/export.d.ts +0 -2
  125. package/dist/cluster/export.d.ts.map +0 -1
  126. package/dist/cluster/export.js.map +0 -1
  127. package/dist/defaultConfigSchema.d.ts +0 -27
  128. package/dist/defaultConfigSchema.d.ts.map +0 -1
  129. package/dist/defaultConfigSchema.js.map +0 -1
  130. package/dist/deviceManager.d.ts +0 -114
  131. package/dist/deviceManager.d.ts.map +0 -1
  132. package/dist/deviceManager.js.map +0 -1
  133. package/dist/frontend.d.ts +0 -221
  134. package/dist/frontend.d.ts.map +0 -1
  135. package/dist/frontend.js.map +0 -1
  136. package/dist/index.d.ts +0 -35
  137. package/dist/index.d.ts.map +0 -1
  138. package/dist/index.js.map +0 -1
  139. package/dist/logger/export.d.ts +0 -2
  140. package/dist/logger/export.d.ts.map +0 -1
  141. package/dist/logger/export.js.map +0 -1
  142. package/dist/matter/behaviors.d.ts +0 -2
  143. package/dist/matter/behaviors.d.ts.map +0 -1
  144. package/dist/matter/behaviors.js.map +0 -1
  145. package/dist/matter/clusters.d.ts +0 -2
  146. package/dist/matter/clusters.d.ts.map +0 -1
  147. package/dist/matter/clusters.js.map +0 -1
  148. package/dist/matter/devices.d.ts +0 -2
  149. package/dist/matter/devices.d.ts.map +0 -1
  150. package/dist/matter/devices.js.map +0 -1
  151. package/dist/matter/endpoints.d.ts +0 -2
  152. package/dist/matter/endpoints.d.ts.map +0 -1
  153. package/dist/matter/endpoints.js.map +0 -1
  154. package/dist/matter/export.d.ts +0 -5
  155. package/dist/matter/export.d.ts.map +0 -1
  156. package/dist/matter/export.js.map +0 -1
  157. package/dist/matter/types.d.ts +0 -3
  158. package/dist/matter/types.d.ts.map +0 -1
  159. package/dist/matter/types.js.map +0 -1
  160. package/dist/matterbridge.d.ts +0 -422
  161. package/dist/matterbridge.d.ts.map +0 -1
  162. package/dist/matterbridge.js.map +0 -1
  163. package/dist/matterbridgeAccessoryPlatform.d.ts +0 -39
  164. package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
  165. package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
  166. package/dist/matterbridgeBehaviors.d.ts +0 -1056
  167. package/dist/matterbridgeBehaviors.d.ts.map +0 -1
  168. package/dist/matterbridgeBehaviors.js.map +0 -1
  169. package/dist/matterbridgeDeviceTypes.d.ts +0 -177
  170. package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
  171. package/dist/matterbridgeDeviceTypes.js.map +0 -1
  172. package/dist/matterbridgeDynamicPlatform.d.ts +0 -39
  173. package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
  174. package/dist/matterbridgeDynamicPlatform.js.map +0 -1
  175. package/dist/matterbridgeEndpoint.d.ts +0 -835
  176. package/dist/matterbridgeEndpoint.d.ts.map +0 -1
  177. package/dist/matterbridgeEndpoint.js.map +0 -1
  178. package/dist/matterbridgeEndpointHelpers.d.ts +0 -2275
  179. package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
  180. package/dist/matterbridgeEndpointHelpers.js.map +0 -1
  181. package/dist/matterbridgePlatform.d.ts +0 -251
  182. package/dist/matterbridgePlatform.d.ts.map +0 -1
  183. package/dist/matterbridgePlatform.js.map +0 -1
  184. package/dist/matterbridgeTypes.d.ts +0 -178
  185. package/dist/matterbridgeTypes.d.ts.map +0 -1
  186. package/dist/matterbridgeTypes.js.map +0 -1
  187. package/dist/pluginManager.d.ts +0 -236
  188. package/dist/pluginManager.d.ts.map +0 -1
  189. package/dist/pluginManager.js.map +0 -1
  190. package/dist/shelly.d.ts +0 -77
  191. package/dist/shelly.d.ts.map +0 -1
  192. package/dist/shelly.js.map +0 -1
  193. package/dist/storage/export.d.ts +0 -2
  194. package/dist/storage/export.d.ts.map +0 -1
  195. package/dist/storage/export.js.map +0 -1
  196. package/dist/update.d.ts +0 -32
  197. package/dist/update.d.ts.map +0 -1
  198. package/dist/update.js.map +0 -1
  199. package/dist/utils/colorUtils.d.ts +0 -61
  200. package/dist/utils/colorUtils.d.ts.map +0 -1
  201. package/dist/utils/colorUtils.js.map +0 -1
  202. package/dist/utils/copyDirectory.d.ts +0 -32
  203. package/dist/utils/copyDirectory.d.ts.map +0 -1
  204. package/dist/utils/copyDirectory.js.map +0 -1
  205. package/dist/utils/createZip.d.ts +0 -38
  206. package/dist/utils/createZip.d.ts.map +0 -1
  207. package/dist/utils/createZip.js.map +0 -1
  208. package/dist/utils/deepCopy.d.ts +0 -31
  209. package/dist/utils/deepCopy.d.ts.map +0 -1
  210. package/dist/utils/deepCopy.js.map +0 -1
  211. package/dist/utils/deepEqual.d.ts +0 -53
  212. package/dist/utils/deepEqual.d.ts.map +0 -1
  213. package/dist/utils/deepEqual.js.map +0 -1
  214. package/dist/utils/export.d.ts +0 -10
  215. package/dist/utils/export.d.ts.map +0 -1
  216. package/dist/utils/export.js.map +0 -1
  217. package/dist/utils/isvalid.d.ts +0 -87
  218. package/dist/utils/isvalid.d.ts.map +0 -1
  219. package/dist/utils/isvalid.js.map +0 -1
  220. package/dist/utils/network.d.ts +0 -70
  221. package/dist/utils/network.d.ts.map +0 -1
  222. package/dist/utils/network.js.map +0 -1
  223. package/dist/utils/parameter.d.ts +0 -44
  224. package/dist/utils/parameter.d.ts.map +0 -1
  225. package/dist/utils/parameter.js.map +0 -1
  226. package/dist/utils/wait.d.ts +0 -43
  227. package/dist/utils/wait.d.ts.map +0 -1
  228. package/dist/utils/wait.js.map +0 -1
  229. package/frontend/build/static/css/main.e52977d6.css +0 -2
  230. package/frontend/build/static/css/main.e52977d6.css.map +0 -1
  231. package/frontend/build/static/js/453.abd36b29.chunk.js +0 -2
  232. package/frontend/build/static/js/main.4a12038d.js +0 -115
  233. package/frontend/build/static/media/roboto-cyrillic-300-normal.1b79538ccd585c259996.woff2 +0 -0
  234. package/frontend/build/static/media/roboto-cyrillic-300-normal.5f077fd7b977d1715acf.woff +0 -0
  235. package/frontend/build/static/media/roboto-cyrillic-400-normal.5d2930082227d172f62c.woff +0 -0
  236. package/frontend/build/static/media/roboto-cyrillic-400-normal.a9e19870cf6c4b973427.woff2 +0 -0
  237. package/frontend/build/static/media/roboto-cyrillic-500-normal.0ae2428323939af5e1ad.woff2 +0 -0
  238. package/frontend/build/static/media/roboto-cyrillic-500-normal.dd7bc8a52c6c70c5a3f5.woff +0 -0
  239. package/frontend/build/static/media/roboto-cyrillic-700-normal.3f6e1548bd5175a8c342.woff +0 -0
  240. package/frontend/build/static/media/roboto-cyrillic-700-normal.4fdfc29a10e7d4b7c527.woff2 +0 -0
  241. package/frontend/build/static/media/roboto-cyrillic-ext-300-normal.795dbc8140e3fef82983.woff +0 -0
  242. package/frontend/build/static/media/roboto-cyrillic-ext-300-normal.80947a31d23c70204b47.woff2 +0 -0
  243. package/frontend/build/static/media/roboto-cyrillic-ext-400-normal.135d076fa32aa0b4d105.woff +0 -0
  244. package/frontend/build/static/media/roboto-cyrillic-ext-400-normal.5cec61a21cc20180fbe1.woff2 +0 -0
  245. package/frontend/build/static/media/roboto-cyrillic-ext-500-normal.6de16332fda843a3dc3d.woff2 +0 -0
  246. package/frontend/build/static/media/roboto-cyrillic-ext-500-normal.c0a0638f90b31d6454ba.woff +0 -0
  247. package/frontend/build/static/media/roboto-cyrillic-ext-700-normal.4750292c47fa2bc6ac1a.woff2 +0 -0
  248. package/frontend/build/static/media/roboto-cyrillic-ext-700-normal.ca247189fc12d00de361.woff +0 -0
  249. package/frontend/build/static/media/roboto-greek-300-normal.285f3e6261d8eb20417d.woff2 +0 -0
  250. package/frontend/build/static/media/roboto-greek-300-normal.889beddda1c9bd9f97df.woff +0 -0
  251. package/frontend/build/static/media/roboto-greek-400-normal.160a791a8e4f46bca3cc.woff +0 -0
  252. package/frontend/build/static/media/roboto-greek-400-normal.2c32b1315be61477013a.woff2 +0 -0
  253. package/frontend/build/static/media/roboto-greek-500-normal.60810e07c7b0273013aa.woff +0 -0
  254. package/frontend/build/static/media/roboto-greek-500-normal.f95e757c5483310f9c11.woff2 +0 -0
  255. package/frontend/build/static/media/roboto-greek-700-normal.77dd370f2001e184ba0d.woff2 +0 -0
  256. package/frontend/build/static/media/roboto-greek-700-normal.df87b053fae3d7ad5f7a.woff +0 -0
  257. package/frontend/build/static/media/roboto-greek-ext-300-normal.b590dbe5c639944366d1.woff +0 -0
  258. package/frontend/build/static/media/roboto-greek-ext-300-normal.d6049cb54aa6fbe14c42.woff2 +0 -0
  259. package/frontend/build/static/media/roboto-greek-ext-400-normal.16eb83b4a3b1ea994243.woff +0 -0
  260. package/frontend/build/static/media/roboto-greek-ext-400-normal.1df4abad55796d11a0c8.woff2 +0 -0
  261. package/frontend/build/static/media/roboto-greek-ext-500-normal.4a96ba31abcce0f5d52b.woff2 +0 -0
  262. package/frontend/build/static/media/roboto-greek-ext-500-normal.fd28d9c008bf3af1bed7.woff +0 -0
  263. package/frontend/build/static/media/roboto-greek-ext-700-normal.2dd6febad11502dec6a6.woff2 +0 -0
  264. package/frontend/build/static/media/roboto-greek-ext-700-normal.4abdc9fff4507f17d726.woff +0 -0
  265. package/frontend/build/static/media/roboto-latin-300-normal.b850f1ff581ea232fac9.woff2 +0 -0
  266. package/frontend/build/static/media/roboto-latin-300-normal.c4bc0593c9954d79cb3a.woff +0 -0
  267. package/frontend/build/static/media/roboto-latin-400-normal.047a7839f69b209db815.woff +0 -0
  268. package/frontend/build/static/media/roboto-latin-400-normal.297d48e1b5a10c0831a9.woff2 +0 -0
  269. package/frontend/build/static/media/roboto-latin-500-normal.68d40d6d01c6f85d24ba.woff +0 -0
  270. package/frontend/build/static/media/roboto-latin-500-normal.7077203b1982951ecf76.woff2 +0 -0
  271. package/frontend/build/static/media/roboto-latin-700-normal.4535474e1cf8598695ad.woff2 +0 -0
  272. package/frontend/build/static/media/roboto-latin-700-normal.9f6a16a7770c87b2042b.woff +0 -0
  273. package/frontend/build/static/media/roboto-latin-ext-300-normal.14982a9e4857a93b6dce.woff +0 -0
  274. package/frontend/build/static/media/roboto-latin-ext-300-normal.97cbc447d4a8d41a9543.woff2 +0 -0
  275. package/frontend/build/static/media/roboto-latin-ext-400-normal.27da5b36b6d3a16f53f4.woff +0 -0
  276. package/frontend/build/static/media/roboto-latin-ext-400-normal.2eeae187764baf05867d.woff2 +0 -0
  277. package/frontend/build/static/media/roboto-latin-ext-500-normal.06c30711d588145a4541.woff +0 -0
  278. package/frontend/build/static/media/roboto-latin-ext-500-normal.9a18d7bb9ff7a6af7b32.woff2 +0 -0
  279. package/frontend/build/static/media/roboto-latin-ext-700-normal.18841836e391d39e83a8.woff2 +0 -0
  280. package/frontend/build/static/media/roboto-latin-ext-700-normal.3c5bcdd0e69c4c3ffafe.woff +0 -0
  281. package/frontend/build/static/media/roboto-vietnamese-300-normal.c96b16e5c05c7b7c3e89.woff2 +0 -0
  282. package/frontend/build/static/media/roboto-vietnamese-300-normal.f5e7cea32756dfe7af40.woff +0 -0
  283. package/frontend/build/static/media/roboto-vietnamese-400-normal.0dc97c66f9b542d6fa17.woff +0 -0
  284. package/frontend/build/static/media/roboto-vietnamese-400-normal.d3f8e26d6c27de8102b6.woff2 +0 -0
  285. package/frontend/build/static/media/roboto-vietnamese-500-normal.090fabef926bdc0e9b9f.woff2 +0 -0
  286. package/frontend/build/static/media/roboto-vietnamese-500-normal.23b7b8a2524d2d4b637b.woff +0 -0
  287. package/frontend/build/static/media/roboto-vietnamese-700-normal.0a79a9fabfc32e33f360.woff2 +0 -0
  288. package/frontend/build/static/media/roboto-vietnamese-700-normal.35ed0597568ff6f19c16.woff +0 -0
@@ -1,35 +1,9 @@
1
- /**
2
- * This file contains the class Matterbridge.
3
- *
4
- * @file matterbridge.ts
5
- * @author Luca Liguori
6
- * @date 2023-12-29
7
- * @version 1.5.2
8
- *
9
- * Copyright 2023, 2024, 2025 Luca Liguori.
10
- *
11
- * Licensed under the Apache License, Version 2.0 (the "License");
12
- * you may not use this file except in compliance with the License.
13
- * You may obtain a copy of the License at
14
- *
15
- * http://www.apache.org/licenses/LICENSE-2.0
16
- *
17
- * Unless required by applicable law or agreed to in writing, software
18
- * distributed under the License is distributed on an "AS IS" BASIS,
19
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
- * See the License for the specific language governing permissions and
21
- * limitations under the License. *
22
- */
23
- // Node.js modules
24
1
  import os from 'node:os';
25
2
  import path from 'node:path';
26
3
  import { promises as fs } from 'node:fs';
27
4
  import EventEmitter from 'node:events';
28
- // AnsiLogger module
29
5
  import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN } from './logger/export.js';
30
- // NodeStorage module
31
6
  import { NodeStorageManager } from './storage/export.js';
32
- // Matterbridge
33
7
  import { getParameter, getIntParameter, hasParameter, copyDirectory, withTimeout } from './utils/export.js';
34
8
  import { logInterfaces, getGlobalNodeModules } from './utils/network.js';
35
9
  import { PluginManager } from './pluginManager.js';
@@ -37,19 +11,14 @@ import { DeviceManager } from './deviceManager.js';
37
11
  import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
38
12
  import { bridge } from './matterbridgeDeviceTypes.js';
39
13
  import { Frontend } from './frontend.js';
40
- // @matter
41
14
  import { DeviceTypeId, Endpoint as EndpointNode, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageService, Environment, ServerNode } from '@matter/main';
42
15
  import { DeviceCommissioner, FabricAction, MdnsService, PaseClient } from '@matter/main/protocol';
43
16
  import { AggregatorEndpoint } from '@matter/main/endpoints';
44
17
  import { BridgedDeviceBasicInformationServer } from '@matter/main/behaviors/bridged-device-basic-information';
45
18
  import { BasicInformationServer } from '@matter/main/behaviors/basic-information';
46
- // Default colors
47
19
  const plg = '\u001B[38;5;33m';
48
20
  const dev = '\u001B[38;5;79m';
49
21
  const typ = '\u001B[38;5;207m';
50
- /**
51
- * Represents the Matterbridge application.
52
- */
53
22
  export class Matterbridge extends EventEmitter {
54
23
  systemInformation = {
55
24
  interfaceName: '',
@@ -93,7 +62,7 @@ export class Matterbridge extends EventEmitter {
93
62
  shellySysUpdate: false,
94
63
  shellyMainUpdate: false,
95
64
  profile: getParameter('profile'),
96
- loggerLevel: "info" /* LogLevel.INFO */,
65
+ loggerLevel: "info",
97
66
  fileLogger: false,
98
67
  matterLoggerLevel: MatterLogLevel.INFO,
99
68
  matterFileLogger: false,
@@ -130,11 +99,9 @@ export class Matterbridge extends EventEmitter {
130
99
  plugins;
131
100
  devices;
132
101
  frontend = new Frontend(this);
133
- // Matterbridge storage
134
102
  nodeStorage;
135
103
  nodeContext;
136
104
  nodeStorageName = 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
137
- // Cleanup
138
105
  hasCleanupStarted = false;
139
106
  initialized = false;
140
107
  execRunningCount = 0;
@@ -147,70 +114,38 @@ export class Matterbridge extends EventEmitter {
147
114
  sigtermHandler;
148
115
  exceptionHandler;
149
116
  rejectionHandler;
150
- // Matter environment
151
117
  environment = Environment.default;
152
- // Matter storage
153
118
  matterStorageName = 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : '');
154
119
  matterStorageService;
155
120
  matterStorageManager;
156
121
  matterbridgeContext;
157
122
  mattercontrollerContext;
158
- // Matter parameters
159
- mdnsInterface; // matter server node mdnsInterface: e.g. 'eth0' or 'wlan0' or 'WiFi'
160
- ipv4address; // matter server node listeningAddressIpv4
161
- ipv6address; // matter server node listeningAddressIpv6
162
- port; // first server node port
163
- passcode; // first server node passcode
164
- discriminator; // first server node discriminator
123
+ mdnsInterface;
124
+ ipv4address;
125
+ ipv6address;
126
+ port;
127
+ passcode;
128
+ discriminator;
165
129
  serverNode;
166
130
  aggregatorNode;
167
131
  aggregatorVendorId = VendorId(getIntParameter('vendorId') ?? 0xfff1);
168
132
  aggregatorProductId = getIntParameter('productId') ?? 0x8000;
169
133
  static instance;
170
- // We load asyncronously so is private
171
134
  constructor() {
172
135
  super();
173
136
  }
174
- /**
175
- * Emits an event of the specified type with the provided arguments.
176
- *
177
- * @template K - The type of the event.
178
- * @param {K} eventName - The name of the event to emit.
179
- * @param {...MatterbridgeEvent[K]} args - The arguments to pass to the event listeners.
180
- * @returns {boolean} - Returns true if the event had listeners, false otherwise.
181
- */
182
137
  emit(eventName, ...args) {
183
138
  return super.emit(eventName, ...args);
184
139
  }
185
- /**
186
- * Registers an event listener for the specified event type.
187
- *
188
- * @template K - The type of the event.
189
- * @param {K} eventName - The name of the event to listen for.
190
- * @param {(...args: MatterbridgeEvent[K]) => void} listener - The callback function to invoke when the event is emitted.
191
- * @returns {this} - Returns the instance of the Matterbridge class.
192
- */
193
140
  on(eventName, listener) {
194
141
  return super.on(eventName, listener);
195
142
  }
196
- /**
197
- * Retrieves the list of Matterbridge devices.
198
- * @returns {MatterbridgeEndpoint[]} An array of MatterbridgeDevice objects.
199
- */
200
143
  getDevices() {
201
144
  return this.devices.array();
202
145
  }
203
- /**
204
- * Retrieves the list of registered plugins.
205
- * @returns {RegisteredPlugin[]} An array of RegisteredPlugin objects.
206
- */
207
146
  getPlugins() {
208
147
  return this.plugins.array();
209
148
  }
210
- /**
211
- * Set the logger logLevel for the Matterbridge classes.
212
- * @param {LogLevel} logLevel The logger logLevel to set.
213
- */
214
149
  async setLogLevel(logLevel) {
215
150
  if (this.log)
216
151
  this.log.logLevel = logLevel;
@@ -224,31 +159,19 @@ export class Matterbridge extends EventEmitter {
224
159
  for (const plugin of this.plugins) {
225
160
  if (!plugin.platform || !plugin.platform.log || !plugin.platform.config)
226
161
  continue;
227
- plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel;
228
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" /* LogLevel.DEBUG */ : this.log.logLevel);
229
- }
230
- // Set the global logger callback for the WebSocketServer to the common minimum logLevel
231
- let callbackLogLevel = "notice" /* LogLevel.NOTICE */;
232
- if (this.matterbridgeInformation.loggerLevel === "info" /* LogLevel.INFO */ || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.INFO)
233
- callbackLogLevel = "info" /* LogLevel.INFO */;
234
- if (this.matterbridgeInformation.loggerLevel === "debug" /* LogLevel.DEBUG */ || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.DEBUG)
235
- callbackLogLevel = "debug" /* LogLevel.DEBUG */;
162
+ plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" : this.log.logLevel;
163
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" : this.log.logLevel);
164
+ }
165
+ let callbackLogLevel = "notice";
166
+ if (this.matterbridgeInformation.loggerLevel === "info" || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.INFO)
167
+ callbackLogLevel = "info";
168
+ if (this.matterbridgeInformation.loggerLevel === "debug" || this.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.DEBUG)
169
+ callbackLogLevel = "debug";
236
170
  AnsiLogger.setGlobalCallback(this.frontend.wssSendMessage.bind(this.frontend), callbackLogLevel);
237
171
  this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
238
172
  }
239
- /** ***********************************************************************************************************************************/
240
- /** loadInstance() and cleanup() methods */
241
- /** ***********************************************************************************************************************************/
242
- /**
243
- * Loads an instance of the Matterbridge class.
244
- * If an instance already exists, return that instance.
245
- *
246
- * @param initialize - Whether to initialize the Matterbridge instance after loading.
247
- * @returns The loaded Matterbridge instance.
248
- */
249
173
  static async loadInstance(initialize = false) {
250
174
  if (!Matterbridge.instance) {
251
- // eslint-disable-next-line no-console
252
175
  if (hasParameter('debug'))
253
176
  console.log(GREEN + 'Creating a new instance of Matterbridge.', initialize ? 'Initializing...' : 'Not initializing...', rs);
254
177
  Matterbridge.instance = new Matterbridge();
@@ -257,14 +180,8 @@ export class Matterbridge extends EventEmitter {
257
180
  }
258
181
  return Matterbridge.instance;
259
182
  }
260
- /**
261
- * Call cleanup().
262
- * @deprecated This method is deprecated and is only used for jest tests.
263
- *
264
- */
265
183
  async destroyInstance() {
266
184
  this.log.info(`Destroy instance...`);
267
- // Save server nodes to close
268
185
  const servers = [];
269
186
  if (this.bridgeMode === 'bridge') {
270
187
  if (this.serverNode)
@@ -276,81 +193,55 @@ export class Matterbridge extends EventEmitter {
276
193
  servers.push(plugin.serverNode);
277
194
  }
278
195
  }
279
- // Cleanup
280
196
  await this.cleanup('destroying instance...', false);
281
- // Close servers mdns service
282
197
  this.log.info(`Dispose ${servers.length} MdnsService...`);
283
198
  for (const server of servers) {
284
199
  await server.env.get(MdnsService)[Symbol.asyncDispose]();
285
200
  this.log.info(`Closed ${server.id} MdnsService`);
286
201
  }
287
- // Wait for the cleanup to finish
288
202
  await new Promise((resolve) => {
289
203
  setTimeout(resolve, 1000);
290
204
  });
291
205
  }
292
- /**
293
- * Initializes the Matterbridge application.
294
- *
295
- * @remarks
296
- * This method performs the necessary setup and initialization steps for the Matterbridge application.
297
- * It displays the help information if the 'help' parameter is provided, sets up the logger, checks the
298
- * node version, registers signal handlers, initializes storage, and parses the command line.
299
- *
300
- * @returns A Promise that resolves when the initialization is complete.
301
- */
302
206
  async initialize() {
303
- // Set the restart mode
304
207
  if (hasParameter('service'))
305
208
  this.restartMode = 'service';
306
209
  if (hasParameter('docker'))
307
210
  this.restartMode = 'docker';
308
- // Set the matterbridge directory
309
211
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
310
212
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
311
- // Setup the matter environment
312
213
  this.environment.vars.set('log.level', MatterLogLevel.INFO);
313
214
  this.environment.vars.set('log.format', MatterLogFormat.ANSI);
314
215
  this.environment.vars.set('path.root', path.join(this.matterbridgeDirectory, this.matterStorageName));
315
216
  this.environment.vars.set('runtime.signals', false);
316
217
  this.environment.vars.set('runtime.exitcode', false);
317
- // Create the matterbridge logger
318
- this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: hasParameter('debug') ? "debug" /* LogLevel.DEBUG */ : "info" /* LogLevel.INFO */ });
319
- // Register process handlers
218
+ this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
320
219
  this.registerProcessHandlers();
321
- // Initialize nodeStorage and nodeContext
322
220
  try {
323
221
  this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
324
222
  this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
325
223
  this.log.debug('Creating node storage context for matterbridge');
326
224
  this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
327
- // TODO: Remove this code when node-persist-manager is updated
328
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
329
225
  const keys = (await this.nodeStorage?.storage.keys());
330
226
  for (const key of keys) {
331
227
  this.log.debug(`Checking node storage manager key: ${CYAN}${key}${db}`);
332
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
333
228
  await this.nodeStorage?.storage.get(key);
334
229
  }
335
230
  const storages = await this.nodeStorage.getStorageNames();
336
231
  for (const storage of storages) {
337
232
  this.log.debug(`Checking storage: ${CYAN}${storage}${db}`);
338
233
  const nodeContext = await this.nodeStorage?.createStorage(storage);
339
- // TODO: Remove this code when node-persist-manager is updated
340
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
341
234
  const keys = (await nodeContext?.storage.keys());
342
235
  keys.forEach(async (key) => {
343
236
  this.log.debug(`Checking key: ${CYAN}${storage}:${key}${db}`);
344
237
  await nodeContext?.get(key);
345
238
  });
346
239
  }
347
- // Creating a backup of the node storage since it is not corrupted
348
240
  this.log.debug('Creating node storage backup...');
349
241
  await copyDirectory(path.join(this.matterbridgeDirectory, this.nodeStorageName), path.join(this.matterbridgeDirectory, this.nodeStorageName + '.backup'));
350
242
  this.log.debug('Created node storage backup');
351
243
  }
352
244
  catch (error) {
353
- // Restoring the backup of the node storage since it is corrupted
354
245
  this.log.error(`Error creating node storage manager and context: ${error instanceof Error ? error.message : error}`);
355
246
  if (hasParameter('norestore')) {
356
247
  this.log.fatal(`The matterbridge node storage is corrupted. Parameter -norestore found: exiting...`);
@@ -365,46 +256,41 @@ export class Matterbridge extends EventEmitter {
365
256
  this.log.fatal('Fatal error creating node storage manager and context for matterbridge');
366
257
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
367
258
  }
368
- // Set the first port to use for the commissioning server (will be incremented in childbridge mode)
369
259
  this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
370
- // Set the first passcode to use for the commissioning server (will be incremented in childbridge mode)
371
260
  this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode')) ?? PaseClient.generateRandomPasscode();
372
- // Set the first discriminator to use for the commissioning server (will be incremented in childbridge mode)
373
261
  this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator')) ?? PaseClient.generateRandomDiscriminator();
374
262
  this.log.debug(`Initializing server node for Matterbridge... on port ${this.port} with passcode ${this.passcode} and discriminator ${this.discriminator}`);
375
- // Set matterbridge logger level (context: matterbridgeLogLevel)
376
263
  if (hasParameter('logger')) {
377
264
  const level = getParameter('logger');
378
265
  if (level === 'debug') {
379
- this.log.logLevel = "debug" /* LogLevel.DEBUG */;
266
+ this.log.logLevel = "debug";
380
267
  }
381
268
  else if (level === 'info') {
382
- this.log.logLevel = "info" /* LogLevel.INFO */;
269
+ this.log.logLevel = "info";
383
270
  }
384
271
  else if (level === 'notice') {
385
- this.log.logLevel = "notice" /* LogLevel.NOTICE */;
272
+ this.log.logLevel = "notice";
386
273
  }
387
274
  else if (level === 'warn') {
388
- this.log.logLevel = "warn" /* LogLevel.WARN */;
275
+ this.log.logLevel = "warn";
389
276
  }
390
277
  else if (level === 'error') {
391
- this.log.logLevel = "error" /* LogLevel.ERROR */;
278
+ this.log.logLevel = "error";
392
279
  }
393
280
  else if (level === 'fatal') {
394
- this.log.logLevel = "fatal" /* LogLevel.FATAL */;
281
+ this.log.logLevel = "fatal";
395
282
  }
396
283
  else {
397
284
  this.log.warn(`Invalid matterbridge logger level: ${level}. Using default level "info".`);
398
- this.log.logLevel = "info" /* LogLevel.INFO */;
285
+ this.log.logLevel = "info";
399
286
  }
400
287
  }
401
288
  else {
402
- this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.matterbridgeInformation.shellyBoard ? "notice" /* LogLevel.NOTICE */ : "info" /* LogLevel.INFO */);
289
+ this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', this.matterbridgeInformation.shellyBoard ? "notice" : "info");
403
290
  }
404
291
  this.frontend.logLevel = this.log.logLevel;
405
292
  MatterbridgeEndpoint.logLevel = this.log.logLevel;
406
293
  this.matterbridgeInformation.loggerLevel = this.log.logLevel;
407
- // Create the file logger for matterbridge (context: matterbridgeFileLog)
408
294
  if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
409
295
  AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), this.log.logLevel, true);
410
296
  this.matterbridgeInformation.fileLogger = true;
@@ -413,7 +299,6 @@ export class Matterbridge extends EventEmitter {
413
299
  this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
414
300
  if (this.profile !== undefined)
415
301
  this.log.debug(`Matterbridge profile: ${this.profile}.`);
416
- // Set matter.js logger level, format and logger (context: matterLogLevel)
417
302
  if (hasParameter('matterlogger')) {
418
303
  const level = getParameter('matterlogger');
419
304
  if (level === 'debug') {
@@ -445,7 +330,6 @@ export class Matterbridge extends EventEmitter {
445
330
  Logger.format = MatterLogFormat.ANSI;
446
331
  Logger.setLogger('default', this.createMatterLogger());
447
332
  this.matterbridgeInformation.matterLoggerLevel = Logger.defaultLogLevel;
448
- // Create the file logger for matter.js (context: matterFileLog)
449
333
  if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
450
334
  this.matterbridgeInformation.matterFileLogger = true;
451
335
  Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
@@ -454,7 +338,6 @@ export class Matterbridge extends EventEmitter {
454
338
  });
455
339
  }
456
340
  this.log.debug(`Matter logLevel: ${Logger.defaultLogLevel} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
457
- // Set the interface to use for matter server node mdnsInterface
458
341
  if (hasParameter('mdnsinterface')) {
459
342
  this.mdnsInterface = getParameter('mdnsinterface');
460
343
  }
@@ -463,7 +346,6 @@ export class Matterbridge extends EventEmitter {
463
346
  if (this.mdnsInterface === '')
464
347
  this.mdnsInterface = undefined;
465
348
  }
466
- // Validate mdnsInterface
467
349
  if (this.mdnsInterface) {
468
350
  const networkInterfaces = os.networkInterfaces();
469
351
  const availableInterfaces = Object.keys(networkInterfaces);
@@ -477,7 +359,6 @@ export class Matterbridge extends EventEmitter {
477
359
  }
478
360
  if (this.mdnsInterface)
479
361
  this.environment.vars.set('mdns.networkInterface', this.mdnsInterface);
480
- // Set the listeningAddressIpv4 for the matter commissioning server
481
362
  if (hasParameter('ipv4address')) {
482
363
  this.ipv4address = getParameter('ipv4address');
483
364
  }
@@ -486,7 +367,6 @@ export class Matterbridge extends EventEmitter {
486
367
  if (this.ipv4address === '')
487
368
  this.ipv4address = undefined;
488
369
  }
489
- // Set the listeningAddressIpv6 for the matter commissioning server
490
370
  if (hasParameter('ipv6address')) {
491
371
  this.ipv6address = getParameter('ipv6address');
492
372
  }
@@ -495,19 +375,14 @@ export class Matterbridge extends EventEmitter {
495
375
  if (this.ipv6address === '')
496
376
  this.ipv6address = undefined;
497
377
  }
498
- // Initialize PluginManager
499
378
  this.plugins = new PluginManager(this);
500
379
  await this.plugins.loadFromStorage();
501
380
  this.plugins.logLevel = this.log.logLevel;
502
- // Initialize DeviceManager
503
381
  this.devices = new DeviceManager(this, this.nodeContext);
504
382
  this.devices.logLevel = this.log.logLevel;
505
- // Get the plugins from node storage and create the plugins node storage contexts
506
383
  for (const plugin of this.plugins) {
507
384
  const packageJson = await this.plugins.parse(plugin);
508
385
  if (packageJson === null && !hasParameter('add') && !hasParameter('remove') && !hasParameter('enable') && !hasParameter('disable') && !hasParameter('reset') && !hasParameter('factoryreset')) {
509
- // Try to reinstall the plugin from npm (for Docker pull and external plugins)
510
- // We don't do this when the add and other parameters are set because we shut down the process after adding the plugin
511
386
  this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
512
387
  try {
513
388
  await this.spawnCommand('npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose']);
@@ -529,7 +404,6 @@ export class Matterbridge extends EventEmitter {
529
404
  await plugin.nodeContext.set('description', plugin.description);
530
405
  await plugin.nodeContext.set('author', plugin.author);
531
406
  }
532
- // Log system info and create .matterbridge directory
533
407
  await this.logNodeAndSystemInfo();
534
408
  this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
535
409
  `${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
@@ -537,7 +411,6 @@ export class Matterbridge extends EventEmitter {
537
411
  `${hasParameter('controller') ? 'mode controller ' : ''}` +
538
412
  `${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
539
413
  `running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
540
- // Check node version and throw error
541
414
  const minNodeVersion = 18;
542
415
  const nodeVersion = process.versions.node;
543
416
  const versionMajor = parseInt(nodeVersion.split('.')[0]);
@@ -545,15 +418,9 @@ export class Matterbridge extends EventEmitter {
545
418
  this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
546
419
  throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
547
420
  }
548
- // Parse command line
549
421
  await this.parseCommandLine();
550
422
  this.initialized = true;
551
423
  }
552
- /**
553
- * Parses the command line arguments and performs the corresponding actions.
554
- * @private
555
- * @returns {Promise<void>} A promise that resolves when the command line arguments have been processed, or the process exits.
556
- */
557
424
  async parseCommandLine() {
558
425
  if (hasParameter('help')) {
559
426
  this.log.info(`\nUsage: matterbridge [options]\n
@@ -665,7 +532,6 @@ export class Matterbridge extends EventEmitter {
665
532
  this.shutdown = true;
666
533
  return;
667
534
  }
668
- // Start the matter storage and create the matterbridge context
669
535
  try {
670
536
  await this.startMatterStorage();
671
537
  }
@@ -673,14 +539,12 @@ export class Matterbridge extends EventEmitter {
673
539
  this.log.fatal(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
674
540
  throw new Error(`Fatal error creating matter storage: ${error instanceof Error ? error.message : error}`);
675
541
  }
676
- // Clear the matterbridge context if the reset parameter is set
677
542
  if (hasParameter('reset') && getParameter('reset') === undefined) {
678
543
  this.initialized = true;
679
544
  await this.shutdownProcessAndReset();
680
545
  this.shutdown = true;
681
546
  return;
682
547
  }
683
- // Clear matterbridge plugin context if the reset parameter is set
684
548
  if (hasParameter('reset') && getParameter('reset') !== undefined) {
685
549
  this.log.debug(`Reset plugin ${getParameter('reset')}`);
686
550
  const plugin = this.plugins.get(getParameter('reset'));
@@ -705,37 +569,30 @@ export class Matterbridge extends EventEmitter {
705
569
  this.shutdown = true;
706
570
  return;
707
571
  }
708
- // Initialize frontend
709
572
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
710
573
  await this.frontend.start(getIntParameter('frontend'));
711
- // Check in 30 seconds the latest versions
712
574
  this.checkUpdateTimeout = setTimeout(async () => {
713
575
  const { checkUpdates } = await import('./update.js');
714
576
  checkUpdates(this);
715
577
  }, 30 * 1000).unref();
716
- // Check each 24 hours the latest versions
717
578
  this.checkUpdateInterval = setInterval(async () => {
718
579
  const { checkUpdates } = await import('./update.js');
719
580
  checkUpdates(this);
720
581
  }, 24 * 60 * 60 * 1000).unref();
721
- // Start the matterbridge in mode test
722
582
  if (hasParameter('test')) {
723
583
  this.bridgeMode = 'bridge';
724
584
  MatterbridgeEndpoint.bridgeMode = 'bridge';
725
585
  return;
726
586
  }
727
- // Start the matterbridge in mode controller
728
587
  if (hasParameter('controller')) {
729
588
  this.bridgeMode = 'controller';
730
589
  await this.startController();
731
590
  return;
732
591
  }
733
- // Check if the bridge mode is set and start matterbridge in bridge mode if not set
734
592
  if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
735
593
  this.log.info('Setting default matterbridge start mode to bridge');
736
594
  await this.nodeContext?.set('bridgeMode', 'bridge');
737
595
  }
738
- // Start matterbridge in bridge mode
739
596
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
740
597
  this.bridgeMode = 'bridge';
741
598
  MatterbridgeEndpoint.bridgeMode = 'bridge';
@@ -743,7 +600,6 @@ export class Matterbridge extends EventEmitter {
743
600
  await this.startBridge();
744
601
  return;
745
602
  }
746
- // Start matterbridge in childbridge mode
747
603
  if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
748
604
  this.bridgeMode = 'childbridge';
749
605
  MatterbridgeEndpoint.bridgeMode = 'childbridge';
@@ -752,20 +608,10 @@ export class Matterbridge extends EventEmitter {
752
608
  return;
753
609
  }
754
610
  }
755
- /**
756
- * Asynchronously loads and starts the registered plugins.
757
- *
758
- * This method is responsible for initializing and staarting all enabled plugins.
759
- * It ensures that each plugin is properly loaded and started before the bridge starts.
760
- *
761
- * @returns {Promise<void>} A promise that resolves when all plugins have been loaded and started.
762
- */
763
611
  async startPlugins() {
764
- // Check, load and start the plugins
765
612
  for (const plugin of this.plugins) {
766
613
  plugin.configJson = await this.plugins.loadConfig(plugin);
767
614
  plugin.schemaJson = await this.plugins.loadSchema(plugin);
768
- // Check if the plugin is available
769
615
  if (!(await this.plugins.resolve(plugin.path))) {
770
616
  this.log.error(`Plugin ${plg}${plugin.name}${er} not found or not validated. Disabling it.`);
771
617
  plugin.enabled = false;
@@ -785,26 +631,20 @@ export class Matterbridge extends EventEmitter {
785
631
  plugin.addedDevices = undefined;
786
632
  plugin.qrPairingCode = undefined;
787
633
  plugin.manualPairingCode = undefined;
788
- this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
634
+ this.plugins.load(plugin, true, 'Matterbridge is starting');
789
635
  }
790
636
  this.frontend.wssSendRefreshRequired('plugins');
791
637
  }
792
- /**
793
- * Registers the process handlers for uncaughtException, unhandledRejection, SIGINT and SIGTERM.
794
- * When either of these signals are received, the cleanup method is called with an appropriate message.
795
- */
796
638
  registerProcessHandlers() {
797
639
  this.log.debug(`Registering uncaughtException and unhandledRejection handlers...`);
798
640
  process.removeAllListeners('uncaughtException');
799
641
  process.removeAllListeners('unhandledRejection');
800
642
  this.exceptionHandler = async (error) => {
801
643
  this.log.error('Unhandled Exception detected at:', error.stack || error, rs);
802
- // await this.cleanup('Unhandled Exception detected, cleaning up...');
803
644
  };
804
645
  process.on('uncaughtException', this.exceptionHandler);
805
646
  this.rejectionHandler = async (reason, promise) => {
806
647
  this.log.error('Unhandled Rejection detected at:', promise, 'reason:', reason instanceof Error ? reason.stack : reason, rs);
807
- // await this.cleanup('Unhandled Rejection detected, cleaning up...');
808
648
  };
809
649
  process.on('unhandledRejection', this.rejectionHandler);
810
650
  this.log.debug(`Registering SIGINT and SIGTERM signal handlers...`);
@@ -817,9 +657,6 @@ export class Matterbridge extends EventEmitter {
817
657
  };
818
658
  process.on('SIGTERM', this.sigtermHandler);
819
659
  }
820
- /**
821
- * Deregisters the process uncaughtException, unhandledRejection, SIGINT and SIGTERM signal handlers.
822
- */
823
660
  deregisterProcesslHandlers() {
824
661
  this.log.debug(`Deregistering uncaughtException and unhandledRejection handlers...`);
825
662
  if (this.exceptionHandler)
@@ -836,17 +673,12 @@ export class Matterbridge extends EventEmitter {
836
673
  process.off('SIGTERM', this.sigtermHandler);
837
674
  this.sigtermHandler = undefined;
838
675
  }
839
- /**
840
- * Logs the node and system information.
841
- */
842
676
  async logNodeAndSystemInfo() {
843
- // IP address information
844
677
  const networkInterfaces = os.networkInterfaces();
845
678
  this.systemInformation.interfaceName = '';
846
679
  this.systemInformation.ipv4Address = '';
847
680
  this.systemInformation.ipv6Address = '';
848
681
  for (const [interfaceName, interfaceDetails] of Object.entries(networkInterfaces)) {
849
- // this.log.debug(`Checking interface: '${interfaceName}' for '${this.mdnsInterface}'`);
850
682
  if (this.mdnsInterface && interfaceName !== this.mdnsInterface)
851
683
  continue;
852
684
  if (!interfaceDetails) {
@@ -872,22 +704,19 @@ export class Matterbridge extends EventEmitter {
872
704
  break;
873
705
  }
874
706
  }
875
- // Node information
876
707
  this.systemInformation.nodeVersion = process.versions.node;
877
708
  const versionMajor = parseInt(this.systemInformation.nodeVersion.split('.')[0]);
878
709
  const versionMinor = parseInt(this.systemInformation.nodeVersion.split('.')[1]);
879
710
  const versionPatch = parseInt(this.systemInformation.nodeVersion.split('.')[2]);
880
- // Host system information
881
711
  this.systemInformation.hostname = os.hostname();
882
712
  this.systemInformation.user = os.userInfo().username;
883
- this.systemInformation.osType = os.type(); // "Windows_NT", "Darwin", etc.
884
- this.systemInformation.osRelease = os.release(); // Kernel version
885
- this.systemInformation.osPlatform = os.platform(); // "win32", "linux", "darwin", etc.
886
- this.systemInformation.osArch = os.arch(); // "x64", "arm", etc.
887
- this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
888
- this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB'; // Convert to GB
889
- this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours'; // Convert to hours
890
- // Log the system information
713
+ this.systemInformation.osType = os.type();
714
+ this.systemInformation.osRelease = os.release();
715
+ this.systemInformation.osPlatform = os.platform();
716
+ this.systemInformation.osArch = os.arch();
717
+ this.systemInformation.totalMemory = (os.totalmem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
718
+ this.systemInformation.freeMemory = (os.freemem() / 1024 / 1024 / 1024).toFixed(2) + ' GB';
719
+ this.systemInformation.systemUptime = (os.uptime() / 60 / 60).toFixed(2) + ' hours';
891
720
  this.log.debug('Host System Information:');
892
721
  this.log.debug(`- Hostname: ${this.systemInformation.hostname}`);
893
722
  this.log.debug(`- User: ${this.systemInformation.user}`);
@@ -903,20 +732,16 @@ export class Matterbridge extends EventEmitter {
903
732
  this.log.debug(`- Total Memory: ${this.systemInformation.totalMemory}`);
904
733
  this.log.debug(`- Free Memory: ${this.systemInformation.freeMemory}`);
905
734
  this.log.debug(`- System Uptime: ${this.systemInformation.systemUptime}`);
906
- // Home directory
907
735
  this.homeDirectory = getParameter('homedir') ?? os.homedir();
908
736
  this.matterbridgeInformation.homeDirectory = this.homeDirectory;
909
737
  this.log.debug(`Home Directory: ${this.homeDirectory}`);
910
- // Package root directory
911
738
  const { fileURLToPath } = await import('node:url');
912
739
  const currentFileDirectory = path.dirname(fileURLToPath(import.meta.url));
913
740
  this.rootDirectory = path.resolve(currentFileDirectory, '../');
914
741
  this.matterbridgeInformation.rootDirectory = this.rootDirectory;
915
742
  this.log.debug(`Root Directory: ${this.rootDirectory}`);
916
- // Global node_modules directory
917
743
  if (this.nodeContext)
918
744
  this.globalModulesDirectory = this.matterbridgeInformation.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
919
- // First run of Matterbridge so the node storage is empty
920
745
  if (this.globalModulesDirectory === '') {
921
746
  try {
922
747
  this.execRunningCount++;
@@ -932,20 +757,6 @@ export class Matterbridge extends EventEmitter {
932
757
  }
933
758
  else
934
759
  this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
935
- /* removed cause is too expensive for the shelly board and not really needed. Why should it change the globalModulesDirectory?
936
- else {
937
- this.getGlobalNodeModules()
938
- .then(async (globalModulesDirectory) => {
939
- this.globalModulesDirectory = globalModulesDirectory;
940
- this.matterbridgeInformation.globalModulesDirectory = this.globalModulesDirectory;
941
- this.log.debug(`Global node_modules Directory: ${this.globalModulesDirectory}`);
942
- await this.nodeContext?.set<string>('globalModulesDirectory', this.globalModulesDirectory);
943
- })
944
- .catch((error) => {
945
- this.log.error(`Error getting global node_modules directory: ${error}`);
946
- });
947
- }*/
948
- // Create the data directory .matterbridge in the home directory
949
760
  this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
950
761
  this.matterbridgeInformation.matterbridgeDirectory = this.matterbridgeDirectory;
951
762
  try {
@@ -969,7 +780,6 @@ export class Matterbridge extends EventEmitter {
969
780
  }
970
781
  }
971
782
  this.log.debug(`Matterbridge Directory: ${this.matterbridgeDirectory}`);
972
- // Create the plugin directory Matterbridge in the home directory
973
783
  this.matterbridgePluginDirectory = path.join(this.homeDirectory, 'Matterbridge');
974
784
  this.matterbridgeInformation.matterbridgePluginDirectory = this.matterbridgePluginDirectory;
975
785
  try {
@@ -993,68 +803,50 @@ export class Matterbridge extends EventEmitter {
993
803
  }
994
804
  }
995
805
  this.log.debug(`Matterbridge Plugin Directory: ${this.matterbridgePluginDirectory}`);
996
- // Matterbridge version
997
806
  const packageJson = JSON.parse(await fs.readFile(path.join(this.rootDirectory, 'package.json'), 'utf-8'));
998
807
  this.matterbridgeVersion = this.matterbridgeLatestVersion = packageJson.version;
999
808
  this.matterbridgeInformation.matterbridgeVersion = this.matterbridgeInformation.matterbridgeLatestVersion = this.matterbridgeVersion;
1000
809
  this.log.debug(`Matterbridge Version: ${this.matterbridgeVersion}`);
1001
- // Matterbridge latest version
1002
810
  if (this.nodeContext)
1003
811
  this.matterbridgeLatestVersion = await this.nodeContext.get('matterbridgeLatestVersion', this.matterbridgeVersion);
1004
812
  this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
1005
- // this.getMatterbridgeLatestVersion();
1006
- // Current working directory
1007
813
  const currentDir = process.cwd();
1008
814
  this.log.debug(`Current Working Directory: ${currentDir}`);
1009
- // Command line arguments (excluding 'node' and the script name)
1010
815
  const cmdArgs = process.argv.slice(2).join(' ');
1011
816
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
1012
817
  }
1013
- /**
1014
- * Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
1015
- *
1016
- * @returns {Function} The MatterLogger function.
1017
- */
1018
818
  createMatterLogger() {
1019
- const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
819
+ const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
1020
820
  return (_level, formattedLog) => {
1021
821
  const logger = formattedLog.slice(44, 44 + 20).trim();
1022
822
  const message = formattedLog.slice(65);
1023
823
  matterLogger.logName = logger;
1024
824
  switch (_level) {
1025
825
  case MatterLogLevel.DEBUG:
1026
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
826
+ matterLogger.log("debug", message);
1027
827
  break;
1028
828
  case MatterLogLevel.INFO:
1029
- matterLogger.log("info" /* LogLevel.INFO */, message);
829
+ matterLogger.log("info", message);
1030
830
  break;
1031
831
  case MatterLogLevel.NOTICE:
1032
- matterLogger.log("notice" /* LogLevel.NOTICE */, message);
832
+ matterLogger.log("notice", message);
1033
833
  break;
1034
834
  case MatterLogLevel.WARN:
1035
- matterLogger.log("warn" /* LogLevel.WARN */, message);
835
+ matterLogger.log("warn", message);
1036
836
  break;
1037
837
  case MatterLogLevel.ERROR:
1038
- matterLogger.log("error" /* LogLevel.ERROR */, message);
838
+ matterLogger.log("error", message);
1039
839
  break;
1040
840
  case MatterLogLevel.FATAL:
1041
- matterLogger.log("fatal" /* LogLevel.FATAL */, message);
841
+ matterLogger.log("fatal", message);
1042
842
  break;
1043
843
  default:
1044
- matterLogger.log("debug" /* LogLevel.DEBUG */, message);
844
+ matterLogger.log("debug", message);
1045
845
  break;
1046
846
  }
1047
847
  };
1048
848
  }
1049
- /**
1050
- * Creates a Matter File Logger.
1051
- *
1052
- * @param {string} filePath - The path to the log file.
1053
- * @param {boolean} [unlink=false] - Whether to unlink the log file before creating a new one.
1054
- * @returns {Function} - A function that logs formatted messages to the log file.
1055
- */
1056
849
  async createMatterFileLogger(filePath, unlink = false) {
1057
- // 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
1058
850
  let fileSize = 0;
1059
851
  if (unlink) {
1060
852
  try {
@@ -1103,21 +895,12 @@ export class Matterbridge extends EventEmitter {
1103
895
  }
1104
896
  };
1105
897
  }
1106
- /**
1107
- * Restarts the process by exiting the current instance and loading a new instance.
1108
- */
1109
898
  async restartProcess() {
1110
899
  await this.cleanup('restarting...', true);
1111
900
  }
1112
- /**
1113
- * Shut down the process by exiting the current process.
1114
- */
1115
901
  async shutdownProcess() {
1116
902
  await this.cleanup('shutting down...', false);
1117
903
  }
1118
- /**
1119
- * Update matterbridge and and shut down the process.
1120
- */
1121
904
  async updateProcess() {
1122
905
  this.log.info('Updating matterbridge...');
1123
906
  try {
@@ -1130,72 +913,51 @@ export class Matterbridge extends EventEmitter {
1130
913
  this.frontend.wssSendRestartRequired();
1131
914
  await this.cleanup('updating...', false);
1132
915
  }
1133
- /**
1134
- * Unregister all devices and shut down the process.
1135
- */
1136
916
  async unregisterAndShutdownProcess() {
1137
917
  this.log.info('Unregistering all devices and shutting down...');
1138
918
  for (const plugin of this.plugins) {
1139
919
  await this.removeAllBridgedEndpoints(plugin.name, 250);
1140
920
  }
1141
921
  this.log.debug('Waiting for the MessageExchange to finish...');
1142
- await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second for MessageExchange to finish
922
+ await new Promise((resolve) => setTimeout(resolve, 1000));
1143
923
  this.log.debug('Cleaning up and shutting down...');
1144
924
  await this.cleanup('unregistered all devices and shutting down...', false);
1145
925
  }
1146
- /**
1147
- * Reset commissioning and shut down the process.
1148
- */
1149
926
  async shutdownProcessAndReset() {
1150
927
  await this.cleanup('shutting down with reset...', false);
1151
928
  }
1152
- /**
1153
- * Factory reset and shut down the process.
1154
- */
1155
929
  async shutdownProcessAndFactoryReset() {
1156
930
  await this.cleanup('shutting down with factory reset...', false);
1157
931
  }
1158
- /**
1159
- * Cleans up the Matterbridge instance.
1160
- * @param message - The cleanup message.
1161
- * @param restart - Indicates whether to restart the instance after cleanup. Default is `false`.
1162
- * @returns A promise that resolves when the cleanup is completed.
1163
- */
1164
932
  async cleanup(message, restart = false) {
1165
933
  if (this.initialized && !this.hasCleanupStarted) {
1166
934
  this.hasCleanupStarted = true;
1167
935
  this.log.info(message);
1168
- // Clear the start matter interval
1169
936
  if (this.startMatterInterval) {
1170
937
  clearInterval(this.startMatterInterval);
1171
938
  this.startMatterInterval = undefined;
1172
939
  this.log.debug('Start matter interval cleared');
1173
940
  }
1174
- // Clear the check update timeout
1175
941
  if (this.checkUpdateTimeout) {
1176
942
  clearInterval(this.checkUpdateTimeout);
1177
943
  this.checkUpdateTimeout = undefined;
1178
944
  this.log.debug('Check update timeout cleared');
1179
945
  }
1180
- // Clear the check update interval
1181
946
  if (this.checkUpdateInterval) {
1182
947
  clearInterval(this.checkUpdateInterval);
1183
948
  this.checkUpdateInterval = undefined;
1184
949
  this.log.debug('Check update interval cleared');
1185
950
  }
1186
- // Clear the configure timeout
1187
951
  if (this.configureTimeout) {
1188
952
  clearTimeout(this.configureTimeout);
1189
953
  this.configureTimeout = undefined;
1190
954
  this.log.debug('Matterbridge configure timeout cleared');
1191
955
  }
1192
- // Clear the reachability timeout
1193
956
  if (this.reachabilityTimeout) {
1194
957
  clearTimeout(this.reachabilityTimeout);
1195
958
  this.reachabilityTimeout = undefined;
1196
959
  this.log.debug('Matterbridge reachability timeout cleared');
1197
960
  }
1198
- // Calling the shutdown method of each plugin and clear the plugins reachability timeout
1199
961
  for (const plugin of this.plugins) {
1200
962
  if (!plugin.enabled || plugin.error)
1201
963
  continue;
@@ -1206,10 +968,9 @@ export class Matterbridge extends EventEmitter {
1206
968
  this.log.debug(`Plugin ${plg}${plugin.name}${db} reachability timeout cleared`);
1207
969
  }
1208
970
  }
1209
- // Stopping matter server nodes
1210
971
  this.log.notice(`Stopping matter server nodes in ${this.bridgeMode} mode...`);
1211
972
  this.log.debug('Waiting for the MessageExchange to finish...');
1212
- await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1 second for MessageExchange to finish
973
+ await new Promise((resolve) => setTimeout(resolve, 1000));
1213
974
  if (this.bridgeMode === 'bridge') {
1214
975
  if (this.serverNode) {
1215
976
  await this.stopServerNode(this.serverNode);
@@ -1225,7 +986,6 @@ export class Matterbridge extends EventEmitter {
1225
986
  }
1226
987
  }
1227
988
  this.log.notice('Stopped matter server nodes');
1228
- // Matter commisioning reset
1229
989
  if (message === 'shutting down with reset...') {
1230
990
  this.log.info('Resetting Matterbridge commissioning information...');
1231
991
  await this.matterStorageManager?.createContext('events')?.clearAll();
@@ -1235,37 +995,17 @@ export class Matterbridge extends EventEmitter {
1235
995
  await this.matterbridgeContext?.clearAll();
1236
996
  this.log.info('Matter storage reset done! Remove the bridge from the controller.');
1237
997
  }
1238
- // Stop matter storage
1239
998
  await this.stopMatterStorage();
1240
- // Stop the frontend
1241
999
  await this.frontend.stop();
1242
- // Remove the matterfilelogger
1243
1000
  try {
1244
1001
  Logger.removeLogger('matterfilelogger');
1245
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1246
1002
  }
1247
1003
  catch (error) {
1248
- // this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
1249
1004
  }
1250
- // Serialize registeredDevices
1251
1005
  if (this.nodeStorage && this.nodeContext) {
1252
- /*
1253
- TODO: Implement serialization of registered devices in edge mode
1254
- this.log.info('Saving registered devices...');
1255
- const serializedRegisteredDevices: SerializedMatterbridgeEndpoint[] = [];
1256
- this.devices.forEach(async (device) => {
1257
- const serializedMatterbridgeDevice = MatterbridgeEndpoint.serialize(device);
1258
- // this.log.info(`- ${serializedMatterbridgeDevice.deviceName}${rs}\n`, serializedMatterbridgeDevice);
1259
- if (serializedMatterbridgeDevice) serializedRegisteredDevices.push(serializedMatterbridgeDevice);
1260
- });
1261
- await this.nodeContext.set<SerializedMatterbridgeEndpoint[]>('devices', serializedRegisteredDevices);
1262
- this.log.info(`Saved registered devices (${serializedRegisteredDevices?.length})`);
1263
- */
1264
- // Clear nodeContext and nodeStorage (they just need 1000ms to write the data to disk)
1265
1006
  this.log.debug(`Closing node storage context for ${plg}Matterbridge${db}...`);
1266
1007
  await this.nodeContext.close();
1267
1008
  this.nodeContext = undefined;
1268
- // Clear nodeContext for each plugin (they just need 1000ms to write the data to disk)
1269
1009
  for (const plugin of this.plugins) {
1270
1010
  if (plugin.nodeContext) {
1271
1011
  this.log.debug(`Closing node storage context for plugin ${plg}${plugin.name}${db}...`);
@@ -1282,10 +1022,8 @@ export class Matterbridge extends EventEmitter {
1282
1022
  }
1283
1023
  this.plugins.clear();
1284
1024
  this.devices.clear();
1285
- // Factory reset
1286
1025
  if (message === 'shutting down with factory reset...') {
1287
1026
  try {
1288
- // Delete old matter storage file and backup
1289
1027
  const file = path.join(this.matterbridgeDirectory, 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.json');
1290
1028
  this.log.info(`Unlinking old matter storage file: ${file}`);
1291
1029
  await fs.unlink(file);
@@ -1299,7 +1037,6 @@ export class Matterbridge extends EventEmitter {
1299
1037
  }
1300
1038
  }
1301
1039
  try {
1302
- // Delete matter node storage directory with its subdirectories and backup
1303
1040
  const dir = path.join(this.matterbridgeDirectory, 'matterstorage' + (getParameter('profile') ? '.' + getParameter('profile') : ''));
1304
1041
  this.log.info(`Removing matter node storage directory: ${dir}`);
1305
1042
  await fs.rm(dir, { recursive: true });
@@ -1313,7 +1050,6 @@ export class Matterbridge extends EventEmitter {
1313
1050
  }
1314
1051
  }
1315
1052
  try {
1316
- // Delete node storage directory with its subdirectories and backup
1317
1053
  const dir = path.join(this.matterbridgeDirectory, 'storage' + (getParameter('profile') ? '.' + getParameter('profile') : ''));
1318
1054
  this.log.info(`Removing storage directory: ${dir}`);
1319
1055
  await fs.rm(dir, { recursive: true });
@@ -1328,13 +1064,12 @@ export class Matterbridge extends EventEmitter {
1328
1064
  }
1329
1065
  this.log.info('Factory reset done! Remove all paired fabrics from the controllers.');
1330
1066
  }
1331
- // Deregisters the process handlers
1332
1067
  this.deregisterProcesslHandlers();
1333
1068
  if (restart) {
1334
1069
  if (message === 'updating...') {
1335
1070
  this.log.info('Cleanup completed. Updating...');
1336
1071
  Matterbridge.instance = undefined;
1337
- this.emit('update'); // Restart the process but the update has been done before. TODO move all updates to the cli
1072
+ this.emit('update');
1338
1073
  }
1339
1074
  else if (message === 'restarting...') {
1340
1075
  this.log.info('Cleanup completed. Restarting...');
@@ -1354,14 +1089,6 @@ export class Matterbridge extends EventEmitter {
1354
1089
  this.log.debug('Cleanup already started...');
1355
1090
  }
1356
1091
  }
1357
- /**
1358
- * Creates and configures the server node for an accessory plugin for a given device.
1359
- *
1360
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1361
- * @param {MatterbridgeEndpoint} device - The device to associate with the plugin.
1362
- * @param {boolean} [start=false] - Whether to start the server node after adding the device.
1363
- * @returns {Promise<void>} A promise that resolves when the server node for the accessory plugin is created and configured.
1364
- */
1365
1092
  async createAccessoryPlugin(plugin, device, start = false) {
1366
1093
  if (!plugin.locked && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
1367
1094
  plugin.locked = true;
@@ -1374,13 +1101,6 @@ export class Matterbridge extends EventEmitter {
1374
1101
  await this.startServerNode(plugin.serverNode);
1375
1102
  }
1376
1103
  }
1377
- /**
1378
- * Creates and configures the server node for a dynamic plugin.
1379
- *
1380
- * @param {RegisteredPlugin} plugin - The plugin to configure.
1381
- * @param {boolean} [start=false] - Whether to start the server node after adding the aggregator node.
1382
- * @returns {Promise<void>} A promise that resolves when the server node for the dynamic plugin is created and configured.
1383
- */
1384
1104
  async createDynamicPlugin(plugin, start = false) {
1385
1105
  if (!plugin.locked) {
1386
1106
  plugin.locked = true;
@@ -1392,13 +1112,7 @@ export class Matterbridge extends EventEmitter {
1392
1112
  await this.startServerNode(plugin.serverNode);
1393
1113
  }
1394
1114
  }
1395
- /**
1396
- * Starts the Matterbridge in bridge mode.
1397
- * @private
1398
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1399
- */
1400
1115
  async startBridge() {
1401
- // Plugins are configured by a timer when matter server is started and plugin.configured is set to true
1402
1116
  if (!this.matterStorageManager)
1403
1117
  throw new Error('No storage manager initialized');
1404
1118
  if (!this.matterbridgeContext)
@@ -1436,9 +1150,7 @@ export class Matterbridge extends EventEmitter {
1436
1150
  clearInterval(this.startMatterInterval);
1437
1151
  this.startMatterInterval = undefined;
1438
1152
  this.log.debug('Cleared startMatterInterval interval for Matterbridge');
1439
- // Start the Matter server node
1440
1153
  this.startServerNode(this.serverNode);
1441
- // Configure the plugins
1442
1154
  this.configureTimeout = setTimeout(async () => {
1443
1155
  for (const plugin of this.plugins) {
1444
1156
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1456,7 +1168,6 @@ export class Matterbridge extends EventEmitter {
1456
1168
  }
1457
1169
  this.frontend.wssSendRefreshRequired('plugins');
1458
1170
  }, 30 * 1000);
1459
- // Setting reachability to true
1460
1171
  this.reachabilityTimeout = setTimeout(() => {
1461
1172
  this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
1462
1173
  if (this.aggregatorNode)
@@ -1465,11 +1176,6 @@ export class Matterbridge extends EventEmitter {
1465
1176
  }, 60 * 1000);
1466
1177
  }, 1000);
1467
1178
  }
1468
- /**
1469
- * Starts the Matterbridge in childbridge mode.
1470
- * @private
1471
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1472
- */
1473
1179
  async startChildbridge() {
1474
1180
  if (!this.matterStorageManager)
1475
1181
  throw new Error('No storage manager initialized');
@@ -1514,7 +1220,6 @@ export class Matterbridge extends EventEmitter {
1514
1220
  clearInterval(this.startMatterInterval);
1515
1221
  this.startMatterInterval = undefined;
1516
1222
  this.log.debug('Cleared startMatterInterval interval in childbridge mode');
1517
- // Configure the plugins
1518
1223
  this.configureTimeout = setTimeout(async () => {
1519
1224
  for (const plugin of this.plugins) {
1520
1225
  if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
@@ -1551,9 +1256,7 @@ export class Matterbridge extends EventEmitter {
1551
1256
  this.log.error(`Node storage context not found for plugin ${plg}${plugin.name}${er}`);
1552
1257
  continue;
1553
1258
  }
1554
- // Start the Matter server node
1555
1259
  this.startServerNode(plugin.serverNode);
1556
- // Setting reachability to true
1557
1260
  plugin.reachabilityTimeout = setTimeout(() => {
1558
1261
  this.log.info(`Setting reachability to true for ${plg}${plugin.name}${db} type ${plugin.type} server node ${plugin.serverNode !== undefined} aggragator node ${plugin.aggregatorNode !== undefined} device ${plugin.device !== undefined}`);
1559
1262
  if (plugin.type === 'DynamicPlatform' && plugin.aggregatorNode)
@@ -1563,219 +1266,9 @@ export class Matterbridge extends EventEmitter {
1563
1266
  }
1564
1267
  }, 1000);
1565
1268
  }
1566
- /**
1567
- * Starts the Matterbridge controller.
1568
- * @private
1569
- * @returns {Promise<void>} A promise that resolves when the Matterbridge is started.
1570
- */
1571
1269
  async startController() {
1572
- /*
1573
- if (!this.storageManager) {
1574
- this.log.error('No storage manager initialized');
1575
- await this.cleanup('No storage manager initialized');
1576
- return;
1577
- }
1578
- this.log.info('Creating context: mattercontrollerContext');
1579
- this.mattercontrollerContext = this.storageManager.createContext('mattercontrollerContext');
1580
- if (!this.mattercontrollerContext) {
1581
- this.log.error('No storage context mattercontrollerContext initialized');
1582
- await this.cleanup('No storage context mattercontrollerContext initialized');
1583
- return;
1584
- }
1585
-
1586
- this.log.debug('Starting matterbridge in mode', this.bridgeMode);
1587
- this.matterServer = await this.createMatterServer(this.storageManager);
1588
- this.log.info('Creating matter commissioning controller');
1589
- this.commissioningController = new CommissioningController({
1590
- autoConnect: false,
1591
- });
1592
- this.log.info('Adding matter commissioning controller to matter server');
1593
- await this.matterServer.addCommissioningController(this.commissioningController);
1594
-
1595
- this.log.info('Starting matter server');
1596
- await this.matterServer.start();
1597
- this.log.info('Matter server started');
1598
-
1599
- if (hasParameter('pairingcode')) {
1600
- this.log.info('Pairing device with pairingcode:', getParameter('pairingcode'));
1601
- const pairingCode = getParameter('pairingcode');
1602
- const ip = this.mattercontrollerContext.has('ip') ? this.mattercontrollerContext.get<string>('ip') : undefined;
1603
- const port = this.mattercontrollerContext.has('port') ? this.mattercontrollerContext.get<number>('port') : undefined;
1604
-
1605
- let longDiscriminator, setupPin, shortDiscriminator;
1606
- if (pairingCode !== undefined) {
1607
- const pairingCodeCodec = ManualPairingCodeCodec.decode(pairingCode);
1608
- shortDiscriminator = pairingCodeCodec.shortDiscriminator;
1609
- longDiscriminator = undefined;
1610
- setupPin = pairingCodeCodec.passcode;
1611
- this.log.info(`Data extracted from pairing code: ${Logger.toJSON(pairingCodeCodec)}`);
1612
- } else {
1613
- longDiscriminator = await this.mattercontrollerContext.get('longDiscriminator', 3840);
1614
- if (longDiscriminator > 4095) throw new Error('Discriminator value must be less than 4096');
1615
- setupPin = this.mattercontrollerContext.get('pin', 20202021);
1616
- }
1617
- if ((shortDiscriminator === undefined && longDiscriminator === undefined) || setupPin === undefined) {
1618
- throw new Error('Please specify the longDiscriminator of the device to commission with -longDiscriminator or provide a valid passcode with -passcode');
1619
- }
1620
-
1621
- const commissioningOptions: ControllerCommissioningFlowOptions = {
1622
- regulatoryLocation: GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor,
1623
- regulatoryCountryCode: 'XX',
1624
- };
1625
- const options = {
1626
- commissioning: commissioningOptions,
1627
- discovery: {
1628
- knownAddress: ip !== undefined && port !== undefined ? { ip, port, type: 'udp' } : undefined,
1629
- identifierData: longDiscriminator !== undefined ? { longDiscriminator } : shortDiscriminator !== undefined ? { shortDiscriminator } : {},
1630
- },
1631
- passcode: setupPin,
1632
- } as NodeCommissioningOptions;
1633
- this.log.info('Commissioning with options:', options);
1634
- const nodeId = await this.commissioningController.commissionNode(options);
1635
- this.log.info(`Commissioning successfully done with nodeId: ${nodeId}`);
1636
- this.log.info('ActiveSessionInformation:', this.commissioningController.getActiveSessionInformation());
1637
- } // (hasParameter('pairingcode'))
1638
-
1639
- if (hasParameter('unpairall')) {
1640
- this.log.info('***Commissioning controller unpairing all nodes...');
1641
- const nodeIds = this.commissioningController.getCommissionedNodes();
1642
- for (const nodeId of nodeIds) {
1643
- this.log.info('***Commissioning controller unpairing node:', nodeId);
1644
- await this.commissioningController.removeNode(nodeId);
1645
- }
1646
- return;
1647
- }
1648
-
1649
- if (hasParameter('discover')) {
1650
- // const discover = await this.commissioningController.discoverCommissionableDevices({ productId: 0x8000, deviceType: 0xfff1 });
1651
- // console.log(discover);
1652
- }
1653
-
1654
- if (!this.commissioningController.isCommissioned()) {
1655
- this.log.info('***Commissioning controller is not commissioned: use matterbridge -controller -pairingcode [pairingcode] to commission a device');
1656
- return;
1657
- }
1658
-
1659
- const nodeIds = this.commissioningController.getCommissionedNodes();
1660
- this.log.info(`***Commissioning controller is commissioned ${this.commissioningController.isCommissioned()} and has ${nodeIds.length} nodes commisioned: `);
1661
- for (const nodeId of nodeIds) {
1662
- this.log.info(`***Connecting to commissioned node: ${nodeId}`);
1663
-
1664
- const node = await this.commissioningController.connectNode(nodeId, {
1665
- autoSubscribe: false,
1666
- attributeChangedCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, attributeName }, value }) =>
1667
- this.log.info(`***Commissioning controller attributeChangedCallback ${peerNodeId}: attribute ${nodeId}/${endpointId}/${clusterId}/${attributeName} changed to ${Logger.toJSON(value)}`),
1668
- eventTriggeredCallback: (peerNodeId, { path: { nodeId, clusterId, endpointId, eventName }, events }) =>
1669
- this.log.info(`***Commissioning controller eventTriggeredCallback ${peerNodeId}: Event ${nodeId}/${endpointId}/${clusterId}/${eventName} triggered with ${Logger.toJSON(events)}`),
1670
- stateInformationCallback: (peerNodeId, info) => {
1671
- switch (info) {
1672
- case NodeStateInformation.Connected:
1673
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} connected`);
1674
- break;
1675
- case NodeStateInformation.Disconnected:
1676
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} disconnected`);
1677
- break;
1678
- case NodeStateInformation.Reconnecting:
1679
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} reconnecting`);
1680
- break;
1681
- case NodeStateInformation.WaitingForDeviceDiscovery:
1682
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} waiting for device discovery`);
1683
- break;
1684
- case NodeStateInformation.StructureChanged:
1685
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} structure changed`);
1686
- break;
1687
- case NodeStateInformation.Decommissioned:
1688
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} decommissioned`);
1689
- break;
1690
- default:
1691
- this.log.info(`***Commissioning controller stateInformationCallback ${peerNodeId}: Node ${nodeId} NodeStateInformation.${info}`);
1692
- break;
1693
- }
1694
- },
1695
- });
1696
-
1697
- node.logStructure();
1698
-
1699
- // Get the interaction client
1700
- this.log.info('Getting the interaction client');
1701
- const interactionClient = await node.getInteractionClient();
1702
- let cluster;
1703
- let attributes;
1704
-
1705
- // Log BasicInformationCluster
1706
- cluster = BasicInformationCluster;
1707
- attributes = await interactionClient.getMultipleAttributes({
1708
- attributes: [{ clusterId: cluster.id }],
1709
- });
1710
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1711
- attributes.forEach((attribute) => {
1712
- this.log.info(
1713
- `- 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}`,
1714
- );
1715
- });
1716
-
1717
- // Log PowerSourceCluster
1718
- cluster = PowerSourceCluster;
1719
- attributes = await interactionClient.getMultipleAttributes({
1720
- attributes: [{ clusterId: cluster.id }],
1721
- });
1722
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1723
- attributes.forEach((attribute) => {
1724
- this.log.info(
1725
- `- 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}`,
1726
- );
1727
- });
1728
-
1729
- // Log ThreadNetworkDiagnostics
1730
- cluster = ThreadNetworkDiagnosticsCluster;
1731
- attributes = await interactionClient.getMultipleAttributes({
1732
- attributes: [{ clusterId: cluster.id }],
1733
- });
1734
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1735
- attributes.forEach((attribute) => {
1736
- this.log.info(
1737
- `- 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}`,
1738
- );
1739
- });
1740
-
1741
- // Log SwitchCluster
1742
- cluster = SwitchCluster;
1743
- attributes = await interactionClient.getMultipleAttributes({
1744
- attributes: [{ clusterId: cluster.id }],
1745
- });
1746
- if (attributes.length > 0) this.log.info(`Cluster: ${idn}${cluster.name}${rs}${nf} attributes:`);
1747
- attributes.forEach((attribute) => {
1748
- this.log.info(
1749
- `- 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}`,
1750
- );
1751
- });
1752
-
1753
- this.log.info('Subscribing to all attributes and events');
1754
- await node.subscribeAllAttributesAndEvents({
1755
- ignoreInitialTriggers: false,
1756
- attributeChangedCallback: ({ path: { nodeId, clusterId, endpointId, attributeName }, version, value }) =>
1757
- this.log.info(
1758
- `***${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}`,
1759
- ),
1760
- eventTriggeredCallback: ({ path: { nodeId, clusterId, endpointId, eventName }, events }) => {
1761
- this.log.info(
1762
- `***${db}Commissioning controller eventTriggeredCallback: event ${BLUE}${nodeId}${db}/${or}${endpointId}${db}/${hk}${getClusterNameById(clusterId)}${db}/${zb}${eventName}${db} triggered with ${debugStringify(events ?? { none: true })}`,
1763
- );
1764
- },
1765
- });
1766
- this.log.info('Subscribed to all attributes and events');
1767
- }
1768
- */
1769
1270
  }
1770
- /** ***********************************************************************************************************************************/
1771
- /** Matter.js methods */
1772
- /** ***********************************************************************************************************************************/
1773
- /**
1774
- * Starts the matter storage process with name Matterbridge.
1775
- * @returns {Promise<void>} - A promise that resolves when the storage process is started.
1776
- */
1777
1271
  async startMatterStorage() {
1778
- // Setup Matter storage
1779
1272
  this.log.info(`Starting matter node storage...`);
1780
1273
  this.matterStorageService = this.environment.get(StorageService);
1781
1274
  this.log.info(`Matter node storage service created: ${this.matterStorageService.location}`);
@@ -1783,25 +1276,13 @@ export class Matterbridge extends EventEmitter {
1783
1276
  this.log.info('Matter node storage manager "Matterbridge" created');
1784
1277
  this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', bridge.code, this.aggregatorVendorId, 'Matterbridge', this.aggregatorProductId, 'Matterbridge aggregator');
1785
1278
  this.log.info('Matter node storage started');
1786
- // Backup matter storage since it is created/opened correctly
1787
1279
  await this.backupMatterStorage(path.join(this.matterbridgeDirectory, this.matterStorageName), path.join(this.matterbridgeDirectory, this.matterStorageName + '.backup'));
1788
1280
  }
1789
- /**
1790
- * Makes a backup copy of the specified matter storage directory.
1791
- *
1792
- * @param storageName - The name of the storage directory to be backed up.
1793
- * @param backupName - The name of the backup directory to be created.
1794
- * @returns {Promise<void>} A promise that resolves when the has been done.
1795
- */
1796
1281
  async backupMatterStorage(storageName, backupName) {
1797
1282
  this.log.info('Creating matter node storage backup...');
1798
1283
  await copyDirectory(storageName, backupName);
1799
1284
  this.log.info('Created matter node storage backup');
1800
1285
  }
1801
- /**
1802
- * Stops the matter storage.
1803
- * @returns {Promise<void>} A promise that resolves when the storage is stopped.
1804
- */
1805
1286
  async stopMatterStorage() {
1806
1287
  this.log.info('Closing matter node storage...');
1807
1288
  this.matterStorageManager?.close();
@@ -1810,19 +1291,6 @@ export class Matterbridge extends EventEmitter {
1810
1291
  this.matterbridgeContext = undefined;
1811
1292
  this.log.info('Matter node storage closed');
1812
1293
  }
1813
- /**
1814
- * Creates a server node storage context.
1815
- *
1816
- * @param {string} pluginName - The name of the plugin.
1817
- * @param {string} deviceName - The name of the device.
1818
- * @param {DeviceTypeId} deviceType - The device type of the device.
1819
- * @param {number} vendorId - The vendor ID.
1820
- * @param {string} vendorName - The vendor name.
1821
- * @param {number} productId - The product ID.
1822
- * @param {string} productName - The product name.
1823
- * @param {string} [serialNumber] - The serial number of the device (optional).
1824
- * @returns {Promise<StorageContext>} The storage context for the commissioning server.
1825
- */
1826
1294
  async createServerNodeContext(pluginName, deviceName, deviceType, vendorId, vendorName, productId, productName, serialNumber) {
1827
1295
  const { randomBytes } = await import('node:crypto');
1828
1296
  if (!this.matterStorageService)
@@ -1856,15 +1324,6 @@ export class Matterbridge extends EventEmitter {
1856
1324
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
1857
1325
  return storageContext;
1858
1326
  }
1859
- /**
1860
- * Creates a server node.
1861
- *
1862
- * @param {StorageContext} storageContext - The storage context for the server node.
1863
- * @param {number} [port=5540] - The port number for the server node. Defaults to 5540.
1864
- * @param {number} [passcode=20242025] - The passcode for the server node. Defaults to 20242025.
1865
- * @param {number} [discriminator=3850] - The discriminator for the server node. Defaults to 3850.
1866
- * @returns {Promise<ServerNode<ServerNode.RootEndpoint>>} A promise that resolves to the created server node.
1867
- */
1868
1327
  async createServerNode(storageContext, port = 5540, passcode = 20242025, discriminator = 3850) {
1869
1328
  const storeId = await storageContext.get('storeId');
1870
1329
  this.log.notice(`Creating server node for ${storeId} on port ${port} with passcode ${passcode} and discriminator ${discriminator}...`);
@@ -1874,33 +1333,21 @@ export class Matterbridge extends EventEmitter {
1874
1333
  this.log.debug(`- uniqueId: ${await storageContext.get('uniqueId')}`);
1875
1334
  this.log.debug(`- softwareVersion: ${await storageContext.get('softwareVersion')} softwareVersionString: ${await storageContext.get('softwareVersionString')}`);
1876
1335
  this.log.debug(`- hardwareVersion: ${await storageContext.get('hardwareVersion')} hardwareVersionString: ${await storageContext.get('hardwareVersionString')}`);
1877
- /**
1878
- * Create a Matter ServerNode, which contains the Root Endpoint and all relevant data and configuration
1879
- */
1880
1336
  const serverNode = await ServerNode.create({
1881
- // Required: Give the Node a unique ID which is used to store the state of this node
1882
1337
  id: storeId,
1883
- // Provide Network relevant configuration like the port
1884
- // Optional when operating only one device on a host, Default port is 5540
1885
1338
  network: {
1886
1339
  listeningAddressIpv4: this.ipv4address,
1887
1340
  listeningAddressIpv6: this.ipv6address,
1888
1341
  port,
1889
1342
  },
1890
- // Provide Commissioning relevant settings
1891
- // Optional for development/testing purposes
1892
1343
  commissioning: {
1893
1344
  passcode,
1894
1345
  discriminator,
1895
1346
  },
1896
- // Provide Node announcement settings
1897
- // Optional: If Ommitted some development defaults are used
1898
1347
  productDescription: {
1899
1348
  name: await storageContext.get('deviceName'),
1900
1349
  deviceType: DeviceTypeId(await storageContext.get('deviceType')),
1901
1350
  },
1902
- // Provide defaults for the BasicInformation cluster on the Root endpoint
1903
- // Optional: If Omitted some development defaults are used
1904
1351
  basicInformation: {
1905
1352
  vendorId: VendorId(await storageContext.get('vendorId')),
1906
1353
  vendorName: await storageContext.get('vendorName'),
@@ -1917,13 +1364,12 @@ export class Matterbridge extends EventEmitter {
1917
1364
  },
1918
1365
  });
1919
1366
  const sanitizeFabrics = (fabrics, resetSessions = false) => {
1920
- // New type of fabric information: Record<FabricIndex, ExposedFabricInformation>
1921
1367
  const sanitizedFabrics = this.sanitizeFabricInformations(Array.from(Object.values(fabrics)));
1922
1368
  this.log.info(`Fabrics: ${debugStringify(sanitizedFabrics)}`);
1923
1369
  if (this.bridgeMode === 'bridge') {
1924
1370
  this.matterbridgeFabricInformations = sanitizedFabrics;
1925
1371
  if (resetSessions)
1926
- this.matterbridgeSessionInformations = undefined; // Changed cause Invoke Matterbridge.operationalCredentials.updateFabricLabel is sent after the session is created
1372
+ this.matterbridgeSessionInformations = undefined;
1927
1373
  this.matterbridgePaired = true;
1928
1374
  }
1929
1375
  if (this.bridgeMode === 'childbridge') {
@@ -1931,19 +1377,13 @@ export class Matterbridge extends EventEmitter {
1931
1377
  if (plugin) {
1932
1378
  plugin.fabricInformations = sanitizedFabrics;
1933
1379
  if (resetSessions)
1934
- plugin.sessionInformations = undefined; // Changed cause Invoke Matterbridge.operationalCredentials.updateFabricLabel is sent after the session is created
1380
+ plugin.sessionInformations = undefined;
1935
1381
  plugin.paired = true;
1936
1382
  }
1937
1383
  }
1938
1384
  };
1939
- /**
1940
- * This event is triggered when the device is initially commissioned successfully.
1941
- * This means: It is added to the first fabric.
1942
- */
1943
1385
  serverNode.lifecycle.commissioned.on(() => this.log.notice(`Server node for ${storeId} was initially commissioned successfully!`));
1944
- /** This event is triggered when all fabrics are removed from the device, usually it also does a factory reset then. */
1945
1386
  serverNode.lifecycle.decommissioned.on(() => this.log.notice(`Server node for ${storeId} was fully decommissioned successfully!`));
1946
- /** This event is triggered when the device went online. This means that it is discoverable in the network. */
1947
1387
  serverNode.lifecycle.online.on(async () => {
1948
1388
  this.log.notice(`Server node for ${storeId} is online`);
1949
1389
  if (!serverNode.lifecycle.isCommissioned) {
@@ -1991,7 +1431,6 @@ export class Matterbridge extends EventEmitter {
1991
1431
  this.frontend.wssSendRefreshRequired('settings');
1992
1432
  this.frontend.wssSendSnackbarMessage(`${storeId} is online`, 5, 'success');
1993
1433
  });
1994
- /** This event is triggered when the device went offline. it is not longer discoverable or connectable in the network. */
1995
1434
  serverNode.lifecycle.offline.on(() => {
1996
1435
  this.log.notice(`Server node for ${storeId} is offline`);
1997
1436
  if (this.bridgeMode === 'bridge') {
@@ -2015,10 +1454,6 @@ export class Matterbridge extends EventEmitter {
2015
1454
  this.frontend.wssSendRefreshRequired('settings');
2016
1455
  this.frontend.wssSendSnackbarMessage(`${storeId} is offline`, 5, 'warning');
2017
1456
  });
2018
- /**
2019
- * This event is triggered when a fabric is added, removed or updated on the device. Use this if more granular
2020
- * information is needed.
2021
- */
2022
1457
  serverNode.events.commissioning.fabricsChanged.on((fabricIndex, fabricAction) => {
2023
1458
  let action = '';
2024
1459
  switch (fabricAction) {
@@ -2052,24 +1487,16 @@ export class Matterbridge extends EventEmitter {
2052
1487
  }
2053
1488
  }
2054
1489
  };
2055
- /**
2056
- * This event is triggered when an operative new session was opened by a Controller.
2057
- * It is not triggered for the initial commissioning process, just afterwards for real connections.
2058
- */
2059
1490
  serverNode.events.sessions.opened.on((session) => {
2060
1491
  this.log.notice(`Session opened on server node for ${storeId}: ${debugStringify(session)}`);
2061
1492
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
2062
1493
  this.frontend.wssSendRefreshRequired('sessions');
2063
1494
  });
2064
- /**
2065
- * This event is triggered when an operative session is closed by a Controller or because the Device goes offline.
2066
- */
2067
1495
  serverNode.events.sessions.closed.on((session) => {
2068
1496
  this.log.notice(`Session closed on server node for ${storeId}: ${debugStringify(session)}`);
2069
1497
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
2070
1498
  this.frontend.wssSendRefreshRequired('sessions');
2071
1499
  });
2072
- /** This event is triggered when a subscription gets added or removed on an operative session. */
2073
1500
  serverNode.events.sessions.subscriptionsChanged.on((session) => {
2074
1501
  this.log.notice(`Session subscriptions changed on server node for ${storeId}: ${debugStringify(session)}`);
2075
1502
  sanitizeSessions(Object.values(serverNode.state.sessions.sessions));
@@ -2078,42 +1505,24 @@ export class Matterbridge extends EventEmitter {
2078
1505
  this.log.info(`Created server node for ${storeId}`);
2079
1506
  return serverNode;
2080
1507
  }
2081
- /**
2082
- * Starts the specified server node.
2083
- *
2084
- * @param {ServerNode} [matterServerNode] - The server node to start.
2085
- * @returns {Promise<void>} A promise that resolves when the server node has started.
2086
- */
2087
1508
  async startServerNode(matterServerNode) {
2088
1509
  if (!matterServerNode)
2089
1510
  return;
2090
1511
  this.log.notice(`Starting ${matterServerNode.id} server node`);
2091
1512
  await matterServerNode.start();
2092
1513
  }
2093
- /**
2094
- * Stops the specified server node.
2095
- *
2096
- * @param {ServerNode} matterServerNode - The server node to stop.
2097
- * @returns {Promise<void>} A promise that resolves when the server node has stopped.
2098
- */
2099
1514
  async stopServerNode(matterServerNode) {
2100
1515
  if (!matterServerNode)
2101
1516
  return;
2102
1517
  this.log.notice(`Closing ${matterServerNode.id} server node`);
2103
1518
  try {
2104
- await withTimeout(matterServerNode.close(), 30000); // 30 seconds timeout to allow slow devices to close gracefully
1519
+ await withTimeout(matterServerNode.close(), 30000);
2105
1520
  this.log.info(`Closed ${matterServerNode.id} server node`);
2106
1521
  }
2107
1522
  catch (error) {
2108
1523
  this.log.error(`Failed to close ${matterServerNode.id} server node: ${error instanceof Error ? error.message : error}`);
2109
1524
  }
2110
1525
  }
2111
- /**
2112
- * Advertises the specified server node.
2113
- *
2114
- * @param {ServerNode} [matterServerNode] - The server node to advertise.
2115
- * @returns {Promise<{ qrPairingCode: string, manualPairingCode: string } | undefined>} A promise that resolves to the pairing codes if the server node is advertised, or undefined if not.
2116
- */
2117
1526
  async advertiseServerNode(matterServerNode) {
2118
1527
  if (matterServerNode) {
2119
1528
  await matterServerNode.env.get(DeviceCommissioner)?.allowBasicCommissioning();
@@ -2122,44 +1531,23 @@ export class Matterbridge extends EventEmitter {
2122
1531
  return { qrPairingCode, manualPairingCode };
2123
1532
  }
2124
1533
  }
2125
- /**
2126
- * Stop advertise the specified server node.
2127
- *
2128
- * @param {ServerNode} [matterServerNode] - The server node to advertise.
2129
- * @returns {Promise<void>} A promise that resolves when the server node has stopped advertising.
2130
- */
2131
1534
  async stopAdvertiseServerNode(matterServerNode) {
2132
1535
  if (matterServerNode && matterServerNode.lifecycle.isOnline) {
2133
1536
  await matterServerNode.env.get(DeviceCommissioner)?.endCommissioning();
2134
1537
  this.log.notice(`Stopped advertising for ${matterServerNode.id}`);
2135
1538
  }
2136
1539
  }
2137
- /**
2138
- * Creates an aggregator node with the specified storage context.
2139
- *
2140
- * @param {StorageContext} storageContext - The storage context for the aggregator node.
2141
- * @returns {Promise<EndpointNode<AggregatorEndpoint>>} A promise that resolves to the created aggregator node.
2142
- */
2143
1540
  async createAggregatorNode(storageContext) {
2144
1541
  this.log.notice(`Creating ${await storageContext.get('storeId')} aggregator `);
2145
1542
  const aggregatorNode = new EndpointNode(AggregatorEndpoint, { id: `${await storageContext.get('storeId')}` });
2146
1543
  return aggregatorNode;
2147
1544
  }
2148
- /**
2149
- * Adds a MatterbridgeEndpoint to the specified plugin.
2150
- *
2151
- * @param {string} pluginName - The name of the plugin.
2152
- * @param {MatterbridgeEndpoint} device - The device to add as a bridged endpoint.
2153
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been added.
2154
- */
2155
1545
  async addBridgedEndpoint(pluginName, device) {
2156
- // Check if the plugin is registered
2157
1546
  const plugin = this.plugins.get(pluginName);
2158
1547
  if (!plugin) {
2159
1548
  this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
2160
1549
  return;
2161
1550
  }
2162
- // Register and add the device to the matterbridge aggregator node
2163
1551
  if (this.bridgeMode === 'bridge') {
2164
1552
  this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
2165
1553
  if (!this.aggregatorNode)
@@ -2182,28 +1570,17 @@ export class Matterbridge extends EventEmitter {
2182
1570
  plugin.registeredDevices++;
2183
1571
  if (plugin.addedDevices !== undefined)
2184
1572
  plugin.addedDevices++;
2185
- // Add the device to the DeviceManager
2186
1573
  this.devices.set(device);
2187
- // Subscribe to the reachable$Changed event
2188
1574
  await this.subscribeAttributeChanged(plugin, device);
2189
1575
  this.log.info(`Added and registered bridged endpoint (${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) for plugin ${plg}${pluginName}${nf}`);
2190
1576
  }
2191
- /**
2192
- * Removes a MatterbridgeEndpoint from the specified plugin.
2193
- *
2194
- * @param {string} pluginName - The name of the plugin.
2195
- * @param {MatterbridgeEndpoint} device - The device to remove as a bridged endpoint.
2196
- * @returns {Promise<void>} A promise that resolves when the bridged endpoint has been removed.
2197
- */
2198
1577
  async removeBridgedEndpoint(pluginName, device) {
2199
1578
  this.log.debug(`Removing bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} (${zb}${device.name}${db}) for plugin ${plg}${pluginName}${db}`);
2200
- // Check if the plugin is registered
2201
1579
  const plugin = this.plugins.get(pluginName);
2202
1580
  if (!plugin) {
2203
1581
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: plugin not found`);
2204
1582
  return;
2205
1583
  }
2206
- // Register and add the device to the matterbridge aggregator node
2207
1584
  if (this.bridgeMode === 'bridge') {
2208
1585
  if (!this.aggregatorNode) {
2209
1586
  this.log.error(`Error removing bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.name}${er}) for plugin ${plg}${pluginName}${er}: aggregator node not found`);
@@ -2218,7 +1595,6 @@ export class Matterbridge extends EventEmitter {
2218
1595
  }
2219
1596
  else if (this.bridgeMode === 'childbridge') {
2220
1597
  if (plugin.type === 'AccessoryPlatform') {
2221
- // Nothing to do here since the server node has no aggregator node but only the device itself
2222
1598
  }
2223
1599
  else if (plugin.type === 'DynamicPlatform') {
2224
1600
  if (!plugin.aggregatorNode) {
@@ -2233,16 +1609,8 @@ export class Matterbridge extends EventEmitter {
2233
1609
  if (plugin.addedDevices !== undefined)
2234
1610
  plugin.addedDevices--;
2235
1611
  }
2236
- // Remove the device from the DeviceManager
2237
1612
  this.devices.remove(device);
2238
1613
  }
2239
- /**
2240
- * Removes all bridged endpoints from the specified plugin.
2241
- *
2242
- * @param {string} pluginName - The name of the plugin.
2243
- * @param {number} [delay=0] - The delay in milliseconds between removing each bridged endpoint (default: 0).
2244
- * @returns {Promise<void>} A promise that resolves when all bridged endpoints have been removed.
2245
- */
2246
1614
  async removeAllBridgedEndpoints(pluginName, delay = 0) {
2247
1615
  this.log.debug(`Removing all bridged endpoints for plugin ${plg}${pluginName}${db}`);
2248
1616
  for (const device of this.devices.array().filter((device) => device.plugin === pluginName)) {
@@ -2251,25 +1619,9 @@ export class Matterbridge extends EventEmitter {
2251
1619
  await new Promise((resolve) => setTimeout(resolve, delay));
2252
1620
  }
2253
1621
  }
2254
- /**
2255
- * Subscribes to the attribute change event for the given device and plugin.
2256
- * Specifically, it listens for changes in the 'reachable' attribute of the
2257
- * BridgedDeviceBasicInformationServer cluster server of the bridged device or BasicInformationServer cluster server of server node.
2258
- *
2259
- * @param {RegisteredPlugin} plugin - The plugin associated with the device.
2260
- * @param {MatterbridgeEndpoint} device - The device to subscribe to attribute changes for.
2261
- * @returns {Promise<void>} A promise that resolves when the subscription is set up.
2262
- */
2263
1622
  async subscribeAttributeChanged(plugin, device) {
2264
1623
  this.log.info(`Subscribing attributes for endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) plugin ${plg}${plugin.name}${nf}`);
2265
1624
  if (this.bridgeMode === 'childbridge' && plugin.type === 'AccessoryPlatform' && plugin.serverNode) {
2266
- /*
2267
- this.log.info(`Accessory endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) subscribed to reachable$Changed`);
2268
- setTimeout(async () => {
2269
- this.log.info(`Accessory endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) changed to reachable false`);
2270
- await plugin.serverNode?.setStateOf(BasicInformationServer, { reachable: false });
2271
- }, 60000).unref();
2272
- */
2273
1625
  plugin.serverNode.eventsOf(BasicInformationServer).reachable$Changed?.on((reachable) => {
2274
1626
  this.log.info(`Accessory endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) is ${reachable ? 'reachable' : 'unreachable'}`);
2275
1627
  this.frontend.wssSendAttributeChangedMessage(device.plugin, device.serialNumber, device.uniqueId, 'BasicInformationServer', 'reachable', reachable);
@@ -2282,12 +1634,6 @@ export class Matterbridge extends EventEmitter {
2282
1634
  });
2283
1635
  }
2284
1636
  }
2285
- /**
2286
- * Sanitizes the fabric information by converting bigint properties to strings because `res.json` doesn't support bigint.
2287
- *
2288
- * @param {ExposedFabricInformation[]} fabricInfo - The array of exposed fabric information objects.
2289
- * @returns {SanitizedExposedFabricInformation[]} An array of sanitized exposed fabric information objects.
2290
- */
2291
1637
  sanitizeFabricInformations(fabricInfo) {
2292
1638
  return fabricInfo.map((info) => {
2293
1639
  return {
@@ -2301,12 +1647,6 @@ export class Matterbridge extends EventEmitter {
2301
1647
  };
2302
1648
  });
2303
1649
  }
2304
- /**
2305
- * Sanitizes the session information by converting bigint properties to strings because `res.json` doesn't support bigint.
2306
- *
2307
- * @param {SessionInformation[]} sessionInfo - The array of session information objects.
2308
- * @returns {SanitizedSessionInformation[]} An array of sanitized session information objects.
2309
- */
2310
1650
  sanitizeSessionInformation(sessionInfo) {
2311
1651
  return sessionInfo
2312
1652
  .filter((session) => session.isPeerActive)
@@ -2334,20 +1674,7 @@ export class Matterbridge extends EventEmitter {
2334
1674
  };
2335
1675
  });
2336
1676
  }
2337
- /**
2338
- * Sets the reachability of the specified aggregator node bridged devices and trigger.
2339
- * @param {EndpointNode<AggregatorEndpoint>} aggregatorNode - The aggregator node to set the reachability for.
2340
- * @param {boolean} reachable - A boolean indicating the reachability status to set.
2341
- */
2342
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2343
1677
  async setAggregatorReachability(aggregatorNode, reachable) {
2344
- /*
2345
- for (const child of aggregatorNode.parts) {
2346
- this.log.debug(`Setting reachability of ${(child as unknown as MatterbridgeEndpoint)?.deviceName} to ${reachable}`);
2347
- await child.setStateOf(BridgedDeviceBasicInformationServer, { reachable });
2348
- child.act((agent) => child.eventsOf(BridgedDeviceBasicInformationServer).reachableChanged.emit({ reachableNewValue: true }, agent.context));
2349
- }
2350
- */
2351
1678
  }
2352
1679
  getVendorIdName = (vendorId) => {
2353
1680
  if (!vendorId)
@@ -2387,37 +1714,14 @@ export class Matterbridge extends EventEmitter {
2387
1714
  }
2388
1715
  return vendorName;
2389
1716
  };
2390
- /**
2391
- * Spawns a child process with the given command and arguments.
2392
- * @param {string} command - The command to execute.
2393
- * @param {string[]} args - The arguments to pass to the command (default: []).
2394
- * @returns {Promise<boolean>} A promise that resolves when the child process exits successfully, or rejects if there is an error.
2395
- */
2396
1717
  async spawnCommand(command, args = []) {
2397
1718
  const { spawn } = await import('node:child_process');
2398
- /*
2399
- npm > npm.cmd on windows
2400
- cmd.exe ['dir'] on windows
2401
- await this.spawnCommand('npm', ['install', '-g', 'matterbridge']);
2402
- process.on('unhandledRejection', (reason, promise) => {
2403
- this.log.error('Unhandled Rejection at:', promise, 'reason:', reason);
2404
- });
2405
-
2406
- spawn - [14:27:21.125] [Matterbridge:spawn]: changed 38 packages in 4s
2407
- spawn - [14:27:21.125] [Matterbridge:spawn]: 10 packages are looking for funding run `npm fund` for details
2408
- debug - [14:27:21.131] [Matterbridge]: Child process exited with code 0 and signal null
2409
- debug - [14:27:21.131] [Matterbridge]: Child process stdio streams have closed with code 0
2410
- */
2411
1719
  const cmdLine = command + ' ' + args.join(' ');
2412
1720
  if (process.platform === 'win32' && command === 'npm') {
2413
- // Must be spawn('cmd.exe', ['/c', 'npm -g install <package>']);
2414
1721
  const argstring = 'npm ' + args.join(' ');
2415
1722
  args.splice(0, args.length, '/c', argstring);
2416
1723
  command = 'cmd.exe';
2417
1724
  }
2418
- // Decide when using sudo on linux
2419
- // When you need sudo: Spawn stderr: npm error Error: EACCES: permission denied
2420
- // When you don't need sudo: Failed to start child process "npm install -g matterbridge-eve-door": spawn sudo ENOENT
2421
1725
  if (hasParameter('sudo') || (process.platform === 'linux' && command === 'npm' && !hasParameter('docker') && !hasParameter('nosudo'))) {
2422
1726
  args.unshift(command);
2423
1727
  command = 'sudo';
@@ -2476,4 +1780,3 @@ export class Matterbridge extends EventEmitter {
2476
1780
  });
2477
1781
  }
2478
1782
  }
2479
- //# sourceMappingURL=matterbridge.js.map