matterbridge 2.1.6-dev.7 → 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 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.1.6] - 2025-02-20
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.2.
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 the nginx configuration file
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 8099;
30
- server_name ubuntu.local;
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
- add matterbridge to enabled sites
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.local:8099/matterbridge/
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
  }
@@ -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, nt } from './logger/export.js';
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, getNpmPackageVersion, getGlobalNodeModules } from './utils/network.js';
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';
@@ -55,7 +58,10 @@ export class Matterbridge extends EventEmitter {
55
58
  matterbridgeAdvertise: false,
56
59
  bridgeMode: '',
57
60
  restartMode: '',
58
- readOnly: hasParameter('readonly'),
61
+ readOnly: hasParameter('readonly') || hasParameter('shelly'),
62
+ shellyBoard: hasParameter('shelly'),
63
+ shellySysUpdate: false,
64
+ shellyMainUpdate: false,
59
65
  profile: getParameter('profile'),
60
66
  loggerLevel: "info",
61
67
  fileLogger: false,
@@ -101,6 +107,7 @@ export class Matterbridge extends EventEmitter {
101
107
  execRunningCount = 0;
102
108
  startMatterInterval;
103
109
  checkUpdateInterval;
110
+ checkUpdateTimeout;
104
111
  configureTimeout;
105
112
  reachabilityTimeout;
106
113
  sigintHandler;
@@ -564,17 +571,14 @@ export class Matterbridge extends EventEmitter {
564
571
  }
565
572
  if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
566
573
  await this.frontend.start(getIntParameter('frontend'));
567
- this.getMatterbridgeLatestVersion();
568
- for (const plugin of this.plugins) {
569
- this.getPluginLatestVersion(plugin);
570
- }
571
- this.checkUpdateInterval = setInterval(() => {
572
- this.getMatterbridgeLatestVersion();
573
- for (const plugin of this.plugins) {
574
- this.getPluginLatestVersion(plugin);
575
- }
576
- this.frontend.wssSendRefreshRequired();
577
- }, 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();
578
582
  if (hasParameter('test')) {
579
583
  this.bridgeMode = 'bridge';
580
584
  MatterbridgeEndpoint.bridgeMode = 'bridge';
@@ -811,37 +815,6 @@ export class Matterbridge extends EventEmitter {
811
815
  const cmdArgs = process.argv.slice(2).join(' ');
812
816
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
813
817
  }
814
- async getMatterbridgeLatestVersion() {
815
- getNpmPackageVersion('matterbridge')
816
- .then(async (version) => {
817
- this.matterbridgeLatestVersion = version;
818
- this.matterbridgeInformation.matterbridgeLatestVersion = version;
819
- await this.nodeContext?.set('matterbridgeLatestVersion', this.matterbridgeLatestVersion);
820
- if (this.matterbridgeVersion !== this.matterbridgeLatestVersion) {
821
- this.log.notice(`Matterbridge is out of date. Current version: ${this.matterbridgeVersion}. Latest version: ${this.matterbridgeLatestVersion}.`);
822
- }
823
- else {
824
- this.log.debug(`Matterbridge is up to date. Current version: ${this.matterbridgeVersion}. Latest version: ${this.matterbridgeLatestVersion}.`);
825
- }
826
- this.frontend.wssSendRefreshRequired();
827
- })
828
- .catch((error) => {
829
- this.log.warn(`Error getting Matterbridge latest version: ${error.message}`);
830
- });
831
- }
832
- async getPluginLatestVersion(plugin) {
833
- getNpmPackageVersion(plugin.name)
834
- .then((version) => {
835
- plugin.latestVersion = version;
836
- if (plugin.version !== plugin.latestVersion)
837
- this.log.notice(`The plugin ${plg}${plugin.name}${nt} is out of date. Current version: ${plugin.version}. Latest version: ${plugin.latestVersion}.`);
838
- else
839
- this.log.debug(`The plugin ${plg}${plugin.name}${db} is up to date. Current version: ${plugin.version}. Latest version: ${plugin.latestVersion}.`);
840
- })
841
- .catch((error) => {
842
- this.log.warn(`Error getting ${plg}${plugin.name}${er} latest version: ${error.message}`);
843
- });
844
- }
845
818
  createMatterLogger() {
846
819
  const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4, logLevel: "debug" });
847
820
  return (_level, formattedLog) => {
@@ -965,6 +938,11 @@ export class Matterbridge extends EventEmitter {
965
938
  this.startMatterInterval = undefined;
966
939
  this.log.debug('Start matter interval cleared');
967
940
  }
941
+ if (this.checkUpdateTimeout) {
942
+ clearInterval(this.checkUpdateTimeout);
943
+ this.checkUpdateTimeout = undefined;
944
+ this.log.debug('Check update timeout cleared');
945
+ }
968
946
  if (this.checkUpdateInterval) {
969
947
  clearInterval(this.checkUpdateInterval);
970
948
  this.checkUpdateInterval = undefined;
@@ -1672,11 +1650,18 @@ export class Matterbridge extends EventEmitter {
1672
1650
  };
1673
1651
  });
1674
1652
  }
1675
- setServerNodeReachability(serverNode, reachable) {
1653
+ async setServerNodeReachability(serverNode, reachable) {
1654
+ await serverNode.setStateOf(BasicInformationServer, { reachable });
1676
1655
  }
1677
- 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
+ }
1678
1661
  }
1679
- 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 });
1680
1665
  }
