matterbridge-example-dynamic-platform 1.0.18 → 1.0.19

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/dist/platform.js CHANGED
@@ -1,9 +1,11 @@
1
- import { BooleanStateCluster, BooleanStateConfiguration, CarbonMonoxideConcentrationMeasurement, ColorControl, ColorControlCluster, DeviceTypes, DoorLock, DoorLockCluster, FanControl, FanControlCluster, FlowMeasurement, LevelControlCluster, OnOffCluster, RelativeHumidityMeasurement, SmokeCoAlarm, SmokeCoAlarmCluster, TemperatureMeasurement, Thermostat, ThermostatCluster, WindowCovering, WindowCoveringCluster, bridgedNode, onOffSwitch, powerSource, rainSensor, smokeCoAlarm, waterFreezeDetector, waterLeakDetector, } from 'matterbridge';
1
+ import { AirQuality, AirQualityCluster, BooleanStateCluster, BooleanStateConfiguration, CarbonDioxideConcentrationMeasurement, CarbonMonoxideConcentrationMeasurement, ColorControl, ColorControlCluster, DeviceTypes, DoorLock, DoorLockCluster, FanControl, FanControlCluster, FlowMeasurement, FormaldehydeConcentrationMeasurement, LevelControlCluster, NitrogenDioxideConcentrationMeasurement, OnOffCluster, OzoneConcentrationMeasurement, Pm10ConcentrationMeasurement, Pm1ConcentrationMeasurement, Pm25ConcentrationMeasurement, RadonConcentrationMeasurement, RelativeHumidityMeasurement, SmokeCoAlarm, SmokeCoAlarmCluster, TemperatureMeasurement, Thermostat, ThermostatCluster, TotalVolatileOrganicCompoundsConcentrationMeasurement, WindowCovering, WindowCoveringCluster, airQualitySensor, bridgedNode, onOffSwitch, powerSource, rainSensor, smokeCoAlarm, waterFreezeDetector, waterLeakDetector, } from 'matterbridge';
2
2
  import { MatterbridgeDevice, MatterbridgeDynamicPlatform } from 'matterbridge';
3
3
  import { isValidBoolean, isValidNumber } from 'matterbridge/utils';
4
- import { db, hk, or } from 'matterbridge/logger';
4
+ import { db, er, hk, or } from 'matterbridge/logger';
5
5
  export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatform {
6
6
  switch;
7
+ lightOnOff;
8
+ dimmer;
7
9
  light;
8
10
  lightXY;
9
11
  lightHS;
@@ -17,6 +19,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
17
19
  waterFreeze;
18
20
  rain;
19
21
  smoke;
22
+ airQuality;
20
23
  switchInterval;
21
24
  lightInterval;
22
25
  outletInterval;
@@ -28,6 +31,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
28
31
  waterFreezeInterval;
29
32
  rainInterval;
30
33
  smokeInterval;
34
+ airQualityInterval;
31
35
  constructor(matterbridge, log, config) {
32
36
  super(matterbridge, log, config);
33
37
  this.log.info('Initializing platform:', this.config.name);
@@ -49,12 +53,71 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
49
53
  this.log.info(`Command identify called identifyTime:${identifyTime}`);
50
54
  });
51
55
  this.switch.addCommandHandler('on', async () => {
52
- this.switch?.getClusterServer(OnOffCluster)?.setOnOffAttribute(true);
53
- this.log.info('Command on called');
56
+ this.switch?.setAttribute(OnOffCluster.id, 'onOff', true, this.switch.log, this.switch);
57
+ this.switch?.log.info('Command on called');
54
58
  });
55
59
  this.switch.addCommandHandler('off', async () => {
56
- this.switch?.getClusterServer(OnOffCluster)?.setOnOffAttribute(false);
57
- this.log.info('Command off called');
60
+ this.switch?.setAttribute(OnOffCluster.id, 'onOff', false, this.switch.log, this.switch);
61
+ this.switch?.log.info('Command off called');
62
+ });
63
+ addCommandHandler(OnOffCluster.id, 'on', async (data) => {
64
+ this.switch?.log.info(`Command on called with: ${data}`);
65
+ }, this.switch.log, this.switch);
66
+ addCommandHandler(OnOffCluster.id, 'off', async (data) => {
67
+ this.switch?.log.info(`Command off called with: ${data}`);
68
+ }, this.switch.log, this.switch);
69
+ // Create a on off light device
70
+ this.lightOnOff = new MatterbridgeDevice(DeviceTypes.ON_OFF_LIGHT, undefined, this.config.debug);
71
+ this.lightOnOff.log.logName = 'Light (on/off)';
72
+ this.lightOnOff.createDefaultIdentifyClusterServer();
73
+ this.lightOnOff.createDefaultGroupsClusterServer();
74
+ this.lightOnOff.createDefaultScenesClusterServer();
75
+ this.lightOnOff.createDefaultBridgedDeviceBasicInformationClusterServer('Light (on/off)', '0x2342375564', 0xfff1, 'Luligu', 'Matterbridge Light on/off');
76
+ this.lightOnOff.createDefaultOnOffClusterServer();
77
+ this.lightOnOff.addDeviceType(powerSource);
78
+ this.lightOnOff.createDefaultPowerSourceWiredClusterServer();
79
+ await this.registerDevice(this.lightOnOff);
80
+ this.lightOnOff.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
81
+ this.lightOnOff?.log.info(`Command identify called identifyTime:${identifyTime}`);
82
+ });
83
+ this.lightOnOff.addCommandHandler('on', async () => {
84
+ this.light?.setAttribute(OnOffCluster.id, 'onOff', true, this.lightOnOff?.log, this.lightOnOff);
85
+ this.lightOnOff?.log.info('Command on called');
86
+ });
87
+ this.lightOnOff.addCommandHandler('off', async () => {
88
+ this.light?.setAttribute(OnOffCluster.id, 'onOff', false, this.lightOnOff?.log, this.lightOnOff);
89
+ this.lightOnOff?.log.info('Command off called');
90
+ });
91
+ // Create a dimmer device
92
+ this.dimmer = new MatterbridgeDevice(DeviceTypes.DIMMABLE_LIGHT, undefined, this.config.debug);
93
+ this.dimmer.log.logName = 'Dimmer';
94
+ this.dimmer.createDefaultIdentifyClusterServer();
95
+ this.dimmer.createDefaultGroupsClusterServer();
96
+ this.dimmer.createDefaultScenesClusterServer();
97
+ this.dimmer.createDefaultBridgedDeviceBasicInformationClusterServer('Dimmer', '0x234554564', 0xfff1, 'Luligu', 'Matterbridge Dimmer');
98
+ this.dimmer.createDefaultOnOffClusterServer();
99
+ this.dimmer.createDefaultLevelControlClusterServer();
100
+ this.dimmer.addDeviceType(powerSource);
101
+ this.dimmer.createDefaultPowerSourceReplaceableBatteryClusterServer(70);
102
+ await this.registerDevice(this.dimmer);
103
+ this.dimmer.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
104
+ this.dimmer?.log.info(`Command identify called identifyTime:${identifyTime}`);
105
+ });
106
+ this.dimmer.addCommandHandler('on', async () => {
107
+ this.dimmer?.setAttribute(OnOffCluster.id, 'onOff', true, this.dimmer.log, this.dimmer);
108
+ this.dimmer?.log.info('Command on called');
109
+ });
110
+ this.dimmer.addCommandHandler('off', async () => {
111
+ this.dimmer?.setAttribute(OnOffCluster.id, 'onOff', true, this.dimmer.log, this.dimmer);
112
+ this.dimmer?.log.info('Command off called');
113
+ });
114
+ this.dimmer.addCommandHandler('moveToLevel', async ({ request: { level }, attributes: { currentLevel } }) => {
115
+ this.dimmer?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.dimmer.log, this.dimmer);
116
+ this.dimmer?.log.debug(`Command moveToLevel called request: ${level} attributes: ${currentLevel?.getLocal()}`);
117
+ });
118
+ this.dimmer.addCommandHandler('moveToLevelWithOnOff', async ({ request: { level }, attributes: { currentLevel } }) => {
119
+ this.dimmer?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.dimmer.log, this.dimmer);
120
+ this.dimmer?.log.debug(`Command moveToLevelWithOnOff called request: ${level} attributes: ${currentLevel?.getLocal()}`);
58
121
  });
59
122
  // Create a light device
60
123
  this.light = new MatterbridgeDevice(DeviceTypes.COLOR_TEMPERATURE_LIGHT, undefined, this.config.debug);
@@ -70,45 +133,45 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
70
133
  this.light.createDefaultPowerSourceReplaceableBatteryClusterServer(70);
71
134
  await this.registerDevice(this.light);
