tsvesync 1.0.50 → 1.0.51

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.
@@ -189,98 +189,121 @@ exports.fanConfig = {
189
189
  // Classic Series
190
190
  'Classic300S': {
191
191
  module: 'VeSyncHumidifier',
192
- features: ['display', 'humidity', 'mist', 'timer', 'auto_mode']
192
+ features: ['display', 'humidity', 'mist', 'timer', 'auto_mode'],
193
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
193
194
  },
194
195
  'Classic200S': {
195
196
  module: 'VeSyncHumidifier',
196
- features: ['display', 'humidity', 'mist', 'timer', 'auto_mode']
197
+ features: ['display', 'humidity', 'mist', 'timer', 'auto_mode'],
198
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
197
199
  },
198
200
  // Dual Series
199
201
  'Dual200S': {
200
202
  module: 'VeSyncHumidifier',
201
- features: ['display', 'humidity', 'mist', 'timer', 'auto_mode']
203
+ features: ['display', 'humidity', 'mist', 'timer', 'auto_mode'],
204
+ levels: [1, 2]
202
205
  },
203
206
  // LUH Series
204
207
  'LUH-A601S-WUSB': {
205
208
  module: 'VeSyncWarmHumidifier',
206
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
209
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
210
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
207
211
  },
208
212
  'LUH-A601S-AUSW': {
209
213
  module: 'VeSyncWarmHumidifier',
210
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
214
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
215
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
211
216
  },
212
217
  'LUH-D301S-WUSR': {
213
218
  module: 'VeSyncWarmHumidifier',
214
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
219
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
220
+ levels: [1, 2]
215
221
  },
216
222
  'LUH-D301S-WJP': {
217
223
  module: 'VeSyncWarmHumidifier',
218
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
224
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
225
+ levels: [1, 2]
219
226
  },
220
227
  'LUH-D301S-WEU': {
221
228
  module: 'VeSyncWarmHumidifier',
222
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
229
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
230
+ levels: [1, 2]
223
231
  },
224
232
  'LUH-A602S-WUSR': {
225
233
  module: 'VeSyncWarmHumidifier',
226
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
234
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
235
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
227
236
  },
228
237
  'LUH-A602S-WUS': {
229
238
  module: 'VeSyncWarmHumidifier',
230
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
239
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
240
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
231
241
  },
232
242
  'LUH-A602S-WEUR': {
233
243
  module: 'VeSyncWarmHumidifier',
234
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
244
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
245
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
235
246
  },
236
247
  'LUH-A602S-WEU': {
237
248
  module: 'VeSyncWarmHumidifier',
238
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
249
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
250
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
239
251
  },
240
252
  'LUH-A602S-WJP': {
241
253
  module: 'VeSyncWarmHumidifier',
242
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
254
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
255
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
243
256
  },
244
257
  'LUH-A602S-WUSC': {
245
258
  module: 'VeSyncWarmHumidifier',
246
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
259
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
260
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
247
261
  },
248
262
  'LUH-O451S-WEU': {
249
263
  module: 'VeSyncWarmHumidifier',
250
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
264
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
265
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
251
266
  },
252
267
  'LUH-O451S-WUS': {
253
268
  module: 'VeSyncWarmHumidifier',
254
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
269
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
270
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
255
271
  },
256
272
  'LUH-O451S-WUSR': {
257
273
  module: 'VeSyncWarmHumidifier',
258
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
274
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
275
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
259
276
  },
260
277
  'LUH-O601S-WUS': {
261
278
  module: 'VeSyncWarmHumidifier',
262
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
279
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
280
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
263
281
  },
264
282
  'LUH-O601S-KUS': {
265
283
  module: 'VeSyncWarmHumidifier',
266
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
284
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
285
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
267
286
  },
268
287
  'LUH-M101S-WUS': {
269
288
  module: 'VeSyncWarmHumidifier',
270
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
289
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
290
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
271
291
  },
272
292
  'LUH-M101S-WEUR': {
273
293
  module: 'VeSyncWarmHumidifier',
274
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
294
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
295
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
275
296
  },
276
297
  // LEH Series
277
298
  'LEH-S601S-WUS': {
278
299
  module: 'VeSyncWarmHumidifier',
279
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode', 'drying']
300
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode', 'drying'],
301
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
280
302
  },
281
303
  'LEH-S601S-WUSR': {
282
304
  module: 'VeSyncWarmHumidifier',
283
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode', 'drying']
305
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode', 'drying'],
306
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
284
307
  },
285
308
  // LV Series
286
309
  'LV-PUR131S': {
@@ -91,11 +91,40 @@ export declare class VeSyncHumidifier extends VeSyncFan {
91
91
  min: number;
92
92
  max: number;
93
93
  };
94
+ protected readonly states: readonly ["inactive", "idle", "humidifying"];
94
95
  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>;
95
116
  /**
96
117
  * Get device details
97
118
  */
98
119
  getDetails(): Promise<Boolean>;
120
+ /**
121
+ * Display device info
122
+ */
123
+ display(): void;
124
+ /**
125
+ * Return JSON details
126
+ */
127
+ displayJSON(): string;
99
128
  /**
100
129
  * Turn device on
101
130
  */
@@ -26,6 +26,7 @@ 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
29
30
  configModule: this.configModule,
30
31
  payload: {
31
32
  method,
@@ -241,10 +242,11 @@ class VeSyncAirBypass extends vesyncFan_1.VeSyncFan {
241
242
  * Set device mode
242
243
  */
243
244
  async setMode(mode) {
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);
245
+ const modeStr = mode.toLowerCase();
246
+ if (!this.modes.includes(modeStr)) {
247
+ logger_1.logger.debug(`Invalid humidity mode used - ${mode}`);
248
+ logger_1.logger.debug(`Proper modes for this device are - ${this.modes.join(', ')}`);
249
+ return false;
248
250
  }
249
251
  logger_1.logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
250
252
  const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', {
@@ -253,15 +255,15 @@ class VeSyncAirBypass extends vesyncFan_1.VeSyncFan {
253
255
  configModule: this.configModule,
254
256
  payload: {
255
257
  data: {
256
- mode
258
+ workMode: this.deviceType.startsWith('Superior') && modeStr === 'auto' ? 'autoPro' : modeStr
257
259
  },
258
- method: 'setPurifierMode',
260
+ method: 'setHumidifierMode',
259
261
  source: 'APP'
260
262
  }
261
263
  }, helpers_1.Helpers.reqHeaderBypass());
262
264
  const success = this.checkResponse([response, status], 'setMode');
263
265
  if (!success) {
264
- logger_1.logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
266
+ logger_1.logger.debug('Error setting humidity mode');
265
267
  }
266
268
  return success;
267
269
  }
@@ -488,6 +490,7 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
488
490
  this.modes = ['auto', 'manual', 'sleep'];
489
491
  this.displayModes = ['on', 'off'];
490
492
  this.humidityRange = { min: 30, max: 80 };
493
+ this.states = ['inactive', 'idle', 'humidifying'];
491
494
  // Set mist levels based on model
492
495
  switch (this.deviceType) {
493
496
  case 'Dual200S':
@@ -502,6 +505,66 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
502
505
  }
503
506
  logger_1.logger.debug(`Initialized VeSyncHumidifier device: ${this.deviceName}`);
504
507
  }
508
+ /**
509
+ * Get current operational state
510
+ */
511
+ get currentState() {
512
+ if (this.deviceStatus === 'off') {
513
+ return 'inactive';
514
+ }
515
+ if (this.details.water_lacks) {
516
+ return 'idle';
517
+ }
518
+ return 'humidifying';
519
+ }
520
+ /**
521
+ * Get water level percentage
522
+ */
523
+ get waterLevel() {
524
+ var _a;
525
+ return (_a = this.details.water_level) !== null && _a !== void 0 ? _a : 0;
526
+ }
527
+ /**
528
+ * Get water tank status
529
+ */
530
+ get waterTankLifted() {
531
+ var _a;
532
+ return (_a = this.details.water_tank_lifted) !== null && _a !== void 0 ? _a : false;
533
+ }
534
+ /**
535
+ * Get oscillation state
536
+ */
537
+ get oscillationEnabled() {
538
+ var _a;
539
+ return (_a = this.details.oscillation_enabled) !== null && _a !== void 0 ? _a : false;
540
+ }
541
+ /**
542
+ * Set oscillation state
543
+ */
544
+ async setOscillation(enabled) {
545
+ if (!this.hasFeature('oscillation')) {
546
+ logger_1.logger.debug('Oscillation not supported');
547
+ return false;
548
+ }
549
+ logger_1.logger.debug(`Setting oscillation to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
550
+ const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', {
551
+ ...helpers_1.Helpers.reqBody(this.manager, 'bypassV2'),
552
+ cid: this.cid,
553
+ configModule: this.configModule,
554
+ payload: {
555
+ data: {
556
+ oscillationEnabled: enabled
557
+ },
558
+ method: 'setSwing',
559
+ source: 'APP'
560
+ }
561
+ }, helpers_1.Helpers.reqHeaderBypass());
562
+ const success = this.checkResponse([response, status], 'setOscillation');
563
+ if (!success) {
564
+ logger_1.logger.debug('Error setting oscillation');
565
+ }
566
+ return success;
567
+ }
505
568
  /**
506
569
  * Get device details
507
570
  */
@@ -533,12 +596,13 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
533
596
  humidity: result.humidity || 0,
534
597
  mist_level: result.mistLevel || 0,
535
598
  mist_virtual_level: result.virtualLevel || 0,
536
- warm_level: result.warmLevel || 0,
537
599
  water_lacks: result.waterLacks || false,
538
- humidity_high: result.humidityHigh || false,
600
+ water_level: result.waterLevel || 0,
539
601
  water_tank_lifted: result.waterTankLifted || false,
602
+ humidity_high: result.humidityHigh || false,
540
603
  display: result.display || false,
541
604
  automatic_stop: result.automaticStop || false,
605
+ oscillation_enabled: result.oscillationEnabled || false,
542
606
  configuration: result.configuration || {},
543
607
  connection_status: result.connectionStatus || null
544
608
  };
@@ -546,6 +610,34 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
546
610
  }
547
611
  return success;
548
612
  }
613
+ /**
614
+ * Display device info
615
+ */
616
+ display() {
617
+ super.display();
618
+ const info = [
619
+ ['Current State: ', this.currentState],
620
+ ['Water Level: ', this.waterLevel, '%'],
621
+ ['Water Tank: ', this.waterTankLifted ? 'Lifted' : 'Seated'],
622
+ ['Oscillation: ', this.oscillationEnabled ? 'On' : 'Off']
623
+ ];
624
+ for (const [key, value, unit = ''] of info) {
625
+ logger_1.logger.info(`${key.toString().padEnd(30, '.')} ${value}${unit}`);
626
+ }
627
+ }
628
+ /**
629
+ * Return JSON details
630
+ */
631
+ displayJSON() {
632
+ const baseInfo = JSON.parse(super.displayJSON());
633
+ return JSON.stringify({
634
+ ...baseInfo,
635
+ 'Current State': this.currentState,
636
+ 'Water Level': this.waterLevel,
637
+ 'Water Tank': this.waterTankLifted ? 'Lifted' : 'Seated',
638
+ 'Oscillation': this.oscillationEnabled ? 'On' : 'Off'
639
+ }, null, 4);
640
+ }
549
641
  /**
550
642
  * Turn device on
551
643
  */
@@ -610,9 +702,9 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
610
702
  */
611
703
  async setMistLevel(level) {
612
704
  if (!this.mistLevels.includes(level)) {
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);
705
+ logger_1.logger.debug(`Invalid mist level: ${level} for device: ${this.deviceName}`);
706
+ logger_1.logger.debug(`Valid levels for ${this.deviceType}: ${this.mistLevels.join(', ')}`);
707
+ return false;
616
708
  }
617
709
  logger_1.logger.info(`Setting mist level to ${level} for device: ${this.deviceName}`);
618
710
  const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', {
@@ -621,9 +713,9 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
621
713
  configModule: this.configModule,
622
714
  payload: {
623
715
  data: {
624
- id: 0,
625
- level: level,
626
- type: 'mist'
716
+ levelIdx: 0,
717
+ virtualLevel: level,
718
+ levelType: 'mist'
627
719
  },
628
720
  method: 'setVirtualLevel',
629
721
  source: 'APP'
@@ -631,7 +723,7 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
631
723
  }, helpers_1.Helpers.reqHeaderBypass());
632
724
  const success = this.checkResponse([response, status], 'setMistLevel');
633
725
  if (!success) {
634
- logger_1.logger.error(`Failed to set mist level to ${level} for device: ${this.deviceName}`);
726
+ logger_1.logger.debug('Error setting mist level');
635
727
  }
636
728
  return success;
637
729
  }
@@ -646,10 +738,11 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
646
738
  * Set device mode
647
739
  */
648
740
  async setMode(mode) {
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);
741
+ const modeStr = mode.toLowerCase();
742
+ if (!this.modes.includes(modeStr)) {
743
+ logger_1.logger.debug(`Invalid humidity mode used - ${mode}`);
744
+ logger_1.logger.debug(`Proper modes for this device are - ${this.modes.join(', ')}`);
745
+ return false;
653
746
  }
654
747
  logger_1.logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
655
748
  const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', {
@@ -658,7 +751,7 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
658
751
  configModule: this.configModule,
659
752
  payload: {
660
753
  data: {
661
- mode
754
+ workMode: this.deviceType.startsWith('Superior') && modeStr === 'auto' ? 'autoPro' : modeStr
662
755
  },
663
756
  method: 'setHumidifierMode',
664
757
  source: 'APP'
@@ -666,7 +759,7 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
666
759
  }, helpers_1.Helpers.reqHeaderBypass());
667
760
  const success = this.checkResponse([response, status], 'setMode');
668
761
  if (!success) {
669
- logger_1.logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
762
+ logger_1.logger.debug('Error setting humidity mode');
670
763
  }
671
764
  return success;
672
765
  }
@@ -916,10 +1009,11 @@ class VeSyncWarmHumidifier extends VeSyncHumidifier {
916
1009
  * Set device mode
917
1010
  */
918
1011
  async setMode(mode) {
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);
1012
+ const modeStr = mode.toLowerCase();
1013
+ if (!this.modes.includes(modeStr)) {
1014
+ logger_1.logger.debug(`Invalid humidity mode used - ${mode}`);
1015
+ logger_1.logger.debug(`Proper modes for this device are - ${this.modes.join(', ')}`);
1016
+ return false;
923
1017
  }
924
1018
  logger_1.logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
925
1019
  const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', {
@@ -928,18 +1022,15 @@ class VeSyncWarmHumidifier extends VeSyncHumidifier {
928
1022
  configModule: this.configModule,
929
1023
  payload: {
930
1024
  data: {
931
- mode
1025
+ workMode: this.deviceType.startsWith('Superior') && modeStr === 'auto' ? 'autoPro' : modeStr
932
1026
  },
933
1027
  method: 'setHumidifierMode',
934
1028
  source: 'APP'
935
1029
  }
936
1030
  }, helpers_1.Helpers.reqHeaderBypass());
937
1031
  const success = this.checkResponse([response, status], 'setMode');
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}`);
1032
+ if (!success) {
1033
+ logger_1.logger.debug('Error setting humidity mode');
943
1034
  }
944
1035
  return success;
945
1036
  }
@@ -948,14 +1039,13 @@ class VeSyncWarmHumidifier extends VeSyncHumidifier {
948
1039
  */
949
1040
  async setWarmLevel(level) {
950
1041
  if (!this.hasFeature('warm')) {
951
- const error = 'Warm mist control not supported';
952
- logger_1.logger.error(`${error} for device: ${this.deviceName}`);
953
- throw new Error(error);
1042
+ logger_1.logger.debug('Warm mist control not supported');
1043
+ return false;
954
1044
  }
955
1045
  if (!this.warmLevels.includes(level)) {
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);
1046
+ logger_1.logger.debug(`Invalid warm level: ${level} for device: ${this.deviceName}`);
1047
+ logger_1.logger.debug(`Valid levels for ${this.deviceType}: ${this.warmLevels.join(', ')}`);
1048
+ return false;
959
1049
  }
960
1050
  logger_1.logger.debug(`Setting warm level to ${level} for device: ${this.deviceName}`);
961
1051
  const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', {
@@ -1094,6 +1184,7 @@ class VeSyncAirBaseV2 extends VeSyncAirBypass {
1094
1184
  const body = {
1095
1185
  ...helpers_1.Helpers.reqBody(this.manager, 'bypassV2'),
1096
1186
  cid: this.cid,
1187
+ deviceId: this.cid, // Add deviceId to match YAML spec
1097
1188
  configModule: this.configModule,
1098
1189
  payload: {
1099
1190
  method,
@@ -1502,6 +1593,7 @@ class VeSyncTowerFan extends VeSyncAirBaseV2 {
1502
1593
  const body = {
1503
1594
  ...helpers_1.Helpers.reqBody(this.manager, 'bypassV2'),
1504
1595
  cid: this.cid,
1596
+ deviceId: this.cid, // Add deviceId to match YAML spec
1505
1597
  configModule: this.configModule,
1506
1598
  payload: {
1507
1599
  method,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsvesync",
3
- "version": "1.0.50",
3
+ "version": "1.0.51",
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",
@@ -200,101 +200,124 @@ export const fanConfig: FanConfig = {
200
200
  // Classic Series
201
201
  'Classic300S': {
202
202
  module: 'VeSyncHumidifier',
203
- features: ['display', 'humidity', 'mist', 'timer', 'auto_mode']
203
+ features: ['display', 'humidity', 'mist', 'timer', 'auto_mode'],
204
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
204
205
  },
205
206
  'Classic200S': {
206
207
  module: 'VeSyncHumidifier',
207
- features: ['display', 'humidity', 'mist', 'timer', 'auto_mode']
208
+ features: ['display', 'humidity', 'mist', 'timer', 'auto_mode'],
209
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
208
210
  },
209
211
 
210
212
  // Dual Series
211
213
  'Dual200S': {
212
214
  module: 'VeSyncHumidifier',
213
- features: ['display', 'humidity', 'mist', 'timer', 'auto_mode']
215
+ features: ['display', 'humidity', 'mist', 'timer', 'auto_mode'],
216
+ levels: [1, 2]
214
217
  },
215
218
 
216
219
  // LUH Series
217
220
  'LUH-A601S-WUSB': {
218
221
  module: 'VeSyncWarmHumidifier',
219
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
222
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
223
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
220
224
  },
221
225
  'LUH-A601S-AUSW': {
222
226
  module: 'VeSyncWarmHumidifier',
223
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
227
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
228
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
224
229
  },
225
230
  'LUH-D301S-WUSR': {
226
231
  module: 'VeSyncWarmHumidifier',
227
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
232
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
233
+ levels: [1, 2]
228
234
  },
229
235
  'LUH-D301S-WJP': {
230
236
  module: 'VeSyncWarmHumidifier',
231
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
237
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
238
+ levels: [1, 2]
232
239
  },
233
240
  'LUH-D301S-WEU': {
234
241
  module: 'VeSyncWarmHumidifier',
235
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
242
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
243
+ levels: [1, 2]
236
244
  },
237
245
  'LUH-A602S-WUSR': {
238
246
  module: 'VeSyncWarmHumidifier',
239
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
247
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
248
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
240
249
  },
241
250
  'LUH-A602S-WUS': {
242
251
  module: 'VeSyncWarmHumidifier',
243
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
252
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
253
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
244
254
  },
245
255
  'LUH-A602S-WEUR': {
246
256
  module: 'VeSyncWarmHumidifier',
247
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
257
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
258
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
248
259
  },
249
260
  'LUH-A602S-WEU': {
250
261
  module: 'VeSyncWarmHumidifier',
251
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
262
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
263
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
252
264
  },
253
265
  'LUH-A602S-WJP': {
254
266
  module: 'VeSyncWarmHumidifier',
255
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
267
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
268
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
256
269
  },
257
270
  'LUH-A602S-WUSC': {
258
271
  module: 'VeSyncWarmHumidifier',
259
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
272
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
273
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
260
274
  },
261
275
  'LUH-O451S-WEU': {
262
276
  module: 'VeSyncWarmHumidifier',
263
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
277
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
278
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
264
279
  },
265
280
  'LUH-O451S-WUS': {
266
281
  module: 'VeSyncWarmHumidifier',
267
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
282
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
283
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
268
284
  },
269
285
  'LUH-O451S-WUSR': {
270
286
  module: 'VeSyncWarmHumidifier',
271
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
287
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
288
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
272
289
  },
273
290
  'LUH-O601S-WUS': {
274
291
  module: 'VeSyncWarmHumidifier',
275
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
292
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
293
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
276
294
  },
277
295
  'LUH-O601S-KUS': {
278
296
  module: 'VeSyncWarmHumidifier',
279
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
297
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
298
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
280
299
  },
281
300
  'LUH-M101S-WUS': {
282
301
  module: 'VeSyncWarmHumidifier',
283
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
302
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
303
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
284
304
  },
285
305
  'LUH-M101S-WEUR': {
286
306
  module: 'VeSyncWarmHumidifier',
287
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
307
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode'],
308
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
288
309
  },
289
310
 
290
311
  // LEH Series
291
312
  'LEH-S601S-WUS': {
292
313
  module: 'VeSyncWarmHumidifier',
293
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode', 'drying']
314
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode', 'drying'],
315
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
294
316
  },
295
317
  'LEH-S601S-WUSR': {
296
318
  module: 'VeSyncWarmHumidifier',
297
- features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode', 'drying']
319
+ features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode', 'drying'],
320
+ levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
298
321
  },
299
322
 
300
323
  // LV Series
@@ -28,6 +28,7 @@ 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
31
32
  configModule: this.configModule,
32
33
  payload: {
33
34
  method,
@@ -296,10 +297,11 @@ export class VeSyncAirBypass extends VeSyncFan {
296
297
  * Set device mode
297
298
  */
298
299
  async setMode(mode: string): Promise<boolean> {
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);
300
+ const modeStr = mode.toLowerCase();
301
+ if (!this.modes.includes(modeStr as any)) {
302
+ logger.debug(`Invalid humidity mode used - ${mode}`);
303
+ logger.debug(`Proper modes for this device are - ${this.modes.join(', ')}`);
304
+ return false;
303
305
  }
304
306
 
305
307
  logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
@@ -312,9 +314,9 @@ export class VeSyncAirBypass extends VeSyncFan {
312
314
  configModule: this.configModule,
313
315
  payload: {
314
316
  data: {
315
- mode
317
+ workMode: this.deviceType.startsWith('Superior') && modeStr === 'auto' ? 'autoPro' : modeStr
316
318
  },
317
- method: 'setPurifierMode',
319
+ method: 'setHumidifierMode',
318
320
  source: 'APP'
319
321
  }
320
322
  },
@@ -323,7 +325,7 @@ export class VeSyncAirBypass extends VeSyncFan {
323
325
 
324
326
  const success = this.checkResponse([response, status], 'setMode');
325
327
  if (!success) {
326
- logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
328
+ logger.debug('Error setting humidity mode');
327
329
  }
328
330
  return success;
329
331
  }
@@ -600,6 +602,7 @@ export class VeSyncHumidifier extends VeSyncFan {
600
602
  protected readonly mistLevels: number[];
601
603
  protected readonly displayModes = ['on', 'off'] as const;
602
604
  protected readonly humidityRange = { min: 30, max: 80 };
605
+ protected readonly states = ['inactive', 'idle', 'humidifying'] as const;
603
606
 
604
607
  constructor(details: Record<string, any>, manager: VeSync) {
605
608
  super(details, manager);
@@ -618,6 +621,75 @@ export class VeSyncHumidifier extends VeSyncFan {
618
621
  logger.debug(`Initialized VeSyncHumidifier device: ${this.deviceName}`);
619
622
  }
620
623
 
624
+ /**
625
+ * Get current operational state
626
+ */
627
+ get currentState(): string {
628
+ if (this.deviceStatus === 'off') {
629
+ return 'inactive';
630
+ }
631
+ if (this.details.water_lacks) {
632
+ return 'idle';
633
+ }
634
+ return 'humidifying';
635
+ }
636
+
637
+ /**
638
+ * Get water level percentage
639
+ */
640
+ get waterLevel(): number {
641
+ return this.details.water_level ?? 0;
642
+ }
643
+
644
+ /**
645
+ * Get water tank status
646
+ */
647
+ get waterTankLifted(): boolean {
648
+ return this.details.water_tank_lifted ?? false;
649
+ }
650
+
651
+ /**
652
+ * Get oscillation state
653
+ */
654
+ get oscillationEnabled(): boolean {
655
+ return this.details.oscillation_enabled ?? false;
656
+ }
657
+
658
+ /**
659
+ * Set oscillation state
660
+ */
661
+ async setOscillation(enabled: boolean): Promise<boolean> {
662
+ if (!this.hasFeature('oscillation')) {
663
+ logger.debug('Oscillation not supported');
664
+ return false;
665
+ }
666
+
667
+ logger.debug(`Setting oscillation to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
668
+ const [response, status] = await this.callApi(
669
+ '/cloud/v2/deviceManaged/bypassV2',
670
+ 'post',
671
+ {
672
+ ...Helpers.reqBody(this.manager, 'bypassV2'),
673
+ cid: this.cid,
674
+ configModule: this.configModule,
675
+ payload: {
676
+ data: {
677
+ oscillationEnabled: enabled
678
+ },
679
+ method: 'setSwing',
680
+ source: 'APP'
681
+ }
682
+ },
683
+ Helpers.reqHeaderBypass()
684
+ );
685
+
686
+ const success = this.checkResponse([response, status], 'setOscillation');
687
+ if (!success) {
688
+ logger.debug('Error setting oscillation');
689
+ }
690
+ return success;
691
+ }
692
+
621
693
  /**
622
694
  * Get device details
623
695
  */
@@ -655,12 +727,13 @@ export class VeSyncHumidifier extends VeSyncFan {
655
727
  humidity: result.humidity || 0,
656
728
  mist_level: result.mistLevel || 0,
657
729
  mist_virtual_level: result.virtualLevel || 0,
658
- warm_level: result.warmLevel || 0,
659
730
  water_lacks: result.waterLacks || false,
660
- humidity_high: result.humidityHigh || false,
731
+ water_level: result.waterLevel || 0,
661
732
  water_tank_lifted: result.waterTankLifted || false,
733
+ humidity_high: result.humidityHigh || false,
662
734
  display: result.display || false,
663
735
  automatic_stop: result.automaticStop || false,
736
+ oscillation_enabled: result.oscillationEnabled || false,
664
737
  configuration: result.configuration || {},
665
738
  connection_status: result.connectionStatus || null
666
739
  };
@@ -669,6 +742,37 @@ export class VeSyncHumidifier extends VeSyncFan {
669
742
  return success;
670
743
  }
671
744
 
745
+ /**
746
+ * Display device info
747
+ */
748
+ override display(): void {
749
+ super.display();
750
+ const info = [
751
+ ['Current State: ', this.currentState],
752
+ ['Water Level: ', this.waterLevel, '%'],
753
+ ['Water Tank: ', this.waterTankLifted ? 'Lifted' : 'Seated'],
754
+ ['Oscillation: ', this.oscillationEnabled ? 'On' : 'Off']
755
+ ];
756
+
757
+ for (const [key, value, unit = ''] of info) {
758
+ logger.info(`${key.toString().padEnd(30, '.')} ${value}${unit}`);
759
+ }
760
+ }
761
+
762
+ /**
763
+ * Return JSON details
764
+ */
765
+ override displayJSON(): string {
766
+ const baseInfo = JSON.parse(super.displayJSON());
767
+ return JSON.stringify({
768
+ ...baseInfo,
769
+ 'Current State': this.currentState,
770
+ 'Water Level': this.waterLevel,
771
+ 'Water Tank': this.waterTankLifted ? 'Lifted' : 'Seated',
772
+ 'Oscillation': this.oscillationEnabled ? 'On' : 'Off'
773
+ }, null, 4);
774
+ }
775
+
672
776
  /**
673
777
  * Turn device on
674
778
  */
@@ -740,9 +844,9 @@ export class VeSyncHumidifier extends VeSyncFan {
740
844
  */
741
845
  async setMistLevel(level: number): Promise<boolean> {
742
846
  if (!this.mistLevels.includes(level)) {
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);
847
+ logger.debug(`Invalid mist level: ${level} for device: ${this.deviceName}`);
848
+ logger.debug(`Valid levels for ${this.deviceType}: ${this.mistLevels.join(', ')}`);
849
+ return false;
746
850
  }
747
851
 
748
852
  logger.info(`Setting mist level to ${level} for device: ${this.deviceName}`);
@@ -755,9 +859,9 @@ export class VeSyncHumidifier extends VeSyncFan {
755
859
  configModule: this.configModule,
756
860
  payload: {
757
861
  data: {
758
- id: 0,
759
- level: level,
760
- type: 'mist'
862
+ levelIdx: 0,
863
+ virtualLevel: level,
864
+ levelType: 'mist'
761
865
  },
762
866
  method: 'setVirtualLevel',
763
867
  source: 'APP'
@@ -768,7 +872,7 @@ export class VeSyncHumidifier extends VeSyncFan {
768
872
 
769
873
  const success = this.checkResponse([response, status], 'setMistLevel');
770
874
  if (!success) {
771
- logger.error(`Failed to set mist level to ${level} for device: ${this.deviceName}`);
875
+ logger.debug('Error setting mist level');
772
876
  }
773
877
  return success;
774
878
  }
@@ -785,10 +889,11 @@ export class VeSyncHumidifier extends VeSyncFan {
785
889
  * Set device mode
786
890
  */
787
891
  async setMode(mode: string): Promise<boolean> {
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);
892
+ const modeStr = mode.toLowerCase();
893
+ if (!this.modes.includes(modeStr as any)) {
894
+ logger.debug(`Invalid humidity mode used - ${mode}`);
895
+ logger.debug(`Proper modes for this device are - ${this.modes.join(', ')}`);
896
+ return false;
792
897
  }
793
898
 
794
899
  logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
@@ -801,7 +906,7 @@ export class VeSyncHumidifier extends VeSyncFan {
801
906
  configModule: this.configModule,
802
907
  payload: {
803
908
  data: {
804
- mode
909
+ workMode: this.deviceType.startsWith('Superior') && modeStr === 'auto' ? 'autoPro' : modeStr
805
910
  },
806
911
  method: 'setHumidifierMode',
807
912
  source: 'APP'
@@ -812,7 +917,7 @@ export class VeSyncHumidifier extends VeSyncFan {
812
917
 
813
918
  const success = this.checkResponse([response, status], 'setMode');
814
919
  if (!success) {
815
- logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
920
+ logger.debug('Error setting humidity mode');
816
921
  }
817
922
  return success;
818
923
  }
@@ -1117,10 +1222,11 @@ export class VeSyncWarmHumidifier extends VeSyncHumidifier {
1117
1222
  * Set device mode
1118
1223
  */
1119
1224
  async setMode(mode: string): Promise<boolean> {
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);
1225
+ const modeStr = mode.toLowerCase();
1226
+ if (!this.modes.includes(modeStr as any)) {
1227
+ logger.debug(`Invalid humidity mode used - ${mode}`);
1228
+ logger.debug(`Proper modes for this device are - ${this.modes.join(', ')}`);
1229
+ return false;
1124
1230
  }
1125
1231
 
1126
1232
  logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
@@ -1133,7 +1239,7 @@ export class VeSyncWarmHumidifier extends VeSyncHumidifier {
1133
1239
  configModule: this.configModule,
1134
1240
  payload: {
1135
1241
  data: {
1136
- mode
1242
+ workMode: this.deviceType.startsWith('Superior') && modeStr === 'auto' ? 'autoPro' : modeStr
1137
1243
  },
1138
1244
  method: 'setHumidifierMode',
1139
1245
  source: 'APP'
@@ -1143,10 +1249,8 @@ export class VeSyncWarmHumidifier extends VeSyncHumidifier {
1143
1249
  );
1144
1250
 
1145
1251
  const success = this.checkResponse([response, status], 'setMode');
1146
- if (success) {
1147
- this.details.mode = mode;
1148
- } else {
1149
- logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
1252
+ if (!success) {
1253
+ logger.debug('Error setting humidity mode');
1150
1254
  }
1151
1255
  return success;
1152
1256
  }
@@ -1156,15 +1260,14 @@ export class VeSyncWarmHumidifier extends VeSyncHumidifier {
1156
1260
  */
1157
1261
  async setWarmLevel(level: number): Promise<boolean> {
1158
1262
  if (!this.hasFeature('warm')) {
1159
- const error = 'Warm mist control not supported';
1160
- logger.error(`${error} for device: ${this.deviceName}`);
1161
- throw new Error(error);
1263
+ logger.debug('Warm mist control not supported');
1264
+ return false;
1162
1265
  }
1163
1266
 
1164
1267
  if (!this.warmLevels.includes(level)) {
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);
1268
+ logger.debug(`Invalid warm level: ${level} for device: ${this.deviceName}`);
1269
+ logger.debug(`Valid levels for ${this.deviceType}: ${this.warmLevels.join(', ')}`);
1270
+ return false;
1168
1271
  }
1169
1272
 
1170
1273
  logger.debug(`Setting warm level to ${level} for device: ${this.deviceName}`);
@@ -1330,6 +1433,7 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
1330
1433
  const body = {
1331
1434
  ...Helpers.reqBody(this.manager, 'bypassV2'),
1332
1435
  cid: this.cid,
1436
+ deviceId: this.cid, // Add deviceId to match YAML spec
1333
1437
  configModule: this.configModule,
1334
1438
  payload: {
1335
1439
  method,
@@ -1850,6 +1954,7 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
1850
1954
  const body = {
1851
1955
  ...Helpers.reqBody(this.manager, 'bypassV2'),
1852
1956
  cid: this.cid,
1957
+ deviceId: this.cid, // Add deviceId to match YAML spec
1853
1958
  configModule: this.configModule,
1854
1959
  payload: {
1855
1960
  method,