1681
1666
  getVendorIdName = (vendorId) => {
1682
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
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" width="1024" viewBox="0.7 0 86.6 24"><path fill="#4594D1" d="m82 15.5 2.4-6.6h-4.6l-2.3 6.6h-2.6l2.4-6.6h-4.7L70.4 15v.5h-3.7l4.8-13.3H67l-4.7 13.3h-4L63 2.2h-4.5l-4.7 13.3h-7.1c-1.1 0-1.7-.3-1.7-1l.1-.4 1-3H49l-1.7 4.5s3.3-1.3 4.4-1.8c1-.5 1.3-1.4 1.3-2.3 0-.8-.6-1.5-1.7-2-.8-.3-1.7-.4-2.8-.4h-1.8c-1.7 0-3 .4-4.3 1.1-1.3 1-2 2.1-2 3.7 0 .6.1 1.2.4 1.7h-4.3l1.4-4c.2-.5.4-1.1.4-1.5 0-.8-.8-1-1.7-1-1.2 0-2.3.4-3.3 1.2l-3.4 2.8 3.8-10.6H29l-5.4 15h2.6c.6 0 1.3-.2 1.8-.7L33 13l-1 2.7-.1 1c0 .6.5 1 1.4 1h27.3a4 4 0 0 0 1.9-.6c.3.4.8.5 1.6.5h5a4 4 0 0 0 1.9-.5c.3.4.8.5 1.4.5h1c-.6.4-1 .9-1.2 1.5a4.7 4.7 0 0 0-.5 2c0 .8.3 1.5.8 2 .6.7 1.4 1 2.4 1 1.7 0 3.1-.7 4.3-2 .8-1 1.6-2.5 2.3-4.5h3.1c1.4 0 2.3-.6 2.8-2h-5.2ZM75.2 22c-.5-.4-.7-.8-.7-1.4 0-.6.2-1.2.7-1.9.5-.6 1-1 1.6-1L75 22.2ZM22 5l1.5-2.9h-2.8c-1.2 0-1.9.5-1.9 1.6 0 .5.4 1.8 1.1 3.6A13 13 0 0 1 21 12c0 2.2-1.3 4-3.8 5a16 16 0 0 1-6.6 1.3 18 18 0 0 1-6.2-1C2 16.5.7 15 .7 13.3.7 10.3 3 9 7.7 9h6c-.2.6-.6 1.1-1.2 1.5-.6.3-1.2.5-2 .5h-1c-.9 0-1.7.1-2.4.5-.9.4-1.3 1-1.3 1.8 0 1 .6 1.7 1.8 2.3 1 .4 2 .6 3.1.6 1.4 0 2.6-.3 3.5-1 1-.6 1.6-1.6 1.6-3 0-.9-.4-2.1-1-3.8-.7-1.7-1-3-1-4C13.7 1.7 16.1.2 21 0h2c1.2 0 2.2.2 3.1.5 1.2.5 1.8 1.2 1.9 2.2 0 1-.5 1.8-1.5 2.5H22Z"/></svg>
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "files": {
3
3
  "main.css": "./static/css/main.cf25d33e.css",
4
- "main.js": "./static/js/main.82e3eb54.js",
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.82e3eb54.js.map": "./static/js/main.82e3eb54.js.map",
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.82e3eb54.js"
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.82e3eb54.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>
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>