tsvesync 1.3.12 → 1.3.13

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.
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VeSyncAir131 = void 0;
4
4
  const vesyncFan_1 = require("../vesyncFan");
5
+ const helpers_1 = require("../helpers");
5
6
  const logger_1 = require("../logger");
6
7
  /**
7
8
  * VeSync Air Purifier 131 Series (LV-PUR131S, LV-RH131S)
@@ -78,6 +79,7 @@ class VeSyncAir131 extends vesyncFan_1.VeSyncFan {
78
79
  logger_1.logger.debug(`${this.deviceName}: API response structure:`, JSON.stringify(data, null, 2));
79
80
  }
80
81
  }
82
+ const normalizedAirQuality = helpers_1.Helpers.normalizeAirQuality(data.airQuality);
81
83
  this.details = {
82
84
  mode: data.mode || 'manual', // Default to manual if not specified
83
85
  speed: data.level || 0,
@@ -86,6 +88,8 @@ class VeSyncAir131 extends vesyncFan_1.VeSyncFan {
86
88
  child_lock: data.childLock || false,
87
89
  air_quality: data.airQuality || 'unknown',
88
90
  air_quality_value: data.air_quality_value || 0,
91
+ air_quality_level: normalizedAirQuality.level >= 1 ? normalizedAirQuality.level : undefined,
92
+ air_quality_label: normalizedAirQuality.label,
89
93
  active_time: data.activeTime || 0
90
94
  };
91
95
  // Store last known speed when device is on and has a valid speed
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VeSyncAirBaseV2 = void 0;
4
4
  const airBypass_1 = require("./airBypass");
5
5
  const logger_1 = require("../logger");
6
+ const helpers_1 = require("../helpers");
6
7
  /**
7
8
  * VeSync Air Purifier with Bypass V2
8
9
  */
