tsvesync 1.3.7 → 1.3.9
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/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/dist/lib/fans/airBaseV2.d.ts +8 -10
- package/dist/lib/fans/airBaseV2.js +63 -67
- package/dist/lib/vesyncSwitchImpl.js +15 -15
- package/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/lib/fans/airBaseV2.ts +65 -71
- package/src/lib/vesyncSwitchImpl.ts +16 -16
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { VeSync } from './lib/vesync';
|
|
|
2
2
|
export { VeSyncAirBypass } from './lib/vesyncFanImpl';
|
|
3
3
|
export { VeSyncOutlet7A, VeSyncOutlet10A, VeSyncOutlet15A, VeSyncOutdoorPlug } from './lib/vesyncOutletImpl';
|
|
4
4
|
export { VeSyncBulb } from './lib/vesyncBulb';
|
|
5
|
-
export { VeSyncWallSwitch } from './lib/vesyncSwitchImpl';
|
|
5
|
+
export { VeSyncWallSwitch, VeSyncDimmerSwitch } from './lib/vesyncSwitchImpl';
|
|
6
6
|
export { VeSyncBaseDevice } from './lib/vesyncBaseDevice';
|
|
7
7
|
export { Helpers, setApiBaseUrl } from './lib/helpers';
|
|
8
8
|
export { CREDENTIAL_ERROR_CODES, CROSS_REGION_ERROR_CODES, isCredentialError, isCrossRegionError } from './lib/constants';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.decodeJwtTimestamps = exports.isCrossRegionError = exports.isCredentialError = exports.CROSS_REGION_ERROR_CODES = exports.CREDENTIAL_ERROR_CODES = exports.setApiBaseUrl = exports.Helpers = exports.VeSyncBaseDevice = exports.VeSyncWallSwitch = exports.VeSyncBulb = exports.VeSyncOutdoorPlug = exports.VeSyncOutlet15A = exports.VeSyncOutlet10A = exports.VeSyncOutlet7A = exports.VeSyncAirBypass = exports.VeSync = void 0;
|
|
3
|
+
exports.decodeJwtTimestamps = exports.isCrossRegionError = exports.isCredentialError = exports.CROSS_REGION_ERROR_CODES = exports.CREDENTIAL_ERROR_CODES = exports.setApiBaseUrl = exports.Helpers = exports.VeSyncBaseDevice = exports.VeSyncDimmerSwitch = exports.VeSyncWallSwitch = exports.VeSyncBulb = exports.VeSyncOutdoorPlug = exports.VeSyncOutlet15A = exports.VeSyncOutlet10A = exports.VeSyncOutlet7A = exports.VeSyncAirBypass = exports.VeSync = void 0;
|
|
4
4
|
// Export main VeSync manager class
|
|
5
5
|
var vesync_1 = require("./lib/vesync");
|
|
6
6
|
Object.defineProperty(exports, "VeSync", { enumerable: true, get: function () { return vesync_1.VeSync; } });
|
|
@@ -16,6 +16,7 @@ var vesyncBulb_1 = require("./lib/vesyncBulb");
|
|
|
16
16
|
Object.defineProperty(exports, "VeSyncBulb", { enumerable: true, get: function () { return vesyncBulb_1.VeSyncBulb; } });
|
|
17
17
|
var vesyncSwitchImpl_1 = require("./lib/vesyncSwitchImpl");
|
|
18
18
|
Object.defineProperty(exports, "VeSyncWallSwitch", { enumerable: true, get: function () { return vesyncSwitchImpl_1.VeSyncWallSwitch; } });
|
|
19
|
+
Object.defineProperty(exports, "VeSyncDimmerSwitch", { enumerable: true, get: function () { return vesyncSwitchImpl_1.VeSyncDimmerSwitch; } });
|
|
19
20
|
// Export base device class
|
|
20
21
|
var vesyncBaseDevice_1 = require("./lib/vesyncBaseDevice");
|
|
21
22
|
Object.defineProperty(exports, "VeSyncBaseDevice", { enumerable: true, get: function () { return vesyncBaseDevice_1.VeSyncBaseDevice; } });
|
|
@@ -30,10 +30,9 @@ export declare class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
30
30
|
action: string;
|
|
31
31
|
} | null);
|
|
32
32
|
/**
|
|
33
|
-
* Check response for
|
|
34
|
-
* These devices return success at API level but may have inner errors
|
|
33
|
+
* Check response for bypassV2 purifiers that surface nested result codes.
|
|
35
34
|
*/
|
|
36
|
-
protected
|
|
35
|
+
protected checkV2Response(response: any, status: number, method: string): boolean;
|
|
37
36
|
/**
|
|
38
37
|
* Get device details
|
|
39
38
|
*/
|
|
@@ -43,24 +42,23 @@ export declare class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
43
42
|
*/
|
|
44
43
|
protected buildPurifierDict(devDict: Record<string, any>): void;
|
|
45
44
|
/**
|
|
46
|
-
*
|
|
47
|
-
* @returns true if this is a LAP-V102S or LAP-V201S device
|
|
45
|
+
* Determine whether this purifier requires the powerSwitch payload and nested response handling.
|
|
48
46
|
*/
|
|
49
|
-
private
|
|
47
|
+
private requiresPowerSwitchPayload;
|
|
50
48
|
/**
|
|
51
|
-
* Override turn on
|
|
49
|
+
* Override turn on to use the powerSwitch payload required by bypassV2 purifiers.
|
|
52
50
|
*/
|
|
53
51
|
turnOn(): Promise<boolean>;
|
|
54
52
|
/**
|
|
55
|
-
* Override turn off
|
|
53
|
+
* Override turn off to use the powerSwitch payload required by bypassV2 purifiers.
|
|
56
54
|
*/
|
|
57
55
|
turnOff(): Promise<boolean>;
|
|
58
56
|
/**
|
|
59
|
-
* Override setMode
|
|
57
|
+
* Override setMode to send workMode payloads for bypassV2 purifiers.
|
|
60
58
|
*/
|
|
61
59
|
setMode(mode: string): Promise<boolean>;
|
|
62
60
|
/**
|
|
63
|
-
* Override changeFanSpeed
|
|
61
|
+
* Override changeFanSpeed to use manualSpeedLevel for bypassV2 purifiers.
|
|
64
62
|
*/
|
|
65
63
|
changeFanSpeed(speed: number): Promise<boolean>;
|
|
66
64
|
/**
|
|
@@ -46,26 +46,21 @@ class VeSyncAirBaseV2 extends airBypass_1.VeSyncAirBypass {
|
|
|
46
46
|
this._timer = value;
|
|
47
47
|
}
|
|
48
48
|
/**
|
|
49
|
-
* Check response for
|
|
50
|
-
* These devices return success at API level but may have inner errors
|
|
49
|
+
* Check response for bypassV2 purifiers that surface nested result codes.
|
|
51
50
|
*/
|
|
52
|
-
|
|
53
|
-
// First check basic response
|
|
51
|
+
checkV2Response(response, status, method) {
|
|
52
|
+
// First check basic response structure
|
|
54
53
|
if (!this.checkResponse([response, status], method)) {
|
|
55
54
|
return false;
|
|
56
55
|
}
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return true; // Not a Vital series device, standard check is enough
|
|
56
|
+
// Only apply extended handling to bypassV2 purifiers (Vital/Everest)
|
|
57
|
+
if (!this.requiresPowerSwitchPayload()) {
|
|
58
|
+
return true;
|
|
61
59
|
}
|
|
62
|
-
//
|
|
60
|
+
// These devices frequently succeed with a nested non-zero code
|
|
63
61
|
if (response.result && response.result.code !== undefined && response.result.code !== 0) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
logger_1.logger.debug(`Vital series device ${this.deviceName} returned inner code ${response.result.code} for ${method}`);
|
|
67
|
-
logger_1.logger.debug('This is normal for Vital series devices - proceeding with operation');
|
|
68
|
-
// Keep the device online despite inner error
|
|
62
|
+
logger_1.logger.debug(`${this.deviceName} returned inner code ${response.result.code} for ${method}`);
|
|
63
|
+
logger_1.logger.debug('BypassV2 purifier reports non-zero inner code but request still succeeded');
|
|
69
64
|
this.connectionStatus = 'online';
|
|
70
65
|
return true;
|
|
71
66
|
}
|
|
@@ -79,22 +74,20 @@ class VeSyncAirBaseV2 extends airBypass_1.VeSyncAirBypass {
|
|
|
79
74
|
logger_1.logger.debug(`Getting details for device: ${this.deviceName}`);
|
|
80
75
|
const [head, body] = this.buildApiDict('getPurifierStatus');
|
|
81
76
|
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
82
|
-
|
|
83
|
-
const isVitalSeries = this.deviceType.includes('LAP-V102S') || this.deviceType.includes('LAP-V201S');
|
|
77
|
+
const needsV2Handling = this.requiresPowerSwitchPayload();
|
|
84
78
|
// First check the outer response
|
|
85
79
|
if (!response || status !== 200) {
|
|
86
80
|
logger_1.logger.debug(`Error getting purifier details for ${this.deviceName}: Invalid response`);
|
|
87
81
|
this.connectionStatus = 'offline';
|
|
88
82
|
return false;
|
|
89
83
|
}
|
|
90
|
-
// For
|
|
91
|
-
|
|
92
|
-
if (isVitalSeries && response.result) {
|
|
84
|
+
// For bypassV2 purifier families the API nests the result and may surface non-zero codes
|
|
85
|
+
if (needsV2Handling && response.result) {
|
|
93
86
|
// Check if we have a valid getPurifierStatus response
|
|
94
87
|
if (response.code === 0 && ((_a = response.result) === null || _a === void 0 ? void 0 : _a.result)) {
|
|
95
88
|
const statusResponse = response.result.result;
|
|
96
89
|
// If we have valid status data, use it regardless of inner result code
|
|
97
|
-
logger_1.logger.debug(`Using status data for
|
|
90
|
+
logger_1.logger.debug(`Using nested status data for bypassV2 purifier: ${this.deviceName}`);
|
|
98
91
|
this.buildPurifierDict(statusResponse);
|
|
99
92
|
if (statusResponse.configuration) {
|
|
100
93
|
this.buildConfigDict(statusResponse.configuration);
|
|
@@ -104,7 +97,7 @@ class VeSyncAirBaseV2 extends airBypass_1.VeSyncAirBypass {
|
|
|
104
97
|
return true;
|
|
105
98
|
}
|
|
106
99
|
}
|
|
107
|
-
// Standard processing for non-
|
|
100
|
+
// Standard processing for non-bypassV2 devices or when no status data is available
|
|
108
101
|
if (!this.checkResponse([response, status], 'getDetails') || !(response === null || response === void 0 ? void 0 : response.result)) {
|
|
109
102
|
logger_1.logger.debug('Error getting purifier details');
|
|
110
103
|
this.connectionStatus = 'offline';
|
|
@@ -133,7 +126,9 @@ class VeSyncAirBaseV2 extends airBypass_1.VeSyncAirBypass {
|
|
|
133
126
|
this.enabled = powerSwitch;
|
|
134
127
|
this.deviceStatus = powerSwitch ? 'on' : 'off';
|
|
135
128
|
this.mode = (_b = devDict.workMode) !== null && _b !== void 0 ? _b : 'manual';
|
|
136
|
-
|
|
129
|
+
const reportedFanSpeed = (_c = devDict.fanSpeedLevel) !== null && _c !== void 0 ? _c : 0;
|
|
130
|
+
const isAutoSentinel = reportedFanSpeed === 255;
|
|
131
|
+
this.speed = isAutoSentinel ? 0 : reportedFanSpeed;
|
|
137
132
|
this.setSpeedLevel = (_d = devDict.manualSpeedLevel) !== null && _d !== void 0 ? _d : 1;
|
|
138
133
|
// Parse filter life with proper fallback handling and logging
|
|
139
134
|
let filterLife = 0;
|
|
@@ -159,7 +154,11 @@ class VeSyncAirBaseV2 extends airBypass_1.VeSyncAirBypass {
|
|
|
159
154
|
light_detection_switch: Boolean((_g = devDict.lightDetectionSwitch) !== null && _g !== void 0 ? _g : 0),
|
|
160
155
|
environment_light_state: Boolean((_h = devDict.environmentLightState) !== null && _h !== void 0 ? _h : 0),
|
|
161
156
|
screen_switch: Boolean((_j = devDict.screenSwitch) !== null && _j !== void 0 ? _j : 0),
|
|
162
|
-
screenStatus: Boolean((_k = devDict.screenSwitch) !== null && _k !== void 0 ? _k : 0) ? 'on' : 'off'
|
|
157
|
+
screenStatus: Boolean((_k = devDict.screenSwitch) !== null && _k !== void 0 ? _k : 0) ? 'on' : 'off',
|
|
158
|
+
manualSpeedLevel: this.setSpeedLevel,
|
|
159
|
+
mode: this.mode,
|
|
160
|
+
speed: this.speed,
|
|
161
|
+
isAutoSentinel
|
|
163
162
|
};
|
|
164
163
|
if (this.hasFeature('air_quality')) {
|
|
165
164
|
this.details.air_quality_value = (_l = devDict.PM25) !== null && _l !== void 0 ? _l : 0;
|
|
@@ -186,29 +185,28 @@ class VeSyncAirBaseV2 extends airBypass_1.VeSyncAirBypass {
|
|
|
186
185
|
}
|
|
187
186
|
}
|
|
188
187
|
/**
|
|
189
|
-
*
|
|
190
|
-
* @returns true if this is a LAP-V102S or LAP-V201S device
|
|
188
|
+
* Determine whether this purifier requires the powerSwitch payload and nested response handling.
|
|
191
189
|
*/
|
|
192
|
-
|
|
193
|
-
|
|
190
|
+
requiresPowerSwitchPayload() {
|
|
191
|
+
const type = (this.deviceType || '').toUpperCase();
|
|
192
|
+
return type.startsWith('LAP-V') || type.startsWith('LAP-EL');
|
|
194
193
|
}
|
|
195
194
|
/**
|
|
196
|
-
* Override turn on
|
|
195
|
+
* Override turn on to use the powerSwitch payload required by bypassV2 purifiers.
|
|
197
196
|
*/
|
|
198
197
|
async turnOn() {
|
|
199
198
|
logger_1.logger.info(`Turning on device: ${this.deviceName}`);
|
|
200
199
|
const [head, body] = this.buildApiDict('setSwitch');
|
|
201
|
-
//
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
logger_1.logger.debug(`Using Vital series specific payload for ${this.deviceName}`);
|
|
200
|
+
// BypassV2 purifiers require powerSwitch toggles; others fall back to the base implementation
|
|
201
|
+
if (this.requiresPowerSwitchPayload()) {
|
|
202
|
+
logger_1.logger.debug(`Using bypassV2 power payload for ${this.deviceName}`);
|
|
205
203
|
body.payload.data = {
|
|
206
204
|
powerSwitch: 1,
|
|
207
205
|
switchIdx: 0
|
|
208
206
|
};
|
|
209
207
|
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
210
|
-
// Use
|
|
211
|
-
const success = this.
|
|
208
|
+
// Use bypassV2 response checking
|
|
209
|
+
const success = this.checkV2Response(response, status, 'turnOn');
|
|
212
210
|
if (success) {
|
|
213
211
|
this.deviceStatus = 'on';
|
|
214
212
|
// Force a details update to sync state
|
|
@@ -221,27 +219,26 @@ class VeSyncAirBaseV2 extends airBypass_1.VeSyncAirBypass {
|
|
|
221
219
|
return success;
|
|
222
220
|
}
|
|
223
221
|
else {
|
|
224
|
-
// Use parent implementation for non-
|
|
222
|
+
// Use parent implementation for non-bypassV2 models
|
|
225
223
|
return super.turnOn();
|
|
226
224
|
}
|
|
227
225
|
}
|
|
228
226
|
/**
|
|
229
|
-
* Override turn off
|
|
227
|
+
* Override turn off to use the powerSwitch payload required by bypassV2 purifiers.
|
|
230
228
|
*/
|
|
231
229
|
async turnOff() {
|
|
232
230
|
logger_1.logger.info(`Turning off device: ${this.deviceName}`);
|
|
233
231
|
const [head, body] = this.buildApiDict('setSwitch');
|
|
234
|
-
//
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
logger_1.logger.debug(`Using Vital series specific payload for ${this.deviceName}`);
|
|
232
|
+
// BypassV2 purifiers require powerSwitch toggles; others fall back to the base implementation
|
|
233
|
+
if (this.requiresPowerSwitchPayload()) {
|
|
234
|
+
logger_1.logger.debug(`Using bypassV2 power payload for ${this.deviceName}`);
|
|
238
235
|
body.payload.data = {
|
|
239
236
|
powerSwitch: 0,
|
|
240
237
|
switchIdx: 0
|
|
241
238
|
};
|
|
242
239
|
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
243
|
-
// Use
|
|
244
|
-
const success = this.
|
|
240
|
+
// Use bypassV2 response checking
|
|
241
|
+
const success = this.checkV2Response(response, status, 'turnOff');
|
|
245
242
|
if (success) {
|
|
246
243
|
this.deviceStatus = 'off';
|
|
247
244
|
// Force a details update to sync state
|
|
@@ -254,12 +251,12 @@ class VeSyncAirBaseV2 extends airBypass_1.VeSyncAirBypass {
|
|
|
254
251
|
return success;
|
|
255
252
|
}
|
|
256
253
|
else {
|
|
257
|
-
// Use parent implementation for non-
|
|
254
|
+
// Use parent implementation for non-bypassV2 models
|
|
258
255
|
return super.turnOff();
|
|
259
256
|
}
|
|
260
257
|
}
|
|
261
258
|
/**
|
|
262
|
-
* Override setMode
|
|
259
|
+
* Override setMode to send workMode payloads for bypassV2 purifiers.
|
|
263
260
|
*/
|
|
264
261
|
async setMode(mode) {
|
|
265
262
|
if (!this.modes.includes(mode)) {
|
|
@@ -272,16 +269,15 @@ class VeSyncAirBaseV2 extends airBypass_1.VeSyncAirBypass {
|
|
|
272
269
|
logger_1.logger.warn(`Auto mode not supported for ${this.deviceType}, using manual mode instead`);
|
|
273
270
|
return this.setMode('manual');
|
|
274
271
|
}
|
|
275
|
-
//
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
logger_1.logger.debug(`Using Vital series specific response handling for ${this.deviceName}`);
|
|
272
|
+
// BypassV2 purifiers need the workMode payload; other models use the base implementation
|
|
273
|
+
if (this.requiresPowerSwitchPayload()) {
|
|
274
|
+
logger_1.logger.debug(`Using bypassV2 mode payload for ${this.deviceName}`);
|
|
279
275
|
const [head, body] = this.buildApiDict('setPurifierMode');
|
|
280
276
|
body.payload.data = {
|
|
281
277
|
workMode: mode
|
|
282
278
|
};
|
|
283
279
|
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
284
|
-
const success = this.
|
|
280
|
+
const success = this.checkV2Response(response, status, 'setMode');
|
|
285
281
|
if (success) {
|
|
286
282
|
this.details.mode = mode;
|
|
287
283
|
this._mode = mode;
|
|
@@ -299,12 +295,12 @@ class VeSyncAirBaseV2 extends airBypass_1.VeSyncAirBypass {
|
|
|
299
295
|
}
|
|
300
296
|
}
|
|
301
297
|
else {
|
|
302
|
-
// Use parent implementation for non-
|
|
298
|
+
// Use parent implementation for non-bypassV2 models
|
|
303
299
|
return super.setMode(mode);
|
|
304
300
|
}
|
|
305
301
|
}
|
|
306
302
|
/**
|
|
307
|
-
* Override changeFanSpeed
|
|
303
|
+
* Override changeFanSpeed to use manualSpeedLevel for bypassV2 purifiers.
|
|
308
304
|
*/
|
|
309
305
|
async changeFanSpeed(speed) {
|
|
310
306
|
var _a;
|
|
@@ -315,17 +311,17 @@ class VeSyncAirBaseV2 extends airBypass_1.VeSyncAirBypass {
|
|
|
315
311
|
}
|
|
316
312
|
logger_1.logger.info(`Changing fan speed to ${speed} for device: ${this.deviceName}`);
|
|
317
313
|
const [head, body] = this.buildApiDict('setLevel');
|
|
318
|
-
// Specific handling for
|
|
319
|
-
if (this.
|
|
320
|
-
logger_1.logger.debug(`Using
|
|
321
|
-
// For
|
|
314
|
+
// Specific handling for bypassV2 devices
|
|
315
|
+
if (this.requiresPowerSwitchPayload()) {
|
|
316
|
+
logger_1.logger.debug(`Using bypassV2 speed payload for ${this.deviceName}`);
|
|
317
|
+
// For these devices, use levelIdx, levelType, and manualSpeedLevel per YAML spec
|
|
322
318
|
body.payload.data = {
|
|
323
319
|
levelIdx: 0,
|
|
324
320
|
levelType: 'wind',
|
|
325
321
|
manualSpeedLevel: speed
|
|
326
322
|
};
|
|
327
323
|
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
328
|
-
const success = this.
|
|
324
|
+
const success = this.checkV2Response(response, status, 'changeFanSpeed');
|
|
329
325
|
if (success) {
|
|
330
326
|
this.speed = speed;
|
|
331
327
|
this.details.manualSpeedLevel = speed;
|
|
@@ -343,7 +339,7 @@ class VeSyncAirBaseV2 extends airBypass_1.VeSyncAirBypass {
|
|
|
343
339
|
}
|
|
344
340
|
}
|
|
345
341
|
else {
|
|
346
|
-
// For non-
|
|
342
|
+
// For non-bypassV2 models, use id, level, mode, and type
|
|
347
343
|
body.payload.data = {
|
|
348
344
|
id: 0,
|
|
349
345
|
level: speed,
|
|
@@ -378,14 +374,14 @@ class VeSyncAirBaseV2 extends airBypass_1.VeSyncAirBypass {
|
|
|
378
374
|
};
|
|
379
375
|
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
380
376
|
// Use the appropriate response checking method based on device type
|
|
381
|
-
const success = this.
|
|
382
|
-
? this.
|
|
377
|
+
const success = this.requiresPowerSwitchPayload()
|
|
378
|
+
? this.checkV2Response(response, status, 'setAutoPreference')
|
|
383
379
|
: this.checkResponse([response, status], 'setAutoPreference');
|
|
384
380
|
if (success) {
|
|
385
381
|
this.details.auto_preference = preference;
|
|
386
382
|
this.details.auto_preference_type = preference;
|
|
387
|
-
// Force a details update to sync state for
|
|
388
|
-
if (this.
|
|
383
|
+
// Force a details update to sync state for bypassV2 purifiers
|
|
384
|
+
if (this.requiresPowerSwitchPayload()) {
|
|
389
385
|
setTimeout(() => {
|
|
390
386
|
this.getDetails().catch(e => {
|
|
391
387
|
logger_1.logger.debug(`Background state refresh failed: ${e}`);
|
|
@@ -405,13 +401,13 @@ class VeSyncAirBaseV2 extends airBypass_1.VeSyncAirBypass {
|
|
|
405
401
|
};
|
|
406
402
|
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
407
403
|
// Use the appropriate response checking method based on device type
|
|
408
|
-
const success = this.
|
|
409
|
-
? this.
|
|
404
|
+
const success = this.requiresPowerSwitchPayload()
|
|
405
|
+
? this.checkV2Response(response, status, 'setLightDetection')
|
|
410
406
|
: this.checkResponse([response, status], 'setLightDetection');
|
|
411
407
|
if (success) {
|
|
412
408
|
this.details.light_detection_switch = enabled;
|
|
413
|
-
// Force a details update to sync state for
|
|
414
|
-
if (this.
|
|
409
|
+
// Force a details update to sync state for bypassV2 purifiers
|
|
410
|
+
if (this.requiresPowerSwitchPayload()) {
|
|
415
411
|
setTimeout(() => {
|
|
416
412
|
this.getDetails().catch(e => {
|
|
417
413
|
logger_1.logger.debug(`Background state refresh failed: ${e}`);
|
|
@@ -486,8 +482,8 @@ class VeSyncAirBaseV2 extends airBypass_1.VeSyncAirBypass {
|
|
|
486
482
|
};
|
|
487
483
|
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
488
484
|
// Use the appropriate response checking method based on device type
|
|
489
|
-
const success = this.
|
|
490
|
-
? this.
|
|
485
|
+
const success = this.requiresPowerSwitchPayload()
|
|
486
|
+
? this.checkV2Response(response, status, 'setOscillation')
|
|
491
487
|
: this.checkResponse([response, status], 'setOscillation');
|
|
492
488
|
if (success) {
|
|
493
489
|
this.details.oscillationState = toggle;
|
|
@@ -22,7 +22,7 @@ class VeSyncWallSwitch extends vesyncSwitch_1.VeSyncSwitch {
|
|
|
22
22
|
logger_1.logger.debug(`Getting details for device: ${this.deviceName}`);
|
|
23
23
|
const body = {
|
|
24
24
|
...helpers_1.Helpers.reqBody(this.manager, 'devicedetail'),
|
|
25
|
-
uuid: this.
|
|
25
|
+
uuid: this.uuid,
|
|
26
26
|
method: 'devicedetail'
|
|
27
27
|
};
|
|
28
28
|
const [response, statusCode] = await this.callApi('/inwallswitch/v1/device/devicedetail', 'post', body, helpers_1.Helpers.reqHeaders(this.manager));
|
|
@@ -44,7 +44,7 @@ class VeSyncWallSwitch extends vesyncSwitch_1.VeSyncSwitch {
|
|
|
44
44
|
const body = {
|
|
45
45
|
...helpers_1.Helpers.reqBody(this.manager, 'devicedetail'),
|
|
46
46
|
method: 'configurations',
|
|
47
|
-
uuid: this.
|
|
47
|
+
uuid: this.uuid
|
|
48
48
|
};
|
|
49
49
|
const [response] = await this.callApi('/inwallswitch/v1/device/configurations', 'post', body, helpers_1.Helpers.reqHeaders(this.manager));
|
|
50
50
|
if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
|
|
@@ -63,7 +63,7 @@ class VeSyncWallSwitch extends vesyncSwitch_1.VeSyncSwitch {
|
|
|
63
63
|
const body = {
|
|
64
64
|
...helpers_1.Helpers.reqBody(this.manager, 'devicestatus'),
|
|
65
65
|
status: 'off',
|
|
66
|
-
uuid: this.
|
|
66
|
+
uuid: this.uuid
|
|
67
67
|
};
|
|
68
68
|
const [response] = await this.callApi('/inwallswitch/v1/device/devicestatus', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
|
|
69
69
|
if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
|
|
@@ -82,7 +82,7 @@ class VeSyncWallSwitch extends vesyncSwitch_1.VeSyncSwitch {
|
|
|
82
82
|
const body = {
|
|
83
83
|
...helpers_1.Helpers.reqBody(this.manager, 'devicestatus'),
|
|
84
84
|
status: 'on',
|
|
85
|
-
uuid: this.
|
|
85
|
+
uuid: this.uuid
|
|
86
86
|
};
|
|
87
87
|
const [response] = await this.callApi('/inwallswitch/v1/device/devicestatus', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
|
|
88
88
|
if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
|
|
@@ -114,7 +114,7 @@ class VeSyncDimmerSwitch extends vesyncSwitch_1.VeSyncSwitch {
|
|
|
114
114
|
logger_1.logger.debug(`Getting details for device: ${this.deviceName}`);
|
|
115
115
|
const body = {
|
|
116
116
|
...helpers_1.Helpers.reqBody(this.manager, 'devicedetail'),
|
|
117
|
-
uuid: this.
|
|
117
|
+
uuid: this.uuid,
|
|
118
118
|
method: 'devicedetail'
|
|
119
119
|
};
|
|
120
120
|
const [response, statusCode] = await this.callApi('/dimmer/v1/device/devicedetail', 'post', body, helpers_1.Helpers.reqHeaders(this.manager));
|
|
@@ -146,7 +146,7 @@ class VeSyncDimmerSwitch extends vesyncSwitch_1.VeSyncSwitch {
|
|
|
146
146
|
const body = {
|
|
147
147
|
...helpers_1.Helpers.reqBody(this.manager, 'devicedetail'),
|
|
148
148
|
method: 'configurations',
|
|
149
|
-
uuid: this.
|
|
149
|
+
uuid: this.uuid
|
|
150
150
|
};
|
|
151
151
|
const [response] = await this.callApi('/dimmer/v1/device/configurations', 'post', body, helpers_1.Helpers.reqHeaders(this.manager));
|
|
152
152
|
if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
|
|
@@ -165,7 +165,7 @@ class VeSyncDimmerSwitch extends vesyncSwitch_1.VeSyncSwitch {
|
|
|
165
165
|
const body = {
|
|
166
166
|
...helpers_1.Helpers.reqBody(this.manager, 'devicestatus'),
|
|
167
167
|
status: 'off',
|
|
168
|
-
uuid: this.
|
|
168
|
+
uuid: this.uuid
|
|
169
169
|
};
|
|
170
170
|
const [response] = await this.callApi('/dimmer/v1/device/devicestatus', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
|
|
171
171
|
if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
|
|
@@ -184,7 +184,7 @@ class VeSyncDimmerSwitch extends vesyncSwitch_1.VeSyncSwitch {
|
|
|
184
184
|
const body = {
|
|
185
185
|
...helpers_1.Helpers.reqBody(this.manager, 'devicestatus'),
|
|
186
186
|
status: 'on',
|
|
187
|
-
uuid: this.
|
|
187
|
+
uuid: this.uuid
|
|
188
188
|
};
|
|
189
189
|
const [response] = await this.callApi('/dimmer/v1/device/devicestatus', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
|
|
190
190
|
if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
|
|
@@ -206,8 +206,8 @@ class VeSyncDimmerSwitch extends vesyncSwitch_1.VeSyncSwitch {
|
|
|
206
206
|
logger_1.logger.debug(`Setting brightness to ${brightness} for device: ${this.deviceName}`);
|
|
207
207
|
const body = {
|
|
208
208
|
...helpers_1.Helpers.reqBody(this.manager, 'devicestatus'),
|
|
209
|
-
brightness
|
|
210
|
-
uuid: this.
|
|
209
|
+
brightness,
|
|
210
|
+
uuid: this.uuid
|
|
211
211
|
};
|
|
212
212
|
const [response] = await this.callApi('/dimmer/v1/device/updatebrightness', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
|
|
213
213
|
if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
|
|
@@ -231,7 +231,7 @@ class VeSyncDimmerSwitch extends vesyncSwitch_1.VeSyncSwitch {
|
|
|
231
231
|
blue: Math.round(blue)
|
|
232
232
|
},
|
|
233
233
|
status: 'on',
|
|
234
|
-
uuid: this.
|
|
234
|
+
uuid: this.uuid
|
|
235
235
|
};
|
|
236
236
|
const [response] = await this.callApi('/dimmer/v1/device/devicergbstatus', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
|
|
237
237
|
if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
|
|
@@ -251,7 +251,7 @@ class VeSyncDimmerSwitch extends vesyncSwitch_1.VeSyncSwitch {
|
|
|
251
251
|
const body = {
|
|
252
252
|
...helpers_1.Helpers.reqBody(this.manager, 'devicestatus'),
|
|
253
253
|
status: 'off',
|
|
254
|
-
uuid: this.
|
|
254
|
+
uuid: this.uuid
|
|
255
255
|
};
|
|
256
256
|
const [response] = await this.callApi('/dimmer/v1/device/devicergbstatus', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
|
|
257
257
|
if ((response === null || response === void 0 ? void 0 : response.code) === 0) {
|
|
@@ -269,7 +269,7 @@ class VeSyncDimmerSwitch extends vesyncSwitch_1.VeSyncSwitch {
|
|
|
269
269
|
logger_1.logger.debug(`Turning on RGB color for device: ${this.deviceName}`);
|
|
270
270
|
const body = {
|
|
271
271
|
...helpers_1.Helpers.reqBody(this.manager, 'devicestatus'),
|
|
272
|
-
uuid: this.
|
|
272
|
+
uuid: this.uuid,
|
|
273
273
|
status: 'on'
|
|
274
274
|
};
|
|
275
275
|
const [response] = await this.callApi('/dimmer/v1/device/devicergbstatus', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
|
|
@@ -288,7 +288,7 @@ class VeSyncDimmerSwitch extends vesyncSwitch_1.VeSyncSwitch {
|
|
|
288
288
|
logger_1.logger.debug(`Turning on indicator light for device: ${this.deviceName}`);
|
|
289
289
|
const body = {
|
|
290
290
|
...helpers_1.Helpers.reqBody(this.manager, 'devicestatus'),
|
|
291
|
-
uuid: this.
|
|
291
|
+
uuid: this.uuid,
|
|
292
292
|
status: 'on'
|
|
293
293
|
};
|
|
294
294
|
const [response] = await this.callApi('/dimmer/v1/device/indicatorlightstatus', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
|
|
@@ -307,7 +307,7 @@ class VeSyncDimmerSwitch extends vesyncSwitch_1.VeSyncSwitch {
|
|
|
307
307
|
logger_1.logger.debug(`Turning off indicator light for device: ${this.deviceName}`);
|
|
308
308
|
const body = {
|
|
309
309
|
...helpers_1.Helpers.reqBody(this.manager, 'devicestatus'),
|
|
310
|
-
uuid: this.
|
|
310
|
+
uuid: this.uuid,
|
|
311
311
|
status: 'off'
|
|
312
312
|
};
|
|
313
313
|
const [response] = await this.callApi('/dimmer/v1/device/indicatorlightstatus', 'put', body, helpers_1.Helpers.reqHeaders(this.manager));
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { VeSync } from './lib/vesync';
|
|
|
5
5
|
export { VeSyncAirBypass } from './lib/vesyncFanImpl';
|
|
6
6
|
export { VeSyncOutlet7A, VeSyncOutlet10A, VeSyncOutlet15A, VeSyncOutdoorPlug } from './lib/vesyncOutletImpl';
|
|
7
7
|
export { VeSyncBulb } from './lib/vesyncBulb';
|
|
8
|
-
export { VeSyncWallSwitch } from './lib/vesyncSwitchImpl';
|
|
8
|
+
export { VeSyncWallSwitch, VeSyncDimmerSwitch } from './lib/vesyncSwitchImpl';
|
|
9
9
|
|
|
10
10
|
// Export base device class
|
|
11
11
|
export { VeSyncBaseDevice } from './lib/vesyncBaseDevice';
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { VeSyncAirBypass } from './airBypass';
|
|
2
2
|
import { VeSync } from '../vesync';
|
|
3
|
-
import { Helpers } from '../helpers';
|
|
4
3
|
import { logger } from '../logger';
|
|
5
4
|
|
|
6
5
|
/**
|
|
@@ -55,29 +54,23 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
/**
|
|
58
|
-
* Check response for
|
|
59
|
-
* These devices return success at API level but may have inner errors
|
|
57
|
+
* Check response for bypassV2 purifiers that surface nested result codes.
|
|
60
58
|
*/
|
|
61
|
-
protected
|
|
62
|
-
// First check basic response
|
|
59
|
+
protected checkV2Response(response: any, status: number, method: string): boolean {
|
|
60
|
+
// First check basic response structure
|
|
63
61
|
if (!this.checkResponse([response, status], method)) {
|
|
64
62
|
return false;
|
|
65
63
|
}
|
|
66
64
|
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return true; // Not a Vital series device, standard check is enough
|
|
65
|
+
// Only apply extended handling to bypassV2 purifiers (Vital/Everest)
|
|
66
|
+
if (!this.requiresPowerSwitchPayload()) {
|
|
67
|
+
return true;
|
|
71
68
|
}
|
|
72
69
|
|
|
73
|
-
//
|
|
70
|
+
// These devices frequently succeed with a nested non-zero code
|
|
74
71
|
if (response.result && response.result.code !== undefined && response.result.code !== 0) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
logger.debug(`Vital series device ${this.deviceName} returned inner code ${response.result.code} for ${method}`);
|
|
78
|
-
logger.debug('This is normal for Vital series devices - proceeding with operation');
|
|
79
|
-
|
|
80
|
-
// Keep the device online despite inner error
|
|
72
|
+
logger.debug(`${this.deviceName} returned inner code ${response.result.code} for ${method}`);
|
|
73
|
+
logger.debug('BypassV2 purifier reports non-zero inner code but request still succeeded');
|
|
81
74
|
this.connectionStatus = 'online';
|
|
82
75
|
return true;
|
|
83
76
|
}
|
|
@@ -99,8 +92,7 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
99
92
|
head
|
|
100
93
|
);
|
|
101
94
|
|
|
102
|
-
|
|
103
|
-
const isVitalSeries = this.deviceType.includes('LAP-V102S') || this.deviceType.includes('LAP-V201S');
|
|
95
|
+
const needsV2Handling = this.requiresPowerSwitchPayload();
|
|
104
96
|
|
|
105
97
|
// First check the outer response
|
|
106
98
|
if (!response || status !== 200) {
|
|
@@ -109,15 +101,14 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
109
101
|
return false;
|
|
110
102
|
}
|
|
111
103
|
|
|
112
|
-
// For
|
|
113
|
-
|
|
114
|
-
if (isVitalSeries && response.result) {
|
|
104
|
+
// For bypassV2 purifier families the API nests the result and may surface non-zero codes
|
|
105
|
+
if (needsV2Handling && response.result) {
|
|
115
106
|
// Check if we have a valid getPurifierStatus response
|
|
116
107
|
if (response.code === 0 && response.result?.result) {
|
|
117
108
|
const statusResponse = response.result.result;
|
|
118
109
|
|
|
119
110
|
// If we have valid status data, use it regardless of inner result code
|
|
120
|
-
logger.debug(`Using status data for
|
|
111
|
+
logger.debug(`Using nested status data for bypassV2 purifier: ${this.deviceName}`);
|
|
121
112
|
this.buildPurifierDict(statusResponse);
|
|
122
113
|
if (statusResponse.configuration) {
|
|
123
114
|
this.buildConfigDict(statusResponse.configuration);
|
|
@@ -128,7 +119,7 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
128
119
|
}
|
|
129
120
|
}
|
|
130
121
|
|
|
131
|
-
// Standard processing for non-
|
|
122
|
+
// Standard processing for non-bypassV2 devices or when no status data is available
|
|
132
123
|
if (!this.checkResponse([response, status], 'getDetails') || !response?.result) {
|
|
133
124
|
logger.debug('Error getting purifier details');
|
|
134
125
|
this.connectionStatus = 'offline';
|
|
@@ -159,10 +150,12 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
159
150
|
this.enabled = powerSwitch;
|
|
160
151
|
this.deviceStatus = powerSwitch ? 'on' : 'off';
|
|
161
152
|
this.mode = devDict.workMode ?? 'manual';
|
|
162
|
-
|
|
163
|
-
|
|
153
|
+
|
|
154
|
+
const reportedFanSpeed = devDict.fanSpeedLevel ?? 0;
|
|
155
|
+
const isAutoSentinel = reportedFanSpeed === 255;
|
|
156
|
+
this.speed = isAutoSentinel ? 0 : reportedFanSpeed;
|
|
164
157
|
this.setSpeedLevel = devDict.manualSpeedLevel ?? 1;
|
|
165
|
-
|
|
158
|
+
|
|
166
159
|
// Parse filter life with proper fallback handling and logging
|
|
167
160
|
let filterLife = 0;
|
|
168
161
|
if (devDict.filterLifePercent !== undefined) {
|
|
@@ -186,7 +179,11 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
186
179
|
light_detection_switch: Boolean(devDict.lightDetectionSwitch ?? 0),
|
|
187
180
|
environment_light_state: Boolean(devDict.environmentLightState ?? 0),
|
|
188
181
|
screen_switch: Boolean(devDict.screenSwitch ?? 0),
|
|
189
|
-
screenStatus: Boolean(devDict.screenSwitch ?? 0) ? 'on' : 'off'
|
|
182
|
+
screenStatus: Boolean(devDict.screenSwitch ?? 0) ? 'on' : 'off',
|
|
183
|
+
manualSpeedLevel: this.setSpeedLevel,
|
|
184
|
+
mode: this.mode,
|
|
185
|
+
speed: this.speed,
|
|
186
|
+
isAutoSentinel
|
|
190
187
|
};
|
|
191
188
|
|
|
192
189
|
if (this.hasFeature('air_quality')) {
|
|
@@ -212,25 +209,24 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
212
209
|
}
|
|
213
210
|
|
|
214
211
|
/**
|
|
215
|
-
*
|
|
216
|
-
* @returns true if this is a LAP-V102S or LAP-V201S device
|
|
212
|
+
* Determine whether this purifier requires the powerSwitch payload and nested response handling.
|
|
217
213
|
*/
|
|
218
|
-
private
|
|
219
|
-
|
|
214
|
+
private requiresPowerSwitchPayload(): boolean {
|
|
215
|
+
const type = (this.deviceType || '').toUpperCase();
|
|
216
|
+
return type.startsWith('LAP-V') || type.startsWith('LAP-EL');
|
|
220
217
|
}
|
|
221
218
|
|
|
222
219
|
/**
|
|
223
|
-
* Override turn on
|
|
220
|
+
* Override turn on to use the powerSwitch payload required by bypassV2 purifiers.
|
|
224
221
|
*/
|
|
225
222
|
override async turnOn(): Promise<boolean> {
|
|
226
223
|
logger.info(`Turning on device: ${this.deviceName}`);
|
|
227
224
|
|
|
228
225
|
const [head, body] = this.buildApiDict('setSwitch');
|
|
229
226
|
|
|
230
|
-
//
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
logger.debug(`Using Vital series specific payload for ${this.deviceName}`);
|
|
227
|
+
// BypassV2 purifiers require powerSwitch toggles; others fall back to the base implementation
|
|
228
|
+
if (this.requiresPowerSwitchPayload()) {
|
|
229
|
+
logger.debug(`Using bypassV2 power payload for ${this.deviceName}`);
|
|
234
230
|
body.payload.data = {
|
|
235
231
|
powerSwitch: 1,
|
|
236
232
|
switchIdx: 0
|
|
@@ -243,8 +239,8 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
243
239
|
head
|
|
244
240
|
);
|
|
245
241
|
|
|
246
|
-
// Use
|
|
247
|
-
const success = this.
|
|
242
|
+
// Use bypassV2 response checking
|
|
243
|
+
const success = this.checkV2Response(response, status, 'turnOn');
|
|
248
244
|
if (success) {
|
|
249
245
|
this.deviceStatus = 'on';
|
|
250
246
|
|
|
@@ -257,23 +253,22 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
257
253
|
}
|
|
258
254
|
return success;
|
|
259
255
|
} else {
|
|
260
|
-
// Use parent implementation for non-
|
|
256
|
+
// Use parent implementation for non-bypassV2 models
|
|
261
257
|
return super.turnOn();
|
|
262
258
|
}
|
|
263
259
|
}
|
|
264
260
|
|
|
265
261
|
/**
|
|
266
|
-
* Override turn off
|
|
262
|
+
* Override turn off to use the powerSwitch payload required by bypassV2 purifiers.
|
|
267
263
|
*/
|
|
268
264
|
override async turnOff(): Promise<boolean> {
|
|
269
265
|
logger.info(`Turning off device: ${this.deviceName}`);
|
|
270
266
|
|
|
271
267
|
const [head, body] = this.buildApiDict('setSwitch');
|
|
272
268
|
|
|
273
|
-
//
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
logger.debug(`Using Vital series specific payload for ${this.deviceName}`);
|
|
269
|
+
// BypassV2 purifiers require powerSwitch toggles; others fall back to the base implementation
|
|
270
|
+
if (this.requiresPowerSwitchPayload()) {
|
|
271
|
+
logger.debug(`Using bypassV2 power payload for ${this.deviceName}`);
|
|
277
272
|
body.payload.data = {
|
|
278
273
|
powerSwitch: 0,
|
|
279
274
|
switchIdx: 0
|
|
@@ -286,8 +281,8 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
286
281
|
head
|
|
287
282
|
);
|
|
288
283
|
|
|
289
|
-
// Use
|
|
290
|
-
const success = this.
|
|
284
|
+
// Use bypassV2 response checking
|
|
285
|
+
const success = this.checkV2Response(response, status, 'turnOff');
|
|
291
286
|
if (success) {
|
|
292
287
|
this.deviceStatus = 'off';
|
|
293
288
|
|
|
@@ -300,13 +295,13 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
300
295
|
}
|
|
301
296
|
return success;
|
|
302
297
|
} else {
|
|
303
|
-
// Use parent implementation for non-
|
|
298
|
+
// Use parent implementation for non-bypassV2 models
|
|
304
299
|
return super.turnOff();
|
|
305
300
|
}
|
|
306
301
|
}
|
|
307
302
|
|
|
308
303
|
/**
|
|
309
|
-
* Override setMode
|
|
304
|
+
* Override setMode to send workMode payloads for bypassV2 purifiers.
|
|
310
305
|
*/
|
|
311
306
|
override async setMode(mode: string): Promise<boolean> {
|
|
312
307
|
if (!this.modes.includes(mode as any)) {
|
|
@@ -321,10 +316,9 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
321
316
|
return this.setMode('manual');
|
|
322
317
|
}
|
|
323
318
|
|
|
324
|
-
//
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
logger.debug(`Using Vital series specific response handling for ${this.deviceName}`);
|
|
319
|
+
// BypassV2 purifiers need the workMode payload; other models use the base implementation
|
|
320
|
+
if (this.requiresPowerSwitchPayload()) {
|
|
321
|
+
logger.debug(`Using bypassV2 mode payload for ${this.deviceName}`);
|
|
328
322
|
const [head, body] = this.buildApiDict('setPurifierMode');
|
|
329
323
|
body.payload.data = {
|
|
330
324
|
workMode: mode
|
|
@@ -337,7 +331,7 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
337
331
|
head
|
|
338
332
|
);
|
|
339
333
|
|
|
340
|
-
const success = this.
|
|
334
|
+
const success = this.checkV2Response(response, status, 'setMode');
|
|
341
335
|
if (success) {
|
|
342
336
|
this.details.mode = mode;
|
|
343
337
|
this._mode = mode;
|
|
@@ -355,13 +349,13 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
355
349
|
return false;
|
|
356
350
|
}
|
|
357
351
|
} else {
|
|
358
|
-
// Use parent implementation for non-
|
|
352
|
+
// Use parent implementation for non-bypassV2 models
|
|
359
353
|
return super.setMode(mode);
|
|
360
354
|
}
|
|
361
355
|
}
|
|
362
356
|
|
|
363
357
|
/**
|
|
364
|
-
* Override changeFanSpeed
|
|
358
|
+
* Override changeFanSpeed to use manualSpeedLevel for bypassV2 purifiers.
|
|
365
359
|
*/
|
|
366
360
|
override async changeFanSpeed(speed: number): Promise<boolean> {
|
|
367
361
|
const speeds = this.config.levels ?? [];
|
|
@@ -374,10 +368,10 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
374
368
|
|
|
375
369
|
const [head, body] = this.buildApiDict('setLevel');
|
|
376
370
|
|
|
377
|
-
// Specific handling for
|
|
378
|
-
if (this.
|
|
379
|
-
logger.debug(`Using
|
|
380
|
-
// For
|
|
371
|
+
// Specific handling for bypassV2 devices
|
|
372
|
+
if (this.requiresPowerSwitchPayload()) {
|
|
373
|
+
logger.debug(`Using bypassV2 speed payload for ${this.deviceName}`);
|
|
374
|
+
// For these devices, use levelIdx, levelType, and manualSpeedLevel per YAML spec
|
|
381
375
|
body.payload.data = {
|
|
382
376
|
levelIdx: 0,
|
|
383
377
|
levelType: 'wind',
|
|
@@ -391,7 +385,7 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
391
385
|
head
|
|
392
386
|
);
|
|
393
387
|
|
|
394
|
-
const success = this.
|
|
388
|
+
const success = this.checkV2Response(response, status, 'changeFanSpeed');
|
|
395
389
|
if (success) {
|
|
396
390
|
this.speed = speed;
|
|
397
391
|
this.details.manualSpeedLevel = speed;
|
|
@@ -409,7 +403,7 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
409
403
|
return false;
|
|
410
404
|
}
|
|
411
405
|
} else {
|
|
412
|
-
// For non-
|
|
406
|
+
// For non-bypassV2 models, use id, level, mode, and type
|
|
413
407
|
body.payload.data = {
|
|
414
408
|
id: 0,
|
|
415
409
|
level: speed,
|
|
@@ -459,16 +453,16 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
459
453
|
);
|
|
460
454
|
|
|
461
455
|
// Use the appropriate response checking method based on device type
|
|
462
|
-
const success = this.
|
|
463
|
-
? this.
|
|
456
|
+
const success = this.requiresPowerSwitchPayload()
|
|
457
|
+
? this.checkV2Response(response, status, 'setAutoPreference')
|
|
464
458
|
: this.checkResponse([response, status], 'setAutoPreference');
|
|
465
459
|
|
|
466
460
|
if (success) {
|
|
467
461
|
this.details.auto_preference = preference;
|
|
468
462
|
this.details.auto_preference_type = preference;
|
|
469
463
|
|
|
470
|
-
// Force a details update to sync state for
|
|
471
|
-
if (this.
|
|
464
|
+
// Force a details update to sync state for bypassV2 purifiers
|
|
465
|
+
if (this.requiresPowerSwitchPayload()) {
|
|
472
466
|
setTimeout(() => {
|
|
473
467
|
this.getDetails().catch(e => {
|
|
474
468
|
logger.debug(`Background state refresh failed: ${e}`);
|
|
@@ -496,15 +490,15 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
496
490
|
);
|
|
497
491
|
|
|
498
492
|
// Use the appropriate response checking method based on device type
|
|
499
|
-
const success = this.
|
|
500
|
-
? this.
|
|
493
|
+
const success = this.requiresPowerSwitchPayload()
|
|
494
|
+
? this.checkV2Response(response, status, 'setLightDetection')
|
|
501
495
|
: this.checkResponse([response, status], 'setLightDetection');
|
|
502
496
|
|
|
503
497
|
if (success) {
|
|
504
498
|
this.details.light_detection_switch = enabled;
|
|
505
499
|
|
|
506
|
-
// Force a details update to sync state for
|
|
507
|
-
if (this.
|
|
500
|
+
// Force a details update to sync state for bypassV2 purifiers
|
|
501
|
+
if (this.requiresPowerSwitchPayload()) {
|
|
508
502
|
setTimeout(() => {
|
|
509
503
|
this.getDetails().catch(e => {
|
|
510
504
|
logger.debug(`Background state refresh failed: ${e}`);
|
|
@@ -595,8 +589,8 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
|
|
|
595
589
|
);
|
|
596
590
|
|
|
597
591
|
// Use the appropriate response checking method based on device type
|
|
598
|
-
const success = this.
|
|
599
|
-
? this.
|
|
592
|
+
const success = this.requiresPowerSwitchPayload()
|
|
593
|
+
? this.checkV2Response(response, status, 'setOscillation')
|
|
600
594
|
: this.checkResponse([response, status], 'setOscillation');
|
|
601
595
|
|
|
602
596
|
if (success) {
|
|
@@ -23,7 +23,7 @@ export class VeSyncWallSwitch extends VeSyncSwitch {
|
|
|
23
23
|
logger.debug(`Getting details for device: ${this.deviceName}`);
|
|
24
24
|
const body = {
|
|
25
25
|
...Helpers.reqBody(this.manager, 'devicedetail'),
|
|
26
|
-
uuid: this.
|
|
26
|
+
uuid: this.uuid,
|
|
27
27
|
method: 'devicedetail'
|
|
28
28
|
};
|
|
29
29
|
|
|
@@ -53,7 +53,7 @@ export class VeSyncWallSwitch extends VeSyncSwitch {
|
|
|
53
53
|
const body = {
|
|
54
54
|
...Helpers.reqBody(this.manager, 'devicedetail'),
|
|
55
55
|
method: 'configurations',
|
|
56
|
-
uuid: this.
|
|
56
|
+
uuid: this.uuid
|
|
57
57
|
};
|
|
58
58
|
|
|
59
59
|
const [response] = await this.callApi(
|
|
@@ -79,7 +79,7 @@ export class VeSyncWallSwitch extends VeSyncSwitch {
|
|
|
79
79
|
const body = {
|
|
80
80
|
...Helpers.reqBody(this.manager, 'devicestatus'),
|
|
81
81
|
status: 'off',
|
|
82
|
-
uuid: this.
|
|
82
|
+
uuid: this.uuid
|
|
83
83
|
};
|
|
84
84
|
|
|
85
85
|
const [response] = await this.callApi(
|
|
@@ -106,7 +106,7 @@ export class VeSyncWallSwitch extends VeSyncSwitch {
|
|
|
106
106
|
const body = {
|
|
107
107
|
...Helpers.reqBody(this.manager, 'devicestatus'),
|
|
108
108
|
status: 'on',
|
|
109
|
-
uuid: this.
|
|
109
|
+
uuid: this.uuid
|
|
110
110
|
};
|
|
111
111
|
|
|
112
112
|
const [response] = await this.callApi(
|
|
@@ -147,7 +147,7 @@ export class VeSyncDimmerSwitch extends VeSyncSwitch {
|
|
|
147
147
|
logger.debug(`Getting details for device: ${this.deviceName}`);
|
|
148
148
|
const body = {
|
|
149
149
|
...Helpers.reqBody(this.manager, 'devicedetail'),
|
|
150
|
-
uuid: this.
|
|
150
|
+
uuid: this.uuid,
|
|
151
151
|
method: 'devicedetail'
|
|
152
152
|
};
|
|
153
153
|
|
|
@@ -187,7 +187,7 @@ export class VeSyncDimmerSwitch extends VeSyncSwitch {
|
|
|
187
187
|
const body = {
|
|
188
188
|
...Helpers.reqBody(this.manager, 'devicedetail'),
|
|
189
189
|
method: 'configurations',
|
|
190
|
-
uuid: this.
|
|
190
|
+
uuid: this.uuid
|
|
191
191
|
};
|
|
192
192
|
|
|
193
193
|
const [response] = await this.callApi(
|
|
@@ -213,7 +213,7 @@ export class VeSyncDimmerSwitch extends VeSyncSwitch {
|
|
|
213
213
|
const body = {
|
|
214
214
|
...Helpers.reqBody(this.manager, 'devicestatus'),
|
|
215
215
|
status: 'off',
|
|
216
|
-
uuid: this.
|
|
216
|
+
uuid: this.uuid
|
|
217
217
|
};
|
|
218
218
|
|
|
219
219
|
const [response] = await this.callApi(
|
|
@@ -240,7 +240,7 @@ export class VeSyncDimmerSwitch extends VeSyncSwitch {
|
|
|
240
240
|
const body = {
|
|
241
241
|
...Helpers.reqBody(this.manager, 'devicestatus'),
|
|
242
242
|
status: 'on',
|
|
243
|
-
uuid: this.
|
|
243
|
+
uuid: this.uuid
|
|
244
244
|
};
|
|
245
245
|
|
|
246
246
|
const [response] = await this.callApi(
|
|
@@ -271,8 +271,8 @@ export class VeSyncDimmerSwitch extends VeSyncSwitch {
|
|
|
271
271
|
logger.debug(`Setting brightness to ${brightness} for device: ${this.deviceName}`);
|
|
272
272
|
const body = {
|
|
273
273
|
...Helpers.reqBody(this.manager, 'devicestatus'),
|
|
274
|
-
brightness
|
|
275
|
-
uuid: this.
|
|
274
|
+
brightness,
|
|
275
|
+
uuid: this.uuid
|
|
276
276
|
};
|
|
277
277
|
|
|
278
278
|
const [response] = await this.callApi(
|
|
@@ -304,7 +304,7 @@ export class VeSyncDimmerSwitch extends VeSyncSwitch {
|
|
|
304
304
|
blue: Math.round(blue)
|
|
305
305
|
},
|
|
306
306
|
status: 'on',
|
|
307
|
-
uuid: this.
|
|
307
|
+
uuid: this.uuid
|
|
308
308
|
};
|
|
309
309
|
|
|
310
310
|
const [response] = await this.callApi(
|
|
@@ -332,7 +332,7 @@ export class VeSyncDimmerSwitch extends VeSyncSwitch {
|
|
|
332
332
|
const body = {
|
|
333
333
|
...Helpers.reqBody(this.manager, 'devicestatus'),
|
|
334
334
|
status: 'off',
|
|
335
|
-
uuid: this.
|
|
335
|
+
uuid: this.uuid
|
|
336
336
|
};
|
|
337
337
|
|
|
338
338
|
const [response] = await this.callApi(
|
|
@@ -358,7 +358,7 @@ export class VeSyncDimmerSwitch extends VeSyncSwitch {
|
|
|
358
358
|
logger.debug(`Turning on RGB color for device: ${this.deviceName}`);
|
|
359
359
|
const body = {
|
|
360
360
|
...Helpers.reqBody(this.manager, 'devicestatus'),
|
|
361
|
-
uuid: this.
|
|
361
|
+
uuid: this.uuid,
|
|
362
362
|
status: 'on'
|
|
363
363
|
};
|
|
364
364
|
|
|
@@ -385,7 +385,7 @@ export class VeSyncDimmerSwitch extends VeSyncSwitch {
|
|
|
385
385
|
logger.debug(`Turning on indicator light for device: ${this.deviceName}`);
|
|
386
386
|
const body = {
|
|
387
387
|
...Helpers.reqBody(this.manager, 'devicestatus'),
|
|
388
|
-
uuid: this.
|
|
388
|
+
uuid: this.uuid,
|
|
389
389
|
status: 'on'
|
|
390
390
|
};
|
|
391
391
|
|
|
@@ -412,7 +412,7 @@ export class VeSyncDimmerSwitch extends VeSyncSwitch {
|
|
|
412
412
|
logger.debug(`Turning off indicator light for device: ${this.deviceName}`);
|
|
413
413
|
const body = {
|
|
414
414
|
...Helpers.reqBody(this.manager, 'devicestatus'),
|
|
415
|
-
uuid: this.
|
|
415
|
+
uuid: this.uuid,
|
|
416
416
|
status: 'off'
|
|
417
417
|
};
|
|
418
418
|
|
|
@@ -455,4 +455,4 @@ export const switchModules: Record<string, new (details: Record<string, any>, ma
|
|
|
455
455
|
'ESWL01': VeSyncWallSwitch,
|
|
456
456
|
'ESWL03': VeSyncWallSwitch,
|
|
457
457
|
'ESWD16': VeSyncDimmerSwitch
|
|
458
|
-
};
|
|
458
|
+
};
|