matterbridge 1.2.8 → 1.2.10
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 +25 -1
- package/README.md +4 -1
- package/dist/matterbridge.d.ts +43 -20
- package/dist/matterbridge.d.ts.map +1 -1
- package/dist/matterbridge.js +222 -165
- package/dist/matterbridge.js.map +1 -1
- package/dist/matterbridgeDevice.d.ts +25 -11
- package/dist/matterbridgeDevice.d.ts.map +1 -1
- package/dist/matterbridgeDevice.js +19 -3
- package/dist/matterbridgeDevice.js.map +1 -1
- package/frontend/build/asset-manifest.json +3 -3
- package/frontend/build/index.html +1 -1
- package/frontend/build/static/js/{main.90cbbf6e.js → main.cf64bc64.js} +3 -3
- package/frontend/build/static/js/main.cf64bc64.js.map +1 -0
- package/package.json +7 -7
- package/TODO.md +0 -3
- package/frontend/build/static/js/main.90cbbf6e.js.map +0 -1
- package/matterbridge.service +0 -17
- /package/frontend/build/static/js/{main.90cbbf6e.js.LICENSE.txt → main.cf64bc64.js.LICENSE.txt} +0 -0
package/dist/matterbridge.js
CHANGED
|
@@ -26,6 +26,7 @@ import { AnsiLogger, BRIGHT, RESET, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugSt
|
|
|
26
26
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
27
27
|
import { promises as fs } from 'fs';
|
|
28
28
|
import { exec, spawn } from 'child_process';
|
|
29
|
+
import https from 'https';
|
|
29
30
|
import EventEmitter from 'events';
|
|
30
31
|
import express from 'express';
|
|
31
32
|
import os from 'os';
|
|
@@ -81,6 +82,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
81
82
|
matterbridgeVersion = '';
|
|
82
83
|
matterbridgeLatestVersion = '';
|
|
83
84
|
bridgeMode = '';
|
|
85
|
+
restartMode = '';
|
|
84
86
|
debugEnabled = false;
|
|
85
87
|
port = 5540;
|
|
86
88
|
log;
|
|
@@ -127,9 +129,11 @@ export class Matterbridge extends EventEmitter {
|
|
|
127
129
|
*
|
|
128
130
|
* @returns A Promise that resolves when the initialization is complete.
|
|
129
131
|
*/
|
|
130
|
-
async
|
|
132
|
+
async startExtension(dataPath, debugEnabled, extensionVersion, port = 5560) {
|
|
133
|
+
// Set the bridge mode
|
|
134
|
+
this.bridgeMode = 'bridge';
|
|
131
135
|
// Set the first port to use
|
|
132
|
-
this.port =
|
|
136
|
+
this.port = port;
|
|
133
137
|
// Set Matterbridge logger
|
|
134
138
|
this.debugEnabled = debugEnabled;
|
|
135
139
|
this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logDebug: this.debugEnabled });
|
|
@@ -140,6 +144,19 @@ export class Matterbridge extends EventEmitter {
|
|
|
140
144
|
this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, 'node_storage'), logging: false });
|
|
141
145
|
this.log.debug('Creating node storage context for matterbridge: matterbridge');
|
|
142
146
|
this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
|
|
147
|
+
const plugin = {
|
|
148
|
+
path: '',
|
|
149
|
+
type: 'DynamicPlatform',
|
|
150
|
+
name: 'MatterbridgeExtension',
|
|
151
|
+
version: '1.0.0',
|
|
152
|
+
description: 'Matterbridge extension',
|
|
153
|
+
author: 'https://github.com/Luligu',
|
|
154
|
+
enabled: false,
|
|
155
|
+
registeredDevices: 0,
|
|
156
|
+
addedDevices: 0,
|
|
157
|
+
};
|
|
158
|
+
this.registeredPlugins.push(plugin);
|
|
159
|
+
await this.nodeContext?.set('plugins', this.getBaseRegisteredPlugins());
|
|
143
160
|
// Log system info and create .matterbridge directory
|
|
144
161
|
await this.logNodeAndSystemInfo();
|
|
145
162
|
this.matterbridgeDirectory = dataPath;
|
|
@@ -148,14 +165,16 @@ export class Matterbridge extends EventEmitter {
|
|
|
148
165
|
Logger.format = Format.ANSI;
|
|
149
166
|
// Start the storage and create matterbridgeContext
|
|
150
167
|
await this.startStorage('json', path.join(this.matterbridgeDirectory, 'matterbridge.json'));
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
168
|
+
if (!this.storageManager)
|
|
169
|
+
return false;
|
|
170
|
+
this.matterbridgeContext = await this.createCommissioningServerContext('Matterbridge', 'Matterbridge zigbee2MQTT', DeviceTypes.AGGREGATOR.code, 0xfff1, 'Matterbridge', 0x8000, 'zigbee2MQTT Matter extension');
|
|
171
|
+
if (!this.matterbridgeContext)
|
|
172
|
+
return false;
|
|
154
173
|
await this.matterbridgeContext.set('softwareVersion', 1);
|
|
155
174
|
await this.matterbridgeContext.set('softwareVersionString', this.matterbridgeVersion);
|
|
156
|
-
await this.matterbridgeContext.set('hardwareVersion',
|
|
157
|
-
await this.matterbridgeContext.set('hardwareVersionString',
|
|
158
|
-
this.createMatterServer(this.storageManager);
|
|
175
|
+
await this.matterbridgeContext.set('hardwareVersion', 1);
|
|
176
|
+
await this.matterbridgeContext.set('hardwareVersionString', extensionVersion); // Update with the extension version
|
|
177
|
+
this.matterServer = this.createMatterServer(this.storageManager);
|
|
159
178
|
this.log.debug(`Creating commissioning server for ${plg}Matterbridge${db}`);
|
|
160
179
|
this.commissioningServer = await this.createCommisioningServer(this.matterbridgeContext, 'Matterbridge');
|
|
161
180
|
this.log.debug(`Creating matter aggregator for ${plg}Matterbridge${db}`);
|
|
@@ -163,24 +182,38 @@ export class Matterbridge extends EventEmitter {
|
|
|
163
182
|
this.log.debug('Adding matterbridge aggregator to commissioning server');
|
|
164
183
|
this.commissioningServer.addDevice(this.matterAggregator);
|
|
165
184
|
this.log.debug('Adding matterbridge commissioning server to matter server');
|
|
166
|
-
await this.matterServer
|
|
167
|
-
this.log.debug(`Setting reachability to true for ${plg}Matterbridge${db}`);
|
|
168
|
-
this.commissioningServer.setReachability(true);
|
|
169
|
-
this.log.debug('Starting matter server...');
|
|
185
|
+
await this.matterServer.addCommissioningServer(this.commissioningServer, { uniqueStorageKey: 'Matterbridge' });
|
|
170
186
|
await this.startMatterServer();
|
|
171
187
|
this.log.info('Matter server started');
|
|
172
188
|
await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
|
|
189
|
+
// Set reachability to true and trigger event after 60 seconds
|
|
190
|
+
setTimeout(() => {
|
|
191
|
+
this.log.info(`*Setting reachability to true for ${plg}Matterbridge${db}`);
|
|
192
|
+
if (this.commissioningServer)
|
|
193
|
+
this.setCommissioningServerReachability(this.commissioningServer, true);
|
|
194
|
+
if (this.matterAggregator)
|
|
195
|
+
this.setAggregatorReachability(this.matterAggregator, true);
|
|
196
|
+
}, 60 * 1000);
|
|
197
|
+
return this.commissioningServer.isCommissioned();
|
|
173
198
|
}
|
|
174
199
|
/**
|
|
175
200
|
* Close the Matterbridge instance as extension for zigbee2mqtt.
|
|
176
201
|
*
|
|
177
202
|
* @returns A Promise that resolves when the initialization is complete.
|
|
178
203
|
*/
|
|
179
|
-
async
|
|
204
|
+
async stopExtension() {
|
|
180
205
|
// Closing matter
|
|
181
206
|
await this.stopMatter();
|
|
207
|
+
// Clearing the session manager
|
|
208
|
+
// this.matterbridgeContext?.createContext('SessionManager').clear();
|
|
182
209
|
// Closing storage
|
|
183
210
|
await this.stopStorage();
|
|
211
|
+
this.log.info('Matter server stopped');
|
|
212
|
+
}
|
|
213
|
+
isExtensionCommissioned() {
|
|
214
|
+
if (!this.commissioningServer)
|
|
215
|
+
return false;
|
|
216
|
+
return this.commissioningServer.isCommissioned();
|
|
184
217
|
}
|
|
185
218
|
/**
|
|
186
219
|
* Initializes the Matterbridge application.
|
|
@@ -220,6 +253,11 @@ export class Matterbridge extends EventEmitter {
|
|
|
220
253
|
}
|
|
221
254
|
// Set the first port to use
|
|
222
255
|
this.port = getIntParameter('port') ?? 5540;
|
|
256
|
+
// Set the restart mode
|
|
257
|
+
if (hasParameter('service'))
|
|
258
|
+
this.restartMode = 'service';
|
|
259
|
+
if (hasParameter('docker'))
|
|
260
|
+
this.restartMode = 'docker';
|
|
223
261
|
// Set Matterbridge logger
|
|
224
262
|
if (hasParameter('debug'))
|
|
225
263
|
this.debugEnabled = true;
|
|
@@ -254,7 +292,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
254
292
|
await this.logNodeAndSystemInfo();
|
|
255
293
|
this.log.info(
|
|
256
294
|
// eslint-disable-next-line max-len
|
|
257
|
-
`Matterbridge version ${this.matterbridgeVersion} mode ${hasParameter('bridge') ? 'bridge' : ''}${hasParameter('childbridge') ? 'childbridge' : ''}${hasParameter('controller') ? 'controller' : ''}
|
|
295
|
+
`Matterbridge version ${this.matterbridgeVersion} mode ${hasParameter('bridge') ? 'bridge' : ''}${hasParameter('childbridge') ? 'childbridge' : ''}${hasParameter('controller') ? 'controller' : ''} ` +
|
|
296
|
+
`${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}running on ${this.systemInformation.osType} ${this.systemInformation.osRelease} ${this.systemInformation.osPlatform} ${this.systemInformation.osArch}`);
|
|
258
297
|
// Check node version and throw error
|
|
259
298
|
requireMinNodeVersion(18);
|
|
260
299
|
// Register SIGINT SIGTERM signal handlers
|
|
@@ -582,6 +621,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
582
621
|
this.log.info(message);
|
|
583
622
|
process.removeAllListeners('SIGINT');
|
|
584
623
|
process.removeAllListeners('SIGTERM');
|
|
624
|
+
this.log.debug('All listeners removed');
|
|
585
625
|
// Calling the shutdown functions with a reason
|
|
586
626
|
for (const plugin of this.registeredPlugins) {
|
|
587
627
|
if (!plugin.enabled)
|
|
@@ -637,11 +677,13 @@ export class Matterbridge extends EventEmitter {
|
|
|
637
677
|
if (this.expressServer) {
|
|
638
678
|
this.expressServer.close();
|
|
639
679
|
this.expressServer = undefined;
|
|
680
|
+
this.log.debug('Express server closed successfully');
|
|
640
681
|
}
|
|
641
682
|
// Remove listeners
|
|
642
683
|
if (this.expressApp) {
|
|
643
684
|
this.expressApp.removeAllListeners();
|
|
644
685
|
this.expressApp = undefined;
|
|
686
|
+
this.log.debug('Frontend closed successfully');
|
|
645
687
|
}
|
|
646
688
|
// Close the WebSocket server
|
|
647
689
|
if (this.webSocketServer) {
|
|
@@ -715,20 +757,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
715
757
|
//cleanupTimeout1.unref();
|
|
716
758
|
}
|
|
717
759
|
}
|
|
718
|
-
/**
|
|
719
|
-
* Sets the reachable attribute of a device.
|
|
720
|
-
*
|
|
721
|
-
* @param device - The device for which to set the reachable attribute.
|
|
722
|
-
* @param reachable - The value to set for the reachable attribute.
|
|
723
|
-
*/
|
|
724
|
-
setReachableAttribute(device, reachable) {
|
|
725
|
-
const basicInformationCluster = device.getClusterServer(BasicInformationCluster);
|
|
726
|
-
if (!basicInformationCluster) {
|
|
727
|
-
this.log.error('setReachableAttribute BasicInformationCluster needs to be set!');
|
|
728
|
-
return;
|
|
729
|
-
}
|
|
730
|
-
basicInformationCluster.setReachableAttribute(reachable);
|
|
731
|
-
}
|
|
732
760
|
/**
|
|
733
761
|
* Adds a device to the Matterbridge.
|
|
734
762
|
* @param pluginName - The name of the plugin.
|
|
@@ -824,7 +852,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
824
852
|
return;
|
|
825
853
|
}
|
|
826
854
|
if (this.bridgeMode === 'childbridge' && !plugin.connected) {
|
|
827
|
-
this.log.
|
|
855
|
+
this.log.info(`Removing bridged device ${dev}${device.deviceName}${wr} (${dev}${device.name}${wr}) plugin ${plg}${pluginName}${wr} not connected`);
|
|
828
856
|
return;
|
|
829
857
|
}
|
|
830
858
|
// Remove the device from matterbridge aggregator in bridge mode
|
|
@@ -971,12 +999,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
971
999
|
return;
|
|
972
1000
|
}
|
|
973
1001
|
this.log.debug('Starting matterbridge in mode', this.bridgeMode);
|
|
974
|
-
this.createMatterServer(this.storageManager);
|
|
975
|
-
if (!this.matterServer) {
|
|
976
|
-
this.log.error('No matter server initialized');
|
|
977
|
-
await this.cleanup('No matter server initialized');
|
|
978
|
-
return;
|
|
979
|
-
}
|
|
1002
|
+
this.matterServer = this.createMatterServer(this.storageManager);
|
|
980
1003
|
this.log.debug('***Starting startMatterbridge interval for Matterbridge');
|
|
981
1004
|
let failCount = 0;
|
|
982
1005
|
const startInterval = setInterval(async () => {
|
|
@@ -1152,7 +1175,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1152
1175
|
return Promise.reject(new Error(`Plugin ${plg}${plugin.name}${er} not loaded or no platform`));
|
|
1153
1176
|
}
|
|
1154
1177
|
if (plugin.started) {
|
|
1155
|
-
this.log.
|
|
1178
|
+
this.log.debug(`Plugin ${plg}${plugin.name}${db} already started`);
|
|
1156
1179
|
return Promise.resolve();
|
|
1157
1180
|
}
|
|
1158
1181
|
this.log.info(`Starting plugin ${plg}${plugin.name}${db} type ${typ}${plugin.type}${db}`);
|
|
@@ -1292,12 +1315,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1292
1315
|
return;
|
|
1293
1316
|
}
|
|
1294
1317
|
this.log.debug('Starting matterbridge in mode', this.bridgeMode);
|
|
1295
|
-
this.createMatterServer(this.storageManager);
|
|
1296
|
-
if (!this.matterServer) {
|
|
1297
|
-
this.log.error('No matter server initialized');
|
|
1298
|
-
await this.cleanup('No matter server initialized');
|
|
1299
|
-
return;
|
|
1300
|
-
}
|
|
1318
|
+
this.matterServer = this.createMatterServer(this.storageManager);
|
|
1301
1319
|
this.log.info('Creating matter commissioning controller');
|
|
1302
1320
|
this.commissioningController = new CommissioningController({
|
|
1303
1321
|
autoConnect: false,
|
|
@@ -1454,12 +1472,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1454
1472
|
return;
|
|
1455
1473
|
}
|
|
1456
1474
|
this.log.debug('Starting matterbridge in mode', this.bridgeMode);
|
|
1457
|
-
this.createMatterServer(this.storageManager);
|
|
1458
|
-
if (!this.matterServer) {
|
|
1459
|
-
this.log.error('No matter server initialized');
|
|
1460
|
-
await this.cleanup('No matter server initialized');
|
|
1461
|
-
return;
|
|
1462
|
-
}
|
|
1475
|
+
this.matterServer = this.createMatterServer(this.storageManager);
|
|
1463
1476
|
if (this.bridgeMode === 'bridge') {
|
|
1464
1477
|
// Plugins are loaded by loadPlugin on startup and plugin.loaded is set to true
|
|
1465
1478
|
// Plugins are started and configured by callback when Matterbridge is commissioned
|
|
@@ -1503,22 +1516,17 @@ export class Matterbridge extends EventEmitter {
|
|
|
1503
1516
|
this.commissioningServer.addDevice(this.matterAggregator);
|
|
1504
1517
|
this.log.debug('Adding matterbridge commissioning server to matter server');
|
|
1505
1518
|
await this.matterServer?.addCommissioningServer(this.commissioningServer, { uniqueStorageKey: 'Matterbridge' });
|
|
1506
|
-
this.log.debug(`Setting reachability to true for ${plg}Matterbridge${db}`);
|
|
1507
|
-
this.commissioningServer.setReachability(true);
|
|
1508
|
-
this.log.debug('Starting matter server...');
|
|
1509
1519
|
await this.startMatterServer();
|
|
1510
1520
|
this.log.info('Matter server started');
|
|
1511
1521
|
await this.showCommissioningQRCode(this.commissioningServer, this.matterbridgeContext, this.nodeContext, 'Matterbridge');
|
|
1512
1522
|
//if (hasParameter('advertise')) await this.commissioningServer.advertise();
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
}, 30 * 1000);
|
|
1521
|
-
*/
|
|
1523
|
+
setTimeout(() => {
|
|
1524
|
+
this.log.info(`*Setting reachability to true for ${plg}Matterbridge${db}`);
|
|
1525
|
+
if (this.commissioningServer)
|
|
1526
|
+
this.setCommissioningServerReachability(this.commissioningServer, true);
|
|
1527
|
+
if (this.matterAggregator)
|
|
1528
|
+
this.setAggregatorReachability(this.matterAggregator, true);
|
|
1529
|
+
}, 60 * 1000);
|
|
1522
1530
|
}, 1000);
|
|
1523
1531
|
}
|
|
1524
1532
|
if (this.bridgeMode === 'childbridge') {
|
|
@@ -1555,6 +1563,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1555
1563
|
plugin.commissioningServer = await this.createCommisioningServer(plugin.storageContext, plugin.name);
|
|
1556
1564
|
this.log.debug(`Adding device ${dev}${registeredDevice.device.name}${db} to commissioning server for plugin ${plg}${plugin.name}${db}`);
|
|
1557
1565
|
plugin.commissioningServer.addDevice(registeredDevice.device);
|
|
1566
|
+
if (!plugin.device)
|
|
1567
|
+
plugin.device = registeredDevice.device;
|
|
1558
1568
|
}
|
|
1559
1569
|
this.log.debug(`Adding commissioning server to matter server for plugin ${plg}${plugin.name}${db}`);
|
|
1560
1570
|
await this.matterServer?.addCommissioningServer(plugin.commissioningServer, { uniqueStorageKey: plugin.name });
|
|
@@ -1595,21 +1605,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
1595
1605
|
return;
|
|
1596
1606
|
clearInterval(startMatterInterval);
|
|
1597
1607
|
this.log.info('Starting matter server...');
|
|
1598
|
-
// Setting reachability to true
|
|
1599
|
-
this.registeredPlugins.forEach((plugin) => {
|
|
1600
|
-
if (!plugin.enabled)
|
|
1601
|
-
return;
|
|
1602
|
-
this.log.debug(`Setting reachability to true for ${plg}${plugin.name}${db}`);
|
|
1603
|
-
plugin.commissioningServer?.setReachability(true);
|
|
1604
|
-
this.registeredDevices.forEach((registeredDevice) => {
|
|
1605
|
-
if (registeredDevice.plugin === plugin.name) {
|
|
1606
|
-
if (plugin.type === 'AccessoryPlatform')
|
|
1607
|
-
this.setReachableAttribute(registeredDevice.device, true);
|
|
1608
|
-
if (plugin.type === 'DynamicPlatform')
|
|
1609
|
-
registeredDevice.device.setBridgedDeviceReachability(true);
|
|
1610
|
-
}
|
|
1611
|
-
});
|
|
1612
|
-
});
|
|
1613
1608
|
await this.startMatterServer();
|
|
1614
1609
|
this.log.info('Matter server started');
|
|
1615
1610
|
for (const plugin of this.registeredPlugins) {
|
|
@@ -1628,6 +1623,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
1628
1623
|
continue;
|
|
1629
1624
|
}
|
|
1630
1625
|
await this.showCommissioningQRCode(plugin.commissioningServer, plugin.storageContext, plugin.nodeContext, plugin.name);
|
|
1626
|
+
// Setting reachability to true
|
|
1627
|
+
this.log.info(`*Setting reachability to true for ${plg}${plugin.name}${db}`);
|
|
1628
|
+
if (plugin.commissioningServer)
|
|
1629
|
+
this.setCommissioningServerReachability(plugin.commissioningServer, true);
|
|
1630
|
+
if (plugin.type === 'AccessoryPlatform' && plugin.device)
|
|
1631
|
+
this.setDeviceReachability(plugin.device, true);
|
|
1632
|
+
if (plugin.type === 'DynamicPlatform' && plugin.aggregator)
|
|
1633
|
+
this.setAggregatorReachability(plugin.aggregator, true);
|
|
1631
1634
|
}
|
|
1632
1635
|
Logger.defaultLogLevel = this.debugEnabled ? Level.DEBUG : Level.INFO;
|
|
1633
1636
|
//clearInterval(startMatterInterval);
|
|
@@ -1644,7 +1647,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1644
1647
|
await this.cleanup('No matter server initialized');
|
|
1645
1648
|
return;
|
|
1646
1649
|
}
|
|
1647
|
-
this.log.debug('Starting matter server');
|
|
1650
|
+
this.log.debug('Starting matter server...');
|
|
1648
1651
|
await this.matterServer.start();
|
|
1649
1652
|
this.log.debug('Started matter server');
|
|
1650
1653
|
}
|
|
@@ -1723,8 +1726,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1723
1726
|
if (!commissioningServer.isCommissioned()) {
|
|
1724
1727
|
this.log.info(`***The commissioning server on port ${commissioningServer.getPort()} for ${plg}${pluginName}${nf} is not commissioned. Pair it scanning the QR code ...`);
|
|
1725
1728
|
const { qrPairingCode, manualPairingCode } = commissioningServer.getPairingCode();
|
|
1726
|
-
storageContext.set('qrPairingCode', qrPairingCode);
|
|
1727
|
-
storageContext.set('manualPairingCode', manualPairingCode);
|
|
1729
|
+
await storageContext.set('qrPairingCode', qrPairingCode);
|
|
1730
|
+
await storageContext.set('manualPairingCode', manualPairingCode);
|
|
1728
1731
|
await nodeContext.set('qrPairingCode', qrPairingCode);
|
|
1729
1732
|
await nodeContext.set('manualPairingCode', manualPairingCode);
|
|
1730
1733
|
const QrCode = new QrCodeSchema();
|
|
@@ -1764,6 +1767,49 @@ export class Matterbridge extends EventEmitter {
|
|
|
1764
1767
|
}
|
|
1765
1768
|
return plugin;
|
|
1766
1769
|
}
|
|
1770
|
+
/**
|
|
1771
|
+
* Sets the reachability of a commissioning server and trigger.
|
|
1772
|
+
*
|
|
1773
|
+
* @param {CommissioningServer} commissioningServer - The commissioning server to set the reachability for.
|
|
1774
|
+
* @param {boolean} reachable - The new reachability status.
|
|
1775
|
+
*/
|
|
1776
|
+
setCommissioningServerReachability(commissioningServer, reachable) {
|
|
1777
|
+
const basicInformationCluster = commissioningServer?.getRootClusterServer(BasicInformationCluster);
|
|
1778
|
+
if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
|
|
1779
|
+
basicInformationCluster.setReachableAttribute(reachable);
|
|
1780
|
+
if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent)
|
|
1781
|
+
basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
|
|
1782
|
+
}
|
|
1783
|
+
/**
|
|
1784
|
+
* Sets the reachability of the specified matter aggregator and its bridged devices and trigger.
|
|
1785
|
+
* @param {Aggregator} matterAggregator - The matter aggregator to set the reachability for.
|
|
1786
|
+
* @param {boolean} reachable - A boolean indicating the reachability status to set.
|
|
1787
|
+
*/
|
|
1788
|
+
setAggregatorReachability(matterAggregator, reachable) {
|
|
1789
|
+
const basicInformationCluster = matterAggregator.getClusterServer(BasicInformationCluster);
|
|
1790
|
+
if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
|
|
1791
|
+
basicInformationCluster.setReachableAttribute(reachable);
|
|
1792
|
+
if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent)
|
|
1793
|
+
basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
|
|
1794
|
+
matterAggregator.getBridgedDevices().forEach((device) => {
|
|
1795
|
+
this.log.debug(`*Setting reachability to true for bridged device: ${dev}${device.name}${nf}`);
|
|
1796
|
+
device.getClusterServer(BridgedDeviceBasicInformationCluster)?.setReachableAttribute(reachable);
|
|
1797
|
+
device.getClusterServer(BridgedDeviceBasicInformationCluster)?.triggerReachableChangedEvent({ reachableNewValue: reachable });
|
|
1798
|
+
});
|
|
1799
|
+
}
|
|
1800
|
+
/**
|
|
1801
|
+
* Sets the reachability of a device and trigger.
|
|
1802
|
+
*
|
|
1803
|
+
* @param {MatterbridgeDevice} device - The device to set the reachability for.
|
|
1804
|
+
* @param {boolean} reachable - The new reachability status of the device.
|
|
1805
|
+
*/
|
|
1806
|
+
setDeviceReachability(device, reachable) {
|
|
1807
|
+
const basicInformationCluster = device.getClusterServer(BasicInformationCluster);
|
|
1808
|
+
if (basicInformationCluster && basicInformationCluster.attributes.reachable !== undefined)
|
|
1809
|
+
basicInformationCluster.setReachableAttribute(reachable);
|
|
1810
|
+
if (basicInformationCluster && basicInformationCluster.triggerReachableChangedEvent)
|
|
1811
|
+
basicInformationCluster.triggerReachableChangedEvent({ reachableNewValue: reachable });
|
|
1812
|
+
}
|
|
1767
1813
|
/**
|
|
1768
1814
|
* Creates a matter commissioning server.
|
|
1769
1815
|
*
|
|
@@ -1814,9 +1860,16 @@ export class Matterbridge extends EventEmitter {
|
|
|
1814
1860
|
const info = commissioningServer.getActiveSessionInformation(fabricIndex);
|
|
1815
1861
|
let connected = false;
|
|
1816
1862
|
info.forEach((session) => {
|
|
1817
|
-
this.log.
|
|
1863
|
+
this.log.info(`***Active session changed on fabric ${fabricIndex} ${session.fabric?.rootVendorId}/${session.fabric?.label} for ${plg}${pluginName}${nf}`, debugStringify(session));
|
|
1818
1864
|
if (session.isPeerActive === true && session.secure === true && session.numberOfActiveSubscriptions >= 1) {
|
|
1819
|
-
|
|
1865
|
+
let controllerName = '';
|
|
1866
|
+
if (session.fabric?.rootVendorId === 4937)
|
|
1867
|
+
controllerName = 'AppleHome';
|
|
1868
|
+
if (session.fabric?.rootVendorId === 4362)
|
|
1869
|
+
controllerName = 'SmartThings';
|
|
1870
|
+
if (session.fabric?.rootVendorId === 4939)
|
|
1871
|
+
controllerName = 'HomeAssistant';
|
|
1872
|
+
this.log.info(`***Controller ${session.fabric?.rootVendorId}${controllerName !== '' ? '(' + controllerName + ')' : ''}/${session.fabric?.label} connected to ${plg}${pluginName}${nf} on session ${session.name}`);
|
|
1820
1873
|
connected = true;
|
|
1821
1874
|
}
|
|
1822
1875
|
});
|
|
@@ -1874,7 +1927,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1874
1927
|
const info = commissioningServer.getCommissionedFabricInformation(fabricIndex);
|
|
1875
1928
|
this.log.debug(`***Commissioning changed on fabric ${fabricIndex} for ${plg}${pluginName}${nf}`, debugStringify(info));
|
|
1876
1929
|
if (info.length === 0) {
|
|
1877
|
-
this.log.warn(`***Commissioning removed from fabric ${fabricIndex} for ${plg}${pluginName}${
|
|
1930
|
+
this.log.warn(`***Commissioning removed from fabric ${fabricIndex} for ${plg}${pluginName}${wr}. Resetting the commissioning server ...`);
|
|
1878
1931
|
await commissioningServer.factoryReset();
|
|
1879
1932
|
if (pluginName === 'Matterbridge') {
|
|
1880
1933
|
await this.matterbridgeContext?.clearAll();
|
|
@@ -1889,6 +1942,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1889
1942
|
}
|
|
1890
1943
|
}
|
|
1891
1944
|
}
|
|
1945
|
+
this.log.warn(`***Restart to activate the pairing for ${plg}${pluginName}${wr}`);
|
|
1892
1946
|
}
|
|
1893
1947
|
},
|
|
1894
1948
|
});
|
|
@@ -1902,8 +1956,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
1902
1956
|
*/
|
|
1903
1957
|
createMatterServer(storageManager) {
|
|
1904
1958
|
this.log.debug('Creating matter server');
|
|
1905
|
-
|
|
1959
|
+
const matterServer = new MatterServer(storageManager, { mdnsAnnounceInterface: undefined });
|
|
1906
1960
|
this.log.debug('Created matter server');
|
|
1961
|
+
return matterServer;
|
|
1907
1962
|
}
|
|
1908
1963
|
/**
|
|
1909
1964
|
* Creates a Matter Aggregator.
|
|
@@ -2249,18 +2304,25 @@ export class Matterbridge extends EventEmitter {
|
|
|
2249
2304
|
childProcess.stdout.on('data', (data) => {
|
|
2250
2305
|
const message = data.toString().trim();
|
|
2251
2306
|
//this.log.info('\n' + message);
|
|
2252
|
-
this.wssSendMessage('spawn', '
|
|
2307
|
+
this.wssSendMessage('Matterbridge:spawn', 'spawn', message);
|
|
2253
2308
|
});
|
|
2254
2309
|
}
|
|
2255
2310
|
if (childProcess.stderr) {
|
|
2256
2311
|
childProcess.stderr.on('data', (data) => {
|
|
2257
2312
|
const message = data.toString().trim();
|
|
2258
2313
|
//this.log.debug('\n' + message);
|
|
2259
|
-
this.wssSendMessage('spawn', '
|
|
2314
|
+
this.wssSendMessage('Matterbridge:spawn', 'spawn', message);
|
|
2260
2315
|
});
|
|
2261
2316
|
}
|
|
2262
2317
|
});
|
|
2263
2318
|
}
|
|
2319
|
+
/**
|
|
2320
|
+
* Sends a WebSocket message to all connected clients.
|
|
2321
|
+
*
|
|
2322
|
+
* @param {string} type - The type of the message: Matterbridge, Plugin, Device, ...
|
|
2323
|
+
* @param {string} subType - The subtype of the message: debug info warn error ....
|
|
2324
|
+
* @param {string} message - The content of the message.
|
|
2325
|
+
*/
|
|
2264
2326
|
wssSendMessage(type, subType, message) {
|
|
2265
2327
|
// Remove ANSI escape codes from the message
|
|
2266
2328
|
// eslint-disable-next-line no-control-regex
|
|
@@ -2280,17 +2342,44 @@ export class Matterbridge extends EventEmitter {
|
|
|
2280
2342
|
*/
|
|
2281
2343
|
async initializeFrontend(port = 8283) {
|
|
2282
2344
|
this.log.debug(`Initializing the frontend on port ${YELLOW}${port}${db} static ${UNDERLINE}${path.join(this.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
|
|
2283
|
-
|
|
2284
|
-
|
|
2345
|
+
const wssPort = 8284;
|
|
2346
|
+
const useHttps = false;
|
|
2347
|
+
//const wssHost = (useHttps ? 'wss://' : 'ws://') + `${os.hostname().toLowerCase()}:${wssPort}`;
|
|
2348
|
+
const wssHost = (useHttps ? 'wss://' : 'ws://') + `${this.systemInformation.ipv4Address}:${wssPort}`;
|
|
2349
|
+
if (!useHttps) {
|
|
2350
|
+
// Create a WebSocket server no certificate required
|
|
2351
|
+
this.webSocketServer = new WebSocketServer({ port: wssPort });
|
|
2352
|
+
this.log.info(`WebSocket server listening on ${UNDERLINE}${wssHost}${UNDERLINEOFF}${rs}`);
|
|
2353
|
+
}
|
|
2354
|
+
else {
|
|
2355
|
+
// Define the options for HTTPS server
|
|
2356
|
+
// openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout mykey.key -out mycert.pem -config openssl.cnf
|
|
2357
|
+
// For wss connect the browser to https://laptop5_luca:8284/ https://192.168.1.189/log and accept the certificate
|
|
2358
|
+
const serverOptions = {
|
|
2359
|
+
cert: await fs.readFile(path.join(this.rootDirectory, 'frontend/certificates/mycert.pem')), // Ensure the path is correct
|
|
2360
|
+
key: await fs.readFile(path.join(this.rootDirectory, 'frontend/certificates/mykey.key')), // Ensure the path is correct
|
|
2361
|
+
// cert: await fs.readFile(path.join(this.rootDirectory, 'frontend/certificates/laptop5_luca.pem')), // Ensure the path is correct
|
|
2362
|
+
// key: await fs.readFile(path.join(this.rootDirectory, 'frontend/certificates/laptop5_luca.key')), // Ensure the path is correct
|
|
2363
|
+
};
|
|
2364
|
+
// Create an HTTPS server
|
|
2365
|
+
const httpsServer = https.createServer(serverOptions);
|
|
2366
|
+
// Attach WebSocket server to HTTPS server
|
|
2367
|
+
this.webSocketServer = new WebSocketServer({ server: httpsServer });
|
|
2368
|
+
// Listen on a specific port
|
|
2369
|
+
httpsServer.listen(wssPort, () => {
|
|
2370
|
+
this.log.info(`WebSocket server listening on ${UNDERLINE}${wssHost}${UNDERLINEOFF}${rs}`);
|
|
2371
|
+
});
|
|
2372
|
+
}
|
|
2285
2373
|
this.webSocketServer.on('connection', (ws) => {
|
|
2286
|
-
this.log.
|
|
2374
|
+
this.log.info('WebSocketServer client connected');
|
|
2287
2375
|
this.log.setGlobalCallback(this.wssSendMessage.bind(this));
|
|
2288
2376
|
this.log.debug('WebSocketServer activated logger callback');
|
|
2377
|
+
this.wssSendMessage('Matterbridge', 'info', 'WebSocketServer client connected to Matterbridge');
|
|
2289
2378
|
ws.on('message', (message) => {
|
|
2290
|
-
this.log.
|
|
2379
|
+
this.log.info(`WebSocketServer received message => ${message}`);
|
|
2291
2380
|
});
|
|
2292
2381
|
ws.on('close', () => {
|
|
2293
|
-
this.log.
|
|
2382
|
+
this.log.info('WebSocketServer client disconnected');
|
|
2294
2383
|
if (this.webSocketServer?.clients.size === 0) {
|
|
2295
2384
|
this.log.setGlobalCallback(undefined);
|
|
2296
2385
|
this.log.debug('WebSocketServer deactivated logger callback');
|
|
@@ -2303,7 +2392,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2303
2392
|
// Serve React build directory
|
|
2304
2393
|
this.expressApp = express();
|
|
2305
2394
|
this.expressApp.use(express.static(path.join(this.rootDirectory, 'frontend/build')));
|
|
2306
|
-
// Endpoint to
|
|
2395
|
+
// Endpoint to validate login code
|
|
2307
2396
|
this.expressApp.post('/api/login', express.json(), async (req, res) => {
|
|
2308
2397
|
const { password } = req.body;
|
|
2309
2398
|
this.log.debug('The frontend sent /api/login', password);
|
|
@@ -2323,63 +2412,30 @@ export class Matterbridge extends EventEmitter {
|
|
|
2323
2412
|
res.json({ valid: false });
|
|
2324
2413
|
}
|
|
2325
2414
|
});
|
|
2326
|
-
// Endpoint to provide
|
|
2327
|
-
this.expressApp.get('/api/
|
|
2328
|
-
this.log.debug('The frontend sent /api/wsshost');
|
|
2329
|
-
res.json({ host: os.hostname() });
|
|
2330
|
-
});
|
|
2331
|
-
// Endpoint to provide port
|
|
2332
|
-
this.expressApp.get('/api/wssport', express.json(), async (req, res) => {
|
|
2333
|
-
this.log.debug('The frontend sent /api/wssport');
|
|
2334
|
-
res.json({ port: 8284 });
|
|
2335
|
-
});
|
|
2336
|
-
// Endpoint to provide manual pairing code
|
|
2337
|
-
this.expressApp.get('/api/pairing-code', (req, res) => {
|
|
2338
|
-
this.log.debug('The frontend sent /api/pairing-code');
|
|
2415
|
+
// Endpoint to provide settings
|
|
2416
|
+
this.expressApp.get('/api/settings', express.json(), async (req, res) => {
|
|
2339
2417
|
if (!this.matterbridgeContext) {
|
|
2340
|
-
this.log.error('/api/
|
|
2341
|
-
res.json([]);
|
|
2342
|
-
return;
|
|
2343
|
-
}
|
|
2344
|
-
try {
|
|
2345
|
-
const qrData = { qrPairingCode: this.matterbridgeContext.get('qrPairingCode'), manualPairingCode: this.matterbridgeContext.get('manualPairingCode') };
|
|
2346
|
-
res.json(qrData);
|
|
2347
|
-
}
|
|
2348
|
-
catch (error) {
|
|
2349
|
-
if (this.bridgeMode === 'bridge')
|
|
2350
|
-
this.log.error('qrPairingCode for /api/qr-code not found');
|
|
2418
|
+
this.log.error('/api/settings matterbridgeContext not found');
|
|
2351
2419
|
res.json({});
|
|
2352
|
-
}
|
|
2353
|
-
});
|
|
2354
|
-
// Endpoint to provide QR pairing code
|
|
2355
|
-
this.expressApp.get('/api/qr-code', (req, res) => {
|
|
2356
|
-
this.log.debug('The frontend sent /api/qr-code');
|
|
2357
|
-
if (!this.matterbridgeContext) {
|
|
2358
|
-
this.log.error('/api/qr-code matterbridgeContext not found');
|
|
2359
|
-
res.json([]);
|
|
2360
2420
|
return;
|
|
2361
2421
|
}
|
|
2422
|
+
let qrPairingCode = '';
|
|
2423
|
+
let manualPairingCode = '';
|
|
2362
2424
|
try {
|
|
2363
|
-
|
|
2364
|
-
|
|
2425
|
+
qrPairingCode = await this.matterbridgeContext.get('qrPairingCode');
|
|
2426
|
+
manualPairingCode = await this.matterbridgeContext.get('manualPairingCode');
|
|
2365
2427
|
}
|
|
2366
2428
|
catch (error) {
|
|
2367
2429
|
if (this.bridgeMode === 'bridge')
|
|
2368
|
-
this.log.error('
|
|
2430
|
+
this.log.error('pairingCode for /api/settings not found');
|
|
2369
2431
|
res.json({});
|
|
2370
2432
|
}
|
|
2371
|
-
});
|
|
2372
|
-
// Endpoint to provide system information
|
|
2373
|
-
this.expressApp.get('/api/system-info', (req, res) => {
|
|
2374
|
-
this.log.debug('The frontend sent /api/system-info');
|
|
2375
|
-
res.json(this.systemInformation);
|
|
2376
|
-
});
|
|
2377
|
-
// Endpoint to provide matterbridge information
|
|
2378
|
-
this.expressApp.get('/api/matterbridge-info', (req, res) => {
|
|
2379
|
-
this.log.debug('The frontend sent /api/matterbridge-info');
|
|
2380
2433
|
this.matterbridgeInformation.bridgeMode = this.bridgeMode;
|
|
2381
2434
|
this.matterbridgeInformation.debugEnabled = this.debugEnabled;
|
|
2382
|
-
|
|
2435
|
+
const response = { wssHost, qrPairingCode, manualPairingCode, systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
|
|
2436
|
+
this.log.debug('The frontend sent /api/settings');
|
|
2437
|
+
this.log.debug('Response:', debugStringify(response));
|
|
2438
|
+
res.json(response);
|
|
2383
2439
|
});
|
|
2384
2440
|
// Endpoint to provide plugins
|
|
2385
2441
|
this.expressApp.get('/api/plugins', (req, res) => {
|
|
@@ -2440,7 +2496,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2440
2496
|
}
|
|
2441
2497
|
catch (error) {
|
|
2442
2498
|
attributeValue = 'Unavailable';
|
|
2443
|
-
this.log.debug(
|
|
2499
|
+
this.log.debug(`GetLocal value ${error} in clusterServer: ${clusterServer.name}(${clusterServer.id}) attribute: ${key}(${value.id})`);
|
|
2444
2500
|
//console.log(error);
|
|
2445
2501
|
}
|
|
2446
2502
|
data.push({
|
|
@@ -2469,7 +2525,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2469
2525
|
// Handle the command setpassword from Settings
|
|
2470
2526
|
if (command === 'setpassword') {
|
|
2471
2527
|
const password = param.slice(1, -1); // Remove the first and last characters
|
|
2472
|
-
this.log.
|
|
2528
|
+
this.log.debug('setpassword', param, password);
|
|
2473
2529
|
await this.nodeContext?.set('password', password);
|
|
2474
2530
|
}
|
|
2475
2531
|
// Handle the command debugLevel from Settings
|
|
@@ -2504,15 +2560,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
2504
2560
|
// Handle the command update from Header
|
|
2505
2561
|
if (command === 'update') {
|
|
2506
2562
|
this.log.info('Updating matterbridge...');
|
|
2507
|
-
//this.wssSendMessage('cmd', 'update', 'Updating matterbridge');
|
|
2508
2563
|
try {
|
|
2509
2564
|
await this.spawnCommand('npm', ['install', '-g', 'matterbridge', '--loglevel=verbose']);
|
|
2510
2565
|
this.log.info('Matterbridge has been updated. Full restart required.');
|
|
2511
|
-
//this.wssSendMessage('cmd', 'update', 'Matterbridge has been updated. Full restart required.');
|
|
2512
2566
|
}
|
|
2513
2567
|
catch (error) {
|
|
2514
2568
|
this.log.error('Error updating matterbridge');
|
|
2515
|
-
//this.wssSendMessage('cmd', 'update', 'Error updating matterbridge');
|
|
2516
2569
|
res.json({ message: 'Command received' });
|
|
2517
2570
|
return;
|
|
2518
2571
|
}
|
|
@@ -2522,15 +2575,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
2522
2575
|
if (command === 'installplugin') {
|
|
2523
2576
|
param = param.replace(/\*/g, '\\');
|
|
2524
2577
|
this.log.info(`Installing plugin ${plg}${param}${db}...`);
|
|
2525
|
-
//this.wssSendMessage('cmd', 'installplugin', `Installing plugin ${param}`);
|
|
2526
2578
|
try {
|
|
2527
2579
|
await this.spawnCommand('npm', ['install', '-g', param, '--loglevel=verbose']);
|
|
2528
2580
|
this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
|
|
2529
|
-
//this.wssSendMessage('cmd', 'installplugin', `Plugin ${param} installed. Full restart required.`);
|
|
2530
2581
|
}
|
|
2531
2582
|
catch (error) {
|
|
2532
2583
|
this.log.error(`Error installing plugin ${plg}${param}${er}`);
|
|
2533
|
-
//this.wssSendMessage('cmd', 'installplugin', `Error installing plugin${param}`);
|
|
2534
2584
|
res.json({ message: 'Command received' });
|
|
2535
2585
|
return;
|
|
2536
2586
|
}
|
|
@@ -2653,9 +2703,26 @@ export class Matterbridge extends EventEmitter {
|
|
|
2653
2703
|
this.log.debug('The frontend sent *', req.url);
|
|
2654
2704
|
res.sendFile(path.join(this.rootDirectory, 'frontend/build/index.html'));
|
|
2655
2705
|
});
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2706
|
+
if (!useHttps) {
|
|
2707
|
+
// Listen on HTTP
|
|
2708
|
+
this.expressServer = this.expressApp.listen(port, () => {
|
|
2709
|
+
this.log.info(`The frontend is running on ${UNDERLINE}http://localhost:${port}${UNDERLINEOFF}${rs}`);
|
|
2710
|
+
});
|
|
2711
|
+
}
|
|
2712
|
+
else {
|
|
2713
|
+
// SSL certificate and private key paths
|
|
2714
|
+
const options = {
|
|
2715
|
+
cert: await fs.readFile(path.join(this.rootDirectory, 'frontend/certificates/laptop5_luca.pem')), // Ensure the path is correct
|
|
2716
|
+
key: await fs.readFile(path.join(this.rootDirectory, 'frontend/certificates/laptop5_luca.key')), // Ensure the path is correct
|
|
2717
|
+
};
|
|
2718
|
+
// Create HTTPS server
|
|
2719
|
+
const httpsServer = https.createServer(options, this.expressApp);
|
|
2720
|
+
// Specify the port to listen on, for example 443 for default HTTPS
|
|
2721
|
+
const PORT = 443;
|
|
2722
|
+
httpsServer.listen(PORT, () => {
|
|
2723
|
+
this.log.info(`The frontend is running on ${UNDERLINE}https://localhost:${PORT}${UNDERLINEOFF}${rs}`);
|
|
2724
|
+
});
|
|
2725
|
+
}
|
|
2659
2726
|
this.log.debug(`Frontend initialized on port ${YELLOW}${port}${db} static ${UNDERLINE}${path.join(this.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
|
|
2660
2727
|
}
|
|
2661
2728
|
/**
|
|
@@ -2699,6 +2766,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
2699
2766
|
attributes += `Humidity: ${clusterServer.getMeasuredValueAttribute() / 100}% `;
|
|
2700
2767
|
if (clusterServer.name === 'PressureMeasurement')
|
|
2701
2768
|
attributes += `Pressure: ${clusterServer.getMeasuredValueAttribute()} `;
|
|
2769
|
+
if (clusterServer.name === 'FlowMeasurement')
|
|
2770
|
+
attributes += `Pressure: ${clusterServer.getMeasuredValueAttribute()} `;
|
|
2702
2771
|
});
|
|
2703
2772
|
return attributes;
|
|
2704
2773
|
}
|
|
@@ -2715,34 +2784,22 @@ function restartProcess() {
|
|
|
2715
2784
|
stdio: 'inherit',
|
|
2716
2785
|
});
|
|
2717
2786
|
|
|
2787
|
+
// Handle errors
|
|
2788
|
+
newProcess.on('error', (err) => {
|
|
2789
|
+
console.error('Failed to start new process:', err);
|
|
2790
|
+
});
|
|
2791
|
+
|
|
2718
2792
|
// Unreference the new process so that the current process can exit
|
|
2719
2793
|
newProcess.unref();
|
|
2720
2794
|
|
|
2721
2795
|
// Exit the current process
|
|
2796
|
+
cleanup();
|
|
2722
2797
|
process.exit();
|
|
2723
2798
|
}
|
|
2724
2799
|
|
|
2725
|
-
import * as WebSocket from 'ws';
|
|
2726
|
-
|
|
2727
|
-
const wss = new WebSocket.Server({ port: 8080 });
|
|
2728
2800
|
|
|
2729
|
-
wss.on('connection', ws => {
|
|
2730
|
-
ws.on('message', message => {
|
|
2731
|
-
console.log(`Received message => ${message}`)
|
|
2732
|
-
});
|
|
2733
|
-
|
|
2734
|
-
// Send a message to the frontend
|
|
2735
|
-
ws.send('Hello from backend!');
|
|
2736
|
-
});
|
|
2737
|
-
|
|
2738
|
-
const ws = new WebSocket('ws://localhost:8080');
|
|
2739
|
-
|
|
2740
|
-
ws.onmessage = (event) => {
|
|
2741
|
-
console.log(`Received message => ${event.data}`);
|
|
2742
|
-
};
|
|
2743
|
-
|
|
2744
|
-
*/
|
|
2745
2801
|
/*
|
|
2802
|
+
How frontend was created
|
|
2746
2803
|
npx create-react-app matterbridge-frontend
|
|
2747
2804
|
cd matterbridge-frontend
|
|
2748
2805
|
npm install react-router-dom
|