matterbridge 3.0.0-edge.1 → 3.0.0-edge.11
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 +54 -3
- package/README-DEV.md +4 -0
- package/README-DOCKER.md +9 -0
- package/dist/cli.js +4 -1
- package/dist/frontend.js +3 -3
- package/dist/matterbridge.js +50 -19
- package/dist/matterbridgeBehaviors.js +31 -31
- package/dist/matterbridgeDeviceTypes.js +121 -20
- package/dist/matterbridgeEndpoint.js +56 -48
- package/dist/matterbridgePlatform.js +2 -2
- package/dist/pluginManager.js +8 -2
- package/frontend/build/asset-manifest.json +3 -3
- package/frontend/build/index.html +1 -1
- package/frontend/build/static/js/{main.1fa50342.js → main.eb438c68.js} +3 -3
- package/frontend/build/static/js/{main.1fa50342.js.map → main.eb438c68.js.map} +1 -1
- package/npm-shrinkwrap.json +296 -365
- package/package.json +3 -4
- package/tsconfig.jest.json +8 -0
- /package/frontend/build/static/js/{main.1fa50342.js.LICENSE.txt → main.eb438c68.js.LICENSE.txt} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -47,26 +47,77 @@ Modified clusters:
|
|
|
47
47
|
### Added
|
|
48
48
|
|
|
49
49
|
- [addEndpoint]: Added an error handler with deep stack on aggregatorNode.add() and serverNode.add() calls.
|
|
50
|
+
- [endpoint]: Added createOffOnlyOnOffClusterServer().
|
|
51
|
+
- [endpoint]: Added createBaseFanControlClusterServer().
|
|
52
|
+
- [endpoint]: Added createDefaultHepaFilterMonitoringClusterServer().
|
|
53
|
+
- [endpoint]: Added createDefaultActivatedCarbonFilterMonitoringClusterServer().
|
|
54
|
+
- [deviceTypes]: Added Robotic device type.
|
|
55
|
+
- [deviceTypes]: Added Appliances device types.
|
|
56
|
+
- [frontend]: Added the matterbridge aggregator serialNumber in the QRDiv.
|
|
50
57
|
|
|
51
58
|
### Changed
|
|
52
59
|
|
|
53
|
-
- [
|
|
60
|
+
- [package]: Updated package.
|
|
61
|
+
- [package]: Updated express to v5.1.0.
|
|
62
|
+
- [package]: Updated dependencies.
|
|
63
|
+
- [package]: Added tsconfig.jest.json with "isolatedModules": true for ts-jest.
|
|
64
|
+
- [deviceTypes]: Updated device types to Matter 1.4.
|
|
65
|
+
- [clusters]: Updated cluster helpers to Matter 1.4.
|
|
54
66
|
- [matter.js]: Update to 0.13.0-alpha.0-20250405-7fc7db48.
|
|
67
|
+
- [matter.js]: Update to 0.13.0-alpha.0-20250408-c916c7e8.
|
|
68
|
+
- [matter.js]: Update to 0.13.0-alpha.0-20250412-5fad64e7b.
|
|
69
|
+
- [matter.js]: Update to 0.13.0-alpha.0-20250413-d5a27700d.
|
|
70
|
+
- [matter.js]: Update to 0.13.0-alpha.0-20250415-475996bb5.
|
|
71
|
+
- [matter.js]: Update to 0.13.0-alpha.0-20250418-8cfc0b832.
|
|
72
|
+
- [matter.js]: Update to 0.13.0-alpha.0-20250420-9f45e4f77.
|
|
73
|
+
- [help]: Updated cli help screen.
|
|
74
|
+
- [logger]: Improved frontend logger cleaning.
|
|
55
75
|
|
|
56
76
|
### Fixed
|
|
57
77
|
|
|
58
78
|
- [doorLock]: Fixed supportedOperatingModes inverted bitmap (Thanks Apollon).
|
|
79
|
+
- [DevicesIcon]: Fixed rendering of leak freeze and rain sensors.
|
|
80
|
+
- [QRCode]: Fixed rendering of QRCode panel when advertising stops.
|
|
81
|
+
- [matterbridge]: Fixed wrong message when advertising stops and the node has been paired.
|
|
59
82
|
|
|
60
|
-
## [2.2.
|
|
83
|
+
## [2.2.9] - 2025-04-18
|
|
61
84
|
|
|
62
85
|
### Added
|
|
63
86
|
|
|
64
|
-
- [
|
|
87
|
+
- [deviceTypes]: Added extendedColorLight device type.
|
|
88
|
+
|
|
89
|
+
### Changed
|
|
90
|
+
|
|
91
|
+
- [package]: Update dependencies.
|
|
92
|
+
|
|
93
|
+
### Fixed
|
|
94
|
+
|
|
95
|
+
- [QRCode]: Fixed update when the server node is no more advertising.
|
|
96
|
+
- [frontend]: Fixed wrong notification when the server node has been paired.
|
|
97
|
+
|
|
98
|
+
<a href="https://www.buymeacoffee.com/luligugithub">
|
|
99
|
+
<img src="bmc-button.svg" alt="Buy me a coffee" width="80">
|
|
100
|
+
</a>
|
|
101
|
+
|
|
102
|
+
## [2.2.8] - 2025-04-10
|
|
103
|
+
|
|
104
|
+
### Added
|
|
105
|
+
|
|
106
|
+
- [platform]: Added stack to error messages.
|
|
107
|
+
- [endpoint]: Added createLevelControlClusterServer()
|
|
65
108
|
- [endpoint]: Added createLevelTvocMeasurementClusterServer()
|
|
109
|
+
- [frontend]: Added a restart button on the QRCode panel when the advertising for a not paired node is expired.
|
|
66
110
|
|
|
67
111
|
### Changed
|
|
68
112
|
|
|
69
113
|
- [package]: Update dependencies.
|
|
114
|
+
- [package]: Use node:https.
|
|
115
|
+
- [endpoint]: Modified createOnOffClusterServer().
|
|
116
|
+
|
|
117
|
+
### Fixed
|
|
118
|
+
|
|
119
|
+
- [homepage]: Fixed warning log for homepage property in package.json.
|
|
120
|
+
- [DevicesIcon]: Fixed rendering of rain, freeze and leak sensors.
|
|
70
121
|
|
|
71
122
|
<a href="https://www.buymeacoffee.com/luligugithub">
|
|
72
123
|
<img src="bmc-button.svg" alt="Buy me a coffee" width="80">
|
package/README-DEV.md
CHANGED
|
@@ -80,6 +80,10 @@ Matterbridge must be linked to the plugin in development only.
|
|
|
80
80
|
"dev:link": "npm link matterbridge",
|
|
81
81
|
'''
|
|
82
82
|
}
|
|
83
|
+
|
|
84
|
+
On the machine you use for development you should also have matterbridge installed globally or built locally and linked (npm link from the package root).
|
|
85
|
+
|
|
86
|
+
Dev and edge branches of matterbridge are not suitable for developemnt cause they are published for production without types. If you want to develop a plugin using the dev or edge branch of matterbridge, you have to clone the dev or edge branch, build locally and link (npm run deepCleanBuild).
|
|
83
87
|
```
|
|
84
88
|
|
|
85
89
|
# \***\*\*\*\*\***
|
package/README-DOCKER.md
CHANGED
|
@@ -141,6 +141,15 @@ docker restart matterbridge
|
|
|
141
141
|
docker logs matterbridge
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
+
### Shows the logs for a time interval
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
docker logs \
|
|
148
|
+
--since "2025-04-19T00:00:00" \
|
|
149
|
+
--until "2025-04-19T00:02:00" \
|
|
150
|
+
matterbridge
|
|
151
|
+
```
|
|
152
|
+
|
|
144
153
|
### Shows the logs real time (tail)
|
|
145
154
|
|
|
146
155
|
```
|
package/dist/cli.js
CHANGED
|
@@ -3,6 +3,7 @@ import { Matterbridge } from './matterbridge.js';
|
|
|
3
3
|
import { getIntParameter, hasParameter } from './utils/export.js';
|
|
4
4
|
import { AnsiLogger, BRIGHT, CYAN, db, YELLOW } from './logger/export.js';
|
|
5
5
|
import { EventEmitter } from 'node:events';
|
|
6
|
+
import { inspect } from 'node:util';
|
|
6
7
|
export const cliEmitter = new EventEmitter();
|
|
7
8
|
export let instance;
|
|
8
9
|
let session;
|
|
@@ -186,5 +187,7 @@ async function main() {
|
|
|
186
187
|
}
|
|
187
188
|
process.title = 'matterbridge';
|
|
188
189
|
main().catch((error) => {
|
|
189
|
-
|
|
190
|
+
const errorMessage = error instanceof Error ? error.message : error;
|
|
191
|
+
const errorInspect = inspect(error, { depth: 10 });
|
|
192
|
+
log.error(`Matterbridge.loadInstance() failed with error: ${errorMessage}\nstack: ${errorInspect}`);
|
|
190
193
|
});
|
package/dist/frontend.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { EndpointServer, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, Lifecycle } from '@matter/main';
|
|
2
2
|
import { createServer } from 'node:http';
|
|
3
|
+
import https from 'node:https';
|
|
3
4
|
import os from 'node:os';
|
|
4
5
|
import path from 'node:path';
|
|
5
6
|
import { promises as fs } from 'node:fs';
|
|
6
|
-
import https from 'https';
|
|
7
7
|
import express from 'express';
|
|
8
8
|
import WebSocket, { WebSocketServer } from 'ws';
|
|
9
9
|
import multer from 'multer';
|
|
@@ -814,9 +814,8 @@ export class Frontend {
|
|
|
814
814
|
res.status(500).send(`Error uploading or installing plugin package ${filename}`);
|
|
815
815
|
}
|
|
816
816
|
});
|
|
817
|
-
this.expressApp.
|
|
817
|
+
this.expressApp.use((req, res) => {
|
|
818
818
|
this.log.debug('The frontend sent:', req.url);
|
|
819
|
-
this.log.debug('Response send file:', path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
|
|
820
819
|
res.sendFile(path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
|
|
821
820
|
});
|
|
822
821
|
this.log.debug(`Frontend initialized on port ${YELLOW}${this.port}${db} static ${UNDERLINE}${path.join(this.matterbridge.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
|
|
@@ -1503,6 +1502,7 @@ export class Frontend {
|
|
|
1503
1502
|
message = message.replace(/[\t\n]/g, '');
|
|
1504
1503
|
message = message.replace(/[\x00-\x1F\x7F]/g, '');
|
|
1505
1504
|
message = message.replace(/\\"/g, '"');
|
|
1505
|
+
message = message.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
1506
1506
|
const maxContinuousLength = 100;
|
|
1507
1507
|
const keepStartLength = 20;
|
|
1508
1508
|
const keepEndLength = 20;
|
package/dist/matterbridge.js
CHANGED
|
@@ -15,8 +15,8 @@ import { Frontend } from './frontend.js';
|
|
|
15
15
|
import { DeviceTypeId, Endpoint as EndpointNode, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageService, Environment, ServerNode } from '@matter/main';
|
|
16
16
|
import { DeviceCommissioner, FabricAction, MdnsService, PaseClient } from '@matter/main/protocol';
|
|
17
17
|
import { AggregatorEndpoint } from '@matter/main/endpoints';
|
|
18
|
-
import { BridgedDeviceBasicInformationServer } from '@matter/main/behaviors/bridged-device-basic-information';
|
|
19
18
|
import { BasicInformationServer } from '@matter/main/behaviors/basic-information';
|
|
19
|
+
import { BridgedDeviceBasicInformationServer } from '@matter/main/behaviors/bridged-device-basic-information';
|
|
20
20
|
const plg = '\u001B[38;5;33m';
|
|
21
21
|
const dev = '\u001B[38;5;79m';
|
|
22
22
|
const typ = '\u001B[38;5;207m';
|
|
@@ -51,6 +51,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
51
51
|
globalModulesDirectory: '',
|
|
52
52
|
matterbridgeVersion: '',
|
|
53
53
|
matterbridgeLatestVersion: '',
|
|
54
|
+
matterbridgeSerialNumber: '',
|
|
54
55
|
matterbridgeQrPairingCode: undefined,
|
|
55
56
|
matterbridgeManualPairingCode: undefined,
|
|
56
57
|
matterbridgeFabricInformations: [],
|
|
@@ -122,7 +123,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
122
123
|
matterStorageService;
|
|
123
124
|
matterStorageManager;
|
|
124
125
|
matterbridgeContext;
|
|
125
|
-
|
|
126
|
+
controllerContext;
|
|
126
127
|
mdnsInterface;
|
|
127
128
|
ipv4address;
|
|
128
129
|
ipv6address;
|
|
@@ -491,6 +492,13 @@ export class Matterbridge extends EventEmitter {
|
|
|
491
492
|
- nosudo: force not to use sudo to install or update packages if the internal logic fails
|
|
492
493
|
- norestore: force not to automatically restore the matterbridge node storage and the matter storage from backup if it is corrupted
|
|
493
494
|
- ssl: enable SSL for the frontend and WebSockerServer (certificates in .matterbridge/certs directory cert.pem, key.pem and ca.pem (optional))
|
|
495
|
+
- vendorId: override the default vendorId 0xfff1
|
|
496
|
+
- vendorName: override the default vendorName "Matterbridge"
|
|
497
|
+
- productId: override the default productId 0x8000
|
|
498
|
+
- productName: override the default productName "Matterbridge aggregator"
|
|
499
|
+
- service: enable the service mode (used in the systemctl configuration file)
|
|
500
|
+
- docker: enable the docker mode (used in the Dockerfile to build the docker image)
|
|
501
|
+
- homedir: override the home directory (default: os.homedir())
|
|
494
502
|
- add [plugin path]: register the plugin from the given absolute or relative path
|
|
495
503
|
- add [plugin name]: register the globally installed plugin with the given name
|
|
496
504
|
- remove [plugin path]: remove the plugin from the given absolute or relative path
|
|
@@ -687,11 +695,15 @@ export class Matterbridge extends EventEmitter {
|
|
|
687
695
|
process.removeAllListeners('uncaughtException');
|
|
688
696
|
process.removeAllListeners('unhandledRejection');
|
|
689
697
|
this.exceptionHandler = async (error) => {
|
|
690
|
-
|
|
698
|
+
const errorMessage = error instanceof Error ? error.message : error;
|
|
699
|
+
const errorInspect = inspect(error, { depth: 10 });
|
|
700
|
+
this.log.error(`Unhandled Exception detected: ${errorMessage}\nstack: ${errorInspect}}`);
|
|
691
701
|
};
|
|
692
702
|
process.on('uncaughtException', this.exceptionHandler);
|
|
693
703
|
this.rejectionHandler = async (reason, promise) => {
|
|
694
|
-
|
|
704
|
+
const errorMessage = reason instanceof Error ? reason.message : reason;
|
|
705
|
+
const errorInspect = inspect(reason, { depth: 10 });
|
|
706
|
+
this.log.error(`Unhandled Rejection detected: ${promise}\nreason: ${errorMessage}\nstack: ${errorInspect}`);
|
|
695
707
|
};
|
|
696
708
|
process.on('unhandledRejection', this.rejectionHandler);
|
|
697
709
|
this.log.debug(`Registering SIGINT and SIGTERM signal handlers...`);
|
|
@@ -1165,6 +1177,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1165
1177
|
plugin.device = device;
|
|
1166
1178
|
plugin.storageContext = await this.createServerNodeContext(plugin.name, device.deviceName, DeviceTypeId(device.deviceType), device.vendorId, device.vendorName, device.productId, device.productName);
|
|
1167
1179
|
plugin.serverNode = await this.createServerNode(plugin.storageContext, this.port ? this.port++ : undefined, this.passcode ? this.passcode++ : undefined, this.discriminator ? this.discriminator++ : undefined);
|
|
1180
|
+
plugin.serialNumber = await plugin.storageContext.get('serialNumber', '');
|
|
1168
1181
|
this.log.debug(`Adding ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to ${plg}${plugin.name}${db} server node`);
|
|
1169
1182
|
await plugin.serverNode.add(device);
|
|
1170
1183
|
if (start)
|
|
@@ -1177,6 +1190,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1177
1190
|
plugin.storageContext = await this.createServerNodeContext(plugin.name, 'Matterbridge', bridge.code, this.aggregatorVendorId, 'Matterbridge', this.aggregatorProductId, plugin.description);
|
|
1178
1191
|
plugin.serverNode = await this.createServerNode(plugin.storageContext, this.port ? this.port++ : undefined, this.passcode ? this.passcode++ : undefined, this.discriminator ? this.discriminator++ : undefined);
|
|
1179
1192
|
plugin.aggregatorNode = await this.createAggregatorNode(plugin.storageContext);
|
|
1193
|
+
plugin.serialNumber = await plugin.storageContext.get('serialNumber', '');
|
|
1180
1194
|
await plugin.serverNode.add(plugin.aggregatorNode);
|
|
1181
1195
|
if (start)
|
|
1182
1196
|
await this.startServerNode(plugin.serverNode);
|
|
@@ -1337,6 +1351,19 @@ export class Matterbridge extends EventEmitter {
|
|
|
1337
1351
|
}, 1000);
|
|
1338
1352
|
}
|
|
1339
1353
|
async startController() {
|
|
1354
|
+
if (!this.matterStorageManager) {
|
|
1355
|
+
this.log.error('No storage manager initialized');
|
|
1356
|
+
await this.cleanup('No storage manager initialized');
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
this.log.info('Creating context: mattercontrollerContext');
|
|
1360
|
+
this.controllerContext = this.matterStorageManager.createContext('mattercontrollerContext');
|
|
1361
|
+
if (!this.controllerContext) {
|
|
1362
|
+
this.log.error('No storage context mattercontrollerContext initialized');
|
|
1363
|
+
await this.cleanup('No storage context mattercontrollerContext initialized');
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
this.log.debug('Starting matterbridge in mode', this.bridgeMode);
|
|
1340
1367
|
}
|
|
1341
1368
|
async startMatterStorage() {
|
|
1342
1369
|
this.log.info(`Starting matter node storage...`);
|
|
@@ -1345,6 +1372,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1345
1372
|
this.matterStorageManager = await this.matterStorageService.open('Matterbridge');
|
|
1346
1373
|
this.log.info('Matter node storage manager "Matterbridge" created');
|
|
1347
1374
|
this.matterbridgeContext = await this.createServerNodeContext('Matterbridge', 'Matterbridge', bridge.code, this.aggregatorVendorId, this.aggregatorVendorName, this.aggregatorProductId, this.aggregatorProductName);
|
|
1375
|
+
this.matterbridgeInformation.matterbridgeSerialNumber = await this.matterbridgeContext.get('serialNumber', '');
|
|
1348
1376
|
this.log.info('Matter node storage started');
|
|
1349
1377
|
await this.backupMatterStorage(path.join(this.matterbridgeDirectory, this.matterStorageName), path.join(this.matterbridgeDirectory, this.matterStorageName + '.backup'));
|
|
1350
1378
|
}
|
|
@@ -1355,7 +1383,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1355
1383
|
}
|
|
1356
1384
|
async stopMatterStorage() {
|
|
1357
1385
|
this.log.info('Closing matter node storage...');
|
|
1358
|
-
this.matterStorageManager?.close();
|
|
1386
|
+
await this.matterStorageManager?.close();
|
|
1359
1387
|
this.matterStorageService = undefined;
|
|
1360
1388
|
this.matterStorageManager = undefined;
|
|
1361
1389
|
this.matterbridgeContext = undefined;
|
|
@@ -1494,6 +1522,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1494
1522
|
}
|
|
1495
1523
|
}
|
|
1496
1524
|
setTimeout(() => {
|
|
1525
|
+
if (serverNode.lifecycle.isCommissioned)
|
|
1526
|
+
return;
|
|
1497
1527
|
if (this.bridgeMode === 'bridge') {
|
|
1498
1528
|
this.matterbridgeQrPairingCode = undefined;
|
|
1499
1529
|
this.matterbridgeManualPairingCode = undefined;
|
|
@@ -1503,10 +1533,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
1503
1533
|
if (plugin) {
|
|
1504
1534
|
plugin.qrPairingCode = undefined;
|
|
1505
1535
|
plugin.manualPairingCode = undefined;
|
|
1506
|
-
this.frontend.wssSendRefreshRequired('plugins');
|
|
1507
1536
|
}
|
|
1508
1537
|
}
|
|
1538
|
+
this.frontend.wssSendRefreshRequired('plugins');
|
|
1509
1539
|
this.frontend.wssSendRefreshRequired('settings');
|
|
1540
|
+
this.frontend.wssSendRefreshRequired('fabrics');
|
|
1541
|
+
this.frontend.wssSendRefreshRequired('sessions');
|
|
1510
1542
|
this.frontend.wssSendSnackbarMessage(`Advertising on server node for ${storeId} stopped. Restart to commission.`, 0);
|
|
1511
1543
|
this.log.notice(`Advertising on server node for ${storeId} stopped. Restart to commission.`);
|
|
1512
1544
|
}, 15 * 60 * 1000).unref();
|
|
@@ -1644,10 +1676,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
1644
1676
|
await this.aggregatorNode?.add(device);
|
|
1645
1677
|
}
|
|
1646
1678
|
catch (error) {
|
|
1647
|
-
const errorMessage = error instanceof Error ? error.message :
|
|
1648
|
-
const
|
|
1649
|
-
|
|
1650
|
-
this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) for plugin ${plg}${pluginName}${er}: ${error} ${errorMessage} ${errorStack} ${errorDebug}`);
|
|
1679
|
+
const errorMessage = error instanceof Error ? error.message : error;
|
|
1680
|
+
const errorInspect = inspect(error, { depth: 10 });
|
|
1681
|
+
this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) for plugin ${plg}${pluginName}${er}: ${errorMessage}\nstack: ${errorInspect}`);
|
|
1651
1682
|
return;
|
|
1652
1683
|
}
|
|
1653
1684
|
}
|
|
@@ -1658,10 +1689,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
1658
1689
|
await this.createAccessoryPlugin(plugin, device);
|
|
1659
1690
|
}
|
|
1660
1691
|
catch (error) {
|
|
1661
|
-
const errorMessage = error instanceof Error ? error.message :
|
|
1662
|
-
const
|
|
1663
|
-
|
|
1664
|
-
this.log.error(`Error creating endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) for AccessoryPlatform plugin ${plg}${pluginName}${er} server node: ${error} ${errorMessage} ${errorStack} ${errorDebug}`);
|
|
1692
|
+
const errorMessage = error instanceof Error ? error.message : error;
|
|
1693
|
+
const errorInspect = inspect(error, { depth: 10 });
|
|
1694
|
+
this.log.error(`Error creating endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) for AccessoryPlatform plugin ${plg}${pluginName}${er} server node: ${errorMessage}\nstack: ${errorInspect}`);
|
|
1665
1695
|
return;
|
|
1666
1696
|
}
|
|
1667
1697
|
}
|
|
@@ -1674,10 +1704,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
1674
1704
|
await plugin.aggregatorNode?.add(device);
|
|
1675
1705
|
}
|
|
1676
1706
|
catch (error) {
|
|
1677
|
-
const errorMessage = error instanceof Error ? error.message :
|
|
1678
|
-
const
|
|
1679
|
-
|
|
1680
|
-
this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) for DynamicPlatform plugin ${plg}${pluginName}${er} aggregator node: ${error} ${errorMessage} ${errorStack} ${errorDebug}`);
|
|
1707
|
+
const errorMessage = error instanceof Error ? error.message : error;
|
|
1708
|
+
const errorInspect = inspect(error, { depth: 10 });
|
|
1709
|
+
this.log.error(`Error adding bridged endpoint ${dev}${device.deviceName}${er} (${zb}${device.id}${er}) for DynamicPlatform plugin ${plg}${pluginName}${er} aggregator node: ${errorMessage}\nstack: ${errorInspect}`);
|
|
1681
1710
|
return;
|
|
1682
1711
|
}
|
|
1683
1712
|
}
|
|
@@ -1728,12 +1757,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
1728
1757
|
this.devices.remove(device);
|
|
1729
1758
|
}
|
|
1730
1759
|
async removeAllBridgedEndpoints(pluginName, delay = 0) {
|
|
1731
|
-
this.log.debug(`Removing all bridged endpoints for plugin ${plg}${pluginName}${db}`);
|
|
1760
|
+
this.log.debug(`Removing all bridged endpoints for plugin ${plg}${pluginName}${db}${delay > 0 ? ` with delay ${delay} ms` : ''}`);
|
|
1732
1761
|
for (const device of this.devices.array().filter((device) => device.plugin === pluginName)) {
|
|
1733
1762
|
await this.removeBridgedEndpoint(pluginName, device);
|
|
1734
1763
|
if (delay > 0)
|
|
1735
1764
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1736
1765
|
}
|
|
1766
|
+
if (delay > 0)
|
|
1767
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
1737
1768
|
}
|
|
1738
1769
|
async subscribeAttributeChanged(plugin, device) {
|
|
1739
1770
|
this.log.info(`Subscribing attributes for endpoint ${dev}${device.deviceName}${nf} (${dev}${device.id}${nf}) plugin ${plg}${plugin.name}${nf}`);
|
|
@@ -19,7 +19,7 @@ import { ValveConfigurationAndControlBehavior } from '@matter/main/behaviors/val
|
|
|
19
19
|
import { ModeSelectServer } from '@matter/main/behaviors/mode-select';
|
|
20
20
|
import { SmokeCoAlarmServer } from '@matter/main/behaviors/smoke-co-alarm';
|
|
21
21
|
import { SwitchServer } from '@matter/main/behaviors/switch';
|
|
22
|
-
export class
|
|
22
|
+
export class MatterbridgeServerDevice {
|
|
23
23
|
log;
|
|
24
24
|
commandHandler;
|
|
25
25
|
device;
|
|
@@ -141,107 +141,107 @@ export class MatterbridgeBehaviorDevice {
|
|
|
141
141
|
this.commandHandler.executeHandler('enableDisableAlarm', { request: { alarmsToEnableDisable }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
|
-
export class
|
|
144
|
+
export class MatterbridgeServer extends Behavior {
|
|
145
145
|
static id = 'matterbridge';
|
|
146
146
|
}
|
|
147
|
-
(function (
|
|
147
|
+
(function (MatterbridgeServer) {
|
|
148
148
|
class State {
|
|
149
149
|
deviceCommand;
|
|
150
150
|
}
|
|
151
|
-
|
|
152
|
-
})(
|
|
151
|
+
MatterbridgeServer.State = State;
|
|
152
|
+
})(MatterbridgeServer || (MatterbridgeServer = {}));
|
|
153
153
|
export class MatterbridgeIdentifyServer extends IdentifyServer {
|
|
154
154
|
initialize() {
|
|
155
|
-
const device = this.agent.get(
|
|
155
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
156
156
|
device.setEndpointId(this.endpoint.maybeId);
|
|
157
157
|
device.setEndpointNumber(this.endpoint.maybeNumber);
|
|
158
158
|
super.initialize();
|
|
159
159
|
}
|
|
160
160
|
identify({ identifyTime }) {
|
|
161
|
-
const device = this.agent.get(
|
|
161
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
162
162
|
device.identify({ identifyTime });
|
|
163
163
|
super.identify({ identifyTime });
|
|
164
164
|
}
|
|
165
165
|
triggerEffect({ effectIdentifier, effectVariant }) {
|
|
166
|
-
const device = this.agent.get(
|
|
166
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
167
167
|
device.triggerEffect({ effectIdentifier, effectVariant });
|
|
168
168
|
super.triggerEffect({ effectIdentifier, effectVariant });
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
export class MatterbridgeOnOffServer extends OnOffServer {
|
|
172
172
|
async on() {
|
|
173
|
-
const device = this.agent.get(
|
|
173
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
174
174
|
device.on();
|
|
175
175
|
super.on();
|
|
176
176
|
}
|
|
177
177
|
async off() {
|
|
178
|
-
const device = this.agent.get(
|
|
178
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
179
179
|
device.off();
|
|
180
180
|
super.off();
|
|
181
181
|
}
|
|
182
182
|
async toggle() {
|
|
183
|
-
const device = this.agent.get(
|
|
183
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
184
184
|
device.toggle();
|
|
185
185
|
super.toggle();
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
188
|
export class MatterbridgeLevelControlServer extends LevelControlServer {
|
|
189
189
|
async moveToLevel({ level, transitionTime, optionsMask, optionsOverride }) {
|
|
190
|
-
const device = this.agent.get(
|
|
190
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
191
191
|
device.moveToLevel({ level, transitionTime, optionsMask, optionsOverride });
|
|
192
192
|
super.moveToLevel({ level, transitionTime, optionsMask, optionsOverride });
|
|
193
193
|
}
|
|
194
194
|
async moveToLevelWithOnOff({ level, transitionTime, optionsMask, optionsOverride }) {
|
|
195
|
-
const device = this.agent.get(
|
|
195
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
196
196
|
device.moveToLevelWithOnOff({ level, transitionTime, optionsMask, optionsOverride });
|
|
197
197
|
super.moveToLevelWithOnOff({ level, transitionTime, optionsMask, optionsOverride });
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
export class MatterbridgeColorControlServer extends ColorControlServer.with(ColorControl.Feature.HueSaturation, ColorControl.Feature.Xy, ColorControl.Feature.ColorTemperature) {
|
|
201
201
|
async moveToHue({ optionsMask, optionsOverride, hue, direction, transitionTime }) {
|
|
202
|
-
const device = this.agent.get(
|
|
202
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
203
203
|
device.moveToHue({ optionsMask, optionsOverride, hue, direction, transitionTime });
|
|
204
204
|
super.moveToHue({ optionsMask, optionsOverride, hue, direction, transitionTime });
|
|
205
205
|
}
|
|
206
206
|
async moveToSaturation({ optionsMask, optionsOverride, saturation, transitionTime }) {
|
|
207
|
-
const device = this.agent.get(
|
|
207
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
208
208
|
device.moveToSaturation({ optionsMask, optionsOverride, saturation, transitionTime });
|
|
209
209
|
super.moveToSaturation({ optionsMask, optionsOverride, saturation, transitionTime });
|
|
210
210
|
}
|
|
211
211
|
async moveToHueAndSaturation({ optionsOverride, optionsMask, saturation, hue, transitionTime }) {
|
|
212
|
-
const device = this.agent.get(
|
|
212
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
213
213
|
device.moveToHueAndSaturation({ optionsOverride, optionsMask, saturation, hue, transitionTime });
|
|
214
214
|
super.moveToHueAndSaturation({ optionsOverride, optionsMask, saturation, hue, transitionTime });
|
|
215
215
|
}
|
|
216
216
|
async moveToColor({ optionsMask, optionsOverride, colorX, colorY, transitionTime }) {
|
|
217
|
-
const device = this.agent.get(
|
|
217
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
218
218
|
device.moveToColor({ optionsMask, optionsOverride, colorX, colorY, transitionTime });
|
|
219
219
|
super.moveToColor({ optionsMask, optionsOverride, colorX, colorY, transitionTime });
|
|
220
220
|
}
|
|
221
221
|
async moveToColorTemperature({ optionsOverride, optionsMask, colorTemperatureMireds, transitionTime }) {
|
|
222
|
-
const device = this.agent.get(
|
|
222
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
223
223
|
device.moveToColorTemperature({ optionsOverride, optionsMask, colorTemperatureMireds, transitionTime });
|
|
224
224
|
super.moveToColorTemperature({ optionsOverride, optionsMask, colorTemperatureMireds, transitionTime });
|
|
225
225
|
}
|
|
226
226
|
}
|
|
227
227
|
export class MatterbridgeWindowCoveringServer extends WindowCoveringServer.with(WindowCovering.Feature.Lift, WindowCovering.Feature.PositionAwareLift) {
|
|
228
228
|
async upOrOpen() {
|
|
229
|
-
const device = this.agent.get(
|
|
229
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
230
230
|
device.upOrOpen();
|
|
231
231
|
super.upOrOpen();
|
|
232
232
|
}
|
|
233
233
|
async downOrClose() {
|
|
234
|
-
const device = this.agent.get(
|
|
234
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
235
235
|
device.downOrClose();
|
|
236
236
|
super.downOrClose();
|
|
237
237
|
}
|
|
238
238
|
stopMotion() {
|
|
239
|
-
const device = this.agent.get(
|
|
239
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
240
240
|
device.stopMotion();
|
|
241
241
|
super.stopMotion();
|
|
242
242
|
}
|
|
243
243
|
goToLiftPercentage({ liftPercent100thsValue }) {
|
|
244
|
-
const device = this.agent.get(
|
|
244
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
245
245
|
device.goToLiftPercentage({ liftPercent100thsValue });
|
|
246
246
|
super.goToLiftPercentage({ liftPercent100thsValue });
|
|
247
247
|
}
|
|
@@ -250,26 +250,26 @@ export class MatterbridgeWindowCoveringServer extends WindowCoveringServer.with(
|
|
|
250
250
|
}
|
|
251
251
|
export class MatterbridgeDoorLockServer extends DoorLockServer {
|
|
252
252
|
async lockDoor() {
|
|
253
|
-
const device = this.agent.get(
|
|
253
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
254
254
|
device.lockDoor();
|
|
255
255
|
super.lockDoor();
|
|
256
256
|
}
|
|
257
257
|
async unlockDoor() {
|
|
258
|
-
const device = this.agent.get(
|
|
258
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
259
259
|
device.unlockDoor();
|
|
260
260
|
super.unlockDoor();
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
263
|
export class MatterbridgeModeSelectServer extends ModeSelectServer {
|
|
264
264
|
async changeToMode({ newMode }) {
|
|
265
|
-
const device = this.agent.get(
|
|
265
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
266
266
|
device.changeToMode({ newMode });
|
|
267
267
|
super.changeToMode({ newMode });
|
|
268
268
|
}
|
|
269
269
|
}
|
|
270
270
|
export class MatterbridgeFanControlServer extends FanControlServer.with(FanControl.Feature.MultiSpeed, FanControl.Feature.Auto, FanControl.Feature.Step) {
|
|
271
271
|
async step({ direction, wrap, lowestOff }) {
|
|
272
|
-
const device = this.agent.get(
|
|
272
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
273
273
|
device.step({ direction, wrap, lowestOff });
|
|
274
274
|
const lookupStepDirection = ['Increase', 'Decrease'];
|
|
275
275
|
device.log.debug(`Command step called with direction: ${lookupStepDirection[direction]} wrap: ${wrap} lowestOff: ${lowestOff}`);
|
|
@@ -294,7 +294,7 @@ export class MatterbridgeFanControlServer extends FanControlServer.with(FanContr
|
|
|
294
294
|
}
|
|
295
295
|
export class MatterbridgeThermostatServer extends ThermostatBehavior.with(Thermostat.Feature.Cooling, Thermostat.Feature.Heating, Thermostat.Feature.AutoMode) {
|
|
296
296
|
async setpointRaiseLower({ mode, amount }) {
|
|
297
|
-
const device = this.agent.get(
|
|
297
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
298
298
|
device.setpointRaiseLower({ mode, amount });
|
|
299
299
|
const lookupSetpointAdjustMode = ['Heat', 'Cool', 'Both'];
|
|
300
300
|
device.log.debug(`Command setpointRaiseLower called with mode: ${lookupSetpointAdjustMode[mode]} amount: ${amount / 10}`);
|
|
@@ -316,14 +316,14 @@ export class MatterbridgeValveConfigurationAndControlServer extends ValveConfigu
|
|
|
316
316
|
initialize() {
|
|
317
317
|
}
|
|
318
318
|
open({ openDuration, targetLevel }) {
|
|
319
|
-
const device = this.agent.get(
|
|
319
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
320
320
|
device.log.debug(`Command open called with openDuration: ${openDuration} targetLevel: ${targetLevel}`);
|
|
321
321
|
device.open({ openDuration, targetLevel });
|
|
322
322
|
this.state.targetLevel = targetLevel ?? 100;
|
|
323
323
|
this.state.currentLevel = targetLevel ?? 100;
|
|
324
324
|
}
|
|
325
325
|
close() {
|
|
326
|
-
const device = this.agent.get(
|
|
326
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
327
327
|
device.log.debug(`Command close called`);
|
|
328
328
|
device.close();
|
|
329
329
|
this.state.targetLevel = 0;
|
|
@@ -332,14 +332,14 @@ export class MatterbridgeValveConfigurationAndControlServer extends ValveConfigu
|
|
|
332
332
|
}
|
|
333
333
|
export class MatterbridgeSmokeCoAlarmServer extends SmokeCoAlarmServer.with(SmokeCoAlarm.Feature.SmokeAlarm, SmokeCoAlarm.Feature.CoAlarm) {
|
|
334
334
|
async selfTestRequest() {
|
|
335
|
-
const device = this.agent.get(
|
|
335
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
336
336
|
device.selfTestRequest();
|
|
337
337
|
super.selfTestRequest();
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
340
|
export class MatterbridgeBooleanStateConfigurationServer extends BooleanStateConfigurationServer.with(BooleanStateConfiguration.Feature.Visual, BooleanStateConfiguration.Feature.Audible, BooleanStateConfiguration.Feature.SensitivityLevel) {
|
|
341
341
|
async enableDisableAlarm({ alarmsToEnableDisable }) {
|
|
342
|
-
const device = this.agent.get(
|
|
342
|
+
const device = this.agent.get(MatterbridgeServer).state.deviceCommand;
|
|
343
343
|
device.enableDisableAlarm({ alarmsToEnableDisable });
|
|
344
344
|
super.enableDisableAlarm({ alarmsToEnableDisable });
|
|
345
345
|
}
|