matterbridge-example-dynamic-platform 1.3.12 → 1.3.13-dev-20250925-7d317a9

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
@@ -23,6 +23,24 @@ If you like this project and find it useful, please consider giving it a star on
23
23
  <img src="bmc-button.svg" alt="Buy me a coffee" width="120">
24
24
  </a>
25
25
 
26
+ ## [1.3.13] - 2025-09-??
27
+
28
+ ### Added
29
+
30
+ - [jest]: Added jest helper module v. 1.0.6.
31
+ - [platform]: Added a thermostat with auto mode and occupancy and outdoorTemperature.
32
+
33
+ ### Changed
34
+
35
+ - [package]: Updated dependencies.
36
+ - [workflows]: Ignore any .md anywhere in all workflows.
37
+ - [package]: Updated to Automator v. 2.0.7.
38
+ - [package]: Required matterbridge 3.2.9.
39
+
40
+ <a href="https://www.buymeacoffee.com/luligugithub">
41
+ <img src="bmc-button.svg" alt="Buy me a coffee" width="80">
42
+ </a>
43
+
26
44
  ## [1.3.12] - 2025-09-14
27
45
 
28
46
  ### Added
package/README.md CHANGED
@@ -17,7 +17,7 @@
17
17
 
18
18
  Matterbridge dynamic platform example plugin is a template to develop your own plugin using the dynamic platform.
19
19
 
20
- It exposes 56 virtual devices:
20
+ It exposes 58 virtual devices:
21
21
 
22
22
  - a door contact sensor
23
23
  - a motion sensor
@@ -39,10 +39,11 @@ It exposes 56 virtual devices:
39
39
  - a cover with windowCovering cluster and lift feature
40
40
  - a cover with windowCovering cluster and both lift and tilt features
41
41
  - a lock with doorLock cluster
42
- - a thermo autoMode (i.e. with Auto Heat and Cool features) with thermostat cluster and 3 sub endpoints with flowMeasurement cluster, temperatureMeasurement cluster
42
+ - a thermostat auto mode (i.e. with Auto Heat and Cool features) with thermostat cluster and 3 sub endpoints with flowMeasurement cluster, temperatureMeasurement cluster
43
43
  and relativeHumidityMeasurement cluster (to show how to create a composed device with sub endpoints)
44
- - a thermo heat only with two external temperature sensors (tagged like Indoor and Outdoor)
45
- - a thermo cool only
44
+ - a thermostat with auto mode (i.e. with Auto Heat and Cool features), occupancy and outdoorTemperature
45
+ - a thermostat heat only with two external temperature sensors (tagged like Indoor and Outdoor)
46
+ - a thermostat cool only
46
47
  - a fan with Off High presets
47
48
  - a fan with Off Low Med High presets
48
49
  - a fan with Off Low Med High Auto presets and step
@@ -164,7 +164,7 @@ export async function startServerNode(name, port) {
164
164
  expect(aggregator.lifecycle.isPartsReady).toBeTruthy();
165
165
  expect(aggregator.lifecycle.hasId).toBeTruthy();
166
166
  expect(aggregator.lifecycle.hasNumber).toBeTruthy();
167
- await flushAsync();
167
+ await flushAsync(undefined, undefined, 200);
168
168
  return [server, aggregator];
169
169
  }
