tsvesync 1.0.90 → 1.0.92

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.
@@ -0,0 +1,257 @@
1
+ "use strict";
2
+ /**
3
+ * Unit tests for VeSyncAirBypass air quality data parsing
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const airBypass_1 = require("../../lib/fans/airBypass");
7
+ // Mock VeSync manager
8
+ const mockManager = {
9
+ username: 'test@example.com',
10
+ password: 'testpass',
11
+ token: 'testtoken',
12
+ accountID: 'testaccount',
13
+ apiKey: 'testapikey',
14
+ apiBase: 'testbase',
15
+ timezone: 'UTC'
16
+ };
17
+ describe('VeSyncAirBypass Air Quality Features', () => {
18
+ let device;
19
+ beforeEach(() => {
20
+ const deviceDetails = {
21
+ deviceName: 'Core300S Test',
22
+ deviceType: 'Core300S',
23
+ cid: 'test-cid',
24
+ uuid: 'test-uuid',
25
+ deviceStatus: 'on',
26
+ deviceRegion: 'US',
27
+ configModule: 'VeSyncAirBypass',
28
+ macId: '00:11:22:33:44:55',
29
+ deviceCategory: 'fan',
30
+ connectionStatus: 'online'
31
+ };
32
+ device = new airBypass_1.VeSyncAirBypass(deviceDetails, mockManager);
33
+ });
34
+ describe('Air Quality Data Parsing', () => {
35
+ it('should parse air quality data from device response', () => {
36
+ const mockResponse = {
37
+ result: {
38
+ code: 0,
39
+ result: {
40
+ enabled: true,
41
+ mode: 'auto',
42
+ level: 3,
43
+ speed: 3,
44
+ display: 'on',
45
+ child_lock: false,
46
+ night_light: 'dim',
47
+ air_quality: 2,
48
+ air_quality_value: 15,
49
+ filter_life: 85,
50
+ timer_remain: 0
51
+ }
52
+ }
53
+ };
54
+ // Simulate API response parsing
55
+ device.details = mockResponse.result.result;
56
+ expect(device.airQualityLevel).toBe(2);
57
+ expect(device.airQualityValue).toBe(15);
58
+ expect(device.filterLife).toBe(85);
59
+ });
60
+ it('should handle missing air quality data gracefully', () => {
61
+ const mockResponse = {
62
+ result: {
63
+ code: 0,
64
+ result: {
65
+ enabled: true,
66
+ mode: 'auto',
67
+ level: 3,
68
+ speed: 3,
69
+ display: 'on',
70
+ child_lock: false,
71
+ filter_life: 85
72
+ // air_quality and air_quality_value missing
73
+ }
74
+ }
75
+ };
76
+ device.details = mockResponse.result.result;
77
+ expect(device.airQualityLevel).toBe('');
78
+ expect(device.airQualityValue).toBe(0);
79
+ expect(device.filterLife).toBe(85);
80
+ });
81
+ it('should handle various air quality value ranges', () => {
82
+ const testCases = [
83
+ { value: 0, level: 1, expected: 'Excellent' },
84
+ { value: 12, level: 1, expected: 'Good' },
85
+ { value: 25, level: 2, expected: 'Fair' },
86
+ { value: 55, level: 3, expected: 'Inferior' },
87
+ { value: 150, level: 4, expected: 'Poor' },
88
+ { value: 500, level: 5, expected: 'Poor' }
89
+ ];
90
+ testCases.forEach(testCase => {
91
+ device.details = {
92
+ air_quality: testCase.level,
93
+ air_quality_value: testCase.value,
94
+ filter_life: 50
95
+ };
96
+ expect(device.airQualityValue).toBe(testCase.value);
97
+ expect(device.airQualityLevel).toBe(testCase.level);
98
+ });
99
+ });
100
+ it('should handle extended air quality data with PM1 and PM10', () => {
101
+ device.details = {
102
+ air_quality: 2,
103
+ air_quality_value: 20,
104
+ pm1: 15,
105
+ pm10: 35,
106
+ aq_percent: 75,
107
+ filter_life: 60
108
+ };
109
+ expect(device.airQualityValue).toBe(20);
110
+ expect(device.pm1).toBe(15);
111
+ expect(device.pm10).toBe(35);
112
+ expect(device.aqPercent).toBe(75);
113
+ });
114
+ it('should handle zero PM values correctly', () => {
115
+ device.details = {
116
+ air_quality: 1,
117
+ air_quality_value: 0,
118
+ pm1: 0,
119
+ pm10: 0,
120
+ aq_percent: 100,
121
+ filter_life: 100
122
+ };
123
+ expect(device.airQualityValue).toBe(0);
124
+ expect(device.pm1).toBe(0);
125
+ expect(device.pm10).toBe(0);
126
+ expect(device.aqPercent).toBe(100);
127
+ });
128
+ });
129
+ describe('Filter Life Parsing', () => {
130
+ it('should parse filter life as number', () => {
131
+ device.details = { filter_life: 75 };
132
+ expect(device.filterLife).toBe(75);
133
+ });
134
+ it('should handle zero filter life', () => {
135
+ device.details = { filter_life: 0 };
136
+ expect(device.filterLife).toBe(0);
137
+ });
138
+ it('should handle 100% filter life', () => {
139
+ device.details = { filter_life: 100 };
140
+ expect(device.filterLife).toBe(100);
141
+ });
142
+ it('should handle missing filter life data', () => {
143
+ device.details = { mode: 'auto', speed: 3 };
144
+ expect(device.filterLife).toBe(0);
145
+ });
146
+ it('should handle invalid filter life data types', () => {
147
+ device.details = { filter_life: 'invalid' };
148
+ expect(device.filterLife).toBe(0);
149
+ });
150
+ });
151
+ describe('Feature Support', () => {
152
+ it('should support air quality features for Core300S', () => {
153
+ expect(device.hasFeature('air_quality')).toBe(true);
154
+ expect(device.hasFeature('auto_mode')).toBe(true);
155
+ expect(device.hasFeature('display')).toBe(true);
156
+ expect(device.hasFeature('child_lock')).toBe(true);
157
+ expect(device.hasFeature('night_light')).toBe(true);
158
+ });
159
+ it('should not support air quality for Core200S', () => {
160
+ const core200s = new airBypass_1.VeSyncAirBypass({
161
+ deviceName: 'Core200S Test',
162
+ deviceType: 'Core200S',
163
+ cid: 'test-cid',
164
+ uuid: 'test-uuid'
165
+ }, mockManager);
166
+ expect(core200s.hasFeature('air_quality')).toBe(false);
167
+ expect(core200s.hasFeature('auto_mode')).toBe(false);
168
+ });
169
+ it('should return correct max speed for different models', () => {
170
+ expect(device.getMaxFanSpeed()).toBe(4); // Core300S has 4 speeds
171
+ const core200s = new airBypass_1.VeSyncAirBypass({
172
+ deviceName: 'Core200S Test',
173
+ deviceType: 'Core200S',
174
+ cid: 'test-cid',
175
+ uuid: 'test-uuid'
176
+ }, mockManager);
177
+ expect(core200s.getMaxFanSpeed()).toBe(3); // Core200S has 3 speeds
178
+ });
179
+ });
180
+ describe('Device State Management', () => {
181
+ it('should track device state correctly', () => {
182
+ device.details = {
183
+ enabled: true,
184
+ mode: 'auto',
185
+ level: 3,
186
+ speed: 3,
187
+ display: 'on',
188
+ child_lock: false,
189
+ air_quality: 2,
190
+ air_quality_value: 25,
191
+ filter_life: 65
192
+ };
193
+ expect(device.deviceStatus).toBe('on');
194
+ expect(device.mode).toBe('auto');
195
+ expect(device.speed).toBe(3);
196
+ expect(device.screenStatus).toBe('on');
197
+ expect(device.childLock).toBe(false);
198
+ });
199
+ it('should handle device off state', () => {
200
+ device.deviceStatus = 'off';
201
+ device.details = {
202
+ enabled: false,
203
+ mode: 'manual',
204
+ level: 0,
205
+ speed: 0,
206
+ air_quality_value: 0
207
+ };
208
+ expect(device.deviceStatus).toBe('off');
209
+ expect(device.speed).toBe(0);
210
+ });
211
+ });
212
+ describe('Error Handling', () => {
213
+ it('should handle malformed API responses', () => {
214
+ device.details = null;
215
+ expect(device.airQualityValue).toBe(0);
216
+ expect(device.filterLife).toBe(0);
217
+ expect(device.mode).toBe('');
218
+ expect(device.speed).toBe(0);
219
+ });
220
+ it('should handle partial API responses', () => {
221
+ device.details = {
222
+ mode: 'auto'
223
+ // Other fields missing
224
+ };
225
+ expect(device.airQualityValue).toBe(0);
226
+ expect(device.filterLife).toBe(0);
227
+ expect(device.mode).toBe('auto');
228
+ expect(device.speed).toBe(0);
229
+ });
230
+ it('should handle negative values gracefully', () => {
231
+ device.details = {
232
+ air_quality_value: -10,
233
+ pm1: -5,
234
+ pm10: -15,
235
+ filter_life: -20
236
+ };
237
+ expect(device.airQualityValue).toBe(-10); // Allow negative for error detection
238
+ expect(device.pm1).toBe(-5);
239
+ expect(device.pm10).toBe(-15);
240
+ expect(device.filterLife).toBe(-20);
241
+ });
242
+ it('should handle extremely high values', () => {
243
+ device.details = {
244
+ air_quality_value: 9999,
245
+ pm1: 5000,
246
+ pm10: 8000,
247
+ filter_life: 200,
248
+ aq_percent: 150
249
+ };
250
+ expect(device.airQualityValue).toBe(9999);
251
+ expect(device.pm1).toBe(5000);
252
+ expect(device.pm10).toBe(8000);
253
+ expect(device.filterLife).toBe(200);
254
+ expect(device.aqPercent).toBe(150);
255
+ });
256
+ });
257
+ });
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Unit tests for VeSyncFan base class and air quality features
3
+ */
4
+ export {};
@@ -0,0 +1,263 @@
1
+ "use strict";
2
+ /**
3
+ * Unit tests for VeSyncFan base class and air quality features
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const vesyncFan_1 = require("../lib/vesyncFan");
7
+ // Mock VeSync manager
8
+ const mockManager = {
9
+ username: 'test@example.com',
10
+ password: 'testpass',
11
+ token: 'testtoken',
12
+ accountID: 'testaccount',
13
+ apiKey: 'testapikey',
14
+ apiBase: 'testbase',
15
+ timezone: 'UTC'
16
+ };
17
+ // Test implementation of abstract VeSyncFan class
18
+ class TestVeSyncFan extends vesyncFan_1.VeSyncFan {
19
+ async getDetails() {
20
+ return true;
21
+ }
22
+ async turnOn() {
23
+ this.deviceStatus = 'on';
24
+ return true;
25
+ }
26
+ async turnOff() {
27
+ this.deviceStatus = 'off';
28
+ return true;
29
+ }
30
+ async changeFanSpeed(level) {
31
+ this.details.speed = level;
32
+ return true;
33
+ }
34
+ async changeMode(mode) {
35
+ this.details.mode = mode;
36
+ return true;
37
+ }
38
+ }
39
+ describe('VeSyncFan Base Class', () => {
40
+ let fan;
41
+ beforeEach(() => {
42
+ const deviceDetails = {
43
+ deviceName: 'Test Fan',
44
+ deviceType: 'Core300S',
45
+ cid: 'test-cid',
46
+ uuid: 'test-uuid',
47
+ deviceStatus: 'off',
48
+ deviceRegion: 'US',
49
+ configModule: 'VeSyncAirBypass',
50
+ macId: '00:11:22:33:44:55',
51
+ deviceCategory: 'fan',
52
+ connectionStatus: 'online'
53
+ };
54
+ fan = new TestVeSyncFan(deviceDetails, mockManager);
55
+ });
56
+ describe('Air Quality Getters', () => {
57
+ it('should return default values when air quality data is not available', () => {
58
+ expect(fan.airQualityValue).toBe(0);
59
+ expect(fan.pm1).toBe(0);
60
+ expect(fan.pm10).toBe(0);
61
+ expect(fan.aqPercent).toBe(0);
62
+ expect(fan.airQualityLevel).toBe('');
63
+ });
64
+ it('should return correct air quality values when data is available', () => {
65
+ fan.details.air_quality_value = 25;
66
+ fan.details.pm1 = 15;
67
+ fan.details.pm10 = 30;
68
+ fan.details.aq_percent = 80;
69
+ fan.details.air_quality = 'Good';
70
+ expect(fan.airQualityValue).toBe(25);
71
+ expect(fan.pm1).toBe(15);
72
+ expect(fan.pm10).toBe(30);
73
+ expect(fan.aqPercent).toBe(80);
74
+ expect(fan.airQualityLevel).toBe('Good');
75
+ });
76
+ it('should handle numeric air quality levels', () => {
77
+ fan.details.air_quality = 2;
78
+ expect(fan.airQualityLevel).toBe(2);
79
+ });
80
+ it('should maintain backward compatibility with airQuality getter', () => {
81
+ fan.details.air_quality = 'Excellent';
82
+ expect(fan.airQuality).toBe('Excellent');
83
+ expect(fan.airQuality).toBe(fan.airQualityLevel);
84
+ });
85
+ it('should handle extreme air quality values', () => {
86
+ fan.details.air_quality_value = 999;
87
+ fan.details.pm1 = 500;
88
+ fan.details.pm10 = 1000;
89
+ fan.details.aq_percent = 100;
90
+ expect(fan.airQualityValue).toBe(999);
91
+ expect(fan.pm1).toBe(500);
92
+ expect(fan.pm10).toBe(1000);
93
+ expect(fan.aqPercent).toBe(100);
94
+ });
95
+ it('should handle zero air quality values', () => {
96
+ fan.details.air_quality_value = 0;
97
+ fan.details.pm1 = 0;
98
+ fan.details.pm10 = 0;
99
+ fan.details.aq_percent = 0;
100
+ expect(fan.airQualityValue).toBe(0);
101
+ expect(fan.pm1).toBe(0);
102
+ expect(fan.pm10).toBe(0);
103
+ expect(fan.aqPercent).toBe(0);
104
+ });
105
+ });
106
+ describe('Filter Life Handling', () => {
107
+ it('should return 0 when filter life is not available', () => {
108
+ expect(fan.filterLife).toBe(0);
109
+ });
110
+ it('should handle number format filter life (VeSyncAirBypass)', () => {
111
+ fan.details.filter_life = 85;
112
+ expect(fan.filterLife).toBe(85);
113
+ });
114
+ it('should handle object format filter life (VeSyncAir131)', () => {
115
+ fan.details.filter_life = { percent: 72 };
116
+ expect(fan.filterLife).toBe(72);
117
+ });
118
+ it('should handle object format with missing percent property', () => {
119
+ fan.details.filter_life = { other: 'value' };
120
+ expect(fan.filterLife).toBe(0);
121
+ });
122
+ it('should handle null filter life object', () => {
123
+ fan.details.filter_life = null;
124
+ expect(fan.filterLife).toBe(0);
125
+ });
126
+ it('should handle undefined filter life', () => {
127
+ fan.details.filter_life = undefined;
128
+ expect(fan.filterLife).toBe(0);
129
+ });
130
+ it('should handle zero filter life values', () => {
131
+ fan.details.filter_life = 0;
132
+ expect(fan.filterLife).toBe(0);
133
+ fan.details.filter_life = { percent: 0 };
134
+ expect(fan.filterLife).toBe(0);
135
+ });
136
+ it('should handle 100% filter life', () => {
137
+ fan.details.filter_life = 100;
138
+ expect(fan.filterLife).toBe(100);
139
+ fan.details.filter_life = { percent: 100 };
140
+ expect(fan.filterLife).toBe(100);
141
+ });
142
+ it('should handle invalid filter life formats gracefully', () => {
143
+ fan.details.filter_life = 'invalid';
144
+ expect(fan.filterLife).toBe(0);
145
+ fan.details.filter_life = [];
146
+ expect(fan.filterLife).toBe(0);
147
+ });
148
+ });
149
+ describe('Feature Detection', () => {
150
+ it('should detect air quality feature for supported devices', () => {
151
+ expect(fan.hasFeature('air_quality')).toBe(true);
152
+ });
153
+ it('should detect supported features based on device type', () => {
154
+ expect(fan.hasFeature('display')).toBe(true);
155
+ expect(fan.hasFeature('child_lock')).toBe(true);
156
+ expect(fan.hasFeature('night_light')).toBe(true);
157
+ expect(fan.hasFeature('timer')).toBe(true);
158
+ expect(fan.hasFeature('fan_speed')).toBe(true);
159
+ expect(fan.hasFeature('auto_mode')).toBe(true);
160
+ expect(fan.hasFeature('sleep_mode')).toBe(true);
161
+ });
162
+ it('should return false for unsupported features', () => {
163
+ expect(fan.hasFeature('unsupported_feature')).toBe(false);
164
+ });
165
+ it('should handle devices without configuration', () => {
166
+ const unknownDevice = new TestVeSyncFan({
167
+ deviceName: 'Unknown Device',
168
+ deviceType: 'UnknownType',
169
+ cid: 'test-cid',
170
+ uuid: 'test-uuid'
171
+ }, mockManager);
172
+ expect(unknownDevice.hasFeature('air_quality')).toBe(false);
173
+ });
174
+ });
175
+ describe('Feature Support in Current Mode', () => {
176
+ it('should support air quality in all modes', () => {
177
+ fan.details.mode = 'auto';
178
+ expect(fan.isFeatureSupportedInCurrentMode('air_quality')).toBe(true);
179
+ fan.details.mode = 'manual';
180
+ expect(fan.isFeatureSupportedInCurrentMode('air_quality')).toBe(true);
181
+ fan.details.mode = 'sleep';
182
+ expect(fan.isFeatureSupportedInCurrentMode('air_quality')).toBe(true);
183
+ });
184
+ it('should disable display and child lock in sleep mode', () => {
185
+ fan.details.mode = 'sleep';
186
+ expect(fan.isFeatureSupportedInCurrentMode('display')).toBe(false);
187
+ expect(fan.isFeatureSupportedInCurrentMode('child_lock')).toBe(false);
188
+ });
189
+ it('should support display and child lock in other modes', () => {
190
+ fan.details.mode = 'auto';
191
+ expect(fan.isFeatureSupportedInCurrentMode('display')).toBe(true);
192
+ expect(fan.isFeatureSupportedInCurrentMode('child_lock')).toBe(true);
193
+ fan.details.mode = 'manual';
194
+ expect(fan.isFeatureSupportedInCurrentMode('display')).toBe(true);
195
+ expect(fan.isFeatureSupportedInCurrentMode('child_lock')).toBe(true);
196
+ });
197
+ it('should return false for unsupported features regardless of mode', () => {
198
+ fan.details.mode = 'auto';
199
+ expect(fan.isFeatureSupportedInCurrentMode('unsupported')).toBe(false);
200
+ });
201
+ });
202
+ describe('Device Capabilities', () => {
203
+ it('should return correct maximum fan speed', () => {
204
+ expect(fan.getMaxFanSpeed()).toBe(4); // Core300S has 4 speeds
205
+ });
206
+ it('should handle devices without speed levels configured', () => {
207
+ const deviceWithoutLevels = new TestVeSyncFan({
208
+ deviceName: 'Basic Device',
209
+ deviceType: 'UnknownType',
210
+ cid: 'test-cid',
211
+ uuid: 'test-uuid'
212
+ }, mockManager);
213
+ expect(deviceWithoutLevels.getMaxFanSpeed()).toBe(3); // Default fallback
214
+ });
215
+ it('should return current mode and speed', () => {
216
+ fan.details.mode = 'auto';
217
+ fan.details.speed = 3;
218
+ expect(fan.mode).toBe('auto');
219
+ expect(fan.speed).toBe(3);
220
+ });
221
+ it('should handle missing mode and speed', () => {
222
+ expect(fan.mode).toBe('');
223
+ expect(fan.speed).toBe(0);
224
+ });
225
+ });
226
+ describe('Edge Cases and Error Handling', () => {
227
+ it('should handle missing details object', () => {
228
+ const minimalFan = new TestVeSyncFan({
229
+ deviceName: 'Minimal Device',
230
+ deviceType: 'Core300S',
231
+ cid: 'test-cid',
232
+ uuid: 'test-uuid'
233
+ }, mockManager);
234
+ // Details should be initialized as empty object
235
+ expect(minimalFan.airQualityValue).toBe(0);
236
+ expect(minimalFan.filterLife).toBe(0);
237
+ expect(minimalFan.mode).toBe('');
238
+ expect(minimalFan.speed).toBe(0);
239
+ });
240
+ it('should handle null and undefined values gracefully', () => {
241
+ fan.details.air_quality_value = null;
242
+ fan.details.filter_life = null;
243
+ fan.details.mode = null;
244
+ fan.details.speed = null;
245
+ expect(fan.airQualityValue).toBe(0);
246
+ expect(fan.filterLife).toBe(0);
247
+ expect(fan.mode).toBe('');
248
+ expect(fan.speed).toBe(0);
249
+ });
250
+ it('should handle invalid data types', () => {
251
+ fan.details.air_quality_value = 'invalid';
252
+ fan.details.pm1 = 'invalid';
253
+ fan.details.pm10 = 'invalid';
254
+ fan.details.aq_percent = 'invalid';
255
+ fan.details.speed = 'invalid';
256
+ expect(fan.airQualityValue).toBe(0);
257
+ expect(fan.pm1).toBe(0);
258
+ expect(fan.pm10).toBe(0);
259
+ expect(fan.aqPercent).toBe(0);
260
+ expect(fan.speed).toBe(0);
261
+ });
262
+ });
263
+ });
@@ -56,10 +56,11 @@ class VeSyncAir131 extends vesyncFan_1.VeSyncFan {
56
56
  this.details = {
57
57
  mode: data.mode || 'manual', // Default to manual if not specified
58
58
  speed: data.level || 0,
59
- filterLife: data.filterLife || 0,
60
- screenStatus: data.screenStatus || 'off',
61
- childLock: data.childLock || false,
62
- airQuality: data.airQuality || 'unknown',
59
+ filter_life: data.filterLife || data.filter_life || 0,
60
+ screen_status: data.screenStatus || 'off',
61
+ child_lock: data.childLock || false,
62
+ air_quality: data.airQuality || 'unknown',
63
+ air_quality_value: data.air_quality_value || 0,
63
64
  active_time: data.activeTime || 0
64
65
  };
65
66
  // Store last known speed when device is on and has a valid speed
@@ -56,11 +56,19 @@ class VeSyncAirBypass extends vesyncFan_1.VeSyncFan {
56
56
  this.details = {
57
57
  mode: result.mode || '',
58
58
  speed: result.level || 0,
59
- filterLife: result.filter_life || 0,
60
- screenStatus: result.display ? 'on' : 'off',
61
- childLock: result.child_lock || false,
62
- airQuality: result.air_quality || 0
59
+ filter_life: result.filter_life || 0,
60
+ screen_status: result.display ? 'on' : 'off',
61
+ child_lock: result.child_lock || false,
62
+ air_quality: result.air_quality || 0,
63
+ air_quality_value: result.air_quality_value || 0
63
64
  };
65
+ // Capture additional air quality properties if available
66
+ if ('PM1' in result)
67
+ this.details.pm1 = result.PM1;
68
+ if ('PM10' in result)
69
+ this.details.pm10 = result.PM10;
70
+ if ('AQPercent' in result)
71
+ this.details.aq_percent = result.AQPercent;
64
72
  // Don't overwrite config as it contains features array
65
73
  if (result.configuration) {
66
74
  this.details.configuration = result.configuration;
@@ -18,10 +18,16 @@ export declare abstract class VeSyncFan extends VeSyncBaseDevice {
18
18
  protected details: {
19
19
  mode?: string;
20
20
  speed?: number;
21
- filter_life?: number;
21
+ filter_life?: number | {
22
+ percent: number;
23
+ };
22
24
  screen_status?: 'on' | 'off';
23
25
  child_lock?: boolean;
24
- air_quality?: string;
26
+ air_quality?: string | number;
27
+ air_quality_value?: number;
28
+ pm1?: number;
29
+ pm10?: number;
30
+ aq_percent?: number;
25
31
  humidity?: number;
26
32
  mist_level?: number;
27
33
  warm_level?: number;
@@ -73,9 +79,29 @@ export declare abstract class VeSyncFan extends VeSyncBaseDevice {
73
79
  */
74
80
  get childLock(): boolean;
75
81
  /**
76
- * Get air quality (if supported)
82
+ * Get air quality level (if supported)
77
83
  */
78
- get airQuality(): string;
84
+ get airQualityLevel(): string | number;
85
+ /**
86
+ * Get air quality (alias for airQualityLevel for backward compatibility)
87
+ */
88
+ get airQuality(): string | number;
89
+ /**
90
+ * Get air quality value - PM2.5 in μg/m³ (if supported)
91
+ */
92
+ get airQualityValue(): number;
93
+ /**
94
+ * Get PM1 value (if supported)
95
+ */
96
+ get pm1(): number;
97
+ /**
98
+ * Get PM10 value (if supported)
99
+ */
100
+ get pm10(): number;
101
+ /**
102
+ * Get air quality percentage (if supported)
103
+ */
104
+ get aqPercent(): number;
79
105
  /**
80
106
  * Get humidity level (if supported)
81
107
  */