72
135
  this.light.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
73
- this.log.info(`Command identify called identifyTime:${identifyTime}`);
136
+ this.light?.log.info(`Command identify called identifyTime:${identifyTime}`);
74
137
  });
75
138
  this.light.addCommandHandler('on', async () => {
76
- this.light?.getClusterServer(OnOffCluster)?.setOnOffAttribute(true);
77
- this.log.info('Command on called');
139
+ this.light?.setAttribute(OnOffCluster.id, 'onOff', true, this.light?.log, this.light);
140
+ this.light?.log.info('Command on called');
78
141
  });
79
142
  this.light.addCommandHandler('off', async () => {
80
- this.light?.getClusterServer(OnOffCluster)?.setOnOffAttribute(false);
81
- this.log.info('Command off called');
143
+ this.light?.setAttribute(OnOffCluster.id, 'onOff', false, this.light?.log, this.light);
144
+ this.light?.log.info('Command off called');
82
145
  });
83
146
  this.light.addCommandHandler('moveToLevel', async ({ request: { level }, attributes: { currentLevel } }) => {
84
- this.light?.getClusterServer(LevelControlCluster)?.setCurrentLevelAttribute(level);
85
- this.log.debug(`Command moveToLevel called request: ${level} attributes: ${currentLevel?.getLocal()}`);
147
+ this.light?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.light?.log, this.light);
148
+ this.light?.log.debug(`Command moveToLevel called request: ${level} attributes: ${currentLevel?.getLocal()}`);
86
149
  });
87
150
  this.light.addCommandHandler('moveToLevelWithOnOff', async ({ request: { level }, attributes: { currentLevel } }) => {
88
- this.light?.getClusterServer(LevelControlCluster)?.setCurrentLevelAttribute(level);
89
- this.log.debug(`Command moveToLevelWithOnOff called request: ${level} attributes: ${currentLevel?.getLocal()}`);
151
+ this.light?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.light?.log, this.light);
152
+ this.light?.log.debug(`Command moveToLevelWithOnOff called request: ${level} attributes: ${currentLevel?.getLocal()}`);
90
153
  });
91
154
  this.light.addCommandHandler('moveToColor', async ({ request: { colorX, colorY }, attributes: { currentX, currentY } }) => {
92
- this.light?.getClusterServer(ColorControlCluster.with(ColorControl.Feature.Xy))?.setCurrentXAttribute(colorX);
93
- this.light?.getClusterServer(ColorControlCluster.with(ColorControl.Feature.Xy))?.setCurrentYAttribute(colorY);
94
- this.log.debug(`Command moveToColor called request: X ${colorX / 65536} Y ${colorY / 65536} attributes: X ${(currentX?.getLocal() ?? 0) / 65536} Y ${(currentY?.getLocal() ?? 0) / 65536}`);
155
+ this.light?.setAttribute(ColorControlCluster.id, 'currentX', colorX, this.light?.log, this.light);
156
+ this.light?.setAttribute(ColorControlCluster.id, 'currentY', colorY, this.light?.log, this.light);
157
+ this.light?.log.debug(`Command moveToColor called request: X ${colorX / 65536} Y ${colorY / 65536} attributes: X ${(currentX?.getLocal() ?? 0) / 65536} Y ${(currentY?.getLocal() ?? 0) / 65536}`);
95
158
  });
96
159
  this.light.addCommandHandler('moveToHueAndSaturation', async ({ request: { hue, saturation }, attributes: { currentHue, currentSaturation } }) => {
97
- this.light?.getClusterServer(ColorControlCluster.with(ColorControl.Feature.HueSaturation))?.setCurrentHueAttribute(hue);
98
- this.light?.getClusterServer(ColorControlCluster.with(ColorControl.Feature.HueSaturation))?.setCurrentSaturationAttribute(saturation);
99
- this.log.debug(`Command moveToHueAndSaturation called request: hue ${hue} saturation ${saturation} attributes: hue ${currentHue?.getLocal()} saturation ${currentSaturation?.getLocal()}`);
160
+ this.light?.setAttribute(ColorControlCluster.id, 'currentHue', hue, this.light?.log, this.light);
161
+ this.light?.setAttribute(ColorControlCluster.id, 'currentSaturation', saturation, this.light?.log, this.light);
162
+ this.light?.log.debug(`Command moveToHueAndSaturation called request: hue ${hue} saturation ${saturation} attributes: hue ${currentHue?.getLocal()} saturation ${currentSaturation?.getLocal()}`);
100
163
  });
101
164
  this.light.addCommandHandler('moveToHue', async ({ request: { hue }, attributes: { currentHue, currentSaturation } }) => {
102
- this.light?.getClusterServer(ColorControlCluster.with(ColorControl.Feature.HueSaturation))?.setCurrentHueAttribute(hue);
103
- this.log.debug(`Command moveToHue called request: hue ${hue} attributes: hue ${currentHue?.getLocal()} saturation ${currentSaturation?.getLocal()}`);
165
+ this.light?.setAttribute(ColorControlCluster.id, 'currentHue', hue, this.light?.log, this.light);
166
+ this.light?.log.debug(`Command moveToHue called request: hue ${hue} attributes: hue ${currentHue?.getLocal()} saturation ${currentSaturation?.getLocal()}`);
104
167
  });
105
168
  this.light.addCommandHandler('moveToSaturation', async ({ request: { saturation }, attributes: { currentHue, currentSaturation } }) => {
106
- this.light?.getClusterServer(ColorControlCluster.with(ColorControl.Feature.HueSaturation))?.setCurrentSaturationAttribute(saturation);
107
- this.log.debug(`Command moveToSaturation called request: saturation ${saturation} attributes: hue ${currentHue?.getLocal()} saturation ${currentSaturation?.getLocal()}`);
169
+ this.light?.setAttribute(ColorControlCluster.id, 'currentSaturation', saturation, this.light?.log, this.light);
170
+ this.light?.log.debug(`Command moveToSaturation called request: saturation ${saturation} attributes: hue ${currentHue?.getLocal()} saturation ${currentSaturation?.getLocal()}`);
108
171
  });
109
172
  this.light.addCommandHandler('moveToColorTemperature', async ({ request, attributes }) => {
110
- this.light?.getClusterServer(ColorControl.Complete)?.setColorTemperatureMiredsAttribute(request.colorTemperatureMireds);
111
- this.log.debug(`Command moveToColorTemperature called request: ${request.colorTemperatureMireds} attributes: ${attributes.colorTemperatureMireds?.getLocal()}`);
173
+ this.light?.setAttribute(ColorControlCluster.id, 'colorTemperatureMireds', request.colorTemperatureMireds, this.light?.log, this.light);
174
+ this.light?.log.debug(`Command moveToColorTemperature called request: ${request.colorTemperatureMireds} attributes: ${attributes.colorTemperatureMireds?.getLocal()}`);
112
175
  });
113
176
  // Create a light device with HS color control
114
177
  this.lightHS = new MatterbridgeDevice(DeviceTypes.COLOR_TEMPERATURE_LIGHT, undefined, this.config.debug);
@@ -125,36 +188,36 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
125
188
  this.lightHS.createDefaultPowerSourceWiredClusterServer();
126
189
  await this.registerDevice(this.lightHS);
127
190
  this.lightHS.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
128
- this.log.info(`Command identify called identifyTime:${identifyTime}`);
191
+ this.lightHS?.log.info(`Command identify called identifyTime:${identifyTime}`);
129
192
  });
130
193
  this.lightHS.addCommandHandler('on', async () => {
131
- this.lightHS?.getClusterServer(OnOffCluster)?.setOnOffAttribute(true);
132
- this.log.info('Command on called');
194
+ this.lightHS?.setAttribute(OnOffCluster.id, 'onOff', true, this.lightHS?.log, this.lightHS);
195
+ this.lightHS?.log.info('Command on called');
133
196
  });
134
197
  this.lightHS.addCommandHandler('off', async () => {
135
- this.lightHS?.getClusterServer(OnOffCluster)?.setOnOffAttribute(false);
136
- this.log.info('Command off called');
198
+ this.lightHS?.setAttribute(OnOffCluster.id, 'onOff', false, this.lightHS?.log, this.lightHS);
199
+ this.lightHS?.log.info('Command off called');
137
200
  });
138
201
  this.lightHS.addCommandHandler('moveToLevel', async ({ request: { level }, attributes: { currentLevel } }) => {
139
- this.lightHS?.getClusterServer(LevelControlCluster)?.setCurrentLevelAttribute(level);
140
- this.log.debug(`Command moveToLevel called request: ${level} attributes: ${currentLevel?.getLocal()}`);
202
+ this.lightHS?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.lightHS?.log, this.lightHS);
203
+ this.lightHS?.log.debug(`Command moveToLevel called request: ${level} attributes: ${currentLevel?.getLocal()}`);
141
204
  });
