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 +18 -0
- package/README.md +5 -4
- package/dist/jestHelpers.js +2 -2
- package/dist/platform.js +43 -4
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
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
|
|
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
|
|
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
|
|
45
|
-
- a
|
|
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
|
package/dist/jestHelpers.js
CHANGED
|
@@ -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.
|
|
108
|
-
throw new Error(`This plugin requires Matterbridge version >= "3.2.
|
|
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
|
|
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 (
|
|
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);
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge-example-dynamic-platform",
|
|
3
|
-
"version": "1.3.
|
|
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.
|
|
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",
|