tsvesync 1.0.11
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/LICENSE +21 -0
- package/README.md +227 -0
- package/api/vesync/VeSync.yaml +33 -0
- package/api/vesyncbulb/ESL100.yaml +74 -0
- package/api/vesyncbulb/ESL100CW.yaml +123 -0
- package/api/vesyncbulb/ESL100MC.yaml +169 -0
- package/api/vesyncbulb/XYD0001.yaml +193 -0
- package/api/vesyncfan/Classic200S.yaml +280 -0
- package/api/vesyncfan/Classic300S.yaml +278 -0
- package/api/vesyncfan/Core200S.yaml +256 -0
- package/api/vesyncfan/Core300S.yaml +281 -0
- package/api/vesyncfan/Core400S.yaml +281 -0
- package/api/vesyncfan/Core600S.yaml +281 -0
- package/api/vesyncfan/Dual200S.yaml +278 -0
- package/api/vesyncfan/LAP-C201S-AUSR.yaml +256 -0
- package/api/vesyncfan/LAP-C202S-WUSR.yaml +256 -0
- package/api/vesyncfan/LAP-C301S-WAAA.yaml +281 -0
- package/api/vesyncfan/LAP-C301S-WJP.yaml +281 -0
- package/api/vesyncfan/LAP-C302S-WUSB.yaml +281 -0
- package/api/vesyncfan/LAP-C401S-WAAA.yaml +281 -0
- package/api/vesyncfan/LAP-C401S-WJP.yaml +281 -0
- package/api/vesyncfan/LAP-C401S-WUSR.yaml +281 -0
- package/api/vesyncfan/LAP-C601S-WEU.yaml +281 -0
- package/api/vesyncfan/LAP-C601S-WUS.yaml +281 -0
- package/api/vesyncfan/LAP-C601S-WUSR.yaml +281 -0
- package/api/vesyncfan/LAP-EL551S-AEUR.yaml +167 -0
- package/api/vesyncfan/LAP-EL551S-AUS.yaml +167 -0
- package/api/vesyncfan/LAP-EL551S-WEU.yaml +167 -0
- package/api/vesyncfan/LAP-EL551S-WUS.yaml +167 -0
- package/api/vesyncfan/LAP-V102S-AASR.yaml +167 -0
- package/api/vesyncfan/LAP-V102S-AUSR.yaml +167 -0
- package/api/vesyncfan/LAP-V102S-WEU.yaml +167 -0
- package/api/vesyncfan/LAP-V102S-WJP.yaml +167 -0
- package/api/vesyncfan/LAP-V102S-WUS.yaml +167 -0
- package/api/vesyncfan/LAP-V201-AUSR.yaml +167 -0
- package/api/vesyncfan/LAP-V201S-AASR.yaml +167 -0
- package/api/vesyncfan/LAP-V201S-AEUR.yaml +167 -0
- package/api/vesyncfan/LAP-V201S-AUSR.yaml +167 -0
- package/api/vesyncfan/LAP-V201S-WEU.yaml +167 -0
- package/api/vesyncfan/LAP-V201S-WJP.yaml +167 -0
- package/api/vesyncfan/LAP-V201S-WUS.yaml +167 -0
- package/api/vesyncfan/LEH-S601S-WUS.yaml +303 -0
- package/api/vesyncfan/LEH-S601S-WUSR.yaml +82 -0
- package/api/vesyncfan/LTF-F422S-KEU.yaml +165 -0
- package/api/vesyncfan/LTF-F422S-WUS.yaml +165 -0
- package/api/vesyncfan/LTF-F422S-WUSR.yaml +167 -0
- package/api/vesyncfan/LTF-F422_WJP.yaml +165 -0
- package/api/vesyncfan/LUH-A601S-AUSW.yaml +82 -0
- package/api/vesyncfan/LUH-A601S-WUSB.yaml +305 -0
- package/api/vesyncfan/LUH-A602S-WEU.yaml +305 -0
- package/api/vesyncfan/LUH-A602S-WEUR.yaml +305 -0
- package/api/vesyncfan/LUH-A602S-WJP.yaml +305 -0
- package/api/vesyncfan/LUH-A602S-WUS.yaml +305 -0
- package/api/vesyncfan/LUH-A602S-WUSC.yaml +305 -0
- package/api/vesyncfan/LUH-A602S-WUSR.yaml +305 -0
- package/api/vesyncfan/LUH-D301S-WEU.yaml +305 -0
- package/api/vesyncfan/LUH-D301S-WJP.yaml +305 -0
- package/api/vesyncfan/LUH-D301S-WUSR.yaml +305 -0
- package/api/vesyncfan/LUH-M101S-WUS.yaml +278 -0
- package/api/vesyncfan/LUH-O451S-WEU.yaml +278 -0
- package/api/vesyncfan/LUH-O451S-WUS.yaml +278 -0
- package/api/vesyncfan/LUH-O451S-WUSR.yaml +305 -0
- package/api/vesyncfan/LUH-O601S-KUS.yaml +305 -0
- package/api/vesyncfan/LUH-O601S-WUS.yaml +305 -0
- package/api/vesyncfan/LV-PUR131S.yaml +108 -0
- package/api/vesyncfan/LV-RH131S.yaml +108 -0
- package/api/vesyncoutlet/ESO15-TB.yaml +124 -0
- package/api/vesyncoutlet/ESW01-EU.yaml +122 -0
- package/api/vesyncoutlet/ESW03-USA.yaml +122 -0
- package/api/vesyncoutlet/ESW15-USA.yaml +156 -0
- package/api/vesyncoutlet/wifi-switch-1.3.yaml +60 -0
- package/api/vesyncswitch/ESWD16.yaml +128 -0
- package/api/vesyncswitch/ESWL01.yaml +56 -0
- package/api/vesyncswitch/ESWL03.yaml +56 -0
- package/dist/lib/helpers.d.ts +87 -0
- package/dist/lib/helpers.js +222 -0
- package/dist/lib/helpers.js.map +1 -0
- package/dist/lib/vesync.d.ts +47 -0
- package/dist/lib/vesync.js +309 -0
- package/dist/lib/vesync.js.map +1 -0
- package/dist/lib/vesyncBaseDevice.d.ts +68 -0
- package/dist/lib/vesyncBaseDevice.js +116 -0
- package/dist/lib/vesyncBaseDevice.js.map +1 -0
- package/dist/lib/vesyncBulb.d.ts +0 -0
- package/dist/lib/vesyncBulb.js +2 -0
- package/dist/lib/vesyncBulb.js.map +1 -0
- package/dist/lib/vesyncFan.d.ts +92 -0
- package/dist/lib/vesyncFan.js +265 -0
- package/dist/lib/vesyncFan.js.map +1 -0
- package/dist/lib/vesyncKitchen.d.ts +0 -0
- package/dist/lib/vesyncKitchen.js +2 -0
- package/dist/lib/vesyncKitchen.js.map +1 -0
- package/dist/lib/vesyncOutlet.d.ts +0 -0
- package/dist/lib/vesyncOutlet.js +2 -0
- package/dist/lib/vesyncOutlet.js.map +1 -0
- package/dist/lib/vesyncSwitch.d.ts +0 -0
- package/dist/lib/vesyncSwitch.js +2 -0
- package/dist/lib/vesyncSwitch.js.map +1 -0
- package/dist/src/lib/helpers.d.ts +88 -0
- package/dist/src/lib/helpers.js +244 -0
- package/dist/src/lib/vesync.d.ts +89 -0
- package/dist/src/lib/vesync.js +430 -0
- package/dist/src/lib/vesyncBaseDevice.d.ts +43 -0
- package/dist/src/lib/vesyncBaseDevice.js +87 -0
- package/dist/src/lib/vesyncBulb.d.ts +79 -0
- package/dist/src/lib/vesyncBulb.js +198 -0
- package/dist/src/lib/vesyncBulbImpl.d.ts +38 -0
- package/dist/src/lib/vesyncBulbImpl.js +161 -0
- package/dist/src/lib/vesyncFan.d.ts +80 -0
- package/dist/src/lib/vesyncFan.js +406 -0
- package/dist/src/lib/vesyncFanImpl.d.ts +137 -0
- package/dist/src/lib/vesyncFanImpl.js +643 -0
- package/dist/src/lib/vesyncOutlet.d.ts +53 -0
- package/dist/src/lib/vesyncOutlet.js +98 -0
- package/dist/src/lib/vesyncOutletImpl.d.ts +70 -0
- package/dist/src/lib/vesyncOutletImpl.js +206 -0
- package/dist/src/lib/vesyncSwitch.d.ts +169 -0
- package/dist/src/lib/vesyncSwitch.js +414 -0
- package/dist/src/lib/vesyncSwitchImpl.d.ts +82 -0
- package/dist/src/lib/vesyncSwitchImpl.js +290 -0
- package/dist/test/testFeatures.d.ts +4 -0
- package/dist/test/testFeatures.js +394 -0
- package/dist/test/testService.d.ts +62 -0
- package/dist/test/testService.js +540 -0
- package/dist/test/testSpecial.d.ts +5 -0
- package/dist/test/testSpecial.js +227 -0
- package/package.json +53 -0
- package/src/lib/helpers.ts +290 -0
- package/src/lib/vesync.ts +530 -0
- package/src/lib/vesyncBaseDevice.ts +114 -0
- package/src/lib/vesyncBulb.ts +252 -0
- package/src/lib/vesyncBulbImpl.ts +215 -0
- package/src/lib/vesyncFan.ts +447 -0
- package/src/lib/vesyncFanImpl.ts +848 -0
- package/src/lib/vesyncOutlet.ts +148 -0
- package/src/lib/vesyncOutletImpl.ts +284 -0
- package/src/lib/vesyncSwitch.ts +546 -0
- package/src/lib/vesyncSwitchImpl.ts +408 -0
|
@@ -0,0 +1,848 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VeSync Fan Implementations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { VeSyncFan } from './vesyncFan';
|
|
6
|
+
import { VeSync } from './vesync';
|
|
7
|
+
import { Helpers } from './helpers';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* VeSync Air Purifier with Bypass
|
|
11
|
+
*/
|
|
12
|
+
export class VeSyncAirBypass extends VeSyncFan {
|
|
13
|
+
protected readonly modes = ['auto', 'manual', 'sleep'] as const;
|
|
14
|
+
protected readonly speeds = [1, 2, 3, 4, 5];
|
|
15
|
+
protected readonly displayModes = ['on', 'off'] as const;
|
|
16
|
+
protected readonly childLockModes = ['on', 'off'] as const;
|
|
17
|
+
|
|
18
|
+
constructor(details: Record<string, any>, manager: VeSync) {
|
|
19
|
+
super(details, manager);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Get device details
|
|
24
|
+
*/
|
|
25
|
+
async getDetails(): Promise<void> {
|
|
26
|
+
const [response, status] = await Helpers.callApi(
|
|
27
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
28
|
+
'post',
|
|
29
|
+
{
|
|
30
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
31
|
+
cid: this.cid,
|
|
32
|
+
configModule: this.configModule,
|
|
33
|
+
payload: {
|
|
34
|
+
data: {},
|
|
35
|
+
method: 'getPurifierStatus',
|
|
36
|
+
source: 'APP'
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
Helpers.reqHeaderBypass()
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
if (this.checkResponse([response, status], 'getDetails')) {
|
|
43
|
+
const result = response?.result?.result;
|
|
44
|
+
if (result) {
|
|
45
|
+
// Update device status
|
|
46
|
+
this.deviceStatus = result.enabled ? 'on' : 'off';
|
|
47
|
+
|
|
48
|
+
// Store device settings
|
|
49
|
+
this.details = {
|
|
50
|
+
mode: result.mode || '',
|
|
51
|
+
speed: result.level || 0,
|
|
52
|
+
filterLife: result.filter_life || 0,
|
|
53
|
+
screenStatus: result.display || false,
|
|
54
|
+
childLock: result.child_lock || false,
|
|
55
|
+
airQuality: result.air_quality || 0
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Store configuration if available
|
|
59
|
+
if (result.configuration) {
|
|
60
|
+
this.config = result.configuration;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Turn device on
|
|
68
|
+
*/
|
|
69
|
+
async turnOn(): Promise<boolean> {
|
|
70
|
+
const [response, status] = await Helpers.callApi(
|
|
71
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
72
|
+
'post',
|
|
73
|
+
{
|
|
74
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
75
|
+
cid: this.cid,
|
|
76
|
+
configModule: this.configModule,
|
|
77
|
+
payload: {
|
|
78
|
+
data: {
|
|
79
|
+
enabled: true,
|
|
80
|
+
id: 0
|
|
81
|
+
},
|
|
82
|
+
method: 'setSwitch',
|
|
83
|
+
source: 'APP'
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
Helpers.reqHeaderBypass()
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
return this.checkResponse([response, status], 'turnOn');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Turn device off
|
|
94
|
+
*/
|
|
95
|
+
async turnOff(): Promise<boolean> {
|
|
96
|
+
const [response, status] = await Helpers.callApi(
|
|
97
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
98
|
+
'post',
|
|
99
|
+
{
|
|
100
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
101
|
+
cid: this.cid,
|
|
102
|
+
configModule: this.configModule,
|
|
103
|
+
payload: {
|
|
104
|
+
data: {
|
|
105
|
+
enabled: false,
|
|
106
|
+
id: 0
|
|
107
|
+
},
|
|
108
|
+
method: 'setSwitch',
|
|
109
|
+
source: 'APP'
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
Helpers.reqHeaderBypass()
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
return this.checkResponse([response, status], 'turnOff');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Change fan speed
|
|
120
|
+
*/
|
|
121
|
+
async changeFanSpeed(speed: number): Promise<boolean> {
|
|
122
|
+
if (!this.speeds.includes(speed)) {
|
|
123
|
+
throw new Error(`Invalid speed: ${speed}. Must be one of: ${this.speeds.join(', ')}`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const [response, status] = await Helpers.callApi(
|
|
127
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
128
|
+
'post',
|
|
129
|
+
{
|
|
130
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
131
|
+
cid: this.cid,
|
|
132
|
+
configModule: this.configModule,
|
|
133
|
+
payload: {
|
|
134
|
+
data: {
|
|
135
|
+
id: 0,
|
|
136
|
+
level: speed,
|
|
137
|
+
mode: 'manual',
|
|
138
|
+
type: 'wind'
|
|
139
|
+
},
|
|
140
|
+
method: 'setLevel',
|
|
141
|
+
source: 'APP'
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
Helpers.reqHeaderBypass()
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
return this.checkResponse([response, status], 'changeFanSpeed');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Set device mode
|
|
152
|
+
*/
|
|
153
|
+
async setMode(mode: string): Promise<boolean> {
|
|
154
|
+
if (!this.modes.includes(mode as any)) {
|
|
155
|
+
throw new Error(`Invalid mode: ${mode}. Must be one of: ${this.modes.join(', ')}`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const [response, status] = await Helpers.callApi(
|
|
159
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
160
|
+
'post',
|
|
161
|
+
{
|
|
162
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
163
|
+
cid: this.cid,
|
|
164
|
+
configModule: this.configModule,
|
|
165
|
+
payload: {
|
|
166
|
+
data: {
|
|
167
|
+
mode
|
|
168
|
+
},
|
|
169
|
+
method: 'setPurifierMode',
|
|
170
|
+
source: 'APP'
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
Helpers.reqHeaderBypass()
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
return this.checkResponse([response, status], 'setMode');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Set display status
|
|
181
|
+
*/
|
|
182
|
+
async setDisplay(enabled: boolean): Promise<boolean> {
|
|
183
|
+
if (!this.hasFeature('display')) {
|
|
184
|
+
throw new Error('Display control not supported');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const [response, status] = await Helpers.callApi(
|
|
188
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
189
|
+
'post',
|
|
190
|
+
{
|
|
191
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
192
|
+
cid: this.cid,
|
|
193
|
+
configModule: this.configModule,
|
|
194
|
+
payload: {
|
|
195
|
+
data: {
|
|
196
|
+
state: enabled
|
|
197
|
+
},
|
|
198
|
+
method: 'setDisplay',
|
|
199
|
+
source: 'APP'
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
Helpers.reqHeaderBypass()
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
return this.checkResponse([response, status], 'setDisplay');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Set child lock
|
|
210
|
+
*/
|
|
211
|
+
async setChildLock(enabled: boolean): Promise<boolean> {
|
|
212
|
+
if (!this.hasFeature('child_lock')) {
|
|
213
|
+
throw new Error('Child lock not supported');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const [response, status] = await Helpers.callApi(
|
|
217
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
218
|
+
'post',
|
|
219
|
+
{
|
|
220
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
221
|
+
cid: this.cid,
|
|
222
|
+
configModule: this.configModule,
|
|
223
|
+
payload: {
|
|
224
|
+
data: {
|
|
225
|
+
state: enabled
|
|
226
|
+
},
|
|
227
|
+
method: 'setChildLock',
|
|
228
|
+
source: 'APP'
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
Helpers.reqHeaderBypass()
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
return this.checkResponse([response, status], 'setChildLock');
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Set timer
|
|
239
|
+
*/
|
|
240
|
+
async setTimer(hours: number): Promise<boolean> {
|
|
241
|
+
if (!this.hasFeature('timer')) {
|
|
242
|
+
throw new Error('Timer not supported');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const [response, status] = await Helpers.callApi(
|
|
246
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
247
|
+
'post',
|
|
248
|
+
{
|
|
249
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
250
|
+
cid: this.cid,
|
|
251
|
+
configModule: this.configModule,
|
|
252
|
+
payload: {
|
|
253
|
+
data: {
|
|
254
|
+
action: 'off',
|
|
255
|
+
total: hours * 3600
|
|
256
|
+
},
|
|
257
|
+
method: 'addTimer',
|
|
258
|
+
source: 'APP'
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
Helpers.reqHeaderBypass()
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
return this.checkResponse([response, status], 'setTimer');
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Clear timer
|
|
269
|
+
*/
|
|
270
|
+
async clearTimer(): Promise<boolean> {
|
|
271
|
+
if (!this.hasFeature('timer')) {
|
|
272
|
+
throw new Error('Timer not supported');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const [response, status] = await Helpers.callApi(
|
|
276
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
277
|
+
'post',
|
|
278
|
+
{
|
|
279
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
280
|
+
cid: this.cid,
|
|
281
|
+
configModule: this.configModule,
|
|
282
|
+
payload: {
|
|
283
|
+
data: {},
|
|
284
|
+
method: 'deleteTimer',
|
|
285
|
+
source: 'APP'
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
Helpers.reqHeaderBypass()
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
return this.checkResponse([response, status], 'clearTimer');
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Turn automatic stop on
|
|
296
|
+
*/
|
|
297
|
+
async automaticStopOn(): Promise<boolean> {
|
|
298
|
+
const [response, status] = await Helpers.callApi(
|
|
299
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
300
|
+
'post',
|
|
301
|
+
{
|
|
302
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
303
|
+
cid: this.cid,
|
|
304
|
+
configModule: this.configModule,
|
|
305
|
+
payload: {
|
|
306
|
+
data: {
|
|
307
|
+
enabled: true
|
|
308
|
+
},
|
|
309
|
+
method: 'setAutomaticStop',
|
|
310
|
+
source: 'APP'
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
Helpers.reqHeaderBypass()
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
return this.checkResponse([response, status], 'automaticStopOn');
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Turn automatic stop off
|
|
321
|
+
*/
|
|
322
|
+
async automaticStopOff(): Promise<boolean> {
|
|
323
|
+
const [response, status] = await Helpers.callApi(
|
|
324
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
325
|
+
'post',
|
|
326
|
+
{
|
|
327
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
328
|
+
cid: this.cid,
|
|
329
|
+
configModule: this.configModule,
|
|
330
|
+
payload: {
|
|
331
|
+
data: {
|
|
332
|
+
enabled: false
|
|
333
|
+
},
|
|
334
|
+
method: 'setAutomaticStop',
|
|
335
|
+
source: 'APP'
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
Helpers.reqHeaderBypass()
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
return this.checkResponse([response, status], 'automaticStopOff');
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* VeSync Humidifier Base Class
|
|
347
|
+
*/
|
|
348
|
+
export class VeSyncHumidifier extends VeSyncFan {
|
|
349
|
+
protected readonly modes = ['auto', 'manual', 'sleep'] as const;
|
|
350
|
+
protected readonly speeds = [1, 2, 3];
|
|
351
|
+
protected readonly displayModes = ['on', 'off'] as const;
|
|
352
|
+
protected readonly mistLevels = [1, 2, 3];
|
|
353
|
+
protected readonly humidityRange = { min: 30, max: 80 };
|
|
354
|
+
|
|
355
|
+
constructor(details: Record<string, any>, manager: VeSync) {
|
|
356
|
+
super(details, manager);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Get device details
|
|
361
|
+
*/
|
|
362
|
+
async getDetails(): Promise<void> {
|
|
363
|
+
const [response, status] = await Helpers.callApi(
|
|
364
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
365
|
+
'post',
|
|
366
|
+
{
|
|
367
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
368
|
+
cid: this.cid,
|
|
369
|
+
configModule: this.configModule,
|
|
370
|
+
payload: {
|
|
371
|
+
data: {},
|
|
372
|
+
method: 'getHumidifierStatus',
|
|
373
|
+
source: 'APP'
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
Helpers.reqHeaderBypass()
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
if (this.checkResponse([response, status], 'getDetails')) {
|
|
380
|
+
this.details = response.result.result;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Turn device on
|
|
386
|
+
*/
|
|
387
|
+
async turnOn(): Promise<boolean> {
|
|
388
|
+
const [response, status] = await Helpers.callApi(
|
|
389
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
390
|
+
'post',
|
|
391
|
+
{
|
|
392
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
393
|
+
cid: this.cid,
|
|
394
|
+
configModule: this.configModule,
|
|
395
|
+
payload: {
|
|
396
|
+
data: {
|
|
397
|
+
enabled: true,
|
|
398
|
+
id: 0
|
|
399
|
+
},
|
|
400
|
+
method: 'setSwitch',
|
|
401
|
+
source: 'APP'
|
|
402
|
+
}
|
|
403
|
+
},
|
|
404
|
+
Helpers.reqHeaderBypass()
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
return this.checkResponse([response, status], 'turnOn');
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Turn device off
|
|
412
|
+
*/
|
|
413
|
+
async turnOff(): Promise<boolean> {
|
|
414
|
+
const [response, status] = await Helpers.callApi(
|
|
415
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
416
|
+
'post',
|
|
417
|
+
{
|
|
418
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
419
|
+
cid: this.cid,
|
|
420
|
+
configModule: this.configModule,
|
|
421
|
+
payload: {
|
|
422
|
+
data: {
|
|
423
|
+
enabled: false,
|
|
424
|
+
id: 0
|
|
425
|
+
},
|
|
426
|
+
method: 'setSwitch',
|
|
427
|
+
source: 'APP'
|
|
428
|
+
}
|
|
429
|
+
},
|
|
430
|
+
Helpers.reqHeaderBypass()
|
|
431
|
+
);
|
|
432
|
+
|
|
433
|
+
return this.checkResponse([response, status], 'turnOff');
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Change fan speed
|
|
438
|
+
*/
|
|
439
|
+
async changeFanSpeed(speed: number): Promise<boolean> {
|
|
440
|
+
if (!this.speeds.includes(speed)) {
|
|
441
|
+
throw new Error(`Invalid speed: ${speed}. Must be one of: ${this.speeds.join(', ')}`);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const [response, status] = await Helpers.callApi(
|
|
445
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
446
|
+
'post',
|
|
447
|
+
{
|
|
448
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
449
|
+
cid: this.cid,
|
|
450
|
+
configModule: this.configModule,
|
|
451
|
+
payload: {
|
|
452
|
+
data: {
|
|
453
|
+
id: 0,
|
|
454
|
+
level: speed,
|
|
455
|
+
type: 'wind'
|
|
456
|
+
},
|
|
457
|
+
method: 'setLevel',
|
|
458
|
+
source: 'APP'
|
|
459
|
+
}
|
|
460
|
+
},
|
|
461
|
+
Helpers.reqHeaderBypass()
|
|
462
|
+
);
|
|
463
|
+
|
|
464
|
+
return this.checkResponse([response, status], 'changeFanSpeed');
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Set device mode
|
|
469
|
+
*/
|
|
470
|
+
async setMode(mode: string): Promise<boolean> {
|
|
471
|
+
if (!this.modes.includes(mode as any)) {
|
|
472
|
+
throw new Error(`Invalid mode: ${mode}. Must be one of: ${this.modes.join(', ')}`);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const [response, status] = await Helpers.callApi(
|
|
476
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
477
|
+
'post',
|
|
478
|
+
{
|
|
479
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
480
|
+
cid: this.cid,
|
|
481
|
+
configModule: this.configModule,
|
|
482
|
+
payload: {
|
|
483
|
+
data: {
|
|
484
|
+
mode
|
|
485
|
+
},
|
|
486
|
+
method: 'setHumidifierMode',
|
|
487
|
+
source: 'APP'
|
|
488
|
+
}
|
|
489
|
+
},
|
|
490
|
+
Helpers.reqHeaderBypass()
|
|
491
|
+
);
|
|
492
|
+
|
|
493
|
+
return this.checkResponse([response, status], 'setMode');
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Set mist level
|
|
498
|
+
*/
|
|
499
|
+
async setMistLevel(level: number): Promise<boolean> {
|
|
500
|
+
if (!this.hasFeature('mist')) {
|
|
501
|
+
throw new Error('Mist control not supported');
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if (!this.mistLevels.includes(level)) {
|
|
505
|
+
throw new Error(`Invalid mist level: ${level}. Must be one of: ${this.mistLevels.join(', ')}`);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
const [response, status] = await Helpers.callApi(
|
|
509
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
510
|
+
'post',
|
|
511
|
+
{
|
|
512
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
513
|
+
cid: this.cid,
|
|
514
|
+
configModule: this.configModule,
|
|
515
|
+
payload: {
|
|
516
|
+
data: {
|
|
517
|
+
mistLevel: level
|
|
518
|
+
},
|
|
519
|
+
method: 'setMistLevel',
|
|
520
|
+
source: 'APP'
|
|
521
|
+
}
|
|
522
|
+
},
|
|
523
|
+
Helpers.reqHeaderBypass()
|
|
524
|
+
);
|
|
525
|
+
|
|
526
|
+
return this.checkResponse([response, status], 'setMistLevel');
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Set target humidity
|
|
531
|
+
*/
|
|
532
|
+
async setHumidity(humidity: number): Promise<boolean> {
|
|
533
|
+
if (!this.hasFeature('humidity')) {
|
|
534
|
+
throw new Error('Humidity control not supported');
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
if (humidity < this.humidityRange.min || humidity > this.humidityRange.max) {
|
|
538
|
+
throw new Error(`Invalid humidity: ${humidity}. Must be between ${this.humidityRange.min} and ${this.humidityRange.max}`);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
const [response, status] = await Helpers.callApi(
|
|
542
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
543
|
+
'post',
|
|
544
|
+
{
|
|
545
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
546
|
+
cid: this.cid,
|
|
547
|
+
configModule: this.configModule,
|
|
548
|
+
payload: {
|
|
549
|
+
data: {
|
|
550
|
+
targetHumidity: humidity
|
|
551
|
+
},
|
|
552
|
+
method: 'setTargetHumidity',
|
|
553
|
+
source: 'APP'
|
|
554
|
+
}
|
|
555
|
+
},
|
|
556
|
+
Helpers.reqHeaderBypass()
|
|
557
|
+
);
|
|
558
|
+
|
|
559
|
+
return this.checkResponse([response, status], 'setHumidity');
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Set display status
|
|
564
|
+
*/
|
|
565
|
+
async setDisplay(enabled: boolean): Promise<boolean> {
|
|
566
|
+
if (!this.hasFeature('display')) {
|
|
567
|
+
throw new Error('Display control not supported');
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
const [response, status] = await Helpers.callApi(
|
|
571
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
572
|
+
'post',
|
|
573
|
+
{
|
|
574
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
575
|
+
cid: this.cid,
|
|
576
|
+
configModule: this.configModule,
|
|
577
|
+
payload: {
|
|
578
|
+
data: {
|
|
579
|
+
state: enabled
|
|
580
|
+
},
|
|
581
|
+
method: 'setDisplay',
|
|
582
|
+
source: 'APP'
|
|
583
|
+
}
|
|
584
|
+
},
|
|
585
|
+
Helpers.reqHeaderBypass()
|
|
586
|
+
);
|
|
587
|
+
|
|
588
|
+
return this.checkResponse([response, status], 'setDisplay');
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Set timer
|
|
593
|
+
*/
|
|
594
|
+
async setTimer(hours: number): Promise<boolean> {
|
|
595
|
+
if (!this.hasFeature('timer')) {
|
|
596
|
+
throw new Error('Timer not supported');
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
const [response, status] = await Helpers.callApi(
|
|
600
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
601
|
+
'post',
|
|
602
|
+
{
|
|
603
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
604
|
+
cid: this.cid,
|
|
605
|
+
configModule: this.configModule,
|
|
606
|
+
payload: {
|
|
607
|
+
data: {
|
|
608
|
+
action: 'off',
|
|
609
|
+
total: hours * 3600
|
|
610
|
+
},
|
|
611
|
+
method: 'addTimer',
|
|
612
|
+
source: 'APP'
|
|
613
|
+
}
|
|
614
|
+
},
|
|
615
|
+
Helpers.reqHeaderBypass()
|
|
616
|
+
);
|
|
617
|
+
|
|
618
|
+
return this.checkResponse([response, status], 'setTimer');
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Clear timer
|
|
623
|
+
*/
|
|
624
|
+
async clearTimer(): Promise<boolean> {
|
|
625
|
+
if (!this.hasFeature('timer')) {
|
|
626
|
+
throw new Error('Timer not supported');
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
const [response, status] = await Helpers.callApi(
|
|
630
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
631
|
+
'post',
|
|
632
|
+
{
|
|
633
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
634
|
+
cid: this.cid,
|
|
635
|
+
configModule: this.configModule,
|
|
636
|
+
payload: {
|
|
637
|
+
data: {},
|
|
638
|
+
method: 'deleteTimer',
|
|
639
|
+
source: 'APP'
|
|
640
|
+
}
|
|
641
|
+
},
|
|
642
|
+
Helpers.reqHeaderBypass()
|
|
643
|
+
);
|
|
644
|
+
|
|
645
|
+
return this.checkResponse([response, status], 'clearTimer');
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* Turn automatic stop on
|
|
650
|
+
*/
|
|
651
|
+
async automaticStopOn(): Promise<boolean> {
|
|
652
|
+
const [response, status] = await Helpers.callApi(
|
|
653
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
654
|
+
'post',
|
|
655
|
+
{
|
|
656
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
657
|
+
cid: this.cid,
|
|
658
|
+
configModule: this.configModule,
|
|
659
|
+
payload: {
|
|
660
|
+
data: {
|
|
661
|
+
enabled: true
|
|
662
|
+
},
|
|
663
|
+
method: 'setAutomaticStop',
|
|
664
|
+
source: 'APP'
|
|
665
|
+
}
|
|
666
|
+
},
|
|
667
|
+
Helpers.reqHeaderBypass()
|
|
668
|
+
);
|
|
669
|
+
|
|
670
|
+
return this.checkResponse([response, status], 'automaticStopOn');
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Turn automatic stop off
|
|
675
|
+
*/
|
|
676
|
+
async automaticStopOff(): Promise<boolean> {
|
|
677
|
+
const [response, status] = await Helpers.callApi(
|
|
678
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
679
|
+
'post',
|
|
680
|
+
{
|
|
681
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
682
|
+
cid: this.cid,
|
|
683
|
+
configModule: this.configModule,
|
|
684
|
+
payload: {
|
|
685
|
+
data: {
|
|
686
|
+
enabled: false
|
|
687
|
+
},
|
|
688
|
+
method: 'setAutomaticStop',
|
|
689
|
+
source: 'APP'
|
|
690
|
+
}
|
|
691
|
+
},
|
|
692
|
+
Helpers.reqHeaderBypass()
|
|
693
|
+
);
|
|
694
|
+
|
|
695
|
+
return this.checkResponse([response, status], 'automaticStopOff');
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* VeSync Warm Humidifier Class
|
|
701
|
+
*/
|
|
702
|
+
export class VeSyncWarmHumidifier extends VeSyncHumidifier {
|
|
703
|
+
protected readonly warmLevels = [1, 2, 3];
|
|
704
|
+
|
|
705
|
+
constructor(details: Record<string, any>, manager: VeSync) {
|
|
706
|
+
super(details, manager);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* Set warm mist level
|
|
711
|
+
*/
|
|
712
|
+
async setWarmLevel(level: number): Promise<boolean> {
|
|
713
|
+
if (!this.hasFeature('warm')) {
|
|
714
|
+
throw new Error('Warm mist control not supported');
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
if (!this.warmLevels.includes(level)) {
|
|
718
|
+
throw new Error(`Invalid warm level: ${level}. Must be one of: ${this.warmLevels.join(', ')}`);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
const [response, status] = await Helpers.callApi(
|
|
722
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
723
|
+
'post',
|
|
724
|
+
{
|
|
725
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
726
|
+
cid: this.cid,
|
|
727
|
+
configModule: this.configModule,
|
|
728
|
+
payload: {
|
|
729
|
+
data: {
|
|
730
|
+
warmLevel: level
|
|
731
|
+
},
|
|
732
|
+
method: 'setWarmLevel',
|
|
733
|
+
source: 'APP'
|
|
734
|
+
}
|
|
735
|
+
},
|
|
736
|
+
Helpers.reqHeaderBypass()
|
|
737
|
+
);
|
|
738
|
+
|
|
739
|
+
return this.checkResponse([response, status], 'setWarmLevel');
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Set drying mode enabled
|
|
744
|
+
*/
|
|
745
|
+
async setDryingModeEnabled(enabled: boolean): Promise<boolean> {
|
|
746
|
+
if (!this.hasFeature('drying')) {
|
|
747
|
+
throw new Error('Drying mode not supported');
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
const [response, status] = await Helpers.callApi(
|
|
751
|
+
'/cloud/v2/deviceManaged/bypassV2',
|
|
752
|
+
'post',
|
|
753
|
+
{
|
|
754
|
+
...Helpers.reqBody(this.manager, 'bypassV2'),
|
|
755
|
+
cid: this.cid,
|
|
756
|
+
configModule: this.configModule,
|
|
757
|
+
payload: {
|
|
758
|
+
data: {
|
|
759
|
+
autoDryingSwitch: enabled ? 1 : 0
|
|
760
|
+
},
|
|
761
|
+
method: 'setDryingMode',
|
|
762
|
+
source: 'APP'
|
|
763
|
+
}
|
|
764
|
+
},
|
|
765
|
+
Helpers.reqHeaderBypass()
|
|
766
|
+
);
|
|
767
|
+
|
|
768
|
+
return this.checkResponse([response, status], 'setDryingModeEnabled');
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
// Export fan modules dictionary
|
|
773
|
+
export const fanModules: Record<string, new (details: Record<string, any>, manager: VeSync) => VeSyncFan> = {
|
|
774
|
+
// Core Series
|
|
775
|
+
'Core200S': VeSyncAirBypass,
|
|
776
|
+
'Core300S': VeSyncAirBypass,
|
|
777
|
+
'Core400S': VeSyncAirBypass,
|
|
778
|
+
'Core600S': VeSyncAirBypass,
|
|
779
|
+
|
|
780
|
+
// LAP Series
|
|
781
|
+
'LAP-C201S-AUSR': VeSyncAirBypass,
|
|
782
|
+
'LAP-C202S-WUSR': VeSyncAirBypass,
|
|
783
|
+
'LAP-C301S-WJP': VeSyncAirBypass,
|
|
784
|
+
'LAP-C302S-WUSB': VeSyncAirBypass,
|
|
785
|
+
'LAP-C301S-WAAA': VeSyncAirBypass,
|
|
786
|
+
'LAP-C401S-WJP': VeSyncAirBypass,
|
|
787
|
+
'LAP-C401S-WUSR': VeSyncAirBypass,
|
|
788
|
+
'LAP-C401S-WAAA': VeSyncAirBypass,
|
|
789
|
+
'LAP-C601S-WUS': VeSyncAirBypass,
|
|
790
|
+
'LAP-C601S-WUSR': VeSyncAirBypass,
|
|
791
|
+
'LAP-C601S-WEU': VeSyncAirBypass,
|
|
792
|
+
'LAP-V102S-AASR': VeSyncAirBypass,
|
|
793
|
+
'LAP-V102S-WUS': VeSyncAirBypass,
|
|
794
|
+
'LAP-V102S-WEU': VeSyncAirBypass,
|
|
795
|
+
'LAP-V102S-AUSR': VeSyncAirBypass,
|
|
796
|
+
'LAP-V102S-WJP': VeSyncAirBypass,
|
|
797
|
+
'LAP-V201S-AASR': VeSyncAirBypass,
|
|
798
|
+
'LAP-V201S-WJP': VeSyncAirBypass,
|
|
799
|
+
'LAP-V201S-WEU': VeSyncAirBypass,
|
|
800
|
+
'LAP-V201S-WUS': VeSyncAirBypass,
|
|
801
|
+
'LAP-V201-AUSR': VeSyncAirBypass,
|
|
802
|
+
'LAP-V201S-AUSR': VeSyncAirBypass,
|
|
803
|
+
'LAP-V201S-AEUR': VeSyncAirBypass,
|
|
804
|
+
'LAP-EL551S-AUS': VeSyncAirBypass,
|
|
805
|
+
'LAP-EL551S-AEUR': VeSyncAirBypass,
|
|
806
|
+
'LAP-EL551S-WEU': VeSyncAirBypass,
|
|
807
|
+
'LAP-EL551S-WUS': VeSyncAirBypass,
|
|
808
|
+
|
|
809
|
+
// LTF Series
|
|
810
|
+
'LTF-F422S-KEU': VeSyncAirBypass,
|
|
811
|
+
'LTF-F422S-WUSR': VeSyncAirBypass,
|
|
812
|
+
'LTF-F422_WJP': VeSyncAirBypass,
|
|
813
|
+
'LTF-F422S-WUS': VeSyncAirBypass,
|
|
814
|
+
|
|
815
|
+
// Classic Series
|
|
816
|
+
'Classic300S': VeSyncHumidifier,
|
|
817
|
+
'Classic200S': VeSyncHumidifier,
|
|
818
|
+
|
|
819
|
+
// Dual Series
|
|
820
|
+
'Dual200S': VeSyncHumidifier,
|
|
821
|
+
|
|
822
|
+
// LUH Series
|
|
823
|
+
'LUH-A601S-WUSB': VeSyncWarmHumidifier,
|
|
824
|
+
'LUH-A601S-AUSW': VeSyncWarmHumidifier,
|
|
825
|
+
'LUH-D301S-WUSR': VeSyncWarmHumidifier,
|
|
826
|
+
'LUH-D301S-WJP': VeSyncWarmHumidifier,
|
|
827
|
+
'LUH-D301S-WEU': VeSyncWarmHumidifier,
|
|
828
|
+
'LUH-A602S-WUSR': VeSyncWarmHumidifier,
|
|
829
|
+
'LUH-A602S-WUS': VeSyncWarmHumidifier,
|
|
830
|
+
'LUH-A602S-WEUR': VeSyncWarmHumidifier,
|
|
831
|
+
'LUH-A602S-WEU': VeSyncWarmHumidifier,
|
|
832
|
+
'LUH-A602S-WJP': VeSyncWarmHumidifier,
|
|
833
|
+
'LUH-A602S-WUSC': VeSyncWarmHumidifier,
|
|
834
|
+
'LUH-O451S-WEU': VeSyncWarmHumidifier,
|
|
835
|
+
'LUH-O451S-WUS': VeSyncWarmHumidifier,
|
|
836
|
+
'LUH-O451S-WUSR': VeSyncWarmHumidifier,
|
|
837
|
+
'LUH-O601S-WUS': VeSyncWarmHumidifier,
|
|
838
|
+
'LUH-O601S-KUS': VeSyncWarmHumidifier,
|
|
839
|
+
'LUH-M101S-WUS': VeSyncWarmHumidifier,
|
|
840
|
+
|
|
841
|
+
// LEH Series
|
|
842
|
+
'LEH-S601S-WUS': VeSyncWarmHumidifier,
|
|
843
|
+
'LEH-S601S-WUSR': VeSyncWarmHumidifier,
|
|
844
|
+
|
|
845
|
+
// LV Series
|
|
846
|
+
'LV-PUR131S': VeSyncAirBypass,
|
|
847
|
+
'LV-RH131S': VeSyncAirBypass
|
|
848
|
+
};
|