142
205
  this.lightHS.addCommandHandler('moveToLevelWithOnOff', async ({ request: { level }, attributes: { currentLevel } }) => {
143
- this.lightHS?.getClusterServer(LevelControlCluster)?.setCurrentLevelAttribute(level);
144
- this.log.debug(`Command moveToLevelWithOnOff called request: ${level} attributes: ${currentLevel?.getLocal()}`);
206
+ this.lightHS?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.lightHS?.log, this.lightHS);
207
+ this.lightHS?.log.debug(`Command moveToLevelWithOnOff called request: ${level} attributes: ${currentLevel?.getLocal()}`);
145
208
  });
146
209
  this.lightHS.addCommandHandler('moveToHueAndSaturation', async ({ request: { hue, saturation }, attributes: { currentHue, currentSaturation } }) => {
147
- this.lightHS?.getClusterServer(ColorControlCluster.with(ColorControl.Feature.HueSaturation))?.setCurrentHueAttribute(hue);
148
- this.lightHS?.getClusterServer(ColorControlCluster.with(ColorControl.Feature.HueSaturation))?.setCurrentSaturationAttribute(saturation);
149
- this.log.debug(`Command moveToHueAndSaturation called request: hue ${hue} saturation ${saturation} attributes: hue ${currentHue?.getLocal()} saturation ${currentSaturation?.getLocal()}`);
210
+ this.lightHS?.setAttribute(ColorControlCluster.id, 'currentHue', hue, this.lightHS?.log, this.lightHS);
211
+ this.lightHS?.setAttribute(ColorControlCluster.id, 'currentSaturation', saturation, this.lightHS?.log, this.lightHS);
212
+ this.lightHS?.log.debug(`Command moveToHueAndSaturation called request: hue ${hue} saturation ${saturation} attributes: hue ${currentHue?.getLocal()} saturation ${currentSaturation?.getLocal()}`);
150
213
  });
151
214
  this.lightHS.addCommandHandler('moveToHue', async ({ request: { hue }, attributes: { currentHue, currentSaturation } }) => {
152
- this.lightHS?.getClusterServer(ColorControlCluster.with(ColorControl.Feature.HueSaturation))?.setCurrentHueAttribute(hue);
153
- this.log.debug(`Command moveToHue called request: hue ${hue} attributes: hue ${currentHue?.getLocal()} saturation ${currentSaturation?.getLocal()}`);
215
+ this.lightHS?.setAttribute(ColorControlCluster.id, 'currentHue', hue, this.lightHS?.log, this.lightHS);
216
+ this.lightHS?.log.debug(`Command moveToHue called request: hue ${hue} attributes: hue ${currentHue?.getLocal()} saturation ${currentSaturation?.getLocal()}`);
154
217
  });
155
218
  this.lightHS.addCommandHandler('moveToSaturation', async ({ request: { saturation }, attributes: { currentHue, currentSaturation } }) => {
156
- this.lightHS?.getClusterServer(ColorControlCluster.with(ColorControl.Feature.HueSaturation))?.setCurrentSaturationAttribute(saturation);
157
- this.log.debug(`Command moveToSaturation called request: saturation ${saturation} attributes: hue ${currentHue?.getLocal()} saturation ${currentSaturation?.getLocal()}`);
219
+ this.lightHS?.setAttribute(ColorControlCluster.id, 'currentSaturation', saturation, this.lightHS?.log, this.lightHS);
220
+ this.lightHS?.log.debug(`Command moveToSaturation called request: saturation ${saturation} attributes: hue ${currentHue?.getLocal()} saturation ${currentSaturation?.getLocal()}`);
158
221
  });
159
222
  // Create a light device with XY color control
160
223
  this.lightXY = new MatterbridgeDevice(DeviceTypes.COLOR_TEMPERATURE_LIGHT, undefined, this.config.debug);
@@ -171,28 +234,28 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
171
234
  this.lightXY.createDefaultPowerSourceWiredClusterServer();
172
235
  await this.registerDevice(this.lightXY);
173
236
  this.lightXY.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
174
- this.log.info(`Command identify called identifyTime:${identifyTime}`);
237
+ this.lightXY?.log.info(`Command identify called identifyTime:${identifyTime}`);
175
238
  });
176
239
  this.lightXY.addCommandHandler('on', async () => {
177
- this.lightXY?.getClusterServer(OnOffCluster)?.setOnOffAttribute(true);
178
- this.log.info('Command on called');
240
+ this.lightXY?.setAttribute(OnOffCluster.id, 'onOff', true, this.lightXY?.log, this.lightXY);
241
+ this.lightXY?.log.info('Command on called');
179
242
  });
180
243
  this.lightXY.addCommandHandler('off', async () => {
181
- this.lightXY?.getClusterServer(OnOffCluster)?.setOnOffAttribute(false);
182
- this.log.info('Command off called');
244
+ this.lightXY?.setAttribute(OnOffCluster.id, 'onOff', false, this.lightXY?.log, this.lightXY);
245
+ this.lightXY?.log.info('Command off called');
183
246
  });
184
247
  this.lightXY.addCommandHandler('moveToLevel', async ({ request: { level }, attributes: { currentLevel } }) => {
185
- this.lightXY?.getClusterServer(LevelControlCluster)?.setCurrentLevelAttribute(level);
186
- this.log.debug(`Command moveToLevel called request: ${level} attributes: ${currentLevel?.getLocal()}`);
248
+ this.lightXY?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.lightXY?.log, this.lightXY);
249
+ this.lightXY?.log.debug(`Command moveToLevel called request: ${level} attributes: ${currentLevel?.getLocal()}`);
187
250
  });
188
251
  this.lightXY.addCommandHandler('moveToLevelWithOnOff', async ({ request: { level }, attributes: { currentLevel } }) => {
189
- this.lightXY?.getClusterServer(LevelControlCluster)?.setCurrentLevelAttribute(level);
190
- this.log.debug(`Command moveToLevelWithOnOff called request: ${level} attributes: ${currentLevel?.getLocal()}`);
252
+ this.lightXY?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.lightXY?.log, this.lightXY);
253
+ this.lightXY?.log.debug(`Command moveToLevelWithOnOff called request: ${level} attributes: ${currentLevel?.getLocal()}`);
191
254
  });
192
255
  this.lightXY.addCommandHandler('moveToColor', async ({ request: { colorX, colorY }, attributes: { currentX, currentY } }) => {
193
- this.lightXY?.getClusterServer(ColorControlCluster.with(ColorControl.Feature.Xy))?.setCurrentXAttribute(colorX);
194
- this.lightXY?.getClusterServer(ColorControlCluster.with(ColorControl.Feature.Xy))?.setCurrentYAttribute(colorY);
195
- this.log.debug(`Command moveToColor called request: X ${colorX / 65536} Y ${colorY / 65536} attributes: X ${(currentX?.getLocal() ?? 0) / 65536} Y ${(currentY?.getLocal() ?? 0) / 65536}`);
256
+ this.lightXY?.setAttribute(ColorControlCluster.id, 'currentX', colorX, this.lightXY?.log, this.lightXY);
257
+ this.lightXY?.setAttribute(ColorControlCluster.id, 'currentY', colorY, this.lightXY?.log, this.lightXY);
258
+ this.lightXY?.log.debug(`Command moveToColor called request: X ${colorX / 65536} Y ${colorY / 65536} attributes: X ${(currentX?.getLocal() ?? 0) / 65536} Y ${(currentY?.getLocal() ?? 0) / 65536}`);
196
259
  });
197
260
  // Create a light device with CT color control
198
261
  this.lightCT = new MatterbridgeDevice(DeviceTypes.COLOR_TEMPERATURE_LIGHT, undefined, this.config.debug);
@@ -209,27 +272,27 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
209
272
  this.lightCT.createDefaultPowerSourceReplaceableBatteryClusterServer(70);
210
273
  await this.registerDevice(this.lightCT);
211
274
  this.lightCT.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
212
- this.log.info(`Command identify called identifyTime:${identifyTime}`);
275
+ this.lightCT?.log.info(`Command identify called identifyTime:${identifyTime}`);
213
276
  });
214
277
  this.lightCT.addCommandHandler('on', async () => {
215
- this.lightCT?.getClusterServer(OnOffCluster)?.setOnOffAttribute(true);
216
- this.log.info('Command on called');
278
+ this.lightCT?.setAttribute(OnOffCluster.id, 'onOff', true, this.lightCT?.log, this.lightCT);
279
+ this.lightCT?.log.info('Command on called');
217
280
  });
