matterbridge-example-dynamic-platform 1.0.18 → 1.0.20

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