tsvesync 1.0.38 → 1.0.40
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/helpers.d.ts +2 -2
- package/dist/lib/helpers.js +2 -2
- package/dist/lib/vesyncFanImpl.d.ts +49 -9
- package/dist/lib/vesyncFanImpl.js +160 -76
- package/package.json +1 -1
- package/src/lib/helpers.ts +2 -2
- package/src/lib/vesyncFanImpl.ts +186 -87
package/dist/lib/helpers.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ export declare class Helpers {
|
|
|
40
40
|
/**
|
|
41
41
|
* Calculate MD5 hash
|
|
42
42
|
*/
|
|
43
|
-
static
|
|
43
|
+
static hashPassword(text: string): string;
|
|
44
44
|
/**
|
|
45
45
|
* Build header for legacy api GET requests
|
|
46
46
|
*/
|
|
@@ -84,5 +84,5 @@ export declare class Helpers {
|
|
|
84
84
|
/**
|
|
85
85
|
* Calculate MD5 hash
|
|
86
86
|
*/
|
|
87
|
-
static
|
|
87
|
+
static md5(text: string): string;
|
|
88
88
|
}
|
package/dist/lib/helpers.js
CHANGED
|
@@ -34,7 +34,7 @@ class Helpers {
|
|
|
34
34
|
/**
|
|
35
35
|
* Calculate MD5 hash
|
|
36
36
|
*/
|
|
37
|
-
static
|
|
37
|
+
static hashPassword(text) {
|
|
38
38
|
return crypto_1.default.createHash('md5').update(text).digest('hex');
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
@@ -250,7 +250,7 @@ class Helpers {
|
|
|
250
250
|
/**
|
|
251
251
|
* Calculate MD5 hash
|
|
252
252
|
*/
|
|
253
|
-
static
|
|
253
|
+
static md5(text) {
|
|
254
254
|
return crypto_1.default.createHash('md5').update(text).digest('hex');
|
|
255
255
|
}
|
|
256
256
|
}
|
|
@@ -245,13 +245,13 @@ export declare class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
245
245
|
protected readonly speeds: number[];
|
|
246
246
|
constructor(details: Record<string, any>, manager: VeSync);
|
|
247
247
|
/**
|
|
248
|
-
*
|
|
248
|
+
* Build API dictionary
|
|
249
249
|
*/
|
|
250
|
-
|
|
250
|
+
protected buildApiDict(method: string): [Record<string, any>, Record<string, any>];
|
|
251
251
|
/**
|
|
252
|
-
*
|
|
252
|
+
* Get device details
|
|
253
253
|
*/
|
|
254
|
-
|
|
254
|
+
getDetails(): Promise<Boolean>;
|
|
255
255
|
/**
|
|
256
256
|
* Toggle device power
|
|
257
257
|
*/
|
|
@@ -268,6 +268,10 @@ export declare class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
268
268
|
* Set tower fan mode
|
|
269
269
|
*/
|
|
270
270
|
mode_toggle(mode: string): Promise<boolean>;
|
|
271
|
+
/**
|
|
272
|
+
* Change fan speed
|
|
273
|
+
*/
|
|
274
|
+
changeFanSpeed(speed: number): Promise<boolean>;
|
|
271
275
|
/**
|
|
272
276
|
* Set normal mode
|
|
273
277
|
*/
|
|
@@ -297,17 +301,53 @@ export declare class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
297
301
|
*/
|
|
298
302
|
get displayState(): boolean;
|
|
299
303
|
/**
|
|
300
|
-
* Get
|
|
304
|
+
* Get oscillation status
|
|
301
305
|
*/
|
|
302
|
-
get
|
|
306
|
+
get oscillationState(): boolean;
|
|
303
307
|
/**
|
|
304
|
-
* Get
|
|
308
|
+
* Get mute status
|
|
305
309
|
*/
|
|
306
|
-
get
|
|
310
|
+
get muteState(): boolean;
|
|
307
311
|
/**
|
|
308
|
-
* Get timer status
|
|
312
|
+
* Get timer status (in seconds)
|
|
309
313
|
*/
|
|
310
314
|
get timer(): number;
|
|
315
|
+
/**
|
|
316
|
+
* Get temperature (in tenths of a degree)
|
|
317
|
+
*/
|
|
318
|
+
get temperature(): number;
|
|
319
|
+
/**
|
|
320
|
+
* Get humidity percentage
|
|
321
|
+
*/
|
|
322
|
+
get humidity(): number;
|
|
323
|
+
/**
|
|
324
|
+
* Get thermal comfort level
|
|
325
|
+
*/
|
|
326
|
+
get thermalComfort(): number;
|
|
327
|
+
/**
|
|
328
|
+
* Get sleep preferences
|
|
329
|
+
*/
|
|
330
|
+
get sleepPreference(): Record<string, any>;
|
|
331
|
+
/**
|
|
332
|
+
* Get schedule count
|
|
333
|
+
*/
|
|
334
|
+
get scheduleCount(): number;
|
|
335
|
+
/**
|
|
336
|
+
* Get error code
|
|
337
|
+
*/
|
|
338
|
+
get errorCode(): number;
|
|
339
|
+
/**
|
|
340
|
+
* Set oscillation state
|
|
341
|
+
*/
|
|
342
|
+
setOscillation(toggle: boolean): Promise<boolean>;
|
|
343
|
+
/**
|
|
344
|
+
* Turn oscillation on
|
|
345
|
+
*/
|
|
346
|
+
setOscillationOn(): Promise<boolean>;
|
|
347
|
+
/**
|
|
348
|
+
* Turn oscillation off
|
|
349
|
+
*/
|
|
350
|
+
setOscillationOff(): Promise<boolean>;
|
|
311
351
|
/**
|
|
312
352
|
* Display device info
|
|
313
353
|
*/
|
|
@@ -1134,84 +1134,75 @@ class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1134
1134
|
this.speeds = Array.from({ length: 12 }, (_, i) => i + 1);
|
|
1135
1135
|
logger_1.logger.debug(`Initialized VeSyncTowerFan device: ${this.deviceName}`);
|
|
1136
1136
|
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Build API dictionary
|
|
1139
|
+
*/
|
|
1140
|
+
buildApiDict(method) {
|
|
1141
|
+
const head = helpers_1.Helpers.reqHeaderBypass();
|
|
1142
|
+
const body = helpers_1.Helpers.reqBody(this.manager, 'bypassV2');
|
|
1143
|
+
body.cid = this.cid;
|
|
1144
|
+
body.deviceId = this.cid;
|
|
1145
|
+
body.configModule = this.configModule;
|
|
1146
|
+
body.configModel = this.configModule;
|
|
1147
|
+
body.payload = {
|
|
1148
|
+
method: method,
|
|
1149
|
+
source: 'APP',
|
|
1150
|
+
data: {}
|
|
1151
|
+
};
|
|
1152
|
+
return [head, body];
|
|
1153
|
+
}
|
|
1137
1154
|
/**
|
|
1138
1155
|
* Get device details
|
|
1139
1156
|
*/
|
|
1140
1157
|
async getDetails() {
|
|
1141
|
-
var _a;
|
|
1142
1158
|
logger_1.logger.debug(`Getting details for device: ${this.deviceName}`);
|
|
1143
1159
|
const [head, body] = this.buildApiDict('getTowerFanStatus');
|
|
1144
|
-
if (!head || !body) {
|
|
1145
|
-
logger_1.logger.debug('Error building API request');
|
|
1146
|
-
return false;
|
|
1147
|
-
}
|
|
1148
1160
|
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
1149
|
-
if (!this.checkResponse([response, status], 'getDetails') || !response) {
|
|
1150
|
-
logger_1.logger.debug('Error getting
|
|
1161
|
+
if (!this.checkResponse([response, status], 'getDetails') || !(response === null || response === void 0 ? void 0 : response.result)) {
|
|
1162
|
+
logger_1.logger.debug('Error getting tower fan details');
|
|
1151
1163
|
this.connectionStatus = 'offline';
|
|
1152
1164
|
return false;
|
|
1153
1165
|
}
|
|
1154
|
-
const
|
|
1155
|
-
if (!
|
|
1166
|
+
const innerResponse = response.result;
|
|
1167
|
+
if (innerResponse.code !== 0 || !innerResponse.result) {
|
|
1168
|
+
logger_1.logger.debug('Error in inner response from tower fan');
|
|
1156
1169
|
this.connectionStatus = 'offline';
|
|
1157
|
-
logger_1.logger.debug('Error in inner result dict from purifier');
|
|
1158
1170
|
return false;
|
|
1159
1171
|
}
|
|
1160
|
-
|
|
1172
|
+
const deviceData = innerResponse.result;
|
|
1173
|
+
this.deviceStatus = deviceData.powerSwitch === 1 ? 'on' : 'off';
|
|
1161
1174
|
this.details = {
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1175
|
+
powerSwitch: deviceData.powerSwitch,
|
|
1176
|
+
workMode: deviceData.workMode,
|
|
1177
|
+
manualSpeedLevel: deviceData.manualSpeedLevel,
|
|
1178
|
+
fanSpeedLevel: deviceData.fanSpeedLevel,
|
|
1179
|
+
screenState: deviceData.screenState,
|
|
1180
|
+
screenSwitch: deviceData.screenSwitch,
|
|
1181
|
+
oscillationState: deviceData.oscillationState,
|
|
1182
|
+
oscillationSwitch: deviceData.oscillationSwitch,
|
|
1183
|
+
muteState: deviceData.muteState,
|
|
1184
|
+
muteSwitch: deviceData.muteSwitch,
|
|
1185
|
+
timerRemain: deviceData.timerRemain,
|
|
1186
|
+
temperature: deviceData.temperature || 0,
|
|
1187
|
+
humidity: deviceData.humidity || 0,
|
|
1188
|
+
thermalComfort: deviceData.thermalComfort,
|
|
1189
|
+
sleepPreference: deviceData.sleepPreference || {},
|
|
1190
|
+
scheduleCount: deviceData.scheduleCount,
|
|
1191
|
+
displayingType: deviceData.displayingType,
|
|
1192
|
+
errorCode: deviceData.errorCode
|
|
1171
1193
|
};
|
|
1172
|
-
if (innerResult.configuration) {
|
|
1173
|
-
this.buildConfigDict(innerResult.configuration);
|
|
1174
|
-
}
|
|
1175
|
-
this._lightDetection = innerResult.light_detection || false;
|
|
1176
|
-
this._lightDetectionState = innerResult.light_detection_state || false;
|
|
1177
1194
|
logger_1.logger.debug(`Successfully got details for device: ${this.deviceName}`);
|
|
1178
1195
|
return true;
|
|
1179
1196
|
}
|
|
1180
|
-
/**
|
|
1181
|
-
* Change fan speed
|
|
1182
|
-
*/
|
|
1183
|
-
async changeFanSpeed(speed) {
|
|
1184
|
-
if (!this.speeds.includes(speed)) {
|
|
1185
|
-
logger_1.logger.debug(`Invalid speed: ${speed}. Must be one of: ${this.speeds.join(', ')}`);
|
|
1186
|
-
return false;
|
|
1187
|
-
}
|
|
1188
|
-
const [head, body] = this.buildApiDict('setLevel');
|
|
1189
|
-
if (!head || !body) {
|
|
1190
|
-
return false;
|
|
1191
|
-
}
|
|
1192
|
-
body.payload.data = {
|
|
1193
|
-
levelIdx: 0,
|
|
1194
|
-
levelType: 'wind',
|
|
1195
|
-
manualSpeedLevel: speed
|
|
1196
|
-
};
|
|
1197
|
-
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
1198
|
-
const success = this.checkResponse([response, status], 'changeFanSpeed');
|
|
1199
|
-
if (success) {
|
|
1200
|
-
this.details.speed = speed;
|
|
1201
|
-
}
|
|
1202
|
-
else {
|
|
1203
|
-
logger_1.logger.debug('Error setting fan speed');
|
|
1204
|
-
}
|
|
1205
|
-
return success;
|
|
1206
|
-
}
|
|
1207
1197
|
/**
|
|
1208
1198
|
* Toggle device power
|
|
1209
1199
|
*/
|
|
1210
1200
|
async toggleSwitch(toggle) {
|
|
1211
|
-
|
|
1212
|
-
|
|
1201
|
+
if (typeof toggle !== 'boolean') {
|
|
1202
|
+
logger_1.logger.debug('Invalid toggle value for tower fan switch');
|
|
1213
1203
|
return false;
|
|
1214
1204
|
}
|
|
1205
|
+
const [head, body] = this.buildApiDict('setSwitch');
|
|
1215
1206
|
body.payload.data = {
|
|
1216
1207
|
powerSwitch: toggle ? 1 : 0,
|
|
1217
1208
|
switchIdx: 0
|
|
@@ -1222,7 +1213,7 @@ class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1222
1213
|
this.deviceStatus = toggle ? 'on' : 'off';
|
|
1223
1214
|
}
|
|
1224
1215
|
else {
|
|
1225
|
-
logger_1.logger.debug('Error toggling
|
|
1216
|
+
logger_1.logger.debug('Error toggling tower fan power');
|
|
1226
1217
|
}
|
|
1227
1218
|
return success;
|
|
1228
1219
|
}
|
|
@@ -1246,16 +1237,13 @@ class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1246
1237
|
async mode_toggle(mode) {
|
|
1247
1238
|
const validModes = this.towerModes.map(m => m.toLowerCase());
|
|
1248
1239
|
if (!validModes.includes(mode.toLowerCase())) {
|
|
1249
|
-
logger_1.logger.debug(`Invalid
|
|
1240
|
+
logger_1.logger.debug(`Invalid tower fan mode used - ${mode}`);
|
|
1250
1241
|
return false;
|
|
1251
1242
|
}
|
|
1252
1243
|
if (mode.toLowerCase() === 'off') {
|
|
1253
1244
|
return this.turnOff();
|
|
1254
1245
|
}
|
|
1255
1246
|
const [head, body] = this.buildApiDict('setTowerFanMode');
|
|
1256
|
-
if (!head || !body) {
|
|
1257
|
-
return false;
|
|
1258
|
-
}
|
|
1259
1247
|
body.deviceId = this.cid;
|
|
1260
1248
|
body.payload.data = {
|
|
1261
1249
|
workMode: mode
|
|
@@ -1263,10 +1251,34 @@ class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1263
1251
|
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
1264
1252
|
const success = this.checkResponse([response, status], 'mode_toggle');
|
|
1265
1253
|
if (success) {
|
|
1266
|
-
this.details.
|
|
1254
|
+
this.details.workMode = mode;
|
|
1267
1255
|
}
|
|
1268
1256
|
else {
|
|
1269
|
-
logger_1.logger.debug('Error setting
|
|
1257
|
+
logger_1.logger.debug('Error setting tower fan mode');
|
|
1258
|
+
}
|
|
1259
|
+
return success;
|
|
1260
|
+
}
|
|
1261
|
+
/**
|
|
1262
|
+
* Change fan speed
|
|
1263
|
+
*/
|
|
1264
|
+
async changeFanSpeed(speed) {
|
|
1265
|
+
if (!this.speeds.includes(speed)) {
|
|
1266
|
+
logger_1.logger.debug(`Invalid speed: ${speed}. Must be one of: ${this.speeds.join(', ')}`);
|
|
1267
|
+
return false;
|
|
1268
|
+
}
|
|
1269
|
+
const [head, body] = this.buildApiDict('setLevel');
|
|
1270
|
+
body.payload.data = {
|
|
1271
|
+
levelIdx: 0,
|
|
1272
|
+
levelType: 'wind',
|
|
1273
|
+
manualSpeedLevel: speed
|
|
1274
|
+
};
|
|
1275
|
+
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
1276
|
+
const success = this.checkResponse([response, status], 'changeFanSpeed');
|
|
1277
|
+
if (success) {
|
|
1278
|
+
this.details.manualSpeedLevel = speed;
|
|
1279
|
+
}
|
|
1280
|
+
else {
|
|
1281
|
+
logger_1.logger.debug('Error setting fan speed');
|
|
1270
1282
|
}
|
|
1271
1283
|
return success;
|
|
1272
1284
|
}
|
|
@@ -1308,31 +1320,91 @@ class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1308
1320
|
* Get current speed
|
|
1309
1321
|
*/
|
|
1310
1322
|
get speed() {
|
|
1311
|
-
return this.details.
|
|
1323
|
+
return this.details.manualSpeedLevel || 0;
|
|
1312
1324
|
}
|
|
1313
1325
|
/**
|
|
1314
1326
|
* Get display status
|
|
1315
1327
|
*/
|
|
1316
1328
|
get displayState() {
|
|
1317
|
-
return this.details.
|
|
1329
|
+
return Boolean(this.details.screenState);
|
|
1318
1330
|
}
|
|
1319
1331
|
/**
|
|
1320
|
-
* Get
|
|
1332
|
+
* Get oscillation status
|
|
1321
1333
|
*/
|
|
1322
|
-
get
|
|
1323
|
-
return this.details.
|
|
1334
|
+
get oscillationState() {
|
|
1335
|
+
return Boolean(this.details.oscillationState);
|
|
1324
1336
|
}
|
|
1325
1337
|
/**
|
|
1326
|
-
* Get
|
|
1338
|
+
* Get mute status
|
|
1327
1339
|
*/
|
|
1328
|
-
get
|
|
1329
|
-
return this.details.
|
|
1340
|
+
get muteState() {
|
|
1341
|
+
return Boolean(this.details.muteState);
|
|
1330
1342
|
}
|
|
1331
1343
|
/**
|
|
1332
|
-
* Get timer status
|
|
1344
|
+
* Get timer status (in seconds)
|
|
1333
1345
|
*/
|
|
1334
1346
|
get timer() {
|
|
1335
|
-
return this.details.
|
|
1347
|
+
return this.details.timerRemain || 0;
|
|
1348
|
+
}
|
|
1349
|
+
/**
|
|
1350
|
+
* Get temperature (in tenths of a degree)
|
|
1351
|
+
*/
|
|
1352
|
+
get temperature() {
|
|
1353
|
+
return this.details.temperature || 0;
|
|
1354
|
+
}
|
|
1355
|
+
/**
|
|
1356
|
+
* Get humidity percentage
|
|
1357
|
+
*/
|
|
1358
|
+
get humidity() {
|
|
1359
|
+
return this.details.humidity || 0;
|
|
1360
|
+
}
|
|
1361
|
+
/**
|
|
1362
|
+
* Get thermal comfort level
|
|
1363
|
+
*/
|
|
1364
|
+
get thermalComfort() {
|
|
1365
|
+
return this.details.thermalComfort || 0;
|
|
1366
|
+
}
|
|
1367
|
+
/**
|
|
1368
|
+
* Get sleep preferences
|
|
1369
|
+
*/
|
|
1370
|
+
get sleepPreference() {
|
|
1371
|
+
return this.details.sleepPreference || {};
|
|
1372
|
+
}
|
|
1373
|
+
/**
|
|
1374
|
+
* Get schedule count
|
|
1375
|
+
*/
|
|
1376
|
+
get scheduleCount() {
|
|
1377
|
+
return this.details.scheduleCount || 0;
|
|
1378
|
+
}
|
|
1379
|
+
/**
|
|
1380
|
+
* Get error code
|
|
1381
|
+
*/
|
|
1382
|
+
get errorCode() {
|
|
1383
|
+
return this.details.errorCode || 0;
|
|
1384
|
+
}
|
|
1385
|
+
/**
|
|
1386
|
+
* Set oscillation state
|
|
1387
|
+
*/
|
|
1388
|
+
async setOscillation(toggle) {
|
|
1389
|
+
logger_1.logger.debug(`Setting oscillation to ${toggle ? 'on' : 'off'} for device: ${this.deviceName}`);
|
|
1390
|
+
const [head, body] = this.buildApiDict('setSwitch');
|
|
1391
|
+
body.payload.data = {
|
|
1392
|
+
oscillationSwitch: toggle ? 1 : 0
|
|
1393
|
+
};
|
|
1394
|
+
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
1395
|
+
return this.checkResponse([response, status], 'setOscillation');
|
|
1396
|
+
}
|
|
1397
|
+
/**
|
|
1398
|
+
* Turn oscillation on
|
|
1399
|
+
*/
|
|
1400
|
+
async setOscillationOn() {
|
|
1401
|
+
return this.setOscillation(true);
|
|
1402
|
+
}
|
|
1403
|
+
/**
|
|
1404
|
+
* Turn oscillation off
|
|
1405
|
+
*/
|
|
1406
|
+
async setOscillationOff() {
|
|
1407
|
+
return this.setOscillation(false);
|
|
1336
1408
|
}
|
|
1337
1409
|
/**
|
|
1338
1410
|
* Display device info
|
|
@@ -1340,14 +1412,26 @@ class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1340
1412
|
display() {
|
|
1341
1413
|
super.display();
|
|
1342
1414
|
const info = [
|
|
1415
|
+
['Mode: ', this.details.workMode || ''],
|
|
1343
1416
|
['Speed: ', this.speed],
|
|
1417
|
+
['Fan Speed Level: ', this.details.fanSpeedLevel || 0],
|
|
1344
1418
|
['Display: ', this.displayState],
|
|
1345
|
-
['
|
|
1346
|
-
['
|
|
1347
|
-
['
|
|
1419
|
+
['Display Switch: ', this.details.screenSwitch],
|
|
1420
|
+
['Oscillation: ', this.oscillationState],
|
|
1421
|
+
['Oscillation Switch: ', this.details.oscillationSwitch],
|
|
1422
|
+
['Mute: ', this.muteState],
|
|
1423
|
+
['Mute Switch: ', this.details.muteSwitch],
|
|
1424
|
+
['Timer: ', this.timer],
|
|
1425
|
+
['Temperature: ', this.temperature / 10, '°C'],
|
|
1426
|
+
['Humidity: ', this.humidity, '%'],
|
|
1427
|
+
['Thermal Comfort: ', this.thermalComfort],
|
|
1428
|
+
['Sleep Preference: ', JSON.stringify(this.sleepPreference)],
|
|
1429
|
+
['Schedule Count: ', this.scheduleCount],
|
|
1430
|
+
['Displaying Type: ', this.details.displayingType],
|
|
1431
|
+
['Error Code: ', this.errorCode]
|
|
1348
1432
|
];
|
|
1349
|
-
for (const [key, value] of info) {
|
|
1350
|
-
logger_1.logger.info(`${key.toString().padEnd(30, '.')} ${value}`);
|
|
1433
|
+
for (const [key, value, unit = ''] of info) {
|
|
1434
|
+
logger_1.logger.info(`${key.toString().padEnd(30, '.')} ${value}${unit}`);
|
|
1351
1435
|
}
|
|
1352
1436
|
}
|
|
1353
1437
|
}
|
package/package.json
CHANGED
package/src/lib/helpers.ts
CHANGED
|
@@ -58,7 +58,7 @@ export class Helpers {
|
|
|
58
58
|
/**
|
|
59
59
|
* Calculate MD5 hash
|
|
60
60
|
*/
|
|
61
|
-
static
|
|
61
|
+
static hashPassword(text: string): string {
|
|
62
62
|
return crypto.createHash('md5').update(text).digest('hex');
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -302,7 +302,7 @@ export class Helpers {
|
|
|
302
302
|
/**
|
|
303
303
|
* Calculate MD5 hash
|
|
304
304
|
*/
|
|
305
|
-
static
|
|
305
|
+
static md5(text: string): string {
|
|
306
306
|
return crypto.createHash('md5').update(text).digest('hex');
|
|
307
307
|
}
|
|
308
308
|
}
|
package/src/lib/vesyncFanImpl.ts
CHANGED
|
@@ -1391,16 +1391,30 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1391
1391
|
logger.debug(`Initialized VeSyncTowerFan device: ${this.deviceName}`);
|
|
1392
1392
|
}
|
|
1393
1393
|
|
|
1394
|
+
/**
|
|
1395
|
+
* Build API dictionary
|
|
1396
|
+
*/
|
|
1397
|
+
protected buildApiDict(method: string): [Record<string, any>, Record<string, any>] {
|
|
1398
|
+
const head = Helpers.reqHeaderBypass();
|
|
1399
|
+
const body = Helpers.reqBody(this.manager, 'bypassV2');
|
|
1400
|
+
body.cid = this.cid;
|
|
1401
|
+
body.deviceId = this.cid;
|
|
1402
|
+
body.configModule = this.configModule;
|
|
1403
|
+
body.configModel = this.configModule;
|
|
1404
|
+
body.payload = {
|
|
1405
|
+
method: method,
|
|
1406
|
+
source: 'APP',
|
|
1407
|
+
data: {}
|
|
1408
|
+
};
|
|
1409
|
+
return [head, body];
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1394
1412
|
/**
|
|
1395
1413
|
* Get device details
|
|
1396
1414
|
*/
|
|
1397
1415
|
async getDetails(): Promise<Boolean> {
|
|
1398
1416
|
logger.debug(`Getting details for device: ${this.deviceName}`);
|
|
1399
1417
|
const [head, body] = this.buildApiDict('getTowerFanStatus');
|
|
1400
|
-
if (!head || !body) {
|
|
1401
|
-
logger.debug('Error building API request');
|
|
1402
|
-
return false;
|
|
1403
|
-
}
|
|
1404
1418
|
|
|
1405
1419
|
const [response, status] = await this.callApi(
|
|
1406
1420
|
'/cloud/v2/deviceManaged/bypassV2',
|
|
@@ -1409,88 +1423,56 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1409
1423
|
head
|
|
1410
1424
|
);
|
|
1411
1425
|
|
|
1412
|
-
if (!this.checkResponse([response, status], 'getDetails') || !response) {
|
|
1413
|
-
logger.debug('Error getting
|
|
1426
|
+
if (!this.checkResponse([response, status], 'getDetails') || !response?.result) {
|
|
1427
|
+
logger.debug('Error getting tower fan details');
|
|
1414
1428
|
this.connectionStatus = 'offline';
|
|
1415
1429
|
return false;
|
|
1416
1430
|
}
|
|
1417
1431
|
|
|
1418
|
-
const
|
|
1419
|
-
if (!
|
|
1432
|
+
const innerResponse = response.result;
|
|
1433
|
+
if (innerResponse.code !== 0 || !innerResponse.result) {
|
|
1434
|
+
logger.debug('Error in inner response from tower fan');
|
|
1420
1435
|
this.connectionStatus = 'offline';
|
|
1421
|
-
logger.debug('Error in inner result dict from purifier');
|
|
1422
1436
|
return false;
|
|
1423
1437
|
}
|
|
1424
1438
|
|
|
1425
|
-
|
|
1439
|
+
const deviceData = innerResponse.result;
|
|
1440
|
+
this.deviceStatus = deviceData.powerSwitch === 1 ? 'on' : 'off';
|
|
1426
1441
|
this.details = {
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1442
|
+
powerSwitch: deviceData.powerSwitch,
|
|
1443
|
+
workMode: deviceData.workMode,
|
|
1444
|
+
manualSpeedLevel: deviceData.manualSpeedLevel,
|
|
1445
|
+
fanSpeedLevel: deviceData.fanSpeedLevel,
|
|
1446
|
+
screenState: deviceData.screenState,
|
|
1447
|
+
screenSwitch: deviceData.screenSwitch,
|
|
1448
|
+
oscillationState: deviceData.oscillationState,
|
|
1449
|
+
oscillationSwitch: deviceData.oscillationSwitch,
|
|
1450
|
+
muteState: deviceData.muteState,
|
|
1451
|
+
muteSwitch: deviceData.muteSwitch,
|
|
1452
|
+
timerRemain: deviceData.timerRemain,
|
|
1453
|
+
temperature: deviceData.temperature || 0,
|
|
1454
|
+
humidity: deviceData.humidity || 0,
|
|
1455
|
+
thermalComfort: deviceData.thermalComfort,
|
|
1456
|
+
sleepPreference: deviceData.sleepPreference || {},
|
|
1457
|
+
scheduleCount: deviceData.scheduleCount,
|
|
1458
|
+
displayingType: deviceData.displayingType,
|
|
1459
|
+
errorCode: deviceData.errorCode
|
|
1436
1460
|
};
|
|
1437
1461
|
|
|
1438
|
-
if (innerResult.configuration) {
|
|
1439
|
-
this.buildConfigDict(innerResult.configuration);
|
|
1440
|
-
}
|
|
1441
|
-
|
|
1442
|
-
this._lightDetection = innerResult.light_detection || false;
|
|
1443
|
-
this._lightDetectionState = innerResult.light_detection_state || false;
|
|
1444
|
-
|
|
1445
1462
|
logger.debug(`Successfully got details for device: ${this.deviceName}`);
|
|
1446
1463
|
return true;
|
|
1447
1464
|
}
|
|
1448
1465
|
|
|
1449
|
-
/**
|
|
1450
|
-
* Change fan speed
|
|
1451
|
-
*/
|
|
1452
|
-
async changeFanSpeed(speed: number): Promise<boolean> {
|
|
1453
|
-
if (!this.speeds.includes(speed)) {
|
|
1454
|
-
logger.debug(`Invalid speed: ${speed}. Must be one of: ${this.speeds.join(', ')}`);
|
|
1455
|
-
return false;
|
|
1456
|
-
}
|
|
1457
|
-
|
|
1458
|
-
const [head, body] = this.buildApiDict('setLevel');
|
|
1459
|
-
if (!head || !body) {
|
|
1460
|
-
return false;
|
|
1461
|
-
}
|
|
1462
|
-
|
|
1463
|
-
body.payload.data = {
|
|
1464
|
-
levelIdx: 0,
|
|
1465
|
-
levelType: 'wind',
|
|
1466
|
-
manualSpeedLevel: speed
|
|
1467
|
-
};
|
|
1468
|
-
|
|
1469
|
-
const [response, status] = await this.callApi(
|
|
1470
|
-
'/cloud/v2/deviceManaged/bypassV2',
|
|
1471
|
-
'post',
|
|
1472
|
-
body,
|
|
1473
|
-
head
|
|
1474
|
-
);
|
|
1475
|
-
|
|
1476
|
-
const success = this.checkResponse([response, status], 'changeFanSpeed');
|
|
1477
|
-
if (success) {
|
|
1478
|
-
this.details.speed = speed;
|
|
1479
|
-
} else {
|
|
1480
|
-
logger.debug('Error setting fan speed');
|
|
1481
|
-
}
|
|
1482
|
-
return success;
|
|
1483
|
-
}
|
|
1484
|
-
|
|
1485
1466
|
/**
|
|
1486
1467
|
* Toggle device power
|
|
1487
1468
|
*/
|
|
1488
1469
|
async toggleSwitch(toggle: boolean): Promise<boolean> {
|
|
1489
|
-
|
|
1490
|
-
|
|
1470
|
+
if (typeof toggle !== 'boolean') {
|
|
1471
|
+
logger.debug('Invalid toggle value for tower fan switch');
|
|
1491
1472
|
return false;
|
|
1492
1473
|
}
|
|
1493
1474
|
|
|
1475
|
+
const [head, body] = this.buildApiDict('setSwitch');
|
|
1494
1476
|
body.payload.data = {
|
|
1495
1477
|
powerSwitch: toggle ? 1 : 0,
|
|
1496
1478
|
switchIdx: 0
|
|
@@ -1507,7 +1489,7 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1507
1489
|
if (success) {
|
|
1508
1490
|
this.deviceStatus = toggle ? 'on' : 'off';
|
|
1509
1491
|
} else {
|
|
1510
|
-
logger.debug('Error toggling
|
|
1492
|
+
logger.debug('Error toggling tower fan power');
|
|
1511
1493
|
}
|
|
1512
1494
|
return success;
|
|
1513
1495
|
}
|
|
@@ -1534,7 +1516,7 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1534
1516
|
async mode_toggle(mode: string): Promise<boolean> {
|
|
1535
1517
|
const validModes = this.towerModes.map(m => m.toLowerCase());
|
|
1536
1518
|
if (!validModes.includes(mode.toLowerCase())) {
|
|
1537
|
-
logger.debug(`Invalid
|
|
1519
|
+
logger.debug(`Invalid tower fan mode used - ${mode}`);
|
|
1538
1520
|
return false;
|
|
1539
1521
|
}
|
|
1540
1522
|
|
|
@@ -1543,10 +1525,6 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1543
1525
|
}
|
|
1544
1526
|
|
|
1545
1527
|
const [head, body] = this.buildApiDict('setTowerFanMode');
|
|
1546
|
-
if (!head || !body) {
|
|
1547
|
-
return false;
|
|
1548
|
-
}
|
|
1549
|
-
|
|
1550
1528
|
body.deviceId = this.cid;
|
|
1551
1529
|
body.payload.data = {
|
|
1552
1530
|
workMode: mode
|
|
@@ -1561,9 +1539,41 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1561
1539
|
|
|
1562
1540
|
const success = this.checkResponse([response, status], 'mode_toggle');
|
|
1563
1541
|
if (success) {
|
|
1564
|
-
this.details.
|
|
1542
|
+
this.details.workMode = mode;
|
|
1565
1543
|
} else {
|
|
1566
|
-
logger.debug('Error setting
|
|
1544
|
+
logger.debug('Error setting tower fan mode');
|
|
1545
|
+
}
|
|
1546
|
+
return success;
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
/**
|
|
1550
|
+
* Change fan speed
|
|
1551
|
+
*/
|
|
1552
|
+
async changeFanSpeed(speed: number): Promise<boolean> {
|
|
1553
|
+
if (!this.speeds.includes(speed)) {
|
|
1554
|
+
logger.debug(`Invalid speed: ${speed}. Must be one of: ${this.speeds.join(', ')}`);
|
|
1555
|
+
return false;
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
const [head, body] = this.buildApiDict('setLevel');
|
|
1559
|
+
body.payload.data = {
|
|
1560
|
+
levelIdx: 0,
|
|
1561
|
+
levelType: 'wind',
|
|
1562
|
+
manualSpeedLevel: speed
|
|
1563
|
+
};
|
|
1564
|
+
|
|
1565
|
+
const [response, status] = await this.callApi(
|
|
1566
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
1567
|
+
'post',
|
|
1568
|
+
body,
|
|
1569
|
+
head
|
|
1570
|
+
);
|
|
1571
|
+
|
|
1572
|
+
const success = this.checkResponse([response, status], 'changeFanSpeed');
|
|
1573
|
+
if (success) {
|
|
1574
|
+
this.details.manualSpeedLevel = speed;
|
|
1575
|
+
} else {
|
|
1576
|
+
logger.debug('Error setting fan speed');
|
|
1567
1577
|
}
|
|
1568
1578
|
return success;
|
|
1569
1579
|
}
|
|
@@ -1611,35 +1621,112 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1611
1621
|
* Get current speed
|
|
1612
1622
|
*/
|
|
1613
1623
|
get speed(): number {
|
|
1614
|
-
return this.details.
|
|
1624
|
+
return this.details.manualSpeedLevel || 0;
|
|
1615
1625
|
}
|
|
1616
1626
|
|
|
1617
1627
|
/**
|
|
1618
1628
|
* Get display status
|
|
1619
1629
|
*/
|
|
1620
1630
|
get displayState(): boolean {
|
|
1621
|
-
return this.details.
|
|
1631
|
+
return Boolean(this.details.screenState);
|
|
1622
1632
|
}
|
|
1623
1633
|
|
|
1624
1634
|
/**
|
|
1625
|
-
* Get
|
|
1635
|
+
* Get oscillation status
|
|
1626
1636
|
*/
|
|
1627
|
-
|
|
1628
|
-
return this.details.
|
|
1637
|
+
get oscillationState(): boolean {
|
|
1638
|
+
return Boolean(this.details.oscillationState);
|
|
1629
1639
|
}
|
|
1630
1640
|
|
|
1631
1641
|
/**
|
|
1632
|
-
* Get
|
|
1642
|
+
* Get mute status
|
|
1633
1643
|
*/
|
|
1634
|
-
get
|
|
1635
|
-
return this.details.
|
|
1644
|
+
get muteState(): boolean {
|
|
1645
|
+
return Boolean(this.details.muteState);
|
|
1636
1646
|
}
|
|
1637
1647
|
|
|
1638
1648
|
/**
|
|
1639
|
-
* Get timer status
|
|
1649
|
+
* Get timer status (in seconds)
|
|
1640
1650
|
*/
|
|
1641
1651
|
get timer(): number {
|
|
1642
|
-
return this.details.
|
|
1652
|
+
return this.details.timerRemain || 0;
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
/**
|
|
1656
|
+
* Get temperature (in tenths of a degree)
|
|
1657
|
+
*/
|
|
1658
|
+
get temperature(): number {
|
|
1659
|
+
return this.details.temperature || 0;
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
/**
|
|
1663
|
+
* Get humidity percentage
|
|
1664
|
+
*/
|
|
1665
|
+
get humidity(): number {
|
|
1666
|
+
return this.details.humidity || 0;
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
/**
|
|
1670
|
+
* Get thermal comfort level
|
|
1671
|
+
*/
|
|
1672
|
+
get thermalComfort(): number {
|
|
1673
|
+
return this.details.thermalComfort || 0;
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
/**
|
|
1677
|
+
* Get sleep preferences
|
|
1678
|
+
*/
|
|
1679
|
+
get sleepPreference(): Record<string, any> {
|
|
1680
|
+
return this.details.sleepPreference || {};
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
/**
|
|
1684
|
+
* Get schedule count
|
|
1685
|
+
*/
|
|
1686
|
+
get scheduleCount(): number {
|
|
1687
|
+
return this.details.scheduleCount || 0;
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
/**
|
|
1691
|
+
* Get error code
|
|
1692
|
+
*/
|
|
1693
|
+
get errorCode(): number {
|
|
1694
|
+
return this.details.errorCode || 0;
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
/**
|
|
1698
|
+
* Set oscillation state
|
|
1699
|
+
*/
|
|
1700
|
+
async setOscillation(toggle: boolean): Promise<boolean> {
|
|
1701
|
+
logger.debug(`Setting oscillation to ${toggle ? 'on' : 'off'} for device: ${this.deviceName}`);
|
|
1702
|
+
|
|
1703
|
+
const [head, body] = this.buildApiDict('setSwitch');
|
|
1704
|
+
body.payload.data = {
|
|
1705
|
+
oscillationSwitch: toggle ? 1 : 0
|
|
1706
|
+
};
|
|
1707
|
+
|
|
1708
|
+
const [response, status] = await this.callApi(
|
|
1709
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
1710
|
+
'post',
|
|
1711
|
+
body,
|
|
1712
|
+
head
|
|
1713
|
+
);
|
|
1714
|
+
|
|
1715
|
+
return this.checkResponse([response, status], 'setOscillation');
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
/**
|
|
1719
|
+
* Turn oscillation on
|
|
1720
|
+
*/
|
|
1721
|
+
async setOscillationOn(): Promise<boolean> {
|
|
1722
|
+
return this.setOscillation(true);
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
/**
|
|
1726
|
+
* Turn oscillation off
|
|
1727
|
+
*/
|
|
1728
|
+
async setOscillationOff(): Promise<boolean> {
|
|
1729
|
+
return this.setOscillation(false);
|
|
1643
1730
|
}
|
|
1644
1731
|
|
|
1645
1732
|
/**
|
|
@@ -1648,15 +1735,27 @@ export class VeSyncTowerFan extends VeSyncAirBaseV2 {
|
|
|
1648
1735
|
override display(): void {
|
|
1649
1736
|
super.display();
|
|
1650
1737
|
const info = [
|
|
1738
|
+
['Mode: ', this.details.workMode || ''],
|
|
1651
1739
|
['Speed: ', this.speed],
|
|
1740
|
+
['Fan Speed Level: ', this.details.fanSpeedLevel || 0],
|
|
1652
1741
|
['Display: ', this.displayState],
|
|
1653
|
-
['
|
|
1654
|
-
['
|
|
1655
|
-
['
|
|
1742
|
+
['Display Switch: ', this.details.screenSwitch],
|
|
1743
|
+
['Oscillation: ', this.oscillationState],
|
|
1744
|
+
['Oscillation Switch: ', this.details.oscillationSwitch],
|
|
1745
|
+
['Mute: ', this.muteState],
|
|
1746
|
+
['Mute Switch: ', this.details.muteSwitch],
|
|
1747
|
+
['Timer: ', this.timer],
|
|
1748
|
+
['Temperature: ', this.temperature / 10, '°C'],
|
|
1749
|
+
['Humidity: ', this.humidity, '%'],
|
|
1750
|
+
['Thermal Comfort: ', this.thermalComfort],
|
|
1751
|
+
['Sleep Preference: ', JSON.stringify(this.sleepPreference)],
|
|
1752
|
+
['Schedule Count: ', this.scheduleCount],
|
|
1753
|
+
['Displaying Type: ', this.details.displayingType],
|
|
1754
|
+
['Error Code: ', this.errorCode]
|
|
1656
1755
|
];
|
|
1657
1756
|
|
|
1658
|
-
for (const [key, value] of info) {
|
|
1659
|
-
logger.info(`${key.toString().padEnd(30, '.')} ${value}`);
|
|
1757
|
+
for (const [key, value, unit = ''] of info) {
|
|
1758
|
+
logger.info(`${key.toString().padEnd(30, '.')} ${value}${unit}`);
|
|
1660
1759
|
}
|
|
1661
1760
|
}
|
|
1662
1761
|
}
|