matterbridge 1.6.8-dev.7 → 1.6.8-dev.9

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
@@ -13,12 +13,14 @@ It is also available the official Matterbridge Home Assistant plugin https://git
13
13
 
14
14
  Tamer (https://github.com/tammeryousef1006) has created the Matterbridge Discord group: https://discord.gg/QX58CDe6hd.
15
15
 
16
- ## [1.6.8-dev.7] - 2024-12-19
16
+ ## [1.6.8-dev.9] - 2024-12-21
17
17
 
18
18
  ### Added
19
19
 
20
- - [storage]: Added conversion from old matter storage to the new api format with fabrics, resumptionRecords, network, commissioning, operationalCredentials, acl and parts number.
20
+ - [storage]: Added conversion from old matter storage to the new api format with fabrics, resumptionRecords, network, commissioning, operationalCredentials, acl and parts number. The conversion is triggered every time you shutdown or restart matterbridge till the new storage has been used with matterbridge edge.
21
+ - [storage]: Added conversion for child endpoint numbers.
21
22
  - [package]: Update README.md and README-SERVICE.md to include instructions for using SSL on port 443.
23
+ - [platform]: Added checkEndpointNumbers() to detect endpoint numbers changes.
22
24
 
23
25
  ### Changed
24
26
 
@@ -137,6 +137,12 @@ export class Matterbridge extends EventEmitter {
137
137
  super();
138
138
  this.matterbridgeMessageHandler = wsMessageHandler.bind(this);
139
139
  }
140
+ getDevices() {
141
+ return this.devices.array();
142
+ }
143
+ getPlugins() {
144
+ return this.plugins.array();
145
+ }
140
146
  matterbridgeMessageHandler;
141
147
  static async loadInstance(initialize = false) {
142
148
  if (!Matterbridge.instance) {
@@ -990,7 +996,7 @@ export class Matterbridge extends EventEmitter {
990
996
  });
991
997
  this.webSocketServer = undefined;
992
998
  }
993
- if (hasParameter('convert') && this.edge === false && this.matterbridgeContext && ['updating...', 'restarting...', 'shutting down...'].includes(message)) {
999
+ if (!hasParameter('nostorageconversion') && this.edge === false && this.matterbridgeContext && ['updating...', 'restarting...', 'shutting down...'].includes(message)) {
994
1000
  await this.convertStorage(this.matterbridgeContext, 'Mattebridge');
995
1001
  }
996
1002
  await this.stopMatterServer();
@@ -1549,128 +1555,165 @@ export class Matterbridge extends EventEmitter {
1549
1555
  await this.matterbridgeContext.set('discriminator', this.discriminator);
1550
1556
  }
1551
1557
  async convertStorage(context, pluginName) {
1552
- const storageService = Environment.default.get(StorageService);
1553
- Environment.default.vars.set('path.root', path.join(this.matterbridgeDirectory, 'matterstorage' + (this.profile ? '.' + this.profile : '')));
1554
- const nodeStorage = await storageService.open('Matterbridge');
1555
- if ((await nodeStorage.createContext('persist').get('converted', false)) === true) {
1556
- this.log.info(`Matter node storage already converted to Matterbridge edge for ${plg}${pluginName}${nf}`);
1557
- return;
1558
- }
1559
- else {
1560
- this.log.notice(`Converting matter node storage to Matterbridge edge for ${plg}${pluginName}${nt}...`);
1561
- }
1562
- const fabricManagerContext = context.createContext('FabricManager');
1563
- const fabrics = (await fabricManagerContext.get('fabrics', []));
1564
- const nextFabricIndex = await fabricManagerContext.get('nextFabricIndex', 1);
1565
- const eventHandlerContext = context.createContext('EventHandler');
1566
- const sessionManagerContext = context.createContext('SessionManager');
1567
- const endpointStructureContext = context.createContext('EndpointStructure');
1568
- const generalCommissioningContext = context.createContext('Cluster-0-48');
1569
- const basicInformationContext = context.createContext('Cluster-0-40');
1570
- const fabricInfo = {};
1571
- const fabricInfoArray = [];
1572
- const nocArray = [];
1573
- const trcArray = [];
1574
- const aclArray = [];
1575
- this.log.info(`Found ${CYAN}${fabrics.length}${nf} fabrics (nextFabricIndex ${CYAN}${nextFabricIndex}${nf}) for ${plg}${pluginName}${nf}:`);
1576
- for (const fabric of fabrics) {
1577
- this.log.info(`- fabricIndex ${CYAN}${fabric.fabricIndex}${nf} fabricId ${CYAN}${fabric.fabricId}${nf} nodeId ${CYAN}${fabric.nodeId}${nf} rootNodeId ${CYAN}${fabric.rootNodeId}${nf} rootVendorId ${CYAN}${fabric.rootVendorId}${nf} label ${CYAN}${fabric.label}${nf}`);
1578
- fabricInfo[fabric.fabricIndex] = {
1579
- fabricIndex: fabric.fabricIndex,
1580
- fabricId: fabric.fabricId,
1581
- nodeId: fabric.nodeId,
1582
- rootNodeId: fabric.rootNodeId,
1583
- rootVendorId: fabric.rootVendorId,
1584
- label: fabric.label,
1585
- };
1586
- fabricInfoArray.push({
1587
- fabricIndex: fabric.fabricIndex,
1588
- fabricId: fabric.fabricId,
1589
- nodeId: fabric.nodeId,
1590
- vendorId: fabric.rootVendorId,
1591
- rootPublicKey: fabric.rootPublicKey,
1592
- label: fabric.label,
1593
- });
1594
- nocArray.push({ noc: fabric.operationalCert, icac: null, fabricIndex: fabric.fabricIndex });
1595
- trcArray.push('{\"__object__\":\"Uint8Array\",\"__value__\":\"' + Buffer.from(fabric.rootCert).toString('hex') + '\"}');
1596
- this.log.info(`- updating ACL for fabricIndex ${fabric.fabricIndex}:`, fabric.scopedClusterData);
1597
- const acl = fabric.scopedClusterData.get(0x1f)?.get('acl');
1598
- if (acl && acl.value.length > 0) {
1599
- aclArray.push(acl.value[0]);
1600
- this.log.info(`- ACL updated to ${debugStringify(acl.value)}${nf} for fabricIndex ${CYAN}${fabric.fabricIndex}${nf}`);
1558
+ try {
1559
+ const storageService = Environment.default.get(StorageService);
1560
+ Environment.default.vars.set('path.root', path.join(this.matterbridgeDirectory, 'matterstorage' + (this.profile ? '.' + this.profile : '')));
1561
+ const nodeStorage = await storageService.open('Matterbridge');
1562
+ if ((await nodeStorage.createContext('root').createContext('generalDiagnostics').get('rebootCount', -1)) >= 0) {
1563
+ this.log.info(`Matter node storage already converted to Matterbridge edge for ${plg}${pluginName}${nf}`);
1564
+ return;
1601
1565
  }
1602
1566
  else {
1603
- const defaultAcl = { fabricIndex: fabric.fabricIndex, privilege: 5, authMode: 2, subjects: [fabric.rootNodeId], targets: null };
1604
- aclArray.push(defaultAcl);
1605
- this.log.info(`- ACL updated to default ${debugStringify(defaultAcl)}${nf} for fabricIndex ${CYAN}${fabric.fabricIndex}${nf}`);
1606
- }
1607
- }
1608
- await nodeStorage.createContext('fabrics').set('fabrics', fabrics);
1609
- await nodeStorage.createContext('fabrics').set('nextFabricIndex', nextFabricIndex);
1610
- await nodeStorage.createContext('sessions').set('resumptionRecords', await sessionManagerContext.get('resumptionRecords', []));
1611
- await nodeStorage.createContext('events').set('lastEventNumber', await eventHandlerContext.get('lastEventNumber', 1));
1612
- await nodeStorage.createContext('root').set('__number__', 0);
1613
- await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').set('__number__', 1);
1614
- await nodeStorage.createContext('root').createContext('commissioning').set('enabled', true);
1615
- await nodeStorage.createContext('root').createContext('commissioning').set('commissioned', true);
1616
- await nodeStorage.createContext('root').createContext('commissioning').set('fabrics', fabricInfo);
1617
- await nodeStorage.createContext('root').createContext('operationalCredentials').set('commissionedFabrics', fabricInfoArray.length);
1618
- await nodeStorage.createContext('root').createContext('operationalCredentials').set('fabrics', fabricInfoArray);
1619
- await nodeStorage.createContext('root').createContext('operationalCredentials').set('nocs', nocArray);
1620
- await nodeStorage.createContext('root').createContext('operationalCredentials').set('trustedRootCertificates', trcArray);
1621
- await nodeStorage.createContext('root').createContext('accessControl').set('acl', aclArray);
1622
- await nodeStorage
1623
- .createContext('root')
1624
- .createContext('generalCommissioning')
1625
- .set('breadcrumb', await generalCommissioningContext.get('breadcrumb', BigInt(0)));
1626
- await nodeStorage
1627
- .createContext('root')
1628
- .createContext('basicInformation')
1629
- .set('location', await basicInformationContext.get('location', 'XX'));
1630
- await nodeStorage.createContext('root').createContext('network').set('ble', false);
1631
- await nodeStorage.createContext('root').createContext('network').set('operationalPort', 5540);
1632
- await nodeStorage.createContext('root').createContext('productDescription').set('productId', 0x8000);
1633
- await nodeStorage.createContext('root').createContext('productDescription').set('vendorId', 0xfff1);
1634
- for (const key of await endpointStructureContext.keys()) {
1635
- if (key === 'nextEndpointId') {
1636
- await nodeStorage.createContext('root').set('__nextNumber__', await endpointStructureContext.get(key));
1637
- continue;
1567
+ this.log.notice(`Converting matter node storage to Matterbridge edge for ${plg}${pluginName}${nt}...`);
1568
+ }
1569
+ const fabricManagerContext = context.createContext('FabricManager');
1570
+ const fabrics = (await fabricManagerContext.get('fabrics', []));
1571
+ const nextFabricIndex = await fabricManagerContext.get('nextFabricIndex', 0);
1572
+ const eventHandlerContext = context.createContext('EventHandler');
1573
+ const sessionManagerContext = context.createContext('SessionManager');
1574
+ const endpointStructureContext = context.createContext('EndpointStructure');
1575
+ const generalCommissioningContext = context.createContext('Cluster-0-48');
1576
+ const basicInformationContext = context.createContext('Cluster-0-40');
1577
+ const fabricInfo = {};
1578
+ const fabricInfoArray = [];
1579
+ const nocArray = [];
1580
+ const trcArray = [];
1581
+ const aclArray = [];
1582
+ this.log.info(`Found ${CYAN}${fabrics.length}${nf} fabrics (nextFabricIndex ${CYAN}${nextFabricIndex}${nf}) for ${plg}${pluginName}${nf}:`);
1583
+ if (fabrics.length === 0 || nextFabricIndex === 0) {
1584
+ this.log.notice(`If you want to try out matterbridge edge (beta) add -edge to the command line and pair it to your controller(s).`);
1585
+ return;
1638
1586
  }
1639
- const parts = key.split('-');
1640
- const number = await endpointStructureContext.get(key);
1641
- if (parts.length === 2) {
1642
- this.log.debug(`Converting Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.__number__:${number}`);
1643
- await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').set('__number__', number);
1644
- }
1645
- else if (parts.length === 3 && parts[2].startsWith('custom_')) {
1646
- this.log.debug(`Converting Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${parts[2].replace('custom_', '')}.__number__:${number}`);
1647
- await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').createContext('parts').createContext(parts[2].replace('custom_', '')).set('__number__', number);
1648
- }
1649
- else if (parts.length === 3 && parts[2].startsWith('unique_')) {
1650
- const device = this.devices.get(parts[2].replace('unique_', ''));
1651
- if (device && device.deviceName && device.maybeNumber) {
1652
- this.log.debug(`Converting Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${device.deviceName.replace(/[ .]/g, '')}.__number__:${device.maybeNumber}`);
1653
- await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').createContext('parts').createContext(device.deviceName.replace(/[ .]/g, '')).set('__number__', device.maybeNumber);
1654
- }
1655
- }
1656
- }
1657
- await nodeStorage.createContext('persist').set('converted', true);
1658
- await nodeStorage.createContext('persist').set('deviceName', await context.get('deviceName'));
1659
- await nodeStorage.createContext('persist').set('deviceType', await context.get('deviceType'));
1660
- await nodeStorage.createContext('persist').set('vendorId', await context.get('vendorId'));
1661
- await nodeStorage.createContext('persist').set('vendorName', await context.get('vendorName'));
1662
- await nodeStorage.createContext('persist').set('productId', await context.get('productId'));
1663
- await nodeStorage.createContext('persist').set('productName', await context.get('productName'));
1664
- await nodeStorage.createContext('persist').set('nodeLabel', await context.get('nodeLabel'));
1665
- await nodeStorage.createContext('persist').set('productLabel', await context.get('productLabel'));
1666
- await nodeStorage.createContext('persist').set('serialNumber', 'SN' + (await context.get('serialNumber')));
1667
- await nodeStorage.createContext('persist').set('uniqueId', await context.get('uniqueId'));
1668
- await nodeStorage.createContext('persist').set('softwareVersion', await context.get('softwareVersion'));
1669
- await nodeStorage.createContext('persist').set('softwareVersionString', await context.get('softwareVersionString'));
1670
- await nodeStorage.createContext('persist').set('hardwareVersion', await context.get('hardwareVersion'));
1671
- await nodeStorage.createContext('persist').set('hardwareVersionString', await context.get('hardwareVersionString'));
1672
- await context.set('converted', true);
1673
- this.log.notice(`Matter storage converted to Matterbridge edge for ${plg}${pluginName}${nt}`);
1587
+ for (const fabric of fabrics) {
1588
+ this.log.info(`- fabricIndex ${CYAN}${fabric.fabricIndex}${nf} fabricId ${CYAN}${fabric.fabricId}${nf} nodeId ${CYAN}${fabric.nodeId}${nf} rootNodeId ${CYAN}${fabric.rootNodeId}${nf} rootVendorId ${CYAN}${fabric.rootVendorId}${nf} label ${CYAN}${fabric.label}${nf}`);
1589
+ fabricInfo[fabric.fabricIndex] = {
1590
+ fabricIndex: fabric.fabricIndex,
1591
+ fabricId: fabric.fabricId,
1592
+ nodeId: fabric.nodeId,
1593
+ rootNodeId: fabric.rootNodeId,
1594
+ rootVendorId: fabric.rootVendorId,
1595
+ label: fabric.label,
1596
+ };
1597
+ fabricInfoArray.push({
1598
+ fabricIndex: fabric.fabricIndex,
1599
+ fabricId: fabric.fabricId,
1600
+ nodeId: fabric.nodeId,
1601
+ vendorId: fabric.rootVendorId,
1602
+ rootPublicKey: fabric.rootPublicKey,
1603
+ label: fabric.label,
1604
+ });
1605
+ nocArray.push({ noc: fabric.operationalCert, icac: null, fabricIndex: fabric.fabricIndex });
1606
+ trcArray.push('{\"__object__\":\"Uint8Array\",\"__value__\":\"' + Buffer.from(fabric.rootCert).toString('hex') + '\"}');
1607
+ this.log.info(`- updating ACL for fabricIndex ${fabric.fabricIndex}:`, fabric.scopedClusterData);
1608
+ const acl = fabric.scopedClusterData.get(0x1f)?.get('acl');
1609
+ if (acl && acl.value.length > 0) {
1610
+ aclArray.push(acl.value[0]);
1611
+ this.log.info(`- ACL updated to ${debugStringify(acl.value)}${nf} for fabricIndex ${CYAN}${fabric.fabricIndex}${nf}`);
1612
+ }
1613
+ else {
1614
+ const defaultAcl = { fabricIndex: fabric.fabricIndex, privilege: 5, authMode: 2, subjects: [fabric.rootNodeId], targets: null };
1615
+ aclArray.push(defaultAcl);
1616
+ this.log.info(`- ACL updated to default ${debugStringify(defaultAcl)}${nf} for fabricIndex ${CYAN}${fabric.fabricIndex}${nf}`);
1617
+ }
1618
+ }
1619
+ await nodeStorage.createContext('fabrics').set('fabrics', fabrics);
1620
+ await nodeStorage.createContext('fabrics').set('nextFabricIndex', nextFabricIndex);
1621
+ await nodeStorage.createContext('sessions').set('resumptionRecords', await sessionManagerContext.get('resumptionRecords', []));
1622
+ await nodeStorage.createContext('events').set('lastEventNumber', await eventHandlerContext.get('lastEventNumber', 1));
1623
+ await nodeStorage.createContext('root').set('__number__', 0);
1624
+ await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').set('__number__', 1);
1625
+ await nodeStorage.createContext('root').createContext('commissioning').set('enabled', true);
1626
+ await nodeStorage.createContext('root').createContext('commissioning').set('commissioned', true);
1627
+ await nodeStorage.createContext('root').createContext('commissioning').set('fabrics', fabricInfo);
1628
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('commissionedFabrics', fabricInfoArray.length);
1629
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('fabrics', fabricInfoArray);
1630
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('nocs', nocArray);
1631
+ await nodeStorage.createContext('root').createContext('operationalCredentials').set('trustedRootCertificates', trcArray);
1632
+ await nodeStorage.createContext('root').createContext('accessControl').set('acl', aclArray);
1633
+ await nodeStorage
1634
+ .createContext('root')
1635
+ .createContext('generalCommissioning')
1636
+ .set('breadcrumb', await generalCommissioningContext.get('breadcrumb', BigInt(0)));
1637
+ await nodeStorage
1638
+ .createContext('root')
1639
+ .createContext('basicInformation')
1640
+ .set('location', await basicInformationContext.get('location', 'XX'));
1641
+ await nodeStorage.createContext('root').createContext('network').set('ble', false);
1642
+ await nodeStorage.createContext('root').createContext('network').set('operationalPort', 5540);
1643
+ await nodeStorage.createContext('root').createContext('productDescription').set('productId', 0x8000);
1644
+ await nodeStorage.createContext('root').createContext('productDescription').set('vendorId', 0xfff1);
1645
+ for (const key of await endpointStructureContext.keys()) {
1646
+ if (key === 'nextEndpointId') {
1647
+ await nodeStorage.createContext('root').set('__nextNumber__', await endpointStructureContext.get(key));
1648
+ continue;
1649
+ }
1650
+ const parts = key.split('-');
1651
+ const number = await endpointStructureContext.get(key);
1652
+ if (parts.length === 2) {
1653
+ this.log.debug(`Converting bridge Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.__number__:${number}`);
1654
+ await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').set('__number__', number);
1655
+ }
1656
+ else if (parts.length === 3 && parts[2].startsWith('custom_')) {
1657
+ this.log.debug(`Converting custom Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${parts[2].replace('custom_', '').replace(/[ .]/g, '')}.__number__:${number}`);
1658
+ await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').createContext('parts').createContext(parts[2].replace('custom_', '').replace(/[ .]/g, '')).set('__number__', number);
1659
+ }
1660
+ else if (parts.length === 3 && parts[2].startsWith('unique_')) {
1661
+ const device = this.devices.get(parts[2].replace('unique_', ''));
1662
+ if (device && device.deviceName && device.maybeNumber) {
1663
+ this.log.debug(`Converting unique Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${device.deviceName.replace(/[ .]/g, '')}.__number__:${device.maybeNumber}`);
1664
+ await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').createContext('parts').createContext(device.deviceName.replace(/[ .]/g, '')).set('__number__', device.maybeNumber);
1665
+ }
1666
+ }
1667
+ else if (parts.length === 4 && parts[2].startsWith('unique_') && parts[3].startsWith('custom_')) {
1668
+ const device = this.devices.get(parts[2].replace('unique_', ''));
1669
+ if (device && device.deviceName && device.maybeNumber) {
1670
+ this.log.debug(`Converting unique Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${device.deviceName.replace(/[ .]/g, '')}.parts.${parts[3].replace('custom_', '').replace(/[ .]/g, '')}.__number__:${device.maybeNumber}`);
1671
+ await nodeStorage
1672
+ .createContext('root')
1673
+ .createContext('parts')
1674
+ .createContext('Matterbridge')
1675
+ .createContext('parts')
1676
+ .createContext(device.deviceName.replace(/[ .]/g, ''))
1677
+ .createContext('parts')
1678
+ .createContext(parts[3].replace('custom_', '').replace(/[ .]/g, ''))
1679
+ .set('__number__', device.maybeNumber);
1680
+ }
1681
+ }
1682
+ else if (parts.length === 4 && parts[2].startsWith('custom_') && parts[3].startsWith('custom_')) {
1683
+ this.log.debug(`Converting custom Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${parts[2].replace('custom_', '').replace(/[ .]/g, '')}.parts.${parts[3].replace('custom_', '').replace(/[ .]/g, '')}.__number__:${number}`);
1684
+ await nodeStorage
1685
+ .createContext('root')
1686
+ .createContext('parts')
1687
+ .createContext('Matterbridge')
1688
+ .createContext('parts')
1689
+ .createContext(parts[2].replace('custom_', '').replace(/[ .]/g, ''))
1690
+ .createContext('parts')
1691
+ .createContext(parts[3].replace('custom_', '').replace(/[ .]/g, ''))
1692
+ .set('__number__', number);
1693
+ }
1694
+ }
1695
+ await nodeStorage.createContext('persist').set('converted', true);
1696
+ await nodeStorage.createContext('persist').set('deviceName', await context.get('deviceName'));
1697
+ await nodeStorage.createContext('persist').set('deviceType', await context.get('deviceType'));
1698
+ await nodeStorage.createContext('persist').set('vendorId', await context.get('vendorId'));
1699
+ await nodeStorage.createContext('persist').set('vendorName', await context.get('vendorName'));
1700
+ await nodeStorage.createContext('persist').set('productId', await context.get('productId'));
1701
+ await nodeStorage.createContext('persist').set('productName', await context.get('productName'));
1702
+ await nodeStorage.createContext('persist').set('nodeLabel', await context.get('nodeLabel'));
1703
+ await nodeStorage.createContext('persist').set('productLabel', await context.get('productLabel'));
1704
+ await nodeStorage.createContext('persist').set('serialNumber', 'SN' + (await context.get('serialNumber')));
1705
+ await nodeStorage.createContext('persist').set('uniqueId', await context.get('uniqueId'));
1706
+ await nodeStorage.createContext('persist').set('softwareVersion', await context.get('softwareVersion'));
1707
+ await nodeStorage.createContext('persist').set('softwareVersionString', await context.get('softwareVersionString'));
1708
+ await nodeStorage.createContext('persist').set('hardwareVersion', await context.get('hardwareVersion'));
1709
+ await nodeStorage.createContext('persist').set('hardwareVersionString', await context.get('hardwareVersionString'));
1710
+ await context.set('converted', true);
1711
+ this.log.notice(`Matter storage converted to Matterbridge edge for ${plg}${pluginName}${nt}`);
1712
+ this.log.notice(`If you want to try out matterbridge edge (beta) add -edge to the command line.`);
1713
+ }
1714
+ catch (error) {
1715
+ this.log.error(`convertStorage error converting matter storage to Matterbridge edge for ${plg}${pluginName}${er}:`, error);
1716
+ }
1674
1717
  }
1675
1718
  async backupMatterStorage(storageName, backupName) {
1676
1719
  try {
@@ -1,7 +1,9 @@
1
1
  import { MatterbridgeDevice } from './matterbridgeDevice.js';
2
- import { CYAN, nf } from 'node-ansi-logger';
3
2
  import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
4
- import { isValidArray, isValidObject } from './utils/utils.js';
3
+ import { isValidArray, isValidObject, isValidString } from './utils/utils.js';
4
+ import { CYAN, db, nf, wr } from 'node-ansi-logger';
5
+ import { NodeStorageManager } from 'node-persist-manager';
6
+ import path from 'path';
5
7
  export class MatterbridgePlatform {
6
8
  matterbridge;
7
9
  log;
@@ -9,20 +11,34 @@ export class MatterbridgePlatform {
9
11
  name = '';
10
12
  type = '';
11
13
  version = '';
14
+ storage;
15
+ context;
12
16
  constructor(matterbridge, log, config) {
13
17
  this.matterbridge = matterbridge;
14
18
  this.log = log;
15
19
  this.config = config;
20
+ if (!isValidString(this.config.name))
21
+ return;
22
+ this.log.debug(`Creating storage for plugin ${this.config.name} in ${path.join(this.matterbridge.matterbridgeDirectory, this.config.name)}`);
23
+ this.storage = new NodeStorageManager({
24
+ dir: path.join(this.matterbridge.matterbridgeDirectory, this.config.name),
25
+ writeQueue: false,
26
+ expiredInterval: undefined,
27
+ logging: false,
28
+ forgiveParseErrors: true,
29
+ });
16
30
  }
17
31
  async onStart(reason) {
18
32
  this.log.error('Plugins must override onStart.', reason);
19
33
  throw new Error('Plugins must override onStart.');
20
34
  }
21
35
  async onConfigure() {
22
- this.log.debug("The plugin doesn't override onConfigure.");
36
+ this.log.debug(`Configuring platform ${this.name}`);
37
+ await this.checkEndpointNumbers();
23
38
  }
24
39
  async onShutdown(reason) {
25
- this.log.debug("The plugin doesn't override onShutdown.", reason);
40
+ this.log.debug(`Shutting down platform ${this.name}`, reason);
41
+ await this.checkEndpointNumbers();
26
42
  }
27
43
  async onChangeLoggerLevel(logLevel) {
28
44
  this.log.debug(`The plugin doesn't override onChangeLoggerLevel. Logger level set to: ${logLevel}`);
@@ -120,4 +136,38 @@ export class MatterbridgePlatform {
120
136
  }
121
137
  return true;
122
138
  }
139
+ async checkEndpointNumbers() {
140
+ if (!this.storage)
141
+ return -1;
142
+ this.log.debug('Checking endpoint numbers...');
143
+ const context = await this.storage.createStorage('context');
144
+ const separator = '|.|';
145
+ const endpointMap = new Map(await context.get('endpointMap', []));
146
+ for (const device of this.matterbridge.getDevices().filter((d) => d.plugin === this.name)) {
147
+ if (device.uniqueId === undefined || device.maybeNumber === undefined)
148
+ continue;
149
+ if (endpointMap.has(device.uniqueId) && endpointMap.get(device.uniqueId) !== device.maybeNumber) {
150
+ this.log.warn(`Endpoint number for device ${CYAN}${device.uniqueId}${wr} changed from ${CYAN}${endpointMap.get(device.uniqueId)}${wr} to ${CYAN}${device.maybeNumber}${wr}`);
151
+ endpointMap.set(device.uniqueId, device.maybeNumber);
152
+ }
153
+ if (!endpointMap.has(device.uniqueId)) {
154
+ this.log.debug(`Setting endpoint number for device ${CYAN}${device.uniqueId}${db} to ${CYAN}${device.maybeNumber}${db}`);
155
+ endpointMap.set(device.uniqueId, device.maybeNumber);
156
+ }
157
+ for (const child of device.getChildEndpoints()) {
158
+ const childId = child instanceof MatterbridgeEndpoint ? child.id : child.uniqueStorageKey;
159
+ if (!childId || !child.maybeNumber)
160
+ continue;
161
+ if (endpointMap.has(device.uniqueId + separator + childId) && endpointMap.get(device.uniqueId + separator + childId) !== child.maybeNumber) {
162
+ this.log.warn(`Child endpoint number for device ${CYAN}${device.uniqueId}${wr}.${CYAN}${childId}${wr} changed from ${CYAN}${endpointMap.get(device.uniqueId + separator + childId)}${wr} to ${CYAN}${child.maybeNumber}${wr}`);
163
+ }
164
+ if (!endpointMap.has(device.uniqueId + separator + childId)) {
165
+ this.log.debug(`Setting child endpoint number for device ${CYAN}${device.uniqueId}${db}.${CYAN}${childId}${db} to ${CYAN}${child.maybeNumber}${db}`);
166
+ endpointMap.set(device.uniqueId + separator + childId, child.maybeNumber);
167
+ }
168
+ }
169
+ }
170
+ await context.set('endpointMap', Array.from(endpointMap.entries()));
171
+ return endpointMap.size;
172
+ }
123
173
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "1.6.8-dev.7",
3
+ "version": "1.6.8-dev.9",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "matterbridge",
9
- "version": "1.6.8-dev.7",
9
+ "version": "1.6.8-dev.9",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@matter/main": "0.11.9",
@@ -1503,9 +1503,9 @@
1503
1503
  }
1504
1504
  },
1505
1505
  "node_modules/readable-stream": {
1506
- "version": "4.5.2",
1507
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
1508
- "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
1506
+ "version": "4.6.0",
1507
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.6.0.tgz",
1508
+ "integrity": "sha512-cbAdYt0VcnpN2Bekq7PU+k363ZRsPwJoEEJOEtSJQlJXzwaxt3FIo/uL+KeDSGIjJqtkwyge4KQgD2S2kd+CQw==",
1509
1509
  "license": "MIT",
1510
1510
  "dependencies": {
1511
1511
  "abort-controller": "^3.0.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "1.6.8-dev.7",
3
+ "version": "1.6.8-dev.9",
4
4
  "description": "Matterbridge plugin manager for Matter",
5
5
  "author": "https://github.com/Luligu",
6
6
  "license": "Apache-2.0",