matterbridge-example-dynamic-platform 1.2.1 → 1.2.3-rc.1
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 +33 -0
- package/README.md +4 -2
- package/dist/appliances.js +13 -18
- package/dist/platform.js +128 -84
- package/npm-shrinkwrap.json +2 -2
- package/package.json +6 -2
- package/dist/robot.js +0 -210
package/CHANGELOG.md
CHANGED
@@ -8,6 +8,39 @@ If you like this project and find it useful, please consider giving it a star on
|
|
8
8
|
<img src="bmc-button.svg" alt="Buy me a coffee" width="120">
|
9
9
|
</a>
|
10
10
|
|
11
|
+
## [1.2.3] - 2025-05-25
|
12
|
+
|
13
|
+
### Added
|
14
|
+
|
15
|
+
- [platform]: Added a cover device with both lift and tilt (supported by the Home app).
|
16
|
+
|
17
|
+
### Changed
|
18
|
+
|
19
|
+
- [package]: Require matterbridge 3.0.4.
|
20
|
+
- [package]: Updated package.
|
21
|
+
- [package]: Updated dependencies.
|
22
|
+
|
23
|
+
<a href="https://www.buymeacoffee.com/luligugithub">
|
24
|
+
<img src="bmc-button.svg" alt="Buy me a coffee" width="80">
|
25
|
+
</a>
|
26
|
+
|
27
|
+
## [1.2.2] - 2025-05-19
|
28
|
+
|
29
|
+
### Added
|
30
|
+
|
31
|
+
- [package]: Added waterHeater device type (not supported by Alexa and Apple Home)
|
32
|
+
|
33
|
+
### Changed
|
34
|
+
|
35
|
+
- [package]: Changed the RVC from local implementation to the new RoboticVacuumCleaner class from matterbridge.
|
36
|
+
- [package]: Require matterbridge 3.0.3.
|
37
|
+
- [package]: Updated package.
|
38
|
+
- [package]: Updated dependencies.
|
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
|
+
|
11
44
|
## [1.2.1] - 2025-05-15
|
12
45
|
|
13
46
|
### Changed
|
package/README.md
CHANGED
@@ -16,7 +16,7 @@
|
|
16
16
|
|
17
17
|
Matterbridge dynamic platform example plugin is a template to develop your own plugin using the dynamic platform.
|
18
18
|
|
19
|
-
It exposes
|
19
|
+
It exposes 40 virtual devices:
|
20
20
|
|
21
21
|
- a switch with onOff cluster
|
22
22
|
- a light with onOff
|
@@ -26,7 +26,8 @@ It exposes 38 devices:
|
|
26
26
|
- a light with onOff, levelControl and colorControl (with XY and CT) clusters
|
27
27
|
- a light with onOff, levelControl and colorControl (with CT only) clusters
|
28
28
|
- an outlet (plug) with onOff cluster
|
29
|
-
- a cover with windowCovering cluster
|
29
|
+
- a cover with windowCovering cluster and lift feature
|
30
|
+
- a cover with windowCovering cluster and both lift and tilt features
|
30
31
|
- a lock with doorLock cluster
|
31
32
|
- a thermo autoMode (i.e. with Auto Heat and Cool features) with thermostat cluster and 3 sub endpoints with flowMeasurement cluster, temperatureMeasurement cluster
|
32
33
|
and relativeHumidityMeasurement cluster (to show how to create a composed device with sub endpoints)
|
@@ -57,6 +58,7 @@ It exposes 38 devices:
|
|
57
58
|
- a microwave Oven device (supported by SmartThings, Alexa and Home Assistant)
|
58
59
|
- an extractor Hood device (supported by SmartThings, Alexa and Home Assistant)
|
59
60
|
- a cooktop device (supported by SmartThings, Alexa and Home Assistant)
|
61
|
+
- a water heater device (supported by SmartThings and Home Assistant)
|
60
62
|
|
61
63
|
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.
|
62
64
|
|
package/dist/appliances.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import { MatterbridgeEndpoint, MatterbridgeServer, MatterbridgeOnOffServer, laundryWasher, laundryDryer, dishwasher, refrigerator, temperatureControlledCabinetCooler, oven, temperatureControlledCabinetHeater, microwaveOven, extractorHood, cooktop, cookSurface, powerSource, } from 'matterbridge';
|
2
|
-
import {
|
3
|
-
import { OperationalState, TemperatureControl, DishwasherMode, LaundryWasherControls, LaundryWasherMode, LaundryDryerControls, OvenMode, ModeBase, RefrigeratorAndTemperatureControlledCabinetMode, MicrowaveOvenMode, MicrowaveOvenControl,
|
4
|
-
import { DishwasherAlarmServer, LaundryDryerControlsServer, LaundryWasherControlsServer, MicrowaveOvenControlBehavior, MicrowaveOvenModeServer, TemperatureControlBehavior, } from 'matterbridge/matter/behaviors';
|
2
|
+
import { PositionTag, RefrigeratorTag } from 'matterbridge/matter';
|
3
|
+
import { OperationalState, TemperatureControl, DishwasherMode, LaundryWasherControls, LaundryWasherMode, LaundryDryerControls, OvenMode, ModeBase, RefrigeratorAndTemperatureControlledCabinetMode, MicrowaveOvenMode, MicrowaveOvenControl, } from 'matterbridge/matter/clusters';
|
4
|
+
import { DishwasherAlarmServer, DishwasherModeBehavior, LaundryDryerControlsServer, LaundryWasherControlsServer, LaundryWasherModeBehavior, MicrowaveOvenControlBehavior, MicrowaveOvenModeServer, OvenCavityOperationalStateBehavior, OvenModeBehavior, RefrigeratorAndTemperatureControlledCabinetModeBehavior, TemperatureControlBehavior, } from 'matterbridge/matter/behaviors';
|
5
5
|
export class Appliances extends MatterbridgeEndpoint {
|
6
6
|
constructor(deviceType, name, serial) {
|
7
7
|
super([deviceType, powerSource], { uniqueStorageKey: `${name}-${serial}` }, true);
|
@@ -112,7 +112,7 @@ export class Appliances extends MatterbridgeEndpoint {
|
|
112
112
|
}
|
113
113
|
}
|
114
114
|
createDefaultOvenCavityOperationalStateClusterServer(operationalState = OperationalState.OperationalStateEnum.Stopped) {
|
115
|
-
this.behaviors.require(
|
115
|
+
this.behaviors.require(MatterbridgeOvenCavityOperationalStateServer, {
|
116
116
|
phaseList: [],
|
117
117
|
currentPhase: null,
|
118
118
|
operationalStateList: [
|
@@ -126,7 +126,7 @@ export class Appliances extends MatterbridgeEndpoint {
|
|
126
126
|
return this;
|
127
127
|
}
|
128
128
|
static createDefaultRefrigeratorAndTemperatureControlledCabinetModeClusterServer(endpoint, currentMode) {
|
129
|
-
endpoint.behaviors.require(
|
129
|
+
endpoint.behaviors.require(MatterbridgeRefrigeratorAndTemperatureControlledCabinetModeServer, {
|
130
130
|
supportedModes: [
|
131
131
|
{ label: 'Auto', mode: 0, modeTags: [{ value: RefrigeratorAndTemperatureControlledCabinetMode.ModeTag.Auto }] },
|
132
132
|
{ label: 'RapidCool', mode: 1, modeTags: [{ value: RefrigeratorAndTemperatureControlledCabinetMode.ModeTag.RapidCool }] },
|
@@ -137,7 +137,7 @@ export class Appliances extends MatterbridgeEndpoint {
|
|
137
137
|
return endpoint;
|
138
138
|
}
|
139
139
|
static createDefaultOvenModeClusterServer(endpoint, currentMode) {
|
140
|
-
endpoint.behaviors.require(
|
140
|
+
endpoint.behaviors.require(MatterbridgeOvenModeServer, {
|
141
141
|
supportedModes: [
|
142
142
|
{ label: 'Bake', mode: 1, modeTags: [{ value: OvenMode.ModeTag.Bake }] },
|
143
143
|
{ label: 'Convection', mode: 2, modeTags: [{ value: OvenMode.ModeTag.Convection }] },
|
@@ -155,7 +155,7 @@ export class Appliances extends MatterbridgeEndpoint {
|
|
155
155
|
return endpoint;
|
156
156
|
}
|
157
157
|
createDefaultDishwasherModeClusterServer(currentMode) {
|
158
|
-
this.behaviors.require(
|
158
|
+
this.behaviors.require(MatterbridgeDishwasherModeServer, {
|
159
159
|
supportedModes: [
|
160
160
|
{ label: 'Light', mode: 1, modeTags: [{ value: DishwasherMode.ModeTag.Light }] },
|
161
161
|
{ label: 'Normal', mode: 2, modeTags: [{ value: DishwasherMode.ModeTag.Normal }] },
|
@@ -166,7 +166,7 @@ export class Appliances extends MatterbridgeEndpoint {
|
|
166
166
|
return this;
|
167
167
|
}
|
168
168
|
createDefaultLaundryWasherModeClusterServer(currentMode) {
|
169
|
-
this.behaviors.require(
|
169
|
+
this.behaviors.require(MatterbridgeLaundryWasherModeServer, {
|
170
170
|
supportedModes: [
|
171
171
|
{ label: 'Delicate', mode: 1, modeTags: [{ value: LaundryWasherMode.ModeTag.Delicate }] },
|
172
172
|
{ label: 'Normal', mode: 2, modeTags: [{ value: LaundryWasherMode.ModeTag.Normal }] },
|
@@ -350,8 +350,7 @@ class MatterbridgeMicrowaveOvenControlServer extends MicrowaveOvenControlBehavio
|
|
350
350
|
}
|
351
351
|
}
|
352
352
|
}
|
353
|
-
export
|
354
|
-
export class OvenCavityOperationalStateServer extends OvenCavityOperationalStateBehavior {
|
353
|
+
export class MatterbridgeOvenCavityOperationalStateServer extends OvenCavityOperationalStateBehavior {
|
355
354
|
initialize() {
|
356
355
|
const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
|
357
356
|
device.log.info('OvenCavityOperationalStateServer initialized: setting operational state to Stopped and operational error to No error');
|
@@ -377,8 +376,7 @@ export class OvenCavityOperationalStateServer extends OvenCavityOperationalState
|
|
377
376
|
};
|
378
377
|
}
|
379
378
|
}
|
380
|
-
|
381
|
-
class RefrigeratorAndTemperatureControlledCabinetModeServer extends RefrigeratorAndTemperatureControlledCabinetModeBehavior {
|
379
|
+
class MatterbridgeRefrigeratorAndTemperatureControlledCabinetModeServer extends RefrigeratorAndTemperatureControlledCabinetModeBehavior {
|
382
380
|
initialize() {
|
383
381
|
const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
|
384
382
|
device.log.info('MatterbridgeRefrigeratorAndTemperatureControlledCabinetModeServer initialized: setting currentMode to 1');
|
@@ -398,8 +396,7 @@ class RefrigeratorAndTemperatureControlledCabinetModeServer extends Refrigerator
|
|
398
396
|
}
|
399
397
|
}
|
400
398
|
}
|
401
|
-
|
402
|
-
class OvenModeServer extends OvenModeBehavior {
|
399
|
+
class MatterbridgeOvenModeServer extends OvenModeBehavior {
|
403
400
|
initialize() {
|
404
401
|
const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
|
405
402
|
device.log.info('OvenModeServer initialized: setting currentMode to 3');
|
@@ -419,8 +416,7 @@ class OvenModeServer extends OvenModeBehavior {
|
|
419
416
|
}
|
420
417
|
}
|
421
418
|
}
|
422
|
-
|
423
|
-
class DishwasherModeServer extends DishwasherModeBehavior {
|
419
|
+
class MatterbridgeDishwasherModeServer extends DishwasherModeBehavior {
|
424
420
|
initialize() {
|
425
421
|
const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
|
426
422
|
device.log.info('DishwasherModeServer initialized: setting currentMode to 3');
|
@@ -448,8 +444,7 @@ class DishwasherModeServer extends DishwasherModeBehavior {
|
|
448
444
|
}
|
449
445
|
}
|
450
446
|
}
|
451
|
-
|
452
|
-
class LaundryWasherModeServer extends LaundryWasherModeBehavior {
|
447
|
+
class MatterbridgeLaundryWasherModeServer extends LaundryWasherModeBehavior {
|
453
448
|
initialize() {
|
454
449
|
const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
|
455
450
|
device.log.info('LaundryWasherModeServer initialized: setting currentMode to 3');
|
package/dist/platform.js
CHANGED
@@ -1,9 +1,8 @@
|
|
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, airConditioner, laundryWasher, cooktop, extractorHood, microwaveOven, oven, refrigerator, dishwasher, laundryDryer, onOffMountedSwitch, dimmableMountedSwitch, extendedColorLight, } 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, airConditioner, laundryWasher, cooktop, extractorHood, microwaveOven, oven, refrigerator, dishwasher, laundryDryer, onOffMountedSwitch, dimmableMountedSwitch, extendedColorLight, RoboticVacuumCleaner, WaterHeater, } from 'matterbridge';
|
2
2
|
import { isValidBoolean, isValidNumber } from 'matterbridge/utils';
|
3
3
|
import { LocationTag } from 'matterbridge/matter';
|
4
4
|
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, } from 'matterbridge/matter/clusters';
|
5
5
|
import { Appliances } from './appliances.js';
|
6
|
-
import { Robot } from './robot.js';
|
7
6
|
export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatform {
|
8
7
|
switch;
|
9
8
|
mountedOnOffSwitch;
|
@@ -15,7 +14,8 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
15
14
|
lightHS;
|
16
15
|
lightCT;
|
17
16
|
outlet;
|
18
|
-
|
17
|
+
coverLift;
|
18
|
+
coverLiftTilt;
|
19
19
|
lock;
|
20
20
|
thermoAuto;
|
21
21
|
thermoHeat;
|
@@ -35,6 +35,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
35
35
|
momentarySwitch;
|
36
36
|
latchingSwitch;
|
37
37
|
vacuum;
|
38
|
+
heater;
|
38
39
|
switchInterval;
|
39
40
|
lightInterval;
|
40
41
|
outletInterval;
|
@@ -57,8 +58,8 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
57
58
|
fanModeLookup = ['Off', 'Low', 'Medium', 'High', 'On', 'Auto', 'Smart'];
|
58
59
|
constructor(matterbridge, log, config) {
|
59
60
|
super(matterbridge, log, config);
|
60
|
-
if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.0.
|
61
|
-
throw new Error(`This plugin requires Matterbridge version >= "3.0.
|
61
|
+
if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.0.4')) {
|
62
|
+
throw new Error(`This plugin requires Matterbridge version >= "3.0.4". Please update Matterbridge from ${this.matterbridge.matterbridgeVersion} to the latest version in the frontend.`);
|
62
63
|
}
|
63
64
|
this.log.info('Initializing platform:', this.config.name);
|
64
65
|
if (config.whiteList === undefined)
|
@@ -432,41 +433,76 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
432
433
|
await this.outlet?.setAttribute(OnOff.Cluster.id, 'onOff', false, this.outlet?.log);
|
433
434
|
this.outlet?.log.info('Command off called');
|
434
435
|
});
|
435
|
-
this.
|
436
|
+
this.coverLift = new MatterbridgeEndpoint([coverDevice, bridgedNode, powerSource], { uniqueStorageKey: 'CoverLift' }, this.config.debug)
|
436
437
|
.createDefaultIdentifyClusterServer()
|
437
438
|
.createDefaultGroupsClusterServer()
|
438
|
-
.createDefaultBridgedDeviceBasicInformationClusterServer('Cover', '
|
439
|
+
.createDefaultBridgedDeviceBasicInformationClusterServer('Cover lift', 'CL01020564', 0xfff1, 'Matterbridge', 'Matterbridge Cover', parseInt(this.version.replace(/\D/g, '')), this.version === '' ? 'Unknown' : this.version, parseInt(this.matterbridge.matterbridgeVersion.replace(/\D/g, '')), this.matterbridge.matterbridgeVersion)
|
439
440
|
.createDefaultWindowCoveringClusterServer()
|
440
441
|
.createDefaultPowerSourceRechargeableBatteryClusterServer(86);
|
441
|
-
this.setSelectDevice(this.
|
442
|
-
if (this.validateDevice(this.
|
443
|
-
await this.registerDevice(this.
|
444
|
-
this.bridgedDevices.set(this.
|
442
|
+
this.setSelectDevice(this.coverLift.serialNumber ?? '', this.coverLift.deviceName ?? '', undefined, 'hub');
|
443
|
+
if (this.validateDevice(this.coverLift.deviceName ?? '')) {
|
444
|
+
await this.registerDevice(this.coverLift);
|
445
|
+
this.bridgedDevices.set(this.coverLift.deviceName ?? '', this.coverLift);
|
445
446
|
}
|
446
447
|
else {
|
447
|
-
this.
|
448
|
+
this.coverLift = undefined;
|
448
449
|
}
|
449
|
-
this.
|
450
|
-
this.
|
451
|
-
}, this.cover.log);
|
452
|
-
this.cover?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
|
453
|
-
this.cover?.log.info(`Command identify called identifyTime:${identifyTime}`);
|
450
|
+
this.coverLift?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
|
451
|
+
this.coverLift?.log.info(`Command identify called identifyTime:${identifyTime}`);
|
454
452
|
});
|
455
|
-
this.
|
456
|
-
await this.
|
457
|
-
this.
|
453
|
+
this.coverLift?.addCommandHandler('stopMotion', async () => {
|
454
|
+
await this.coverLift?.setWindowCoveringTargetAsCurrentAndStopped();
|
455
|
+
this.coverLift?.log.info(`Command stopMotion called`);
|
458
456
|
});
|
459
|
-
this.
|
460
|
-
await this.
|
461
|
-
this.
|
457
|
+
this.coverLift?.addCommandHandler('downOrClose', async () => {
|
458
|
+
await this.coverLift?.setWindowCoveringCurrentTargetStatus(10000, 10000, WindowCovering.MovementStatus.Stopped);
|
459
|
+
this.coverLift?.log.info(`Command downOrClose called`);
|
462
460
|
});
|
463
|
-
this.
|
464
|
-
await this.
|
465
|
-
this.
|
461
|
+
this.coverLift?.addCommandHandler('upOrOpen', async () => {
|
462
|
+
await this.coverLift?.setWindowCoveringCurrentTargetStatus(0, 0, WindowCovering.MovementStatus.Stopped);
|
463
|
+
this.coverLift?.log.info(`Command upOrOpen called`);
|
466
464
|
});
|
467
|
-
this.
|
468
|
-
await this.
|
469
|
-
this.
|
465
|
+
this.coverLift?.addCommandHandler('goToLiftPercentage', async ({ request: { liftPercent100thsValue } }) => {
|
466
|
+
await this.coverLift?.setWindowCoveringCurrentTargetStatus(liftPercent100thsValue, liftPercent100thsValue, WindowCovering.MovementStatus.Stopped);
|
467
|
+
this.coverLift?.log.info(`Command goToLiftPercentage ${liftPercent100thsValue} called`);
|
468
|
+
});
|
469
|
+
this.coverLiftTilt = new MatterbridgeEndpoint([coverDevice, bridgedNode, powerSource], { uniqueStorageKey: 'CoverLiftTilt' }, this.config.debug)
|
470
|
+
.createDefaultIdentifyClusterServer()
|
471
|
+
.createDefaultGroupsClusterServer()
|
472
|
+
.createDefaultBridgedDeviceBasicInformationClusterServer('Cover lift and tilt', 'CLT01020554', 0xfff1, 'Matterbridge', 'Matterbridge Cover', parseInt(this.version.replace(/\D/g, '')), this.version === '' ? 'Unknown' : this.version, parseInt(this.matterbridge.matterbridgeVersion.replace(/\D/g, '')), this.matterbridge.matterbridgeVersion)
|
473
|
+
.createDefaultLiftTiltWindowCoveringClusterServer()
|
474
|
+
.createDefaultPowerSourceRechargeableBatteryClusterServer(86);
|
475
|
+
this.setSelectDevice(this.coverLiftTilt.serialNumber ?? '', this.coverLiftTilt.deviceName ?? '', undefined, 'hub');
|
476
|
+
if (this.validateDevice(this.coverLiftTilt.deviceName ?? '')) {
|
477
|
+
await this.registerDevice(this.coverLiftTilt);
|
478
|
+
this.bridgedDevices.set(this.coverLiftTilt.deviceName ?? '', this.coverLiftTilt);
|
479
|
+
}
|
480
|
+
else {
|
481
|
+
this.coverLiftTilt = undefined;
|
482
|
+
}
|
483
|
+
this.coverLiftTilt?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
|
484
|
+
this.coverLiftTilt?.log.info(`Command identify called identifyTime:${identifyTime}`);
|
485
|
+
});
|
486
|
+
this.coverLiftTilt?.addCommandHandler('stopMotion', async () => {
|
487
|
+
await this.coverLiftTilt?.setWindowCoveringTargetAsCurrentAndStopped();
|
488
|
+
this.coverLiftTilt?.log.info(`Command stopMotion called`);
|
489
|
+
});
|
490
|
+
this.coverLiftTilt?.addCommandHandler('downOrClose', async () => {
|
491
|
+
await this.coverLiftTilt?.setWindowCoveringCurrentTargetStatus(10000, 10000, WindowCovering.MovementStatus.Stopped);
|
492
|
+
this.coverLiftTilt?.log.info(`Command downOrClose called`);
|
493
|
+
});
|
494
|
+
this.coverLiftTilt?.addCommandHandler('upOrOpen', async () => {
|
495
|
+
await this.coverLiftTilt?.setWindowCoveringCurrentTargetStatus(0, 0, WindowCovering.MovementStatus.Stopped);
|
496
|
+
this.coverLiftTilt?.log.info(`Command upOrOpen called`);
|
497
|
+
});
|
498
|
+
this.coverLiftTilt?.addCommandHandler('goToLiftPercentage', async ({ request: { liftPercent100thsValue } }) => {
|
499
|
+
await this.coverLiftTilt?.setWindowCoveringCurrentTargetStatus(liftPercent100thsValue, liftPercent100thsValue, WindowCovering.MovementStatus.Stopped);
|
500
|
+
this.coverLiftTilt?.log.info(`Command goToLiftPercentage ${liftPercent100thsValue} called`);
|
501
|
+
});
|
502
|
+
this.coverLiftTilt?.addCommandHandler('goToTiltPercentage', async ({ request: { tiltPercent100thsValue } }) => {
|
503
|
+
const position = this.coverLiftTilt?.getAttribute(WindowCovering.Cluster.id, 'currentPositionLiftPercent100ths', this.coverLiftTilt?.log);
|
504
|
+
await this.coverLiftTilt?.setWindowCoveringTargetAndCurrentPosition(position, tiltPercent100thsValue);
|
505
|
+
this.coverLiftTilt?.log.info(`Command goToTiltPercentage ${tiltPercent100thsValue} called`);
|
470
506
|
});
|
471
507
|
this.lock = new MatterbridgeEndpoint([doorLockDevice, bridgedNode, powerSource], { uniqueStorageKey: 'Lock' }, this.config.debug)
|
472
508
|
.createDefaultIdentifyClusterServer()
|
@@ -538,14 +574,14 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
538
574
|
this.thermoAuto?.log.info('Set occupiedCoolingSetpoint:', setpoint);
|
539
575
|
}
|
540
576
|
});
|
541
|
-
this.thermoAuto?.subscribeAttribute(ThermostatCluster.id, 'systemMode',
|
577
|
+
await this.thermoAuto?.subscribeAttribute(ThermostatCluster.id, 'systemMode', (value) => {
|
542
578
|
const lookupSystemMode = ['Off', 'Auto', '', 'Cool', 'Heat', 'EmergencyHeat', 'Precooling', 'FanOnly', 'Dry', 'Sleep'];
|
543
579
|
this.thermoAuto?.log.info('Subscribe systemMode called with:', lookupSystemMode[value]);
|
544
580
|
}, this.thermoAuto.log);
|
545
|
-
this.thermoAuto?.subscribeAttribute(ThermostatCluster.id, 'occupiedHeatingSetpoint',
|
581
|
+
await this.thermoAuto?.subscribeAttribute(ThermostatCluster.id, 'occupiedHeatingSetpoint', (value) => {
|
546
582
|
this.thermoAuto?.log.info('Subscribe occupiedHeatingSetpoint called with:', value / 100);
|
547
583
|
}, this.thermoAuto.log);
|
548
|
-
this.thermoAuto?.subscribeAttribute(ThermostatCluster.id, 'occupiedCoolingSetpoint',
|
584
|
+
await this.thermoAuto?.subscribeAttribute(ThermostatCluster.id, 'occupiedCoolingSetpoint', (value) => {
|
549
585
|
this.thermoAuto?.log.info('Subscribe occupiedCoolingSetpoint called with:', value / 100);
|
550
586
|
}, this.thermoAuto.log);
|
551
587
|
this.thermoHeat = new MatterbridgeEndpoint([thermostatDevice, bridgedNode, powerSource], { uniqueStorageKey: 'Thermostat (Heat)' }, this.config.debug)
|
@@ -580,11 +616,11 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
580
616
|
this.thermoHeat?.addCommandHandler('triggerEffect', async ({ request: { effectIdentifier, effectVariant } }) => {
|
581
617
|
this.thermoHeat?.log.info(`Command identify called effectIdentifier ${effectIdentifier} effectVariant ${effectVariant}`);
|
582
618
|
});
|
583
|
-
this.thermoHeat?.subscribeAttribute(ThermostatCluster.id, 'systemMode',
|
619
|
+
await this.thermoHeat?.subscribeAttribute(ThermostatCluster.id, 'systemMode', (value) => {
|
584
620
|
const lookupSystemMode = ['Off', 'Auto', '', 'Cool', 'Heat', 'EmergencyHeat', 'Precooling', 'FanOnly', 'Dry', 'Sleep'];
|
585
621
|
this.thermoHeat?.log.info('Subscribe systemMode called with:', lookupSystemMode[value]);
|
586
622
|
}, this.thermoHeat.log);
|
587
|
-
this.thermoHeat?.subscribeAttribute(ThermostatCluster.id, 'occupiedHeatingSetpoint',
|
623
|
+
await this.thermoHeat?.subscribeAttribute(ThermostatCluster.id, 'occupiedHeatingSetpoint', (value) => {
|
588
624
|
this.thermoHeat?.log.info('Subscribe occupiedHeatingSetpoint called with:', value / 100);
|
589
625
|
}, this.thermoHeat.log);
|
590
626
|
this.thermoCool = new MatterbridgeEndpoint([thermostatDevice, bridgedNode, powerSource], { uniqueStorageKey: 'Thermostat (Cool)' }, this.config.debug)
|
@@ -607,11 +643,11 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
607
643
|
this.thermoCool?.addCommandHandler('triggerEffect', async ({ request: { effectIdentifier, effectVariant } }) => {
|
608
644
|
this.thermoCool?.log.info(`Command identify called effectIdentifier ${effectIdentifier} effectVariant ${effectVariant}`);
|
609
645
|
});
|
610
|
-
this.thermoCool?.subscribeAttribute(ThermostatCluster.id, 'systemMode',
|
646
|
+
await this.thermoCool?.subscribeAttribute(ThermostatCluster.id, 'systemMode', (value) => {
|
611
647
|
const lookupSystemMode = ['Off', 'Auto', '', 'Cool', 'Heat', 'EmergencyHeat', 'Precooling', 'FanOnly', 'Dry', 'Sleep'];
|
612
648
|
this.thermoCool?.log.info('Subscribe systemMode called with:', lookupSystemMode[value]);
|
613
649
|
}, this.thermoCool.log);
|
614
|
-
this.thermoCool?.subscribeAttribute(ThermostatCluster.id, 'occupiedCoolingSetpoint',
|
650
|
+
await this.thermoCool?.subscribeAttribute(ThermostatCluster.id, 'occupiedCoolingSetpoint', (value) => {
|
615
651
|
this.thermoCool?.log.info('Subscribe occupiedCoolingSetpoint called with:', value / 100);
|
616
652
|
}, this.thermoCool.log);
|
617
653
|
this.airPurifier = new MatterbridgeEndpoint([airPurifier, temperatureSensor, humiditySensor, bridgedNode, powerSource], { uniqueStorageKey: 'Air purifier' }, this.config.debug)
|
@@ -634,31 +670,28 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
634
670
|
this.airPurifier?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
|
635
671
|
this.airPurifier?.log.info(`Command identify called identifyTime:${identifyTime}`);
|
636
672
|
});
|
637
|
-
this.airPurifier?.subscribeAttribute(FanControl.Cluster.id, 'fanMode',
|
638
|
-
this.
|
673
|
+
await this.airPurifier?.subscribeAttribute(FanControl.Cluster.id, 'fanMode', (newValue, oldValue, context) => {
|
674
|
+
this.airPurifier?.log.info(`Fan mode changed from ${this.fanModeLookup[oldValue]} to ${this.fanModeLookup[newValue]} context: ${context.offline === true ? 'offline' : 'online'}`);
|
639
675
|
if (newValue === FanControl.FanMode.Off) {
|
640
|
-
|
676
|
+
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 0, this.airPurifier?.log);
|
641
677
|
}
|
642
678
|
else if (newValue === FanControl.FanMode.Low) {
|
643
|
-
|
679
|
+
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 33, this.airPurifier?.log);
|
644
680
|
}
|
645
681
|
else if (newValue === FanControl.FanMode.Medium) {
|
646
|
-
|
682
|
+
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 66, this.airPurifier?.log);
|
647
683
|
}
|
648
684
|
else if (newValue === FanControl.FanMode.High) {
|
649
|
-
|
685
|
+
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 100, this.airPurifier?.log);
|
650
686
|
}
|
651
687
|
else if (newValue === FanControl.FanMode.On) {
|
652
|
-
|
653
|
-
}
|
654
|
-
else if (newValue === FanControl.FanMode.Auto) {
|
655
|
-
await this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 50, this.airPurifier?.log);
|
688
|
+
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 100, this.airPurifier?.log);
|
656
689
|
}
|
657
690
|
}, this.airPurifier.log);
|
658
|
-
this.airPurifier?.subscribeAttribute(FanControl.Cluster.id, 'percentSetting',
|
659
|
-
this.
|
691
|
+
await this.airPurifier?.subscribeAttribute(FanControl.Cluster.id, 'percentSetting', (newValue, oldValue, context) => {
|
692
|
+
this.airPurifier?.log.info(`Percent setting changed from ${oldValue} to ${newValue} context: ${context.offline === true ? 'offline' : 'online'}`);
|
660
693
|
if (isValidNumber(newValue, 0, 100))
|
661
|
-
|
694
|
+
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentCurrent', newValue, this.airPurifier?.log);
|
662
695
|
}, this.airPurifier.log);
|
663
696
|
this.airConditioner = new MatterbridgeEndpoint([airConditioner, bridgedNode, powerSource], { uniqueStorageKey: 'Air Conditioner' }, this.config.debug)
|
664
697
|
.createDefaultBridgedDeviceBasicInformationClusterServer('Air Conditioner', '0x96382864AC', 0xfff1, 'Matterbridge', 'Matterbridge Air Conditioner', parseInt(this.version.replace(/\D/g, '')), this.version === '' ? 'Unknown' : this.version, parseInt(this.matterbridge.matterbridgeVersion.replace(/\D/g, '')), this.matterbridge.matterbridgeVersion)
|
@@ -718,11 +751,15 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
718
751
|
});
|
719
752
|
this.pump?.addCommandHandler('on', async () => {
|
720
753
|
this.pump?.log.info('Command on called');
|
721
|
-
await this.pump?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.pump?.log);
|
722
754
|
});
|
723
755
|
this.pump?.addCommandHandler('off', async () => {
|
724
756
|
this.pump?.log.info('Command off called');
|
725
|
-
|
757
|
+
});
|
758
|
+
this.pump?.addCommandHandler('moveToLevel', async ({ request: { level } }) => {
|
759
|
+
this.pump?.log.info(`Command moveToLevel called request: ${level}`);
|
760
|
+
});
|
761
|
+
this.pump?.addCommandHandler('moveToLevelWithOnOff', async ({ request: { level } }) => {
|
762
|
+
this.pump?.log.info(`Command moveToLevelWithOnOff called request: ${level}`);
|
726
763
|
});
|
727
764
|
this.valve = new MatterbridgeEndpoint([waterValve, bridgedNode, powerSource], { uniqueStorageKey: 'Water valve' }, this.config.debug)
|
728
765
|
.createDefaultBridgedDeviceBasicInformationClusterServer('Water valve', '0x96382864WV', 0xfff1, 'Matterbridge', 'Matterbridge Water valve', parseInt(this.version.replace(/\D/g, '')), this.version === '' ? 'Unknown' : this.version, parseInt(this.matterbridge.matterbridgeVersion.replace(/\D/g, '')), this.matterbridge.matterbridgeVersion)
|
@@ -752,42 +789,42 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
752
789
|
else {
|
753
790
|
this.fan = undefined;
|
754
791
|
}
|
755
|
-
this.fan?.subscribeAttribute(FanControl.Cluster.id, 'fanMode',
|
756
|
-
this.fan?.log.info(`Fan mode changed from ${this.fanModeLookup[oldValue]} to ${this.fanModeLookup[newValue]}`);
|
792
|
+
await this.fan?.subscribeAttribute(FanControl.Cluster.id, 'fanMode', (newValue, oldValue, context) => {
|
793
|
+
this.fan?.log.info(`Fan mode changed from ${this.fanModeLookup[oldValue]} to ${this.fanModeLookup[newValue]} context: ${context.offline === true ? 'offline' : 'online'}`);
|
757
794
|
if (newValue === FanControl.FanMode.Off) {
|
758
|
-
|
759
|
-
|
795
|
+
this.fan?.setAttribute(FanControl.Cluster.id, 'percentSetting', 0, this.fan?.log);
|
796
|
+
this.fan?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 0, this.fan?.log);
|
760
797
|
}
|
761
798
|
else if (newValue === FanControl.FanMode.Low) {
|
762
|
-
|
763
|
-
|
799
|
+
this.fan?.setAttribute(FanControl.Cluster.id, 'percentSetting', 33, this.fan?.log);
|
800
|
+
this.fan?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 33, this.fan?.log);
|
764
801
|
}
|
765
802
|
else if (newValue === FanControl.FanMode.Medium) {
|
766
|
-
|
767
|
-
|
803
|
+
this.fan?.setAttribute(FanControl.Cluster.id, 'percentSetting', 66, this.fan?.log);
|
804
|
+
this.fan?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 66, this.fan?.log);
|
768
805
|
}
|
769
806
|
else if (newValue === FanControl.FanMode.High) {
|
770
|
-
|
771
|
-
|
807
|
+
this.fan?.setAttribute(FanControl.Cluster.id, 'percentSetting', 100, this.fan?.log);
|
808
|
+
this.fan?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 100, this.fan?.log);
|
772
809
|
}
|
773
810
|
else if (newValue === FanControl.FanMode.On) {
|
774
|
-
|
775
|
-
|
811
|
+
this.fan?.setAttribute(FanControl.Cluster.id, 'percentSetting', 100, this.fan?.log);
|
812
|
+
this.fan?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 100, this.fan?.log);
|
776
813
|
}
|
777
814
|
else if (newValue === FanControl.FanMode.Auto) {
|
778
|
-
|
779
|
-
|
815
|
+
this.fan?.setAttribute(FanControl.Cluster.id, 'percentSetting', 50, this.fan?.log);
|
816
|
+
this.fan?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 50, this.fan?.log);
|
780
817
|
}
|
781
818
|
}, this.fan.log);
|
782
|
-
this.fan?.subscribeAttribute(FanControl.Cluster.id, 'percentSetting',
|
783
|
-
this.fan?.log.info(`Percent setting changed from ${oldValue} to ${newValue}`);
|
819
|
+
await this.fan?.subscribeAttribute(FanControl.Cluster.id, 'percentSetting', (newValue, oldValue, context) => {
|
820
|
+
this.fan?.log.info(`Percent setting changed from ${oldValue} to ${newValue} context: ${context.offline === true ? 'offline' : 'online'}`);
|
784
821
|
if (isValidNumber(newValue, 0, 100))
|
785
|
-
|
822
|
+
this.fan?.setAttribute(FanControl.Cluster.id, 'percentCurrent', newValue, this.fan?.log);
|
786
823
|
}, this.fan.log);
|
787
|
-
this.fan?.subscribeAttribute(FanControl.Cluster.id, 'speedSetting',
|
788
|
-
this.fan?.log.info(`Speed setting changed from ${oldValue} to ${newValue}`);
|
824
|
+
await this.fan?.subscribeAttribute(FanControl.Cluster.id, 'speedSetting', (newValue, oldValue, context) => {
|
825
|
+
this.fan?.log.info(`Speed setting changed from ${oldValue} to ${newValue} context: ${context.offline === true ? 'offline' : 'online'}`);
|
789
826
|
if (isValidNumber(newValue, 0, 100))
|
790
|
-
|
827
|
+
this.fan?.setAttribute(FanControl.Cluster.id, 'speedCurrent', newValue, this.fan?.log);
|
791
828
|
}, this.fan.log);
|
792
829
|
this.waterLeak = new MatterbridgeEndpoint([waterLeakDetector, bridgedNode, powerSource], { uniqueStorageKey: 'Water leak detector' }, this.config.debug)
|
793
830
|
.createDefaultBridgedDeviceBasicInformationClusterServer('Water leak detector', 'serial_98745631222', 0xfff1, 'Matterbridge', 'Matterbridge WaterLeakDetector', parseInt(this.version.replace(/\D/g, '')), this.version === '' ? 'Unknown' : this.version, parseInt(this.matterbridge.matterbridgeVersion.replace(/\D/g, '')), this.matterbridge.matterbridgeVersion)
|
@@ -922,13 +959,19 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
922
959
|
this.latchingSwitch = undefined;
|
923
960
|
}
|
924
961
|
if (this.config.enableRVC === true) {
|
925
|
-
const robot = new
|
962
|
+
const robot = new RoboticVacuumCleaner('Robot Vacuum', '1238777820');
|
926
963
|
this.setSelectDevice(robot.serialNumber ?? '', robot.deviceName ?? '', undefined, 'hub');
|
927
964
|
if (this.validateDevice(robot.deviceName ?? '')) {
|
928
965
|
await this.registerDevice(robot);
|
929
966
|
this.bridgedDevices.set(robot.deviceName ?? '', robot);
|
930
967
|
}
|
931
968
|
}
|
969
|
+
const heater = new WaterHeater('Water Heater', '3456177820');
|
970
|
+
this.setSelectDevice(heater.serialNumber ?? '', heater.deviceName ?? '', undefined, 'hub');
|
971
|
+
if (this.validateDevice(heater.deviceName ?? '')) {
|
972
|
+
await this.registerDevice(heater);
|
973
|
+
this.bridgedDevices.set(heater.deviceName ?? '', heater);
|
974
|
+
}
|
932
975
|
const laundryWasherDevice = new Appliances(laundryWasher, 'Laundry Washer', '1234567890');
|
933
976
|
this.setSelectDevice(laundryWasherDevice.serialNumber ?? '', laundryWasherDevice.deviceName ?? '', undefined, 'hub');
|
934
977
|
if (this.validateDevice(laundryWasherDevice.deviceName ?? '')) {
|
@@ -1081,17 +1124,17 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
1081
1124
|
}
|
1082
1125
|
}, 60 * 1000 + 300);
|
1083
1126
|
}
|
1084
|
-
await this.
|
1085
|
-
this.
|
1127
|
+
await this.coverLift?.setWindowCoveringTargetAsCurrentAndStopped();
|
1128
|
+
this.coverLift?.log.info('Set cover initial targetPositionLiftPercent100ths = currentPositionLiftPercent100ths and operationalStatus to Stopped.');
|
1086
1129
|
if (this.config.useInterval) {
|
1087
1130
|
this.coverInterval = setInterval(async () => {
|
1088
|
-
let position = this.
|
1131
|
+
let position = this.coverLift?.getAttribute(WindowCovering.Cluster.id, 'currentPositionLiftPercent100ths', this.coverLift.log);
|
1089
1132
|
if (isValidNumber(position, 0, 10000)) {
|
1090
1133
|
position = position > 9000 ? 0 : position + 1000;
|
1091
|
-
await this.
|
1092
|
-
await this.
|
1093
|
-
await this.
|
1094
|
-
this.
|
1134
|
+
await this.coverLift?.setAttribute(WindowCovering.Cluster.id, 'targetPositionLiftPercent100ths', position, this.coverLift.log);
|
1135
|
+
await this.coverLift?.setAttribute(WindowCovering.Cluster.id, 'currentPositionLiftPercent100ths', position, this.coverLift.log);
|
1136
|
+
await this.coverLift?.setAttribute(WindowCovering.Cluster.id, 'operationalStatus', { global: WindowCovering.MovementStatus.Stopped, lift: WindowCovering.MovementStatus.Stopped, tilt: WindowCovering.MovementStatus.Stopped }, this.coverLift.log);
|
1137
|
+
this.coverLift?.log.info(`Set cover current and target positionLiftPercent100ths to ${position} and operationalStatus to Stopped`);
|
1095
1138
|
}
|
1096
1139
|
}, 60 * 1000 + 400);
|
1097
1140
|
}
|
@@ -1266,26 +1309,27 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
|
|
1266
1309
|
await surface2?.setAttribute(OnOff.Cluster.id, 'onOff', true, surface2.log);
|
1267
1310
|
surface2?.log.info(`Set Surface 2 onOff only OnOff to on`);
|
1268
1311
|
if (this.config.useInterval) {
|
1312
|
+
this.genericSwitchLastEvent = 'Release';
|
1269
1313
|
this.genericSwitchInterval = setInterval(async () => {
|
1270
1314
|
if (this.genericSwitchLastEvent === 'Release') {
|
1271
|
-
await this.momentarySwitch?.triggerSwitchEvent('Single', this.momentarySwitch?.log);
|
1272
1315
|
this.genericSwitchLastEvent = 'Single';
|
1316
|
+
await this.momentarySwitch?.triggerSwitchEvent('Single', this.momentarySwitch?.log);
|
1273
1317
|
}
|
1274
1318
|
else if (this.genericSwitchLastEvent === 'Single') {
|
1275
|
-
await this.momentarySwitch?.triggerSwitchEvent('Double', this.momentarySwitch?.log);
|
1276
1319
|
this.genericSwitchLastEvent = 'Double';
|
1320
|
+
await this.momentarySwitch?.triggerSwitchEvent('Double', this.momentarySwitch?.log);
|
1277
1321
|
}
|
1278
1322
|
else if (this.genericSwitchLastEvent === 'Double') {
|
1279
|
-
await this.momentarySwitch?.triggerSwitchEvent('Long', this.momentarySwitch?.log);
|
1280
1323
|
this.genericSwitchLastEvent = 'Long';
|
1324
|
+
await this.momentarySwitch?.triggerSwitchEvent('Long', this.momentarySwitch?.log);
|
1281
1325
|
}
|
1282
1326
|
else if (this.genericSwitchLastEvent === 'Long') {
|
1283
|
-
await this.latchingSwitch?.triggerSwitchEvent('Press', this.latchingSwitch?.log);
|
1284
1327
|
this.genericSwitchLastEvent = 'Press';
|
1328
|
+
await this.latchingSwitch?.triggerSwitchEvent('Press', this.latchingSwitch?.log);
|
1285
1329
|
}
|
1286
1330
|
else if (this.genericSwitchLastEvent === 'Press') {
|
1287
|
-
await this.latchingSwitch?.triggerSwitchEvent('Release', this.latchingSwitch?.log);
|
1288
1331
|
this.genericSwitchLastEvent = 'Release';
|
1332
|
+
await this.latchingSwitch?.triggerSwitchEvent('Release', this.latchingSwitch?.log);
|
1289
1333
|
}
|
1290
1334
|
}, 60 * 1000 + 1900);
|
1291
1335
|
}
|
package/npm-shrinkwrap.json
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
{
|
2
2
|
"name": "matterbridge-example-dynamic-platform",
|
3
|
-
"version": "1.2.1",
|
3
|
+
"version": "1.2.3-rc.1",
|
4
4
|
"lockfileVersion": 3,
|
5
5
|
"requires": true,
|
6
6
|
"packages": {
|
7
7
|
"": {
|
8
8
|
"name": "matterbridge-example-dynamic-platform",
|
9
|
-
"version": "1.2.1",
|
9
|
+
"version": "1.2.3-rc.1",
|
10
10
|
"license": "MIT",
|
11
11
|
"dependencies": {
|
12
12
|
"node-ansi-logger": "3.0.1",
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "matterbridge-example-dynamic-platform",
|
3
|
-
"version": "1.2.1",
|
3
|
+
"version": "1.2.3-rc.1",
|
4
4
|
"description": "Matterbridge dynamic plugin",
|
5
5
|
"author": "https://github.com/Luligu",
|
6
6
|
"license": "MIT",
|
@@ -24,7 +24,11 @@
|
|
24
24
|
"matter",
|
25
25
|
"matter.js",
|
26
26
|
"example",
|
27
|
-
"plugin"
|
27
|
+
"plugin",
|
28
|
+
"dynamic",
|
29
|
+
"platform",
|
30
|
+
"virtual device",
|
31
|
+
"virtual devices"
|
28
32
|
],
|
29
33
|
"engines": {
|
30
34
|
"node": ">=18.0.0 <19.0.0 || >=20.0.0 <21.0.0 || >=22.0.0"
|
package/dist/robot.js
DELETED
@@ -1,210 +0,0 @@
|
|
1
|
-
import { Matterbridge, MatterbridgeServer, MatterbridgeEndpoint, roboticVacuumCleaner, dishwasher } from 'matterbridge';
|
2
|
-
import { LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, DeviceTypeId, VendorId } from 'matterbridge/matter';
|
3
|
-
import { ModeBase, OperationalState, PowerSource, RvcRunMode, RvcCleanMode, RvcOperationalState, ServiceArea } from 'matterbridge/matter/clusters';
|
4
|
-
import { ActionsServer, RvcCleanModeBehavior, RvcOperationalStateBehavior, RvcRunModeBehavior, ServiceAreaBehavior } from 'matterbridge/matter/behaviors';
|
5
|
-
import { AnsiLogger } from 'matterbridge/logger';
|
6
|
-
export class Robot extends MatterbridgeEndpoint {
|
7
|
-
constructor(name, serial) {
|
8
|
-
super(roboticVacuumCleaner, { uniqueStorageKey: `${name}-${serial}` }, true);
|
9
|
-
this.createDefaultIdentifyClusterServer()
|
10
|
-
.createDefaultBasicInformationClusterServer(name, serial, 0xfff1, 'Matterbridge', 0x8000, 'Matterbridge Robot Vacuum Cleaner')
|
11
|
-
.createDefaultRvcRunModeClusterServer()
|
12
|
-
.createDefaultRvcOperationalStateClusterServer()
|
13
|
-
.createDefaultRvcCleanModeClusterServer()
|
14
|
-
.createDefaultServiceAreaClusterServer()
|
15
|
-
.createDefaultPowerSourceRechargeableBatteryClusterServer(80, PowerSource.BatChargeLevel.Ok, 5900);
|
16
|
-
}
|
17
|
-
createDefaultRvcRunModeClusterServer(currentMode, supportedModes) {
|
18
|
-
this.behaviors.require(MatterbridgeRvcRunModeServer, {
|
19
|
-
supportedModes: supportedModes ?? [
|
20
|
-
{ label: 'Idle', mode: 1, modeTags: [{ value: RvcRunMode.ModeTag.Idle }] },
|
21
|
-
{ label: 'Cleaning', mode: 2, modeTags: [{ value: RvcRunMode.ModeTag.Cleaning }] },
|
22
|
-
{ label: 'Mapping', mode: 3, modeTags: [{ value: RvcRunMode.ModeTag.Mapping }] },
|
23
|
-
{ label: 'SpotCleaning', mode: 4, modeTags: [{ value: RvcRunMode.ModeTag.Cleaning }, { value: RvcRunMode.ModeTag.Max }] },
|
24
|
-
],
|
25
|
-
currentMode: currentMode ?? 1,
|
26
|
-
});
|
27
|
-
return this;
|
28
|
-
}
|
29
|
-
createDefaultRvcCleanModeClusterServer(currentMode, supportedModes) {
|
30
|
-
this.behaviors.require(MatterbridgeRvcCleanModeServer, {
|
31
|
-
supportedModes: supportedModes ?? [
|
32
|
-
{ label: 'Vacuum', mode: 1, modeTags: [{ value: RvcCleanMode.ModeTag.Vacuum }] },
|
33
|
-
{ label: 'Mop', mode: 2, modeTags: [{ value: RvcCleanMode.ModeTag.Mop }] },
|
34
|
-
{ label: 'Clean', mode: 3, modeTags: [{ value: RvcCleanMode.ModeTag.DeepClean }] },
|
35
|
-
],
|
36
|
-
currentMode: currentMode ?? 1,
|
37
|
-
});
|
38
|
-
return this;
|
39
|
-
}
|
40
|
-
createDefaultServiceAreaClusterServer(supportedAreas, selectedAreas) {
|
41
|
-
this.behaviors.require(MatterbridgeServiceAreaServer, {
|
42
|
-
supportedAreas: supportedAreas ?? [
|
43
|
-
{
|
44
|
-
areaId: 1,
|
45
|
-
mapId: null,
|
46
|
-
areaInfo: { locationInfo: { locationName: 'Living', floorNumber: null, areaType: null }, landmarkInfo: null },
|
47
|
-
},
|
48
|
-
{
|
49
|
-
areaId: 2,
|
50
|
-
mapId: null,
|
51
|
-
areaInfo: { locationInfo: { locationName: 'Kitchen', floorNumber: null, areaType: null }, landmarkInfo: null },
|
52
|
-
},
|
53
|
-
{
|
54
|
-
areaId: 3,
|
55
|
-
mapId: null,
|
56
|
-
areaInfo: { locationInfo: { locationName: 'Bedroom', floorNumber: null, areaType: null }, landmarkInfo: null },
|
57
|
-
},
|
58
|
-
{
|
59
|
-
areaId: 4,
|
60
|
-
mapId: null,
|
61
|
-
areaInfo: { locationInfo: { locationName: 'Bathroom', floorNumber: null, areaType: null }, landmarkInfo: null },
|
62
|
-
},
|
63
|
-
],
|
64
|
-
selectedAreas: selectedAreas ?? [],
|
65
|
-
currentArea: 1,
|
66
|
-
estimatedEndTime: null,
|
67
|
-
});
|
68
|
-
return this;
|
69
|
-
}
|
70
|
-
createDefaultRvcOperationalStateClusterServer(phaseList = null, currentPhase = null, operationalStateList, operationalState, operationalError) {
|
71
|
-
this.behaviors.require(MatterbridgeRvcOperationalStateServer, {
|
72
|
-
phaseList,
|
73
|
-
currentPhase,
|
74
|
-
operationalStateList: operationalStateList ?? [
|
75
|
-
{ operationalStateId: RvcOperationalState.OperationalState.Stopped, operationalStateLabel: 'Stopped' },
|
76
|
-
{ operationalStateId: RvcOperationalState.OperationalState.Running, operationalStateLabel: 'Running' },
|
77
|
-
{ operationalStateId: RvcOperationalState.OperationalState.Paused, operationalStateLabel: 'Paused' },
|
78
|
-
{ operationalStateId: RvcOperationalState.OperationalState.Error, operationalStateLabel: 'Error' },
|
79
|
-
{ operationalStateId: RvcOperationalState.OperationalState.SeekingCharger, operationalStateLabel: 'SeekingCharger' },
|
80
|
-
{ operationalStateId: RvcOperationalState.OperationalState.Charging, operationalStateLabel: 'Charging' },
|
81
|
-
{ operationalStateId: RvcOperationalState.OperationalState.Docked, operationalStateLabel: 'Docked' },
|
82
|
-
],
|
83
|
-
operationalState: operationalState ?? RvcOperationalState.OperationalState.Docked,
|
84
|
-
operationalError: operationalError ?? { errorStateId: RvcOperationalState.ErrorState.NoError, errorStateLabel: 'No Error', errorStateDetails: 'Fully operational' },
|
85
|
-
});
|
86
|
-
return this;
|
87
|
-
}
|
88
|
-
}
|
89
|
-
export class MatterbridgeServiceAreaServer extends ServiceAreaBehavior {
|
90
|
-
initialize() {
|
91
|
-
}
|
92
|
-
selectAreas({ newAreas }) {
|
93
|
-
const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
|
94
|
-
for (const area of newAreas) {
|
95
|
-
const supportedArea = this.state.supportedAreas.find((supportedArea) => supportedArea.areaId === area);
|
96
|
-
if (!supportedArea) {
|
97
|
-
device.log.error('MatterbridgeServiceAreaServer selectAreas called with unsupported area:', area);
|
98
|
-
return { status: ServiceArea.SelectAreasStatus.UnsupportedArea, statusText: 'Unsupported areas' };
|
99
|
-
}
|
100
|
-
}
|
101
|
-
this.state.selectedAreas = newAreas;
|
102
|
-
this.state.currentArea = newAreas[0];
|
103
|
-
device.log.info(`***MatterbridgeServiceAreaServer selectAreas called with: ${newAreas.map((area) => area.toString()).join(', ')}`);
|
104
|
-
return { status: ServiceArea.SelectAreasStatus.Success, statusText: 'Succesfully selected new areas' };
|
105
|
-
}
|
106
|
-
}
|
107
|
-
export class MatterbridgeRvcRunModeServer extends RvcRunModeBehavior {
|
108
|
-
initialize() {
|
109
|
-
this.state.currentMode = 1;
|
110
|
-
}
|
111
|
-
changeToMode({ newMode }) {
|
112
|
-
const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
|
113
|
-
const changedMode = this.state.supportedModes.find((mode) => mode.mode === newMode);
|
114
|
-
if (!changedMode) {
|
115
|
-
device.log.error('MatterbridgeRvcRunModeServer changeToMode called with unsupported newMode:', newMode);
|
116
|
-
return { status: ModeBase.ModeChangeStatus.InvalidInMode, statusText: 'Invalid mode' };
|
117
|
-
}
|
118
|
-
device.changeToMode({ newMode });
|
119
|
-
this.state.currentMode = newMode;
|
120
|
-
if (changedMode.modeTags.find((tag) => tag.value === RvcRunMode.ModeTag.Cleaning)) {
|
121
|
-
device.log.info('***MatterbridgeRvcRunModeServer changeToMode called with newMode Cleaning => Running');
|
122
|
-
this.agent.get(MatterbridgeRvcOperationalStateServer).state.operationalState = RvcOperationalState.OperationalState.Running;
|
123
|
-
return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Running' };
|
124
|
-
}
|
125
|
-
else if (changedMode.modeTags.find((tag) => tag.value === RvcRunMode.ModeTag.Idle)) {
|
126
|
-
device.log.info('***MatterbridgeRvcRunModeServer changeToMode called with newMode Idle => Docked');
|
127
|
-
this.agent.get(MatterbridgeRvcOperationalStateServer).state.operationalState = RvcOperationalState.OperationalState.Docked;
|
128
|
-
return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Docked' };
|
129
|
-
}
|
130
|
-
device.log.info(`***MatterbridgeRvcRunModeServer changeToMode called with newMode ${newMode} => ${changedMode.label}`);
|
131
|
-
this.agent.get(MatterbridgeRvcOperationalStateServer).state.operationalState = RvcOperationalState.OperationalState.Running;
|
132
|
-
return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Success' };
|
133
|
-
}
|
134
|
-
}
|
135
|
-
export class MatterbridgeRvcCleanModeServer extends RvcCleanModeBehavior {
|
136
|
-
initialize() {
|
137
|
-
this.state.currentMode = 1;
|
138
|
-
}
|
139
|
-
changeToMode({ newMode }) {
|
140
|
-
const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
|
141
|
-
const supported = this.state.supportedModes.find((mode) => mode.mode === newMode);
|
142
|
-
if (!supported) {
|
143
|
-
device.log.error('***MatterbridgeRvcCleanModeServer changeToMode called with unsupported newMode:', newMode);
|
144
|
-
return { status: ModeBase.ModeChangeStatus.InvalidInMode, statusText: 'Invalid mode' };
|
145
|
-
}
|
146
|
-
device.changeToMode({ newMode });
|
147
|
-
this.state.currentMode = newMode;
|
148
|
-
device.log.info(`***MatterbridgeRvcCleanModeServer changeToMode called with newMode ${newMode} => ${supported.label}`);
|
149
|
-
return { status: ModeBase.ModeChangeStatus.Success, statusText: 'Success' };
|
150
|
-
}
|
151
|
-
}
|
152
|
-
export class MatterbridgeRvcOperationalStateServer extends RvcOperationalStateBehavior {
|
153
|
-
initialize() {
|
154
|
-
const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
|
155
|
-
device.log.info('***MatterbridgeRvcOperationalStateServer initialized: setting operational state to Docked');
|
156
|
-
this.state.operationalState = RvcOperationalState.OperationalState.Docked;
|
157
|
-
this.state.operationalError = { errorStateId: RvcOperationalState.ErrorState.NoError, errorStateLabel: 'No Error', errorStateDetails: 'Fully operational' };
|
158
|
-
}
|
159
|
-
pause() {
|
160
|
-
const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
|
161
|
-
device.log.info('MatterbridgeRvcOperationalStateServer: pause called setting operational state to Paused and currentMode to Idle');
|
162
|
-
this.agent.get(MatterbridgeRvcRunModeServer).state.currentMode = 1;
|
163
|
-
this.state.operationalState = RvcOperationalState.OperationalState.Paused;
|
164
|
-
this.state.operationalError = { errorStateId: RvcOperationalState.ErrorState.NoError, errorStateLabel: 'No Error', errorStateDetails: 'Fully operational' };
|
165
|
-
return {
|
166
|
-
commandResponseState: { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' },
|
167
|
-
};
|
168
|
-
}
|
169
|
-
resume() {
|
170
|
-
const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
|
171
|
-
device.log.info('MatterbridgeRvcOperationalStateServer: resume called setting operational state to Running and currentMode to Cleaning');
|
172
|
-
this.agent.get(MatterbridgeRvcRunModeServer).state.currentMode = 2;
|
173
|
-
this.state.operationalState = RvcOperationalState.OperationalState.Running;
|
174
|
-
this.state.operationalError = { errorStateId: RvcOperationalState.ErrorState.NoError, errorStateLabel: 'No Error', errorStateDetails: 'Fully operational' };
|
175
|
-
return {
|
176
|
-
commandResponseState: { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' },
|
177
|
-
};
|
178
|
-
}
|
179
|
-
goHome() {
|
180
|
-
const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
|
181
|
-
device.log.info('MatterbridgeRvcOperationalStateServer: goHome called setting operational state to Docked and currentMode to Idle');
|
182
|
-
this.agent.get(MatterbridgeRvcRunModeServer).state.currentMode = 1;
|
183
|
-
this.state.operationalState = RvcOperationalState.OperationalState.Docked;
|
184
|
-
this.state.operationalError = { errorStateId: RvcOperationalState.ErrorState.NoError, errorStateLabel: 'No Error', errorStateDetails: 'Fully operational' };
|
185
|
-
return {
|
186
|
-
commandResponseState: { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' },
|
187
|
-
};
|
188
|
-
}
|
189
|
-
}
|
190
|
-
function createEndpointActionsClusterServer(endpoint, endpointLists) {
|
191
|
-
endpoint.behaviors.require(ActionsServer, {
|
192
|
-
actionList: [],
|
193
|
-
endpointLists,
|
194
|
-
});
|
195
|
-
return endpoint;
|
196
|
-
}
|
197
|
-
if (process.argv.includes('-testRobot')) {
|
198
|
-
const matterbridge = await Matterbridge.loadInstance(false);
|
199
|
-
matterbridge.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4, logLevel: "debug" });
|
200
|
-
matterbridge.environment.vars.set('log.level', MatterLogLevel.DEBUG);
|
201
|
-
matterbridge.environment.vars.set('log.format', MatterLogFormat.ANSI);
|
202
|
-
matterbridge.environment.vars.set('path.root', 'matterstorage');
|
203
|
-
matterbridge.environment.vars.set('runtime.signals', true);
|
204
|
-
matterbridge.environment.vars.set('runtime.exitcode', true);
|
205
|
-
matterbridge.environment.vars.set('mdns.networkInterface', 'Wi-Fi');
|
206
|
-
await matterbridge.startMatterStorage();
|
207
|
-
const deviceType = dishwasher;
|
208
|
-
const context = await matterbridge.createServerNodeContext('Matterbridge', deviceType.name, DeviceTypeId(deviceType.code), VendorId(0xfff1), 'Matterbridge', 0x8000, 'Matterbridge device');
|
209
|
-
const server = (await matterbridge.createServerNode(context));
|
210
|
-
}
|