matterbridge 3.0.8-dev-20250622-9a6255a → 3.0.8-dev-20250625-61b3769
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.
- package/CHANGELOG.md +4 -2
- package/README-DEV.md +27 -11
- package/README.md +11 -11
- package/dist/frontend.js +1 -1
- package/dist/matterbridge.js +83 -12
- package/dist/matterbridgeEndpoint.js +3 -2
- package/dist/pluginManager.js +11 -1
- package/npm-shrinkwrap.json +9 -8
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -16,7 +16,7 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
16
16
|
|
|
17
17
|
- [DevContainer]: Added support for the **Matterbridge Dev Container** with an optimized named volume for `node_modules`.
|
|
18
18
|
- [GitHub]: Added GitHub issue templates for bug reports and feature requests.
|
|
19
|
-
- [Systemd]: Added a systemd service file for Matterbridge.
|
|
19
|
+
- [Systemd]: Added a systemd service file for Matterbridge in the systemd directory.
|
|
20
20
|
- [ESLint]: Refactored ESLint configuration for TypeScript and improved plugin integration.
|
|
21
21
|
- [ESLint]: Added the plugins `eslint-plugin-promise`, `eslint-plugin-jsdoc`, and `@vitest/eslint-plugin`.
|
|
22
22
|
- [Vitest]: Added Vitest for TypeScript project testing. It will replace Jest, which does not work correctly with ESM module mocks.
|
|
@@ -24,8 +24,10 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
24
24
|
|
|
25
25
|
### Changed
|
|
26
26
|
|
|
27
|
-
- [package]: Updated
|
|
27
|
+
- [package]: Updated package to Automator v. 2.0.0.
|
|
28
|
+
- [package]: Updated dependencies.
|
|
28
29
|
- [storage]: Bumped `node-storage-manager` to 2.0.0.
|
|
30
|
+
- [logger]: Bumped `node-ansi-logger` to 3.1.1.
|
|
29
31
|
|
|
30
32
|
### Fixed
|
|
31
33
|
|
package/README-DEV.md
CHANGED
|
@@ -18,13 +18,13 @@
|
|
|
18
18
|
|
|
19
19
|
The easiest way is to clone the [Matterbridge Plugin Template](https://github.com/Luligu/matterbridge-plugin-template) that has **Dev Container support for instant development environment** and all tools and extensions (like Node.js, npm, TypeScript, ESLint, Prettier, Jest and Vitest) already loaded and configured.
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
After you clone it locally, change the name (keep always matterbridge- at the beginning of the name), version, description, author, homepage, repository, bugs and funding in the package.json.
|
|
22
22
|
|
|
23
|
-
It is possible to add two custom properties to the package.json: **help** and **changelog** with a url that will be used in the frontend instead of the default (/blob/main/README.md and /blob/main/CHANGELOG.md).
|
|
23
|
+
It is also possible to add two custom properties to the package.json: **help** and **changelog** with a url that will be used in the frontend instead of the default (/blob/main/README.md and /blob/main/CHANGELOG.md).
|
|
24
24
|
|
|
25
25
|
Add your plugin logic in module.ts.
|
|
26
26
|
|
|
27
|
-
The Matterbridge Plugin Template has an already configured Jest / Vitest test unit (
|
|
27
|
+
The Matterbridge Plugin Template has an already configured Jest / Vitest test unit (with 100% coverage) that you can expand while you add your own plugin logic.
|
|
28
28
|
|
|
29
29
|
It also has a workflow configured to run on push and pull request that build, lint and test the plugin on node 20, 22 and 24 with ubuntu, macOS and windows.
|
|
30
30
|
|
|
@@ -80,13 +80,13 @@ Matterbridge exports from:
|
|
|
80
80
|
|
|
81
81
|
- All matter.js types.
|
|
82
82
|
|
|
83
|
-
### WARNING \***\*\*\*\*\***
|
|
83
|
+
### \***\*\*\*\*\*** WARNING \***\*\*\*\*\***
|
|
84
84
|
|
|
85
85
|
A plugin must never install or import from `@matter` or `@project-chip` directly (neither as a dependency, devDependency, nor peerDependency), as this leads to a second instance of `matter.js`, causing instability and unpredictable errors such as "The only instance is Endpoint".
|
|
86
86
|
|
|
87
87
|
Additionally, when Matterbridge updates the `matter.js` version, it should be consistent across all plugins.
|
|
88
88
|
|
|
89
|
-
### WARNING \***\*\*\*\*\***
|
|
89
|
+
### \***\*\*\*\*\*** WARNING \***\*\*\*\*\***
|
|
90
90
|
|
|
91
91
|
A plugin must never install Matterbridge (neither as a dependency, devDependency, nor peerDependency).
|
|
92
92
|
|
|
@@ -100,9 +100,25 @@ Matterbridge must be linked to the plugin in development only. At runtime the pl
|
|
|
100
100
|
}
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
-
If you don't use Dev Container from the Matterbridge Plugin Template, on the
|
|
103
|
+
If you don't use Dev Container from the Matterbridge Plugin Template, on the host you use for the development of your plugin, you need to clone matterbridge, built it locally and link it globally (npm link from the matterbridge package root).
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
git clone https://github.com/Luligu/matterbridge.git
|
|
107
|
+
cd matterbridge
|
|
108
|
+
npm install
|
|
109
|
+
npm run build
|
|
110
|
+
npm link
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
If you want to develop a plugin using the dev branch of matterbridge (I suggest you do it).
|
|
104
114
|
|
|
105
|
-
|
|
115
|
+
```bash
|
|
116
|
+
git clone -b dev https://github.com/Luligu/matterbridge.git
|
|
117
|
+
cd matterbridge
|
|
118
|
+
npm install
|
|
119
|
+
npm run build
|
|
120
|
+
npm link
|
|
121
|
+
```
|
|
106
122
|
|
|
107
123
|
Always keep your local instance of matterbridge up to date.
|
|
108
124
|
|
|
@@ -116,19 +132,19 @@ To install i.e. https://github.com/Luligu/matterbridge-example-accessory-platfor
|
|
|
116
132
|
|
|
117
133
|
On windows:
|
|
118
134
|
|
|
119
|
-
```
|
|
135
|
+
```powershell
|
|
120
136
|
cd $HOME\Matterbridge
|
|
121
137
|
```
|
|
122
138
|
|
|
123
139
|
On linux or macOS:
|
|
124
140
|
|
|
125
|
-
```
|
|
141
|
+
```bash
|
|
126
142
|
cd ~/Matterbridge
|
|
127
143
|
```
|
|
128
144
|
|
|
129
145
|
then clone the plugin
|
|
130
146
|
|
|
131
|
-
```
|
|
147
|
+
```bash
|
|
132
148
|
git clone https://github.com/Luligu/matterbridge-example-accessory-platform
|
|
133
149
|
cd matterbridge-example-accessory-platform
|
|
134
150
|
npm install
|
|
@@ -138,7 +154,7 @@ npm run build
|
|
|
138
154
|
|
|
139
155
|
then add the plugin to Matterbridge
|
|
140
156
|
|
|
141
|
-
```
|
|
157
|
+
```bash
|
|
142
158
|
matterbridge -add .
|
|
143
159
|
```
|
|
144
160
|
|
package/README.md
CHANGED
|
@@ -15,25 +15,25 @@
|
|
|
15
15
|
|
|
16
16
|
Matterbridge is a Matter plugin manager.
|
|
17
17
|
|
|
18
|
-
It allows you to have all your Matter devices up and running in a couple of minutes without
|
|
19
|
-
having to deal with the pairing process of each single device.
|
|
18
|
+
It allows you to have all your Matter devices up and running in a couple of minutes without having to deal with the pairing process for each individual device.
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
Developers can focus solely on device development by extending the provided classes.
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
Simply pair Matterbridge once, and it will load all your registered plugins.
|
|
24
23
|
|
|
25
|
-
This project aims to
|
|
24
|
+
This project aims to enable porting Homebridge plugins to Matterbridge plugins without having to recode everything ([Development](README-DEV.md)).
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
The easiest way to start create a new plugin is to clone the [Matterbridge Plugin Template](https://github.com/Luligu/matterbridge-plugin-template) which has **Dev Container support for instant development environment** and all tools and extensions (like Node.js, npm, TypeScript, ESLint, Prettier, Jest and Vitest) already loaded and configured.
|
|
27
|
+
|
|
28
|
+
Matterbridge creates a device that can be paired with any ecosystem, such as Apple Home, Google Home, Amazon Alexa, Home Assistant, or any other platform supporting Matter.
|
|
29
29
|
|
|
30
30
|
You don't need a hub or a dedicated new machine.
|
|
31
31
|
|
|
32
|
-
No complex setup just copy paste the installation scripts.
|
|
32
|
+
No complex setup: just copy paste the installation scripts.
|
|
33
33
|
|
|
34
|
-
Matterbridge is
|
|
34
|
+
Matterbridge is lightweight and also runs on slow Linux machines with as little as 512MB of memory.
|
|
35
35
|
|
|
36
|
-
It runs perfectly on macOS and Windows
|
|
36
|
+
It also runs perfectly on macOS and Windows.
|
|
37
37
|
|
|
38
38
|
If you like this project and find it useful, please consider giving it a star on GitHub at https://github.com/Luligu/matterbridge and sponsoring it.
|
|
39
39
|
|
|
@@ -45,7 +45,7 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
45
45
|
|
|
46
46
|
The project is build on top of https://github.com/project-chip/matter.js.
|
|
47
47
|
|
|
48
|
-
A special
|
|
48
|
+
A special thanks to Apollon77 for his incredible work.
|
|
49
49
|
|
|
50
50
|
## Discord
|
|
51
51
|
|
package/dist/frontend.js
CHANGED
|
@@ -769,7 +769,7 @@ export class Frontend {
|
|
|
769
769
|
this.matterbridge.devices.forEach(async (device) => {
|
|
770
770
|
if (pluginName && pluginName !== device.plugin)
|
|
771
771
|
return;
|
|
772
|
-
if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
|
|
772
|
+
if (!device.plugin || !device.deviceType || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
|
|
773
773
|
return;
|
|
774
774
|
const cluster = this.getClusterTextFromDevice(device);
|
|
775
775
|
devices.push({
|
package/dist/matterbridge.js
CHANGED
|
@@ -198,12 +198,18 @@ export class Matterbridge extends EventEmitter {
|
|
|
198
198
|
if (this.serverNode)
|
|
199
199
|
servers.push(this.serverNode);
|
|
200
200
|
}
|
|
201
|
-
if (this.bridgeMode === 'childbridge') {
|
|
201
|
+
if (this.bridgeMode === 'childbridge' && this.plugins !== undefined) {
|
|
202
202
|
for (const plugin of this.plugins.array()) {
|
|
203
203
|
if (plugin.serverNode)
|
|
204
204
|
servers.push(plugin.serverNode);
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
|
+
if (this.devices !== undefined) {
|
|
208
|
+
for (const device of this.devices.array()) {
|
|
209
|
+
if (device.serverMode === 'server' && device.serverNode)
|
|
210
|
+
servers.push(device.serverNode);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
207
213
|
await Promise.resolve();
|
|
208
214
|
await this.cleanup('destroying instance...', false);
|
|
209
215
|
this.log.info(`Dispose ${servers.length} MdnsService...`);
|
|
@@ -1075,6 +1081,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
1075
1081
|
}
|
|
1076
1082
|
}
|
|
1077
1083
|
}
|
|
1084
|
+
for (const device of this.devices.array()) {
|
|
1085
|
+
if (device.serverMode === 'server' && device.serverNode) {
|
|
1086
|
+
await this.stopServerNode(device.serverNode);
|
|
1087
|
+
device.serverNode = undefined;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1078
1090
|
this.log.notice('Stopped matter server nodes');
|
|
1079
1091
|
if (message === 'shutting down with reset...') {
|
|
1080
1092
|
this.log.info('Resetting Matterbridge commissioning information...');
|
|
@@ -1168,8 +1180,18 @@ export class Matterbridge extends EventEmitter {
|
|
|
1168
1180
|
this.log.debug('Cleanup already started...');
|
|
1169
1181
|
}
|
|
1170
1182
|
}
|
|
1183
|
+
async createDeviceServerNode(plugin, device) {
|
|
1184
|
+
if (device.serverMode === 'server' && !device.serverNode && device.deviceType && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
|
|
1185
|
+
this.log.debug(`Creating device ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} server node...`);
|
|
1186
|
+
const storageContext = await this.createServerNodeContext(device.deviceName.replace(/[ .]/g, ''), device.deviceName, DeviceTypeId(device.deviceType), device.vendorId, device.vendorName, device.productId, device.productName);
|
|
1187
|
+
device.serverNode = await this.createServerNode(storageContext, this.port ? this.port++ : undefined, this.passcode ? this.passcode++ : undefined, this.discriminator ? this.discriminator++ : undefined);
|
|
1188
|
+
this.log.debug(`Adding ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to server node...`);
|
|
1189
|
+
await device.serverNode.add(device);
|
|
1190
|
+
this.log.debug(`Added ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to server node`);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1171
1193
|
async createAccessoryPlugin(plugin, device, start = false) {
|
|
1172
|
-
if (!plugin.locked && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
|
|
1194
|
+
if (!plugin.locked && device.deviceType && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
|
|
1173
1195
|
plugin.locked = true;
|
|
1174
1196
|
plugin.device = device;
|
|
1175
1197
|
plugin.storageContext = await this.createServerNodeContext(plugin.name, device.deviceName, DeviceTypeId(device.deviceType), device.vendorId, device.vendorName, device.productId, device.productName);
|
|
@@ -1233,6 +1255,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
1233
1255
|
this.startMatterInterval = undefined;
|
|
1234
1256
|
this.log.debug('Cleared startMatterInterval interval for Matterbridge');
|
|
1235
1257
|
this.startServerNode(this.serverNode);
|
|
1258
|
+
for (const device of this.devices.array()) {
|
|
1259
|
+
if (device.serverMode === 'server' && device.serverNode) {
|
|
1260
|
+
this.log.debug(`Starting server node for device ${dev}${device.deviceName}${db} in server mode...`);
|
|
1261
|
+
await this.startServerNode(device.serverNode);
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1236
1264
|
this.configureTimeout = setTimeout(async () => {
|
|
1237
1265
|
for (const plugin of this.plugins) {
|
|
1238
1266
|
if (!plugin.enabled || !plugin.loaded || !plugin.started || plugin.error)
|
|
@@ -1312,7 +1340,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1312
1340
|
}
|
|
1313
1341
|
this.frontend.wssSendRefreshRequired('plugins');
|
|
1314
1342
|
}, 30 * 1000);
|
|
1315
|
-
for (const plugin of this.plugins) {
|
|
1343
|
+
for (const plugin of this.plugins.array()) {
|
|
1316
1344
|
if (!plugin.enabled || plugin.error)
|
|
1317
1345
|
continue;
|
|
1318
1346
|
if (plugin.type !== 'DynamicPlatform' && (!plugin.addedDevices || plugin.addedDevices === 0)) {
|
|
@@ -1339,6 +1367,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
1339
1367
|
this.frontend.wssSendRefreshRequired('reachability');
|
|
1340
1368
|
}, 60 * 1000);
|
|
1341
1369
|
}
|
|
1370
|
+
for (const device of this.devices.array()) {
|
|
1371
|
+
if (device.serverMode === 'server' && device.serverNode) {
|
|
1372
|
+
this.log.debug(`***Starting server node for device ${plg}${device.deviceName}${db} in server mode...`);
|
|
1373
|
+
await this.startServerNode(device.serverNode);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1342
1376
|
}, 1000);
|
|
1343
1377
|
}
|
|
1344
1378
|
async startController() {
|
|
@@ -1668,22 +1702,52 @@ export class Matterbridge extends EventEmitter {
|
|
|
1668
1702
|
this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) plugin ${plg}${pluginName}${er} not found`);
|
|
1669
1703
|
return;
|
|
1670
1704
|
}
|
|
1671
|
-
if (
|
|
1672
|
-
this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
|
|
1673
|
-
if (!this.aggregatorNode) {
|
|
1674
|
-
this.log.error('Aggregator node not found for Matterbridge');
|
|
1675
|
-
return;
|
|
1676
|
-
}
|
|
1705
|
+
if (device.serverMode === 'server') {
|
|
1677
1706
|
try {
|
|
1678
|
-
|
|
1707
|
+
this.log.debug(`Creating server node for device ${dev}${device.deviceName}${db} of plugin ${plg}${plugin.name}${db}...`);
|
|
1708
|
+
await this.createDeviceServerNode(plugin, device);
|
|
1679
1709
|
}
|
|
1680
1710
|
catch (error) {
|
|
1681
1711
|
const errorMessage = error instanceof Error ? error.message : error;
|
|
1682
1712
|
const errorInspect = inspect(error, { depth: 10 });
|
|
1683
|
-
this.log.error(`Error
|
|
1713
|
+
this.log.error(`Error creating server node for device ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) of plugin ${plg}${pluginName}${er}: ${errorMessage}\nstack: ${errorInspect}`);
|
|
1684
1714
|
return;
|
|
1685
1715
|
}
|
|
1686
1716
|
}
|
|
1717
|
+
else if (this.bridgeMode === 'bridge') {
|
|
1718
|
+
if (device.serverMode === 'matter') {
|
|
1719
|
+
this.log.debug(`Adding matter endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge server node...`);
|
|
1720
|
+
if (!this.serverNode) {
|
|
1721
|
+
this.log.error('Server node not found for Matterbridge');
|
|
1722
|
+
return;
|
|
1723
|
+
}
|
|
1724
|
+
try {
|
|
1725
|
+
await this.serverNode.add(device);
|
|
1726
|
+
}
|
|
1727
|
+
catch (error) {
|
|
1728
|
+
const errorMessage = error instanceof Error ? error.message : error;
|
|
1729
|
+
const errorInspect = inspect(error, { depth: 10 });
|
|
1730
|
+
this.log.error(`Error adding matter endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) for plugin ${plg}${pluginName}${er}: ${errorMessage}\nstack: ${errorInspect}`);
|
|
1731
|
+
return;
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
else {
|
|
1735
|
+
this.log.debug(`Adding bridged endpoint ${plg}${pluginName}${db}:${dev}${device.deviceName}${db} to Matterbridge aggregator node`);
|
|
1736
|
+
if (!this.aggregatorNode) {
|
|
1737
|
+
this.log.error('Aggregator node not found for Matterbridge');
|
|
1738
|
+
return;
|
|
1739
|
+
}
|
|
1740
|
+
try {
|
|
1741
|
+
await this.aggregatorNode.add(device);
|
|
1742
|
+
}
|
|
1743
|
+
catch (error) {
|
|
1744
|
+
const errorMessage = error instanceof Error ? error.message : error;
|
|
1745
|
+
const errorInspect = inspect(error, { depth: 10 });
|
|
1746
|
+
this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) for plugin ${plg}${pluginName}${er}: ${errorMessage}\nstack: ${errorInspect}`);
|
|
1747
|
+
return;
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1687
1751
|
else if (this.bridgeMode === 'childbridge') {
|
|
1688
1752
|
if (plugin.type === 'AccessoryPlatform') {
|
|
1689
1753
|
try {
|
|
@@ -1706,11 +1770,18 @@ export class Matterbridge extends EventEmitter {
|
|
|
1706
1770
|
this.log.debug(`Adding bridged endpoint ${dev}${device.deviceName}${db} for DynamicPlatform plugin ${plg}${plugin.name}${db} aggregator node`);
|
|
1707
1771
|
await this.createDynamicPlugin(plugin);
|
|
1708
1772
|
await waiter(`createDynamicPlugin(${plugin.name})`, () => plugin.serverNode?.hasParts === true);
|
|
1773
|
+
if (!plugin.serverNode) {
|
|
1774
|
+
this.log.error(`Server node not found for plugin ${plg}${plugin.name}${er}`);
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1709
1777
|
if (!plugin.aggregatorNode) {
|
|
1710
1778
|
this.log.error(`Aggregator node not found for plugin ${plg}${plugin.name}${er}`);
|
|
1711
1779
|
return;
|
|
1712
1780
|
}
|
|
1713
|
-
|
|
1781
|
+
if (device.serverMode === 'matter')
|
|
1782
|
+
await plugin.serverNode.add(device);
|
|
1783
|
+
else
|
|
1784
|
+
await plugin.aggregatorNode.add(device);
|
|
1714
1785
|
}
|
|
1715
1786
|
catch (error) {
|
|
1716
1787
|
const errorMessage = error instanceof Error ? error.message : error;
|
|
@@ -68,6 +68,8 @@ import { addClusterServers, addFixedLabel, addOptionalClusterServers, addRequire
|
|
|
68
68
|
export class MatterbridgeEndpoint extends Endpoint {
|
|
69
69
|
static bridgeMode = '';
|
|
70
70
|
static logLevel = "info";
|
|
71
|
+
serverMode = undefined;
|
|
72
|
+
serverNode;
|
|
71
73
|
log;
|
|
72
74
|
plugin = undefined;
|
|
73
75
|
configUrl = undefined;
|
|
@@ -83,9 +85,8 @@ export class MatterbridgeEndpoint extends Endpoint {
|
|
|
83
85
|
hardwareVersion = undefined;
|
|
84
86
|
hardwareVersionString = undefined;
|
|
85
87
|
productUrl = 'https://www.npmjs.com/package/matterbridge';
|
|
86
|
-
serverNode;
|
|
87
88
|
name = undefined;
|
|
88
|
-
deviceType;
|
|
89
|
+
deviceType = undefined;
|
|
89
90
|
uniqueStorageKey = undefined;
|
|
90
91
|
tagList = undefined;
|
|
91
92
|
deviceTypes = new Map();
|
package/dist/pluginManager.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import EventEmitter from 'node:events';
|
|
1
2
|
import { AnsiLogger, UNDERLINE, UNDERLINEOFF, BLUE, db, er, nf, nt, rs, wr } from 'node-ansi-logger';
|
|
2
3
|
import { plg, typ } from './matterbridgeTypes.js';
|
|
3
|
-
export class PluginManager {
|
|
4
|
+
export class PluginManager extends EventEmitter {
|
|
4
5
|
_plugins = new Map();
|
|
5
6
|
nodeContext;
|
|
6
7
|
matterbridge;
|
|
7
8
|
log;
|
|
8
9
|
constructor(matterbridge) {
|
|
10
|
+
super();
|
|
9
11
|
this.matterbridge = matterbridge;
|
|
10
12
|
this.nodeContext = matterbridge.nodeContext;
|
|
11
13
|
this.log = new AnsiLogger({ logName: 'PluginManager', logTimestampFormat: 4, logLevel: matterbridge.log.logLevel });
|
|
@@ -319,6 +321,7 @@ export class PluginManager {
|
|
|
319
321
|
plugin.enabled = true;
|
|
320
322
|
this.log.info(`Enabled plugin ${plg}${plugin.name}${nf}`);
|
|
321
323
|
await this.saveToStorage();
|
|
324
|
+
this.emit('enabled', plugin.name);
|
|
322
325
|
return plugin;
|
|
323
326
|
}
|
|
324
327
|
catch (err) {
|
|
@@ -352,6 +355,7 @@ export class PluginManager {
|
|
|
352
355
|
plugin.enabled = false;
|
|
353
356
|
this.log.info(`Disabled plugin ${plg}${plugin.name}${nf}`);
|
|
354
357
|
await this.saveToStorage();
|
|
358
|
+
this.emit('disabled', plugin.name);
|
|
355
359
|
return plugin;
|
|
356
360
|
}
|
|
357
361
|
catch (err) {
|
|
@@ -385,6 +389,7 @@ export class PluginManager {
|
|
|
385
389
|
this._plugins.delete(packageJson.name);
|
|
386
390
|
this.log.info(`Removed plugin ${plg}${plugin.name}${nf}`);
|
|
387
391
|
await this.saveToStorage();
|
|
392
|
+
this.emit('removed', plugin.name);
|
|
388
393
|
return plugin;
|
|
389
394
|
}
|
|
390
395
|
catch (err) {
|
|
@@ -419,6 +424,7 @@ export class PluginManager {
|
|
|
419
424
|
this.log.info(`Added plugin ${plg}${packageJson.name}${nf}`);
|
|
420
425
|
await this.saveToStorage();
|
|
421
426
|
const plugin = this._plugins.get(packageJson.name);
|
|
427
|
+
this.emit('added', packageJson.name);
|
|
422
428
|
return plugin || null;
|
|
423
429
|
}
|
|
424
430
|
catch (err) {
|
|
@@ -529,6 +535,7 @@ export class PluginManager {
|
|
|
529
535
|
plugin.addedDevices = 0;
|
|
530
536
|
await this.saveToStorage();
|
|
531
537
|
this.log.notice(`Loaded plugin ${plg}${plugin.name}${nt} type ${typ}${platform.type}${nt} (entrypoint ${UNDERLINE}${pluginEntry}${UNDERLINEOFF})`);
|
|
538
|
+
this.emit('loaded', plugin.name);
|
|
532
539
|
if (start)
|
|
533
540
|
await this.start(plugin, message, false);
|
|
534
541
|
if (configure)
|
|
@@ -565,6 +572,7 @@ export class PluginManager {
|
|
|
565
572
|
this.log.notice(`Started plugin ${plg}${plugin.name}${nt} type ${typ}${plugin.type}${nt}`);
|
|
566
573
|
plugin.started = true;
|
|
567
574
|
await this.saveConfigFromPlugin(plugin);
|
|
575
|
+
this.emit('started', plugin.name);
|
|
568
576
|
if (configure)
|
|
569
577
|
await this.configure(plugin);
|
|
570
578
|
return plugin;
|
|
@@ -597,6 +605,7 @@ export class PluginManager {
|
|
|
597
605
|
await plugin.platform.onConfigure();
|
|
598
606
|
this.log.notice(`Configured plugin ${plg}${plugin.name}${nt} type ${typ}${plugin.type}${nt}`);
|
|
599
607
|
plugin.configured = true;
|
|
608
|
+
this.emit('configured', plugin.name);
|
|
600
609
|
return plugin;
|
|
601
610
|
}
|
|
602
611
|
catch (err) {
|
|
@@ -640,6 +649,7 @@ export class PluginManager {
|
|
|
640
649
|
plugin.registeredDevices = undefined;
|
|
641
650
|
plugin.addedDevices = undefined;
|
|
642
651
|
this.log.notice(`Shutdown of plugin ${plg}${plugin.name}${nt} completed`);
|
|
652
|
+
this.emit('shutdown', plugin.name);
|
|
643
653
|
return plugin;
|
|
644
654
|
}
|
|
645
655
|
catch (err) {
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge",
|
|
3
|
-
"version": "3.0.8-dev-
|
|
3
|
+
"version": "3.0.8-dev-20250625-61b3769",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "matterbridge",
|
|
9
|
-
"version": "3.0.8-dev-
|
|
9
|
+
"version": "3.0.8-dev-20250625-61b3769",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@matter/main": "0.14.0",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"express": "5.1.0",
|
|
15
15
|
"glob": "11.0.3",
|
|
16
16
|
"multer": "2.0.1",
|
|
17
|
-
"node-ansi-logger": "3.
|
|
17
|
+
"node-ansi-logger": "3.1.1",
|
|
18
18
|
"node-persist-manager": "2.0.0",
|
|
19
19
|
"ws": "8.18.2"
|
|
20
20
|
},
|
|
@@ -1349,12 +1349,13 @@
|
|
|
1349
1349
|
}
|
|
1350
1350
|
},
|
|
1351
1351
|
"node_modules/node-ansi-logger": {
|
|
1352
|
-
"version": "3.
|
|
1353
|
-
"resolved": "https://registry.npmjs.org/node-ansi-logger/-/node-ansi-logger-3.
|
|
1354
|
-
"integrity": "sha512-
|
|
1355
|
-
"
|
|
1352
|
+
"version": "3.1.1",
|
|
1353
|
+
"resolved": "https://registry.npmjs.org/node-ansi-logger/-/node-ansi-logger-3.1.1.tgz",
|
|
1354
|
+
"integrity": "sha512-tFeCSxwiRg5XaNda5nC27alzraZP76nLtUk1JDZqb9byhW4WYaSGL7/lmxFHEI16gypQDMEYljuF+wcG+cPPHw==",
|
|
1355
|
+
"hasShrinkwrap": true,
|
|
1356
|
+
"license": "Apache-2.0",
|
|
1356
1357
|
"engines": {
|
|
1357
|
-
"node": ">=18.0.0"
|
|
1358
|
+
"node": ">=18.0.0 <19.0.0 || >=20.0.0 <21.0.0 || >=22.0.0 <23.0.0 || >=24.0.0 <25.0.0"
|
|
1358
1359
|
},
|
|
1359
1360
|
"funding": {
|
|
1360
1361
|
"type": "buymeacoffee",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge",
|
|
3
|
-
"version": "3.0.8-dev-
|
|
3
|
+
"version": "3.0.8-dev-20250625-61b3769",
|
|
4
4
|
"description": "Matterbridge plugin manager for Matter",
|
|
5
5
|
"author": "https://github.com/Luligu",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
"express": "5.1.0",
|
|
104
104
|
"glob": "11.0.3",
|
|
105
105
|
"multer": "2.0.1",
|
|
106
|
-
"node-ansi-logger": "3.
|
|
106
|
+
"node-ansi-logger": "3.1.1",
|
|
107
107
|
"node-persist-manager": "2.0.0",
|
|
108
108
|
"ws": "8.18.2"
|
|
109
109
|
}
|