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