218
281
  this.lightCT.addCommandHandler('off', async () => {
219
- this.lightCT?.getClusterServer(OnOffCluster)?.setOnOffAttribute(false);
220
- this.log.info('Command off called');
282
+ this.lightCT?.setAttribute(OnOffCluster.id, 'onOff', false, this.lightCT?.log, this.lightCT);
283
+ this.lightCT?.log.info('Command off called');
221
284
  });
222
285
  this.lightCT.addCommandHandler('moveToLevel', async ({ request: { level }, attributes: { currentLevel } }) => {
223
- this.lightCT?.getClusterServer(LevelControlCluster)?.setCurrentLevelAttribute(level);
224
- this.log.debug(`Command moveToLevel called request: ${level} attributes: ${currentLevel?.getLocal()}`);
286
+ this.lightCT?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.lightCT?.log, this.lightCT);
287
+ this.lightCT?.log.debug(`Command moveToLevel called request: ${level} attributes: ${currentLevel?.getLocal()}`);
225
288
  });
226
289
  this.lightCT.addCommandHandler('moveToLevelWithOnOff', async ({ request: { level }, attributes: { currentLevel } }) => {
227
- this.lightCT?.getClusterServer(LevelControlCluster)?.setCurrentLevelAttribute(level);
228
- this.log.debug(`Command moveToLevelWithOnOff called request: ${level} attributes: ${currentLevel?.getLocal()}`);
290
+ this.lightCT?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.lightCT?.log, this.lightCT);
291
+ this.lightCT?.log.debug(`Command moveToLevelWithOnOff called request: ${level} attributes: ${currentLevel?.getLocal()}`);
229
292
  });
230
293
  this.lightCT.addCommandHandler('moveToColorTemperature', async ({ request, attributes }) => {
231
- this.lightCT?.getClusterServer(ColorControl.Complete)?.setColorTemperatureMiredsAttribute(request.colorTemperatureMireds);
232
- this.log.debug(`Command moveToColorTemperature called request: ${request.colorTemperatureMireds} attributes: ${attributes.colorTemperatureMireds?.getLocal()}`);
294
+ this.lightCT?.setAttribute(ColorControlCluster.id, 'colorTemperatureMireds', request.colorTemperatureMireds, this.lightCT?.log, this.lightCT);
295
+ this.lightCT?.log.debug(`Command moveToColorTemperature called request: ${request.colorTemperatureMireds} attributes: ${attributes.colorTemperatureMireds?.getLocal()}`);
233
296
  });
234
297
  // Create an outlet device
235
298
  this.outlet = new MatterbridgeDevice(DeviceTypes.ON_OFF_PLUGIN_UNIT, undefined, this.config.debug);
@@ -243,15 +306,15 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
243
306
  this.outlet.createDefaultPowerSourceWiredClusterServer();
244
307
  await this.registerDevice(this.outlet);
245
308
  this.outlet.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
246
- this.log.info(`Command identify called identifyTime:${identifyTime}`);
309
+ this.outlet?.log.info(`Command identify called identifyTime:${identifyTime}`);
247
310
  });
248
311
  this.outlet.addCommandHandler('on', async () => {
249
- this.outlet?.getClusterServer(OnOffCluster)?.setOnOffAttribute(true);
250
- this.log.info('Command on called');
312
+ this.outlet?.setAttribute(OnOffCluster.id, 'onOff', true, this.outlet?.log, this.outlet);
313
+ this.outlet?.log.info('Command on called');
251
314
  });
252
315
  this.outlet.addCommandHandler('off', async () => {
253
- this.outlet?.getClusterServer(OnOffCluster)?.setOnOffAttribute(false);
254
- this.log.info('Command off called');
316
+ this.outlet?.setAttribute(OnOffCluster.id, 'onOff', false, this.outlet?.log, this.outlet);
317
+ this.outlet?.log.info('Command off called');
255
318
  });
256
319
  // Create a window covering device
257
320
  // Matter uses 10000 = fully closed 0 = fully opened
@@ -266,23 +329,23 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
266
329
  this.cover.createDefaultPowerSourceRechargeableBatteryClusterServer(86);
267
330
  await this.registerDevice(this.cover);
268
331
  this.cover.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
269
- this.log.info(`Command identify called identifyTime:${identifyTime}`);
332
+ this.cover?.log.info(`Command identify called identifyTime:${identifyTime}`);
270
333
  });
271
334
  this.cover.addCommandHandler('stopMotion', async ({ attributes: { currentPositionLiftPercent100ths, targetPositionLiftPercent100ths, operationalStatus } }) => {
272
335
  this.cover?.setWindowCoveringTargetAsCurrentAndStopped();
273
- this.log.info(`Command stopMotion called: current ${currentPositionLiftPercent100ths?.getLocal()} target ${targetPositionLiftPercent100ths?.getLocal()} status ${operationalStatus?.getLocal().lift}`);
336
+ this.cover?.log.info(`Command stopMotion called: current ${currentPositionLiftPercent100ths?.getLocal()} target ${targetPositionLiftPercent100ths?.getLocal()} status ${operationalStatus?.getLocal().lift}`);
274
337
  });
275
338
  this.cover.addCommandHandler('downOrClose', async ({ attributes: { currentPositionLiftPercent100ths, targetPositionLiftPercent100ths, operationalStatus } }) => {
276
339
  this.cover?.setWindowCoveringCurrentTargetStatus(10000, 10000, WindowCovering.MovementStatus.Stopped);
277
- this.log.info(`Command downOrClose called: current ${currentPositionLiftPercent100ths?.getLocal()} target ${targetPositionLiftPercent100ths?.getLocal()} status ${operationalStatus?.getLocal().lift}`);
340
+ this.cover?.log.info(`Command downOrClose called: current ${currentPositionLiftPercent100ths?.getLocal()} target ${targetPositionLiftPercent100ths?.getLocal()} status ${operationalStatus?.getLocal().lift}`);
278
341
  });
279
342
  this.cover.addCommandHandler('upOrOpen', async ({ attributes: { currentPositionLiftPercent100ths, targetPositionLiftPercent100ths, operationalStatus } }) => {
280
343
  this.cover?.setWindowCoveringCurrentTargetStatus(0, 0, WindowCovering.MovementStatus.Stopped);
281
- this.log.info(`Command upOrOpen called: current ${currentPositionLiftPercent100ths?.getLocal()} target ${targetPositionLiftPercent100ths?.getLocal()} status ${operationalStatus?.getLocal().lift}`);
344
+ this.cover?.log.info(`Command upOrOpen called: current ${currentPositionLiftPercent100ths?.getLocal()} target ${targetPositionLiftPercent100ths?.getLocal()} status ${operationalStatus?.getLocal().lift}`);
282
345
  });
283
346
  this.cover.addCommandHandler('goToLiftPercentage', async ({ request: { liftPercent100thsValue }, attributes: { currentPositionLiftPercent100ths, targetPositionLiftPercent100ths, operationalStatus } }) => {
284
347
  this.cover?.setWindowCoveringCurrentTargetStatus(liftPercent100thsValue, liftPercent100thsValue, WindowCovering.MovementStatus.Stopped);
285
- this.log.info(`Command goToLiftPercentage ${liftPercent100thsValue} called: current ${currentPositionLiftPercent100ths?.getLocal()} target ${targetPositionLiftPercent100ths?.getLocal()} status ${operationalStatus?.getLocal().lift}`);
348
+ this.cover?.log.info(`Command goToLiftPercentage ${liftPercent100thsValue} called: current ${currentPositionLiftPercent100ths?.getLocal()} target ${targetPositionLiftPercent100ths?.getLocal()} status ${operationalStatus?.getLocal().lift}`);
286
349
  });
287
350
  // Create a lock device
288
351
  this.lock = new MatterbridgeDevice(DeviceTypes.DOOR_LOCK, undefined, this.config.debug);
@@ -294,15 +357,15 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
294
357
  this.lock.createDefaultPowerSourceRechargeableBatteryClusterServer(30);
295
358
  await this.registerDevice(this.lock);
296
359
  this.lock.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
297
- this.log.info(`Command identify called identifyTime:${identifyTime}`);
360
+ this.lock?.log.info(`Command identify called identifyTime:${identifyTime}`);
298
361
  });
299
362
  this.lock.addCommandHandler('lockDoor', async () => {
300
- this.lock?.getClusterServer(DoorLockCluster)?.setLockStateAttribute(DoorLock.LockState.Locked);
301
- this.log.info('Command lockDoor called');
363
+ this.lock?.setAttribute(DoorLockCluster.id, 'lockState', DoorLock.LockState.Locked, this.lock?.log, this.lock);
364
+ this.lock?.log.info('Command lockDoor called');
302
365
  });
