matterbridge-example-dynamic-platform 1.3.9 → 1.3.10
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 +1 -0
- package/dist/platform.js +76 -35
- 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
|
<img src="bmc-button.svg" alt="Buy me a coffee" width="120">
|
|
24
24
|
</a>
|
|
25
25
|
|
|
26
|
+
## [1.3.10] - 2025-09-06
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- [platform]: Added AirConditioner device class from Matterbridge.
|
|
31
|
+
- [platform]: Added a Speaker device type.
|
|
32
|
+
- [platform]: Added estimatedEndTime to Rvc animation.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- [package]: Updated dependencies.
|
|
37
|
+
- [package]: Required matterbridge 3.2.6.
|
|
38
|
+
|
|
39
|
+
<a href="https://www.buymeacoffee.com/luligugithub">
|
|
40
|
+
<img src="bmc-button.svg" alt="Buy me a coffee" width="80">
|
|
41
|
+
</a>
|
|
42
|
+
|
|
26
43
|
## [1.3.9] - 2025-08-30
|
|
27
44
|
|
|
28
45
|
### Added
|
package/README.md
CHANGED
|
@@ -76,6 +76,7 @@ It exposes 56 virtual devices:
|
|
|
76
76
|
- a solar power device
|
|
77
77
|
- a battery storage device
|
|
78
78
|
- a heat pump device
|
|
79
|
+
- a speaker device (supported by SmartThings)
|
|
79
80
|
|
|
80
81
|
All these devices continuously change state and position. The plugin also shows how to use all the command handlers (you can control all the devices), how to subscribe to attributes and how to trigger events.
|
|
81
82
|
|
package/dist/platform.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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,
|
|
2
|
-
import { RoboticVacuumCleaner, LaundryWasher, WaterHeater, Evse, SolarPower, BatteryStorage, LaundryDryer, HeatPump, Dishwasher, ExtractorHood, MicrowaveOven, Oven, Cooktop, Refrigerator, } from 'matterbridge/devices';
|
|
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';
|
|
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';
|
|
@@ -56,7 +56,6 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
56
56
|
smokeOnly;
|
|
57
57
|
coOnly;
|
|
58
58
|
airQuality;
|
|
59
|
-
airConditioner;
|
|
60
59
|
airPurifier;
|
|
61
60
|
pump;
|
|
62
61
|
valve;
|
|
@@ -77,6 +76,8 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
77
76
|
oven;
|
|
78
77
|
cooktop;
|
|
79
78
|
refrigerator;
|
|
79
|
+
airConditioner;
|
|
80
|
+
speaker;
|
|
80
81
|
phaseInterval;
|
|
81
82
|
phase = -1;
|
|
82
83
|
sensorInterval;
|
|
@@ -103,8 +104,8 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
103
104
|
fanDirectionLookup = ['Forward', 'Reverse'];
|
|
104
105
|
constructor(matterbridge, log, config) {
|
|
105
106
|
super(matterbridge, log, config);
|
|
106
|
-
if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.2.
|
|
107
|
-
throw new Error(`This plugin requires Matterbridge version >= "3.2.
|
|
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
109
|
}
|
|
109
110
|
this.log.info('Initializing platform:', this.config.name);
|
|
110
111
|
if (config.whiteList === undefined)
|
|
@@ -707,35 +708,6 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
707
708
|
if (isValidNumber(newValue, 0, 100))
|
|
708
709
|
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentCurrent', newValue, this.airPurifier?.log);
|
|
709
710
|
}, this.airPurifier.log);
|
|
710
|
-
this.airConditioner = new MatterbridgeEndpoint([airConditioner, bridgedNode, powerSource], { uniqueStorageKey: 'Air Conditioner' }, this.config.debug)
|
|
711
|
-
.createDefaultBridgedDeviceBasicInformationClusterServer('Air Conditioner', 'ACO00027', 0xfff1, 'Matterbridge', 'Matterbridge Air Conditioner')
|
|
712
|
-
.createDefaultIdentifyClusterServer()
|
|
713
|
-
.createDeadFrontOnOffClusterServer(true)
|
|
714
|
-
.createDefaultThermostatClusterServer(20, 18, 22)
|
|
715
|
-
.createDefaultThermostatUserInterfaceConfigurationClusterServer()
|
|
716
|
-
.createDefaultFanControlClusterServer(FanControl.FanMode.Auto)
|
|
717
|
-
.createDefaultTemperatureMeasurementClusterServer(20 * 100)
|
|
718
|
-
.createDefaultRelativeHumidityMeasurementClusterServer(50 * 100)
|
|
719
|
-
.createDefaultPowerSourceWiredClusterServer()
|
|
720
|
-
.addRequiredClusterServers();
|
|
721
|
-
this.airConditioner = await this.addDevice(this.airConditioner);
|
|
722
|
-
this.airConditioner?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
|
|
723
|
-
this.airConditioner?.log.info(`Command identify called identifyTime:${identifyTime}`);
|
|
724
|
-
});
|
|
725
|
-
this.airConditioner?.addCommandHandler('on', async () => {
|
|
726
|
-
this.airConditioner?.log.info('Command on called');
|
|
727
|
-
await this.airConditioner?.setAttribute(ThermostatCluster.id, 'localTemperature', 20 * 100, this.airConditioner?.log);
|
|
728
|
-
await this.airConditioner?.setAttribute(TemperatureMeasurement.Cluster.id, 'measuredValue', 20 * 100, this.airConditioner?.log);
|
|
729
|
-
await this.airConditioner?.setAttribute(RelativeHumidityMeasurementCluster.id, 'measuredValue', 50 * 100, this.airConditioner?.log);
|
|
730
|
-
await this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentSetting', 50, this.airConditioner?.log);
|
|
731
|
-
});
|
|
732
|
-
this.airConditioner?.addCommandHandler('off', async () => {
|
|
733
|
-
this.airConditioner?.log.info('Command off called');
|
|
734
|
-
await this.airConditioner?.setAttribute(ThermostatCluster.id, 'localTemperature', null, this.airConditioner?.log);
|
|
735
|
-
await this.airConditioner?.setAttribute(TemperatureMeasurement.Cluster.id, 'measuredValue', null, this.airConditioner?.log);
|
|
736
|
-
await this.airConditioner?.setAttribute(RelativeHumidityMeasurementCluster.id, 'measuredValue', null, this.airConditioner?.log);
|
|
737
|
-
await this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentSetting', null, this.airConditioner?.log);
|
|
738
|
-
});
|
|
739
711
|
this.pump = new MatterbridgeEndpoint([pumpDevice, bridgedNode, powerSource], { uniqueStorageKey: 'Pump' }, this.config.debug)
|
|
740
712
|
.createDefaultBridgedDeviceBasicInformationClusterServer('Pump', 'PUM00028', 0xfff1, 'Matterbridge', 'Matterbridge Pump')
|
|
741
713
|
.createDefaultIdentifyClusterServer()
|
|
@@ -771,6 +743,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
771
743
|
this.fanDefault = new MatterbridgeEndpoint([fanDevice, bridgedNode, powerSource], { uniqueStorageKey: 'Fan off low medium high auto' }, this.config.debug)
|
|
772
744
|
.createDefaultBridgedDeviceBasicInformationClusterServer('Fan', 'FAN00030', 0xfff1, 'Matterbridge', 'Matterbridge Fan')
|
|
773
745
|
.createDefaultPowerSourceWiredClusterServer()
|
|
746
|
+
.createDefaultFanControlClusterServer()
|
|
774
747
|
.addRequiredClusterServers();
|
|
775
748
|
this.fanDefault = await this.addDevice(this.fanDefault);
|
|
776
749
|
await this.fanDefault?.subscribeAttribute(FanControl.Cluster.id, 'fanMode', (newValue, oldValue, context) => {
|
|
@@ -1188,6 +1161,71 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
1188
1161
|
{ label: 'RapidFreeze', mode: 2, modeTags: [{ value: RefrigeratorAndTemperatureControlledCabinetMode.ModeTag.RapidFreeze }] },
|
|
1189
1162
|
], undefined, undefined, -1000);
|
|
1190
1163
|
this.refrigerator = (await this.addDevice(refrigerator));
|
|
1164
|
+
this.airConditioner = new AirConditioner('Air Conditioner', 'ACO00027', {
|
|
1165
|
+
localTemperature: 20,
|
|
1166
|
+
occupiedCoolingSetpoint: 18,
|
|
1167
|
+
occupiedHeatingSetpoint: 22,
|
|
1168
|
+
fanMode: FanControl.FanMode.Auto,
|
|
1169
|
+
})
|
|
1170
|
+
.createDefaultTemperatureMeasurementClusterServer(20 * 100)
|
|
1171
|
+
.createDefaultRelativeHumidityMeasurementClusterServer(50 * 100)
|
|
1172
|
+
.addRequiredClusterServers();
|
|
1173
|
+
this.airConditioner = await this.addDevice(this.airConditioner);
|
|
1174
|
+
this.airConditioner?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
|
|
1175
|
+
this.airConditioner?.log.info(`Command identify called identifyTime:${identifyTime}`);
|
|
1176
|
+
});
|
|
1177
|
+
this.airConditioner?.addCommandHandler('on', async () => {
|
|
1178
|
+
this.airConditioner?.log.info('Command on called');
|
|
1179
|
+
await this.airConditioner?.setAttribute(ThermostatCluster.id, 'localTemperature', 20 * 100, this.airConditioner?.log);
|
|
1180
|
+
await this.airConditioner?.setAttribute(TemperatureMeasurement.Cluster.id, 'measuredValue', 20 * 100, this.airConditioner?.log);
|
|
1181
|
+
await this.airConditioner?.setAttribute(RelativeHumidityMeasurementCluster.id, 'measuredValue', 50 * 100, this.airConditioner?.log);
|
|
1182
|
+
await this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentSetting', 50, this.airConditioner?.log);
|
|
1183
|
+
});
|
|
1184
|
+
this.airConditioner?.addCommandHandler('off', async () => {
|
|
1185
|
+
this.airConditioner?.log.info('Command off called');
|
|
1186
|
+
await this.airConditioner?.setAttribute(ThermostatCluster.id, 'localTemperature', null, this.airConditioner?.log);
|
|
1187
|
+
await this.airConditioner?.setAttribute(TemperatureMeasurement.Cluster.id, 'measuredValue', null, this.airConditioner?.log);
|
|
1188
|
+
await this.airConditioner?.setAttribute(RelativeHumidityMeasurementCluster.id, 'measuredValue', null, this.airConditioner?.log);
|
|
1189
|
+
await this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentSetting', null, this.airConditioner?.log);
|
|
1190
|
+
});
|
|
1191
|
+
await this.airConditioner?.subscribeAttribute(FanControl.Cluster.id, 'fanMode', (newValue, oldValue, context) => {
|
|
1192
|
+
this.airConditioner?.log.info(`Fan mode changed from ${this.fanModeLookup[oldValue]} to ${this.fanModeLookup[newValue]} context: ${context.offline === true ? 'offline' : 'online'}`);
|
|
1193
|
+
if (context.offline === true)
|
|
1194
|
+
return;
|
|
1195
|
+
if (newValue === FanControl.FanMode.Off) {
|
|
1196
|
+
this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentSetting', 0, this.airConditioner?.log);
|
|
1197
|
+
this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 0, this.airConditioner?.log);
|
|
1198
|
+
}
|
|
1199
|
+
else if (newValue === FanControl.FanMode.Low) {
|
|
1200
|
+
this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentSetting', 33, this.airConditioner?.log);
|
|
1201
|
+
this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 33, this.airConditioner?.log);
|
|
1202
|
+
}
|
|
1203
|
+
else if (newValue === FanControl.FanMode.Medium) {
|
|
1204
|
+
this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentSetting', 66, this.airConditioner?.log);
|
|
1205
|
+
this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 66, this.airConditioner?.log);
|
|
1206
|
+
}
|
|
1207
|
+
else if (newValue === FanControl.FanMode.High) {
|
|
1208
|
+
this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentSetting', 100, this.airConditioner?.log);
|
|
1209
|
+
this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 100, this.airConditioner?.log);
|
|
1210
|
+
}
|
|
1211
|
+
else if (newValue === FanControl.FanMode.On) {
|
|
1212
|
+
this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentSetting', 100, this.airConditioner?.log);
|
|
1213
|
+
this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 100, this.airConditioner?.log);
|
|
1214
|
+
}
|
|
1215
|
+
else if (newValue === FanControl.FanMode.Auto) {
|
|
1216
|
+
this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentSetting', 50, this.airConditioner?.log);
|
|
1217
|
+
this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 50, this.airConditioner?.log);
|
|
1218
|
+
}
|
|
1219
|
+
}, this.airConditioner?.log);
|
|
1220
|
+
await this.airConditioner?.subscribeAttribute(FanControl.Cluster.id, 'percentSetting', (newValue, oldValue, context) => {
|
|
1221
|
+
this.airConditioner?.log.info(`Percent setting changed from ${oldValue} to ${newValue} context: ${context.offline === true ? 'offline' : 'online'}`);
|
|
1222
|
+
if (context.offline === true)
|
|
1223
|
+
return;
|
|
1224
|
+
if (isValidNumber(newValue, 0, 100))
|
|
1225
|
+
this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentCurrent', newValue, this.airConditioner?.log);
|
|
1226
|
+
}, this.airConditioner?.log);
|
|
1227
|
+
this.speaker = new Speaker('Speaker', 'SPE00057', false, 100);
|
|
1228
|
+
this.speaker = (await this.addDevice(this.speaker));
|
|
1191
1229
|
}
|
|
1192
1230
|
async onConfigure() {
|
|
1193
1231
|
await super.onConfigure();
|
|
@@ -1203,7 +1241,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
1203
1241
|
await this.laundryWasher?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.laundryWasher.log);
|
|
1204
1242
|
await this.laundryDryer?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.laundryDryer.log);
|
|
1205
1243
|
await this.dishwasher?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.dishwasher.log);
|
|
1206
|
-
this.cooktop?.log.info(`Set Cooktop offOnly onOff clusters to
|
|
1244
|
+
this.cooktop?.log.info(`Set Cooktop offOnly onOff clusters to true`);
|
|
1207
1245
|
await this.cooktop?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.cooktop.log);
|
|
1208
1246
|
await this.cooktop?.getChildEndpointByName('SurfaceTopLeft')?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.cooktop?.log);
|
|
1209
1247
|
await this.cooktop?.getChildEndpointByName('SurfaceTopRight')?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.cooktop?.log);
|
|
@@ -1225,6 +1263,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
1225
1263
|
await this.roboticVacuum.setAttribute('RvcRunMode', 'currentMode', 2, this.roboticVacuum.log);
|
|
1226
1264
|
await this.roboticVacuum.setAttribute('RvcOperationalState', 'operationalState', RvcOperationalState.OperationalState.Running, this.roboticVacuum.log);
|
|
1227
1265
|
await this.roboticVacuum.setAttribute('ServiceArea', 'currentArea', 1, this.roboticVacuum.log);
|
|
1266
|
+
await this.roboticVacuum.setAttribute('ServiceArea', 'estimatedEndTime', Math.floor(Date.now() / 1000) + 300, this.roboticVacuum.log);
|
|
1228
1267
|
}
|
|
1229
1268
|
if (this.phase === 2) {
|
|
1230
1269
|
this.roboticVacuum.log.info(`RVC: pause cleaning...`);
|
|
@@ -1237,12 +1276,14 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
|
1237
1276
|
await this.roboticVacuum.setAttribute('RvcRunMode', 'currentMode', 2, this.roboticVacuum.log);
|
|
1238
1277
|
await this.roboticVacuum.setAttribute('RvcOperationalState', 'operationalState', RvcOperationalState.OperationalState.Running, this.roboticVacuum.log);
|
|
1239
1278
|
await this.roboticVacuum.setAttribute('ServiceArea', 'currentArea', 2, this.roboticVacuum.log);
|
|
1279
|
+
await this.roboticVacuum.setAttribute('ServiceArea', 'estimatedEndTime', Math.floor(Date.now() / 1000) + 180, this.roboticVacuum.log);
|
|
1240
1280
|
}
|
|
1241
1281
|
if (this.phase === 4) {
|
|
1242
1282
|
this.roboticVacuum.log.info(`RVC: stop cleaning...`);
|
|
1243
1283
|
await this.roboticVacuum.setAttribute('PowerSource', 'batPercentRemaining', 160, this.roboticVacuum.log);
|
|
1244
1284
|
await this.roboticVacuum.setAttribute('RvcRunMode', 'currentMode', 1, this.roboticVacuum.log);
|
|
1245
1285
|
await this.roboticVacuum.setAttribute('RvcOperationalState', 'operationalState', RvcOperationalState.OperationalState.Stopped, this.roboticVacuum.log);
|
|
1286
|
+
await this.roboticVacuum.setAttribute('ServiceArea', 'estimatedEndTime', 0, this.roboticVacuum.log);
|
|
1246
1287
|
}
|
|
1247
1288
|
if (this.phase === 5) {
|
|
1248
1289
|
this.roboticVacuum.log.info(`RVC: going home...`);
|
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.10",
|
|
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.10",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"node-ansi-logger": "3.1.1",
|