tsvesync 1.0.49 → 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.
- package/dist/lib/vesyncFan.d.ts +20 -3
- package/dist/lib/vesyncFan.js +129 -67
- package/dist/lib/vesyncFanImpl.d.ts +29 -2
- package/dist/lib/vesyncFanImpl.js +179 -88
- package/package.json +1 -1
- package/src/lib/vesyncFan.ts +149 -68
- package/src/lib/vesyncFanImpl.ts +187 -85
package/src/lib/vesyncFanImpl.ts
CHANGED
|
@@ -12,7 +12,6 @@ import { logger } from './logger';
|
|
|
12
12
|
*/
|
|
13
13
|
export class VeSyncAirBypass extends VeSyncFan {
|
|
14
14
|
protected readonly modes = ['auto', 'manual', 'sleep'] as const;
|
|
15
|
-
protected readonly speeds = [1, 2, 3, 4, 5];
|
|
16
15
|
protected readonly displayModes = ['on', 'off'] as const;
|
|
17
16
|
protected readonly childLockModes = ['on', 'off'] as const;
|
|
18
17
|
|
|
@@ -29,6 +28,7 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
29
28
|
const body = {
|
|
30
29
|
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
31
30
|
cid: this.cid,
|
|
31
|
+
deviceId: this.cid, // Add deviceId to match YAML spec
|
|
32
32
|
configModule: this.configModule,
|
|
33
33
|
payload: {
|
|
34
34
|
method,
|
|
@@ -258,10 +258,10 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
258
258
|
* Change fan speed
|
|
259
259
|
*/
|
|
260
260
|
async changeFanSpeed(speed: number): Promise<boolean> {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
logger.error(
|
|
264
|
-
|
|
261
|
+
const speeds = this.config.levels ?? [];
|
|
262
|
+
if (!speeds.includes(speed)) {
|
|
263
|
+
logger.error(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')} for device: ${this.deviceName}`);
|
|
264
|
+
return false;
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
logger.info(`Changing fan speed to ${speed} for device: ${this.deviceName}`);
|
|
@@ -297,10 +297,11 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
297
297
|
* Set device mode
|
|
298
298
|
*/
|
|
299
299
|
async setMode(mode: string): Promise<boolean> {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
logger.
|
|
303
|
-
|
|
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;
|
|
304
305
|
}
|
|
305
306
|
|
|
306
307
|
logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
|
|
@@ -313,9 +314,9 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
313
314
|
configModule: this.configModule,
|
|
314
315
|
payload: {
|
|
315
316
|
data: {
|
|
316
|
-
|
|
317
|
+
workMode: this.deviceType.startsWith('Superior') && modeStr === 'auto' ? 'autoPro' : modeStr
|
|
317
318
|
},
|
|
318
|
-
method: '
|
|
319
|
+
method: 'setHumidifierMode',
|
|
319
320
|
source: 'APP'
|
|
320
321
|
}
|
|
321
322
|
},
|
|
@@ -324,7 +325,7 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
324
325
|
|
|
325
326
|
const success = this.checkResponse([response, status], 'setMode');
|
|
326
327
|
if (!success) {
|
|
327
|
-
logger.
|
|
328
|
+
logger.debug('Error setting humidity mode');
|
|
328
329
|
}
|
|
329
330
|
return success;
|
|
330
331
|
}
|
|
@@ -601,6 +602,7 @@ export class VeSyncHumidifier extends VeSyncFan {
|
|
|
601
602
|
protected readonly mistLevels: number[];
|
|
602
603
|
protected readonly displayModes = ['on', 'off'] as const;
|
|
603
604
|
protected readonly humidityRange = { min: 30, max: 80 };
|
|
605
|
+
protected readonly states = ['inactive', 'idle', 'humidifying'] as const;
|
|
604
606
|
|
|
605
607
|
constructor(details: Record<string, any>, manager: VeSync) {
|
|
606
608
|
super(details, manager);
|
|
@@ -619,6 +621,75 @@ export class VeSyncHumidifier extends VeSyncFan {
|
|
|
619
621
|
logger.debug(`Initialized VeSyncHumidifier device: ${this.deviceName}`);
|
|
620
622
|
}
|
|
621
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
|
+
|
|
622
693
|
/**
|
|
623
694
|
* Get device details
|
|
624
695
|
*/
|
|
@@ -656,12 +727,13 @@ export class VeSyncHumidifier extends VeSyncFan {
|
|
|
656
727
|
humidity: result.humidity || 0,
|
|
657
728
|
mist_level: result.mistLevel || 0,
|
|
658
729
|
mist_virtual_level: result.virtualLevel || 0,
|
|
659
|
-
warm_level: result.warmLevel || 0,
|
|
660
730
|
water_lacks: result.waterLacks || false,
|
|
661
|
-
|
|
731
|
+
water_level: result.waterLevel || 0,
|
|
662
732
|
water_tank_lifted: result.waterTankLifted || false,
|
|
733
|
+
humidity_high: result.humidityHigh || false,
|
|
663
734
|
display: result.display || false,
|
|
664
735
|
automatic_stop: result.automaticStop || false,
|
|
736
|
+
oscillation_enabled: result.oscillationEnabled || false,
|
|
665
737
|
configuration: result.configuration || {},
|
|
666
738
|
connection_status: result.connectionStatus || null
|
|
667
739
|
};
|
|
@@ -670,6 +742,37 @@ export class VeSyncHumidifier extends VeSyncFan {
|
|
|
670
742
|
return success;
|
|
671
743
|
}
|
|
672
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
|
+
|
|
673
776
|
/**
|
|
674
777
|
* Turn device on
|
|
675
778
|
*/
|
|
@@ -741,9 +844,9 @@ export class VeSyncHumidifier extends VeSyncFan {
|
|
|
741
844
|
*/
|
|
742
845
|
async setMistLevel(level: number): Promise<boolean> {
|
|
743
846
|
if (!this.mistLevels.includes(level)) {
|
|
744
|
-
|
|
745
|
-
logger.
|
|
746
|
-
|
|
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;
|
|
747
850
|
}
|
|
748
851
|
|
|
749
852
|
logger.info(`Setting mist level to ${level} for device: ${this.deviceName}`);
|
|
@@ -756,9 +859,9 @@ export class VeSyncHumidifier extends VeSyncFan {
|
|
|
756
859
|
configModule: this.configModule,
|
|
757
860
|
payload: {
|
|
758
861
|
data: {
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
862
|
+
levelIdx: 0,
|
|
863
|
+
virtualLevel: level,
|
|
864
|
+
levelType: 'mist'
|
|
762
865
|
},
|
|
763
866
|
method: 'setVirtualLevel',
|
|
764
867
|
source: 'APP'
|
|
@@ -769,7 +872,7 @@ export class VeSyncHumidifier extends VeSyncFan {
|
|
|
769
872
|
|
|
770
873
|
const success = this.checkResponse([response, status], 'setMistLevel');
|
|
771
874
|
if (!success) {
|
|
772
|
-
logger.
|
|
875
|
+
logger.debug('Error setting mist level');
|
|
773
876
|
}
|
|
774
877
|
return success;
|
|
775
878
|
}
|
|
@@ -786,10 +889,11 @@ export class VeSyncHumidifier extends VeSyncFan {
|
|
|
786
889
|
* Set device mode
|
|
787
890
|
*/
|
|
788
891
|
async setMode(mode: string): Promise<boolean> {
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
logger.
|
|
792
|
-
|
|
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;
|
|
793
897
|
}
|
|
794
898
|
|
|
795
899
|
logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
|
|
@@ -802,7 +906,7 @@ export class VeSyncHumidifier extends VeSyncFan {
|
|
|
802
906
|
configModule: this.configModule,
|
|
803
907
|
payload: {
|
|
804
908
|
data: {
|
|
805
|
-
|
|
909
|
+
workMode: this.deviceType.startsWith('Superior') && modeStr === 'auto' ? 'autoPro' : modeStr
|
|
806
910
|
},
|
|
807
911
|
method: 'setHumidifierMode',
|
|
808
912
|
source: 'APP'
|
|
@@ -813,7 +917,7 @@ export class VeSyncHumidifier extends VeSyncFan {
|
|
|
813
917
|
|
|
814
918
|
const success = this.checkResponse([response, status], 'setMode');
|
|
815
919
|
if (!success) {
|
|
816
|
-
logger.
|
|
920
|
+
logger.debug('Error setting humidity mode');
|
|
817
921
|
}
|
|
818
922
|
return success;
|
|
819
923
|
}
|
|
@@ -1096,7 +1200,7 @@ export class VeSyncWarmHumidifier extends VeSyncHumidifier {
|
|
|
1096
1200
|
// Add warm humidifier specific fields
|
|
1097
1201
|
this.details = {
|
|
1098
1202
|
...this.details,
|
|
1099
|
-
warm_enabled: this.details.warm_level > 0,
|
|
1203
|
+
warm_enabled: Boolean(this.details.warm_level && this.details.warm_level > 0),
|
|
1100
1204
|
drying_mode_enabled: this.details.autoDryingSwitch === 1,
|
|
1101
1205
|
drying_mode_state: this.details.dryingMode || '',
|
|
1102
1206
|
drying_mode_level: this.details.dryingLevel || 0,
|
|
@@ -1118,10 +1222,11 @@ export class VeSyncWarmHumidifier extends VeSyncHumidifier {
|
|
|
1118
1222
|
* Set device mode
|
|
1119
1223
|
*/
|
|
1120
1224
|
async setMode(mode: string): Promise<boolean> {
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
logger.
|
|
1124
|
-
|
|
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;
|
|
1125
1230
|
}
|
|
1126
1231
|
|
|
1127
1232
|
logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
|
|
@@ -1134,7 +1239,7 @@ export class VeSyncWarmHumidifier extends VeSyncHumidifier {
|
|
|
1134
1239
|
configModule: this.configModule,
|
|
1135
1240
|
payload: {
|
|
1136
1241
|
data: {
|
|
1137
|
-
|
|
1242
|
+
workMode: this.deviceType.startsWith('Superior') && modeStr === 'auto' ? 'autoPro' : modeStr
|
|
1138
1243
|
},
|
|
1139
1244
|
method: 'setHumidifierMode',
|
|
1140
1245
|
source: 'APP'
|
|
@@ -1144,10 +1249,8 @@ export class VeSyncWarmHumidifier extends VeSyncHumidifier {
|
|
|
1144
1249
|
);
|
|
1145
1250
|
|
|
1146
1251
|
const success = this.checkResponse([response, status], 'setMode');
|
|
1147
|
-
if (success) {
|
|
1148
|
-
|
|
1149
|
-
} else {
|
|
1150
|
-
logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
|
|
1252
|
+
if (!success) {
|
|
1253
|
+
logger.debug('Error setting humidity mode');
|
|
1151
1254
|
}
|
|
1152
1255
|
return success;
|
|
1153
1256
|
}
|
|
@@ -1157,15 +1260,14 @@ export class VeSyncWarmHumidifier extends VeSyncHumidifier {
|
|
|
1157
1260
|
*/
|
|
1158
1261
|
async setWarmLevel(level: number): Promise<boolean> {
|
|
1159
1262
|
if (!this.hasFeature('warm')) {
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
throw new Error(error);
|
|
1263
|
+
logger.debug('Warm mist control not supported');
|
|
1264
|
+
return false;
|
|
1163
1265
|
}
|
|
1164
1266
|
|
|
1165
1267
|
if (!this.warmLevels.includes(level)) {
|
|
1166
|
-
|
|
1167
|
-
logger.
|
|
1168
|
-
|
|
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;
|
|
1169
1271
|
}
|
|
1170
1272
|
|
|
1171
1273
|
logger.debug(`Setting warm level to ${level} for device: ${this.deviceName}`);
|
|
@@ -1292,7 +1394,10 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
1292
1394
|
|
|
1293
1395
|
protected buildConfigDict(configDict: Record<string, any>): void {
|
|
1294
1396
|
if (configDict) {
|
|
1295
|
-
this.config =
|
|
1397
|
+
this.config = {
|
|
1398
|
+
...this.config, // Preserve existing config
|
|
1399
|
+
...configDict // Merge in new config
|
|
1400
|
+
};
|
|
1296
1401
|
}
|
|
1297
1402
|
}
|
|
1298
1403
|
|
|
@@ -1328,6 +1433,7 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
1328
1433
|
const body = {
|
|
1329
1434
|
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
1330
1435
|
cid: this.cid,
|
|
1436
|
+
deviceId: this.cid, // Add deviceId to match YAML spec
|
|
1331
1437
|
configModule: this.configModule,
|
|
1332
1438
|
payload: {
|
|
1333
1439
|
method,
|
|
@@ -1467,35 +1573,32 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
1467
1573
|
* Change fan speed
|
|
1468
1574
|
*/
|
|
1469
1575
|
async changeFanSpeed(speed: number): Promise<boolean> {
|
|
1470
|
-
const speeds
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
if (!speeds.includes(speed)) {
|
|
1475
|
-
logger.debug(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')}`);
|
|
1476
|
-
return false;
|
|
1477
|
-
}
|
|
1478
|
-
} else {
|
|
1479
|
-
if (currentSpeed === speeds[speeds.length - 1] || currentSpeed === 0) {
|
|
1480
|
-
speed = speeds[0];
|
|
1481
|
-
} else {
|
|
1482
|
-
const currentIndex = speeds.indexOf(currentSpeed);
|
|
1483
|
-
speed = speeds[currentIndex + 1];
|
|
1484
|
-
}
|
|
1576
|
+
const speeds = this.config.levels ?? [];
|
|
1577
|
+
if (!speeds.includes(speed)) {
|
|
1578
|
+
logger.error(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')} for device: ${this.deviceName}`);
|
|
1579
|
+
return false;
|
|
1485
1580
|
}
|
|
1486
1581
|
|
|
1487
|
-
|
|
1488
|
-
body.payload.data = {
|
|
1489
|
-
levelIdx: 0,
|
|
1490
|
-
manualSpeedLevel: speed,
|
|
1491
|
-
levelType: 'wind'
|
|
1492
|
-
};
|
|
1493
|
-
|
|
1582
|
+
logger.info(`Changing fan speed to ${speed} for device: ${this.deviceName}`);
|
|
1494
1583
|
const [response, status] = await this.callApi(
|
|
1495
1584
|
'/cloud/v2/deviceManaged/bypassV2',
|
|
1496
1585
|
'post',
|
|
1497
|
-
|
|
1498
|
-
|
|
1586
|
+
{
|
|
1587
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
1588
|
+
cid: this.cid,
|
|
1589
|
+
configModule: this.configModule,
|
|
1590
|
+
payload: {
|
|
1591
|
+
data: {
|
|
1592
|
+
id: 0,
|
|
1593
|
+
level: speed,
|
|
1594
|
+
mode: 'manual',
|
|
1595
|
+
type: 'wind'
|
|
1596
|
+
},
|
|
1597
|
+
method: 'setLevel',
|
|
1598
|
+
source: 'APP'
|
|
1599
|
+
}
|
|
1600
|
+
},
|
|
1601
|
+
Helpers.reqHeaderBypass()
|
|
1499
1602
|
);
|
|
1500
1603
|
|
|
1501
1604
|
const success = this.checkResponse([response, status], 'changeFanSpeed');
|
|
@@ -1757,13 +1860,14 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
1757
1860
|
const details: Record<string, string> = {
|
|
1758
1861
|
...baseInfo,
|
|
1759
1862
|
'Mode': this.mode,
|
|
1760
|
-
'Filter Life': this.details.filter_life.toString(),
|
|
1863
|
+
'Filter Life': (this.details.filter_life ?? 0).toString(),
|
|
1761
1864
|
'Fan Level': this.speed.toString(),
|
|
1762
|
-
'Display On': this.details.display
|
|
1763
|
-
'Child Lock': this.details.child_lock.toString(),
|
|
1764
|
-
'
|
|
1765
|
-
'
|
|
1766
|
-
'
|
|
1865
|
+
'Display On': this.details.display?.toString() ?? 'false',
|
|
1866
|
+
'Child Lock': (this.details.child_lock ?? false).toString(),
|
|
1867
|
+
'Night Light': (this.details.night_light ?? '').toString(),
|
|
1868
|
+
'Display Set On': (this.details.screen_switch ?? false).toString(),
|
|
1869
|
+
'Light Detection Enabled': (this.details.light_detection_switch ?? false).toString(),
|
|
1870
|
+
'Environment Light State': (this.details.environment_light_state ?? false).toString()
|
|
1767
1871
|
};
|
|
1768
1872
|
|
|
1769
1873
|
if (this.hasFeature('air_quality')) {
|
|
@@ -1780,7 +1884,7 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
1780
1884
|
|
|
1781
1885
|
for (const [key, value] of Object.entries(everestKeys)) {
|
|
1782
1886
|
if (key in this.details) {
|
|
1783
|
-
details[value] = this.details[key]
|
|
1887
|
+
details[value] = this.details[key]?.toString() ?? '';
|
|
1784
1888
|
}
|
|
1785
1889
|
}
|
|
1786
1890
|
|
|
@@ -1820,7 +1924,6 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
1820
1924
|
*/
|
|
1821
1925
|
export class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
1822
1926
|
protected readonly towerModes = ['normal', 'advancedSleep', 'off'] as const;
|
|
1823
|
-
protected readonly speeds = Array.from({length: 12}, (_, i) => i + 1);
|
|
1824
1927
|
|
|
1825
1928
|
constructor(details: Record<string, any>, manager: VeSync) {
|
|
1826
1929
|
super(details, manager);
|
|
@@ -1851,6 +1954,7 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1851
1954
|
const body = {
|
|
1852
1955
|
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
1853
1956
|
cid: this.cid,
|
|
1957
|
+
deviceId: this.cid, // Add deviceId to match YAML spec
|
|
1854
1958
|
configModule: this.configModule,
|
|
1855
1959
|
payload: {
|
|
1856
1960
|
method,
|
|
@@ -1899,8 +2003,6 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1899
2003
|
screenSwitch: deviceData.screenSwitch,
|
|
1900
2004
|
oscillationState: deviceData.oscillationState,
|
|
1901
2005
|
oscillationSwitch: deviceData.oscillationSwitch,
|
|
1902
|
-
muteState: deviceData.muteState,
|
|
1903
|
-
muteSwitch: deviceData.muteSwitch,
|
|
1904
2006
|
timerRemain: deviceData.timerRemain,
|
|
1905
2007
|
temperature: deviceData.temperature || 0,
|
|
1906
2008
|
humidity: deviceData.humidity || 0,
|
|
@@ -1966,13 +2068,12 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1966
2068
|
* Set tower fan mode
|
|
1967
2069
|
*/
|
|
1968
2070
|
async mode_toggle(mode: string): Promise<boolean> {
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
logger.debug(`Invalid tower fan mode used - ${mode}`);
|
|
2071
|
+
if (!this.towerModes.includes(mode as any)) {
|
|
2072
|
+
logger.debug(`Invalid mode: ${mode}. Must be one of: ${this.towerModes.join(', ')}`);
|
|
1972
2073
|
return false;
|
|
1973
2074
|
}
|
|
1974
2075
|
|
|
1975
|
-
if (mode
|
|
2076
|
+
if (mode === 'off') {
|
|
1976
2077
|
return this.turnOff();
|
|
1977
2078
|
}
|
|
1978
2079
|
|
|
@@ -1993,7 +2094,7 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1993
2094
|
if (success) {
|
|
1994
2095
|
this.details.workMode = mode;
|
|
1995
2096
|
} else {
|
|
1996
|
-
logger.
|
|
2097
|
+
logger.error(`Failed to set ${mode} mode for device: ${this.deviceName}`);
|
|
1997
2098
|
}
|
|
1998
2099
|
return success;
|
|
1999
2100
|
}
|
|
@@ -2002,8 +2103,9 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
2002
2103
|
* Change fan speed
|
|
2003
2104
|
*/
|
|
2004
2105
|
async changeFanSpeed(speed: number): Promise<boolean> {
|
|
2005
|
-
|
|
2006
|
-
|
|
2106
|
+
const speeds = this.config.levels ?? [];
|
|
2107
|
+
if (!speeds.includes(speed)) {
|
|
2108
|
+
logger.debug(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')}`);
|
|
2007
2109
|
return false;
|
|
2008
2110
|
}
|
|
2009
2111
|
|