303
366
  this.lock.addCommandHandler('unlockDoor', async () => {
304
- this.lock?.getClusterServer(DoorLockCluster)?.setLockStateAttribute(DoorLock.LockState.Unlocked);
305
- this.log.info('Command unlockDoor called');
367
+ this.lock?.setAttribute(DoorLockCluster.id, 'lockState', DoorLock.LockState.Unlocked, this.lock?.log, this.lock);
368
+ this.lock?.log.info('Command unlockDoor called');
306
369
  });
307
370
  // Create a thermostat device
308
371
  this.thermo = new MatterbridgeDevice(DeviceTypes.THERMOSTAT, undefined, this.config.debug);
@@ -322,34 +385,33 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
322
385
  humidityChild.getClusterServer(RelativeHumidityMeasurement.Cluster)?.setMeasuredValueAttribute(80 * 100);
323
386
  await this.registerDevice(this.thermo);
324
387
  this.thermo.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
325
- this.log.info(`Command identify called identifyTime:${identifyTime}`);
326
- // if (this.thermo) logEndpoint(this.thermo);
388
+ this.thermo?.log.info(`Command identify called identifyTime:${identifyTime}`);
327
389
  });
328
390
  this.thermo.addCommandHandler('setpointRaiseLower', async ({ request: { mode, amount }, attributes }) => {
329
391
  const lookupSetpointAdjustMode = ['Heat', 'Cool', 'Both'];
330
- this.log.info(`Command setpointRaiseLower called with mode: ${lookupSetpointAdjustMode[mode]} amount: ${amount / 10}`);
392
+ this.thermo?.log.info(`Command setpointRaiseLower called with mode: ${lookupSetpointAdjustMode[mode]} amount: ${amount / 10}`);
331
393
  if (mode === /* Thermostat.SetpointRaiseLowerMode.Heat*/ 0 && attributes.occupiedHeatingSetpoint) {
332
394
  const setpoint = attributes.occupiedHeatingSetpoint?.getLocal() / 100 + amount / 10;
333
395
  attributes.occupiedHeatingSetpoint.setLocal(setpoint * 100);
334
- this.log.info('Set occupiedHeatingSetpoint:', setpoint);
396
+ this.thermo?.log.info('Set occupiedHeatingSetpoint:', setpoint);
335
397
  }
336
398
  if (mode === /* Thermostat.SetpointRaiseLowerMode.Cool*/ 1 && attributes.occupiedCoolingSetpoint) {
337
399
  const setpoint = attributes.occupiedCoolingSetpoint.getLocal() / 100 + amount / 10;
338
400
  attributes.occupiedCoolingSetpoint.setLocal(setpoint * 100);
339
- this.log.info('Set occupiedCoolingSetpoint:', setpoint);
401
+ this.thermo?.log.info('Set occupiedCoolingSetpoint:', setpoint);
340
402
  }
341
403
  });
342
404
  const thermostat = this.thermo.getClusterServer(ThermostatCluster.with(Thermostat.Feature.Heating, Thermostat.Feature.Cooling, Thermostat.Feature.AutoMode));
343
405
  if (thermostat) {
344
406
  subscribeAttribute(ThermostatCluster.id, 'systemMode', async (value) => {
345
407
  const lookupSystemMode = ['Off', 'Auto', '', 'Cool', 'Heat', 'EmergencyHeat', 'Precooling', 'FanOnly', 'Dry', 'Sleep'];
346
- this.log.info('Subscribe systemMode called with:', lookupSystemMode[value]);
408
+ this.thermo?.log.info('Subscribe systemMode called with:', lookupSystemMode[value]);
347
409
  }, this.thermo.log, this.thermo);
348
410
  subscribeAttribute(ThermostatCluster.id, 'occupiedHeatingSetpoint', async (value) => {
349
- this.log.info('Subscribe occupiedHeatingSetpoint called with:', value / 100);
411
+ this.thermo?.log.info('Subscribe occupiedHeatingSetpoint called with:', value / 100);
350
412
  }, this.thermo.log, this.thermo);
351
413
  subscribeAttribute(ThermostatCluster.id, 'occupiedCoolingSetpoint', async (value) => {
352
- this.log.info('Subscribe occupiedCoolingSetpoint called with:', value / 100);
414
+ this.thermo?.log.info('Subscribe occupiedCoolingSetpoint called with:', value / 100);
353
415
  }, this.thermo.log, this.thermo);
354
416
  }
355
417
  // Create a fan device
@@ -362,7 +424,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
362
424
  if (fanCluster) {
363
425
  const fanModeLookup = ['Off', 'Low', 'Medium', 'High', 'On', 'Auto', 'Smart'];
364
426
  subscribeAttribute(FanControlCluster.id, 'fanMode', (newValue, oldValue) => {
365
- this.log.info(`Fan mode changed from ${fanModeLookup[oldValue]} to ${fanModeLookup[newValue]}`);
427
+ this.fan?.log.info(`Fan mode changed from ${fanModeLookup[oldValue]} to ${fanModeLookup[newValue]}`);
366
428
  if (newValue === FanControl.FanMode.Off) {
367
429
  fanCluster.setPercentCurrentAttribute(0);
368
430
  }
@@ -383,12 +445,12 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
383
445
  }
384
446
  }, this.fan.log, this.fan);
385
447
  subscribeAttribute(FanControlCluster.id, 'percentSetting', (newValue, oldValue) => {
386
- this.log.info(`Percent setting changed from ${oldValue} to ${newValue}`);
448
+ this.fan?.log.info(`Percent setting changed from ${oldValue} to ${newValue}`);
387
449
  if (newValue)
388
450
  fanCluster.setPercentCurrentAttribute(newValue);
389
451
  }, this.fan.log, this.fan);
390
452
  subscribeAttribute(FanControlCluster.id, 'speedSetting', (newValue, oldValue) => {
391
- this.log.info(`Speed setting changed from ${oldValue} to ${newValue}`);
453
+ this.fan?.log.info(`Speed setting changed from ${oldValue} to ${newValue}`);
392
454
  if (newValue)
393
455
  fanCluster.setSpeedCurrentAttribute(newValue);
394
456
  }, this.fan.log, this.fan);
@@ -397,69 +459,108 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
397
459
  this.waterLeak.log.logName = 'Water leak detector';
398
460
  this.waterLeak.createDefaultBridgedDeviceBasicInformationClusterServer('Water leak detector', 'serial_98745631222', 0xfff1, 'Luligu', 'Matterbridge WaterLeakDetector');
399
461
  this.waterLeak.addDeviceTypeWithClusterServer([waterLeakDetector], [BooleanStateConfiguration.Cluster.id]);
400
- this.waterLeak.getClusterServer(BooleanStateCluster)?.setStateValueAttribute(false);
462
+ this.waterLeak.setAttribute(BooleanStateCluster.id, 'stateValue', false, this.waterLeak.log);
401
463
  await this.registerDevice(this.waterLeak);
402
464
  this.waterFreeze = new MatterbridgeDevice([waterFreezeDetector, bridgedNode], undefined, this.config.debug);
403
465
  this.waterFreeze.log.logName = 'Water freeze detector';
404
466
  this.waterFreeze.createDefaultBridgedDeviceBasicInformationClusterServer('Water freeze detector', 'serial_98745631223', 0xfff1, 'Luligu', 'Matterbridge WaterFreezeDetector');
405
467
  this.waterFreeze.addDeviceTypeWithClusterServer([waterFreezeDetector], [BooleanStateConfiguration.Cluster.id]);
406
- this.waterFreeze.getClusterServer(BooleanStateCluster)?.setStateValueAttribute(false);
468
+ this.waterFreeze.setAttribute(BooleanStateCluster.id, 'stateValue', false, this.waterFreeze.log);
407
469
  await this.registerDevice(this.waterFreeze);
408
470
  this.rain = new MatterbridgeDevice([rainSensor, bridgedNode], undefined, this.config.debug);
409
471
  this.rain.log.logName = 'Rain sensor';
410
472
  this.rain.createDefaultBridgedDeviceBasicInformationClusterServer('Rain sensor', 'serial_98745631224', 0xfff1, 'Luligu', 'Matterbridge RainSensor');
411
473
  this.rain.addDeviceTypeWithClusterServer([rainSensor], [BooleanStateConfiguration.Cluster.id]);
412
- this.rain.getClusterServer(BooleanStateCluster)?.setStateValueAttribute(false);
474
+ this.rain.setAttribute(BooleanStateCluster.id, 'stateValue', false, this.rain.log);
413
475
  await this.registerDevice(this.rain);
414
476
  this.smoke = new MatterbridgeDevice([smokeCoAlarm, bridgedNode], undefined, this.config.debug);
415
477
  this.smoke.log.logName = 'Smoke alarm sensor';
