tsvesync 1.0.58 → 1.0.60

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.
@@ -16,11 +16,6 @@ export declare abstract class VeSyncBaseDevice {
16
16
  deviceCategory: string;
17
17
  connectionStatus: string;
18
18
  constructor(details: Record<string, any>, manager: VeSync);
19
- /**
20
- * Normalize device type to match configuration keys
21
- * This handles variations in device type strings from the API
22
- */
23
- protected normalizeDeviceType(deviceType: string): string;
24
19
  /**
25
20
  * Return formatted device info to stdout
26
21
  */
@@ -13,7 +13,7 @@ class VeSyncBaseDevice {
13
13
  this.cid = details.cid || '';
14
14
  this.deviceName = details.deviceName || '';
15
15
  this.deviceStatus = details.deviceStatus || 'off';
16
- this.deviceType = this.normalizeDeviceType(details.deviceType || '');
16
+ this.deviceType = details.deviceType || '';
17
17
  this.deviceRegion = details.deviceRegion || '';
18
18
  this.uuid = details.uuid || '';
19
19
  this.configModule = details.configModule || '';
@@ -21,34 +21,6 @@ class VeSyncBaseDevice {
21
21
  this.deviceCategory = details.deviceCategory || '';
22
22
  this.connectionStatus = details.connectionStatus || 'offline';
23
23
  }
24
- /**
25
- * Normalize device type to match configuration keys
26
- * This handles variations in device type strings from the API
27
- */
28
- normalizeDeviceType(deviceType) {
29
- // Remove any region suffixes (e.g. -USA, -EU)
30
- const baseType = deviceType.split('-')[0];
31
- // Handle known prefix mappings
32
- const prefixMap = {
33
- 'Core': 'Core',
34
- 'LAP': 'LAP',
35
- 'LTF': 'LTF',
36
- 'Classic': 'Classic',
37
- 'Dual': 'Dual',
38
- 'LUH': 'LUH',
39
- 'LEH': 'LEH',
40
- 'LV-PUR': 'LV-PUR',
41
- 'LV-RH': 'LV-RH'
42
- };
43
- // Check if the device type starts with any known prefix
44
- for (const [prefix, normalized] of Object.entries(prefixMap)) {
45
- if (deviceType.startsWith(prefix)) {
46
- return deviceType; // Keep the full device type for exact matches
47
- }
48
- }
49
- // If no prefix match, return the base type
50
- return baseType;
51
- }
52
24
  /**
53
25
  * Return formatted device info to stdout
54
26
  */
@@ -189,121 +189,98 @@ exports.fanConfig = {
189
189
  // Classic Series
190
190
  'Classic300S': {
191
191
  module: 'VeSyncHumidifier',
192
- features: ['display', 'humidity', 'mist', 'timer', 'auto_mode'],
193
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
192
+ features: ['display', 'humidity', 'mist', 'timer', 'auto_mode']
194
193
  },
195
194
  'Classic200S': {
196
195
  module: 'VeSyncHumidifier',
197
- features: ['display', 'humidity', 'mist', 'timer', 'auto_mode'],
198
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
196
+ features: ['display', 'humidity', 'mist', 'timer', 'auto_mode']
199
197
  },
200
198
  // Dual Series
201
199
  'Dual200S': {
202
200
  module: 'VeSyncHumidifier',
203
- features: ['display', 'humidity', 'mist', 'timer', 'auto_mode'],
204
- levels: [1, 2]
201
+ features: ['display', 'humidity', 'mist', 'timer', 'auto_mode']
205
202
  },
206
203
  // LUH Series
207
204
  'LUH-A601S-WUSB': {
208
205
  module: 'VeSyncWarmHumidifier',
209
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
210
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
206
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
211
207
  },
212
208
  'LUH-A601S-AUSW': {
213
209
  module: 'VeSyncWarmHumidifier',
214
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
215
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
210
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
216
211
  },
217
212
  'LUH-D301S-WUSR': {
218
213
  module: 'VeSyncWarmHumidifier',
219
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
220
- levels: [1, 2]
214
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
221
215
  },
222
216
  'LUH-D301S-WJP': {
223
217
  module: 'VeSyncWarmHumidifier',
224
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
225
- levels: [1, 2]
218
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
226
219
  },
227
220
  'LUH-D301S-WEU': {
228
221
  module: 'VeSyncWarmHumidifier',
229
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
230
- levels: [1, 2]
222
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
231
223
  },
232
224
  'LUH-A602S-WUSR': {
233
225
  module: 'VeSyncWarmHumidifier',
234
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
235
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
226
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
236
227
  },
237
228
  'LUH-A602S-WUS': {
238
229
  module: 'VeSyncWarmHumidifier',
239
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
240
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
230
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
241
231
  },
242
232
  'LUH-A602S-WEUR': {
243
233
  module: 'VeSyncWarmHumidifier',
244
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
245
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
234
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
246
235
  },
247
236
  'LUH-A602S-WEU': {
248
237
  module: 'VeSyncWarmHumidifier',
249
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
250
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
238
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
251
239
  },
252
240
  'LUH-A602S-WJP': {
253
241
  module: 'VeSyncWarmHumidifier',
254
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
255
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
242
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
256
243
  },
257
244
  'LUH-A602S-WUSC': {
258
245
  module: 'VeSyncWarmHumidifier',
259
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
260
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
246
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
261
247
  },
262
248
  'LUH-O451S-WEU': {
263
249
  module: 'VeSyncWarmHumidifier',
264
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
265
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
250
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
266
251
  },
267
252
  'LUH-O451S-WUS': {
268
253
  module: 'VeSyncWarmHumidifier',
269
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
270
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
254
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
271
255
  },
272
256
  'LUH-O451S-WUSR': {
273
257
  module: 'VeSyncWarmHumidifier',
274
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
275
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
258
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
276
259
  },
277
260
  'LUH-O601S-WUS': {
278
261
  module: 'VeSyncWarmHumidifier',
279
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
280
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
262
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
281
263
  },
282
264
  'LUH-O601S-KUS': {
283
265
  module: 'VeSyncWarmHumidifier',
284
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
285
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
266
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
286
267
  },
287
268
  'LUH-M101S-WUS': {
288
269
  module: 'VeSyncWarmHumidifier',
289
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
290
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
270
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
291
271
  },
292
272
  'LUH-M101S-WEUR': {
293
273
  module: 'VeSyncWarmHumidifier',
294
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
295
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
274
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
296
275
  },
297
276
  // LEH Series
298
277
  'LEH-S601S-WUS': {
299
278
  module: 'VeSyncWarmHumidifier',
300
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode', 'drying'],
301
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
279
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode', 'drying']
302
280
  },
303
281
  'LEH-S601S-WUSR': {
304
282
  module: 'VeSyncWarmHumidifier',
305
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode', 'drying'],
306
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
283
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode', 'drying']
307
284
  },
308
285
  // LV Series
309
286
  'LV-PUR131S': {
@@ -328,22 +305,11 @@ class VeSyncFan extends vesyncBaseDevice_1.VeSyncBaseDevice {
328
305
  this.speed_dict = {};
329
306
  this._timer = null;
330
307
  this.details = details;
331
- // Try exact match first
332
- let config = exports.fanConfig[this.deviceType];
333
- // If no exact match, try base type
334
- if (!config) {
335
- const baseType = this.deviceType.split('-')[0];
336
- config = exports.fanConfig[baseType];
337
- }
338
- // If still no match, use default
339
- this.config = config || {
308
+ this.config = exports.fanConfig[this.deviceType] || {
340
309
  module: 'VeSyncAirBypass',
341
310
  features: [],
342
311
  levels: []
343
312
  };
344
- if (!config) {
345
- logger_1.logger.debug(`No configuration found for device type: ${this.deviceType}`);
346
- }
347
313
  }
348
314
  /**
349
315
  * Check if feature is supported
@@ -91,40 +91,11 @@ export declare class VeSyncHumidifier extends VeSyncFan {
91
91
  min: number;
92
92
  max: number;
93
93
  };
94
- protected readonly states: readonly ["inactive", "idle", "humidifying"];
95
94
  constructor(details: Record<string, any>, manager: VeSync);
96
- /**
97
- * Get current operational state
98
- */
99
- get currentState(): string;
100
- /**
101
- * Get water level percentage
102
- */
103
- get waterLevel(): number;
104
- /**
105
- * Get water tank status
106
- */
107
- get waterTankLifted(): boolean;
108
- /**
109
- * Get oscillation state
110
- */
111
- get oscillationEnabled(): boolean;
112
- /**
113
- * Set oscillation state
114
- */
115
- setOscillation(enabled: boolean): Promise<boolean>;
116
95
  /**
117
96
  * Get device details
118
97
  */
119
98
  getDetails(): Promise<Boolean>;
120
- /**
121
- * Display device info
122
- */
123
- display(): void;
124
- /**
125
- * Return JSON details
126
- */
127
- displayJSON(): string;
128
99
  /**
129
100
  * Turn device on
130
101
  */
@@ -26,7 +26,6 @@ class VeSyncAirBypass extends vesyncFan_1.VeSyncFan {
26
26
  const body = {
27
27
  ...helpers_1.Helpers.reqBody(this.manager, 'bypassV2'),
28
28
  cid: this.cid,
29
- deviceId: this.cid, // Add deviceId to match YAML spec
30
29
  configModule: this.configModule,
31
30
  payload: {
32
31
  method,
@@ -211,13 +210,11 @@ class VeSyncAirBypass extends vesyncFan_1.VeSyncFan {
211
210
  */
212
211
  async changeFanSpeed(speed) {
213
212
  var _a;
214
- logger_1.logger.debug(`Attempting to change fan speed to ${speed} for device: ${this.deviceName}`);
215
- logger_1.logger.debug(`Available speeds: ${(_a = this.config.levels) === null || _a === void 0 ? void 0 : _a.join(', ')}`);
216
- // const speeds = this.config.levels ?? [];
217
- // if (!speeds.includes(speed)) {
218
- // logger.debug(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')}`);
219
- // return false;
220
- // }
213
+ const speeds = (_a = this.config.levels) !== null && _a !== void 0 ? _a : [];
214
+ if (!speeds.includes(speed)) {
215
+ logger_1.logger.error(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')} for device: ${this.deviceName}`);
216
+ return false;
217
+ }
221
218
  logger_1.logger.info(`Changing fan speed to ${speed} for device: ${this.deviceName}`);
222
219
  const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', {
223
220
  ...helpers_1.Helpers.reqBody(this.manager, 'bypassV2'),
@@ -244,11 +241,10 @@ class VeSyncAirBypass extends vesyncFan_1.VeSyncFan {
244
241
  * Set device mode
245
242
  */
246
243
  async setMode(mode) {
247
- const modeStr = mode.toLowerCase();
248
- if (!this.modes.includes(modeStr)) {
249
- logger_1.logger.debug(`Invalid humidity mode used - ${mode}`);
250
- logger_1.logger.debug(`Proper modes for this device are - ${this.modes.join(', ')}`);
251
- return false;
244
+ if (!this.modes.includes(mode)) {
245
+ const error = `Invalid mode: ${mode}. Must be one of: ${this.modes.join(', ')}`;
246
+ logger_1.logger.error(`${error} for device: ${this.deviceName}`);
247
+ throw new Error(error);
252
248
  }
253
249
  logger_1.logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
254
250
  const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', {
@@ -257,15 +253,15 @@ class VeSyncAirBypass extends vesyncFan_1.VeSyncFan {
257
253
  configModule: this.configModule,
258
254
  payload: {
259
255
  data: {
260
- workMode: this.deviceType.startsWith('Superior') && modeStr === 'auto' ? 'autoPro' : modeStr
256
+ mode
261
257
  },
262
- method: 'setHumidifierMode',
258
+ method: 'setPurifierMode',
263
259
  source: 'APP'
264
260
  }
265
261
  }, helpers_1.Helpers.reqHeaderBypass());
266
262
  const success = this.checkResponse([response, status], 'setMode');
267
263
  if (!success) {
268
- logger_1.logger.debug('Error setting humidity mode');
264
+ logger_1.logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
269
265
  }
270
266
  return success;
271
267
  }
@@ -492,7 +488,6 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
492
488
  this.modes = ['auto', 'manual', 'sleep'];
493
489
  this.displayModes = ['on', 'off'];
494
490
  this.humidityRange = { min: 30, max: 80 };
495
- this.states = ['inactive', 'idle', 'humidifying'];
496
491
  // Set mist levels based on model
497
492
  switch (this.deviceType) {
498
493
  case 'Dual200S':
@@ -507,66 +502,6 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
507
502
  }
508
503
  logger_1.logger.debug(`Initialized VeSyncHumidifier device: ${this.deviceName}`);
509
504
  }
510
- /**
511
- * Get current operational state
512
- */
513
- get currentState() {
514
- if (this.deviceStatus === 'off') {
515
- return 'inactive';
516
- }
517
- if (this.details.water_lacks) {
518
- return 'idle';
519
- }
520
- return 'humidifying';
521
- }
522
- /**
523
- * Get water level percentage
524
- */
525
- get waterLevel() {
526
- var _a;
527
- return (_a = this.details.water_level) !== null && _a !== void 0 ? _a : 0;
528
- }
529
- /**
530
- * Get water tank status
531
- */
532
- get waterTankLifted() {
533
- var _a;
534
- return (_a = this.details.water_tank_lifted) !== null && _a !== void 0 ? _a : false;
535
- }
536
- /**
537
- * Get oscillation state
538
- */
539
- get oscillationEnabled() {
540
- var _a;
541
- return (_a = this.details.oscillation_enabled) !== null && _a !== void 0 ? _a : false;
542
- }
543
- /**
544
- * Set oscillation state
545
- */
546
- async setOscillation(enabled) {
547
- if (!this.hasFeature('oscillation')) {
548
- logger_1.logger.debug('Oscillation not supported');
549
- return false;
550
- }
551
- logger_1.logger.debug(`Setting oscillation to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
552
- const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', {
553
- ...helpers_1.Helpers.reqBody(this.manager, 'bypassV2'),
554
- cid: this.cid,
555
- configModule: this.configModule,
556
- payload: {
557
- data: {
558
- oscillationEnabled: enabled
559
- },
560
- method: 'setSwing',
561
- source: 'APP'
562
- }
563
- }, helpers_1.Helpers.reqHeaderBypass());
564
- const success = this.checkResponse([response, status], 'setOscillation');
565
- if (!success) {
566
- logger_1.logger.debug('Error setting oscillation');
567
- }
568
- return success;
569
- }
570
505
  /**
571
506
  * Get device details
572
507
  */
@@ -598,13 +533,12 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
598
533
  humidity: result.humidity || 0,
599
534
  mist_level: result.mistLevel || 0,
600
535
  mist_virtual_level: result.virtualLevel || 0,
536
+ warm_level: result.warmLevel || 0,
601
537
  water_lacks: result.waterLacks || false,
602
- water_level: result.waterLevel || 0,
603
- water_tank_lifted: result.waterTankLifted || false,
604
538
  humidity_high: result.humidityHigh || false,
539
+ water_tank_lifted: result.waterTankLifted || false,
605
540
  display: result.display || false,
606
541
  automatic_stop: result.automaticStop || false,
607
- oscillation_enabled: result.oscillationEnabled || false,
608
542
  configuration: result.configuration || {},
609
543
  connection_status: result.connectionStatus || null
610
544
  };
@@ -612,34 +546,6 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
612
546
  }
613
547
  return success;
614
548
  }
615
- /**
616
- * Display device info
617
- */
618
- display() {
619
- super.display();
620
- const info = [
621
- ['Current State: ', this.currentState],
622
- ['Water Level: ', this.waterLevel, '%'],
623
- ['Water Tank: ', this.waterTankLifted ? 'Lifted' : 'Seated'],
624
- ['Oscillation: ', this.oscillationEnabled ? 'On' : 'Off']
625
- ];
626
- for (const [key, value, unit = ''] of info) {
627
- logger_1.logger.info(`${key.toString().padEnd(30, '.')} ${value}${unit}`);
628
- }
629
- }
630
- /**
631
- * Return JSON details
632
- */
633
- displayJSON() {
634
- const baseInfo = JSON.parse(super.displayJSON());
635
- return JSON.stringify({
636
- ...baseInfo,
637
- 'Current State': this.currentState,
638
- 'Water Level': this.waterLevel,
639
- 'Water Tank': this.waterTankLifted ? 'Lifted' : 'Seated',
640
- 'Oscillation': this.oscillationEnabled ? 'On' : 'Off'
641
- }, null, 4);
642
- }
643
549
  /**
644
550
  * Turn device on
645
551
  */
@@ -704,9 +610,9 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
704
610
  */
705
611
  async setMistLevel(level) {
706
612
  if (!this.mistLevels.includes(level)) {
707
- logger_1.logger.debug(`Invalid mist level: ${level} for device: ${this.deviceName}`);
708
- logger_1.logger.debug(`Valid levels for ${this.deviceType}: ${this.mistLevels.join(', ')}`);
709
- return false;
613
+ const error = `Invalid mist level: ${level}. Must be one of: ${this.mistLevels.join(', ')}`;
614
+ logger_1.logger.error(`${error} for device: ${this.deviceName}`);
615
+ throw new Error(error);
710
616
  }
711
617
  logger_1.logger.info(`Setting mist level to ${level} for device: ${this.deviceName}`);
712
618
  const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', {
@@ -715,9 +621,9 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
715
621
  configModule: this.configModule,
716
622
  payload: {
717
623
  data: {
718
- levelIdx: 0,
719
- virtualLevel: level,
720
- levelType: 'mist'
624
+ id: 0,
625
+ level: level,
626
+ type: 'mist'
721
627
  },
722
628
  method: 'setVirtualLevel',
723
629
  source: 'APP'
@@ -725,7 +631,7 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
725
631
  }, helpers_1.Helpers.reqHeaderBypass());
726
632
  const success = this.checkResponse([response, status], 'setMistLevel');
727
633
  if (!success) {
728
- logger_1.logger.debug('Error setting mist level');
634
+ logger_1.logger.error(`Failed to set mist level to ${level} for device: ${this.deviceName}`);
729
635
  }
730
636
  return success;
731
637
  }
@@ -740,11 +646,10 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
740
646
  * Set device mode
741
647
  */
742
648
  async setMode(mode) {
743
- const modeStr = mode.toLowerCase();
744
- if (!this.modes.includes(modeStr)) {
745
- logger_1.logger.debug(`Invalid humidity mode used - ${mode}`);
746
- logger_1.logger.debug(`Proper modes for this device are - ${this.modes.join(', ')}`);
747
- return false;
649
+ if (!this.modes.includes(mode)) {
650
+ const error = `Invalid mode: ${mode}. Must be one of: ${this.modes.join(', ')}`;
651
+ logger_1.logger.error(`${error} for device: ${this.deviceName}`);
652
+ throw new Error(error);
748
653
  }
749
654
  logger_1.logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
750
655
  const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', {
@@ -753,7 +658,7 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
753
658
  configModule: this.configModule,
754
659
  payload: {
755
660
  data: {
756
- workMode: this.deviceType.startsWith('Superior') && modeStr === 'auto' ? 'autoPro' : modeStr
661
+ mode
757
662
  },
758
663
  method: 'setHumidifierMode',
759
664
  source: 'APP'
@@ -761,7 +666,7 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
761
666
  }, helpers_1.Helpers.reqHeaderBypass());
762
667
  const success = this.checkResponse([response, status], 'setMode');
763
668
  if (!success) {
764
- logger_1.logger.debug('Error setting humidity mode');
669
+ logger_1.logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
765
670
  }
766
671
  return success;
767
672
  }
@@ -1011,11 +916,10 @@ class VeSyncWarmHumidifier extends VeSyncHumidifier {
1011
916
  * Set device mode
1012
917
  */
1013
918
  async setMode(mode) {
1014
- const modeStr = mode.toLowerCase();
1015
- if (!this.modes.includes(modeStr)) {
1016
- logger_1.logger.debug(`Invalid humidity mode used - ${mode}`);
1017
- logger_1.logger.debug(`Proper modes for this device are - ${this.modes.join(', ')}`);
1018
- return false;
919
+ if (!this.modes.includes(mode)) {
920
+ const error = `Invalid mode: ${mode}. Must be one of: ${this.modes.join(', ')}`;
921
+ logger_1.logger.error(`${error} for device: ${this.deviceName}`);
922
+ throw new Error(error);
1019
923
  }
1020
924
  logger_1.logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
1021
925
  const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', {
@@ -1024,15 +928,18 @@ class VeSyncWarmHumidifier extends VeSyncHumidifier {
1024
928
  configModule: this.configModule,
1025
929
  payload: {
1026
930
  data: {
1027
- workMode: this.deviceType.startsWith('Superior') && modeStr === 'auto' ? 'autoPro' : modeStr
931
+ mode
1028
932
  },
1029
933
  method: 'setHumidifierMode',
1030
934
  source: 'APP'
1031
935
  }
1032
936
  }, helpers_1.Helpers.reqHeaderBypass());
1033
937
  const success = this.checkResponse([response, status], 'setMode');
1034
- if (!success) {
1035
- logger_1.logger.debug('Error setting humidity mode');
938
+ if (success) {
939
+ this.details.mode = mode;
940
+ }
941
+ else {
942
+ logger_1.logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
1036
943
  }
1037
944
  return success;
1038
945
  }
@@ -1041,13 +948,14 @@ class VeSyncWarmHumidifier extends VeSyncHumidifier {
1041
948
  */
1042
949
  async setWarmLevel(level) {
1043
950
  if (!this.hasFeature('warm')) {
1044
- logger_1.logger.debug('Warm mist control not supported');
1045
- return false;
951
+ const error = 'Warm mist control not supported';
952
+ logger_1.logger.error(`${error} for device: ${this.deviceName}`);
953
+ throw new Error(error);
1046
954
  }
1047
955
  if (!this.warmLevels.includes(level)) {
1048
- logger_1.logger.debug(`Invalid warm level: ${level} for device: ${this.deviceName}`);
1049
- logger_1.logger.debug(`Valid levels for ${this.deviceType}: ${this.warmLevels.join(', ')}`);
1050
- return false;
956
+ const error = `Invalid warm level: ${level}. Must be one of: ${this.warmLevels.join(', ')}`;
957
+ logger_1.logger.error(`${error} for device: ${this.deviceName}`);
958
+ throw new Error(error);
1051
959
  }
1052
960
  logger_1.logger.debug(`Setting warm level to ${level} for device: ${this.deviceName}`);
1053
961
  const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', {
@@ -1186,7 +1094,6 @@ class VeSyncAirBaseV2 extends VeSyncAirBypass {
1186
1094
  const body = {
1187
1095
  ...helpers_1.Helpers.reqBody(this.manager, 'bypassV2'),
1188
1096
  cid: this.cid,
1189
- deviceId: this.cid, // Add deviceId to match YAML spec
1190
1097
  configModule: this.configModule,
1191
1098
  payload: {
1192
1099
  method,
@@ -1304,11 +1211,12 @@ class VeSyncAirBaseV2 extends VeSyncAirBypass {
1304
1211
  * Change fan speed
1305
1212
  */
1306
1213
  async changeFanSpeed(speed) {
1307
- // const speeds = this.config.levels ?? [];
1308
- // if (!speeds.includes(speed)) {
1309
- // logger.error(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')} for device: ${this.deviceName}`);
1310
- // return false;
1311
- // }
1214
+ var _a;
1215
+ const speeds = (_a = this.config.levels) !== null && _a !== void 0 ? _a : [];
1216
+ if (!speeds.includes(speed)) {
1217
+ logger_1.logger.error(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')} for device: ${this.deviceName}`);
1218
+ return false;
1219
+ }
1312
1220
  logger_1.logger.info(`Changing fan speed to ${speed} for device: ${this.deviceName}`);
1313
1221
  const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', {
1314
1222
  ...helpers_1.Helpers.reqBody(this.manager, 'bypassV2'),
@@ -1594,7 +1502,6 @@ class VeSyncTowerFan extends VeSyncAirBaseV2 {
1594
1502
  const body = {
1595
1503
  ...helpers_1.Helpers.reqBody(this.manager, 'bypassV2'),
1596
1504
  cid: this.cid,
1597
- deviceId: this.cid, // Add deviceId to match YAML spec
1598
1505
  configModule: this.configModule,
1599
1506
  payload: {
1600
1507
  method,
@@ -1712,11 +1619,12 @@ class VeSyncTowerFan extends VeSyncAirBaseV2 {
1712
1619
  * Change fan speed
1713
1620
  */
1714
1621
  async changeFanSpeed(speed) {
1715
- // const speeds = this.config.levels ?? [];
1716
- // if (!speeds.includes(speed)) {
1717
- // logger.debug(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')}`);
1718
- // return false;
1719
- // }
1622
+ var _a;
1623
+ const speeds = (_a = this.config.levels) !== null && _a !== void 0 ? _a : [];
1624
+ if (!speeds.includes(speed)) {
1625
+ logger_1.logger.debug(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')}`);
1626
+ return false;
1627
+ }
1720
1628
  const [head, body] = this.buildApiDict('setLevel');
1721
1629
  body.payload.data = {
1722
1630
  levelIdx: 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsvesync",
3
- "version": "1.0.58",
3
+ "version": "1.0.60",
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",
@@ -26,7 +26,7 @@ export abstract class VeSyncBaseDevice {
26
26
  this.cid = details.cid || '';
27
27
  this.deviceName = details.deviceName || '';
28
28
  this.deviceStatus = details.deviceStatus || 'off';
29
- this.deviceType = this.normalizeDeviceType(details.deviceType || '');
29
+ this.deviceType = details.deviceType || '';
30
30
  this.deviceRegion = details.deviceRegion || '';
31
31
  this.uuid = details.uuid || '';
32
32
  this.configModule = details.configModule || '';
@@ -35,38 +35,6 @@ export abstract class VeSyncBaseDevice {
35
35
  this.connectionStatus = details.connectionStatus || 'offline';
36
36
  }
37
37
 
38
- /**
39
- * Normalize device type to match configuration keys
40
- * This handles variations in device type strings from the API
41
- */
42
- protected normalizeDeviceType(deviceType: string): string {
43
- // Remove any region suffixes (e.g. -USA, -EU)
44
- const baseType = deviceType.split('-')[0];
45
-
46
- // Handle known prefix mappings
47
- const prefixMap: Record<string, string> = {
48
- 'Core': 'Core',
49
- 'LAP': 'LAP',
50
- 'LTF': 'LTF',
51
- 'Classic': 'Classic',
52
- 'Dual': 'Dual',
53
- 'LUH': 'LUH',
54
- 'LEH': 'LEH',
55
- 'LV-PUR': 'LV-PUR',
56
- 'LV-RH': 'LV-RH'
57
- };
58
-
59
- // Check if the device type starts with any known prefix
60
- for (const [prefix, normalized] of Object.entries(prefixMap)) {
61
- if (deviceType.startsWith(prefix)) {
62
- return deviceType; // Keep the full device type for exact matches
63
- }
64
- }
65
-
66
- // If no prefix match, return the base type
67
- return baseType;
68
- }
69
-
70
38
  /**
71
39
  * Return formatted device info to stdout
72
40
  */
@@ -200,124 +200,101 @@ export const fanConfig: FanConfig = {
200
200
  // Classic Series
201
201
  'Classic300S': {
202
202
  module: 'VeSyncHumidifier',
203
- features: ['display', 'humidity', 'mist', 'timer', 'auto_mode'],
204
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
203
+ features: ['display', 'humidity', 'mist', 'timer', 'auto_mode']
205
204
  },
206
205
  'Classic200S': {
207
206
  module: 'VeSyncHumidifier',
208
- features: ['display', 'humidity', 'mist', 'timer', 'auto_mode'],
209
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
207
+ features: ['display', 'humidity', 'mist', 'timer', 'auto_mode']
210
208
  },
211
209
 
212
210
  // Dual Series
213
211
  'Dual200S': {
214
212
  module: 'VeSyncHumidifier',
215
- features: ['display', 'humidity', 'mist', 'timer', 'auto_mode'],
216
- levels: [1, 2]
213
+ features: ['display', 'humidity', 'mist', 'timer', 'auto_mode']
217
214
  },
218
215
 
219
216
  // LUH Series
220
217
  'LUH-A601S-WUSB': {
221
218
  module: 'VeSyncWarmHumidifier',
222
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
223
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
219
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
224
220
  },
225
221
  'LUH-A601S-AUSW': {
226
222
  module: 'VeSyncWarmHumidifier',
227
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
228
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
223
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
229
224
  },
230
225
  'LUH-D301S-WUSR': {
231
226
  module: 'VeSyncWarmHumidifier',
232
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
233
- levels: [1, 2]
227
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
234
228
  },
235
229
  'LUH-D301S-WJP': {
236
230
  module: 'VeSyncWarmHumidifier',
237
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
238
- levels: [1, 2]
231
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
239
232
  },
240
233
  'LUH-D301S-WEU': {
241
234
  module: 'VeSyncWarmHumidifier',
242
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
243
- levels: [1, 2]
235
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
244
236
  },
245
237
  'LUH-A602S-WUSR': {
246
238
  module: 'VeSyncWarmHumidifier',
247
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
248
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
239
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
249
240
  },
250
241
  'LUH-A602S-WUS': {
251
242
  module: 'VeSyncWarmHumidifier',
252
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
253
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
243
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
254
244
  },
255
245
  'LUH-A602S-WEUR': {
256
246
  module: 'VeSyncWarmHumidifier',
257
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
258
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
247
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
259
248
  },
260
249
  'LUH-A602S-WEU': {
261
250
  module: 'VeSyncWarmHumidifier',
262
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
263
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
251
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
264
252
  },
265
253
  'LUH-A602S-WJP': {
266
254
  module: 'VeSyncWarmHumidifier',
267
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
268
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
255
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
269
256
  },
270
257
  'LUH-A602S-WUSC': {
271
258
  module: 'VeSyncWarmHumidifier',
272
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
273
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
259
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
274
260
  },
275
261
  'LUH-O451S-WEU': {
276
262
  module: 'VeSyncWarmHumidifier',
277
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
278
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
263
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
279
264
  },
280
265
  'LUH-O451S-WUS': {
281
266
  module: 'VeSyncWarmHumidifier',
282
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
283
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
267
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
284
268
  },
285
269
  'LUH-O451S-WUSR': {
286
270
  module: 'VeSyncWarmHumidifier',
287
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
288
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
271
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
289
272
  },
290
273
  'LUH-O601S-WUS': {
291
274
  module: 'VeSyncWarmHumidifier',
292
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
293
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
275
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
294
276
  },
295
277
  'LUH-O601S-KUS': {
296
278
  module: 'VeSyncWarmHumidifier',
297
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
298
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
279
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
299
280
  },
300
281
  'LUH-M101S-WUS': {
301
282
  module: 'VeSyncWarmHumidifier',
302
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
303
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
283
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
304
284
  },
305
285
  'LUH-M101S-WEUR': {
306
286
  module: 'VeSyncWarmHumidifier',
307
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
308
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
287
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
309
288
  },
310
289
 
311
290
  // LEH Series
312
291
  'LEH-S601S-WUS': {
313
292
  module: 'VeSyncWarmHumidifier',
314
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode', 'drying'],
315
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
293
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode', 'drying']
316
294
  },
317
295
  'LEH-S601S-WUSR': {
318
296
  module: 'VeSyncWarmHumidifier',
319
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode', 'drying'],
320
- levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
297
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode', 'drying']
321
298
  },
322
299
 
323
300
  // LV Series
@@ -362,26 +339,11 @@ export abstract class VeSyncFan extends VeSyncBaseDevice {
362
339
  constructor(details: Record<string, any>, manager: VeSync) {
363
340
  super(details, manager);
364
341
  this.details = details;
365
-
366
- // Try exact match first
367
- let config = fanConfig[this.deviceType];
368
-
369
- // If no exact match, try base type
370
- if (!config) {
371
- const baseType = this.deviceType.split('-')[0];
372
- config = fanConfig[baseType];
373
- }
374
-
375
- // If still no match, use default
376
- this.config = config || {
342
+ this.config = fanConfig[this.deviceType] || {
377
343
  module: 'VeSyncAirBypass',
378
344
  features: [],
379
345
  levels: []
380
346
  };
381
-
382
- if (!config) {
383
- logger.debug(`No configuration found for device type: ${this.deviceType}`);
384
- }
385
347
  }
386
348
 
387
349
  /**
@@ -28,7 +28,6 @@ export class VeSyncAirBypass extends VeSyncFan {
28
28
  const body = {
29
29
  ...Helpers.reqBody(this.manager, 'bypassV2'),
30
30
  cid: this.cid,
31
- deviceId: this.cid, // Add deviceId to match YAML spec
32
31
  configModule: this.configModule,
33
32
  payload: {
34
33
  method,
@@ -258,14 +257,11 @@ export class VeSyncAirBypass extends VeSyncFan {
258
257
  * Change fan speed
259
258
  */
260
259
  async changeFanSpeed(speed: number): Promise<boolean> {
261
- logger.debug(`Attempting to change fan speed to ${speed} for device: ${this.deviceName}`);
262
- logger.debug(`Available speeds: ${this.config.levels?.join(', ')}`);
263
-
264
- // const speeds = this.config.levels ?? [];
265
- // if (!speeds.includes(speed)) {
266
- // logger.debug(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')}`);
267
- // return false;
268
- // }
260
+ const speeds = this.config.levels ?? [];
261
+ if (!speeds.includes(speed)) {
262
+ logger.error(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')} for device: ${this.deviceName}`);
263
+ return false;
264
+ }
269
265
 
270
266
  logger.info(`Changing fan speed to ${speed} for device: ${this.deviceName}`);
271
267
  const [response, status] = await this.callApi(
@@ -300,11 +296,10 @@ export class VeSyncAirBypass extends VeSyncFan {
300
296
  * Set device mode
301
297
  */
302
298
  async setMode(mode: string): Promise<boolean> {
303
- const modeStr = mode.toLowerCase();
304
- if (!this.modes.includes(modeStr as any)) {
305
- logger.debug(`Invalid humidity mode used - ${mode}`);
306
- logger.debug(`Proper modes for this device are - ${this.modes.join(', ')}`);
307
- return false;
299
+ if (!this.modes.includes(mode as any)) {
300
+ const error = `Invalid mode: ${mode}. Must be one of: ${this.modes.join(', ')}`;
301
+ logger.error(`${error} for device: ${this.deviceName}`);
302
+ throw new Error(error);
308
303
  }
309
304
 
310
305
  logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
@@ -317,9 +312,9 @@ export class VeSyncAirBypass extends VeSyncFan {
317
312
  configModule: this.configModule,
318
313
  payload: {
319
314
  data: {
320
- workMode: this.deviceType.startsWith('Superior') && modeStr === 'auto' ? 'autoPro' : modeStr
315
+ mode
321
316
  },
322
- method: 'setHumidifierMode',
317
+ method: 'setPurifierMode',
323
318
  source: 'APP'
324
319
  }
325
320
  },
@@ -328,7 +323,7 @@ export class VeSyncAirBypass extends VeSyncFan {
328
323
 
329
324
  const success = this.checkResponse([response, status], 'setMode');
330
325
  if (!success) {
331
- logger.debug('Error setting humidity mode');
326
+ logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
332
327
  }
333
328
  return success;
334
329
  }
@@ -605,7 +600,6 @@ export class VeSyncHumidifier extends VeSyncFan {
605
600
  protected readonly mistLevels: number[];
606
601
  protected readonly displayModes = ['on', 'off'] as const;
607
602
  protected readonly humidityRange = { min: 30, max: 80 };
608
- protected readonly states = ['inactive', 'idle', 'humidifying'] as const;
609
603
 
610
604
  constructor(details: Record<string, any>, manager: VeSync) {
611
605
  super(details, manager);
@@ -624,75 +618,6 @@ export class VeSyncHumidifier extends VeSyncFan {
624
618
  logger.debug(`Initialized VeSyncHumidifier device: ${this.deviceName}`);
625
619
  }
626
620
 
627
- /**
628
- * Get current operational state
629
- */
630
- get currentState(): string {
631
- if (this.deviceStatus === 'off') {
632
- return 'inactive';
633
- }
634
- if (this.details.water_lacks) {
635
- return 'idle';
636
- }
637
- return 'humidifying';
638
- }
639
-
640
- /**
641
- * Get water level percentage
642
- */
643
- get waterLevel(): number {
644
- return this.details.water_level ?? 0;
645
- }
646
-
647
- /**
648
- * Get water tank status
649
- */
650
- get waterTankLifted(): boolean {
651
- return this.details.water_tank_lifted ?? false;
652
- }
653
-
654
- /**
655
- * Get oscillation state
656
- */
657
- get oscillationEnabled(): boolean {
658
- return this.details.oscillation_enabled ?? false;
659
- }
660
-
661
- /**
662
- * Set oscillation state
663
- */
664
- async setOscillation(enabled: boolean): Promise<boolean> {
665
- if (!this.hasFeature('oscillation')) {
666
- logger.debug('Oscillation not supported');
667
- return false;
668
- }
669
-
670
- logger.debug(`Setting oscillation to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
671
- const [response, status] = await this.callApi(
672
- '/cloud/v2/deviceManaged/bypassV2',
673
- 'post',
674
- {
675
- ...Helpers.reqBody(this.manager, 'bypassV2'),
676
- cid: this.cid,
677
- configModule: this.configModule,
678
- payload: {
679
- data: {
680
- oscillationEnabled: enabled
681
- },
682
- method: 'setSwing',
683
- source: 'APP'
684
- }
685
- },
686
- Helpers.reqHeaderBypass()
687
- );
688
-
689
- const success = this.checkResponse([response, status], 'setOscillation');
690
- if (!success) {
691
- logger.debug('Error setting oscillation');
692
- }
693
- return success;
694
- }
695
-
696
621
  /**
697
622
  * Get device details
698
623
  */
@@ -730,13 +655,12 @@ export class VeSyncHumidifier extends VeSyncFan {
730
655
  humidity: result.humidity || 0,
731
656
  mist_level: result.mistLevel || 0,
732
657
  mist_virtual_level: result.virtualLevel || 0,
658
+ warm_level: result.warmLevel || 0,
733
659
  water_lacks: result.waterLacks || false,
734
- water_level: result.waterLevel || 0,
735
- water_tank_lifted: result.waterTankLifted || false,
736
660
  humidity_high: result.humidityHigh || false,
661
+ water_tank_lifted: result.waterTankLifted || false,
737
662
  display: result.display || false,
738
663
  automatic_stop: result.automaticStop || false,
739
- oscillation_enabled: result.oscillationEnabled || false,
740
664
  configuration: result.configuration || {},
741
665
  connection_status: result.connectionStatus || null
742
666
  };
@@ -745,37 +669,6 @@ export class VeSyncHumidifier extends VeSyncFan {
745
669
  return success;
746
670
  }
747
671
 
748
- /**
749
- * Display device info
750
- */
751
- override display(): void {
752
- super.display();
753
- const info = [
754
- ['Current State: ', this.currentState],
755
- ['Water Level: ', this.waterLevel, '%'],
756
- ['Water Tank: ', this.waterTankLifted ? 'Lifted' : 'Seated'],
757
- ['Oscillation: ', this.oscillationEnabled ? 'On' : 'Off']
758
- ];
759
-
760
- for (const [key, value, unit = ''] of info) {
761
- logger.info(`${key.toString().padEnd(30, '.')} ${value}${unit}`);
762
- }
763
- }
764
-
765
- /**
766
- * Return JSON details
767
- */
768
- override displayJSON(): string {
769
- const baseInfo = JSON.parse(super.displayJSON());
770
- return JSON.stringify({
771
- ...baseInfo,
772
- 'Current State': this.currentState,
773
- 'Water Level': this.waterLevel,
774
- 'Water Tank': this.waterTankLifted ? 'Lifted' : 'Seated',
775
- 'Oscillation': this.oscillationEnabled ? 'On' : 'Off'
776
- }, null, 4);
777
- }
778
-
779
672
  /**
780
673
  * Turn device on
781
674
  */
@@ -847,9 +740,9 @@ export class VeSyncHumidifier extends VeSyncFan {
847
740
  */
848
741
  async setMistLevel(level: number): Promise<boolean> {
849
742
  if (!this.mistLevels.includes(level)) {
850
- logger.debug(`Invalid mist level: ${level} for device: ${this.deviceName}`);
851
- logger.debug(`Valid levels for ${this.deviceType}: ${this.mistLevels.join(', ')}`);
852
- return false;
743
+ const error = `Invalid mist level: ${level}. Must be one of: ${this.mistLevels.join(', ')}`;
744
+ logger.error(`${error} for device: ${this.deviceName}`);
745
+ throw new Error(error);
853
746
  }
854
747
 
855
748
  logger.info(`Setting mist level to ${level} for device: ${this.deviceName}`);
@@ -862,9 +755,9 @@ export class VeSyncHumidifier extends VeSyncFan {
862
755
  configModule: this.configModule,
863
756
  payload: {
864
757
  data: {
865
- levelIdx: 0,
866
- virtualLevel: level,
867
- levelType: 'mist'
758
+ id: 0,
759
+ level: level,
760
+ type: 'mist'
868
761
  },
869
762
  method: 'setVirtualLevel',
870
763
  source: 'APP'
@@ -875,7 +768,7 @@ export class VeSyncHumidifier extends VeSyncFan {
875
768
 
876
769
  const success = this.checkResponse([response, status], 'setMistLevel');
877
770
  if (!success) {
878
- logger.debug('Error setting mist level');
771
+ logger.error(`Failed to set mist level to ${level} for device: ${this.deviceName}`);
879
772
  }
880
773
  return success;
881
774
  }
@@ -892,11 +785,10 @@ export class VeSyncHumidifier extends VeSyncFan {
892
785
  * Set device mode
893
786
  */
894
787
  async setMode(mode: string): Promise<boolean> {
895
- const modeStr = mode.toLowerCase();
896
- if (!this.modes.includes(modeStr as any)) {
897
- logger.debug(`Invalid humidity mode used - ${mode}`);
898
- logger.debug(`Proper modes for this device are - ${this.modes.join(', ')}`);
899
- return false;
788
+ if (!this.modes.includes(mode as any)) {
789
+ const error = `Invalid mode: ${mode}. Must be one of: ${this.modes.join(', ')}`;
790
+ logger.error(`${error} for device: ${this.deviceName}`);
791
+ throw new Error(error);
900
792
  }
901
793
 
902
794
  logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
@@ -909,7 +801,7 @@ export class VeSyncHumidifier extends VeSyncFan {
909
801
  configModule: this.configModule,
910
802
  payload: {
911
803
  data: {
912
- workMode: this.deviceType.startsWith('Superior') && modeStr === 'auto' ? 'autoPro' : modeStr
804
+ mode
913
805
  },
914
806
  method: 'setHumidifierMode',
915
807
  source: 'APP'
@@ -920,7 +812,7 @@ export class VeSyncHumidifier extends VeSyncFan {
920
812
 
921
813
  const success = this.checkResponse([response, status], 'setMode');
922
814
  if (!success) {
923
- logger.debug('Error setting humidity mode');
815
+ logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
924
816
  }
925
817
  return success;
926
818
  }
@@ -1225,11 +1117,10 @@ export class VeSyncWarmHumidifier extends VeSyncHumidifier {
1225
1117
  * Set device mode
1226
1118
  */
1227
1119
  async setMode(mode: string): Promise<boolean> {
1228
- const modeStr = mode.toLowerCase();
1229
- if (!this.modes.includes(modeStr as any)) {
1230
- logger.debug(`Invalid humidity mode used - ${mode}`);
1231
- logger.debug(`Proper modes for this device are - ${this.modes.join(', ')}`);
1232
- return false;
1120
+ if (!this.modes.includes(mode as any)) {
1121
+ const error = `Invalid mode: ${mode}. Must be one of: ${this.modes.join(', ')}`;
1122
+ logger.error(`${error} for device: ${this.deviceName}`);
1123
+ throw new Error(error);
1233
1124
  }
1234
1125
 
1235
1126
  logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
@@ -1242,7 +1133,7 @@ export class VeSyncWarmHumidifier extends VeSyncHumidifier {
1242
1133
  configModule: this.configModule,
1243
1134
  payload: {
1244
1135
  data: {
1245
- workMode: this.deviceType.startsWith('Superior') && modeStr === 'auto' ? 'autoPro' : modeStr
1136
+ mode
1246
1137
  },
1247
1138
  method: 'setHumidifierMode',
1248
1139
  source: 'APP'
@@ -1252,8 +1143,10 @@ export class VeSyncWarmHumidifier extends VeSyncHumidifier {
1252
1143
  );
1253
1144
 
1254
1145
  const success = this.checkResponse([response, status], 'setMode');
1255
- if (!success) {
1256
- logger.debug('Error setting humidity mode');
1146
+ if (success) {
1147
+ this.details.mode = mode;
1148
+ } else {
1149
+ logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
1257
1150
  }
1258
1151
  return success;
1259
1152
  }
@@ -1263,14 +1156,15 @@ export class VeSyncWarmHumidifier extends VeSyncHumidifier {
1263
1156
  */
1264
1157
  async setWarmLevel(level: number): Promise<boolean> {
1265
1158
  if (!this.hasFeature('warm')) {
1266
- logger.debug('Warm mist control not supported');
1267
- return false;
1159
+ const error = 'Warm mist control not supported';
1160
+ logger.error(`${error} for device: ${this.deviceName}`);
1161
+ throw new Error(error);
1268
1162
  }
1269
1163
 
1270
1164
  if (!this.warmLevels.includes(level)) {
1271
- logger.debug(`Invalid warm level: ${level} for device: ${this.deviceName}`);
1272
- logger.debug(`Valid levels for ${this.deviceType}: ${this.warmLevels.join(', ')}`);
1273
- return false;
1165
+ const error = `Invalid warm level: ${level}. Must be one of: ${this.warmLevels.join(', ')}`;
1166
+ logger.error(`${error} for device: ${this.deviceName}`);
1167
+ throw new Error(error);
1274
1168
  }
1275
1169
 
1276
1170
  logger.debug(`Setting warm level to ${level} for device: ${this.deviceName}`);
@@ -1436,7 +1330,6 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
1436
1330
  const body = {
1437
1331
  ...Helpers.reqBody(this.manager, 'bypassV2'),
1438
1332
  cid: this.cid,
1439
- deviceId: this.cid, // Add deviceId to match YAML spec
1440
1333
  configModule: this.configModule,
1441
1334
  payload: {
1442
1335
  method,
@@ -1576,11 +1469,11 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
1576
1469
  * Change fan speed
1577
1470
  */
1578
1471
  async changeFanSpeed(speed: number): Promise<boolean> {
1579
- // const speeds = this.config.levels ?? [];
1580
- // if (!speeds.includes(speed)) {
1581
- // logger.error(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')} for device: ${this.deviceName}`);
1582
- // return false;
1583
- // }
1472
+ const speeds = this.config.levels ?? [];
1473
+ if (!speeds.includes(speed)) {
1474
+ logger.error(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')} for device: ${this.deviceName}`);
1475
+ return false;
1476
+ }
1584
1477
 
1585
1478
  logger.info(`Changing fan speed to ${speed} for device: ${this.deviceName}`);
1586
1479
  const [response, status] = await this.callApi(
@@ -1957,7 +1850,6 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
1957
1850
  const body = {
1958
1851
  ...Helpers.reqBody(this.manager, 'bypassV2'),
1959
1852
  cid: this.cid,
1960
- deviceId: this.cid, // Add deviceId to match YAML spec
1961
1853
  configModule: this.configModule,
1962
1854
  payload: {
1963
1855
  method,
@@ -2106,11 +1998,11 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
2106
1998
  * Change fan speed
2107
1999
  */
2108
2000
  async changeFanSpeed(speed: number): Promise<boolean> {
2109
- // const speeds = this.config.levels ?? [];
2110
- // if (!speeds.includes(speed)) {
2111
- // logger.debug(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')}`);
2112
- // return false;
2113
- // }
2001
+ const speeds = this.config.levels ?? [];
2002
+ if (!speeds.includes(speed)) {
2003
+ logger.debug(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')}`);
2004
+ return false;
2005
+ }
2114
2006
 
2115
2007
  const [head, body] = this.buildApiDict('setLevel');
2116
2008
  body.payload.data = {