tsvesync 1.0.42 → 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.
@@ -26,7 +26,7 @@ class VeSyncAirBypass extends vesyncFan_1.VeSyncFan {
26
26
  const head = helpers_1.Helpers.reqHeaderBypass();
27
27
  const body = {
28
28
  ...helpers_1.Helpers.reqBody(this.manager, 'bypassV2'),
29
- deviceId: this.cid,
29
+ cid: this.cid,
30
30
  configModule: this.configModule,
31
31
  payload: {
32
32
  method,
@@ -423,79 +423,37 @@ class VeSyncAirBypass extends vesyncFan_1.VeSyncFan {
423
423
  return success;
424
424
  }
425
425
  /**
426
- * Set mode
426
+ * Set auto mode
427
427
  */
428
- async mode_toggle(mode) {
429
- if (!this.modes.includes(mode.toLowerCase())) {
430
- logger_1.logger.debug(`Invalid purifier mode used - ${mode}`);
431
- return false;
432
- }
433
- const [head, body] = this.buildApiDict('setPurifierMode');
434
- if (!head || !body) {
435
- return false;
436
- }
437
- if (mode === 'manual') {
438
- body.payload = {
439
- data: {
440
- id: 0,
441
- level: 1,
442
- type: 'wind'
443
- },
444
- method: 'setLevel',
445
- type: 'APP'
446
- };
447
- }
448
- else {
449
- body.payload.data = {
450
- mode: mode.toLowerCase()
451
- };
452
- }
453
- const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
454
- const success = this.checkResponse([response, status], 'mode_toggle');
455
- if (success) {
456
- if (mode === 'manual') {
457
- this.details.speed = 1;
458
- this.details.mode = 'manual';
459
- }
460
- else {
461
- this.details.mode = mode;
462
- this.details.speed = 0;
463
- }
464
- }
465
- else {
466
- logger_1.logger.debug('Error setting purifier mode');
428
+ async autoMode() {
429
+ logger_1.logger.debug(`Setting auto mode for device: ${this.deviceName}`);
430
+ const success = await this.setMode('auto');
431
+ if (!success) {
432
+ logger_1.logger.error(`Failed to set auto mode for device: ${this.deviceName}`);
467
433
  }
468
434
  return success;
469
435
  }
470
436
  /**
471
437
  * Set manual mode
472
438
  */
473
- async manual_mode() {
474
- if (!this.modes.includes('manual')) {
475
- logger_1.logger.debug(`${this.deviceName} does not have manual mode`);
476
- return false;
439
+ async manualMode() {
440
+ logger_1.logger.debug(`Setting manual mode for device: ${this.deviceName}`);
441
+ const success = await this.setMode('manual');
442
+ if (!success) {
443
+ logger_1.logger.error(`Failed to set manual mode for device: ${this.deviceName}`);
477
444
  }
478
- return this.mode_toggle('manual');
445
+ return success;
479
446
  }
480
447
  /**
481
448
  * Set sleep mode
482
449
  */
483
- async sleep_mode() {
484
- if (!this.modes.includes('sleep')) {
485
- logger_1.logger.debug(`${this.deviceName} does not have sleep mode`);
486
- return false;
487
- }
488
- return this.mode_toggle('sleep');
489
- }
490
- /**
491
- * Set auto mode
492
- */
493
- async auto_mode() {
494
- if (!this.modes.includes('auto')) {
495
- logger_1.logger.debug(`${this.deviceName} does not have auto mode`);
496
- return false;
450
+ async sleepMode() {
451
+ logger_1.logger.debug(`Setting sleep mode for device: ${this.deviceName}`);
452
+ const success = await this.setMode('sleep');
453
+ if (!success) {
454
+ logger_1.logger.error(`Failed to set sleep mode for device: ${this.deviceName}`);
497
455
  }
498
- return this.mode_toggle('auto');
456
+ return success;
499
457
  }
500
458
  /**
501
459
  * Turn off display
@@ -519,24 +477,6 @@ class VeSyncAirBypass extends vesyncFan_1.VeSyncFan {
519
477
  }
520
478
  return success;
521
479
  }
522
- /**
523
- * Display device info
524
- */
525
- display() {
526
- super.display();
527
- const info = [
528
- ['Mode: ', this.details.mode || ''],
529
- ['Speed: ', this.speed],
530
- ['Filter Life: ', this.filterLife || 0, '%'],
531
- ['Air Quality: ', this.details.air_quality || ''],
532
- ['Display: ', this.details.display || false],
533
- ['Child Lock: ', this.details.child_lock || false],
534
- ['Night Light: ', this.details.night_light || 'off']
535
- ];
536
- for (const [key, value, unit = ''] of info) {
537
- logger_1.logger.info(`${key.toString().padEnd(30, '.')} ${value}${unit}`);
538
- }
539
- }
540
480
  }
541
481
  exports.VeSyncAirBypass = VeSyncAirBypass;
542
482
  /**
@@ -914,17 +854,6 @@ class VeSyncHumidifier extends vesyncFan_1.VeSyncFan {
914
854
  }
915
855
  return success;
916
856
  }
917
- /**
918
- * Set sleep mode
919
- */
920
- async sleepMode() {
921
- logger_1.logger.debug(`Setting sleep mode for device: ${this.deviceName}`);
922
- const success = await this.setMode('sleep');
923
- if (!success) {
924
- logger_1.logger.error(`Failed to set sleep mode for device: ${this.deviceName}`);
925
- }
926
- return success;
927
- }
928
857
  /**
929
858
  * Turn off display
930
859
  */
@@ -1123,8 +1052,37 @@ class VeSyncAirBaseV2 extends VeSyncAirBypass {
1123
1052
  super(details, manager);
1124
1053
  this._lightDetection = false;
1125
1054
  this._lightDetectionState = false;
1055
+ this.setSpeedLevel = null;
1056
+ this.autoPreferences = ['default', 'efficient', 'quiet'];
1057
+ this.enabled = false;
1058
+ this._mode = '';
1059
+ this._speed = 0;
1060
+ this._timer = null;
1126
1061
  logger_1.logger.debug(`Initialized VeSyncAirBaseV2 device: ${this.deviceName}`);
1127
1062
  }
1063
+ buildConfigDict(configDict) {
1064
+ if (configDict) {
1065
+ this.config = configDict;
1066
+ }
1067
+ }
1068
+ get mode() {
1069
+ return this._mode;
1070
+ }
1071
+ set mode(value) {
1072
+ this._mode = value;
1073
+ }
1074
+ get speed() {
1075
+ return this._speed;
1076
+ }
1077
+ set speed(value) {
1078
+ this._speed = value;
1079
+ }
1080
+ get timer() {
1081
+ return this._timer;
1082
+ }
1083
+ set timer(value) {
1084
+ this._timer = value;
1085
+ }
1128
1086
  /**
1129
1087
  * Build API dictionary
1130
1088
  */
@@ -1132,7 +1090,7 @@ class VeSyncAirBaseV2 extends VeSyncAirBypass {
1132
1090
  const head = helpers_1.Helpers.reqHeaderBypass();
1133
1091
  const body = {
1134
1092
  ...helpers_1.Helpers.reqBody(this.manager, 'bypassV2'),
1135
- deviceId: this.cid,
1093
+ cid: this.cid,
1136
1094
  configModule: this.configModule,
1137
1095
  payload: {
1138
1096
  method,
@@ -1142,101 +1100,354 @@ class VeSyncAirBaseV2 extends VeSyncAirBypass {
1142
1100
  };
1143
1101
  return [head, body];
1144
1102
  }
1145
- get lightDetection() {
1146
- return this._lightDetection;
1147
- }
1148
- set lightDetection(toggle) {
1149
- this._lightDetection = toggle;
1103
+ /**
1104
+ * Get device details
1105
+ */
1106
+ async getDetails() {
1107
+ logger_1.logger.debug(`Getting details for device: ${this.deviceName}`);
1108
+ const [head, body] = this.buildApiDict('getPurifierStatus');
1109
+ const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
1110
+ if (!this.checkResponse([response, status], 'getDetails') || !(response === null || response === void 0 ? void 0 : response.result)) {
1111
+ logger_1.logger.debug('Error getting purifier details');
1112
+ this.connectionStatus = 'offline';
1113
+ return false;
1114
+ }
1115
+ const innerResponse = response.result;
1116
+ if (innerResponse.code !== 0 || !innerResponse.result) {
1117
+ logger_1.logger.debug('Error in inner response from purifier');
1118
+ this.connectionStatus = 'offline';
1119
+ return false;
1120
+ }
1121
+ const deviceData = innerResponse.result;
1122
+ this.buildPurifierDict(deviceData);
1123
+ if (deviceData.configuration) {
1124
+ this.buildConfigDict(deviceData.configuration);
1125
+ }
1126
+ return true;
1150
1127
  }
1151
- get lightDetectionState() {
1152
- return this._lightDetectionState;
1128
+ /**
1129
+ * Build purifier dictionary
1130
+ */
1131
+ buildPurifierDict(devDict) {
1132
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
1133
+ this.connectionStatus = 'online';
1134
+ const powerSwitch = Boolean((_a = devDict.powerSwitch) !== null && _a !== void 0 ? _a : 0);
1135
+ this.enabled = powerSwitch;
1136
+ this.deviceStatus = powerSwitch ? 'on' : 'off';
1137
+ this.mode = (_b = devDict.workMode) !== null && _b !== void 0 ? _b : 'manual';
1138
+ this.speed = (_c = devDict.fanSpeedLevel) !== null && _c !== void 0 ? _c : 0;
1139
+ this.setSpeedLevel = (_d = devDict.manualSpeedLevel) !== null && _d !== void 0 ? _d : 1;
1140
+ this.details = {
1141
+ ...this.details,
1142
+ filter_life: (_e = devDict.filterLifePercent) !== null && _e !== void 0 ? _e : 0,
1143
+ child_lock: Boolean((_f = devDict.childLockSwitch) !== null && _f !== void 0 ? _f : 0),
1144
+ display: Boolean((_g = devDict.screenState) !== null && _g !== void 0 ? _g : 0),
1145
+ light_detection_switch: Boolean((_h = devDict.lightDetectionSwitch) !== null && _h !== void 0 ? _h : 0),
1146
+ environment_light_state: Boolean((_j = devDict.environmentLightState) !== null && _j !== void 0 ? _j : 0),
1147
+ screen_switch: Boolean((_k = devDict.screenSwitch) !== null && _k !== void 0 ? _k : 0)
1148
+ };
1149
+ if (this.hasFeature('air_quality')) {
1150
+ this.details.air_quality_value = (_l = devDict.PM25) !== null && _l !== void 0 ? _l : 0;
1151
+ this.details.air_quality = (_m = devDict.AQLevel) !== null && _m !== void 0 ? _m : 0;
1152
+ }
1153
+ if ('PM1' in devDict)
1154
+ this.details.pm1 = devDict.PM1;
1155
+ if ('PM10' in devDict)
1156
+ this.details.pm10 = devDict.PM10;
1157
+ if ('AQPercent' in devDict)
1158
+ this.details.aq_percent = devDict.AQPercent;
1159
+ if ('fanRotateAngle' in devDict)
1160
+ this.details.fan_rotate_angle = devDict.fanRotateAngle;
1161
+ if ('filterOpenState' in devDict)
1162
+ this.details.filter_open_state = Boolean(devDict.filterOpenState);
1163
+ if (((_o = devDict.timerRemain) !== null && _o !== void 0 ? _o : 0) > 0) {
1164
+ this.timer = { duration: devDict.timerRemain, action: 'off' };
1165
+ }
1166
+ if (typeof devDict.autoPreference === 'object' && devDict.autoPreference) {
1167
+ this.details.auto_preference_type = (_q = (_p = devDict.autoPreference) === null || _p === void 0 ? void 0 : _p.autoPreferenceType) !== null && _q !== void 0 ? _q : 'default';
1168
+ }
1169
+ else {
1170
+ this.details.auto_preference_type = null;
1171
+ }
1153
1172
  }
1154
- async setLightDetection(toggle) {
1155
- const [head, body] = this.buildApiDict('setLightDetection');
1156
- if (!head || !body) {
1173
+ /**
1174
+ * Toggle device power
1175
+ */
1176
+ async toggleSwitch(toggle) {
1177
+ if (typeof toggle !== 'boolean') {
1178
+ logger_1.logger.debug('Invalid toggle value for purifier switch');
1157
1179
  return false;
1158
1180
  }
1159
- body.payload.data = { enabled: toggle };
1181
+ const [head, body] = this.buildApiDict('setSwitch');
1182
+ body.payload.data = {
1183
+ powerSwitch: toggle ? 1 : 0,
1184
+ switchIdx: 0
1185
+ };
1160
1186
  const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
1161
- const success = this.checkResponse([response, status], 'setLightDetection');
1187
+ const success = this.checkResponse([response, status], 'toggleSwitch');
1162
1188
  if (success) {
1163
- this._lightDetection = toggle;
1189
+ this.deviceStatus = toggle ? 'on' : 'off';
1164
1190
  }
1165
1191
  return success;
1166
1192
  }
1167
- async setLightDetectionOn() {
1168
- return this.setLightDetection(true);
1169
- }
1170
- async setLightDetectionOff() {
1171
- return this.setLightDetection(false);
1172
- }
1173
- async turboMode() {
1174
- return this.mode_toggle('turbo');
1193
+ /**
1194
+ * Turn device on - compatibility method that proxies to toggleSwitch
1195
+ */
1196
+ async turnOn() {
1197
+ logger_1.logger.info(`Turning on device: ${this.deviceName}`);
1198
+ return this.toggleSwitch(true);
1175
1199
  }
1176
- async petMode() {
1177
- return this.mode_toggle('pet');
1200
+ /**
1201
+ * Turn device off - compatibility method that proxies to toggleSwitch
1202
+ */
1203
+ async turnOff() {
1204
+ logger_1.logger.info(`Turning off device: ${this.deviceName}`);
1205
+ return this.toggleSwitch(false);
1178
1206
  }
1179
1207
  /**
1180
- * Build configuration dictionary
1208
+ * Change fan speed
1181
1209
  */
1182
- buildConfigDict(configDict) {
1183
- if (configDict) {
1184
- this.config = configDict;
1210
+ async changeFanSpeed(speed) {
1211
+ var _a, _b, _c;
1212
+ const speeds = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.levels) !== null && _b !== void 0 ? _b : [];
1213
+ const currentSpeed = (_c = this.setSpeedLevel) !== null && _c !== void 0 ? _c : 0;
1214
+ if (speed !== undefined) {
1215
+ if (!speeds.includes(speed)) {
1216
+ logger_1.logger.debug(`Invalid speed: ${speed}. Must be one of: ${speeds.join(', ')}`);
1217
+ return false;
1218
+ }
1185
1219
  }
1220
+ else {
1221
+ if (currentSpeed === speeds[speeds.length - 1] || currentSpeed === 0) {
1222
+ speed = speeds[0];
1223
+ }
1224
+ else {
1225
+ const currentIndex = speeds.indexOf(currentSpeed);
1226
+ speed = speeds[currentIndex + 1];
1227
+ }
1228
+ }
1229
+ const [head, body] = this.buildApiDict('setLevel');
1230
+ body.payload.data = {
1231
+ levelIdx: 0,
1232
+ manualSpeedLevel: speed,
1233
+ levelType: 'wind'
1234
+ };
1235
+ const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
1236
+ const success = this.checkResponse([response, status], 'changeFanSpeed');
1237
+ if (success) {
1238
+ this.setSpeedLevel = speed;
1239
+ this.mode = 'manual';
1240
+ }
1241
+ return success;
1186
1242
  }
1187
1243
  /**
1188
1244
  * Set mode
1189
1245
  */
1190
- async mode_toggle(mode) {
1191
- const validModes = this.modes.map(m => m.toLowerCase());
1192
- if (!validModes.includes(mode.toLowerCase())) {
1193
- logger_1.logger.debug(`Invalid mode used - ${mode}`);
1246
+ async setMode(mode) {
1247
+ if (!this.modes.includes(mode)) {
1248
+ logger_1.logger.debug(`Invalid mode: ${mode}. Must be one of: ${this.modes.join(', ')}`);
1194
1249
  return false;
1195
1250
  }
1251
+ if (mode === 'manual') {
1252
+ if (!this.speed || this.speed === 0) {
1253
+ return this.changeFanSpeed(1);
1254
+ }
1255
+ return this.changeFanSpeed(this.speed);
1256
+ }
1257
+ if (mode === 'off') {
1258
+ return this.turnOff();
1259
+ }
1196
1260
  const [head, body] = this.buildApiDict('setPurifierMode');
1197
- if (!head || !body) {
1198
- return false;
1261
+ body.payload.data = {
1262
+ workMode: mode
1263
+ };
1264
+ const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
1265
+ const success = this.checkResponse([response, status], 'setMode');
1266
+ if (success) {
1267
+ this.mode = mode;
1268
+ }
1269
+ return success;
1270
+ }
1271
+ /**
1272
+ * Set display status
1273
+ */
1274
+ async setDisplay(enabled) {
1275
+ if (!this.hasFeature('display')) {
1276
+ const error = 'Display control not supported';
1277
+ logger_1.logger.error(`${error} for device: ${this.deviceName}`);
1278
+ throw new Error(error);
1199
1279
  }
1280
+ const [head, body] = this.buildApiDict('setDisplay');
1200
1281
  body.payload.data = {
1201
- mode: mode
1282
+ screenSwitch: enabled ? 1 : 0
1202
1283
  };
1203
1284
  const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
1204
- const success = this.checkResponse([response, status], 'mode_toggle');
1285
+ const success = this.checkResponse([response, status], 'setDisplay');
1205
1286
  if (success) {
1206
- this.details.mode = mode;
1287
+ this.details.screen_switch = enabled;
1207
1288
  }
1208
- else {
1209
- logger_1.logger.debug('Error setting mode');
1289
+ return success;
1290
+ }
1291
+ /**
1292
+ * Set child lock
1293
+ */
1294
+ async setChildLock(enabled) {
1295
+ if (!this.hasFeature('child_lock')) {
1296
+ const error = 'Child lock not supported';
1297
+ logger_1.logger.error(`${error} for device: ${this.deviceName}`);
1298
+ throw new Error(error);
1299
+ }
1300
+ const [head, body] = this.buildApiDict('setChildLock');
1301
+ body.payload.data = {
1302
+ childLockSwitch: enabled ? 1 : 0
1303
+ };
1304
+ const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
1305
+ const success = this.checkResponse([response, status], 'setChildLock');
1306
+ if (success) {
1307
+ this.details.child_lock = enabled;
1210
1308
  }
1211
1309
  return success;
1212
1310
  }
1213
1311
  /**
1214
- * Set manual mode
1312
+ * Set timer
1215
1313
  */
1216
- async manual_mode() {
1217
- return this.mode_toggle('manual');
1314
+ async setTimer(timerDuration, action = 'off', method = 'powerSwitch') {
1315
+ if (!this.hasFeature('timer')) {
1316
+ const error = 'Timer not supported';
1317
+ logger_1.logger.error(`${error} for device: ${this.deviceName}`);
1318
+ throw new Error(error);
1319
+ }
1320
+ if (!['on', 'off'].includes(action)) {
1321
+ logger_1.logger.debug('Invalid action for timer');
1322
+ return false;
1323
+ }
1324
+ if (method !== 'powerSwitch') {
1325
+ logger_1.logger.debug('Invalid method for timer');
1326
+ return false;
1327
+ }
1328
+ const [head, body] = this.buildApiDict('addTimerV2');
1329
+ body.payload.subDeviceNo = 0;
1330
+ body.payload.data = {
1331
+ startAct: [{
1332
+ type: method,
1333
+ num: 0,
1334
+ act: action === 'on' ? 1 : 0
1335
+ }],
1336
+ total: timerDuration,
1337
+ subDeviceNo: 0
1338
+ };
1339
+ const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
1340
+ const success = this.checkResponse([response, status], 'setTimer');
1341
+ if (success) {
1342
+ this.timer = { duration: timerDuration, action };
1343
+ }
1344
+ return success;
1218
1345
  }
1219
1346
  /**
1220
- * Set sleep mode
1347
+ * Clear timer
1221
1348
  */
1222
- async sleep_mode() {
1223
- return this.mode_toggle('sleep');
1349
+ async clearTimer() {
1350
+ if (!this.hasFeature('timer')) {
1351
+ const error = 'Timer not supported';
1352
+ logger_1.logger.error(`${error} for device: ${this.deviceName}`);
1353
+ throw new Error(error);
1354
+ }
1355
+ const [head, body] = this.buildApiDict('delTimerV2');
1356
+ body.payload.subDeviceNo = 0;
1357
+ body.payload.data = { id: 1, subDeviceNo: 0 };
1358
+ const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
1359
+ const success = this.checkResponse([response, status], 'clearTimer');
1360
+ if (success) {
1361
+ this.timer = null;
1362
+ }
1363
+ return success;
1224
1364
  }
1225
1365
  /**
1226
- * Set auto mode
1366
+ * Set auto preference
1227
1367
  */
1228
- async auto_mode() {
1229
- if (!this.modes.includes('auto')) {
1230
- logger_1.logger.debug(`${this.deviceName} does not have auto mode`);
1368
+ async setAutoPreference(preference = 'default', roomSize = 600) {
1369
+ if (!this.autoPreferences.includes(preference)) {
1370
+ logger_1.logger.debug(`Invalid preference: ${preference} - valid preferences are default, efficient, quiet`);
1231
1371
  return false;
1232
1372
  }
1233
- return this.mode_toggle('auto');
1373
+ const [head, body] = this.buildApiDict('setAutoPreference');
1374
+ body.payload.data = {
1375
+ autoPreference: preference,
1376
+ roomSize: roomSize
1377
+ };
1378
+ const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
1379
+ const success = this.checkResponse([response, status], 'setAutoPreference');
1380
+ if (success) {
1381
+ this.details.auto_preference = preference;
1382
+ }
1383
+ return success;
1234
1384
  }
1235
1385
  /**
1236
- * Set turbo mode
1386
+ * Set light detection
1237
1387
  */
1238
- async turbo_mode() {
1239
- return this.mode_toggle('turbo');
1388
+ async setLightDetection(enabled) {
1389
+ const [head, body] = this.buildApiDict('setLightDetection');
1390
+ body.payload.data = {
1391
+ lightDetectionSwitch: enabled ? 1 : 0
1392
+ };
1393
+ const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
1394
+ const success = this.checkResponse([response, status], 'setLightDetection');
1395
+ if (success) {
1396
+ this.details.light_detection_switch = enabled;
1397
+ }
1398
+ return success;
1399
+ }
1400
+ /**
1401
+ * Get light detection status
1402
+ */
1403
+ get lightDetection() {
1404
+ return Boolean(this.details.light_detection_switch);
1405
+ }
1406
+ /**
1407
+ * Get light detection state
1408
+ */
1409
+ get lightDetectionState() {
1410
+ return Boolean(this.details.environment_light_state);
1411
+ }
1412
+ /**
1413
+ * Get auto preference type
1414
+ */
1415
+ get autoPreferenceType() {
1416
+ return this.details.auto_preference_type;
1417
+ }
1418
+ /**
1419
+ * Display JSON details
1420
+ */
1421
+ displayJSON() {
1422
+ var _a, _b;
1423
+ const baseInfo = JSON.parse(super.displayJSON());
1424
+ const details = {
1425
+ ...baseInfo,
1426
+ 'Mode': this.mode,
1427
+ 'Filter Life': this.details.filter_life.toString(),
1428
+ 'Fan Level': this.speed.toString(),
1429
+ 'Display On': this.details.display.toString(),
1430
+ 'Child Lock': this.details.child_lock.toString(),
1431
+ 'Display Set On': this.details.screen_switch.toString(),
1432
+ 'Light Detection Enabled': this.details.light_detection_switch.toString(),
1433
+ 'Environment Light State': this.details.environment_light_state.toString()
1434
+ };
1435
+ if (this.hasFeature('air_quality')) {
1436
+ details['Air Quality Level'] = ((_a = this.details.air_quality) !== null && _a !== void 0 ? _a : '').toString();
1437
+ details['Air Quality Value'] = ((_b = this.details.air_quality_value) !== null && _b !== void 0 ? _b : '').toString();
1438
+ }
1439
+ const everestKeys = {
1440
+ 'pm1': 'PM1',
1441
+ 'pm10': 'PM10',
1442
+ 'fan_rotate_angle': 'Fan Rotate Angle',
1443
+ 'filter_open_state': 'Filter Open State'
1444
+ };
1445
+ for (const [key, value] of Object.entries(everestKeys)) {
1446
+ if (key in this.details) {
1447
+ details[value] = this.details[key].toString();
1448
+ }
1449
+ }
1450
+ return JSON.stringify(details, null, 4);
1240
1451
  }
1241
1452
  }
1242
1453
  exports.VeSyncAirBaseV2 = VeSyncAirBaseV2;
@@ -1250,20 +1461,35 @@ class VeSyncTowerFan extends VeSyncAirBaseV2 {
1250
1461
  this.speeds = Array.from({ length: 12 }, (_, i) => i + 1);
1251
1462
  logger_1.logger.debug(`Initialized VeSyncTowerFan device: ${this.deviceName}`);
1252
1463
  }
1464
+ /**
1465
+ * Get timer status (in seconds)
1466
+ */
1467
+ get timer() {
1468
+ const timerRemain = this.details.timerRemain || 0;
1469
+ return timerRemain > 0 ? { duration: timerRemain, action: 'off' } : null;
1470
+ }
1471
+ set timer(value) {
1472
+ if (value) {
1473
+ this.details.timerRemain = value.duration;
1474
+ }
1475
+ else {
1476
+ this.details.timerRemain = 0;
1477
+ }
1478
+ }
1253
1479
  /**
1254
1480
  * Build API dictionary
1255
1481
  */
1256
1482
  buildApiDict(method) {
1257
1483
  const head = helpers_1.Helpers.reqHeaderBypass();
1258
- const body = helpers_1.Helpers.reqBody(this.manager, 'bypassV2');
1259
- body.cid = this.cid;
1260
- body.deviceId = this.cid;
1261
- body.configModule = this.configModule;
1262
- body.configModel = this.configModule;
1263
- body.payload = {
1264
- method: method,
1265
- source: 'APP',
1266
- data: {}
1484
+ const body = {
1485
+ ...helpers_1.Helpers.reqBody(this.manager, 'bypassV2'),
1486
+ cid: this.cid,
1487
+ configModule: this.configModule,
1488
+ payload: {
1489
+ method,
1490
+ source: 'APP',
1491
+ data: {}
1492
+ }
1267
1493
  };
1268
1494
  return [head, body];
1269
1495
  }
@@ -1456,12 +1682,6 @@ class VeSyncTowerFan extends VeSyncAirBaseV2 {
1456
1682
  get muteState() {
1457
1683
  return Boolean(this.details.muteState);
1458
1684
  }
1459
- /**
1460
- * Get timer status (in seconds)
1461
- */
1462
- get timer() {
1463
- return this.details.timerRemain || 0;
1464
- }
1465
1685
  /**
1466
1686
  * Get temperature (in tenths of a degree)
1467
1687
  */
@@ -1571,22 +1791,25 @@ exports.fanModules = {
1571
1791
  'LAP-C601S-WUS': VeSyncAirBypass,
1572
1792
  'LAP-C601S-WUSR': VeSyncAirBypass,
1573
1793
  'LAP-C601S-WEU': VeSyncAirBypass,
1574
- 'LAP-V102S-AASR': VeSyncAirBypass,
1575
- 'LAP-V102S-WUS': VeSyncAirBypass,
1576
- 'LAP-V102S-WEU': VeSyncAirBypass,
1577
- 'LAP-V102S-AUSR': VeSyncAirBypass,
1578
- 'LAP-V102S-WJP': VeSyncAirBypass,
1579
- 'LAP-V201S-AASR': VeSyncAirBypass,
1580
- 'LAP-V201S-WJP': VeSyncAirBypass,
1581
- 'LAP-V201S-WEU': VeSyncAirBypass,
1582
- 'LAP-V201S-WUS': VeSyncAirBypass,
1583
- 'LAP-V201-AUSR': VeSyncAirBypass,
1584
- 'LAP-V201S-AUSR': VeSyncAirBypass,
1585
- 'LAP-V201S-AEUR': VeSyncAirBypass,
1586
- 'LAP-EL551S-AUS': VeSyncAirBypass,
1587
- 'LAP-EL551S-AEUR': VeSyncAirBypass,
1588
- 'LAP-EL551S-WEU': VeSyncAirBypass,
1589
- 'LAP-EL551S-WUS': VeSyncAirBypass,
1794
+ // Vital100S Series - Using VeSyncAirBaseV2
1795
+ 'LAP-V102S-AASR': VeSyncAirBaseV2,
1796
+ 'LAP-V102S-WUS': VeSyncAirBaseV2,
1797
+ 'LAP-V102S-WEU': VeSyncAirBaseV2,
1798
+ 'LAP-V102S-AUSR': VeSyncAirBaseV2,
1799
+ 'LAP-V102S-WJP': VeSyncAirBaseV2,
1800
+ // Vital200S Series - Using VeSyncAirBaseV2
1801
+ 'LAP-V201S-AASR': VeSyncAirBaseV2,
1802
+ 'LAP-V201S-WJP': VeSyncAirBaseV2,
1803
+ 'LAP-V201S-WEU': VeSyncAirBaseV2,
1804
+ 'LAP-V201S-WUS': VeSyncAirBaseV2,
1805
+ 'LAP-V201-AUSR': VeSyncAirBaseV2,
1806
+ 'LAP-V201S-AUSR': VeSyncAirBaseV2,
1807
+ 'LAP-V201S-AEUR': VeSyncAirBaseV2,
1808
+ // EverestAir Series - Using VeSyncAirBaseV2
1809
+ 'LAP-EL551S-AUS': VeSyncAirBaseV2,
1810
+ 'LAP-EL551S-AEUR': VeSyncAirBaseV2,
1811
+ 'LAP-EL551S-WEU': VeSyncAirBaseV2,
1812
+ 'LAP-EL551S-WUS': VeSyncAirBaseV2,
1590
1813
  // LTF Series
1591
1814
  'LTF-F422S-KEU': VeSyncTowerFan,
1592
1815
  'LTF-F422S-WUSR': VeSyncTowerFan,