416
478
  this.smoke.createDefaultBridgedDeviceBasicInformationClusterServer('Smoke alarm sensor', 'serial_94745631225', 0xfff1, 'Luligu', 'Matterbridge SmokeCoAlarm');
417
479
  this.smoke.addDeviceTypeWithClusterServer([smokeCoAlarm], [CarbonMonoxideConcentrationMeasurement.Cluster.id]);
418
- this.smoke.getClusterServer(SmokeCoAlarmCluster.with(SmokeCoAlarm.Feature.SmokeAlarm, SmokeCoAlarm.Feature.CoAlarm))?.setSmokeStateAttribute(SmokeCoAlarm.AlarmState.Normal);
419
- this.smoke.getClusterServer(SmokeCoAlarmCluster.with(SmokeCoAlarm.Feature.SmokeAlarm, SmokeCoAlarm.Feature.CoAlarm))?.setCoStateAttribute(SmokeCoAlarm.AlarmState.Normal);
420
- this.smoke.getClusterServer(CarbonMonoxideConcentrationMeasurement.Complete)?.setMeasuredValueAttribute(100);
480
+ this.smoke.setAttribute(SmokeCoAlarmCluster.id, 'smokeState', SmokeCoAlarm.AlarmState.Normal, this.smoke.log);
481
+ this.smoke.setAttribute(SmokeCoAlarmCluster.id, 'coState', SmokeCoAlarm.AlarmState.Normal, this.smoke.log);
482
+ this.smoke.setAttribute(CarbonMonoxideConcentrationMeasurement.Cluster.id, 'measuredValue', 100, this.smoke.log);
421
483
  await this.registerDevice(this.smoke);
484
+ // Create an airQuality device
485
+ this.airQuality = new MatterbridgeDevice([airQualitySensor, bridgedNode], undefined, this.config.debug);
486
+ this.airQuality.log.logName = 'Air quality Sensor';
487
+ this.airQuality.createDefaultBridgedDeviceBasicInformationClusterServer('Air quality sensor', 'serial_987484318322', 0xfff1, 'Luligu', 'Matterbridge Air Quality Sensor');
488
+ this.airQuality.addDeviceTypeWithClusterServer([airQualitySensor], [
489
+ TemperatureMeasurement.Cluster.id,
490
+ RelativeHumidityMeasurement.Cluster.id,
491
+ CarbonMonoxideConcentrationMeasurement.Cluster.id,
492
+ CarbonDioxideConcentrationMeasurement.Cluster.id,
493
+ NitrogenDioxideConcentrationMeasurement.Cluster.id,
494
+ OzoneConcentrationMeasurement.Cluster.id,
495
+ FormaldehydeConcentrationMeasurement.Cluster.id,
496
+ Pm1ConcentrationMeasurement.Cluster.id,
497
+ Pm25ConcentrationMeasurement.Cluster.id,
498
+ Pm10ConcentrationMeasurement.Cluster.id,
499
+ RadonConcentrationMeasurement.Cluster.id,
500
+ TotalVolatileOrganicCompoundsConcentrationMeasurement.Cluster.id,
501
+ ]);
502
+ this.airQuality.setAttribute(AirQuality.Cluster.id, 'airQuality', AirQuality.AirQualityEnum.Good, this.airQuality.log);
503
+ this.airQuality.setAttribute(TemperatureMeasurement.Cluster.id, 'measuredValue', 2150, this.airQuality.log);
504
+ this.airQuality.setAttribute(RelativeHumidityMeasurement.Cluster.id, 'measuredValue', 5500, this.airQuality.log);
505
+ this.airQuality.setAttribute(CarbonMonoxideConcentrationMeasurement.Cluster.id, 'measuredValue', 10, this.airQuality.log);
506
+ this.airQuality.setAttribute(CarbonDioxideConcentrationMeasurement.Cluster.id, 'measuredValue', 400, this.airQuality.log);
507
+ this.airQuality.setAttribute(NitrogenDioxideConcentrationMeasurement.Cluster.id, 'measuredValue', 1, this.airQuality.log);
508
+ this.airQuality.setAttribute(OzoneConcentrationMeasurement.Cluster.id, 'measuredValue', 1, this.airQuality.log);
509
+ this.airQuality.setAttribute(FormaldehydeConcentrationMeasurement.Cluster.id, 'measuredValue', 1, this.airQuality.log);
510
+ this.airQuality.setAttribute(Pm1ConcentrationMeasurement.Cluster.id, 'measuredValue', 100, this.airQuality.log);
511
+ this.airQuality.setAttribute(Pm25ConcentrationMeasurement.Cluster.id, 'measuredValue', 100, this.airQuality.log);
512
+ this.airQuality.setAttribute(Pm10ConcentrationMeasurement.Cluster.id, 'measuredValue', 100, this.airQuality.log);
513
+ this.airQuality.setAttribute(RadonConcentrationMeasurement.Cluster.id, 'measuredValue', 100, this.airQuality.log);
514
+ this.airQuality.setAttribute(TotalVolatileOrganicCompoundsConcentrationMeasurement.Cluster.id, 'measuredValue', 100, this.airQuality.log);
515
+ await this.registerDevice(this.airQuality);
422
516
  }
