matterbridge 1.6.8-dev.8 → 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.8] - 2024-12-19
16
+ ## [1.6.8-dev.9] - 2024-12-21
17
17
 
18
18
  ### Added
19
19
 
20
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) {
@@ -1553,7 +1559,7 @@ export class Matterbridge extends EventEmitter {
1553
1559
  const storageService = Environment.default.get(StorageService);
1554
1560
  Environment.default.vars.set('path.root', path.join(this.matterbridgeDirectory, 'matterstorage' + (this.profile ? '.' + this.profile : '')));
1555
1561
  const nodeStorage = await storageService.open('Matterbridge');
1556
- if ((await nodeStorage.createContext('root').createContext('generalDiagnostics').get('rebootCount', 0)) > 0) {
1562
+ if ((await nodeStorage.createContext('root').createContext('generalDiagnostics').get('rebootCount', -1)) >= 0) {
1557
1563
  this.log.info(`Matter node storage already converted to Matterbridge edge for ${plg}${pluginName}${nf}`);
1558
1564
  return;
1559
1565
  }
@@ -1562,7 +1568,7 @@ export class Matterbridge extends EventEmitter {
1562
1568
  }
1563
1569
  const fabricManagerContext = context.createContext('FabricManager');
1564
1570
  const fabrics = (await fabricManagerContext.get('fabrics', []));
1565
- const nextFabricIndex = await fabricManagerContext.get('nextFabricIndex', 1);
1571
+ const nextFabricIndex = await fabricManagerContext.get('nextFabricIndex', 0);
1566
1572
  const eventHandlerContext = context.createContext('EventHandler');
1567
1573
  const sessionManagerContext = context.createContext('SessionManager');
1568
1574
  const endpointStructureContext = context.createContext('EndpointStructure');
@@ -1574,6 +1580,10 @@ export class Matterbridge extends EventEmitter {
1574
1580
  const trcArray = [];
1575
1581
  const aclArray = [];
1576
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;
1586
+ }
1577
1587
  for (const fabric of fabrics) {
1578
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}`);
1579
1589
  fabricInfo[fabric.fabricIndex] = {
@@ -1640,20 +1650,47 @@ export class Matterbridge extends EventEmitter {
1640
1650
  const parts = key.split('-');
1641
1651
  const number = await endpointStructureContext.get(key);
1642
1652
  if (parts.length === 2) {
1643
- this.log.debug(`Converting Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.__number__:${number}`);
1653
+ this.log.debug(`Converting bridge Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.__number__:${number}`);
1644
1654
  await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').set('__number__', number);
1645
1655
  }
1646
1656
  else if (parts.length === 3 && parts[2].startsWith('custom_')) {
1647
- this.log.debug(`Converting Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${parts[2].replace('custom_', '')}.__number__:${number}`);
1648
- await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').createContext('parts').createContext(parts[2].replace('custom_', '')).set('__number__', number);
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);
1649
1659
  }
1650
1660
  else if (parts.length === 3 && parts[2].startsWith('unique_')) {
1651
1661
  const device = this.devices.get(parts[2].replace('unique_', ''));
1652
1662
  if (device && device.deviceName && device.maybeNumber) {
1653
- this.log.debug(`Converting Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${device.deviceName.replace(/[ .]/g, '')}.__number__:${device.maybeNumber}`);
1663
+ this.log.debug(`Converting unique Matterbridge.EndpointStructure:${key}:${number} to root.parts.Matterbridge.parts.${device.deviceName.replace(/[ .]/g, '')}.__number__:${device.maybeNumber}`);
1654
1664
  await nodeStorage.createContext('root').createContext('parts').createContext('Matterbridge').createContext('parts').createContext(device.deviceName.replace(/[ .]/g, '')).set('__number__', device.maybeNumber);
1655
1665
  }
1656
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
+ }
1657
1694
  }
1658
1695
  await nodeStorage.createContext('persist').set('converted', true);
1659
1696
  await nodeStorage.createContext('persist').set('deviceName', await context.get('deviceName'));
@@ -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.8",
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.8",
9
+ "version": "1.6.8-dev.9",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@matter/main": "0.11.9",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "1.6.8-dev.8",
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",