matterbridge 1.6.6-dev.1 → 1.6.6-dev.13

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
@@ -14,12 +14,36 @@ If you want to run Matterbridge in Home Assistant please use the official add-on
14
14
 
15
15
  Tamer (https://github.com/tammeryousef1006) has created the Matterbridge Discord group: https://discord.gg/QX58CDe6hd.
16
16
 
17
- ## [1.6.6] - 2024-12-05
17
+ ## [1.6.6-dev.13] - 2024-12-10
18
+
19
+ ### Added
20
+
21
+ - [frontend]: Add the possibility to install a specific version or the dev of any plugin (i.e. you can install matterbridge-hass@dev or matterbridge-hass@0.0.3).
22
+ It is also possible to use the install plugin to install a specific version of matterbridge (i.e. you can install matterbridge@dev or matterbridge@1.6.5)
23
+ - [frontend]: Add the possibility to set the matter discriminator for commissioning (you can always override passing **-discriminator [DISCRIMINATOR]** on the command line).
24
+ - [frontend]: Add the possibility to set the matter passcode for commissioning (you can always override passing **-passcode [PASSCODE]** on the command line).
25
+ - [frontend]: Add the possibility to set the matter port for commissioning (you can always override passing **-port [PORT]** on the command line).
26
+ - [deviceTypes]: Add device type airConditioner (not supported by the Apple Home).
27
+ - [docker]: Add matterbridge-hass to docker dev.
28
+ - [platform]: Added validateDeviceWhiteBlackList and validateEntityBlackList to be used consistently by all plugins.
29
+ - [/api/devices]: Added productUrl and configUrl.
18
30
 
19
31
  ### Changed
20
32
 
21
- - [plugin]: Removed check on types since we are moving to production plugins.
33
+ - [package]: Update matter.js to 0.11.9-alpha.0-20241206-22f23333.
34
+ - [package]: Update matter.js to 0.11.9-alpha.0-20241207-b604cfa44
35
+ - [package]: Update matter.js to 0.11.9-alpha.0-20241209-06a8040e1
36
+ - [plugin]: Removed check on package types since we are moving to production plugins.
37
+ - [package]: Set required node version to 18, 20 and 22.
22
38
  - [package]: Update dependencies.
39
+ - [onOff]: Set default to OnOff.Feature.Lighting.
40
+ - [levelControl]: Set default to LevelControl.Feature.Lighting.
41
+ - [lightSensor]: Refactor lightSensor removing Group optional cluster server.
42
+ - [jest]: Update Jest tests.
43
+
44
+ ### Fixed
45
+
46
+ - [device]: Fix typos in Device and Endpoint.
23
47
 
24
48
  <a href="https://www.buymeacoffee.com/luligugithub">
25
49
  <img src="./yellow-button.png" alt="Buy me a coffee" width="120">
package/README-DEV.md CHANGED
@@ -71,9 +71,9 @@ I added some error messages when a plugin has wrong imports or configurations an
71
71
 
72
72
  I'm working with matter.js team to define the strategy for the migration of Matterbridge to the new API.
73
73
 
74
- - First phase: crete MatterbridgeEdge class: completed 90%
75
- - Second phase: create MatterbridgeEndpoint and MatterbridgeBehaviors classes: completed 90%
76
- - Third phase: modifiy all plugins to support both normal and edge mode of Matterbridge: completed 80%
74
+ - First phase: create MatterbridgeEdge class: completed 95%
75
+ - Second phase: create MatterbridgeEndpoint and MatterbridgeBehaviors classes: completed 95%
76
+ - Third phase: modifiy all plugins to support both normal and edge mode of Matterbridge: completed 90%
77
77
  - Fourth phase: remove all old api code from Matterbridge and all plugins...
78
78
 
79
79
  ## How to create your plugin
package/README.md CHANGED
@@ -46,6 +46,10 @@ A special thank to Apollon77 for his incredible work.
46
46
 
47
47
  To run Matterbridge, you need either a [Node.js](https://nodejs.org/en/download/package-manager) environment or [Docker](https://docs.docker.com/get-started/get-docker/) installed on your system.
48
48
 
49
+ If you don't have Node.js already install, please use this method to install it on a debian device: https://github.com/nodesource/distributions. Nvm is not a good choice.
50
+
51
+ If you don't have Docker already install, please use this method to install it on a debian device: https://docs.docker.com/desktop/setup/install/linux/debian/.
52
+
49
53
  ## Installation
50
54
 
51
55
  Follow these steps to install Matterbridge:
@@ -68,6 +68,9 @@ export class Matterbridge extends EventEmitter {
68
68
  mattermdnsinterface: undefined,
69
69
  matteripv4address: undefined,
70
70
  matteripv6address: undefined,
71
+ matterPort: 5540,
72
+ matterDiscriminator: undefined,
73
+ matterPasscode: undefined,
71
74
  restartRequired: false,
72
75
  refreshRequired: false,
73
76
  };
@@ -151,9 +154,6 @@ export class Matterbridge extends EventEmitter {
151
154
  await wait(1000, 'Wait for the global node_modules and matterbridge version', false);
152
155
  }
153
156
  async initialize() {
154
- this.port = getIntParameter('port') ?? 5540;
155
- this.passcode = getIntParameter('passcode');
156
- this.discriminator = getIntParameter('discriminator');
157
157
  if (hasParameter('service'))
158
158
  this.restartMode = 'service';
159
159
  if (hasParameter('docker'))
@@ -200,6 +200,9 @@ export class Matterbridge extends EventEmitter {
200
200
  this.log.fatal('Fatal error creating node storage manager and context for matterbridge');
201
201
  throw new Error('Fatal error creating node storage manager and context for matterbridge');
202
202
  }
203
+ this.port = getIntParameter('port') ?? (await this.nodeContext.get('matterport', 5540)) ?? 5540;
204
+ this.passcode = getIntParameter('passcode') ?? (await this.nodeContext.get('matterpasscode'));
205
+ this.discriminator = getIntParameter('discriminator') ?? (await this.nodeContext.get('matterdiscriminator'));
203
206
  if (hasParameter('logger')) {
204
207
  const level = getParameter('logger');
205
208
  if (level === 'debug') {
@@ -1646,7 +1649,7 @@ export class Matterbridge extends EventEmitter {
1646
1649
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with uniqueId ${uniqueId} serialNumber ${serialNumber}`);
1647
1650
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with softwareVersion ${softwareVersion} softwareVersionString ${softwareVersionString}`);
1648
1651
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with hardwareVersion ${hardwareVersion} hardwareVersionString ${hardwareVersionString}`);
1649
- this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with nodeLabel '${productName}' port ${this.port} passcode ${this.passcode} discriminator ${this.discriminator}`);
1652
+ this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with nodeLabel '${productName}' port ${CYAN}${this.port}${db} discriminator ${CYAN}${this.discriminator}${db} passcode ${CYAN}${this.passcode}${db} `);
1650
1653
  if (this.ipv4address) {
1651
1654
  const networkInterfaces = os.networkInterfaces();
1652
1655
  const availableAddresses = Object.values(networkInterfaces)
@@ -2312,6 +2315,9 @@ export class Matterbridge extends EventEmitter {
2312
2315
  this.matterbridgeInformation.mattermdnsinterface = (await this.nodeContext?.get('mattermdnsinterface', '')) || '';
2313
2316
  this.matterbridgeInformation.matteripv4address = (await this.nodeContext?.get('matteripv4address', '')) || '';
2314
2317
  this.matterbridgeInformation.matteripv6address = (await this.nodeContext?.get('matteripv6address', '')) || '';
2318
+ this.matterbridgeInformation.matterPort = (await this.nodeContext?.get('matterport', 5540)) ?? 5540;
2319
+ this.matterbridgeInformation.matterDiscriminator = await this.nodeContext?.get('matterdiscriminator');
2320
+ this.matterbridgeInformation.matterPasscode = await this.nodeContext?.get('matterpasscode');
2315
2321
  this.matterbridgeInformation.matterbridgePaired = this.matterbridgePaired;
2316
2322
  this.matterbridgeInformation.matterbridgeConnected = this.matterbridgeConnected;
2317
2323
  this.matterbridgeInformation.matterbridgeQrPairingCode = this.matterbridgeQrPairingCode;
@@ -2340,6 +2346,9 @@ export class Matterbridge extends EventEmitter {
2340
2346
  let serial = device.getClusterServer(BasicInformationCluster)?.attributes.serialNumber?.getLocal();
2341
2347
  if (!serial)
2342
2348
  serial = device.getClusterServer(BridgedDeviceBasicInformationCluster)?.attributes.serialNumber?.getLocal() ?? 'Unknown';
2349
+ let productUrl = device.getClusterServer(BasicInformationCluster)?.attributes.productUrl?.getLocal();
2350
+ if (!productUrl)
2351
+ productUrl = device.getClusterServer(BridgedDeviceBasicInformationCluster)?.attributes.productUrl?.getLocal() ?? 'Unknown';
2343
2352
  let uniqueId = device.getClusterServer(BasicInformationCluster)?.attributes.uniqueId?.getLocal();
2344
2353
  if (!uniqueId)
2345
2354
  uniqueId = device.getClusterServer(BridgedDeviceBasicInformationCluster)?.attributes.uniqueId?.getLocal() ?? 'Unknown';
@@ -2350,6 +2359,8 @@ export class Matterbridge extends EventEmitter {
2350
2359
  endpoint: device.number,
2351
2360
  name,
2352
2361
  serial,
2362
+ productUrl,
2363
+ configUrl: device.configUrl,
2353
2364
  uniqueId,
2354
2365
  cluster: cluster,
2355
2366
  });
@@ -2629,6 +2640,30 @@ export class Matterbridge extends EventEmitter {
2629
2640
  res.json({ message: 'Command received' });
2630
2641
  return;
2631
2642
  }
2643
+ if (command === 'setmatterport') {
2644
+ const port = Math.min(Math.max(parseInt(param), 5540), 5560);
2645
+ this.matterbridgeInformation.matterPort = port;
2646
+ this.log.debug(`Set matter commissioning port to ${CYAN}${port}${db}`);
2647
+ await this.nodeContext?.set('matterport', port);
2648
+ res.json({ message: 'Command received' });
2649
+ return;
2650
+ }
2651
+ if (command === 'setmatterdiscriminator') {
2652
+ const discriminator = Math.min(Math.max(parseInt(param), 1000), 4095);
2653
+ this.matterbridgeInformation.matterDiscriminator = discriminator;
2654
+ this.log.debug(`Set matter commissioning discriminator to ${CYAN}${discriminator}${db}`);
2655
+ await this.nodeContext?.set('matterdiscriminator', discriminator);
2656
+ res.json({ message: 'Command received' });
2657
+ return;
2658
+ }
2659
+ if (command === 'setmatterpasscode') {
2660
+ const passcode = Math.min(Math.max(parseInt(param), 10000000), 90000000);
2661
+ this.matterbridgeInformation.matterPasscode = passcode;
2662
+ this.log.debug(`Set matter commissioning passcode to ${CYAN}${passcode}${db}`);
2663
+ await this.nodeContext?.set('matterpasscode', passcode);
2664
+ res.json({ message: 'Command received' });
2665
+ return;
2666
+ }
2632
2667
  if (command === 'setmblogfile') {
2633
2668
  this.log.debug('Matterbridge file log:', param);
2634
2669
  this.matterbridgeInformation.fileLogger = param === 'true';
@@ -2732,6 +2767,11 @@ export class Matterbridge extends EventEmitter {
2732
2767
  this.log.error(`Error installing plugin ${plg}${param}${er}`);
2733
2768
  }
2734
2769
  this.wssSendRestartRequired();
2770
+ param = param.split('@')[0];
2771
+ if (param === 'matterbridge') {
2772
+ res.json({ message: 'Command received' });
2773
+ return;
2774
+ }
2735
2775
  }
2736
2776
  if (command === 'addplugin' || command === 'installplugin') {
2737
2777
  param = param.replace(/\*/g, '\\');
@@ -23,6 +23,10 @@ export class MatterbridgeBehaviorDevice {
23
23
  this.log.info(`Identifying device for ${identifyTime} seconds`);
24
24
  this.commandHandler.executeHandler('identify', { request: { identifyTime }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
25
25
  }
26
+ triggerEffect({ effectIdentifier, effectVariant }) {
27
+ this.log.info(`Triggering effect ${effectIdentifier} variant ${effectVariant}`);
28
+ this.commandHandler.executeHandler('triggerEffect', { request: { effectIdentifier, effectVariant }, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
29
+ }
26
30
  on() {
27
31
  this.log.info(`Switching device on (endpoint ${this.endpointId}.${this.endpointNumber})`);
28
32
  this.commandHandler.executeHandler('on', { request: {}, attributes: {}, endpoint: { number: this.endpointNumber, uniqueStorageKey: this.endpointId } });
@@ -125,6 +129,11 @@ export class MatterbridgeIdentifyServer extends IdentifyServer {
125
129
  device.identify({ identifyTime });
126
130
  super.identify({ identifyTime });
127
131
  }
132
+ triggerEffect({ effectIdentifier, effectVariant }) {
133
+ const device = this.agent.get(MatterbridgeBehavior).state.deviceCommand;
134
+ device.triggerEffect({ effectIdentifier, effectVariant });
135
+ super.triggerEffect({ effectIdentifier, effectVariant });
136
+ }
128
137
  }
129
138
  export class MatterbridgeOnOffServer extends OnOffServer {
130
139
  async on() {
@@ -12,6 +12,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
12
12
  static logLevel = "info";
13
13
  log;
14
14
  plugin = undefined;
15
+ configUrl = undefined;
15
16
  serialNumber = undefined;
16
17
  deviceName = undefined;
17
18
  uniqueId = undefined;
@@ -458,6 +459,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
458
459
  vendorName: vendorName.slice(0, 32),
459
460
  productId: productId,
460
461
  productName: productName.slice(0, 32),
462
+ productUrl: 'https://www.npmjs.com/package/matterbridge',
461
463
  productLabel: deviceName.slice(0, 64),
462
464
  nodeLabel: deviceName.slice(0, 32),
463
465
  serialNumber: serialNumber.slice(0, 32),
@@ -502,6 +504,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
502
504
  vendorId: vendorId !== undefined ? VendorId(vendorId) : undefined,
503
505
  vendorName: vendorName.slice(0, 32),
504
506
  productName: productName.slice(0, 32),
507
+ productUrl: 'https://www.npmjs.com/package/matterbridge',
505
508
  productLabel: deviceName.slice(0, 64),
506
509
  nodeLabel: deviceName.slice(0, 32),
507
510
  serialNumber: serialNumber.slice(0, 32),
@@ -644,12 +647,14 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
644
647
  createDefaultOnOffClusterServer(onOff = false, globalSceneControl = false, onTime = 0, offWaitTime = 0, startUpOnOff = null) {
645
648
  this.addClusterServer(this.getDefaultOnOffClusterServer(onOff, globalSceneControl, onTime, offWaitTime, startUpOnOff));
646
649
  }
647
- getDefaultLevelControlClusterServer(currentLevel = 254, minLevel = 0, maxLevel = 254, onLevel = null) {
648
- return ClusterServer(LevelControlCluster.with(LevelControl.Feature.OnOff), {
650
+ getDefaultLevelControlClusterServer(currentLevel = 254, minLevel = 1, maxLevel = 254, onLevel = null, startUpCurrentLevel = null) {
651
+ return ClusterServer(LevelControlCluster.with(LevelControl.Feature.OnOff, LevelControl.Feature.Lighting), {
649
652
  currentLevel,
650
653
  minLevel,
651
654
  maxLevel,
652
655
  onLevel,
656
+ remainingTime: 0,
657
+ startUpCurrentLevel,
653
658
  options: {
654
659
  executeIfOff: false,
655
660
  coupleColorTempToLevel: false,
@@ -683,8 +688,8 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
683
688
  },
684
689
  });
685
690
  }
686
- createDefaultLevelControlClusterServer(currentLevel = 254, minLevel = 0, maxLevel = 254, onLevel = null) {
687
- this.addClusterServer(this.getDefaultLevelControlClusterServer(currentLevel, minLevel, maxLevel, onLevel));
691
+ createDefaultLevelControlClusterServer(currentLevel = 254, minLevel = 1, maxLevel = 254, onLevel = null, startUpCurrentLevel = null) {
692
+ this.addClusterServer(this.getDefaultLevelControlClusterServer(currentLevel, minLevel, maxLevel, onLevel, startUpCurrentLevel));
688
693
  }
689
694
  getDefaultColorControlClusterServer(currentX = 0, currentY = 0, currentHue = 0, currentSaturation = 0, colorTemperatureMireds = 500, colorTempPhysicalMinMireds = 147, colorTempPhysicalMaxMireds = 500) {
690
695
  return ClusterServer(ColorControlCluster.with(ColorControl.Feature.Xy, ColorControl.Feature.HueSaturation, ColorControl.Feature.ColorTemperature), {
@@ -702,6 +707,9 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
702
707
  colorTemperatureMireds,
703
708
  colorTempPhysicalMinMireds,
704
709
  colorTempPhysicalMaxMireds,
710
+ coupleColorTempToLevelMinMireds: colorTempPhysicalMinMireds,
711
+ remainingTime: 0,
712
+ startUpColorTemperatureMireds: null,
705
713
  }, {
706
714
  moveToColor: async (data) => {
707
715
  this.log.debug('Matter command: moveToColor request:', data.request, 'attributes.currentX:', data.attributes.currentX.getLocal(), 'attributes.currentY:', data.attributes.currentY.getLocal());
@@ -766,6 +774,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
766
774
  numberOfPrimaries: null,
767
775
  currentX,
768
776
  currentY,
777
+ remainingTime: 0,
769
778
  }, {
770
779
  moveToColor: async (data) => {
771
780
  this.log.debug('Matter command: moveToColor request:', data.request, 'attributes.currentX:', data.attributes.currentX.getLocal(), 'attributes.currentY:', data.attributes.currentY.getLocal());
@@ -782,7 +791,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
782
791
  },
783
792
  }, {});
784
793
  }
785
- createXyControlClusterServer(currentX = 0, currentY = 0) {
794
+ createXyColorControlClusterServer(currentX = 0, currentY = 0) {
786
795
  this.addClusterServer(this.getXyColorControlClusterServer(currentX, currentY));
787
796
  }
788
797
  getHsColorControlClusterServer(currentHue = 0, currentSaturation = 0) {
@@ -796,6 +805,7 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
796
805
  numberOfPrimaries: null,
797
806
  currentHue,
798
807
  currentSaturation,
808
+ remainingTime: 0,
799
809
  }, {
800
810
  moveToHue: async ({ request, attributes, endpoint }) => {
801
811
  this.log.debug('Matter command: moveToHue request:', request, 'attributes.currentHue:', attributes.currentHue.getLocal());
@@ -841,6 +851,9 @@ export class MatterbridgeDevice extends extendPublicHandlerMethods(Device) {
841
851
  colorTemperatureMireds,
842
852
  colorTempPhysicalMinMireds,
843
853
  colorTempPhysicalMaxMireds,
854
+ coupleColorTempToLevelMinMireds: colorTempPhysicalMinMireds,
855
+ remainingTime: 0,
856
+ startUpColorTemperatureMireds: null,
844
857
  }, {
845
858
  stopMoveStep: async () => {
846
859
  this.log.error('Matter command: stopMoveStep not implemented');
@@ -116,7 +116,6 @@ export const lightSensor = DeviceTypeDefinition({
116
116
  deviceClass: DeviceClasses.Simple,
117
117
  revision: 3,
118
118
  requiredServerClusters: [Identify.Cluster.id, IlluminanceMeasurement.Cluster.id],
119
- optionalClientClusters: [Groups.Cluster.id],
120
119
  });
121
120
  export const occupancySensor = DeviceTypeDefinition({
122
121
  name: 'MA-occupancysensor',
@@ -48,9 +48,6 @@ export class MatterbridgeEdge extends Matterbridge {
48
48
  await super.initialize();
49
49
  if (this.mdnsInterface)
50
50
  this.environment.vars.set('mdns.networkInterface', this.mdnsInterface);
51
- this.port = 5540;
52
- this.passcode = 20242025;
53
- this.discriminator = 3840;
54
51
  }
55
52
  async startMatterStorage(storageType, storageName) {
56
53
  this.log.info(`Starting matter node storage...`);