tsvesync 1.0.71 → 1.0.73
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/fans/airBypass.js +86 -13
- package/dist/lib/fans/humid1000S.d.ts +70 -0
- package/dist/lib/fans/humid1000S.js +222 -0
- package/dist/lib/fans/humid200S.d.ts +52 -0
- package/dist/lib/fans/humid200S.js +169 -0
- package/dist/lib/fans/index.d.ts +3 -0
- package/dist/lib/fans/index.js +16 -7
- package/dist/lib/fans/superior6000S.d.ts +150 -0
- package/dist/lib/fans/superior6000S.js +360 -0
- package/dist/lib/vesyncFan.d.ts +10 -2
- package/dist/lib/vesyncFan.js +50 -11
- package/package.json +1 -1
- package/src/lib/fans/airBypass.ts +87 -13
- package/src/lib/fans/airBypass.ts.bak +890 -0
- package/src/lib/fans/humid1000S.ts +276 -0
- package/src/lib/fans/humid200S.ts +199 -0
- package/src/lib/fans/index.ts +12 -6
- package/src/lib/fans/superior6000S.ts +466 -0
- package/src/lib/vesyncFan.ts +59 -13
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VeSyncSuperior6000S = void 0;
|
|
4
|
+
const vesyncFan_1 = require("../vesyncFan");
|
|
5
|
+
const helpers_1 = require("../helpers");
|
|
6
|
+
const logger_1 = require("../logger");
|
|
7
|
+
/**
|
|
8
|
+
* VeSync Superior 6000S Humidifier Class
|
|
9
|
+
* Implementation based on PyVeSync's VeSyncSuperior6000S class
|
|
10
|
+
*/
|
|
11
|
+
class VeSyncSuperior6000S extends vesyncFan_1.VeSyncFan {
|
|
12
|
+
constructor(details, manager) {
|
|
13
|
+
super(details, manager);
|
|
14
|
+
this.modes = ['auto', 'manual', 'sleep', 'humidity'];
|
|
15
|
+
this.mistLevels = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
16
|
+
this.humidityRange = { min: 30, max: 80 };
|
|
17
|
+
this._apiModes = [
|
|
18
|
+
'getHumidifierStatus',
|
|
19
|
+
'setSwitch',
|
|
20
|
+
'setVirtualLevel',
|
|
21
|
+
'setTargetHumidity',
|
|
22
|
+
'setHumidityMode',
|
|
23
|
+
'setDisplay',
|
|
24
|
+
'setDryingMode',
|
|
25
|
+
];
|
|
26
|
+
// Initialize details object
|
|
27
|
+
this.details = {
|
|
28
|
+
mode: '',
|
|
29
|
+
speed: 0,
|
|
30
|
+
filter_life: 0,
|
|
31
|
+
screen_status: 'off',
|
|
32
|
+
child_lock: false,
|
|
33
|
+
humidity: 0,
|
|
34
|
+
target_humidity: 0,
|
|
35
|
+
mist_level: 0,
|
|
36
|
+
mist_virtual_level: 0,
|
|
37
|
+
water_lacks: false,
|
|
38
|
+
water_tank_lifted: false,
|
|
39
|
+
display: false,
|
|
40
|
+
filter_life_percentage: 0,
|
|
41
|
+
temperature: 0,
|
|
42
|
+
drying_mode: {},
|
|
43
|
+
configuration: {},
|
|
44
|
+
connection_status: null
|
|
45
|
+
};
|
|
46
|
+
// Update config for Superior 6000S
|
|
47
|
+
this.config = {
|
|
48
|
+
module: 'VeSyncAirBypass', // This doesn't matter as we're implementing directly
|
|
49
|
+
features: ['display', 'humidity', 'mist', 'timer', 'auto_mode', 'drying'],
|
|
50
|
+
levels: this.mistLevels
|
|
51
|
+
};
|
|
52
|
+
logger_1.logger.debug(`Initialized VeSyncSuperior6000S device: ${this.deviceName}`);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Build API dictionary for humidifier
|
|
56
|
+
*/
|
|
57
|
+
buildApiDict(method) {
|
|
58
|
+
if (!this._apiModes.includes(method)) {
|
|
59
|
+
logger_1.logger.debug(`Invalid mode - ${method}`);
|
|
60
|
+
throw new Error(`Invalid mode - ${method}`);
|
|
61
|
+
}
|
|
62
|
+
const head = helpers_1.Helpers.reqHeaderBypass();
|
|
63
|
+
const body = {
|
|
64
|
+
...helpers_1.Helpers.reqBody(this.manager, 'bypassV2'),
|
|
65
|
+
cid: this.cid,
|
|
66
|
+
configModule: this.configModule,
|
|
67
|
+
payload: {
|
|
68
|
+
method: method,
|
|
69
|
+
source: 'APP',
|
|
70
|
+
data: {}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
return [head, body];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get device details
|
|
77
|
+
*/
|
|
78
|
+
async getDetails() {
|
|
79
|
+
var _a;
|
|
80
|
+
logger_1.logger.debug(`Getting details for device: ${this.deviceName}`);
|
|
81
|
+
const [head, body] = this.buildApiDict('getHumidifierStatus');
|
|
82
|
+
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
83
|
+
const success = this.checkResponse([response, status], 'getDetails');
|
|
84
|
+
if (success && ((_a = response === null || response === void 0 ? void 0 : response.result) === null || _a === void 0 ? void 0 : _a.result)) {
|
|
85
|
+
const result = response.result.result;
|
|
86
|
+
// Update device status based on powerSwitch field
|
|
87
|
+
this.deviceStatus = result.powerSwitch === 1 ? 'on' : 'off';
|
|
88
|
+
// Build details object with Superior 6000S specific fields
|
|
89
|
+
this.details = {
|
|
90
|
+
mode: result.workMode === 'autoPro' ? 'auto' : result.workMode || '',
|
|
91
|
+
humidity: result.humidity || 0,
|
|
92
|
+
target_humidity: result.targetHumidity || 0,
|
|
93
|
+
mist_level: result.mistLevel || 0,
|
|
94
|
+
mist_virtual_level: result.virtualLevel || 0,
|
|
95
|
+
water_lacks: result.waterLacksState || false,
|
|
96
|
+
water_tank_lifted: result.waterTankLifted || false,
|
|
97
|
+
display: result.screenSwitch === 1,
|
|
98
|
+
filter_life_percentage: result.filterLifePercent || 0,
|
|
99
|
+
temperature: result.temperature || 0,
|
|
100
|
+
drying_mode: result.dryingMode || {},
|
|
101
|
+
configuration: result.configuration || {},
|
|
102
|
+
connection_status: result.connectionStatus || null
|
|
103
|
+
};
|
|
104
|
+
logger_1.logger.debug(`Successfully got details for device: ${this.deviceName}`);
|
|
105
|
+
}
|
|
106
|
+
return success;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Turn device on
|
|
110
|
+
*/
|
|
111
|
+
async turnOn() {
|
|
112
|
+
return this.toggleSwitch(true);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Turn device off
|
|
116
|
+
*/
|
|
117
|
+
async turnOff() {
|
|
118
|
+
return this.toggleSwitch(false);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Toggle device power
|
|
122
|
+
*/
|
|
123
|
+
async toggleSwitch(enabled) {
|
|
124
|
+
logger_1.logger.info(`Setting device power to ${enabled ? 'on' : 'off'}: ${this.deviceName}`);
|
|
125
|
+
const [head, body] = this.buildApiDict('setSwitch');
|
|
126
|
+
body.payload.data = {
|
|
127
|
+
powerSwitch: enabled ? 1 : 0,
|
|
128
|
+
switchIdx: 0
|
|
129
|
+
};
|
|
130
|
+
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
131
|
+
const success = this.checkResponse([response, status], 'toggleSwitch');
|
|
132
|
+
if (success) {
|
|
133
|
+
this.deviceStatus = enabled ? 'on' : 'off';
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
logger_1.logger.error(`Failed to set device power to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Set mist level
|
|
141
|
+
*/
|
|
142
|
+
async setMistLevel(level) {
|
|
143
|
+
if (!this.mistLevels.includes(level)) {
|
|
144
|
+
const error = `Invalid mist level: ${level}. Must be one of: ${this.mistLevels.join(', ')}`;
|
|
145
|
+
logger_1.logger.error(`${error} for device: ${this.deviceName}`);
|
|
146
|
+
throw new Error(error);
|
|
147
|
+
}
|
|
148
|
+
logger_1.logger.info(`Setting mist level to ${level} for device: ${this.deviceName}`);
|
|
149
|
+
const [head, body] = this.buildApiDict('setVirtualLevel');
|
|
150
|
+
body.payload.data = {
|
|
151
|
+
levelIdx: 0,
|
|
152
|
+
virtualLevel: level,
|
|
153
|
+
levelType: 'mist'
|
|
154
|
+
};
|
|
155
|
+
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
156
|
+
const success = this.checkResponse([response, status], 'setMistLevel');
|
|
157
|
+
if (!success) {
|
|
158
|
+
logger_1.logger.error(`Failed to set mist level to ${level} for device: ${this.deviceName}`);
|
|
159
|
+
}
|
|
160
|
+
return success;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Change fan speed - Implemented to satisfy interface but redirects to setMistLevel
|
|
164
|
+
*/
|
|
165
|
+
async changeFanSpeed(speed) {
|
|
166
|
+
logger_1.logger.debug(`Redirecting fan speed change to mist level for device: ${this.deviceName}`);
|
|
167
|
+
return this.setMistLevel(speed);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Set device mode
|
|
171
|
+
*/
|
|
172
|
+
async setMode(mode) {
|
|
173
|
+
if (!this.modes.includes(mode)) {
|
|
174
|
+
const error = `Invalid mode: ${mode}. Must be one of: ${this.modes.join(', ')}`;
|
|
175
|
+
logger_1.logger.error(`${error} for device: ${this.deviceName}`);
|
|
176
|
+
throw new Error(error);
|
|
177
|
+
}
|
|
178
|
+
logger_1.logger.debug(`Setting mode to ${mode} for device: ${this.deviceName}`);
|
|
179
|
+
const [head, body] = this.buildApiDict('setHumidityMode');
|
|
180
|
+
body.payload.data = {
|
|
181
|
+
workMode: mode === 'auto' ? 'autoPro' : mode
|
|
182
|
+
};
|
|
183
|
+
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
184
|
+
const success = this.checkResponse([response, status], 'setMode');
|
|
185
|
+
if (success) {
|
|
186
|
+
this.details.mode = mode;
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
logger_1.logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
|
|
190
|
+
}
|
|
191
|
+
return success;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Set target humidity
|
|
195
|
+
*/
|
|
196
|
+
async setHumidity(humidity) {
|
|
197
|
+
if (humidity < this.humidityRange.min || humidity > this.humidityRange.max) {
|
|
198
|
+
const error = `Invalid humidity: ${humidity}. Must be between ${this.humidityRange.min} and ${this.humidityRange.max}`;
|
|
199
|
+
logger_1.logger.error(`${error} for device: ${this.deviceName}`);
|
|
200
|
+
throw new Error(error);
|
|
201
|
+
}
|
|
202
|
+
logger_1.logger.debug(`Setting target humidity to ${humidity}% for device: ${this.deviceName}`);
|
|
203
|
+
const [head, body] = this.buildApiDict('setTargetHumidity');
|
|
204
|
+
body.payload.data = {
|
|
205
|
+
targetHumidity: humidity
|
|
206
|
+
};
|
|
207
|
+
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
208
|
+
const success = this.checkResponse([response, status], 'setHumidity');
|
|
209
|
+
if (!success) {
|
|
210
|
+
logger_1.logger.error(`Failed to set target humidity to ${humidity}% for device: ${this.deviceName}`);
|
|
211
|
+
}
|
|
212
|
+
return success;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Set display status
|
|
216
|
+
*/
|
|
217
|
+
async setDisplay(enabled) {
|
|
218
|
+
logger_1.logger.debug(`Setting display to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
|
|
219
|
+
const [head, body] = this.buildApiDict('setDisplay');
|
|
220
|
+
body.payload.data = {
|
|
221
|
+
screenSwitch: enabled ? 1 : 0
|
|
222
|
+
};
|
|
223
|
+
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
224
|
+
const success = this.checkResponse([response, status], 'setDisplay');
|
|
225
|
+
if (!success) {
|
|
226
|
+
logger_1.logger.error(`Failed to set display to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
|
|
227
|
+
}
|
|
228
|
+
return success;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Set drying mode enabled
|
|
232
|
+
*/
|
|
233
|
+
async setDryingModeEnabled(enabled) {
|
|
234
|
+
logger_1.logger.debug(`Setting drying mode to ${enabled ? 'enabled' : 'disabled'} for device: ${this.deviceName}`);
|
|
235
|
+
const [head, body] = this.buildApiDict('setDryingMode');
|
|
236
|
+
body.payload.data = {
|
|
237
|
+
autoDryingSwitch: enabled ? 1 : 0
|
|
238
|
+
};
|
|
239
|
+
const [response, status] = await this.callApi('/cloud/v2/deviceManaged/bypassV2', 'post', body, head);
|
|
240
|
+
const success = this.checkResponse([response, status], 'setDryingModeEnabled');
|
|
241
|
+
if (!success) {
|
|
242
|
+
logger_1.logger.error(`Failed to set drying mode to ${enabled ? 'enabled' : 'disabled'} for device: ${this.deviceName}`);
|
|
243
|
+
}
|
|
244
|
+
return success;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Turn on display
|
|
248
|
+
*/
|
|
249
|
+
async turnOnDisplay() {
|
|
250
|
+
logger_1.logger.debug(`Turning on display for device: ${this.deviceName}`);
|
|
251
|
+
return this.setDisplay(true);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Turn off display
|
|
255
|
+
*/
|
|
256
|
+
async turnOffDisplay() {
|
|
257
|
+
logger_1.logger.debug(`Turning off display for device: ${this.deviceName}`);
|
|
258
|
+
return this.setDisplay(false);
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Set auto mode
|
|
262
|
+
*/
|
|
263
|
+
async setAutoMode() {
|
|
264
|
+
logger_1.logger.debug(`Setting auto mode for device: ${this.deviceName}`);
|
|
265
|
+
return this.setMode('auto');
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Set manual mode
|
|
269
|
+
*/
|
|
270
|
+
async setManualMode() {
|
|
271
|
+
logger_1.logger.debug(`Setting manual mode for device: ${this.deviceName}`);
|
|
272
|
+
return this.setMode('manual');
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Get current humidity
|
|
276
|
+
* Provides access to the current humidity reading
|
|
277
|
+
*/
|
|
278
|
+
get currentHumidity() {
|
|
279
|
+
return this.details.humidity || 0;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Get target humidity
|
|
283
|
+
* Provides access to the target humidity setting
|
|
284
|
+
*/
|
|
285
|
+
get targetHumidity() {
|
|
286
|
+
return this.details.target_humidity || 0;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Get current temperature
|
|
290
|
+
* Provides access to the current temperature reading
|
|
291
|
+
*/
|
|
292
|
+
get temperature() {
|
|
293
|
+
return this.details.temperature || 0;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Check if water tank is empty
|
|
297
|
+
* Returns true if water tank is empty and needs to be refilled
|
|
298
|
+
*/
|
|
299
|
+
get waterLacks() {
|
|
300
|
+
return this.details.water_lacks || false;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Check if water tank is lifted
|
|
304
|
+
* Returns true if water tank is lifted/removed from the device
|
|
305
|
+
*/
|
|
306
|
+
get waterTankLifted() {
|
|
307
|
+
return this.details.water_tank_lifted || false;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Get filter life percentage
|
|
311
|
+
* Returns the percentage of filter life remaining
|
|
312
|
+
*/
|
|
313
|
+
get filterLifePercentage() {
|
|
314
|
+
return this.details.filter_life_percentage || 0;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Check if drying mode is enabled
|
|
318
|
+
* Returns true if drying mode is enabled
|
|
319
|
+
*/
|
|
320
|
+
get dryingModeEnabled() {
|
|
321
|
+
var _a;
|
|
322
|
+
const enabled = (_a = this.details.drying_mode) === null || _a === void 0 ? void 0 : _a.autoDryingSwitch;
|
|
323
|
+
return enabled === 1;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Get drying mode state
|
|
327
|
+
* Returns 'on' if drying mode is active, 'off' if inactive, null if unknown
|
|
328
|
+
*/
|
|
329
|
+
get dryingModeState() {
|
|
330
|
+
var _a;
|
|
331
|
+
const state = (_a = this.details.drying_mode) === null || _a === void 0 ? void 0 : _a.dryingState;
|
|
332
|
+
if (state === 1)
|
|
333
|
+
return 'on';
|
|
334
|
+
if (state === 2)
|
|
335
|
+
return 'off';
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Get drying mode level
|
|
340
|
+
* Returns 'low' if level is 1, 'high' if level is 2, null if unknown
|
|
341
|
+
*/
|
|
342
|
+
get dryingModeLevel() {
|
|
343
|
+
var _a;
|
|
344
|
+
const level = (_a = this.details.drying_mode) === null || _a === void 0 ? void 0 : _a.dryingLevel;
|
|
345
|
+
if (level === 1)
|
|
346
|
+
return 'low';
|
|
347
|
+
if (level === 2)
|
|
348
|
+
return 'high';
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Get drying mode seconds remaining
|
|
353
|
+
* Returns the number of seconds remaining in drying mode
|
|
354
|
+
*/
|
|
355
|
+
get dryingModeSecondsRemaining() {
|
|
356
|
+
var _a;
|
|
357
|
+
return ((_a = this.details.drying_mode) === null || _a === void 0 ? void 0 : _a.dryingRemain) || 0;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
exports.VeSyncSuperior6000S = VeSyncSuperior6000S;
|
package/dist/lib/vesyncFan.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { VeSyncBaseDevice } from './vesyncBaseDevice';
|
|
|
5
5
|
import { VeSync } from './vesync';
|
|
6
6
|
interface FanConfig {
|
|
7
7
|
[key: string]: {
|
|
8
|
-
module: 'VeSyncAirBypass' | 'VeSyncHumidifier' | 'VeSyncWarmHumidifier' | 'VeSyncTowerFan' | 'VeSyncAirBaseV2';
|
|
8
|
+
module: 'VeSyncAirBypass' | 'VeSyncHumidifier' | 'VeSyncWarmHumidifier' | 'VeSyncTowerFan' | 'VeSyncAirBaseV2' | 'VeSyncSuperior6000S' | 'VeSyncHumid1000S' | 'VeSyncHumid200S';
|
|
9
9
|
features: string[];
|
|
10
10
|
levels?: number[];
|
|
11
11
|
};
|
|
@@ -35,7 +35,7 @@ export declare abstract class VeSyncFan extends VeSyncBaseDevice {
|
|
|
35
35
|
action: string;
|
|
36
36
|
} | null;
|
|
37
37
|
protected config: {
|
|
38
|
-
module: 'VeSyncAirBypass' | 'VeSyncHumidifier' | 'VeSyncWarmHumidifier' | 'VeSyncTowerFan' | 'VeSyncAirBaseV2';
|
|
38
|
+
module: 'VeSyncAirBypass' | 'VeSyncHumidifier' | 'VeSyncWarmHumidifier' | 'VeSyncTowerFan' | 'VeSyncAirBaseV2' | 'VeSyncSuperior6000S' | 'VeSyncHumid1000S' | 'VeSyncHumid200S';
|
|
39
39
|
features: string[];
|
|
40
40
|
levels?: number[];
|
|
41
41
|
};
|
|
@@ -44,6 +44,14 @@ export declare abstract class VeSyncFan extends VeSyncBaseDevice {
|
|
|
44
44
|
* Check if feature is supported
|
|
45
45
|
*/
|
|
46
46
|
hasFeature(feature: string): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Check if feature is supported in current mode
|
|
49
|
+
*/
|
|
50
|
+
isFeatureSupportedInCurrentMode(feature: string): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Get maximum fan speed level
|
|
53
|
+
*/
|
|
54
|
+
getMaxFanSpeed(): number;
|
|
47
55
|
/**
|
|
48
56
|
* Get current mode
|
|
49
57
|
*/
|
package/dist/lib/vesyncFan.js
CHANGED
|
@@ -192,8 +192,9 @@ exports.fanConfig = {
|
|
|
192
192
|
features: ['display', 'humidity', 'mist', 'timer', 'auto_mode']
|
|
193
193
|
},
|
|
194
194
|
'Classic200S': {
|
|
195
|
-
module: '
|
|
196
|
-
features: ['display', 'humidity', 'mist', 'timer', 'auto_mode']
|
|
195
|
+
module: 'VeSyncHumid200S',
|
|
196
|
+
features: ['display', 'humidity', 'mist', 'timer', 'auto_mode'],
|
|
197
|
+
levels: [1, 2, 3]
|
|
197
198
|
},
|
|
198
199
|
// Dual Series
|
|
199
200
|
'Dual200S': {
|
|
@@ -266,21 +267,25 @@ exports.fanConfig = {
|
|
|
266
267
|
features: ['display', 'humidity', 'mist', 'warm', 'timer', 'auto_mode']
|
|
267
268
|
},
|
|
268
269
|
'LUH-M101S-WUS': {
|
|
269
|
-
module: '
|
|
270
|
-
features: ['display', 'humidity', 'mist', '
|
|
270
|
+
module: 'VeSyncHumid1000S',
|
|
271
|
+
features: ['display', 'humidity', 'mist', 'timer', 'auto_mode', 'night_light'],
|
|
272
|
+
levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
271
273
|
},
|
|
272
274
|
'LUH-M101S-WEUR': {
|
|
273
|
-
module: '
|
|
274
|
-
features: ['display', 'humidity', 'mist', '
|
|
275
|
+
module: 'VeSyncHumid1000S',
|
|
276
|
+
features: ['display', 'humidity', 'mist', 'timer', 'auto_mode', 'night_light'],
|
|
277
|
+
levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
275
278
|
},
|
|
276
|
-
// LEH Series
|
|
279
|
+
// LEH Series - Superior 6000S
|
|
277
280
|
'LEH-S601S-WUS': {
|
|
278
|
-
module: '
|
|
279
|
-
features: ['display', 'humidity', 'mist', '
|
|
281
|
+
module: 'VeSyncSuperior6000S',
|
|
282
|
+
features: ['display', 'humidity', 'mist', 'timer', 'auto_mode', 'drying', 'temperature'],
|
|
283
|
+
levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
280
284
|
},
|
|
281
285
|
'LEH-S601S-WUSR': {
|
|
282
|
-
module: '
|
|
283
|
-
features: ['display', 'humidity', 'mist', '
|
|
286
|
+
module: 'VeSyncSuperior6000S',
|
|
287
|
+
features: ['display', 'humidity', 'mist', 'timer', 'auto_mode', 'drying', 'temperature'],
|
|
288
|
+
levels: [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
284
289
|
},
|
|
285
290
|
// LV Series
|
|
286
291
|
'LV-PUR131S': {
|
|
@@ -317,6 +322,40 @@ class VeSyncFan extends vesyncBaseDevice_1.VeSyncBaseDevice {
|
|
|
317
322
|
hasFeature(feature) {
|
|
318
323
|
return this.config.features.includes(feature);
|
|
319
324
|
}
|
|
325
|
+
/**
|
|
326
|
+
* Check if feature is supported in current mode
|
|
327
|
+
*/
|
|
328
|
+
isFeatureSupportedInCurrentMode(feature) {
|
|
329
|
+
// First check if the feature is supported at all
|
|
330
|
+
if (!this.hasFeature(feature)) {
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
// Check mode-specific restrictions
|
|
334
|
+
const currentMode = this.mode;
|
|
335
|
+
// Some features are not supported in sleep mode
|
|
336
|
+
if (currentMode === 'sleep') {
|
|
337
|
+
// Display and child lock are not supported in sleep mode
|
|
338
|
+
if (feature === 'display' || feature === 'child_lock') {
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
// Fan speed is only supported in manual mode for some devices
|
|
343
|
+
if (feature === 'fan_speed' && this.deviceType.startsWith('LV-')) {
|
|
344
|
+
return currentMode === 'manual';
|
|
345
|
+
}
|
|
346
|
+
// Auto mode is not supported on Core200S
|
|
347
|
+
if (feature === 'auto_mode' && this.deviceType.includes('Core200S')) {
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
// Feature is supported in current mode
|
|
351
|
+
return true;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Get maximum fan speed level
|
|
355
|
+
*/
|
|
356
|
+
getMaxFanSpeed() {
|
|
357
|
+
return this.config.levels ? Math.max(...this.config.levels) : 3;
|
|
358
|
+
}
|
|
320
359
|
/**
|
|
321
360
|
* Get current mode
|
|
322
361
|
*/
|
package/package.json
CHANGED
|
@@ -388,6 +388,13 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
388
388
|
}
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
+
// Special handling for Core200S auto mode
|
|
392
|
+
if (this.deviceType.includes('Core200S') && mode === 'auto') {
|
|
393
|
+
// Core200S doesn't support auto mode, so we'll set it to manual mode
|
|
394
|
+
logger.warn(`Auto mode not supported for ${this.deviceType}, using manual mode instead`);
|
|
395
|
+
return this.setMode('manual');
|
|
396
|
+
}
|
|
397
|
+
|
|
391
398
|
// Standard implementation for other devices
|
|
392
399
|
const [response, status] = await this.callApi(
|
|
393
400
|
'/cloud/v2/deviceManaged/bypassV2',
|
|
@@ -408,10 +415,13 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
408
415
|
);
|
|
409
416
|
|
|
410
417
|
const success = this.checkResponse([response, status], 'setMode');
|
|
411
|
-
if (
|
|
418
|
+
if (success) {
|
|
419
|
+
this.details.mode = mode;
|
|
420
|
+
return true;
|
|
421
|
+
} else {
|
|
412
422
|
logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
|
|
423
|
+
return false;
|
|
413
424
|
}
|
|
414
|
-
return success;
|
|
415
425
|
}
|
|
416
426
|
|
|
417
427
|
/**
|
|
@@ -424,6 +434,11 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
424
434
|
throw new Error(error);
|
|
425
435
|
}
|
|
426
436
|
|
|
437
|
+
// Check if device is in sleep mode - display control may not work in sleep mode
|
|
438
|
+
if (this.details.mode === 'sleep') {
|
|
439
|
+
logger.warn(`Device ${this.deviceName} is in sleep mode, display control may not work`);
|
|
440
|
+
}
|
|
441
|
+
|
|
427
442
|
logger.debug(`Setting display to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
|
|
428
443
|
|
|
429
444
|
// Special handling for LV series
|
|
@@ -479,12 +494,20 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
479
494
|
);
|
|
480
495
|
|
|
481
496
|
const success = this.checkResponse([response, status], 'setDisplay');
|
|
497
|
+
|
|
498
|
+
// Check for error code 11018000 (operation not supported in current mode)
|
|
499
|
+
if (response?.result?.code === 11018000) {
|
|
500
|
+
logger.warn(`Display control not supported in current mode for device: ${this.deviceName}`);
|
|
501
|
+
return false;
|
|
502
|
+
}
|
|
503
|
+
|
|
482
504
|
if (success) {
|
|
483
505
|
this.details.screenStatus = enabled ? 'on' : 'off';
|
|
506
|
+
return true;
|
|
484
507
|
} else {
|
|
485
508
|
logger.error(`Failed to set display to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
|
|
509
|
+
return false;
|
|
486
510
|
}
|
|
487
|
-
return success;
|
|
488
511
|
}
|
|
489
512
|
|
|
490
513
|
/**
|
|
@@ -497,6 +520,11 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
497
520
|
throw new Error(error);
|
|
498
521
|
}
|
|
499
522
|
|
|
523
|
+
// Check if device is in sleep mode - child lock may not work in sleep mode
|
|
524
|
+
if (this.details.mode === 'sleep') {
|
|
525
|
+
logger.warn(`Device ${this.deviceName} is in sleep mode, child lock control may not work`);
|
|
526
|
+
}
|
|
527
|
+
|
|
500
528
|
logger.debug(`Setting child lock to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
|
|
501
529
|
|
|
502
530
|
// Special handling for LV series
|
|
@@ -527,6 +555,11 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
527
555
|
this.details.childLock = enabled;
|
|
528
556
|
return true;
|
|
529
557
|
} else {
|
|
558
|
+
// Check for error code 11000000 (feature not supported)
|
|
559
|
+
if (response?.code === 11000000) {
|
|
560
|
+
logger.warn(`Child lock control not supported via API for device: ${this.deviceName}`);
|
|
561
|
+
return false;
|
|
562
|
+
}
|
|
530
563
|
logger.error(`Failed to set child lock to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
|
|
531
564
|
return false;
|
|
532
565
|
}
|
|
@@ -552,12 +585,20 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
552
585
|
);
|
|
553
586
|
|
|
554
587
|
const success = this.checkResponse([response, status], 'setChildLock');
|
|
588
|
+
|
|
589
|
+
// Check for error code 11000000 (feature not supported)
|
|
590
|
+
if (response?.code === 11000000 || (response?.result?.code === 11000000)) {
|
|
591
|
+
logger.warn(`Child lock control not supported via API for device: ${this.deviceName}`);
|
|
592
|
+
return false;
|
|
593
|
+
}
|
|
594
|
+
|
|
555
595
|
if (success) {
|
|
556
|
-
this.details.
|
|
596
|
+
this.details.childLock = enabled;
|
|
597
|
+
return true;
|
|
557
598
|
} else {
|
|
558
599
|
logger.error(`Failed to set child lock to ${enabled ? 'on' : 'off'} for device: ${this.deviceName}`);
|
|
600
|
+
return false;
|
|
559
601
|
}
|
|
560
|
-
return success;
|
|
561
602
|
}
|
|
562
603
|
|
|
563
604
|
/**
|
|
@@ -597,10 +638,13 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
597
638
|
);
|
|
598
639
|
|
|
599
640
|
const success = this.checkResponse([response, status], 'setTimer');
|
|
600
|
-
if (
|
|
641
|
+
if (success) {
|
|
642
|
+
this.timer = { duration: hours * 3600, action: 'off' };
|
|
643
|
+
return true;
|
|
644
|
+
} else {
|
|
601
645
|
logger.error(`Failed to set timer to ${hours} hours for device: ${this.deviceName}`);
|
|
646
|
+
return false;
|
|
602
647
|
}
|
|
603
|
-
return success;
|
|
604
648
|
}
|
|
605
649
|
|
|
606
650
|
// Standard implementation for other devices
|
|
@@ -624,10 +668,20 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
624
668
|
);
|
|
625
669
|
|
|
626
670
|
const success = this.checkResponse([response, status], 'setTimer');
|
|
627
|
-
|
|
671
|
+
|
|
672
|
+
// Check for successful response with timer ID
|
|
673
|
+
if (success && response?.result?.result?.id) {
|
|
674
|
+
this.timer = { duration: hours * 3600, action: 'off' };
|
|
675
|
+
return true;
|
|
676
|
+
} else if (success) {
|
|
677
|
+
// API call succeeded but no timer ID returned
|
|
678
|
+
logger.warn(`Timer API call succeeded but no timer ID returned for device: ${this.deviceName}`);
|
|
679
|
+
this.timer = { duration: hours * 3600, action: 'off' };
|
|
680
|
+
return true;
|
|
681
|
+
} else {
|
|
628
682
|
logger.error(`Failed to set timer to ${hours} hours for device: ${this.deviceName}`);
|
|
683
|
+
return false;
|
|
629
684
|
}
|
|
630
|
-
return success;
|
|
631
685
|
}
|
|
632
686
|
|
|
633
687
|
/**
|
|
@@ -640,6 +694,12 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
640
694
|
throw new Error(error);
|
|
641
695
|
}
|
|
642
696
|
|
|
697
|
+
// If no timer is set, return success
|
|
698
|
+
if (!this.timer) {
|
|
699
|
+
logger.debug(`No timer to clear for device: ${this.deviceName}`);
|
|
700
|
+
return true;
|
|
701
|
+
}
|
|
702
|
+
|
|
643
703
|
logger.debug(`Clearing timer for device: ${this.deviceName}`);
|
|
644
704
|
|
|
645
705
|
// Special handling for LV series
|
|
@@ -665,10 +725,13 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
665
725
|
);
|
|
666
726
|
|
|
667
727
|
const success = this.checkResponse([response, status], 'clearTimer');
|
|
668
|
-
if (
|
|
728
|
+
if (success) {
|
|
729
|
+
this.timer = null;
|
|
730
|
+
return true;
|
|
731
|
+
} else {
|
|
669
732
|
logger.error(`Failed to clear timer for device: ${this.deviceName}`);
|
|
733
|
+
return false;
|
|
670
734
|
}
|
|
671
|
-
return success;
|
|
672
735
|
}
|
|
673
736
|
|
|
674
737
|
// Standard implementation for other devices
|
|
@@ -689,10 +752,21 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
689
752
|
);
|
|
690
753
|
|
|
691
754
|
const success = this.checkResponse([response, status], 'clearTimer');
|
|
692
|
-
|
|
755
|
+
|
|
756
|
+
// Check for error code 11000000 (feature not supported or no timer to clear)
|
|
757
|
+
if (response?.code === 11000000 || (response?.result?.code === 11000000)) {
|
|
758
|
+
logger.warn(`No timer to clear or timer control not supported via API for device: ${this.deviceName}`);
|
|
759
|
+
this.timer = null;
|
|
760
|
+
return true;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
if (success) {
|
|
764
|
+
this.timer = null;
|
|
765
|
+
return true;
|
|
766
|
+
} else {
|
|
693
767
|
logger.error(`Failed to clear timer for device: ${this.deviceName}`);
|
|
768
|
+
return false;
|
|
694
769
|
}
|
|
695
|
-
return success;
|
|
696
770
|
}
|
|
697
771
|
|
|
698
772
|
/**
|