423
517
  async onConfigure() {
424
518
  this.log.info('onConfigure called');
425
519
  // Set switch to off
426
520
  this.switch?.setAttribute(OnOffCluster.id, 'onOff', false, this.switch.log);
427
- this.log.info('Set switch initial onOff to false');
521
+ this.switch?.log.info('Set switch initial onOff to false');
428
522
  // Toggle switch onOff every minute
429
523
  this.switchInterval = setInterval(() => {
430
524
  const status = this.switch?.getAttribute(OnOffCluster.id, 'onOff', this.switch.log);
431
525
  if (isValidBoolean(status)) {
432
526
  this.switch?.setAttribute(OnOffCluster.id, 'onOff', !status, this.switch.log);
433
- this.log.info(`Set switch onOff to ${!status}`);
527
+ this.switch?.log.info(`Set switch onOff to ${!status}`);
434
528
  }
435
529
  }, 60 * 1000 + 100);
530
+ // Set light on/off to off
531
+ this.lightOnOff?.setAttribute(OnOffCluster.id, 'onOff', false, this.lightOnOff.log);
532
+ this.lightOnOff?.log.info('Set light initial onOff to false.');
533
+ // Set light on/off to off
534
+ this.dimmer?.setAttribute(OnOffCluster.id, 'onOff', false, this.dimmer.log);
535
+ this.dimmer?.setAttribute(LevelControlCluster.id, 'currentLevel', 0, this.dimmer.log);
536
+ this.dimmer?.log.info('Set dimmer initial onOff to false, currentLevel to 0.');
436
537
  // Set light to off, level to 0 and hue to 0 and saturation to 50% (pink color)
437
538
  this.light?.setAttribute(OnOffCluster.id, 'onOff', false, this.light.log);
438
539
  this.light?.setAttribute(LevelControlCluster.id, 'currentLevel', 0, this.light.log);
439
540
  this.light?.setAttribute(ColorControlCluster.id, 'currentHue', 0, this.light.log);
440
541
  this.light?.setAttribute(ColorControlCluster.id, 'currentSaturation', 128, this.light.log);
441
542
  this.light?.configureColorControlMode(ColorControl.ColorMode.CurrentHueAndCurrentSaturation);
442
- this.log.info('Set light initial onOff to false, currentLevel to 0, hue to 0 and saturation to 50%.');
543
+ this.light?.log.info('Set light initial onOff to false, currentLevel to 0, hue to 0 and saturation to 50%.');
443
544
  // Set light XY to true, level to 100% and XY to red
444
545
  this.lightXY?.setAttribute(OnOffCluster.id, 'onOff', true, this.lightXY.log);
445
546
  this.lightXY?.setAttribute(LevelControlCluster.id, 'currentLevel', 254, this.lightXY.log);
446
547
  this.lightXY?.setAttribute(ColorControlCluster.id, 'currentX', 0.7006 * 65536, this.lightXY.log);
447
548
  this.lightXY?.setAttribute(ColorControlCluster.id, 'currentY', 0.2993 * 65536, this.lightXY.log);
448
549
  this.lightXY?.configureColorControlMode(ColorControl.ColorMode.CurrentXAndCurrentY);
449
- this.log.info('Set light XY initial onOff to true, currentLevel to 254, X to 0.7006 and Y to 0.2993.');
550
+ this.lightXY?.log.info('Set light XY initial onOff to true, currentLevel to 254, X to 0.7006 and Y to 0.2993.');
450
551
  // Set light HS to off, level to 0 and hue to 0 and saturation to 50% (pink color)
451
552
  this.lightHS?.setAttribute(OnOffCluster.id, 'onOff', false, this.lightHS.log);
452
553
  this.lightHS?.setAttribute(LevelControlCluster.id, 'currentLevel', 0, this.lightHS.log);
453
554
  this.lightHS?.setAttribute(ColorControlCluster.id, 'currentHue', 0, this.lightHS.log);
454
555
  this.lightHS?.setAttribute(ColorControlCluster.id, 'currentSaturation', 128, this.lightHS.log);
455
556
  this.lightHS?.configureColorControlMode(ColorControl.ColorMode.CurrentHueAndCurrentSaturation);
456
- this.log.info('Set light HS initial onOff to false, currentLevel to 0, hue to 0 and saturation to 50%.');
557
+ this.lightHS?.log.info('Set light HS initial onOff to false, currentLevel to 0, hue to 0 and saturation to 50%.');
457
558
  // Set light CT to true, level to 50% and colorTemperatureMireds to 250
458
559
  this.lightCT?.setAttribute(OnOffCluster.id, 'onOff', true, this.lightCT.log);
459
560
  this.lightCT?.setAttribute(LevelControlCluster.id, 'currentLevel', 128, this.lightCT.log);
460
561
  this.lightCT?.setAttribute(ColorControlCluster.id, 'colorTemperatureMireds', 250, this.lightCT.log);
461
562
  this.lightCT?.configureColorControlMode(ColorControl.ColorMode.ColorTemperatureMireds);
462
- this.log.info('Set light CT initial onOff to true, currentLevel to 128, colorTemperatureMireds to 250.');
563
+ this.lightCT?.log.info('Set light CT initial onOff to true, currentLevel to 128, colorTemperatureMireds to 250.');
463
564
  this.lightInterval = setInterval(() => {
464
565
  const state = this.light?.getAttribute(OnOffCluster.id, 'onOff', this.light.log);
465
566
  let level = this.light?.getAttribute(LevelControlCluster.id, 'currentLevel', this.light.log);
@@ -467,45 +568,51 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
467
568
  level += 10;
468
569
  if (level > 254) {
469
570
  level = 0;
470
- this.light?.setAttribute(OnOffCluster.id, 'onOff', false, this.light?.log);
471
- this.lightXY?.setAttribute(OnOffCluster.id, 'onOff', false, this.light?.log);
472
- this.lightHS?.setAttribute(OnOffCluster.id, 'onOff', false, this.light?.log);
473
- this.lightCT?.setAttribute(OnOffCluster.id, 'onOff', false, this.light?.log);
474
- this.log.info('Set light onOff to false');
571
+ this.lightOnOff?.setAttribute(OnOffCluster.id, 'onOff', false, this.lightOnOff.log);
572
+ this.dimmer?.setAttribute(OnOffCluster.id, 'onOff', false, this.dimmer.log);
573
+ this.light?.setAttribute(OnOffCluster.id, 'onOff', false, this.light.log);
574
+ this.lightXY?.setAttribute(OnOffCluster.id, 'onOff', false, this.lightXY.log);
575
+ this.lightHS?.setAttribute(OnOffCluster.id, 'onOff', false, this.lightHS.log);
576
+ this.lightCT?.setAttribute(OnOffCluster.id, 'onOff', false, this.lightCT.log);
577
+ this.log.info('Set lights onOff to false');
578
+ this.dimmer?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.dimmer.log);
475
579
  this.light?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.light.log);
476
- this.lightXY?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.light?.log);
477
- this.lightHS?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.light?.log);
478
- this.lightCT?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.light?.log);
479
- this.log.info(`Set light currentLevel to ${level}`);
580
+ this.lightXY?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.lightXY.log);
581
+ this.lightHS?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.lightHS.log);
582
+ this.lightCT?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.lightCT.log);
583
+ this.log.info(`Set lights currentLevel to ${level}`);
480
584
  }
481
585
  else {
586
+ this.lightOnOff?.setAttribute(OnOffCluster.id, 'onOff', true, this.lightOnOff?.log);
587
+ this.dimmer?.setAttribute(OnOffCluster.id, 'onOff', true, this.dimmer.log);
482
588
  this.light?.setAttribute(OnOffCluster.id, 'onOff', true, this.light.log);
483
- this.lightXY?.setAttribute(OnOffCluster.id, 'onOff', true, this.light?.log);
484
- this.lightHS?.setAttribute(OnOffCluster.id, 'onOff', true, this.light?.log);
485
- this.lightCT?.setAttribute(OnOffCluster.id, 'onOff', true, this.light?.log);
486
- this.log.info('Set light onOff to true');
589
+ this.lightXY?.setAttribute(OnOffCluster.id, 'onOff', true, this.lightXY.log);
590
+ this.lightHS?.setAttribute(OnOffCluster.id, 'onOff', true, this.lightHS.log);
591
+ this.lightCT?.setAttribute(OnOffCluster.id, 'onOff', true, this.lightCT.log);
592
+ this.log.info('Set lights onOff to true');
593
+ this.dimmer?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.dimmer.log);
487
594
  this.light?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.light.log);
488
- this.lightXY?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.light?.log);
489
- this.lightHS?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.light?.log);
490
- this.lightCT?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.light?.log);
491
- this.log.info(`Set light currentLevel to ${level}`);
595
+ this.lightXY?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.lightXY.log);
596
+ this.lightHS?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.lightHS.log);
597
+ this.lightCT?.setAttribute(LevelControlCluster.id, 'currentLevel', level, this.lightCT.log);
598
+ this.log.info(`Set lights currentLevel to ${level}`);
492
599
  }
493
600
  }
494
601
  }, 60 * 1000 + 200);
495
602
  // Set outlet to off
496
603
  this.outlet?.setAttribute(OnOffCluster.id, 'onOff', false, this.outlet.log);
497
- this.log.info('Set outlet initial onOff to false');
604
+ this.outlet?.log.info('Set outlet initial onOff to false');
498
605
  // Toggle outlet onOff every minute
499
606
  this.outletInterval = setInterval(() => {
500
607
  const state = this.outlet?.getAttribute(OnOffCluster.id, 'onOff', this.outlet.log);
501
608
  if (isValidBoolean(state)) {
502
609
  this.outlet?.setAttribute(OnOffCluster.id, 'onOff', !state, this.outlet.log);
503
- this.log.info(`Set outlet onOff to ${!state}`);
610
+ this.outlet?.log.info(`Set outlet onOff to ${!state}`);
504
611
  }
505
612
  }, 60 * 1000 + 300);
506
613
  // Set cover to target = current position and status to stopped (current position is persisted in the cluster)
507
614
  this.cover?.setWindowCoveringTargetAsCurrentAndStopped();
508
- this.log.info('Set cover initial targetPositionLiftPercent100ths = currentPositionLiftPercent100ths and operationalStatus to Stopped.');
615
+ this.cover?.log.info('Set cover initial targetPositionLiftPercent100ths = currentPositionLiftPercent100ths and operationalStatus to Stopped.');
509
616
  // Increment cover position every minute
510
617
  this.coverInterval = setInterval(() => {
511
618
  let position = this.cover?.getAttribute(WindowCoveringCluster.id, 'currentPositionLiftPercent100ths', this.cover.log);
@@ -514,35 +621,35 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
514
621
  this.cover?.setAttribute(WindowCoveringCluster.id, 'targetPositionLiftPercent100ths', position, this.cover.log);
515
622
  this.cover?.setAttribute(WindowCoveringCluster.id, 'currentPositionLiftPercent100ths', position, this.cover.log);
516
623
  this.cover?.setAttribute(WindowCoveringCluster.id, 'operationalStatus', { global: WindowCovering.MovementStatus.Stopped, lift: WindowCovering.MovementStatus.Stopped, tilt: WindowCovering.MovementStatus.Stopped }, this.cover.log);
517
- this.log.info(`Set cover current and target positionLiftPercent100ths to ${position} and operationalStatus to Stopped`);
624
+ this.cover?.log.info(`Set cover current and target positionLiftPercent100ths to ${position} and operationalStatus to Stopped`);
518
625
  }
519
626
  }, 60 * 1000 + 400);
520
627
  // Set lock to Locked
521
628
  this.lock?.setAttribute(DoorLockCluster.id, 'lockState', DoorLock.LockState.Locked, this.lock.log);
522
- this.log.info('Set lock initial lockState to Locked');
629
+ this.lock?.log.info('Set lock initial lockState to Locked');
523
630
  // Toggle lock every minute
