tsvesync 1.0.43 → 1.0.44
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 +13 -2
- package/dist/lib/vesyncFan.js +48 -33
- package/dist/lib/vesyncFanImpl.d.ts +99 -14
- package/dist/lib/vesyncFanImpl.js +408 -69
- package/package.json +1 -1
- package/src/lib/vesyncFan.ts +49 -34
- package/src/lib/vesyncFanImpl.ts +491 -70
package/src/lib/vesyncFanImpl.ts
CHANGED
|
@@ -21,6 +21,24 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
21
21
|
logger.debug(`Initialized VeSyncAirBypass device: ${this.deviceName}`);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Build API dictionary
|
|
26
|
+
*/
|
|
27
|
+
protected buildApiDict(method: string): [Record<string, any>, Record<string, any>] {
|
|
28
|
+
const head = Helpers.reqHeaderBypass();
|
|
29
|
+
const body = {
|
|
30
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
31
|
+
cid: this.cid,
|
|
32
|
+
configModule: this.configModule,
|
|
33
|
+
payload: {
|
|
34
|
+
method,
|
|
35
|
+
source: 'APP',
|
|
36
|
+
data: {}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
return [head, body];
|
|
40
|
+
}
|
|
41
|
+
|
|
24
42
|
/**
|
|
25
43
|
* Get device details
|
|
26
44
|
*/
|
|
@@ -1260,12 +1278,48 @@ export class VeSyncWarmHumidifier extends VeSyncHumidifier {
|
|
|
1260
1278
|
export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
1261
1279
|
protected _lightDetection: boolean = false;
|
|
1262
1280
|
protected _lightDetectionState: boolean = false;
|
|
1281
|
+
protected setSpeedLevel: number | null = null;
|
|
1282
|
+
protected autoPreferences: string[] = ['default', 'efficient', 'quiet'];
|
|
1283
|
+
protected enabled: boolean = false;
|
|
1284
|
+
protected _mode: string = '';
|
|
1285
|
+
protected _speed: number = 0;
|
|
1286
|
+
protected _timer: { duration: number; action: string } | null = null;
|
|
1263
1287
|
|
|
1264
1288
|
constructor(details: Record<string, any>, manager: VeSync) {
|
|
1265
1289
|
super(details, manager);
|
|
1266
1290
|
logger.debug(`Initialized VeSyncAirBaseV2 device: ${this.deviceName}`);
|
|
1267
1291
|
}
|
|
1268
1292
|
|
|
1293
|
+
protected buildConfigDict(configDict: Record<string, any>): void {
|
|
1294
|
+
if (configDict) {
|
|
1295
|
+
this.config = configDict;
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
get mode(): string {
|
|
1300
|
+
return this._mode;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
set mode(value: string) {
|
|
1304
|
+
this._mode = value;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
get speed(): number {
|
|
1308
|
+
return this._speed;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
set speed(value: number) {
|
|
1312
|
+
this._speed = value;
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
get timer(): { duration: number; action: string } | null {
|
|
1316
|
+
return this._timer;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
set timer(value: { duration: number; action: string } | null) {
|
|
1320
|
+
this._timer = value;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1269
1323
|
/**
|
|
1270
1324
|
* Build API dictionary
|
|
1271
1325
|
*/
|
|
@@ -1273,7 +1327,7 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
1273
1327
|
const head = Helpers.reqHeaderBypass();
|
|
1274
1328
|
const body = {
|
|
1275
1329
|
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
1276
|
-
|
|
1330
|
+
cid: this.cid,
|
|
1277
1331
|
configModule: this.configModule,
|
|
1278
1332
|
payload: {
|
|
1279
1333
|
method,
|
|
@@ -1284,25 +1338,100 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
1284
1338
|
return [head, body];
|
|
1285
1339
|
}
|
|
1286
1340
|
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1341
|
+
/**
|
|
1342
|
+
* Get device details
|
|
1343
|
+
*/
|
|
1344
|
+
async getDetails(): Promise<Boolean> {
|
|
1345
|
+
logger.debug(`Getting details for device: ${this.deviceName}`);
|
|
1346
|
+
const [head, body] = this.buildApiDict('getPurifierStatus');
|
|
1290
1347
|
|
|
1291
|
-
|
|
1292
|
-
|
|
1348
|
+
const [response, status] = await this.callApi(
|
|
1349
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
1350
|
+
'post',
|
|
1351
|
+
body,
|
|
1352
|
+
head
|
|
1353
|
+
);
|
|
1354
|
+
|
|
1355
|
+
if (!this.checkResponse([response, status], 'getDetails') || !response?.result) {
|
|
1356
|
+
logger.debug('Error getting purifier details');
|
|
1357
|
+
this.connectionStatus = 'offline';
|
|
1358
|
+
return false;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
const innerResponse = response.result;
|
|
1362
|
+
if (innerResponse.code !== 0 || !innerResponse.result) {
|
|
1363
|
+
logger.debug('Error in inner response from purifier');
|
|
1364
|
+
this.connectionStatus = 'offline';
|
|
1365
|
+
return false;
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
const deviceData = innerResponse.result;
|
|
1369
|
+
this.buildPurifierDict(deviceData);
|
|
1370
|
+
if (deviceData.configuration) {
|
|
1371
|
+
this.buildConfigDict(deviceData.configuration);
|
|
1372
|
+
}
|
|
1373
|
+
return true;
|
|
1293
1374
|
}
|
|
1294
1375
|
|
|
1295
|
-
|
|
1296
|
-
|
|
1376
|
+
/**
|
|
1377
|
+
* Build purifier dictionary
|
|
1378
|
+
*/
|
|
1379
|
+
protected buildPurifierDict(devDict: Record<string, any>): void {
|
|
1380
|
+
this.connectionStatus = 'online';
|
|
1381
|
+
const powerSwitch = Boolean(devDict.powerSwitch ?? 0);
|
|
1382
|
+
this.enabled = powerSwitch;
|
|
1383
|
+
this.deviceStatus = powerSwitch ? 'on' : 'off';
|
|
1384
|
+
this.mode = devDict.workMode ?? 'manual';
|
|
1385
|
+
|
|
1386
|
+
this.speed = devDict.fanSpeedLevel ?? 0;
|
|
1387
|
+
this.setSpeedLevel = devDict.manualSpeedLevel ?? 1;
|
|
1388
|
+
|
|
1389
|
+
this.details = {
|
|
1390
|
+
...this.details,
|
|
1391
|
+
filter_life: devDict.filterLifePercent ?? 0,
|
|
1392
|
+
child_lock: Boolean(devDict.childLockSwitch ?? 0),
|
|
1393
|
+
display: Boolean(devDict.screenState ?? 0),
|
|
1394
|
+
light_detection_switch: Boolean(devDict.lightDetectionSwitch ?? 0),
|
|
1395
|
+
environment_light_state: Boolean(devDict.environmentLightState ?? 0),
|
|
1396
|
+
screen_switch: Boolean(devDict.screenSwitch ?? 0)
|
|
1397
|
+
};
|
|
1398
|
+
|
|
1399
|
+
if (this.hasFeature('air_quality')) {
|
|
1400
|
+
this.details.air_quality_value = devDict.PM25 ?? 0;
|
|
1401
|
+
this.details.air_quality = devDict.AQLevel ?? 0;
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
if ('PM1' in devDict) this.details.pm1 = devDict.PM1;
|
|
1405
|
+
if ('PM10' in devDict) this.details.pm10 = devDict.PM10;
|
|
1406
|
+
if ('AQPercent' in devDict) this.details.aq_percent = devDict.AQPercent;
|
|
1407
|
+
if ('fanRotateAngle' in devDict) this.details.fan_rotate_angle = devDict.fanRotateAngle;
|
|
1408
|
+
if ('filterOpenState' in devDict) this.details.filter_open_state = Boolean(devDict.filterOpenState);
|
|
1409
|
+
|
|
1410
|
+
if ((devDict.timerRemain ?? 0) > 0) {
|
|
1411
|
+
this.timer = { duration: devDict.timerRemain, action: 'off' };
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
if (typeof devDict.autoPreference === 'object' && devDict.autoPreference) {
|
|
1415
|
+
this.details.auto_preference_type = devDict.autoPreference?.autoPreferenceType ?? 'default';
|
|
1416
|
+
} else {
|
|
1417
|
+
this.details.auto_preference_type = null;
|
|
1418
|
+
}
|
|
1297
1419
|
}
|
|
1298
1420
|
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1421
|
+
/**
|
|
1422
|
+
* Toggle device power
|
|
1423
|
+
*/
|
|
1424
|
+
async toggleSwitch(toggle: boolean): Promise<boolean> {
|
|
1425
|
+
if (typeof toggle !== 'boolean') {
|
|
1426
|
+
logger.debug('Invalid toggle value for purifier switch');
|
|
1302
1427
|
return false;
|
|
1303
1428
|
}
|
|
1304
1429
|
|
|
1305
|
-
body
|
|
1430
|
+
const [head, body] = this.buildApiDict('setSwitch');
|
|
1431
|
+
body.payload.data = {
|
|
1432
|
+
powerSwitch: toggle ? 1 : 0,
|
|
1433
|
+
switchIdx: 0
|
|
1434
|
+
};
|
|
1306
1435
|
|
|
1307
1436
|
const [response, status] = await this.callApi(
|
|
1308
1437
|
'/cloud/v2/deviceManaged/bypassV2',
|
|
@@ -1311,55 +1440,255 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
1311
1440
|
head
|
|
1312
1441
|
);
|
|
1313
1442
|
|
|
1314
|
-
const success = this.checkResponse([response, status], '
|
|
1443
|
+
const success = this.checkResponse([response, status], 'toggleSwitch');
|
|
1315
1444
|
if (success) {
|
|
1316
|
-
this.
|
|
1445
|
+
this.deviceStatus = toggle ? 'on' : 'off';
|
|
1317
1446
|
}
|
|
1318
1447
|
return success;
|
|
1319
1448
|
}
|
|
1320
1449
|
|
|
1321
|
-
|
|
1322
|
-
|
|
1450
|
+
/**
|
|
1451
|
+
* Turn device on - compatibility method that proxies to toggleSwitch
|
|
1452
|
+
*/
|
|
1453
|
+
async turnOn(): Promise<boolean> {
|
|
1454
|
+
logger.info(`Turning on device: ${this.deviceName}`);
|
|
1455
|
+
return this.toggleSwitch(true);
|
|
1323
1456
|
}
|
|
1324
1457
|
|
|
1325
|
-
|
|
1326
|
-
|
|
1458
|
+
/**
|
|
1459
|
+
* Turn device off - compatibility method that proxies to toggleSwitch
|
|
1460
|
+
*/
|
|
1461
|
+
async turnOff(): Promise<boolean> {
|
|
1462
|
+
logger.info(`Turning off device: ${this.deviceName}`);
|
|
1463
|
+
return this.toggleSwitch(false);
|
|
1327
1464
|
}
|
|
1328
1465
|
|
|
1329
|
-
|
|
1330
|
-
|
|
1466
|
+
/**
|
|
1467
|
+
* Change fan speed
|
|
1468
|
+
*/
|
|
1469
|
+
async changeFanSpeed(speed: number): Promise<boolean> {
|
|
1470
|
+
const speeds: number[] = this.config?.levels ?? [];
|
|
1471
|
+
const currentSpeed = this.setSpeedLevel ?? 0;
|
|
1472
|
+
|
|
1473
|
+
if (speed !== undefined) {
|
|
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
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
const [head, body] = this.buildApiDict('setLevel');
|
|
1488
|
+
body.payload.data = {
|
|
1489
|
+
levelIdx: 0,
|
|
1490
|
+
manualSpeedLevel: speed,
|
|
1491
|
+
levelType: 'wind'
|
|
1492
|
+
};
|
|
1493
|
+
|
|
1494
|
+
const [response, status] = await this.callApi(
|
|
1495
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
1496
|
+
'post',
|
|
1497
|
+
body,
|
|
1498
|
+
head
|
|
1499
|
+
);
|
|
1500
|
+
|
|
1501
|
+
const success = this.checkResponse([response, status], 'changeFanSpeed');
|
|
1502
|
+
if (success) {
|
|
1503
|
+
this.setSpeedLevel = speed;
|
|
1504
|
+
this.mode = 'manual';
|
|
1505
|
+
}
|
|
1506
|
+
return success;
|
|
1331
1507
|
}
|
|
1332
1508
|
|
|
1333
|
-
|
|
1334
|
-
|
|
1509
|
+
/**
|
|
1510
|
+
* Set mode
|
|
1511
|
+
*/
|
|
1512
|
+
async setMode(mode: string): Promise<boolean> {
|
|
1513
|
+
if (!this.modes.includes(mode as any)) {
|
|
1514
|
+
logger.debug(`Invalid mode: ${mode}. Must be one of: ${this.modes.join(', ')}`);
|
|
1515
|
+
return false;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
if (mode === 'manual') {
|
|
1519
|
+
if (!this.speed || this.speed === 0) {
|
|
1520
|
+
return this.changeFanSpeed(1);
|
|
1521
|
+
}
|
|
1522
|
+
return this.changeFanSpeed(this.speed);
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
if (mode === 'off') {
|
|
1526
|
+
return this.turnOff();
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
const [head, body] = this.buildApiDict('setPurifierMode');
|
|
1530
|
+
body.payload.data = {
|
|
1531
|
+
workMode: mode
|
|
1532
|
+
};
|
|
1533
|
+
|
|
1534
|
+
const [response, status] = await this.callApi(
|
|
1535
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
1536
|
+
'post',
|
|
1537
|
+
body,
|
|
1538
|
+
head
|
|
1539
|
+
);
|
|
1540
|
+
|
|
1541
|
+
const success = this.checkResponse([response, status], 'setMode');
|
|
1542
|
+
if (success) {
|
|
1543
|
+
this.mode = mode;
|
|
1544
|
+
}
|
|
1545
|
+
return success;
|
|
1335
1546
|
}
|
|
1336
1547
|
|
|
1337
1548
|
/**
|
|
1338
|
-
*
|
|
1549
|
+
* Set display status
|
|
1339
1550
|
*/
|
|
1340
|
-
|
|
1341
|
-
if (
|
|
1342
|
-
|
|
1551
|
+
async setDisplay(enabled: boolean): Promise<boolean> {
|
|
1552
|
+
if (!this.hasFeature('display')) {
|
|
1553
|
+
const error = 'Display control not supported';
|
|
1554
|
+
logger.error(`${error} for device: ${this.deviceName}`);
|
|
1555
|
+
throw new Error(error);
|
|
1343
1556
|
}
|
|
1557
|
+
|
|
1558
|
+
const [head, body] = this.buildApiDict('setDisplay');
|
|
1559
|
+
body.payload.data = {
|
|
1560
|
+
screenSwitch: enabled ? 1 : 0
|
|
1561
|
+
};
|
|
1562
|
+
|
|
1563
|
+
const [response, status] = await this.callApi(
|
|
1564
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
1565
|
+
'post',
|
|
1566
|
+
body,
|
|
1567
|
+
head
|
|
1568
|
+
);
|
|
1569
|
+
|
|
1570
|
+
const success = this.checkResponse([response, status], 'setDisplay');
|
|
1571
|
+
if (success) {
|
|
1572
|
+
this.details.screen_switch = enabled;
|
|
1573
|
+
}
|
|
1574
|
+
return success;
|
|
1344
1575
|
}
|
|
1345
1576
|
|
|
1346
1577
|
/**
|
|
1347
|
-
* Set
|
|
1578
|
+
* Set child lock
|
|
1348
1579
|
*/
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
logger.
|
|
1580
|
+
async setChildLock(enabled: boolean): Promise<boolean> {
|
|
1581
|
+
if (!this.hasFeature('child_lock')) {
|
|
1582
|
+
const error = 'Child lock not supported';
|
|
1583
|
+
logger.error(`${error} for device: ${this.deviceName}`);
|
|
1584
|
+
throw new Error(error);
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
const [head, body] = this.buildApiDict('setChildLock');
|
|
1588
|
+
body.payload.data = {
|
|
1589
|
+
childLockSwitch: enabled ? 1 : 0
|
|
1590
|
+
};
|
|
1591
|
+
|
|
1592
|
+
const [response, status] = await this.callApi(
|
|
1593
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
1594
|
+
'post',
|
|
1595
|
+
body,
|
|
1596
|
+
head
|
|
1597
|
+
);
|
|
1598
|
+
|
|
1599
|
+
const success = this.checkResponse([response, status], 'setChildLock');
|
|
1600
|
+
if (success) {
|
|
1601
|
+
this.details.child_lock = enabled;
|
|
1602
|
+
}
|
|
1603
|
+
return success;
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
/**
|
|
1607
|
+
* Set timer
|
|
1608
|
+
*/
|
|
1609
|
+
async setTimer(timerDuration: number, action: 'on' | 'off' = 'off', method: string = 'powerSwitch'): Promise<boolean> {
|
|
1610
|
+
if (!this.hasFeature('timer')) {
|
|
1611
|
+
const error = 'Timer not supported';
|
|
1612
|
+
logger.error(`${error} for device: ${this.deviceName}`);
|
|
1613
|
+
throw new Error(error);
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
if (!['on', 'off'].includes(action)) {
|
|
1617
|
+
logger.debug('Invalid action for timer');
|
|
1618
|
+
return false;
|
|
1619
|
+
}
|
|
1620
|
+
if (method !== 'powerSwitch') {
|
|
1621
|
+
logger.debug('Invalid method for timer');
|
|
1353
1622
|
return false;
|
|
1354
1623
|
}
|
|
1355
1624
|
|
|
1356
|
-
const [head, body] = this.buildApiDict('
|
|
1357
|
-
|
|
1625
|
+
const [head, body] = this.buildApiDict('addTimerV2');
|
|
1626
|
+
body.payload.subDeviceNo = 0;
|
|
1627
|
+
body.payload.data = {
|
|
1628
|
+
startAct: [{
|
|
1629
|
+
type: method,
|
|
1630
|
+
num: 0,
|
|
1631
|
+
act: action === 'on' ? 1 : 0
|
|
1632
|
+
}],
|
|
1633
|
+
total: timerDuration,
|
|
1634
|
+
subDeviceNo: 0
|
|
1635
|
+
};
|
|
1636
|
+
|
|
1637
|
+
const [response, status] = await this.callApi(
|
|
1638
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
1639
|
+
'post',
|
|
1640
|
+
body,
|
|
1641
|
+
head
|
|
1642
|
+
);
|
|
1643
|
+
|
|
1644
|
+
const success = this.checkResponse([response, status], 'setTimer');
|
|
1645
|
+
if (success) {
|
|
1646
|
+
this.timer = { duration: timerDuration, action };
|
|
1647
|
+
}
|
|
1648
|
+
return success;
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
/**
|
|
1652
|
+
* Clear timer
|
|
1653
|
+
*/
|
|
1654
|
+
async clearTimer(): Promise<boolean> {
|
|
1655
|
+
if (!this.hasFeature('timer')) {
|
|
1656
|
+
const error = 'Timer not supported';
|
|
1657
|
+
logger.error(`${error} for device: ${this.deviceName}`);
|
|
1658
|
+
throw new Error(error);
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
const [head, body] = this.buildApiDict('delTimerV2');
|
|
1662
|
+
body.payload.subDeviceNo = 0;
|
|
1663
|
+
body.payload.data = { id: 1, subDeviceNo: 0 };
|
|
1664
|
+
|
|
1665
|
+
const [response, status] = await this.callApi(
|
|
1666
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
1667
|
+
'post',
|
|
1668
|
+
body,
|
|
1669
|
+
head
|
|
1670
|
+
);
|
|
1671
|
+
|
|
1672
|
+
const success = this.checkResponse([response, status], 'clearTimer');
|
|
1673
|
+
if (success) {
|
|
1674
|
+
this.timer = null;
|
|
1675
|
+
}
|
|
1676
|
+
return success;
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
/**
|
|
1680
|
+
* Set auto preference
|
|
1681
|
+
*/
|
|
1682
|
+
async setAutoPreference(preference: string = 'default', roomSize: number = 600): Promise<boolean> {
|
|
1683
|
+
if (!this.autoPreferences.includes(preference)) {
|
|
1684
|
+
logger.debug(`Invalid preference: ${preference} - valid preferences are default, efficient, quiet`);
|
|
1358
1685
|
return false;
|
|
1359
1686
|
}
|
|
1360
1687
|
|
|
1688
|
+
const [head, body] = this.buildApiDict('setAutoPreference');
|
|
1361
1689
|
body.payload.data = {
|
|
1362
|
-
|
|
1690
|
+
autoPreference: preference,
|
|
1691
|
+
roomSize: roomSize
|
|
1363
1692
|
};
|
|
1364
1693
|
|
|
1365
1694
|
const [response, status] = await this.callApi(
|
|
@@ -1369,14 +1698,94 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
1369
1698
|
head
|
|
1370
1699
|
);
|
|
1371
1700
|
|
|
1372
|
-
const success = this.checkResponse([response, status], '
|
|
1701
|
+
const success = this.checkResponse([response, status], 'setAutoPreference');
|
|
1373
1702
|
if (success) {
|
|
1374
|
-
this.details.
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1703
|
+
this.details.auto_preference = preference;
|
|
1704
|
+
}
|
|
1705
|
+
return success;
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
/**
|
|
1709
|
+
* Set light detection
|
|
1710
|
+
*/
|
|
1711
|
+
async setLightDetection(enabled: boolean): Promise<boolean> {
|
|
1712
|
+
const [head, body] = this.buildApiDict('setLightDetection');
|
|
1713
|
+
body.payload.data = {
|
|
1714
|
+
lightDetectionSwitch: enabled ? 1 : 0
|
|
1715
|
+
};
|
|
1716
|
+
|
|
1717
|
+
const [response, status] = await this.callApi(
|
|
1718
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
1719
|
+
'post',
|
|
1720
|
+
body,
|
|
1721
|
+
head
|
|
1722
|
+
);
|
|
1723
|
+
|
|
1724
|
+
const success = this.checkResponse([response, status], 'setLightDetection');
|
|
1725
|
+
if (success) {
|
|
1726
|
+
this.details.light_detection_switch = enabled;
|
|
1377
1727
|
}
|
|
1378
1728
|
return success;
|
|
1379
1729
|
}
|
|
1730
|
+
|
|
1731
|
+
/**
|
|
1732
|
+
* Get light detection status
|
|
1733
|
+
*/
|
|
1734
|
+
get lightDetection(): boolean {
|
|
1735
|
+
return Boolean(this.details.light_detection_switch);
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
/**
|
|
1739
|
+
* Get light detection state
|
|
1740
|
+
*/
|
|
1741
|
+
get lightDetectionState(): boolean {
|
|
1742
|
+
return Boolean(this.details.environment_light_state);
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
/**
|
|
1746
|
+
* Get auto preference type
|
|
1747
|
+
*/
|
|
1748
|
+
get autoPreferenceType(): string | null {
|
|
1749
|
+
return this.details.auto_preference_type;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
/**
|
|
1753
|
+
* Display JSON details
|
|
1754
|
+
*/
|
|
1755
|
+
override displayJSON(): string {
|
|
1756
|
+
const baseInfo = JSON.parse(super.displayJSON());
|
|
1757
|
+
const details: Record<string, string> = {
|
|
1758
|
+
...baseInfo,
|
|
1759
|
+
'Mode': this.mode,
|
|
1760
|
+
'Filter Life': this.details.filter_life.toString(),
|
|
1761
|
+
'Fan Level': this.speed.toString(),
|
|
1762
|
+
'Display On': this.details.display.toString(),
|
|
1763
|
+
'Child Lock': this.details.child_lock.toString(),
|
|
1764
|
+
'Display Set On': this.details.screen_switch.toString(),
|
|
1765
|
+
'Light Detection Enabled': this.details.light_detection_switch.toString(),
|
|
1766
|
+
'Environment Light State': this.details.environment_light_state.toString()
|
|
1767
|
+
};
|
|
1768
|
+
|
|
1769
|
+
if (this.hasFeature('air_quality')) {
|
|
1770
|
+
details['Air Quality Level'] = (this.details.air_quality ?? '').toString();
|
|
1771
|
+
details['Air Quality Value'] = (this.details.air_quality_value ?? '').toString();
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
const everestKeys: Record<string, string> = {
|
|
1775
|
+
'pm1': 'PM1',
|
|
1776
|
+
'pm10': 'PM10',
|
|
1777
|
+
'fan_rotate_angle': 'Fan Rotate Angle',
|
|
1778
|
+
'filter_open_state': 'Filter Open State'
|
|
1779
|
+
};
|
|
1780
|
+
|
|
1781
|
+
for (const [key, value] of Object.entries(everestKeys)) {
|
|
1782
|
+
if (key in this.details) {
|
|
1783
|
+
details[value] = this.details[key].toString();
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
return JSON.stringify(details, null, 4);
|
|
1788
|
+
}
|
|
1380
1789
|
}
|
|
1381
1790
|
|
|
1382
1791
|
/**
|
|
@@ -1391,20 +1800,36 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1391
1800
|
logger.debug(`Initialized VeSyncTowerFan device: ${this.deviceName}`);
|
|
1392
1801
|
}
|
|
1393
1802
|
|
|
1803
|
+
/**
|
|
1804
|
+
* Get timer status (in seconds)
|
|
1805
|
+
*/
|
|
1806
|
+
override get timer(): { duration: number; action: string } | null {
|
|
1807
|
+
const timerRemain = this.details.timerRemain || 0;
|
|
1808
|
+
return timerRemain > 0 ? { duration: timerRemain, action: 'off' } : null;
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
override set timer(value: { duration: number; action: string } | null) {
|
|
1812
|
+
if (value) {
|
|
1813
|
+
this.details.timerRemain = value.duration;
|
|
1814
|
+
} else {
|
|
1815
|
+
this.details.timerRemain = 0;
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1394
1819
|
/**
|
|
1395
1820
|
* Build API dictionary
|
|
1396
1821
|
*/
|
|
1397
1822
|
protected buildApiDict(method: string): [Record<string, any>, Record<string, any>] {
|
|
1398
1823
|
const head = Helpers.reqHeaderBypass();
|
|
1399
|
-
const body =
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1824
|
+
const body = {
|
|
1825
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
1826
|
+
cid: this.cid,
|
|
1827
|
+
configModule: this.configModule,
|
|
1828
|
+
payload: {
|
|
1829
|
+
method,
|
|
1830
|
+
source: 'APP',
|
|
1831
|
+
data: {}
|
|
1832
|
+
}
|
|
1408
1833
|
};
|
|
1409
1834
|
return [head, body];
|
|
1410
1835
|
}
|
|
@@ -1645,13 +2070,6 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1645
2070
|
return Boolean(this.details.muteState);
|
|
1646
2071
|
}
|
|
1647
2072
|
|
|
1648
|
-
/**
|
|
1649
|
-
* Get timer status (in seconds)
|
|
1650
|
-
*/
|
|
1651
|
-
get timer(): number {
|
|
1652
|
-
return this.details.timerRemain || 0;
|
|
1653
|
-
}
|
|
1654
|
-
|
|
1655
2073
|
/**
|
|
1656
2074
|
* Get temperature (in tenths of a degree)
|
|
1657
2075
|
*/
|
|
@@ -1780,22 +2198,25 @@ export const fanModules: Record<string, new (details: Record<string, any>, manag
|
|
|
1780
2198
|
'LAP-C601S-WUS': VeSyncAirBypass,
|
|
1781
2199
|
'LAP-C601S-WUSR': VeSyncAirBypass,
|
|
1782
2200
|
'LAP-C601S-WEU': VeSyncAirBypass,
|
|
1783
|
-
|
|
1784
|
-
'LAP-V102S-
|
|
1785
|
-
'LAP-V102S-
|
|
1786
|
-
'LAP-V102S-
|
|
1787
|
-
'LAP-V102S-
|
|
1788
|
-
'LAP-
|
|
1789
|
-
|
|
1790
|
-
'LAP-V201S-
|
|
1791
|
-
'LAP-V201S-
|
|
1792
|
-
'LAP-
|
|
1793
|
-
'LAP-V201S-
|
|
1794
|
-
'LAP-
|
|
1795
|
-
'LAP-
|
|
1796
|
-
'LAP-
|
|
1797
|
-
|
|
1798
|
-
'LAP-EL551S-
|
|
2201
|
+
// Vital100S Series - Using VeSyncAirBaseV2
|
|
2202
|
+
'LAP-V102S-AASR': VeSyncAirBaseV2,
|
|
2203
|
+
'LAP-V102S-WUS': VeSyncAirBaseV2,
|
|
2204
|
+
'LAP-V102S-WEU': VeSyncAirBaseV2,
|
|
2205
|
+
'LAP-V102S-AUSR': VeSyncAirBaseV2,
|
|
2206
|
+
'LAP-V102S-WJP': VeSyncAirBaseV2,
|
|
2207
|
+
// Vital200S Series - Using VeSyncAirBaseV2
|
|
2208
|
+
'LAP-V201S-AASR': VeSyncAirBaseV2,
|
|
2209
|
+
'LAP-V201S-WJP': VeSyncAirBaseV2,
|
|
2210
|
+
'LAP-V201S-WEU': VeSyncAirBaseV2,
|
|
2211
|
+
'LAP-V201S-WUS': VeSyncAirBaseV2,
|
|
2212
|
+
'LAP-V201-AUSR': VeSyncAirBaseV2,
|
|
2213
|
+
'LAP-V201S-AUSR': VeSyncAirBaseV2,
|
|
2214
|
+
'LAP-V201S-AEUR': VeSyncAirBaseV2,
|
|
2215
|
+
// EverestAir Series - Using VeSyncAirBaseV2
|
|
2216
|
+
'LAP-EL551S-AUS': VeSyncAirBaseV2,
|
|
2217
|
+
'LAP-EL551S-AEUR': VeSyncAirBaseV2,
|
|
2218
|
+
'LAP-EL551S-WEU': VeSyncAirBaseV2,
|
|
2219
|
+
'LAP-EL551S-WUS': VeSyncAirBaseV2,
|
|
1799
2220
|
|
|
1800
2221
|
// LTF Series
|
|
1801
2222
|
'LTF-F422S-KEU': VeSyncTowerFan,
|