matterbridge-example-dynamic-platform 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -8,11 +8,40 @@ 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.2] - 2025-05-19
12
+
13
+ ### Changed
14
+
15
+ - [package]: Added waterHeater device type (not supported by Alexa and Apple Home)
16
+
17
+ ### Changed
18
+
19
+ - [package]: Changed the RVC from local implementation to the new RoboticVacuumCleaner class from matterbridge.
20
+ - [package]: Require matterbridge 3.0.3.
21
+ - [package]: Updated package.
22
+ - [package]: Updated dependencies.
23
+
24
+ <a href="https://www.buymeacoffee.com/luligugithub">
25
+ <img src="bmc-button.svg" alt="Buy me a coffee" width="80">
26
+ </a>
27
+
28
+ ## [1.2.1] - 2025-05-15
29
+
30
+ ### Changed
31
+
32
+ - [package]: Require matterbridge 3.0.1.
33
+ - [package]: Updated package.
34
+ - [package]: Updated dependencies.
35
+
36
+ <a href="https://www.buymeacoffee.com/luligugithub">
37
+ <img src="bmc-button.svg" alt="Buy me a coffee" width="80">
38
+ </a>
39
+
11
40
  ## [1.2.0] - 2025-04-30
12
41
 
13
42
  ### Added
14
43
 
15
- - [platform]: Added Robot Vacuum Cleaner device (supported by SmartThings, Alexa, Home Assistant and partially by Apple Home). Read carefully the readme please.
44
+ - [platform]: Added Robot Vacuum Cleaner device (supported by SmartThings, Alexa, Home Assistant and partially by Apple Home). Read carefully the readme please and also https://github.com/Luligu/matterbridge/discussions/264.
16
45
  - [platform]: Added OnOff Mounted Switch device (supported by SmartThings, Alexa, Home Assistant).
17
46
  - [platform]: Added Dimmer Mounted Switch device (supported by SmartThings, Alexa, Home Assistant).
18
47
  - [platform]: Added Laundry Washer device (supported by SmartThings, Alexa and Home Assistant).
package/README.md CHANGED
@@ -43,7 +43,7 @@ It exposes 38 devices:
43
43
  - an airPurifier device with temperature and humidity sensor (supported by Apple Home)
44
44
  - a pumpDevice device
45
45
  - a waterValve device
46
- - an airQuality device with all concentration measurements clusters (supported by Apple Home only without the concentration measurements)
46
+ - an airQuality device with all concentration measurements clusters (supported by Apple Home with the concentration measurements from version 18.5)
47
47
  - a momentary switch
48
48
  - a latching switch
49
49
  - a Robot Vacuum Cleaner device (supported by SmartThings, Alexa, Home Assistant and partially by Apple Home). Read also https://github.com/Luligu/matterbridge/discussions/264.
@@ -57,6 +57,7 @@ It exposes 38 devices:
57
57
  - a microwave Oven device (supported by SmartThings, Alexa and Home Assistant)
58
58
  - an extractor Hood device (supported by SmartThings, Alexa and Home Assistant)
59
59
  - a cooktop device (supported by SmartThings, Alexa and Home Assistant)
60
+ - a water heater device (supported by SmartThings and Home Assistant)
60
61
 
61
62
  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
63
 
@@ -1,7 +1,7 @@
1
- import { MatterbridgeEndpoint, MatterbridgeServer, MatterbridgeOnOffServer, RefrigeratorTag, PositionTag, laundryWasher, laundryDryer, dishwasher, refrigerator, temperatureControlledCabinetCooler, oven, temperatureControlledCabinetHeater, microwaveOven, extractorHood, cooktop, cookSurface, powerSource, } from 'matterbridge';
2
- import { ClusterBehavior } from 'matterbridge/matter';
1
+ import { MatterbridgeEndpoint, MatterbridgeServer, MatterbridgeOnOffServer, laundryWasher, laundryDryer, dishwasher, refrigerator, temperatureControlledCabinetCooler, oven, temperatureControlledCabinetHeater, microwaveOven, extractorHood, cooktop, cookSurface, powerSource, } from 'matterbridge';
2
+ import { ClusterBehavior, PositionTag, RefrigeratorTag } from 'matterbridge/matter';
3
3
  import { OperationalState, TemperatureControl, DishwasherMode, LaundryWasherControls, LaundryWasherMode, LaundryDryerControls, OvenMode, ModeBase, RefrigeratorAndTemperatureControlledCabinetMode, MicrowaveOvenMode, MicrowaveOvenControl, OvenCavityOperationalState, } from 'matterbridge/matter/clusters';
