matterbridge-example-dynamic-platform 2.0.4 → 2.0.5-dev-20260125-f72d187
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 +17 -0
- package/README.md +4 -1
- package/dist/module.d.ts +3 -0
- package/dist/module.js +261 -8
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -23,6 +23,23 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
23
23
|
|
|
24
24
|
<a href="https://www.buymeacoffee.com/luligugithub"><img src="https://matterbridge.io/assets/bmc-button.svg" alt="Buy me a coffee" width="120"></a>
|
|
25
25
|
|
|
26
|
+
## [2.0.5] - 2026-01-24
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- [thermostat]: Added a thermostat auto mode with presets (Comfort and Away modes) including 3 sub endpoints with flowMeasurement, temperature and humidity sensors. Thanks Ludovic BOUÉ (<https://github.com/Luligu/matterbridge-example-dynamic-platform/pull/42> and https://github.com/Luligu/matterbridge-example-dynamic-platform/pull/43).
|
|
31
|
+
- [presets]: Added support for Matter Thermostat Presets feature with preset activation and setpoint management.
|
|
32
|
+
- [Energy]: Added an outlet (plug) with onOff cluster, energy measurements and power measurements
|
|
33
|
+
- [EnergyApparent]: Added an outlet (plug) with onOff cluster, apparent energy measurements and power measurements
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- [package]: Updated dependencies.
|
|
38
|
+
- [package]: Bumped package to automator v.3.0.2.
|
|
39
|
+
- [package]: Required matterbridge 3.5.1.
|
|
40
|
+
|
|
41
|
+
<a href="https://www.buymeacoffee.com/luligugithub"><img src="https://matterbridge.io/assets/bmc-button.svg" alt="Buy me a coffee" width="80"></a>
|
|
42
|
+
|
|
26
43
|
## [2.0.4] - 2026-01-20
|
|
27
44
|
|
|
28
45
|
### Added
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
Matterbridge dynamic platform example plugin is a template to develop your own plugin using the dynamic platform.
|
|
21
21
|
|
|
22
|
-
It exposes
|
|
22
|
+
It exposes 61 virtual devices:
|
|
23
23
|
|
|
24
24
|
- a door contact sensor
|
|
25
25
|
- a motion sensor
|
|
@@ -38,12 +38,15 @@ It exposes 58 virtual devices:
|
|
|
38
38
|
- a light with onOff, levelControl and colorControl (with XY and CT) clusters
|
|
39
39
|
- a light with onOff, levelControl and colorControl (with CT only) clusters
|
|
40
40
|
- an outlet (plug) with onOff cluster
|
|
41
|
+
- an outlet (plug) with onOff cluster, energy measurements and power measurements
|
|
42
|
+
- an outlet (plug) with onOff cluster, apparent energy measurements and power measurements
|
|
41
43
|
- a cover with windowCovering cluster and lift feature
|
|
42
44
|
- a cover with windowCovering cluster and both lift and tilt features
|
|
43
45
|
- a lock with doorLock cluster
|
|
44
46
|
- a thermostat auto mode (i.e. with Auto Heat and Cool features) with thermostat cluster and 3 sub endpoints with flowMeasurement cluster, temperatureMeasurement cluster
|
|
45
47
|
and relativeHumidityMeasurement cluster (to show how to create a composed device with sub endpoints)
|
|
46
48
|
- a thermostat with auto mode (i.e. with Auto Heat and Cool features), occupancy and outdoorTemperature
|
|
49
|
+
- a thermostat auto mode with presets (Home, Away, Sleep, Wake, Vacation and GoingToSleep modes) including 2 sub endpoints with temperature and humidity sensors
|
|
47
50
|
- a thermostat heat only with two external temperature sensors (tagged like Indoor and Outdoor)
|
|
48
51
|
- a thermostat cool only
|
|
49
52
|
- a fan with Off High presets
|
package/dist/module.d.ts
CHANGED
|
@@ -29,11 +29,14 @@ export declare class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDyna
|
|
|
29
29
|
lightHS: MatterbridgeEndpoint | undefined;
|
|
30
30
|
lightCT: MatterbridgeEndpoint | undefined;
|
|
31
31
|
outlet: MatterbridgeEndpoint | undefined;
|
|
32
|
+
outletEnergy: MatterbridgeEndpoint | undefined;
|
|
33
|
+
outletEnergyApparent: MatterbridgeEndpoint | undefined;
|
|
32
34
|
coverLift: MatterbridgeEndpoint | undefined;
|
|
33
35
|
coverLiftTilt: MatterbridgeEndpoint | undefined;
|
|
34
36
|
lock: MatterbridgeEndpoint | undefined;
|
|
35
37
|
thermoAuto: MatterbridgeEndpoint | undefined;
|
|
36
38
|
thermoAutoOccupancy: MatterbridgeEndpoint | undefined;
|
|
39
|
+
thermoAutoPresets: MatterbridgeEndpoint | undefined;
|
|
37
40
|
thermoHeat: MatterbridgeEndpoint | undefined;
|
|
38
41
|
thermoCool: MatterbridgeEndpoint | undefined;
|
|
39
42
|
fanBase: MatterbridgeEndpoint | undefined;
|
package/dist/module.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { MatterbridgeEndpoint, MatterbridgeDynamicPlatform, airQualitySensor, bridgedNode, colorTemperatureLight, coverDevice, dimmableLight, doorLockDevice, fanDevice, flowSensor, humiditySensor, onOffLight, onOffOutlet, onOffSwitch, powerSource, rainSensor, smokeCoAlarm, temperatureSensor, thermostatDevice, waterFreezeDetector, waterLeakDetector, airPurifier, pumpDevice, waterValve, genericSwitch, onOffMountedSwitch, dimmableMountedSwitch, extendedColorLight, pressureSensor, contactSensor, occupancySensor, lightSensor, modeSelect, } from 'matterbridge';
|
|
1
|
+
import { MatterbridgeEndpoint, MatterbridgeDynamicPlatform, airQualitySensor, bridgedNode, colorTemperatureLight, coverDevice, dimmableLight, doorLockDevice, fanDevice, flowSensor, humiditySensor, onOffLight, onOffOutlet, onOffSwitch, powerSource, rainSensor, smokeCoAlarm, temperatureSensor, thermostatDevice, waterFreezeDetector, waterLeakDetector, airPurifier, pumpDevice, waterValve, genericSwitch, onOffMountedSwitch, dimmableMountedSwitch, extendedColorLight, pressureSensor, contactSensor, occupancySensor, lightSensor, modeSelect, electricalSensor, } from 'matterbridge';
|
|
2
2
|
import { RoboticVacuumCleaner, LaundryWasher, WaterHeater, Evse, SolarPower, BatteryStorage, LaundryDryer, HeatPump, Dishwasher, ExtractorHood, MicrowaveOven, Oven, Cooktop, Refrigerator, AirConditioner, Speaker, } from 'matterbridge/devices';
|
|
3
3
|
import { isValidBoolean, isValidNumber, isValidObject, isValidString } from 'matterbridge/utils';
|
|
4
4
|
import { debugStringify } from 'matterbridge/logger';
|
|
5
5
|
import { AreaNamespaceTag, LocationTag, NumberTag, PositionTag, RefrigeratorTag, SwitchesTag, UINT16_MAX, UINT32_MAX } from 'matterbridge/matter';
|
|
6
|
-
import { PowerSource, BooleanState, OnOff, LevelControl, AirQuality, CarbonDioxideConcentrationMeasurement, CarbonMonoxideConcentrationMeasurement, FlowMeasurement, ColorControl, DoorLock, FanControl, FormaldehydeConcentrationMeasurement, NitrogenDioxideConcentrationMeasurement, OzoneConcentrationMeasurement, Pm10ConcentrationMeasurement, Pm1ConcentrationMeasurement, Pm25ConcentrationMeasurement, RadonConcentrationMeasurement, RelativeHumidityMeasurement, RelativeHumidityMeasurementCluster, SmokeCoAlarm, TemperatureMeasurement, Thermostat, ThermostatCluster, TotalVolatileOrganicCompoundsConcentrationMeasurement, WindowCovering, EnergyEvseMode, EnergyEvse, RvcRunMode, RvcCleanMode, Descriptor, BridgedDeviceBasicInformation, OvenMode, OperationalState, OccupancySensing, IlluminanceMeasurement, PressureMeasurement, RefrigeratorAndTemperatureControlledCabinetMode, RvcOperationalState, DeviceEnergyManagement, } from 'matterbridge/matter/clusters';
|
|
6
|
+
import { PowerSource, BooleanState, OnOff, LevelControl, AirQuality, CarbonDioxideConcentrationMeasurement, CarbonMonoxideConcentrationMeasurement, FlowMeasurement, ColorControl, DoorLock, FanControl, FormaldehydeConcentrationMeasurement, NitrogenDioxideConcentrationMeasurement, OzoneConcentrationMeasurement, Pm10ConcentrationMeasurement, Pm1ConcentrationMeasurement, Pm25ConcentrationMeasurement, RadonConcentrationMeasurement, RelativeHumidityMeasurement, RelativeHumidityMeasurementCluster, SmokeCoAlarm, TemperatureMeasurement, Thermostat, ThermostatCluster, TotalVolatileOrganicCompoundsConcentrationMeasurement, WindowCovering, EnergyEvseMode, EnergyEvse, RvcRunMode, RvcCleanMode, Descriptor, BridgedDeviceBasicInformation, OvenMode, OperationalState, OccupancySensing, IlluminanceMeasurement, PressureMeasurement, RefrigeratorAndTemperatureControlledCabinetMode, RvcOperationalState, DeviceEnergyManagement, ElectricalEnergyMeasurement, ElectricalPowerMeasurement, } from 'matterbridge/matter/clusters';
|
|
7
7
|
function luxToMatter(lux) {
|
|
8
8
|
if (!Number.isFinite(lux) || lux <= 0)
|
|
9
9
|
return 0;
|
|
@@ -43,11 +43,14 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
43
43
|
lightHS;
|
|
44
44
|
lightCT;
|
|
45
45
|
outlet;
|
|
46
|
+
outletEnergy;
|
|
47
|
+
outletEnergyApparent;
|
|
46
48
|
coverLift;
|
|
47
49
|
coverLiftTilt;
|
|
48
50
|
lock;
|
|
49
51
|
thermoAuto;
|
|
50
52
|
thermoAutoOccupancy;
|
|
53
|
+
thermoAutoPresets;
|
|
51
54
|
thermoHeat;
|
|
52
55
|
thermoCool;
|
|
53
56
|
fanBase;
|
|
@@ -110,8 +113,8 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
110
113
|
constructor(matterbridge, log, config) {
|
|
111
114
|
super(matterbridge, log, config);
|
|
112
115
|
this.config = config;
|
|
113
|
-
if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.
|
|
114
|
-
throw new Error(`This plugin requires Matterbridge version >= "3.
|
|
116
|
+
if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.5.1')) {
|
|
117
|
+
throw new Error(`This plugin requires Matterbridge version >= "3.5.1". Please update Matterbridge from ${this.matterbridge.matterbridgeVersion} to the latest version in the frontend.`);
|
|
115
118
|
}
|
|
116
119
|
this.log.info('Initializing platform:', this.config.name);
|
|
117
120
|
}
|
|
@@ -432,6 +435,42 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
432
435
|
this.outlet?.addCommandHandler('off', async () => {
|
|
433
436
|
this.outlet?.log.info('Command off called');
|
|
434
437
|
});
|
|
438
|
+
this.outletEnergy = new MatterbridgeEndpoint([onOffOutlet, electricalSensor, bridgedNode, powerSource], { id: 'OutletEnergy' }, this.config.debug)
|
|
439
|
+
.createDefaultIdentifyClusterServer()
|
|
440
|
+
.createDefaultElectricalEnergyMeasurementClusterServer(0, 0)
|
|
441
|
+
.createDefaultElectricalPowerMeasurementClusterServer(220_000, 0, 0, 50_000)
|
|
442
|
+
.createDefaultBridgedDeviceBasicInformationClusterServer('OutletEnergy', 'OEN00019', 0xfff1, 'Matterbridge', 'Matterbridge Outlet With Energy')
|
|
443
|
+
.createDefaultOnOffClusterServer()
|
|
444
|
+
.createDefaultPowerSourceWiredClusterServer()
|
|
445
|
+
.addRequiredClusterServers();
|
|
446
|
+
this.outletEnergy = await this.addDevice(this.outletEnergy);
|
|
447
|
+
this.outletEnergy?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
|
|
448
|
+
this.outletEnergy?.log.info(`Command identify called identifyTime:${identifyTime}`);
|
|
449
|
+
});
|
|
450
|
+
this.outletEnergy?.addCommandHandler('on', async () => {
|
|
451
|
+
this.outletEnergy?.log.info('Command on called');
|
|
452
|
+
});
|
|
453
|
+
this.outletEnergy?.addCommandHandler('off', async () => {
|
|
454
|
+
this.outletEnergy?.log.info('Command off called');
|
|
455
|
+
});
|
|
456
|
+
this.outletEnergyApparent = new MatterbridgeEndpoint([onOffOutlet, electricalSensor, bridgedNode, powerSource], { id: 'OutletEnergyApparent' }, this.config.debug)
|
|
457
|
+
.createDefaultIdentifyClusterServer()
|
|
458
|
+
.createDefaultElectricalEnergyMeasurementClusterServer(0, 0)
|
|
459
|
+
.createApparentElectricalPowerMeasurementClusterServer(220_000, 0, 0, 50_000)
|
|
460
|
+
.createDefaultBridgedDeviceBasicInformationClusterServer('OutletEnergyApparent', 'OEA00019', 0xfff1, 'Matterbridge', 'Matterbridge Outlet With Apparent Energy')
|
|
461
|
+
.createDefaultOnOffClusterServer()
|
|
462
|
+
.createDefaultPowerSourceWiredClusterServer()
|
|
463
|
+
.addRequiredClusterServers();
|
|
464
|
+
this.outletEnergyApparent = await this.addDevice(this.outletEnergyApparent);
|
|
465
|
+
this.outletEnergyApparent?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
|
|
466
|
+
this.outletEnergyApparent?.log.info(`Command identify called identifyTime:${identifyTime}`);
|
|
467
|
+
});
|
|
468
|
+
this.outletEnergyApparent?.addCommandHandler('on', async () => {
|
|
469
|
+
this.outletEnergyApparent?.log.info('Command on called');
|
|
470
|
+
});
|
|
471
|
+
this.outletEnergyApparent?.addCommandHandler('off', async () => {
|
|
472
|
+
this.outletEnergyApparent?.log.info('Command off called');
|
|
473
|
+
});
|
|
435
474
|
this.coverLift = new MatterbridgeEndpoint([coverDevice, bridgedNode, powerSource], { id: 'CoverLift' }, this.config.debug)
|
|
436
475
|
.createDefaultIdentifyClusterServer()
|
|
437
476
|
.createDefaultGroupsClusterServer()
|
|
@@ -550,7 +589,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
550
589
|
this.thermoAutoOccupancy = new MatterbridgeEndpoint([thermostatDevice, bridgedNode, powerSource], { id: 'Thermostat (AutoModeOccupancy)' }, this.config.debug)
|
|
551
590
|
.createDefaultIdentifyClusterServer()
|
|
552
591
|
.createDefaultGroupsClusterServer()
|
|
553
|
-
.createDefaultBridgedDeviceBasicInformationClusterServer('Thermostat (AutoOccupancy)', 'TAO00058', 0xfff1, 'Matterbridge', 'Matterbridge Thermostat')
|
|
592
|
+
.createDefaultBridgedDeviceBasicInformationClusterServer('Thermostat (AutoOccupancy)', 'TAO00058', 0xfff1, 'Matterbridge', 'Matterbridge Thermostat Presets')
|
|
554
593
|
.createDefaultThermostatClusterServer(20, 18, 22, 1, 0, 35, 15, 50, 10, 30, false, 20.5)
|
|
555
594
|
.createDefaultPowerSourceWiredClusterServer();
|
|
556
595
|
this.thermoAutoOccupancy = await this.addDevice(this.thermoAutoOccupancy);
|
|
@@ -570,6 +609,165 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
570
609
|
await this.thermoAutoOccupancy?.subscribeAttribute(ThermostatCluster.id, 'unoccupiedCoolingSetpoint', (value) => {
|
|
571
610
|
this.thermoAutoOccupancy?.log.info('Subscribe unoccupiedCoolingSetpoint called with:', value / 100);
|
|
572
611
|
}, this.thermoAutoOccupancy.log);
|
|
612
|
+
const presets_List = [
|
|
613
|
+
{
|
|
614
|
+
presetHandle: new Uint8Array([0]),
|
|
615
|
+
presetScenario: Thermostat.PresetScenario.Occupied,
|
|
616
|
+
name: 'Home',
|
|
617
|
+
coolingSetpoint: 2300,
|
|
618
|
+
heatingSetpoint: 2200,
|
|
619
|
+
builtIn: true,
|
|
620
|
+
},
|
|
621
|
+
{
|
|
622
|
+
presetHandle: new Uint8Array([1]),
|
|
623
|
+
presetScenario: Thermostat.PresetScenario.Unoccupied,
|
|
624
|
+
name: 'Away',
|
|
625
|
+
coolingSetpoint: 2600,
|
|
626
|
+
heatingSetpoint: 1800,
|
|
627
|
+
builtIn: true,
|
|
628
|
+
},
|
|
629
|
+
{
|
|
630
|
+
presetHandle: new Uint8Array([2]),
|
|
631
|
+
presetScenario: Thermostat.PresetScenario.Sleep,
|
|
632
|
+
name: 'Sleep',
|
|
633
|
+
coolingSetpoint: 2100,
|
|
634
|
+
heatingSetpoint: 1800,
|
|
635
|
+
builtIn: true,
|
|
636
|
+
},
|
|
637
|
+
{
|
|
638
|
+
presetHandle: new Uint8Array([3]),
|
|
639
|
+
presetScenario: Thermostat.PresetScenario.Wake,
|
|
640
|
+
name: 'Wake',
|
|
641
|
+
coolingSetpoint: 2400,
|
|
642
|
+
heatingSetpoint: 1900,
|
|
643
|
+
builtIn: true,
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
presetHandle: new Uint8Array([4]),
|
|
647
|
+
presetScenario: Thermostat.PresetScenario.Vacation,
|
|
648
|
+
name: 'Vacation',
|
|
649
|
+
coolingSetpoint: 2700,
|
|
650
|
+
heatingSetpoint: 1600,
|
|
651
|
+
builtIn: true,
|
|
652
|
+
},
|
|
653
|
+
{
|
|
654
|
+
presetHandle: new Uint8Array([5]),
|
|
655
|
+
presetScenario: Thermostat.PresetScenario.GoingToSleep,
|
|
656
|
+
name: 'GoingToSleep',
|
|
657
|
+
coolingSetpoint: 2200,
|
|
658
|
+
heatingSetpoint: 1850,
|
|
659
|
+
builtIn: true,
|
|
660
|
+
},
|
|
661
|
+
];
|
|
662
|
+
const presetTypeDefinitions = [
|
|
663
|
+
{
|
|
664
|
+
presetScenario: Thermostat.PresetScenario.Occupied,
|
|
665
|
+
numberOfPresets: presets_List.filter((p) => p.presetScenario === Thermostat.PresetScenario.Occupied).length,
|
|
666
|
+
presetTypeFeatures: {
|
|
667
|
+
automatic: false,
|
|
668
|
+
supportsNames: true,
|
|
669
|
+
},
|
|
670
|
+
},
|
|
671
|
+
{
|
|
672
|
+
presetScenario: Thermostat.PresetScenario.Unoccupied,
|
|
673
|
+
numberOfPresets: presets_List.filter((p) => p.presetScenario === Thermostat.PresetScenario.Unoccupied).length,
|
|
674
|
+
presetTypeFeatures: {
|
|
675
|
+
automatic: false,
|
|
676
|
+
supportsNames: true,
|
|
677
|
+
},
|
|
678
|
+
},
|
|
679
|
+
{
|
|
680
|
+
presetScenario: Thermostat.PresetScenario.Sleep,
|
|
681
|
+
numberOfPresets: presets_List.filter((p) => p.presetScenario === Thermostat.PresetScenario.Sleep).length,
|
|
682
|
+
presetTypeFeatures: {
|
|
683
|
+
automatic: false,
|
|
684
|
+
supportsNames: true,
|
|
685
|
+
},
|
|
686
|
+
},
|
|
687
|
+
{
|
|
688
|
+
presetScenario: Thermostat.PresetScenario.Wake,
|
|
689
|
+
numberOfPresets: presets_List.filter((p) => p.presetScenario === Thermostat.PresetScenario.Wake).length,
|
|
690
|
+
presetTypeFeatures: {
|
|
691
|
+
automatic: false,
|
|
692
|
+
supportsNames: true,
|
|
693
|
+
},
|
|
694
|
+
},
|
|
695
|
+
{
|
|
696
|
+
presetScenario: Thermostat.PresetScenario.Vacation,
|
|
697
|
+
numberOfPresets: presets_List.filter((p) => p.presetScenario === Thermostat.PresetScenario.Vacation).length,
|
|
698
|
+
presetTypeFeatures: {
|
|
699
|
+
automatic: false,
|
|
700
|
+
supportsNames: true,
|
|
701
|
+
},
|
|
702
|
+
},
|
|
703
|
+
{
|
|
704
|
+
presetScenario: Thermostat.PresetScenario.GoingToSleep,
|
|
705
|
+
numberOfPresets: presets_List.filter((p) => p.presetScenario === Thermostat.PresetScenario.GoingToSleep).length,
|
|
706
|
+
presetTypeFeatures: {
|
|
707
|
+
automatic: false,
|
|
708
|
+
supportsNames: true,
|
|
709
|
+
},
|
|
710
|
+
},
|
|
711
|
+
];
|
|
712
|
+
this.thermoAutoPresets = new MatterbridgeEndpoint([thermostatDevice, bridgedNode, powerSource], { id: 'Thermostat (AutoModePresets)' }, this.config.debug)
|
|
713
|
+
.createDefaultIdentifyClusterServer()
|
|
714
|
+
.createDefaultGroupsClusterServer()
|
|
715
|
+
.createDefaultBridgedDeviceBasicInformationClusterServer('Thermostat (AutoModePresets)', 'TAP00058', 0xfff1, 'Matterbridge', 'Matterbridge Thermostat With Presets')
|
|
716
|
+
.createDefaultPresetsThermostatClusterServer(20, 18, 22, 1, 0, 35, 15, 50, 10, 30, false, 20.5, undefined, presets_List, presetTypeDefinitions)
|
|
717
|
+
.createDefaultPowerSourceWiredClusterServer();
|
|
718
|
+
if (this.thermoAutoPresets) {
|
|
719
|
+
this.thermoAutoPresets
|
|
720
|
+
.addChildDeviceType('Temperature', temperatureSensor)
|
|
721
|
+
.createDefaultTemperatureMeasurementClusterServer(21 * 100)
|
|
722
|
+
.addRequiredClusterServers();
|
|
723
|
+
this.thermoAutoPresets
|
|
724
|
+
.addChildDeviceType('Humidity', humiditySensor)
|
|
725
|
+
.createDefaultRelativeHumidityMeasurementClusterServer(50 * 100)
|
|
726
|
+
.addRequiredClusterServers();
|
|
727
|
+
this.thermoAutoPresets = await this.addDevice(this.thermoAutoPresets);
|
|
728
|
+
}
|
|
729
|
+
this.thermoAutoPresets?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
|
|
730
|
+
this.thermoAutoPresets?.log.info(`Command identify called identifyTime ${identifyTime}`);
|
|
731
|
+
});
|
|
732
|
+
this.thermoAutoPresets?.addCommandHandler('triggerEffect', async ({ request: { effectIdentifier, effectVariant } }) => {
|
|
733
|
+
this.thermoAutoPresets?.log.info(`Command identify called effectIdentifier ${effectIdentifier} effectVariant ${effectVariant}`);
|
|
734
|
+
});
|
|
735
|
+
this.thermoAutoPresets?.addCommandHandler('setpointRaiseLower', async ({ request: { mode, amount } }) => {
|
|
736
|
+
const lookupSetpointAdjustMode = ['Heat', 'Cool', 'Both'];
|
|
737
|
+
this.thermoAutoPresets?.log.info(`Command setpointRaiseLower called with mode: ${lookupSetpointAdjustMode[mode]} amount: ${amount / 10}`);
|
|
738
|
+
});
|
|
739
|
+
this.thermoAutoPresets?.addCommandHandler('setActivePresetRequest', async ({ request: { presetHandle } }) => {
|
|
740
|
+
const handle = Uint8Array.from(presetHandle);
|
|
741
|
+
const preset = presets_List.find((p) => p.presetHandle.length === handle.length && p.presetHandle.every((v, i) => v === handle[i]));
|
|
742
|
+
if (!preset) {
|
|
743
|
+
this.thermoAutoPresets?.log.error(`Command setActivePresetRequest received unknown presetHandle: ${Array.from(handle).join(',')}`);
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
await this.thermoAutoPresets?.setAttribute(ThermostatCluster.id, 'activePresetHandle', handle, this.thermoAutoPresets?.log);
|
|
747
|
+
if (preset.heatingSetpoint !== undefined) {
|
|
748
|
+
await this.thermoAutoPresets?.setAttribute(ThermostatCluster.id, 'occupiedHeatingSetpoint', preset.heatingSetpoint, this.thermoAutoPresets?.log);
|
|
749
|
+
}
|
|
750
|
+
if (preset.coolingSetpoint !== undefined) {
|
|
751
|
+
await this.thermoAutoPresets?.setAttribute(ThermostatCluster.id, 'occupiedCoolingSetpoint', preset.coolingSetpoint, this.thermoAutoPresets?.log);
|
|
752
|
+
}
|
|
753
|
+
this.thermoAutoPresets?.log.info(`Command setActivePresetRequest applied. Active preset is now '${preset.name}' (handle ${Array.from(handle).join(',')}) with heating setpoint ${preset.heatingSetpoint / 100}°C and cooling setpoint ${preset.coolingSetpoint / 100}°C.`);
|
|
754
|
+
});
|
|
755
|
+
await this.thermoAutoPresets?.subscribeAttribute(ThermostatCluster.id, 'systemMode', (value) => {
|
|
756
|
+
const lookupSystemMode = ['Off', 'Auto', '', 'Cool', 'Heat', 'EmergencyHeat', 'Precooling', 'FanOnly', 'Dry', 'Sleep'];
|
|
757
|
+
this.thermoAutoPresets?.log.info('Subscribe systemMode called with:', lookupSystemMode[value]);
|
|
758
|
+
}, this.thermoAutoPresets.log);
|
|
759
|
+
await this.thermoAutoPresets?.subscribeAttribute(ThermostatCluster.id, 'occupiedHeatingSetpoint', (value) => {
|
|
760
|
+
this.thermoAutoPresets?.log.info('Subscribe occupiedHeatingSetpoint called with:', value / 100);
|
|
761
|
+
}, this.thermoAutoPresets.log);
|
|
762
|
+
await this.thermoAutoPresets?.subscribeAttribute(ThermostatCluster.id, 'occupiedCoolingSetpoint', (value) => {
|
|
763
|
+
this.thermoAutoPresets?.log.info('Subscribe occupiedCoolingSetpoint called with:', value / 100);
|
|
764
|
+
}, this.thermoAutoPresets.log);
|
|
765
|
+
await this.thermoAutoPresets?.subscribeAttribute(ThermostatCluster.id, 'activePresetHandle', (value) => {
|
|
766
|
+
this.thermoAutoPresets?.log.info('Subscribe activePresetHandle called with:', value);
|
|
767
|
+
}, this.thermoAutoPresets.log);
|
|
768
|
+
await this.thermoAutoPresets?.subscribeAttribute(ThermostatCluster.id, 'presets', (value) => {
|
|
769
|
+
this.thermoAutoPresets?.log.info('Subscribe presets called with:', value);
|
|
770
|
+
}, this.thermoAutoPresets.log);
|
|
573
771
|
this.thermoHeat = new MatterbridgeEndpoint([thermostatDevice, bridgedNode, powerSource], { id: 'Thermostat (Heat)' }, this.config.debug)
|
|
574
772
|
.createDefaultIdentifyClusterServer()
|
|
575
773
|
.createDefaultGroupsClusterServer()
|
|
@@ -1545,14 +1743,69 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
1545
1743
|
this.log.info(`Set lights colorTemperatureMireds to ${this.intervalColorTemperature}`);
|
|
1546
1744
|
}, 60 * 1000 + 200);
|
|
1547
1745
|
}
|
|
1548
|
-
await this.outlet?.setAttribute(OnOff.Cluster.id, 'onOff', false, this.outlet.log);
|
|
1549
1746
|
this.outlet?.log.info('Set outlet initial onOff to false');
|
|
1747
|
+
await this.outlet?.setAttribute(OnOff.Cluster.id, 'onOff', false, this.outlet.log);
|
|
1748
|
+
this.outletEnergy?.log.info('Set outlet initial onOff to false and energy/power to 0');
|
|
1749
|
+
await this.outletEnergy?.setAttribute(OnOff.Cluster.id, 'onOff', false, this.outletEnergy.log);
|
|
1750
|
+
await this.outletEnergy?.setAttribute(ElectricalEnergyMeasurement.Cluster.id, 'cumulativeEnergyImported', { energy: 0 }, this.outletEnergy.log);
|
|
1751
|
+
await this.outletEnergy?.setAttribute(ElectricalPowerMeasurement.Cluster.id, 'voltage', 220_000, this.outletEnergy.log);
|
|
1752
|
+
await this.outletEnergy?.setAttribute(ElectricalPowerMeasurement.Cluster.id, 'activeCurrent', 0, this.outletEnergy.log);
|
|
1753
|
+
await this.outletEnergy?.setAttribute(ElectricalPowerMeasurement.Cluster.id, 'activePower', 0, this.outletEnergy.log);
|
|
1754
|
+
this.outletEnergyApparent?.log.info('Set outlet initial onOff to false and apparent energy/power to 0');
|
|
1755
|
+
await this.outletEnergyApparent?.setAttribute(OnOff.Cluster.id, 'onOff', false, this.outletEnergyApparent.log);
|
|
1756
|
+
await this.outletEnergyApparent?.setAttribute(ElectricalEnergyMeasurement.Cluster.id, 'cumulativeEnergyImported', { energy: 0 }, this.outletEnergyApparent.log);
|
|
1757
|
+
await this.outletEnergyApparent?.setAttribute(ElectricalPowerMeasurement.Cluster.id, 'voltage', 220_000, this.outletEnergyApparent.log);
|
|
1758
|
+
await this.outletEnergyApparent?.setAttribute(ElectricalPowerMeasurement.Cluster.id, 'apparentCurrent', 0, this.outletEnergyApparent.log);
|
|
1759
|
+
await this.outletEnergyApparent?.setAttribute(ElectricalPowerMeasurement.Cluster.id, 'apparentPower', 0, this.outletEnergyApparent.log);
|
|
1550
1760
|
if (this.config.useInterval) {
|
|
1551
1761
|
this.outletInterval = setInterval(async () => {
|
|
1552
|
-
|
|
1762
|
+
let state = this.outlet?.getAttribute(OnOff.Cluster.id, 'onOff', this.outlet.log);
|
|
1553
1763
|
if (isValidBoolean(state)) {
|
|
1554
|
-
await this.outlet?.setAttribute(OnOff.Cluster.id, 'onOff', !state, this.outlet.log);
|
|
1555
1764
|
this.outlet?.log.info(`Set outlet onOff to ${!state}`);
|
|
1765
|
+
await this.outlet?.setAttribute(OnOff.Cluster.id, 'onOff', !state, this.outlet.log);
|
|
1766
|
+
}
|
|
1767
|
+
state = this.outletEnergy?.getAttribute(OnOff.Cluster.id, 'onOff', this.outletEnergy.log);
|
|
1768
|
+
if (isValidBoolean(state)) {
|
|
1769
|
+
this.outletEnergy?.log.info(`Set outlet onOff to ${!state}`);
|
|
1770
|
+
await this.outletEnergy?.setAttribute(OnOff.Cluster.id, 'onOff', !state, this.outletEnergy.log);
|
|
1771
|
+
if (!state) {
|
|
1772
|
+
await this.outletEnergy?.setAttribute(ElectricalPowerMeasurement.Cluster.id, 'activeCurrent', 100_000, this.outletEnergy.log);
|
|
1773
|
+
await this.outletEnergy?.setAttribute(ElectricalPowerMeasurement.Cluster.id, 'activePower', 220_000_000, this.outletEnergy.log);
|
|
1774
|
+
const energy = this.outletEnergy?.getAttribute(ElectricalEnergyMeasurement.Cluster.id, 'cumulativeEnergyImported', this.outletEnergy.log);
|
|
1775
|
+
if (isValidObject(energy, 1)) {
|
|
1776
|
+
if (typeof energy.energy === 'bigint')
|
|
1777
|
+
energy.energy += 5000n;
|
|
1778
|
+
else
|
|
1779
|
+
energy.energy += 5000;
|
|
1780
|
+
await this.outletEnergy?.setAttribute(ElectricalEnergyMeasurement.Cluster.id, 'cumulativeEnergyImported', energy, this.outletEnergy.log);
|
|
1781
|
+
}
|
|
1782
|
+
await this.outletEnergy?.setAttribute(ElectricalEnergyMeasurement.Cluster.id, 'cumulativeEnergyImported', { energy: 0 }, this.outletEnergy.log);
|
|
1783
|
+
}
|
|
1784
|
+
else {
|
|
1785
|
+
await this.outletEnergy?.setAttribute(ElectricalPowerMeasurement.Cluster.id, 'activeCurrent', 0, this.outletEnergy.log);
|
|
1786
|
+
await this.outletEnergy?.setAttribute(ElectricalPowerMeasurement.Cluster.id, 'activePower', 0, this.outletEnergy.log);
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
state = this.outletEnergyApparent?.getAttribute(OnOff.Cluster.id, 'onOff', this.outletEnergyApparent.log);
|
|
1790
|
+
if (isValidBoolean(state)) {
|
|
1791
|
+
this.outletEnergyApparent?.log.info(`Set outlet onOff to ${!state}`);
|
|
1792
|
+
await this.outletEnergyApparent?.setAttribute(OnOff.Cluster.id, 'onOff', !state, this.outletEnergyApparent.log);
|
|
1793
|
+
if (!state) {
|
|
1794
|
+
await this.outletEnergyApparent?.setAttribute(ElectricalPowerMeasurement.Cluster.id, 'apparentCurrent', 100_000, this.outletEnergyApparent.log);
|
|
1795
|
+
await this.outletEnergyApparent?.setAttribute(ElectricalPowerMeasurement.Cluster.id, 'apparentPower', 220_000_000, this.outletEnergyApparent.log);
|
|
1796
|
+
const energy = this.outletEnergyApparent?.getAttribute(ElectricalEnergyMeasurement.Cluster.id, 'cumulativeEnergyImported', this.outletEnergyApparent.log);
|
|
1797
|
+
if (isValidObject(energy, 1)) {
|
|
1798
|
+
if (typeof energy.energy === 'bigint')
|
|
1799
|
+
energy.energy += 5000n;
|
|
1800
|
+
else
|
|
1801
|
+
energy.energy += 5000;
|
|
1802
|
+
await this.outletEnergyApparent?.setAttribute(ElectricalEnergyMeasurement.Cluster.id, 'cumulativeEnergyImported', energy, this.outletEnergyApparent.log);
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
else {
|
|
1806
|
+
await this.outletEnergyApparent?.setAttribute(ElectricalPowerMeasurement.Cluster.id, 'apparentCurrent', 0, this.outletEnergyApparent.log);
|
|
1807
|
+
await this.outletEnergyApparent?.setAttribute(ElectricalPowerMeasurement.Cluster.id, 'apparentPower', 0, this.outletEnergyApparent.log);
|
|
1808
|
+
}
|
|
1556
1809
|
}
|
|
1557
1810
|
}, 60 * 1000 + 300);
|
|
1558
1811
|
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge-example-dynamic-platform",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5-dev-20260125-f72d187",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "matterbridge-example-dynamic-platform",
|
|
9
|
-
"version": "2.0.
|
|
9
|
+
"version": "2.0.5-dev-20260125-f72d187",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"node-ansi-logger": "3.1.1",
|