@@ -163,6 +164,11 @@ class VeSyncAirBaseV2 extends airBypass_1.VeSyncAirBypass {
163
164
  if (this.hasFeature('air_quality')) {
164
165
  this.details.air_quality_value = (_l = devDict.PM25) !== null && _l !== void 0 ? _l : 0;
165
166
  this.details.air_quality = (_m = devDict.AQLevel) !== null && _m !== void 0 ? _m : 0;
167
+ const normalizedAirQuality = helpers_1.Helpers.normalizeAirQuality(devDict.AQLevel);
168
+ if (normalizedAirQuality.level >= 1) {
169
+ this.details.air_quality_level = normalizedAirQuality.level;
170
+ }
171
+ this.details.air_quality_label = normalizedAirQuality.label;
166
172
  }
167
173
  if ('PM1' in devDict)
168
174
  this.details.pm1 = devDict.PM1;
@@ -78,6 +78,11 @@ class VeSyncAirBypass extends vesyncFan_1.VeSyncFan {
78
78
  air_quality: result.air_quality || 0,
79
79
  air_quality_value: result.air_quality_value || 0
80
80
  };
81
+ const normalizedAirQuality = helpers_1.Helpers.normalizeAirQuality(result.air_quality);
82
+ if (normalizedAirQuality.level >= 1) {
83
+ this.details.air_quality_level = normalizedAirQuality.level;
84
+ }
85
+ this.details.air_quality_label = normalizedAirQuality.label;
81
86
  // Capture additional air quality properties if available
82
87
  if ('PM1' in result)
83
88
  this.details.pm1 = result.PM1;
@@ -106,6 +106,10 @@ export interface LoginResponse {
106
106
  export declare class Helpers {
107
107
  static shouldRedact: boolean;
108
108
  static generateTraceId(): string;
109
+ static normalizeAirQuality(value: unknown): {
110
+ level: number;
111
+ label: string;
112
+ };
109
113
  /**
110
114
  * Calculate MD5 hash
111
115
  */
@@ -182,6 +182,50 @@ class Helpers {
182
182
  static generateTraceId() {
183
183
  return generateTraceId();
184
184
  }
185
+ static normalizeAirQuality(value) {
186
+ const stringMap = {
187
+ 'excellent': 1,
188
+ 'very good': 1,
189
+ 'good': 2,
190
+ 'moderate': 3,
191
+ 'fair': 3,
192
+ 'inferior': 4,
193
+ 'poor': 4,
194
+ 'bad': 4,
195
+ };
196
+ if (typeof value === 'number') {
197
+ const level = Number.isFinite(value) ? Math.trunc(value) : -1;
198
+ if (level >= 1 && level <= 4) {
199
+ return {
200
+ level,
201
+ label: level === 1
202
+ ? 'excellent'
203
+ : level === 2
204
+ ? 'good'
205
+ : level === 3
206
+ ? 'moderate'
207
+ : 'poor',
208
+ };
209
+ }
210
+ }
211
+ else if (typeof value === 'string') {
212
+ const normalized = value.trim().toLowerCase();
213
+ const level = stringMap[normalized];
214
+ if (level) {
215
+ return {
216
+ level,
217
+ label: level === 1
218
+ ? 'excellent'
219
+ : level === 2
220
+ ? 'good'
221
+ : level === 3
222
+ ? 'moderate'
223
+ : 'poor',
224
+ };
225
+ }
226
+ }
227
+ return { level: -1, label: 'unknown' };
228
+ }
185
229
  /**
186
230
  * Calculate MD5 hash
187
231
  */
@@ -25,6 +25,8 @@ export declare abstract class VeSyncFan extends VeSyncBaseDevice {
25
25
  child_lock?: boolean;
26
26
  air_quality?: string | number;
27
27
  air_quality_value?: number;
28
+ air_quality_level?: number;
29
+ air_quality_label?: string;
28
30
  pm1?: number;
29
31
  pm10?: number;
30
32
  aq_percent?: number;
@@ -90,6 +92,13 @@ export declare abstract class VeSyncFan extends VeSyncBaseDevice {
90
92
  * Get air quality value - PM2.5 in μg/m³ (if supported)
91
93
  */
92
94
  get airQualityValue(): number;
95
+ /**
96
+ * Normalized air quality metadata aligned with pyvesync levels.
97
+ */
98
+ getNormalizedAirQuality(): {
99
+ level: number;
100
+ label: string;
101
+ };
93
102
  /**
94
103
  * Get PM1 value (if supported)
95
104
  */
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.VeSyncFan = exports.fanConfig = void 0;
7
7
  const vesyncBaseDevice_1 = require("./vesyncBaseDevice");
8
8
  const logger_1 = require("./logger");
9
+ const helpers_1 = require("./helpers");
9
10
  // Fan configuration
10
11
  exports.fanConfig = {
11
12
  // Core Series
@@ -418,6 +419,22 @@ class VeSyncFan extends vesyncBaseDevice_1.VeSyncBaseDevice {
418
419
  var _a;
419
420
  return (_a = this.details.air_quality_value) !== null && _a !== void 0 ? _a : 0;
420
421
  }
422
+ /**
423
+ * Normalized air quality metadata aligned with pyvesync levels.
424
+ */
425
+ getNormalizedAirQuality() {
426
+ var _a;
427
+ if (typeof this.details.air_quality_level === 'number' && this.details.air_quality_level >= 1) {
428
+ const label = (_a = this.details.air_quality_label) !== null && _a !== void 0 ? _a : helpers_1.Helpers.normalizeAirQuality(this.details.air_quality_level).label;
429
+ return { level: this.details.air_quality_level, label };
430
+ }
431
+ const normalized = helpers_1.Helpers.normalizeAirQuality(this.details.air_quality);
432
+ if (normalized.level >= 1) {
433
+ this.details.air_quality_level = normalized.level;
434
+ this.details.air_quality_label = normalized.label;
435
+ }
436
+ return normalized;
437
+ }
421
438
  /**
422
439
  * Get PM1 value (if supported)
423
440
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsvesync",
3
- "version": "1.3.12",
3
+ "version": "1.3.13",
4
4
  "description": "A TypeScript library for interacting with VeSync smart home devices",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -88,6 +88,8 @@ export class VeSyncAir131 extends VeSyncFan {
88
88
  }
89
89
  }
90
90
 
91
+ const normalizedAirQuality = Helpers.normalizeAirQuality(data.airQuality);
92
+
91
93
  this.details = {
92
94
  mode: data.mode || 'manual', // Default to manual if not specified
93
95
  speed: data.level || 0,
@@ -96,6 +98,8 @@ export class VeSyncAir131 extends VeSyncFan {
96
98
  child_lock: data.childLock || false,
97
99
  air_quality: data.airQuality || 'unknown',
98
100
  air_quality_value: data.air_quality_value || 0,
101
+ air_quality_level: normalizedAirQuality.level >= 1 ? normalizedAirQuality.level : undefined,
102
+ air_quality_label: normalizedAirQuality.label,
99
103
  active_time: data.activeTime || 0
100
104
  };
101
105
 
@@ -1,6 +1,7 @@
1
1
  import { VeSyncAirBypass } from './airBypass';
2
2
  import { VeSync } from '../vesync';
3
3
  import { logger } from '../logger';
4
+ import { Helpers } from '../helpers';
4
5
 
5
6
  /**
6
7
  * VeSync Air Purifier with Bypass V2
@@ -189,6 +190,11 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
189
190
  if (this.hasFeature('air_quality')) {
190
191
  this.details.air_quality_value = devDict.PM25 ?? 0;
191
192
  this.details.air_quality = devDict.AQLevel ?? 0;
193
+ const normalizedAirQuality = Helpers.normalizeAirQuality(devDict.AQLevel);
194
+ if (normalizedAirQuality.level >= 1) {
195
+ this.details.air_quality_level = normalizedAirQuality.level;
196
+ }
197
+ this.details.air_quality_label = normalizedAirQuality.label;
192
198
  }
193
199
 
194
200
  if ('PM1' in devDict) this.details.pm1 = devDict.PM1;
@@ -87,6 +87,12 @@ export class VeSyncAirBypass extends VeSyncFan {
87
87
  air_quality_value: result.air_quality_value || 0
88
88
  };
89
89
 
90
+ const normalizedAirQuality = Helpers.normalizeAirQuality(result.air_quality);
91
+ if (normalizedAirQuality.level >= 1) {
92
+ this.details.air_quality_level = normalizedAirQuality.level;
93
+ }
94
+ this.details.air_quality_label = normalizedAirQuality.label;
95
+
90
96
  // Capture additional air quality properties if available
91
97
  if ('PM1' in result) this.details.pm1 = result.PM1;
92
98
  if ('PM10' in result) this.details.pm10 = result.PM10;
@@ -245,6 +245,52 @@ export class Helpers {
245
245
  return generateTraceId();
246
246
  }
247
247
 
248
+ static normalizeAirQuality(value: unknown): { level: number; label: string } {
249
+ const stringMap: Record<string, number> = {
250
+ 'excellent': 1,
251
+ 'very good': 1,
252
+ 'good': 2,
253
+ 'moderate': 3,
254
+ 'fair': 3,
255
+ 'inferior': 4,
256
+ 'poor': 4,
257
+ 'bad': 4,
258
+ };
259
+
260
+ if (typeof value === 'number') {
261
+ const level = Number.isFinite(value) ? Math.trunc(value) : -1;
262
+ if (level >= 1 && level <= 4) {
263
+ return {
264
+ level,
265
+ label: level === 1
266
+ ? 'excellent'
267
+ : level === 2
268
+ ? 'good'
269
+ : level === 3
270
+ ? 'moderate'
271
+ : 'poor',
272
+ };
273
+ }
274
+ } else if (typeof value === 'string') {
275
+ const normalized = value.trim().toLowerCase();
276
+ const level = stringMap[normalized];
277
+ if (level) {
278
+ return {
279
+ level,
280
+ label: level === 1
281
+ ? 'excellent'
282
+ : level === 2
283
+ ? 'good'
284
+ : level === 3
285
+ ? 'moderate'
286
+ : 'poor',
287
+ };
288
+ }
289
+ }
290
+
291
+ return { level: -1, label: 'unknown' };
292
+ }
293
+
248
294
  /**
249
295
  * Calculate MD5 hash
250
296
  */
@@ -5,6 +5,7 @@
5
5
  import { VeSyncBaseDevice } from './vesyncBaseDevice';
6
6
  import { VeSync } from './vesync';
7
7
  import { logger } from './logger';
8
+ import { Helpers } from './helpers';
8
9
 
9
10
  interface FanConfig {
10
11
  [key: string]: {
@@ -327,6 +328,8 @@ export abstract class VeSyncFan extends VeSyncBaseDevice {
327
328
  child_lock?: boolean;
328
329
  air_quality?: string | number;
329
330
  air_quality_value?: number;
331
+ air_quality_level?: number;
332
+ air_quality_label?: string;
330
333
  pm1?: number;
331
334
  pm10?: number;
332
335
  aq_percent?: number;
@@ -468,6 +471,23 @@ export abstract class VeSyncFan extends VeSyncBaseDevice {
468
471
  return this.details.air_quality_value ?? 0;
469
472
  }
470
473
 
474
+ /**
475
+ * Normalized air quality metadata aligned with pyvesync levels.
476
+ */
477
+ getNormalizedAirQuality(): { level: number; label: string } {
478
+ if (typeof this.details.air_quality_level === 'number' && this.details.air_quality_level >= 1) {
479
+ const label = this.details.air_quality_label ?? Helpers.normalizeAirQuality(this.details.air_quality_level).label;
480
+ return { level: this.details.air_quality_level, label };
481
+ }
482
+
483
+ const normalized = Helpers.normalizeAirQuality(this.details.air_quality);
484
+ if (normalized.level >= 1) {
485
+ this.details.air_quality_level = normalized.level;
486
+ this.details.air_quality_label = normalized.label;
487
+ }
488
+ return normalized;
489
+ }
490
+
471
491
  /**
472
492
  * Get PM1 value (if supported)
473
493
  */