matterbridge 2.1.6-dev.8 → 2.2.0-dev.2
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 +6 -2
- package/README-NGINX.md +76 -6
- package/dist/frontend.js +35 -2
- package/dist/matterbridge.js +27 -56
- package/dist/shelly.js +190 -0
- package/dist/update.js +50 -0
- package/frontend/build/asset-manifest.json +3 -3
- package/frontend/build/index.html +1 -1
- package/frontend/build/static/js/{main.f3c386d7.js → main.a462621b.js} +13 -13
- package/frontend/build/static/js/main.a462621b.js.map +1 -0
- package/npm-shrinkwrap.json +61 -61
- package/package.json +3 -3
- package/frontend/build/static/js/main.f3c386d7.js.map +0 -1
- /package/frontend/build/static/js/{main.f3c386d7.js.LICENSE.txt → main.a462621b.js.LICENSE.txt} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -33,7 +33,7 @@ matterbridge-zigbee2mqtt v. 2.4.4
|
|
|
33
33
|
matterbridge-somfy-tahoma v. 1.2.3
|
|
34
34
|
matterbridge-hass v. 0.0.8
|
|
35
35
|
|
|
36
|
-
## [2.
|
|
36
|
+
## [2.2.0] - 2025-02-25
|
|
37
37
|
|
|
38
38
|
### Added
|
|
39
39
|
|
|
@@ -41,11 +41,12 @@ matterbridge-hass v. 0.0.8
|
|
|
41
41
|
- [platform]: Saving in the storage the selects for faster loading of plugins.
|
|
42
42
|
- [icon]: Added matterbridge svg icon (thanks: https://github.com/robvanoostenrijk https://github.com/stuntguy3000).
|
|
43
43
|
- [pluginManager]: Refactor PluginManager to optimize memory and load time.
|
|
44
|
-
- [frontend]: Frontend v.2.4.
|
|
44
|
+
- [frontend]: Frontend v.2.4.5. Please refresh the frontend page after the update.
|
|
45
45
|
- [frontend]: Added processUptime.
|
|
46
46
|
- [frontend]: Added Share fabrics and Stop sharing to the menu. This allows to pair other controllers without the need to share from the first controller.
|
|
47
47
|
- [frontend]: Added subscriptions to QRDiv.
|
|
48
48
|
- [utils]: Optimized memory and loading time.
|
|
49
|
+
- [shelly]: Added all shelly api to be used when matterbridge is running on the shelly matterbridge board.
|
|
49
50
|
|
|
50
51
|
### Changed
|
|
51
52
|
|
|
@@ -53,6 +54,9 @@ matterbridge-hass v. 0.0.8
|
|
|
53
54
|
- [package]: Update matter.js to 0.12.4-alpha.0-20250213-1187f81eb
|
|
54
55
|
- [package]: Update matter.js to 0.12.4-alpha.0-20250215-5af08a8d6
|
|
55
56
|
- [package]: Update matter.js to 0.12.4-alpha.0-20250217-b0bba5179
|
|
57
|
+
- [package]: Update matter.js to 0.12.4-alpha.0-20250223-1e0341a1a
|
|
58
|
+
- [package]: Update matter.js to 0.12.4-alpha.0-20250224-46934b522
|
|
59
|
+
- [matterbridge]: The check for available updates now runs at restart and each 24 hours after.
|
|
56
60
|
|
|
57
61
|
### Fixed
|
|
58
62
|
|
package/README-NGINX.md
CHANGED
|
@@ -16,18 +16,19 @@
|
|
|
16
16
|
|
|
17
17
|
## Run matterbridge with nginx
|
|
18
18
|
|
|
19
|
-
### Create
|
|
19
|
+
### Create a basic nginx configuration file
|
|
20
20
|
|
|
21
21
|
```
|
|
22
22
|
sudo nano /etc/nginx/sites-available/matterbridge
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
paste this configuration and change the port to listen and the server_name using yours:
|
|
25
|
+
paste this configuration and if desired change the port to listen (here is 80) and the server_name using yours:
|
|
26
26
|
|
|
27
27
|
```
|
|
28
28
|
server {
|
|
29
|
-
listen
|
|
30
|
-
|
|
29
|
+
listen 80 default_server;
|
|
30
|
+
listen [::]:80 default_server;
|
|
31
|
+
server_name _;
|
|
31
32
|
|
|
32
33
|
location /matterbridge/ {
|
|
33
34
|
# Redirect to Matterbridge frontend
|
|
@@ -45,7 +46,72 @@ server {
|
|
|
45
46
|
}
|
|
46
47
|
```
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
Add matterbridge to enabled sites
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
sudo ln -s /etc/nginx/sites-available/matterbridge /etc/nginx/sites-enabled/
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Create an advanced nginx configuration file that redirect to ssl
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
sudo nano /etc/nginx/sites-available/matterbridge
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
paste this configuration adding your certificates:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
# Redirect all HTTP requests to HTTPS
|
|
65
|
+
server {
|
|
66
|
+
listen 80 default_server;
|
|
67
|
+
listen [::]:80 default_server;
|
|
68
|
+
server_name _;
|
|
69
|
+
|
|
70
|
+
return 301 https://$host$request_uri;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# HTTPS server configuration
|
|
74
|
+
server {
|
|
75
|
+
listen 443 ssl default_server;
|
|
76
|
+
listen [::]:443 ssl default_server;
|
|
77
|
+
http2 on;
|
|
78
|
+
server_name _;
|
|
79
|
+
|
|
80
|
+
# SSL certificate paths
|
|
81
|
+
ssl_certificate /etc/nginx/certs/cert.pem;
|
|
82
|
+
ssl_certificate_key /etc/nginx/certs/key.pem;
|
|
83
|
+
|
|
84
|
+
# SSL security settings
|
|
85
|
+
ssl_protocols TLSv1.2 TLSv1.3;
|
|
86
|
+
ssl_ciphers HIGH:!aNULL:!MD5;
|
|
87
|
+
ssl_prefer_server_ciphers on;
|
|
88
|
+
|
|
89
|
+
root /var/www/html;
|
|
90
|
+
index index.html index.htm index.nginx-debian.html;
|
|
91
|
+
|
|
92
|
+
location / {
|
|
93
|
+
# First attempt to serve request as file, then
|
|
94
|
+
# as directory, then fall back to displaying a 404.
|
|
95
|
+
try_files $uri $uri/ =404;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
location /matterbridge/ {
|
|
99
|
+
# Redirect to Matterbridge frontend
|
|
100
|
+
proxy_pass http://localhost:8283/;
|
|
101
|
+
proxy_set_header Host $host;
|
|
102
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
103
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
104
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
105
|
+
|
|
106
|
+
# WebSocket support
|
|
107
|
+
proxy_http_version 1.1;
|
|
108
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
109
|
+
proxy_set_header Connection "upgrade";
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Add matterbridge to enabled sites
|
|
49
115
|
|
|
50
116
|
```
|
|
51
117
|
sudo ln -s /etc/nginx/sites-available/matterbridge /etc/nginx/sites-enabled/
|
|
@@ -60,4 +126,8 @@ sudo nginx -t
|
|
|
60
126
|
|
|
61
127
|
### Use matterbridge with nginx
|
|
62
128
|
|
|
63
|
-
http://ubuntu
|
|
129
|
+
http://ubuntu/matterbridge/
|
|
130
|
+
|
|
131
|
+
or
|
|
132
|
+
|
|
133
|
+
https://ubuntu/matterbridge/
|
package/dist/frontend.js
CHANGED
|
@@ -17,6 +17,8 @@ export const WS_ID_CPU_UPDATE = 3;
|
|
|
17
17
|
export const WS_ID_MEMORY_UPDATE = 4;
|
|
18
18
|
export const WS_ID_UPTIME_UPDATE = 5;
|
|
19
19
|
export const WS_ID_SNACKBAR = 6;
|
|
20
|
+
export const WS_ID_SHELLY_SYS_UPDATE = 100;
|
|
21
|
+
export const WS_ID_SHELLY_MAIN_UPDATE = 101;
|
|
20
22
|
export class Frontend {
|
|
21
23
|
matterbridge;
|
|
22
24
|
log;
|
|
@@ -656,8 +658,9 @@ export class Frontend {
|
|
|
656
658
|
if (!plugin)
|
|
657
659
|
return;
|
|
658
660
|
this.matterbridge.plugins.saveConfigFromJson(plugin, req.body);
|
|
661
|
+
this.wssSendSnackbarMessage(`Saved config for plugin ${param}`);
|
|
662
|
+
this.wssSendRestartRequired();
|
|
659
663
|
}
|
|
660
|
-
this.wssSendRestartRequired();
|
|
661
664
|
res.json({ message: 'Command received' });
|
|
662
665
|
return;
|
|
663
666
|
}
|
|
@@ -1075,6 +1078,27 @@ export class Frontend {
|
|
|
1075
1078
|
});
|
|
1076
1079
|
return;
|
|
1077
1080
|
}
|
|
1081
|
+
else if (data.method === '/api/shellysysupdate') {
|
|
1082
|
+
const { triggerShellySysUpdate } = await import('./shelly.js');
|
|
1083
|
+
triggerShellySysUpdate(this.matterbridge);
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
else if (data.method === '/api/shellymainupdate') {
|
|
1087
|
+
const { triggerShellyMainUpdate } = await import('./shelly.js');
|
|
1088
|
+
triggerShellyMainUpdate(this.matterbridge);
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
else if (data.method === '/api/shellynetconfig') {
|
|
1092
|
+
this.log.debug('/api/shellynetconfig:', data.params);
|
|
1093
|
+
const { triggerShellyChangeIp: triggerShellyChangeNet } = await import('./shelly.js');
|
|
1094
|
+
triggerShellyChangeNet(this.matterbridge, data.params);
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
else if (data.method === '/api/reboot') {
|
|
1098
|
+
const { triggerShellyReboot } = await import('./shelly.js');
|
|
1099
|
+
triggerShellyReboot(this.matterbridge);
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1078
1102
|
else if (data.method === '/api/restart') {
|
|
1079
1103
|
this.wssSendSnackbarMessage(`Restarting matterbridge...`, 0);
|
|
1080
1104
|
await this.matterbridge.restartProcess();
|
|
@@ -1242,7 +1266,7 @@ export class Frontend {
|
|
|
1242
1266
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, plugin: data.params.plugin, deviceName, serialNumber, endpoint: data.params.endpoint, deviceTypes, response: clusters }));
|
|
1243
1267
|
return;
|
|
1244
1268
|
}
|
|
1245
|
-
else if (data.method === '/api/select') {
|
|
1269
|
+
else if (data.method === '/api/select' || data.method === '/api/select/devices') {
|
|
1246
1270
|
if (!isValidString(data.params.plugin, 10)) {
|
|
1247
1271
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Wrong parameter plugin in /api/select' }));
|
|
1248
1272
|
return;
|
|
@@ -1319,6 +1343,7 @@ export class Frontend {
|
|
|
1319
1343
|
wssSendRestartRequired() {
|
|
1320
1344
|
this.log.debug('Sending a restart required message to all connected clients');
|
|
1321
1345
|
this.matterbridge.matterbridgeInformation.restartRequired = true;
|
|
1346
|
+
this.wssSendSnackbarMessage(`Restart required`, 0);
|
|
1322
1347
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1323
1348
|
if (client.readyState === WebSocket.OPEN) {
|
|
1324
1349
|
client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', params: {} }));
|
|
@@ -1357,4 +1382,12 @@ export class Frontend {
|
|
|
1357
1382
|
}
|
|
1358
1383
|
});
|
|
1359
1384
|
}
|
|
1385
|
+
wssBroadcastMessage(id, method, params) {
|
|
1386
|
+
this.log.debug(`Sending a broadcast message id ${id} method ${method} params ${debugStringify(params ?? {})} to all connected clients`);
|
|
1387
|
+
this.webSocketServer?.clients.forEach((client) => {
|
|
1388
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
1389
|
+
client.send(JSON.stringify({ id, src: 'Matterbridge', dst: 'Frontend', method, params }));
|
|
1390
|
+
}
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1360
1393
|
}
|
package/dist/matterbridge.js
CHANGED
|
@@ -2,10 +2,10 @@ import os from 'node:os';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { promises as fs } from 'node:fs';
|
|
4
4
|
import EventEmitter from 'node:events';
|
|
5
|
-
import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN
|
|
5
|
+
import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN } from './logger/export.js';
|
|
6
6
|
import { NodeStorageManager } from './storage/export.js';
|
|
7
7
|
import { getParameter, getIntParameter, hasParameter, copyDirectory, withTimeout } from './utils/export.js';
|
|
8
|
-
import { logInterfaces,
|
|
8
|
+
import { logInterfaces, getGlobalNodeModules } from './utils/network.js';
|
|
9
9
|
import { PluginManager } from './pluginManager.js';
|
|
10
10
|
import { DeviceManager } from './deviceManager.js';
|
|
11
11
|
import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
|
|
@@ -14,6 +14,7 @@ import { Frontend } from './frontend.js';
|
|
|
14
14
|
import { DeviceTypeId, Endpoint as EndpointNode, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageService, Environment, ServerNode } from '@matter/main';
|
|
15
15
|
import { DeviceCommissioner, FabricAction, MdnsService, PaseClient } from '@matter/main/protocol';
|
|
16
16
|
import { AggregatorEndpoint } from '@matter/main/endpoints';
|
|
17
|
+
import { BridgedDeviceBasicInformationServer } from '@matter/main/behaviors/bridged-device-basic-information';
|
|
17
18
|
const plg = '\u001B[38;5;33m';
|
|
18
19
|
const dev = '\u001B[38;5;79m';
|
|
19
20
|
const typ = '\u001B[38;5;207m';
|
|
@@ -57,6 +58,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
57
58
|
restartMode: '',
|
|
58
59
|
readOnly: hasParameter('readonly') || hasParameter('shelly'),
|
|
59
60
|
shellyBoard: hasParameter('shelly'),
|
|
61
|
+
shellySysUpdate: false,
|
|
62
|
+
shellyMainUpdate: false,
|
|
60
63
|
profile: getParameter('profile'),
|
|
61
64
|
loggerLevel: "info",
|
|
62
65
|
fileLogger: false,
|
|
@@ -102,6 +105,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
102
105
|
execRunningCount = 0;
|
|
103
106
|
startMatterInterval;
|
|
104
107
|
checkUpdateInterval;
|
|
108
|
+
checkUpdateTimeout;
|
|
105
109
|
configureTimeout;
|
|
106
110
|
reachabilityTimeout;
|
|
107
111
|
sigintHandler;
|
|
@@ -565,17 +569,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
565
569
|
}
|
|
566
570
|
if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
|
|
567
571
|
await this.frontend.start(getIntParameter('frontend'));
|
|
568
|
-
this.
|
|
569
|
-
|
|
570
|
-
this
|
|
571
|
-
}
|
|
572
|
-
this.checkUpdateInterval = setInterval(() => {
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
}
|
|
577
|
-
this.frontend.wssSendRefreshRequired();
|
|
578
|
-
}, 60 * 60 * 1000);
|
|
572
|
+
this.checkUpdateTimeout = setTimeout(async () => {
|
|
573
|
+
const { checkUpdates } = await import('./update.js');
|
|
574
|
+
checkUpdates(this);
|
|
575
|
+
}, 30 * 1000).unref();
|
|
576
|
+
this.checkUpdateInterval = setInterval(async () => {
|
|
577
|
+
const { checkUpdates } = await import('./update.js');
|
|
578
|
+
checkUpdates(this);
|
|
579
|
+
}, 24 * 60 * 60 * 1000).unref();
|
|
579
580
|
if (hasParameter('test')) {
|
|
580
581
|
this.bridgeMode = 'bridge';
|
|
581
582
|
MatterbridgeEndpoint.bridgeMode = 'bridge';
|
|
@@ -812,37 +813,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
812
813
|
const cmdArgs = process.argv.slice(2).join(' ');
|
|
813
814
|
this.log.debug(`Command Line Arguments: ${cmdArgs}`);
|
|
814
815
|
}
|
|
815
|
-
async getMatterbridgeLatestVersion() {
|
|
816
|
-
getNpmPackageVersion('matterbridge')
|
|
817
|
-
.then(async (version) => {
|
|
818
|
-
this.matterbridgeLatestVersion = version;
|
|
819
|
-
this.matterbridgeInformation.matterbridgeLatestVersion = version;
|
|
820
|
-
await this.nodeContext?.set('matterbridgeLatestVersion', this.matterbridgeLatestVersion);
|
|
821
|
-
if (this.matterbridgeVersion !== this.matterbridgeLatestVersion) {
|
|
822
|
-
this.log.notice(`Matterbridge is out of date. Current version: ${this.matterbridgeVersion}. Latest version: ${this.matterbridgeLatestVersion}.`);
|
|
823
|
-
}
|
|
824
|
-
else {
|
|
825
|
-
this.log.debug(`Matterbridge is up to date. Current version: ${this.matterbridgeVersion}. Latest version: ${this.matterbridgeLatestVersion}.`);
|
|
826
|
-
}
|
|
827
|
-
this.frontend.wssSendRefreshRequired();
|
|
828
|
-
})
|
|
829
|
-
.catch((error) => {
|
|
830
|
-
this.log.warn(`Error getting Matterbridge latest version: ${error.message}`);
|
|
831
|
-
});
|
|
832
|
-
}
|
|
833
|
-
async getPluginLatestVersion(plugin) {
|
|
834
|
-
getNpmPackageVersion(plugin.name)
|
|
835
|
-
.then((version) => {
|
|
836
|
-
plugin.latestVersion = version;
|
|
837
|
-
if (plugin.version !== plugin.latestVersion)
|
|
838
|
-
this.log.notice(`The plugin ${plg}${plugin.name}${nt} is out of date. Current version: ${plugin.version}. Latest version: ${plugin.latestVersion}.`);
|
|
839
|
-
else
|
|
840
|
-
this.log.debug(`The plugin ${plg}${plugin.name}${db} is up to date. Current version: ${plugin.version}. Latest version: ${plugin.latestVersion}.`);
|
|
841
|
-
})
|
|
842
|
-
.catch((error) => {
|
|
843
|
-
this.log.warn(`Error getting ${plg}${plugin.name}${er} latest version: ${error.message}`);
|
|
844
|
-
});
|
|
845
|
-
}
|
|
846
816
|
createMatterLogger() {
|
|
847
817
|
const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
|
|
848
818
|
return (_level, formattedLog) => {
|
|
@@ -966,6 +936,11 @@ export class Matterbridge extends EventEmitter {
|
|
|
966
936
|
this.startMatterInterval = undefined;
|
|
967
937
|
this.log.debug('Start matter interval cleared');
|
|
968
938
|
}
|
|
939
|
+
if (this.checkUpdateTimeout) {
|
|
940
|
+
clearInterval(this.checkUpdateTimeout);
|
|
941
|
+
this.checkUpdateTimeout = undefined;
|
|
942
|
+
this.log.debug('Check update timeout cleared');
|
|
943
|
+
}
|
|
969
944
|
if (this.checkUpdateInterval) {
|
|
970
945
|
clearInterval(this.checkUpdateInterval);
|
|
971
946
|
this.checkUpdateInterval = undefined;
|
|
@@ -1115,6 +1090,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1115
1090
|
async createAccessoryPlugin(plugin, device, start = false) {
|
|
1116
1091
|
if (!plugin.locked && device.deviceName && device.vendorId && device.productId && device.vendorName && device.productName) {
|
|
1117
1092
|
plugin.locked = true;
|
|
1093
|
+
plugin.device = device;
|
|
1118
1094
|
plugin.storageContext = await this.createServerNodeContext(plugin.name, device.deviceName, DeviceTypeId(device.deviceType), device.vendorId, device.vendorName, device.productId, device.productName);
|
|
1119
1095
|
plugin.serverNode = await this.createServerNode(plugin.storageContext, this.port ? this.port++ : undefined, this.passcode ? this.passcode++ : undefined, this.discriminator ? this.discriminator++ : undefined);
|
|
1120
1096
|
this.log.debug(`Adding ${plg}${plugin.name}${db}:${dev}${device.deviceName}${db} to ${plg}${plugin.name}${db} server node`);
|
|
@@ -1188,8 +1164,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1188
1164
|
}, 30 * 1000);
|
|
1189
1165
|
this.reachabilityTimeout = setTimeout(() => {
|
|
1190
1166
|
this.log.info(`Setting reachability to true for ${plg}Matterbridge${db}`);
|
|
1191
|
-
if (this.serverNode)
|
|
1192
|
-
this.setServerNodeReachability(this.serverNode, true);
|
|
1193
1167
|
if (this.aggregatorNode)
|
|
1194
1168
|
this.setAggregatorReachability(this.aggregatorNode, true);
|
|
1195
1169
|
this.frontend.wssSendRefreshRequired();
|
|
@@ -1274,11 +1248,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1274
1248
|
}
|
|
1275
1249
|
this.startServerNode(plugin.serverNode);
|
|
1276
1250
|
plugin.reachabilityTimeout = setTimeout(() => {
|
|
1277
|
-
this.log.info(`Setting reachability to true for ${plg}${plugin.name}${db}`);
|
|
1278
|
-
if (plugin.serverNode)
|
|
1279
|
-
this.setServerNodeReachability(plugin.serverNode, true);
|
|
1280
|
-
if (plugin.type === 'AccessoryPlatform' && plugin.device)
|
|
1281
|
-
this.setDeviceReachability(plugin.device, true);
|
|
1251
|
+
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}`);
|
|
1282
1252
|
if (plugin.type === 'DynamicPlatform' && plugin.aggregatorNode)
|
|
1283
1253
|
this.setAggregatorReachability(plugin.aggregatorNode, true);
|
|
1284
1254
|
this.frontend.wssSendRefreshRequired();
|
|
@@ -1673,11 +1643,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
1673
1643
|
};
|
|
1674
1644
|
});
|
|
1675
1645
|
}
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1646
|
+
async setAggregatorReachability(aggregatorNode, reachable) {
|
|
1647
|
+
for (const child of aggregatorNode.parts) {
|
|
1648
|
+
this.log.debug(`Setting reachability of ${child?.deviceName} to ${reachable}`);
|
|
1649
|
+
await child.setStateOf(BridgedDeviceBasicInformationServer, { reachable });
|
|
1650
|
+
child.act((agent) => child.eventsOf(BridgedDeviceBasicInformationServer).reachableChanged.emit({ reachableNewValue: true }, agent.context));
|
|
1651
|
+
}
|
|
1681
1652
|
}
|
|
1682
1653
|
getVendorIdName = (vendorId) => {
|
|
1683
1654
|
if (!vendorId)
|
package/dist/shelly.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { WS_ID_SHELLY_MAIN_UPDATE, WS_ID_SHELLY_SYS_UPDATE } from './frontend.js';
|
|
2
|
+
import { debugStringify } from './logger/export.js';
|
|
3
|
+
export async function getShellySysUpdate(matterbridge) {
|
|
4
|
+
getShelly('/api/updates/sys/check', 60 * 1000)
|
|
5
|
+
.then(async (data) => {
|
|
6
|
+
if (data.length > 0) {
|
|
7
|
+
matterbridge.matterbridgeInformation.shellySysUpdate = true;
|
|
8
|
+
matterbridge.log.notice(`Shelly system update available: ${debugStringify(data)}`);
|
|
9
|
+
matterbridge.frontend.wssSendSnackbarMessage('Shelly system update available', 60);
|
|
10
|
+
matterbridge.frontend.wssBroadcastMessage(WS_ID_SHELLY_SYS_UPDATE, 'shelly-sys-update', { available: true });
|
|
11
|
+
for (const update of data) {
|
|
12
|
+
if (update.name)
|
|
13
|
+
matterbridge.frontend.wssSendSnackbarMessage('Shelly system update available: ' + update.name, 10);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
.catch((error) => {
|
|
18
|
+
matterbridge.log.warn(`Error getting Shelly system updates: ${error instanceof Error ? error.message : error}`);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export async function triggerShellySysUpdate(matterbridge) {
|
|
22
|
+
getShelly('/api/updates/sys/perform', 10 * 1000)
|
|
23
|
+
.then(async () => {
|
|
24
|
+
matterbridge.log.debug(`Triggered Shelly system updates`);
|
|
25
|
+
})
|
|
26
|
+
.catch((error) => {
|
|
27
|
+
matterbridge.log.debug(`****Error triggering Shelly system updates: ${error instanceof Error ? error.message : error}`);
|
|
28
|
+
})
|
|
29
|
+
.finally(() => {
|
|
30
|
+
matterbridge.matterbridgeInformation.shellySysUpdate = false;
|
|
31
|
+
matterbridge.log.notice(`Installing Shelly system update...`);
|
|
32
|
+
matterbridge.frontend.wssSendSnackbarMessage('Installing Shelly system update...', 60);
|
|
33
|
+
matterbridge.frontend.wssBroadcastMessage(WS_ID_SHELLY_SYS_UPDATE, 'shelly-sys-update', { available: false });
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export async function getShellyMainUpdate(matterbridge) {
|
|
37
|
+
getShelly('/api/updates/main/check', 60 * 1000)
|
|
38
|
+
.then(async (data) => {
|
|
39
|
+
if (data.length > 0) {
|
|
40
|
+
matterbridge.matterbridgeInformation.shellyMainUpdate = true;
|
|
41
|
+
matterbridge.log.notice(`Shelly software update available: ${debugStringify(data)}`);
|
|
42
|
+
matterbridge.frontend.wssSendSnackbarMessage('Shelly software update available', 60);
|
|
43
|
+
matterbridge.frontend.wssBroadcastMessage(WS_ID_SHELLY_MAIN_UPDATE, 'shelly-main-update', { available: true });
|
|
44
|
+
for (const update of data) {
|
|
45
|
+
if (update.name)
|
|
46
|
+
matterbridge.frontend.wssSendSnackbarMessage('Shelly software update available: ' + update.name, 10);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
.catch((error) => {
|
|
51
|
+
matterbridge.log.warn(`Error getting Shelly main updates: ${error instanceof Error ? error.message : error}`);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
export async function triggerShellyMainUpdate(matterbridge) {
|
|
55
|
+
getShelly('/api/updates/main/perform', 10 * 1000)
|
|
56
|
+
.then(async () => {
|
|
57
|
+
matterbridge.log.debug(`Triggered Shelly main updates`);
|
|
58
|
+
})
|
|
59
|
+
.catch((error) => {
|
|
60
|
+
matterbridge.log.debug(`****Error triggering Shelly main updates: ${error instanceof Error ? error.message : error}`);
|
|
61
|
+
})
|
|
62
|
+
.finally(() => {
|
|
63
|
+
matterbridge.matterbridgeInformation.shellyMainUpdate = false;
|
|
64
|
+
matterbridge.log.notice(`Installing Shelly software update...`);
|
|
65
|
+
matterbridge.frontend.wssSendSnackbarMessage('Installing Shelly software update...', 60);
|
|
66
|
+
matterbridge.frontend.wssBroadcastMessage(WS_ID_SHELLY_MAIN_UPDATE, 'shelly-main-update', { available: false });
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
export async function triggerShellyChangeIp(matterbridge, config) {
|
|
70
|
+
const api = config.type === 'static' ? '/api/network/connection/static' : '/api/network/connection/dynamic';
|
|
71
|
+
const data = { interface: 'end0' };
|
|
72
|
+
if (config.type === 'static') {
|
|
73
|
+
data['addr'] = config.ip;
|
|
74
|
+
data['mask'] = config.subnet;
|
|
75
|
+
data['gw'] = config.gateway;
|
|
76
|
+
data['dns'] = config.dns;
|
|
77
|
+
}
|
|
78
|
+
matterbridge.log.debug(`Triggering Shelly network configuration change: ${debugStringify(config)}`);
|
|
79
|
+
postShelly(api, data, 60 * 1000)
|
|
80
|
+
.then(async () => {
|
|
81
|
+
matterbridge.log.debug(`Triggered Shelly network configuration change: ${debugStringify(config)}`);
|
|
82
|
+
})
|
|
83
|
+
.catch((error) => {
|
|
84
|
+
matterbridge.log.debug(`****Error triggering Shelly network configuration change: ${error instanceof Error ? error.message : error}`);
|
|
85
|
+
})
|
|
86
|
+
.finally(() => {
|
|
87
|
+
matterbridge.log.notice(`Changed Shelly network configuration`);
|
|
88
|
+
matterbridge.frontend.wssSendSnackbarMessage('Changed Shelly network configuration');
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
export async function triggerShellyReboot(matterbridge) {
|
|
92
|
+
matterbridge.log.debug(`Triggering Shelly system reboot`);
|
|
93
|
+
postShelly('/api/system/reboot', {}, 60 * 1000)
|
|
94
|
+
.then(async () => {
|
|
95
|
+
matterbridge.log.debug(`Triggered Shelly system reboot`);
|
|
96
|
+
})
|
|
97
|
+
.catch((error) => {
|
|
98
|
+
matterbridge.log.debug(`****Error triggering Shelly system reboot: ${error instanceof Error ? error.message : error}`);
|
|
99
|
+
})
|
|
100
|
+
.finally(() => {
|
|
101
|
+
matterbridge.log.notice(`Rebooting Shelly board...`);
|
|
102
|
+
matterbridge.frontend.wssSendSnackbarMessage('Rebooting Shelly board...');
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
async function getShelly(api, timeout = 60000) {
|
|
106
|
+
const http = await import('node:http');
|
|
107
|
+
return new Promise((resolve, reject) => {
|
|
108
|
+
const url = `http://127.0.0.1:8101${api}`;
|
|
109
|
+
const controller = new AbortController();
|
|
110
|
+
const timeoutId = setTimeout(() => {
|
|
111
|
+
controller.abort();
|
|
112
|
+
reject(new Error(`Request timed out after ${timeout / 1000} seconds`));
|
|
113
|
+
}, timeout).unref();
|
|
114
|
+
const req = http.get(url, { signal: controller.signal }, (res) => {
|
|
115
|
+
let data = '';
|
|
116
|
+
if (res.statusCode !== 200) {
|
|
117
|
+
clearTimeout(timeoutId);
|
|
118
|
+
res.resume();
|
|
119
|
+
req.destroy();
|
|
120
|
+
reject(new Error(`Failed to fetch data. Status code: ${res.statusCode}`));
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
res.on('data', (chunk) => {
|
|
124
|
+
data += chunk;
|
|
125
|
+
});
|
|
126
|
+
res.on('end', () => {
|
|
127
|
+
clearTimeout(timeoutId);
|
|
128
|
+
try {
|
|
129
|
+
const jsonData = JSON.parse(data);
|
|
130
|
+
resolve(jsonData);
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
reject(new Error(`Failed to parse response JSON: ${error instanceof Error ? error.message : error}`));
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
req.on('error', (error) => {
|
|
138
|
+
clearTimeout(timeoutId);
|
|
139
|
+
reject(new Error(`Request failed: ${error instanceof Error ? error.message : error}`));
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
async function postShelly(api, data, timeout = 60000) {
|
|
144
|
+
const http = await import('node:http');
|
|
145
|
+
return new Promise((resolve, reject) => {
|
|
146
|
+
const url = `http://127.0.0.1:8101${api}`;
|
|
147
|
+
const controller = new AbortController();
|
|
148
|
+
const timeoutId = setTimeout(() => {
|
|
149
|
+
controller.abort();
|
|
150
|
+
reject(new Error(`Request timed out after ${timeout / 1000} seconds`));
|
|
151
|
+
}, timeout).unref();
|
|
152
|
+
const jsonData = JSON.stringify(data);
|
|
153
|
+
const options = {
|
|
154
|
+
method: 'POST',
|
|
155
|
+
headers: {
|
|
156
|
+
'Content-Type': 'application/json',
|
|
157
|
+
'Content-Length': Buffer.byteLength(jsonData),
|
|
158
|
+
},
|
|
159
|
+
signal: controller.signal,
|
|
160
|
+
};
|
|
161
|
+
const req = http.request(url, options, (res) => {
|
|
162
|
+
let responseData = '';
|
|
163
|
+
if (res.statusCode && res.statusCode >= 300) {
|
|
164
|
+
clearTimeout(timeoutId);
|
|
165
|
+
res.resume();
|
|
166
|
+
req.destroy();
|
|
167
|
+
return reject(new Error(`Failed to post data. Status code: ${res.statusCode}`));
|
|
168
|
+
}
|
|
169
|
+
res.on('data', (chunk) => {
|
|
170
|
+
responseData += chunk;
|
|
171
|
+
});
|
|
172
|
+
res.on('end', () => {
|
|
173
|
+
clearTimeout(timeoutId);
|
|
174
|
+
try {
|
|
175
|
+
const jsonResponse = JSON.parse(responseData);
|
|
176
|
+
resolve(jsonResponse);
|
|
177
|
+
}
|
|
178
|
+
catch (err) {
|
|
179
|
+
reject(new Error(`Failed to parse response JSON: ${err instanceof Error ? err.message : err}`));
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
req.on('error', (error) => {
|
|
184
|
+
clearTimeout(timeoutId);
|
|
185
|
+
reject(new Error(`Request failed: ${error instanceof Error ? error.message : error}`));
|
|
186
|
+
});
|
|
187
|
+
req.write(jsonData);
|
|
188
|
+
req.end();
|
|
189
|
+
});
|
|
190
|
+
}
|
package/dist/update.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { plg } from './matterbridgeTypes.js';
|
|
2
|
+
import { db, er, nt } from './logger/export.js';
|
|
3
|
+
export async function checkUpdates(matterbridge) {
|
|
4
|
+
const { hasParameter } = await import('./utils/parameter.js');
|
|
5
|
+
getMatterbridgeLatestVersion(matterbridge);
|
|
6
|
+
for (const plugin of matterbridge.plugins) {
|
|
7
|
+
getPluginLatestVersion(matterbridge, plugin);
|
|
8
|
+
}
|
|
9
|
+
if (hasParameter('shelly')) {
|
|
10
|
+
const { getShellySysUpdate, getShellyMainUpdate } = await import('./shelly.js');
|
|
11
|
+
getShellySysUpdate(matterbridge);
|
|
12
|
+
getShellyMainUpdate(matterbridge);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
async function getMatterbridgeLatestVersion(matterbridge) {
|
|
16
|
+
const { getNpmPackageVersion } = await import('./utils/network.js');
|
|
17
|
+
getNpmPackageVersion('matterbridge')
|
|
18
|
+
.then(async (version) => {
|
|
19
|
+
matterbridge.matterbridgeLatestVersion = version;
|
|
20
|
+
matterbridge.matterbridgeInformation.matterbridgeLatestVersion = version;
|
|
21
|
+
await matterbridge.nodeContext?.set('matterbridgeLatestVersion', matterbridge.matterbridgeLatestVersion);
|
|
22
|
+
if (matterbridge.matterbridgeVersion !== matterbridge.matterbridgeLatestVersion) {
|
|
23
|
+
matterbridge.log.notice(`Matterbridge is out of date. Current version: ${matterbridge.matterbridgeVersion}. Latest version: ${matterbridge.matterbridgeLatestVersion}.`);
|
|
24
|
+
matterbridge.frontend.wssSendRefreshRequired();
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
matterbridge.log.debug(`Matterbridge is up to date. Current version: ${matterbridge.matterbridgeVersion}. Latest version: ${matterbridge.matterbridgeLatestVersion}.`);
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
.catch((error) => {
|
|
31
|
+
matterbridge.log.warn(`Error getting Matterbridge latest version: ${error.message}`);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async function getPluginLatestVersion(matterbridge, plugin) {
|
|
35
|
+
const { getNpmPackageVersion } = await import('./utils/network.js');
|
|
36
|
+
getNpmPackageVersion(plugin.name)
|
|
37
|
+
.then((version) => {
|
|
38
|
+
plugin.latestVersion = version;
|
|
39
|
+
if (plugin.version !== plugin.latestVersion) {
|
|
40
|
+
matterbridge.log.notice(`The plugin ${plg}${plugin.name}${nt} is out of date. Current version: ${plugin.version}. Latest version: ${plugin.latestVersion}.`);
|
|
41
|
+
matterbridge.frontend.wssSendRefreshRequired();
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
matterbridge.log.debug(`The plugin ${plg}${plugin.name}${db} is up to date. Current version: ${plugin.version}. Latest version: ${plugin.latestVersion}.`);
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
.catch((error) => {
|
|
48
|
+
matterbridge.log.warn(`Error getting ${plg}${plugin.name}${er} latest version: ${error.message}`);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files": {
|
|
3
3
|
"main.css": "./static/css/main.cf25d33e.css",
|
|
4
|
-
"main.js": "./static/js/main.
|
|
4
|
+
"main.js": "./static/js/main.a462621b.js",
|
|
5
5
|
"static/js/453.abd36b29.chunk.js": "./static/js/453.abd36b29.chunk.js",
|
|
6
6
|
"static/media/roboto-latin-700-normal.woff2": "./static/media/roboto-latin-700-normal.4535474e1cf8598695ad.woff2",
|
|
7
7
|
"static/media/roboto-latin-500-normal.woff2": "./static/media/roboto-latin-500-normal.7077203b1982951ecf76.woff2",
|
|
@@ -61,11 +61,11 @@
|
|
|
61
61
|
"static/media/roboto-greek-ext-400-normal.woff": "./static/media/roboto-greek-ext-400-normal.16eb83b4a3b1ea994243.woff",
|
|
62
62
|
"index.html": "./index.html",
|
|
63
63
|
"main.cf25d33e.css.map": "./static/css/main.cf25d33e.css.map",
|
|
64
|
-
"main.
|
|
64
|
+
"main.a462621b.js.map": "./static/js/main.a462621b.js.map",
|
|
65
65
|
"453.abd36b29.chunk.js.map": "./static/js/453.abd36b29.chunk.js.map"
|
|
66
66
|
},
|
|
67
67
|
"entrypoints": [
|
|
68
68
|
"static/css/main.cf25d33e.css",
|
|
69
|
-
"static/js/main.
|
|
69
|
+
"static/js/main.a462621b.js"
|
|
70
70
|
]
|
|
71
71
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!doctype html><html lang="en"><head><meta charset="utf-8"/><base href="./"><link rel="icon" href="./matterbridge 32x32.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>Matterbridge</title><link rel="manifest" href="./manifest.json"/><script defer="defer" src="./static/js/main.
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"/><base href="./"><link rel="icon" href="./matterbridge 32x32.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>Matterbridge</title><link rel="manifest" href="./manifest.json"/><script defer="defer" src="./static/js/main.a462621b.js"></script><link href="./static/css/main.cf25d33e.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|