4
- import { DishwasherAlarmServer, LaundryDryerControlsServer, LaundryWasherControlsServer, MicrowaveOvenControlBehavior, MicrowaveOvenModeServer, OperationalStateBehavior, TemperatureControlBehavior, } from 'matterbridge/matter/behaviors';
4
+ import { DishwasherAlarmServer, LaundryDryerControlsServer, LaundryWasherControlsServer, MicrowaveOvenControlBehavior, MicrowaveOvenModeServer, 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);
@@ -111,21 +111,6 @@ export class Appliances extends MatterbridgeEndpoint {
111
111
  });
112
112
  }
113
113
  }
114
- createDefaultOperationalStateClusterServer(operationalState = OperationalState.OperationalStateEnum.Stopped) {
115
- this.behaviors.require(MatterbridgeOperationalStateServer, {
116
- phaseList: [],
117
- currentPhase: null,
118
- operationalStateList: [
119
- { operationalStateId: OperationalState.OperationalStateEnum.Stopped, operationalStateLabel: 'Stopped' },
120
- { operationalStateId: OperationalState.OperationalStateEnum.Running, operationalStateLabel: 'Running' },
121
- { operationalStateId: OperationalState.OperationalStateEnum.Paused, operationalStateLabel: 'Paused' },
122
- { operationalStateId: OperationalState.OperationalStateEnum.Error, operationalStateLabel: 'Error' },
123
- ],
124
- operationalState,
125
- operationalError: { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' },
126
- });
127
- return this;
128
- }
129
114
  createDefaultOvenCavityOperationalStateClusterServer(operationalState = OperationalState.OperationalStateEnum.Stopped) {
130
115
  this.behaviors.require(OvenCavityOperationalStateServer, {
131
116
  phaseList: [],
@@ -288,50 +273,6 @@ export class Appliances extends MatterbridgeEndpoint {
288
273
  return endpoint;
289
274
  }
290
275
  }
291
- class MatterbridgeOperationalStateServer extends OperationalStateBehavior {
292
- initialize() {
293
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
294
- device.log.info('MatterbridgeOperationalStateServer initialized: setting operational state to Stopped');
295
- this.state.operationalState = OperationalState.OperationalStateEnum.Stopped;
296
- this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' };
297
- }
298
- pause() {
299
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
300
- device.log.info('MatterbridgeOperationalStateServer: pause called setting operational state to Paused');
301
- this.state.operationalState = OperationalState.OperationalStateEnum.Paused;
302
- this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' };
303
- return {
304
- commandResponseState: { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' },
305
- };
306
- }
307
- stop() {
308
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
309
- device.log.info('MatterbridgeOperationalStateServer: stop called setting operational state to Stopped');
310
- this.state.operationalState = OperationalState.OperationalStateEnum.Stopped;
311
- this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' };
312
- return {
313
- commandResponseState: { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' },
314
- };
315
- }
316
- start() {
317
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
318
- device.log.info('MatterbridgeOperationalStateServer: start called setting operational state to Running');
319
- this.state.operationalState = OperationalState.OperationalStateEnum.Running;
320
- this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' };
321
- return {
322
- commandResponseState: { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' },
323
- };
324
- }
325
- resume() {
326
- const device = this.endpoint.stateOf(MatterbridgeServer).deviceCommand;
327
- device.log.info('MatterbridgeOperationalStateServer: resume called setting operational state to Running');
328
- this.state.operationalState = OperationalState.OperationalStateEnum.Running;
329
- this.state.operationalError = { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' };
330
- return {
331
- commandResponseState: { errorStateId: OperationalState.ErrorState.NoError, errorStateLabel: 'No error', errorStateDetails: 'Fully operational' },
332
- };
333
- }
334
- }
335
276
  class MatterbridgeLevelTemperatureControlServer extends TemperatureControlBehavior.with(TemperatureControl.Feature.TemperatureLevel) {
336
277
  initialize() {
337
278
  if (this.state.supportedTemperatureLevels.length >= 2) {
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;
@@ -35,6 +34,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
35
34
  momentarySwitch;
36
35
  latchingSwitch;
37
36
  vacuum;
37
+ heater;
38
38
  switchInterval;
39
39
  lightInterval;
40
40
  outletInterval;
@@ -57,16 +57,14 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
57
57
  fanModeLookup = ['Off', 'Low', 'Medium', 'High', 'On', 'Auto', 'Smart'];
58
58
  constructor(matterbridge, log, config) {
59
59
  super(matterbridge, log, config);
60
- if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.0.0')) {
61
- throw new Error(`This plugin requires Matterbridge version >= "3.0.0". Please update Matterbridge from ${this.matterbridge.matterbridgeVersion} to the latest version in the frontend.`);
60
+ if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.0.3')) {
61
+ throw new Error(`This plugin requires Matterbridge version >= "3.0.3". Please update Matterbridge from ${this.matterbridge.matterbridgeVersion} to the latest version in the frontend.`);
62
62
  }
63
63
  this.log.info('Initializing platform:', this.config.name);
64
64
  if (config.whiteList === undefined)
65
65
  config.whiteList = [];
66
66
  if (config.blackList === undefined)
67
67
  config.blackList = [];
68
- if (config.enableConcentrationMeasurements === undefined)
69
- config.enableConcentrationMeasurements = false;
70
68
  if (config.enableRVC === undefined)
71
69
  config.enableRVC = false;
72
70
  }
@@ -720,11 +718,15 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
720
718
  });
721
719
  this.pump?.addCommandHandler('on', async () => {
722
720
  this.pump?.log.info('Command on called');
723
- await this.pump?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.pump?.log);
724
721
  });
725
722
  this.pump?.addCommandHandler('off', async () => {
726
723
  this.pump?.log.info('Command off called');
727
- await this.pump?.setAttribute(OnOff.Cluster.id, 'onOff', false, this.pump?.log);
724
+ });
725
+ this.pump?.addCommandHandler('moveToLevel', async ({ request: { level } }) => {
726
+ this.pump?.log.info(`Command moveToLevel called request: ${level}`);
727
+ });
728
+ this.pump?.addCommandHandler('moveToLevelWithOnOff', async ({ request: { level } }) => {
729
+ this.pump?.log.info(`Command moveToLevelWithOnOff called request: ${level}`);
728
730
  });
729
731
  this.valve = new MatterbridgeEndpoint([waterValve, bridgedNode, powerSource], { uniqueStorageKey: 'Water valve' }, this.config.debug)
730
732
  .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)
@@ -837,9 +839,8 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
837
839
  .createDefaultBridgedDeviceBasicInformationClusterServer('SmokeCo alarm sensor', 'serial_94745631225', 0xfff1, 'Matterbridge', 'Matterbridge SmokeCoAlarm', parseInt(this.version.replace(/\D/g, '')), this.version === '' ? 'Unknown' : this.version, parseInt(this.matterbridge.matterbridgeVersion.replace(/\D/g, '')), this.matterbridge.matterbridgeVersion)
838
840
  .createDefaultIdentifyClusterServer()
839
841
  .createDefaultSmokeCOAlarmClusterServer(SmokeCoAlarm.AlarmState.Normal, SmokeCoAlarm.AlarmState.Normal)
840
- .createDefaultPowerSourceReplaceableBatteryClusterServer();
841
- if (this.config.enableConcentrationMeasurements === true)
842
- this.smokeCo.createDefaultCarbonMonoxideConcentrationMeasurementClusterServer(100);
842
+ .createDefaultPowerSourceReplaceableBatteryClusterServer()
843
+ .createDefaultCarbonMonoxideConcentrationMeasurementClusterServer(100);
843
844
  this.setSelectDevice(this.smokeCo.serialNumber ?? '', this.smokeCo.deviceName ?? '', undefined, 'hub');
844
845
  if (this.validateDevice(this.smokeCo.deviceName ?? '')) {
845
846
  await this.registerDevice(this.smokeCo);
@@ -865,9 +866,8 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
865
866
  .createDefaultBridgedDeviceBasicInformationClusterServer('Co alarm sensor', 'serial_947456317488', 0xfff1, 'Matterbridge', 'Matterbridge SmokeCoAlarm', parseInt(this.version.replace(/\D/g, '')), this.version === '' ? 'Unknown' : this.version, parseInt(this.matterbridge.matterbridgeVersion.replace(/\D/g, '')), this.matterbridge.matterbridgeVersion)
866
867
  .createDefaultIdentifyClusterServer()
867
868
  .createCoOnlySmokeCOAlarmClusterServer(SmokeCoAlarm.AlarmState.Normal)
868
- .createDefaultPowerSourceReplaceableBatteryClusterServer();
869
- if (this.config.enableConcentrationMeasurements === true)
870
- this.coOnly.createDefaultCarbonMonoxideConcentrationMeasurementClusterServer(100);
869
+ .createDefaultPowerSourceReplaceableBatteryClusterServer()
870
+ .createDefaultCarbonMonoxideConcentrationMeasurementClusterServer(100);
871
871
  this.setSelectDevice(this.coOnly.serialNumber ?? '', this.coOnly.deviceName ?? '', undefined, 'hub');
872
872
  if (this.validateDevice(this.coOnly.deviceName ?? '')) {
873
873
  await this.registerDevice(this.coOnly);
@@ -880,19 +880,17 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
880
880
  .createDefaultBridgedDeviceBasicInformationClusterServer('Air quality sensor', 'serial_987484318322', 0xfff1, 'Matterbridge', 'Matterbridge Air Quality Sensor', parseInt(this.version.replace(/\D/g, '')), this.version === '' ? 'Unknown' : this.version, parseInt(this.matterbridge.matterbridgeVersion.replace(/\D/g, '')), this.matterbridge.matterbridgeVersion)
881
881
  .createDefaultPowerSourceReplaceableBatteryClusterServer(50, PowerSource.BatChargeLevel.Warning, 2900, 'CR2450', 1)
882
882
  .addRequiredClusterServers()
883
- .addClusterServers([TemperatureMeasurement.Cluster.id, RelativeHumidityMeasurement.Cluster.id]);
884
- if (this.config.enableConcentrationMeasurements === true) {
885
- this.airQuality.createDefaultCarbonMonoxideConcentrationMeasurementClusterServer(10);
886
- this.airQuality.createDefaultCarbonDioxideConcentrationMeasurementClusterServer(400);
887
- this.airQuality.createDefaultNitrogenDioxideConcentrationMeasurementClusterServer(1);
888
- this.airQuality.createDefaultOzoneConcentrationMeasurementClusterServer(1);
889
- this.airQuality.createDefaultFormaldehydeConcentrationMeasurementClusterServer(1);
890
- this.airQuality.createDefaultPm1ConcentrationMeasurementClusterServer(100);
891
- this.airQuality.createDefaultPm25ConcentrationMeasurementClusterServer(100);
892
- this.airQuality.createDefaultPm10ConcentrationMeasurementClusterServer(100);
893
- this.airQuality.createDefaultRadonConcentrationMeasurementClusterServer(100);
894
- this.airQuality.createDefaultTvocMeasurementClusterServer(100);
895
- }
883
+ .addClusterServers([TemperatureMeasurement.Cluster.id, RelativeHumidityMeasurement.Cluster.id])
884
+ .createDefaultCarbonMonoxideConcentrationMeasurementClusterServer(10)
885
+ .createDefaultCarbonDioxideConcentrationMeasurementClusterServer(400)
886
+ .createDefaultNitrogenDioxideConcentrationMeasurementClusterServer(1)
887
+ .createDefaultOzoneConcentrationMeasurementClusterServer(1)
888
+ .createDefaultFormaldehydeConcentrationMeasurementClusterServer(1)
889
+ .createDefaultPm1ConcentrationMeasurementClusterServer(100)
890
+ .createDefaultPm25ConcentrationMeasurementClusterServer(100)
891
+ .createDefaultPm10ConcentrationMeasurementClusterServer(100)
892
+ .createDefaultRadonConcentrationMeasurementClusterServer(100)
893
+ .createDefaultTvocMeasurementClusterServer(100);
896
894
  this.setSelectDevice(this.airQuality.serialNumber ?? '', this.airQuality.deviceName ?? '', undefined, 'hub');
897
895
  if (this.validateDevice(this.airQuality.deviceName ?? '')) {
898
896
  await this.registerDevice(this.airQuality);
@@ -928,13 +926,19 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
928
926
  this.latchingSwitch = undefined;
929
927
  }
930
928
  if (this.config.enableRVC === true) {
931
- const robot = new Robot('Robot Vacuum', '1238777820');
929
+ const robot = new RoboticVacuumCleaner('Robot Vacuum', '1238777820');
932
930
  this.setSelectDevice(robot.serialNumber ?? '', robot.deviceName ?? '', undefined, 'hub');
933
931
  if (this.validateDevice(robot.deviceName ?? '')) {
934
932
  await this.registerDevice(robot);
935
933
  this.bridgedDevices.set(robot.deviceName ?? '', robot);
936
934
  }
937
935
  }
936
+ const heater = new WaterHeater('Water Heater', '3456177820');
937
+ this.setSelectDevice(heater.serialNumber ?? '', heater.deviceName ?? '', undefined, 'hub');
938
+ if (this.validateDevice(heater.deviceName ?? '')) {
939
+ await this.registerDevice(heater);
940
+ this.bridgedDevices.set(heater.deviceName ?? '', heater);
941
+ }
938
942
  const laundryWasherDevice = new Appliances(laundryWasher, 'Laundry Washer', '1234567890');
939
943
  this.setSelectDevice(laundryWasherDevice.serialNumber ?? '', laundryWasherDevice.deviceName ?? '', undefined, 'hub');
940
944
  if (this.validateDevice(laundryWasherDevice.deviceName ?? '')) {
@@ -39,13 +39,8 @@
39
39
  "type": "boolean",
40
40
  "default": true
41
41
  },
42
- "enableConcentrationMeasurements": {
43
- "description": "Enable the ConcentrationMeasurements in the Air Quality device and SmokeCoSensor device (Apple Home 18.4 will discard these devices when enabled)",
44
- "type": "boolean",
45
- "default": false
46
- },
47
42
  "enableRVC": {
48
- "description": "Enable the Robot Vacuum Cleaner (Apple Home 18.4 will crash unless you use child bridge and put the rvc in the white list as a single device)",
43
+ "description": "Enable the Robot Vacuum Cleaner (Apple Home will crash unless you use child bridge and put the rvc in the white list as a single device)",
49
44
  "type": "boolean",
50
45
  "default": false
51
46
  },
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "matterbridge-example-dynamic-platform",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "matterbridge-example-dynamic-platform",
9
- "version": "1.2.0",
9
+ "version": "1.2.2",
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.0",
3
+ "version": "1.2.2",
4
4
  "description": "Matterbridge dynamic plugin",
5
5
  "author": "https://github.com/Luligu",
6
6
  "license": "MIT",
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
- }