170
170
  export async function stopServerNode(server) {
@@ -177,7 +177,7 @@ export async function stopServerNode(server) {
177
177
  expect(server.lifecycle.isReady).toBeTruthy();
178
178
  expect(server.lifecycle.isOnline).toBeFalsy();
179
179
  await server.env.get(MdnsService)[Symbol.asyncDispose]();
180
- await flushAsync();
180
+ await flushAsync(undefined, undefined, 200);
181
181
  }
182
182
  export async function addDevice(owner, device, pause = 10) {
183
183
  expect(owner).toBeDefined();
package/dist/platform.js CHANGED
@@ -43,6 +43,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
43
43
  coverLiftTilt;
44
44
  lock;
45
45
  thermoAuto;
46
+ thermoAutoOccupancy;
46
47
  thermoHeat;
47
48
  thermoCool;
48
49
  fanBase;
@@ -104,8 +105,8 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
104
105
  fanDirectionLookup = ['Forward', 'Reverse'];
105
106
  constructor(matterbridge, log, config) {
106
107
  super(matterbridge, log, config);
107
- if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.2.6')) {
108
- throw new Error(`This plugin requires Matterbridge version >= "3.2.6". Please update Matterbridge from ${this.matterbridge.matterbridgeVersion} to the latest version in the frontend.`);
108
+ if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.2.9')) {
109
+ throw new Error(`This plugin requires Matterbridge version >= "3.2.9". Please update Matterbridge from ${this.matterbridge.matterbridgeVersion} to the latest version in the frontend.`);
109
110
  }
110
111
  this.log.info('Initializing platform:', this.config.name);
111
112
  if (config.whiteList === undefined)
@@ -286,7 +287,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
286
287
  this.dimmer?.addCommandHandler('moveToLevelWithOnOff', async ({ request: { level } }) => {
287
288
  this.dimmer?.log.debug(`Command moveToLevelWithOnOff called request: ${level}`);
288
289
  });
289
- this.light = new MatterbridgeEndpoint([extendedColorLight, bridgedNode, powerSource], { uniqueStorageKey: 'Light (XY, HS and CT)' }, this.config.debug)
290
+ this.light = new MatterbridgeEndpoint([extendedColorLight, bridgedNode, powerSource], { uniqueStorageKey: 'Light (XY, HS, CT)' }, this.config.debug)
290
291
  .createDefaultIdentifyClusterServer()
291
292
  .createDefaultGroupsClusterServer()
292
293
  .createDefaultBridgedDeviceBasicInformationClusterServer('Light (XY, HS and CT)', 'LXC00015', 0xfff1, 'Matterbridge', 'Matterbridge Light')
@@ -509,7 +510,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
509
510
  this.thermoAuto = new MatterbridgeEndpoint([thermostatDevice, bridgedNode, powerSource], { uniqueStorageKey: 'Thermostat (AutoMode)' }, this.config.debug)
510
511
  .createDefaultIdentifyClusterServer()
511
512
  .createDefaultGroupsClusterServer()
512
- .createDefaultBridgedDeviceBasicInformationClusterServer('Thermostat (AutoMode)', 'TAU00023', 0xfff1, 'Matterbridge', 'Matterbridge Thermostat')
513
+ .createDefaultBridgedDeviceBasicInformationClusterServer('Thermostat (Auto)', 'TAU00023', 0xfff1, 'Matterbridge', 'Matterbridge Thermostat')
513
514
  .createDefaultThermostatClusterServer(20, 18, 22)
514
515
  .createDefaultPowerSourceRechargeableBatteryClusterServer(70, PowerSource.BatChargeLevel.Ok, 4700);
515
516
  this.thermoAuto
@@ -545,6 +546,29 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
545
546
  await this.thermoAuto?.subscribeAttribute(ThermostatCluster.id, 'occupiedCoolingSetpoint', (value) => {
546
547
  this.thermoAuto?.log.info('Subscribe occupiedCoolingSetpoint called with:', value / 100);
547
548
  }, this.thermoAuto.log);
549
+ this.thermoAutoOccupancy = new MatterbridgeEndpoint([thermostatDevice, bridgedNode, powerSource], { uniqueStorageKey: 'Thermostat (AutoModeOccupancy)' }, this.config.debug)
550
+ .createDefaultIdentifyClusterServer()
551
+ .createDefaultGroupsClusterServer()
552
+ .createDefaultBridgedDeviceBasicInformationClusterServer('Thermostat (AutoOccupancy)', 'TAO00058', 0xfff1, 'Matterbridge', 'Matterbridge Thermostat')
553
+ .createDefaultThermostatClusterServer(20, 18, 22, 1, 0, 35, 15, 50, 10, 30, false, 20.5)
554
+ .createDefaultPowerSourceWiredClusterServer();
555
+ this.thermoAutoOccupancy = await this.addDevice(this.thermoAutoOccupancy);
556
+ await this.thermoAutoOccupancy?.subscribeAttribute(ThermostatCluster.id, 'systemMode', (value) => {
557
+ const lookupSystemMode = ['Off', 'Auto', '', 'Cool', 'Heat', 'EmergencyHeat', 'Precooling', 'FanOnly', 'Dry', 'Sleep'];
558
+ this.thermoAutoOccupancy?.log.info('Subscribe systemMode called with:', lookupSystemMode[value]);
559
+ }, this.thermoAutoOccupancy.log);
560
+ await this.thermoAutoOccupancy?.subscribeAttribute(ThermostatCluster.id, 'occupiedHeatingSetpoint', (value) => {
561
+ this.thermoAutoOccupancy?.log.info('Subscribe occupiedHeatingSetpoint called with:', value / 100);
562
+ }, this.thermoAutoOccupancy.log);
563
+ await this.thermoAutoOccupancy?.subscribeAttribute(ThermostatCluster.id, 'occupiedCoolingSetpoint', (value) => {
564
+ this.thermoAutoOccupancy?.log.info('Subscribe occupiedCoolingSetpoint called with:', value / 100);
565
+ }, this.thermoAutoOccupancy.log);
566
+ await this.thermoAutoOccupancy?.subscribeAttribute(ThermostatCluster.id, 'unoccupiedHeatingSetpoint', (value) => {
567
+ this.thermoAutoOccupancy?.log.info('Subscribe unoccupiedHeatingSetpoint called with:', value / 100);
568
+ }, this.thermoAutoOccupancy.log);
569
+ await this.thermoAutoOccupancy?.subscribeAttribute(ThermostatCluster.id, 'unoccupiedCoolingSetpoint', (value) => {
570
+ this.thermoAutoOccupancy?.log.info('Subscribe unoccupiedCoolingSetpoint called with:', value / 100);
571
+ }, this.thermoAutoOccupancy.log);
548
572
  this.thermoHeat = new MatterbridgeEndpoint([thermostatDevice, bridgedNode, powerSource], { uniqueStorageKey: 'Thermostat (Heat)' }, this.config.debug)
549
573
  .createDefaultIdentifyClusterServer()
550
574
  .createDefaultGroupsClusterServer()
@@ -1558,6 +1582,9 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
1558
1582
  const flow = this.thermoAuto?.getChildEndpointByName('Flow');
1559
1583
  await flow?.setAttribute(FlowMeasurement.Cluster.id, 'measuredValue', 10, this.thermoAuto?.log);
1560
1584
  this.thermoAuto?.log.info('Set thermostat ext temperature to 16°C, ext humidity to 50% and ext valve flow to 10');
1585
+ await this.thermoAutoOccupancy?.setAttribute(ThermostatCluster.id, 'occupancy', { occupied: true }, this.thermoAutoOccupancy.log);
1586
+ await this.thermoAutoOccupancy?.setAttribute(ThermostatCluster.id, 'systemMode', Thermostat.SystemMode.Auto, this.thermoAutoOccupancy.log);
1587
+ this.thermoAutoOccupancy?.log.info('Set thermostat occupancy to true and mode Auto');
1561
1588
  if (this.config.useInterval) {
1562
1589
  this.thermoInterval = setInterval(async () => {
1563
1590
  let temperature = this.thermoAuto?.getAttribute(ThermostatCluster.id, 'localTemperature', this.thermoAuto.log);
@@ -1580,6 +1607,18 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
1580
1607
  this.thermoHeat?.log.info(`Set thermostat localTemperature to ${temperature / 100}°C`);
1581
1608
  this.thermoCool?.log.info(`Set thermostat localTemperature to ${temperature / 100}°C`);
1582
1609
  }
1610
+ let temperatureOccupancy = this.thermoAutoOccupancy?.getAttribute(ThermostatCluster.id, 'localTemperature', this.thermoAutoOccupancy.log);
1611
+ if (isValidNumber(temperatureOccupancy, 1600, 2400)) {
1612
+ temperatureOccupancy = temperatureOccupancy + 100 > 2400 ? 1600 : temperatureOccupancy + 100;
1613
+ await this.thermoAutoOccupancy?.setAttribute(ThermostatCluster.id, 'localTemperature', temperatureOccupancy, this.thermoAutoOccupancy.log);
1614
+ await this.thermoAutoOccupancy?.setAttribute(ThermostatCluster.id, 'outdoorTemperature', temperatureOccupancy + 100, this.thermoAutoOccupancy.log);
1615
+ const occupancyValue = this.thermoAutoOccupancy?.getAttribute(Thermostat.Cluster.id, 'occupancy', this.thermoAutoOccupancy.log);
1616
+ if (isValidObject(occupancyValue, 1)) {
1617
+ occupancyValue.occupied = !occupancyValue.occupied;
1618
+ await this.thermoAutoOccupancy?.setAttribute(Thermostat.Cluster.id, 'occupancy', occupancyValue, this.thermoAutoOccupancy.log);
1619
+ this.thermoAutoOccupancy?.log.info(`Set thermostat occupancy to ${occupancyValue.occupied}`);
1620
+ }
1621
+ }
1583
1622
  }, 60 * 1000 + 600);
1584
1623
  }
1585
1624
  await this.airConditioner?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.airConditioner.log);
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "matterbridge-example-dynamic-platform",
3
- "version": "1.3.12",
3
+ "version": "1.3.13-dev-20250925-7d317a9",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "matterbridge-example-dynamic-platform",
9
- "version": "1.3.12",
9
+ "version": "1.3.13-dev-20250925-7d317a9",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "node-ansi-logger": "3.1.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterbridge-example-dynamic-platform",
3
- "version": "1.3.12",
3
+ "version": "1.3.13-dev-20250925-7d317a9",
4
4
  "description": "Matterbridge dynamic plugin",
5
5
  "author": "https://github.com/Luligu",
6
6
  "license": "Apache-2.0",