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.
Files changed (138) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +227 -0
  3. package/api/vesync/VeSync.yaml +33 -0
  4. package/api/vesyncbulb/ESL100.yaml +74 -0
  5. package/api/vesyncbulb/ESL100CW.yaml +123 -0
  6. package/api/vesyncbulb/ESL100MC.yaml +169 -0
  7. package/api/vesyncbulb/XYD0001.yaml +193 -0
  8. package/api/vesyncfan/Classic200S.yaml +280 -0
  9. package/api/vesyncfan/Classic300S.yaml +278 -0
  10. package/api/vesyncfan/Core200S.yaml +256 -0
  11. package/api/vesyncfan/Core300S.yaml +281 -0
  12. package/api/vesyncfan/Core400S.yaml +281 -0
  13. package/api/vesyncfan/Core600S.yaml +281 -0
  14. package/api/vesyncfan/Dual200S.yaml +278 -0
  15. package/api/vesyncfan/LAP-C201S-AUSR.yaml +256 -0
  16. package/api/vesyncfan/LAP-C202S-WUSR.yaml +256 -0
  17. package/api/vesyncfan/LAP-C301S-WAAA.yaml +281 -0
  18. package/api/vesyncfan/LAP-C301S-WJP.yaml +281 -0
  19. package/api/vesyncfan/LAP-C302S-WUSB.yaml +281 -0
  20. package/api/vesyncfan/LAP-C401S-WAAA.yaml +281 -0
  21. package/api/vesyncfan/LAP-C401S-WJP.yaml +281 -0
  22. package/api/vesyncfan/LAP-C401S-WUSR.yaml +281 -0
  23. package/api/vesyncfan/LAP-C601S-WEU.yaml +281 -0
  24. package/api/vesyncfan/LAP-C601S-WUS.yaml +281 -0
  25. package/api/vesyncfan/LAP-C601S-WUSR.yaml +281 -0
  26. package/api/vesyncfan/LAP-EL551S-AEUR.yaml +167 -0
  27. package/api/vesyncfan/LAP-EL551S-AUS.yaml +167 -0
  28. package/api/vesyncfan/LAP-EL551S-WEU.yaml +167 -0
  29. package/api/vesyncfan/LAP-EL551S-WUS.yaml +167 -0
  30. package/api/vesyncfan/LAP-V102S-AASR.yaml +167 -0
  31. package/api/vesyncfan/LAP-V102S-AUSR.yaml +167 -0
  32. package/api/vesyncfan/LAP-V102S-WEU.yaml +167 -0
  33. package/api/vesyncfan/LAP-V102S-WJP.yaml +167 -0
  34. package/api/vesyncfan/LAP-V102S-WUS.yaml +167 -0
  35. package/api/vesyncfan/LAP-V201-AUSR.yaml +167 -0
  36. package/api/vesyncfan/LAP-V201S-AASR.yaml +167 -0
  37. package/api/vesyncfan/LAP-V201S-AEUR.yaml +167 -0
  38. package/api/vesyncfan/LAP-V201S-AUSR.yaml +167 -0
  39. package/api/vesyncfan/LAP-V201S-WEU.yaml +167 -0
  40. package/api/vesyncfan/LAP-V201S-WJP.yaml +167 -0
  41. package/api/vesyncfan/LAP-V201S-WUS.yaml +167 -0
  42. package/api/vesyncfan/LEH-S601S-WUS.yaml +303 -0
  43. package/api/vesyncfan/LEH-S601S-WUSR.yaml +82 -0
  44. package/api/vesyncfan/LTF-F422S-KEU.yaml +165 -0
  45. package/api/vesyncfan/LTF-F422S-WUS.yaml +165 -0
  46. package/api/vesyncfan/LTF-F422S-WUSR.yaml +167 -0
  47. package/api/vesyncfan/LTF-F422_WJP.yaml +165 -0
  48. package/api/vesyncfan/LUH-A601S-AUSW.yaml +82 -0
  49. package/api/vesyncfan/LUH-A601S-WUSB.yaml +305 -0
  50. package/api/vesyncfan/LUH-A602S-WEU.yaml +305 -0
  51. package/api/vesyncfan/LUH-A602S-WEUR.yaml +305 -0
  52. package/api/vesyncfan/LUH-A602S-WJP.yaml +305 -0
  53. package/api/vesyncfan/LUH-A602S-WUS.yaml +305 -0
  54. package/api/vesyncfan/LUH-A602S-WUSC.yaml +305 -0
  55. package/api/vesyncfan/LUH-A602S-WUSR.yaml +305 -0
  56. package/api/vesyncfan/LUH-D301S-WEU.yaml +305 -0
  57. package/api/vesyncfan/LUH-D301S-WJP.yaml +305 -0
  58. package/api/vesyncfan/LUH-D301S-WUSR.yaml +305 -0
  59. package/api/vesyncfan/LUH-M101S-WUS.yaml +278 -0
  60. package/api/vesyncfan/LUH-O451S-WEU.yaml +278 -0
  61. package/api/vesyncfan/LUH-O451S-WUS.yaml +278 -0
  62. package/api/vesyncfan/LUH-O451S-WUSR.yaml +305 -0
  63. package/api/vesyncfan/LUH-O601S-KUS.yaml +305 -0
  64. package/api/vesyncfan/LUH-O601S-WUS.yaml +305 -0
  65. package/api/vesyncfan/LV-PUR131S.yaml +108 -0
  66. package/api/vesyncfan/LV-RH131S.yaml +108 -0
  67. package/api/vesyncoutlet/ESO15-TB.yaml +124 -0
  68. package/api/vesyncoutlet/ESW01-EU.yaml +122 -0
  69. package/api/vesyncoutlet/ESW03-USA.yaml +122 -0
  70. package/api/vesyncoutlet/ESW15-USA.yaml +156 -0
  71. package/api/vesyncoutlet/wifi-switch-1.3.yaml +60 -0
  72. package/api/vesyncswitch/ESWD16.yaml +128 -0
  73. package/api/vesyncswitch/ESWL01.yaml +56 -0
  74. package/api/vesyncswitch/ESWL03.yaml +56 -0
  75. package/dist/lib/helpers.d.ts +87 -0
  76. package/dist/lib/helpers.js +222 -0
  77. package/dist/lib/helpers.js.map +1 -0
  78. package/dist/lib/vesync.d.ts +47 -0
  79. package/dist/lib/vesync.js +309 -0
  80. package/dist/lib/vesync.js.map +1 -0
  81. package/dist/lib/vesyncBaseDevice.d.ts +68 -0
  82. package/dist/lib/vesyncBaseDevice.js +116 -0
  83. package/dist/lib/vesyncBaseDevice.js.map +1 -0
  84. package/dist/lib/vesyncBulb.d.ts +0 -0
  85. package/dist/lib/vesyncBulb.js +2 -0
  86. package/dist/lib/vesyncBulb.js.map +1 -0
  87. package/dist/lib/vesyncFan.d.ts +92 -0
  88. package/dist/lib/vesyncFan.js +265 -0
  89. package/dist/lib/vesyncFan.js.map +1 -0
  90. package/dist/lib/vesyncKitchen.d.ts +0 -0
  91. package/dist/lib/vesyncKitchen.js +2 -0
  92. package/dist/lib/vesyncKitchen.js.map +1 -0
  93. package/dist/lib/vesyncOutlet.d.ts +0 -0
  94. package/dist/lib/vesyncOutlet.js +2 -0
  95. package/dist/lib/vesyncOutlet.js.map +1 -0
  96. package/dist/lib/vesyncSwitch.d.ts +0 -0
  97. package/dist/lib/vesyncSwitch.js +2 -0
  98. package/dist/lib/vesyncSwitch.js.map +1 -0
  99. package/dist/src/lib/helpers.d.ts +88 -0
  100. package/dist/src/lib/helpers.js +244 -0
  101. package/dist/src/lib/vesync.d.ts +89 -0
  102. package/dist/src/lib/vesync.js +430 -0
  103. package/dist/src/lib/vesyncBaseDevice.d.ts +43 -0
  104. package/dist/src/lib/vesyncBaseDevice.js +87 -0
  105. package/dist/src/lib/vesyncBulb.d.ts +79 -0
  106. package/dist/src/lib/vesyncBulb.js +198 -0
  107. package/dist/src/lib/vesyncBulbImpl.d.ts +38 -0
  108. package/dist/src/lib/vesyncBulbImpl.js +161 -0
  109. package/dist/src/lib/vesyncFan.d.ts +80 -0
  110. package/dist/src/lib/vesyncFan.js +406 -0
  111. package/dist/src/lib/vesyncFanImpl.d.ts +137 -0
  112. package/dist/src/lib/vesyncFanImpl.js +643 -0
  113. package/dist/src/lib/vesyncOutlet.d.ts +53 -0
  114. package/dist/src/lib/vesyncOutlet.js +98 -0
  115. package/dist/src/lib/vesyncOutletImpl.d.ts +70 -0
  116. package/dist/src/lib/vesyncOutletImpl.js +206 -0
  117. package/dist/src/lib/vesyncSwitch.d.ts +169 -0
  118. package/dist/src/lib/vesyncSwitch.js +414 -0
  119. package/dist/src/lib/vesyncSwitchImpl.d.ts +82 -0
  120. package/dist/src/lib/vesyncSwitchImpl.js +290 -0
  121. package/dist/test/testFeatures.d.ts +4 -0
  122. package/dist/test/testFeatures.js +394 -0
  123. package/dist/test/testService.d.ts +62 -0
  124. package/dist/test/testService.js +540 -0
  125. package/dist/test/testSpecial.d.ts +5 -0
  126. package/dist/test/testSpecial.js +227 -0
  127. package/package.json +53 -0
  128. package/src/lib/helpers.ts +290 -0
  129. package/src/lib/vesync.ts +530 -0
  130. package/src/lib/vesyncBaseDevice.ts +114 -0
  131. package/src/lib/vesyncBulb.ts +252 -0
  132. package/src/lib/vesyncBulbImpl.ts +215 -0
  133. package/src/lib/vesyncFan.ts +447 -0
  134. package/src/lib/vesyncFanImpl.ts +848 -0
  135. package/src/lib/vesyncOutlet.ts +148 -0
  136. package/src/lib/vesyncOutletImpl.ts +284 -0
  137. package/src/lib/vesyncSwitch.ts +546 -0
  138. 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
+ };