matterbridge-example-dynamic-platform 1.0.23 → 1.1.0

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