524
631
  this.lockInterval = setInterval(() => {
525
632
  const status = this.lock?.getAttribute(DoorLockCluster.id, 'lockState', this.lock.log);
526
633
  if (isValidNumber(status, DoorLock.LockState.Locked, DoorLock.LockState.Unlocked)) {
527
634
  this.lock?.setAttribute(DoorLockCluster.id, 'lockState', status === DoorLock.LockState.Locked ? DoorLock.LockState.Unlocked : DoorLock.LockState.Locked, this.lock.log);
528
- this.log.info(`Set lock lockState to ${status === DoorLock.LockState.Locked ? 'Unlocked' : 'Locked'}`);
635
+ this.lock?.log.info(`Set lock lockState to ${status === DoorLock.LockState.Locked ? 'Unlocked' : 'Locked'}`);
529
636
  }
530
637
  }, 60 * 1000 + 500);
531
638
  // Set local to 16°C
532
639
  this.thermo?.setAttribute(ThermostatCluster.id, 'localTemperature', 1600, this.thermo.log);
533
640
  this.thermo?.setAttribute(ThermostatCluster.id, 'systemMode', Thermostat.SystemMode.Auto, this.thermo.log);
534
- this.log.info('Set thermostat initial localTemperature to 16°C and mode Auto');
641
+ this.thermo?.log.info('Set thermostat initial localTemperature to 16°C and mode Auto');
535
642
  // Increment localTemperature every minute
536
643
  this.thermoInterval = setInterval(() => {
537
644
  let temperature = this.thermo?.getAttribute(ThermostatCluster.id, 'localTemperature', this.thermo.log);
538
645
  if (isValidNumber(temperature, 1600, 2400)) {
539
646
  temperature = temperature + 100 >= 2400 ? 1600 : temperature + 100;
540
647
  this.thermo?.setAttribute(ThermostatCluster.id, 'localTemperature', temperature, this.thermo.log);
541
- this.log.info(`Set thermostat localTemperature to ${temperature / 100}°C`);
648
+ this.thermo?.log.info(`Set thermostat localTemperature to ${temperature / 100}°C`);
542
649
  }
543
650
  }, 60 * 1000 + 600);
544
651
  // Set fan to auto
545
- this.log.info('Set fan initial fanMode to Auto, percentCurrent to 50 and speedCurrent to 50');
652
+ this.fan?.log.info('Set fan initial fanMode to Auto, percentCurrent to 50 and speedCurrent to 50');
546
653
  this.fan?.setAttribute(FanControlCluster.id, 'fanMode', FanControl.FanMode.Auto, this.fan.log);
547
654
  this.fan?.setAttribute(FanControlCluster.id, 'percentCurrent', 50, this.fan.log);
548
655
  this.fan?.setAttribute(FanControlCluster.id, 'speedCurrent', 50, this.fan.log);
@@ -553,7 +660,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
553
660
  if (isValidNumber(mode, FanControl.FanMode.Off, FanControl.FanMode.Auto) && mode === FanControl.FanMode.Auto && isValidNumber(value, 0, 100)) {
554
661
  value = value + 10 >= 100 ? 0 : value + 10;
555
662
  this.fan?.setAttribute(FanControlCluster.id, 'percentCurrent', value, this.fan.log);
556
- this.log.info(`Set fan percentCurrent to ${value}`);
663
+ this.fan?.log.info(`Set fan percentCurrent to ${value}`);
557
664
  }
558
665
  }, 60 * 1000 + 700);
559
666
  // Set waterLeak to false
@@ -564,7 +671,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
564
671
  if (isValidBoolean(value)) {
565
672
  value = !value;
566
673
  this.waterLeak?.setAttribute(BooleanStateCluster.id, 'stateValue', value, this.waterLeak.log);
567
- this.log.info(`Set waterLeak stateValue to ${value}`);
674
+ this.waterLeak?.log.info(`Set waterLeak stateValue to ${value}`);
568
675
  }
569
676
  }, 60 * 1000 + 800);
570
677
  // Set waterFreeze to false
@@ -575,7 +682,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
575
682
  if (isValidBoolean(value)) {
576
683
  value = !value;
577
684
  this.waterFreeze?.setAttribute(BooleanStateCluster.id, 'stateValue', value, this.waterFreeze.log);
578
- this.log.info(`Set waterFreeze stateValue to ${value}`);
685
+ this.waterFreeze?.log.info(`Set waterFreeze stateValue to ${value}`);
579
686
  }
580
687
  }, 60 * 1000 + 900);
581
688
  // Set rain to false
@@ -586,7 +693,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
586
693
  if (isValidBoolean(value)) {
587
694
  value = !value;
588
695
  this.rain?.setAttribute(BooleanStateCluster.id, 'stateValue', value, this.rain.log);
589
- this.log.info(`Set rain stateValue to ${value}`);
696
+ this.rain?.log.info(`Set rain stateValue to ${value}`);
590
697
  }
591
698
  }, 60 * 1000 + 1000);
592
699
  // Set smoke to Normal
@@ -599,7 +706,18 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
599
706
  value = value === SmokeCoAlarm.AlarmState.Normal ? SmokeCoAlarm.AlarmState.Critical : SmokeCoAlarm.AlarmState.Normal;
600
707
  this.smoke?.setAttribute(SmokeCoAlarmCluster.id, 'smokeState', value, this.smoke.log);
601
708
  this.smoke?.setAttribute(SmokeCoAlarmCluster.id, 'coState', value, this.smoke.log);
602
- this.log.info(`Set smoke smokeState and coState to ${value}`);
709
+ this.smoke?.log.info(`Set smoke smokeState and coState to ${value}`);
710
+ }
711
+ }, 60 * 1000 + 1100);
712
+ // Set air quality to Normal
713
+ this.airQuality?.setAttribute(AirQualityCluster.id, 'airQuality', AirQuality.AirQualityEnum.Good, this.airQuality.log);
714
+ // Toggle air quality every minute
715
+ this.airQualityInterval = setInterval(() => {
716
+ let value = this.airQuality?.getAttribute(AirQualityCluster.id, 'airQuality', this.airQuality?.log);
717
+ if (isValidNumber(value, AirQuality.AirQualityEnum.Good, AirQuality.AirQualityEnum.ExtremelyPoor)) {
718
+ value = value >= AirQuality.AirQualityEnum.ExtremelyPoor ? AirQuality.AirQualityEnum.Good : value + 1;
719
+ this.airQuality?.setAttribute(AirQualityCluster.id, 'airQuality', value, this.airQuality.log);
720
+ this.smoke?.log.info(`Set air quality to ${value}`);
603
721
  }
604
722
  }, 60 * 1000 + 1100);
605
723
  }
@@ -616,6 +734,7 @@ export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatf
616
734
  clearInterval(this.waterFreezeInterval);
617
735
  clearInterval(this.rainInterval);
618
736
  clearInterval(this.smokeInterval);
737
+ clearInterval(this.airQualityInterval);
619
738
  if (this.config.unregisterOnShutdown === true)
620
739
  await this.unregisterAllDevices();
621
740
  }
@@ -649,4 +768,32 @@ function subscribeAttribute(clusterId, attribute, listener, log, endpoint) {
649
768
  log?.info(`${db}Subscribe endpoint ${or}${endpoint.name}:${endpoint.number}${db} attribute ${hk}${clusterServer.name}.${capitalizedAttributeName}${db}`);
650
769
  return true;
651
770
  }
771
+ function addCommandHandler(clusterId, command, handler, log, endpoint) {
772
+ // if (!endpoint) endpoint = this as Endpoint;
773
+ if (!endpoint)
774
+ return false;
775
+ const clusterServer = endpoint.getClusterServerById(clusterId);
776
+ if (!clusterServer) {
777
+ log?.error(`addCommandHandler error: Cluster ${clusterId} not found on endpoint ${endpoint.name}:${endpoint.number}`);
778
+ return false;
779
+ }
780
+ if (!clusterServer.isCommandSupportedByName(command)) {
781
+ if (log)
782
+ log.error(`addCommandHandler error: Command ${command} not found on Cluster ${clusterServer.name} on endpoint ${endpoint.name}:${endpoint.number}`);
783
+ return false;
784
+ }
785
+ // Find the command
786
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
787
+ const commands = clusterServer.commands;
788
+ for (const [key, value] of Object.entries(commands)) {
789
+ // console.log(`Key "${key}": ${debugStringify(value)}`);
790
+ if (key === command) {
791
+ value.handler = handler;
792
+ log?.info(`${db}Command handler added for endpoint ${or}${endpoint.name}:${endpoint.number}${db} ${hk}${clusterServer.name}.${command}${db}`);
793
+ return true;
794
+ }
795
+ }
796
+ log?.error(`Command handler not found for endpoint ${or}${endpoint.name}:${endpoint.number}${er} ${hk}${clusterServer.name}.${command}${er}`);
797
+ return false;
798
+ }
652
799
  //# sourceMappingURL=platform.js.map