matterbridge 2.1.6-dev.8 → 2.2.0-dev.1
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-NGINX.md +76 -6
- package/dist/frontend.js +30 -2
- package/dist/matterbridge.js +31 -47
- package/dist/shelly.js +176 -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.fed77626.js} +13 -13
- package/frontend/build/static/js/main.fed77626.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.fed77626.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,7 +41,7 @@ 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.3. 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.
|
|
@@ -53,6 +53,8 @@ matterbridge-hass v. 0.0.8
|
|
|
53
53
|
- [package]: Update matter.js to 0.12.4-alpha.0-20250213-1187f81eb
|
|
54
54
|
- [package]: Update matter.js to 0.12.4-alpha.0-20250215-5af08a8d6
|
|
55
55
|
- [package]: Update matter.js to 0.12.4-alpha.0-20250217-b0bba5179
|
|
56
|
+
- [package]: Update matter.js to 0.12.4-alpha.0-20250223-1e0341a1a
|
|
57
|
+
- [package]: Update matter.js to 0.12.4-alpha.0-20250224-46934b522
|
|
56
58
|
|
|
57
59
|
### Fixed
|
|
58
60
|
|
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,22 @@ 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
|
+
}
|
|
1078
1097
|
else if (data.method === '/api/restart') {
|
|
1079
1098
|
this.wssSendSnackbarMessage(`Restarting matterbridge...`, 0);
|
|
1080
1099
|
await this.matterbridge.restartProcess();
|
|
@@ -1242,7 +1261,7 @@ export class Frontend {
|
|
|
1242
1261
|
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
1262
|
return;
|
|
1244
1263
|
}
|
|
1245
|
-
else if (data.method === '/api/select') {
|
|
1264
|
+
else if (data.method === '/api/select' || data.method === '/api/select/devices') {
|
|
1246
1265
|
if (!isValidString(data.params.plugin, 10)) {
|
|
1247
1266
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Wrong parameter plugin in /api/select' }));
|
|
1248
1267
|
return;
|
|
@@ -1319,6 +1338,7 @@ export class Frontend {
|
|
|
1319
1338
|
wssSendRestartRequired() {
|
|
1320
1339
|
this.log.debug('Sending a restart required message to all connected clients');
|
|
1321
1340
|
this.matterbridge.matterbridgeInformation.restartRequired = true;
|
|
1341
|
+
this.wssSendSnackbarMessage(`Restart required`, 0);
|
|
1322
1342
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1323
1343
|
if (client.readyState === WebSocket.OPEN) {
|
|
1324
1344
|
client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', params: {} }));
|
|
@@ -1357,4 +1377,12 @@ export class Frontend {
|
|
|
1357
1377
|
}
|
|
1358
1378
|
});
|
|
1359
1379
|
}
|
|
1380
|
+
wssBroadcastMessage(id, method, params) {
|
|
1381
|
+
this.log.debug(`Sending a broadcast message id ${id} method ${method} params ${debugStringify(params ?? {})} to all connected clients`);
|
|
1382
|
+
this.webSocketServer?.clients.forEach((client) => {
|
|
1383
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
1384
|
+
client.send(JSON.stringify({ id, src: 'Matterbridge', dst: 'Frontend', method, params }));
|
|
1385
|
+
}
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1360
1388
|
}
|
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,9 @@ 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 { BasicInformationServer } from '@matter/main/behaviors/basic-information';
|
|
18
|
+
import { BridgedDeviceBasicInformation } from '@matter/main/clusters/bridged-device-basic-information';
|
|
19
|
+
import { BasicInformation } from '@matter/main/clusters/basic-information';
|
|
17
20
|
const plg = '\u001B[38;5;33m';
|
|
18
21
|
const dev = '\u001B[38;5;79m';
|
|
19
22
|
const typ = '\u001B[38;5;207m';
|
|
@@ -57,6 +60,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
57
60
|
restartMode: '',
|
|
58
61
|
readOnly: hasParameter('readonly') || hasParameter('shelly'),
|
|
59
62
|
shellyBoard: hasParameter('shelly'),
|
|
63
|
+
shellySysUpdate: false,
|
|
64
|
+
shellyMainUpdate: false,
|
|
60
65
|
profile: getParameter('profile'),
|
|
61
66
|
loggerLevel: "info",
|
|
62
67
|
fileLogger: false,
|
|
@@ -102,6 +107,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
102
107
|
execRunningCount = 0;
|
|
103
108
|
startMatterInterval;
|
|
104
109
|
checkUpdateInterval;
|
|
110
|
+
checkUpdateTimeout;
|
|
105
111
|
configureTimeout;
|
|
106
112
|
reachabilityTimeout;
|
|
107
113
|
sigintHandler;
|
|
@@ -565,17 +571,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
565
571
|
}
|
|
566
572
|
if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
|
|
567
573
|
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);
|
|
574
|
+
this.checkUpdateTimeout = setTimeout(async () => {
|
|
575
|
+
const { checkUpdates } = await import('./update.js');
|
|
576
|
+
checkUpdates(this);
|
|
577
|
+
}, 30 * 1000).unref();
|
|
578
|
+
this.checkUpdateInterval = setInterval(async () => {
|
|
579
|
+
const { checkUpdates } = await import('./update.js');
|
|
580
|
+
checkUpdates(this);
|
|
581
|
+
}, 24 * 60 * 60 * 1000).unref();
|
|
579
582
|
if (hasParameter('test')) {
|
|
580
583
|
this.bridgeMode = 'bridge';
|
|
581
584
|
MatterbridgeEndpoint.bridgeMode = 'bridge';
|
|
@@ -812,37 +815,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
812
815
|
const cmdArgs = process.argv.slice(2).join(' ');
|
|
813
816
|
this.log.debug(`Command Line Arguments: ${cmdArgs}`);
|
|
814
817
|
}
|
|
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
818
|
createMatterLogger() {
|
|
847
819
|
const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
|
|
848
820
|
return (_level, formattedLog) => {
|
|
@@ -966,6 +938,11 @@ export class Matterbridge extends EventEmitter {
|
|
|
966
938
|
this.startMatterInterval = undefined;
|
|
967
939
|
this.log.debug('Start matter interval cleared');
|
|
968
940
|
}
|
|
941
|
+
if (this.checkUpdateTimeout) {
|
|
942
|
+
clearInterval(this.checkUpdateTimeout);
|
|
943
|
+
this.checkUpdateTimeout = undefined;
|
|
944
|
+
this.log.debug('Check update timeout cleared');
|
|
945
|
+
}
|
|
969
946
|
if (this.checkUpdateInterval) {
|
|
970
947
|
clearInterval(this.checkUpdateInterval);
|
|
971
948
|
this.checkUpdateInterval = undefined;
|
|
@@ -1673,11 +1650,18 @@ export class Matterbridge extends EventEmitter {
|
|
|
1673
1650
|
};
|
|
1674
1651
|
});
|
|
1675
1652
|
}
|
|
1676
|
-
setServerNodeReachability(serverNode, reachable) {
|
|
1653
|
+
async setServerNodeReachability(serverNode, reachable) {
|
|
1654
|
+
await serverNode.setStateOf(BasicInformationServer, { reachable });
|
|
1677
1655
|
}
|
|
1678
|
-
setAggregatorReachability(aggregatorNode, reachable) {
|
|
1656
|
+
async setAggregatorReachability(aggregatorNode, reachable) {
|
|
1657
|
+
for (const child of aggregatorNode.parts) {
|
|
1658
|
+
await child.setAttribute(BridgedDeviceBasicInformation.Cluster.id, 'reachable', reachable);
|
|
1659
|
+
await child.triggerEvent(BridgedDeviceBasicInformation.Cluster.id, 'reachableChanged', { reachableNewValue: reachable });
|
|
1660
|
+
}
|
|
1679
1661
|
}
|
|
1680
|
-
setDeviceReachability(device, reachable) {
|
|
1662
|
+
async setDeviceReachability(device, reachable) {
|
|
1663
|
+
await device.setAttribute(BasicInformation.Cluster.id, 'reachable', reachable);
|
|
1664
|
+
await device.triggerEvent(BasicInformation.Cluster.id, 'reachableChanged', { reachableNewValue: reachable });
|
|
1681
1665
|
}
|
|
1682
1666
|
getVendorIdName = (vendorId) => {
|
|
1683
1667
|
if (!vendorId)
|
package/dist/shelly.js
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
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
|
+
async function getShelly(api, timeout = 60000) {
|
|
92
|
+
const http = await import('node:http');
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
const url = `http://127.0.0.1:8101${api}`;
|
|
95
|
+
const controller = new AbortController();
|
|
96
|
+
const timeoutId = setTimeout(() => {
|
|
97
|
+
controller.abort();
|
|
98
|
+
reject(new Error(`Request timed out after ${timeout / 1000} seconds`));
|
|
99
|
+
}, timeout).unref();
|
|
100
|
+
const req = http.get(url, { signal: controller.signal }, (res) => {
|
|
101
|
+
let data = '';
|
|
102
|
+
if (res.statusCode !== 200) {
|
|
103
|
+
clearTimeout(timeoutId);
|
|
104
|
+
res.resume();
|
|
105
|
+
req.destroy();
|
|
106
|
+
reject(new Error(`Failed to fetch data. Status code: ${res.statusCode}`));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
res.on('data', (chunk) => {
|
|
110
|
+
data += chunk;
|
|
111
|
+
});
|
|
112
|
+
res.on('end', () => {
|
|
113
|
+
clearTimeout(timeoutId);
|
|
114
|
+
try {
|
|
115
|
+
const jsonData = JSON.parse(data);
|
|
116
|
+
resolve(jsonData);
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
reject(new Error(`Failed to parse response JSON: ${error instanceof Error ? error.message : error}`));
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
req.on('error', (error) => {
|
|
124
|
+
clearTimeout(timeoutId);
|
|
125
|
+
reject(new Error(`Request failed: ${error instanceof Error ? error.message : error}`));
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
async function postShelly(api, data, timeout = 60000) {
|
|
130
|
+
const http = await import('node:http');
|
|
131
|
+
return new Promise((resolve, reject) => {
|
|
132
|
+
const url = `http://127.0.0.1:8101${api}`;
|
|
133
|
+
const controller = new AbortController();
|
|
134
|
+
const timeoutId = setTimeout(() => {
|
|
135
|
+
controller.abort();
|
|
136
|
+
reject(new Error(`Request timed out after ${timeout / 1000} seconds`));
|
|
137
|
+
}, timeout).unref();
|
|
138
|
+
const jsonData = JSON.stringify(data);
|
|
139
|
+
const options = {
|
|
140
|
+
method: 'POST',
|
|
141
|
+
headers: {
|
|
142
|
+
'Content-Type': 'application/json',
|
|
143
|
+
'Content-Length': Buffer.byteLength(jsonData),
|
|
144
|
+
},
|
|
145
|
+
signal: controller.signal,
|
|
146
|
+
};
|
|
147
|
+
const req = http.request(url, options, (res) => {
|
|
148
|
+
let responseData = '';
|
|
149
|
+
if (res.statusCode && res.statusCode >= 300) {
|
|
150
|
+
clearTimeout(timeoutId);
|
|
151
|
+
res.resume();
|
|
152
|
+
req.destroy();
|
|
153
|
+
return reject(new Error(`Failed to post data. Status code: ${res.statusCode}`));
|
|
154
|
+
}
|
|
155
|
+
res.on('data', (chunk) => {
|
|
156
|
+
responseData += chunk;
|
|
157
|
+
});
|
|
158
|
+
res.on('end', () => {
|
|
159
|
+
clearTimeout(timeoutId);
|
|
160
|
+
try {
|
|
161
|
+
const jsonResponse = JSON.parse(responseData);
|
|
162
|
+
resolve(jsonResponse);
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
reject(new Error(`Failed to parse response JSON: ${err instanceof Error ? err.message : err}`));
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
req.on('error', (error) => {
|
|
170
|
+
clearTimeout(timeoutId);
|
|
171
|
+
reject(new Error(`Request failed: ${error instanceof Error ? error.message : error}`));
|
|
172
|
+
});
|
|
173
|
+
req.write(jsonData);
|
|
174
|
+
req.end();
|
|
175
|
+
});
|
|
176
|
+
}
|
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.fed77626.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.fed77626.js.map": "./static/js/main.fed77626.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.fed77626.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.fed77626.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>
|