tsvesync 1.3.13 → 1.4.1

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.
@@ -13,158 +13,217 @@ exports.fanConfig = {
13
13
  'Core200S': {
14
14
  module: 'VeSyncAirBypass',
15
15
  features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'sleep_mode', 'filter_life'],
16
- levels: [1, 2, 3, 4] // 4 levels including sleep mode, matching reference plugin
16
+ levels: [1, 2, 3, 4], // 4 levels including sleep mode, matching reference plugin
17
+ modes: ['sleep', 'manual']
17
18
  },
18
19
  'Core300S': {
19
20
  module: 'VeSyncAirBypass',
20
21
  features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
21
- levels: [1, 2, 3, 4]
22
+ levels: [1, 2, 3, 4],
23
+ modes: ['sleep', 'manual', 'auto'],
24
+ autoPreferences: ['default', 'efficient', 'quiet']
22
25
  },
23
26
  'Core400S': {
24
27
  module: 'VeSyncAirBypass',
25
28
  features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
26
- levels: [1, 2, 3, 4]
29
+ levels: [1, 2, 3, 4],
30
+ modes: ['sleep', 'manual', 'auto'],
31
+ autoPreferences: ['default', 'efficient', 'quiet']
27
32
  },
28
33
  'Core600S': {
29
34
  module: 'VeSyncAirBypass',
30
35
  features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
31
- levels: [1, 2, 3, 4]
36
+ levels: [1, 2, 3, 4],
37
+ modes: ['sleep', 'manual', 'auto'],
38
+ autoPreferences: ['default', 'efficient', 'quiet']
32
39
  },
33
40
  // LAP Series
34
41
  'LAP-C201S-AUSR': {
35
42
  module: 'VeSyncAirBypass',
36
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
37
- levels: [1, 2, 3]
43
+ features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'sleep_mode', 'filter_life'],
44
+ levels: [1, 2, 3],
45
+ modes: ['sleep', 'manual']
38
46
  },
39
47
  'LAP-C202S-WUSR': {
40
48
  module: 'VeSyncAirBypass',
41
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
42
- levels: [1, 2, 3]
49
+ features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'sleep_mode', 'filter_life'],
50
+ levels: [1, 2, 3],
51
+ modes: ['sleep', 'manual']
43
52
  },
44
53
  'LAP-C301S-WJP': {
45
54
  module: 'VeSyncAirBypass',
46
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
47
- levels: [1, 2, 3, 4]
55
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
56
+ levels: [1, 2, 3, 4],
57
+ modes: ['sleep', 'manual', 'auto'],
58
+ autoPreferences: ['default', 'efficient', 'quiet']
48
59
  },
49
60
  'LAP-C302S-WUSB': {
50
61
  module: 'VeSyncAirBypass',
51
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
52
- levels: [1, 2, 3, 4]
62
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
63
+ levels: [1, 2, 3, 4],
64
+ modes: ['sleep', 'manual', 'auto'],
65
+ autoPreferences: ['default', 'efficient', 'quiet']
53
66
  },
54
67
  'LAP-C301S-WAAA': {
55
68
  module: 'VeSyncAirBypass',
56
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
57
- levels: [1, 2, 3, 4]
69
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
70
+ levels: [1, 2, 3, 4],
71
+ modes: ['sleep', 'manual', 'auto'],
72
+ autoPreferences: ['default', 'efficient', 'quiet']
58
73
  },
59
74
  'LAP-C401S-WJP': {
60
75
  module: 'VeSyncAirBypass',
61
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
62
- levels: [1, 2, 3, 4]
76
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
77
+ levels: [1, 2, 3, 4],
78
+ modes: ['sleep', 'manual', 'auto'],
79
+ autoPreferences: ['default', 'efficient', 'quiet']
63
80
  },
64
81
  'LAP-C401S-WUSR': {
65
82
  module: 'VeSyncAirBypass',
66
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
67
- levels: [1, 2, 3, 4]
83
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
84
+ levels: [1, 2, 3, 4],
85
+ modes: ['sleep', 'manual', 'auto'],
86
+ autoPreferences: ['default', 'efficient', 'quiet']
68
87
  },
69
88
  'LAP-C401S-WAAA': {
70
89
  module: 'VeSyncAirBypass',
71
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
72
- levels: [1, 2, 3, 4]
90
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
91
+ levels: [1, 2, 3, 4],
92
+ modes: ['sleep', 'manual', 'auto'],
93
+ autoPreferences: ['default', 'efficient', 'quiet']
73
94
  },
74
95
  'LAP-C601S-WUS': {
75
96
  module: 'VeSyncAirBypass',
76
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
77
- levels: [1, 2, 3, 4]
97
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
98
+ levels: [1, 2, 3, 4],
99
+ modes: ['sleep', 'manual', 'auto'],
100
+ autoPreferences: ['default', 'efficient', 'quiet']
78
101
  },
79
102
  'LAP-C601S-WUSR': {
80
103
  module: 'VeSyncAirBypass',
81
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
82
- levels: [1, 2, 3, 4]
104
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
105
+ levels: [1, 2, 3, 4],
106
+ modes: ['sleep', 'manual', 'auto'],
107
+ autoPreferences: ['default', 'efficient', 'quiet']
83
108
  },
84
109
  'LAP-C601S-WEU': {
85
110
  module: 'VeSyncAirBypass',
86
- features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
87
- levels: [1, 2, 3, 4]
111
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
112
+ levels: [1, 2, 3, 4],
113
+ modes: ['sleep', 'manual', 'auto'],
114
+ autoPreferences: ['default', 'efficient', 'quiet']
88
115
  },
89
116
  'LAP-V102S-AASR': {
90
117
  module: 'VeSyncAirBaseV2',
91
- features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'filter_life'],
92
- levels: [1, 2, 3, 4]
118
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'pet_mode', 'filter_life'],
119
+ levels: [1, 2, 3, 4],
120
+ modes: ['sleep', 'manual', 'auto', 'pet'],
121
+ autoPreferences: ['default', 'efficient', 'quiet']
93
122
  },
94
123
  'LAP-V102S-WUS': {
95
124
  module: 'VeSyncAirBaseV2',
96
- features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'filter_life'],
97
- levels: [1, 2, 3, 4]
125
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'pet_mode', 'filter_life'],
126
+ levels: [1, 2, 3, 4],
127
+ modes: ['sleep', 'manual', 'auto', 'pet'],
128
+ autoPreferences: ['default', 'efficient', 'quiet']
98
129
  },
99
130
  'LAP-V102S-WEU': {
100
131
  module: 'VeSyncAirBaseV2',
101
- features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'filter_life'],
102
- levels: [1, 2, 3, 4]
132
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'pet_mode', 'filter_life'],
133
+ levels: [1, 2, 3, 4],
134
+ modes: ['sleep', 'manual', 'auto', 'pet'],
135
+ autoPreferences: ['default', 'efficient', 'quiet']
103
136
  },
104
137
  'LAP-V102S-AUSR': {
105
138
  module: 'VeSyncAirBaseV2',
106
- features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'filter_life'],
107
- levels: [1, 2, 3, 4]
139
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'pet_mode', 'filter_life'],
140
+ levels: [1, 2, 3, 4],
141
+ modes: ['sleep', 'manual', 'auto', 'pet'],
142
+ autoPreferences: ['default', 'efficient', 'quiet']
108
143
  },
109
144
  'LAP-V102S-WJP': {
110
145
  module: 'VeSyncAirBaseV2',
111
- features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'filter_life'],
112
- levels: [1, 2, 3, 4]
146
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'pet_mode', 'filter_life'],
147
+ levels: [1, 2, 3, 4],
148
+ modes: ['sleep', 'manual', 'auto', 'pet'],
149
+ autoPreferences: ['default', 'efficient', 'quiet']
113
150
  },
114
151
  'LAP-V201S-AASR': {
115
152
  module: 'VeSyncAirBaseV2',
116
- features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'light_detection', 'fan_speed', 'auto_mode', 'filter_life'],
117
- levels: [1, 2, 3, 4]
153
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'light_detection', 'fan_speed', 'auto_mode', 'sleep_mode', 'pet_mode', 'filter_life'],
154
+ levels: [1, 2, 3, 4],
155
+ modes: ['sleep', 'manual', 'auto', 'pet'],
156
+ autoPreferences: ['default', 'efficient', 'quiet']
118
157
  },
119
158
  'LAP-V201S-WJP': {
120
159
  module: 'VeSyncAirBaseV2',
121
- features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'light_detection', 'fan_speed', 'auto_mode', 'filter_life'],
122
- levels: [1, 2, 3, 4]
160
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'light_detection', 'fan_speed', 'auto_mode', 'sleep_mode', 'pet_mode', 'filter_life'],
161
+ levels: [1, 2, 3, 4],
162
+ modes: ['sleep', 'manual', 'auto', 'pet'],
163
+ autoPreferences: ['default', 'efficient', 'quiet']
123
164
  },
124
165
  'LAP-V201S-WEU': {
125
166
  module: 'VeSyncAirBaseV2',
126
- features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'light_detection', 'fan_speed', 'auto_mode', 'filter_life'],
127
- levels: [1, 2, 3, 4]
167
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'light_detection', 'fan_speed', 'auto_mode', 'sleep_mode', 'pet_mode', 'filter_life'],
168
+ levels: [1, 2, 3, 4],
169
+ modes: ['sleep', 'manual', 'auto', 'pet'],
170
+ autoPreferences: ['default', 'efficient', 'quiet']
128
171
  },
129
172
  'LAP-V201S-WUS': {
130
173
  module: 'VeSyncAirBaseV2',
131
- features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'light_detection', 'fan_speed', 'auto_mode', 'filter_life'],
132
- levels: [1, 2, 3, 4]
174
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'light_detection', 'fan_speed', 'auto_mode', 'sleep_mode', 'pet_mode', 'filter_life'],
175
+ levels: [1, 2, 3, 4],
176
+ modes: ['sleep', 'manual', 'auto', 'pet'],
177
+ autoPreferences: ['default', 'efficient', 'quiet']
133
178
  },
134
179
  'LAP-V201-AUSR': {
135
180
  module: 'VeSyncAirBaseV2',
136
- features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'light_detection', 'fan_speed', 'auto_mode', 'filter_life'],
137
- levels: [1, 2, 3, 4]
181
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'light_detection', 'fan_speed', 'auto_mode', 'sleep_mode', 'pet_mode', 'filter_life'],
182
+ levels: [1, 2, 3, 4],
183
+ modes: ['sleep', 'manual', 'auto', 'pet'],
184
+ autoPreferences: ['default', 'efficient', 'quiet']
138
185
  },
139
186
  'LAP-V201S-AUSR': {
140
187
  module: 'VeSyncAirBaseV2',
141
- features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'light_detection', 'fan_speed', 'auto_mode', 'filter_life'],
142
- levels: [1, 2, 3, 4]
188
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'light_detection', 'fan_speed', 'auto_mode', 'sleep_mode', 'pet_mode', 'filter_life'],
189
+ levels: [1, 2, 3, 4],
190
+ modes: ['sleep', 'manual', 'auto', 'pet'],
191
+ autoPreferences: ['default', 'efficient', 'quiet']
143
192
  },
144
193
  'LAP-V201S-AEUR': {
145
194
  module: 'VeSyncAirBaseV2',
146
- features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'light_detection', 'fan_speed', 'auto_mode', 'filter_life'],
147
- levels: [1, 2, 3, 4]
195
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'light_detection', 'fan_speed', 'auto_mode', 'sleep_mode', 'pet_mode', 'filter_life'],
196
+ levels: [1, 2, 3, 4],
197
+ modes: ['sleep', 'manual', 'auto', 'pet'],
198
+ autoPreferences: ['default', 'efficient', 'quiet']
148
199
  },
149
200
  'LAP-EL551S-AUS': {
150
201
  module: 'VeSyncAirBaseV2',
151
- features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_rotate', 'fan_speed', 'auto_mode', 'filter_life'],
152
- levels: [1, 2, 3]
202
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_rotate', 'fan_speed', 'auto_mode', 'sleep_mode', 'turbo_mode', 'light_detection', 'filter_life'],
203
+ levels: [1, 2, 3],
204
+ modes: ['sleep', 'manual', 'auto', 'turbo'],
205
+ autoPreferences: ['default', 'efficient', 'quiet']
153
206
  },
154
207
  'LAP-EL551S-AEUR': {
155
208
  module: 'VeSyncAirBaseV2',
156
- features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_rotate', 'fan_speed', 'auto_mode', 'filter_life'],
157
- levels: [1, 2, 3]
209
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_rotate', 'fan_speed', 'auto_mode', 'sleep_mode', 'turbo_mode', 'light_detection', 'filter_life'],
210
+ levels: [1, 2, 3],
211
+ modes: ['sleep', 'manual', 'auto', 'turbo'],
212
+ autoPreferences: ['default', 'efficient', 'quiet']
158
213
  },
159
214
  'LAP-EL551S-WEU': {
160
215
  module: 'VeSyncAirBaseV2',
161
- features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_rotate', 'fan_speed', 'auto_mode', 'filter_life'],
162
- levels: [1, 2, 3]
216
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_rotate', 'fan_speed', 'auto_mode', 'sleep_mode', 'turbo_mode', 'light_detection', 'filter_life'],
217
+ levels: [1, 2, 3],
218
+ modes: ['sleep', 'manual', 'auto', 'turbo'],
219
+ autoPreferences: ['default', 'efficient', 'quiet']
163
220
  },
164
221
  'LAP-EL551S-WUS': {
165
222
  module: 'VeSyncAirBaseV2',
166
- features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_rotate', 'fan_speed', 'auto_mode', 'filter_life'],
167
- levels: [1, 2, 3]
223
+ features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_rotate', 'fan_speed', 'auto_mode', 'sleep_mode', 'turbo_mode', 'light_detection', 'filter_life'],
224
+ levels: [1, 2, 3],
225
+ modes: ['sleep', 'manual', 'auto', 'turbo'],
226
+ autoPreferences: ['default', 'efficient', 'quiet']
168
227
  },
169
228
  // LTF Series
170
229
  'LTF-F422S-KEU': {
@@ -311,11 +370,64 @@ class VeSyncFan extends vesyncBaseDevice_1.VeSyncBaseDevice {
311
370
  this.speed_dict = {};
312
371
  this._timer = null;
313
372
  this.details = details;
314
- this.config = exports.fanConfig[this.deviceType] || {
315
- module: 'VeSyncAirBypass',
316
- features: [],
317
- levels: []
318
- };
373
+ // Try exact match first
374
+ let entry = exports.fanConfig[this.deviceType];
375
+ // If no exact match, try substring matching for LAP variants
376
+ // This handles cases where device reports as "LAP-C401S-WUSR" but we only have "Core400S" config
377
+ if (!entry) {
378
+ entry = this.findConfigBySubstring(this.deviceType);
379
+ }
380
+ if (entry) {
381
+ this.config = {
382
+ ...entry,
383
+ features: [...entry.features],
384
+ levels: entry.levels ? [...entry.levels] : undefined,
385
+ modes: entry.modes ? [...entry.modes] : undefined,
386
+ autoPreferences: entry.autoPreferences ? [...entry.autoPreferences] : undefined
387
+ };
388
+ }
389
+ else {
390
+ this.config = {
391
+ module: 'VeSyncAirBypass',
392
+ features: [],
393
+ levels: [],
394
+ modes: [],
395
+ autoPreferences: []
396
+ };
397
+ }
398
+ }
399
+ /**
400
+ * Find config entry by substring matching for variant device types
401
+ * Maps LAP variants to their base model configs (e.g., LAP-C401S-WUSR → Core400S)
402
+ */
403
+ findConfigBySubstring(deviceType) {
404
+ // Define model number mappings
405
+ const modelMappings = [
406
+ // Core series air purifiers
407
+ { patterns: ['Core300S', '301S', '302S'], configKey: 'Core300S' },
408
+ { patterns: ['Core400S', '401S'], configKey: 'Core400S' },
409
+ { patterns: ['Core600S', '601S', '602S'], configKey: 'Core600S' },
410
+ { patterns: ['Core200S', '201S', '202S'], configKey: 'Core200S' },
411
+ // Vital series
412
+ { patterns: ['V102S'], configKey: 'LAP-V102S-AASR' },
413
+ { patterns: ['V201S'], configKey: 'LAP-V201S-AASR' },
414
+ // LV-PUR series
415
+ { patterns: ['LV-PUR131S', 'LV-RH131S'], configKey: 'LV-PUR131S' },
416
+ // Everest series
417
+ { patterns: ['LAP-EL551S'], configKey: 'LAP-EL551S-AUS' },
418
+ ];
419
+ // Check each mapping
420
+ for (const mapping of modelMappings) {
421
+ // If device type contains any of the patterns, use the config key
422
+ if (mapping.patterns.some(pattern => deviceType.includes(pattern))) {
423
+ const config = exports.fanConfig[mapping.configKey];
424
+ if (config) {
425
+ logger_1.logger.debug(`${deviceType}: Using fallback config from ${mapping.configKey} via substring match`);
426
+ return config;
427
+ }
428
+ }
429
+ }
430
+ return undefined;
319
431
  }
320
432
  /**
321
433
  * Check if feature is supported
@@ -323,6 +435,36 @@ class VeSyncFan extends vesyncBaseDevice_1.VeSyncBaseDevice {
323
435
  hasFeature(feature) {
324
436
  return this.config.features.includes(feature);
325
437
  }
438
+ /**
439
+ * Get configured modes for the device, falling back to provided defaults.
440
+ */
441
+ getConfigModes(defaultModes = []) {
442
+ if (Array.isArray(this.config.modes) && this.config.modes.length > 0) {
443
+ return this.config.modes;
444
+ }
445
+ return defaultModes;
446
+ }
447
+ /**
448
+ * Get configured auto preferences for the device, falling back to provided defaults.
449
+ */
450
+ getConfigAutoPreferences(defaultPreferences = []) {
451
+ if (Array.isArray(this.config.autoPreferences) && this.config.autoPreferences.length > 0) {
452
+ return this.config.autoPreferences;
453
+ }
454
+ return defaultPreferences;
455
+ }
456
+ /**
457
+ * Public accessor for supported modes for consumers that need to inspect capability metadata.
458
+ */
459
+ getSupportedModes(defaultModes = []) {
460
+ return this.getConfigModes(defaultModes);
461
+ }
462
+ /**
463
+ * Public accessor for supported auto preference profiles.
464
+ */
465
+ getSupportedAutoPreferences(defaultPreferences = []) {
466
+ return this.getConfigAutoPreferences(defaultPreferences);
467
+ }
326
468
  /**
327
469
  * Check if feature is supported in current mode
328
470
  */
@@ -355,7 +497,10 @@ class VeSyncFan extends vesyncBaseDevice_1.VeSyncBaseDevice {
355
497
  * Get maximum fan speed level
356
498
  */
357
499
  getMaxFanSpeed() {
358
- return this.config.levels ? Math.max(...this.config.levels) : 3;
500
+ if (this.config.levels && this.config.levels.length > 0) {
501
+ return Math.max(...this.config.levels);
502
+ }
503
+ return 3;
359
504
  }
360
505
  /**
361
506
  * Get current mode
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "tsvesync",
3
- "version": "1.3.13",
3
+ "version": "1.4.1",
4
4
  "description": "A TypeScript library for interacting with VeSync smart home devices",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "scripts": {
8
8
  "build": "tsc",
9
9
  "clean": "rm -rf dist",
10
+ "test:everest": "ts-node test/everest-air-parity.test.ts",
10
11
  "prepare": "npm run build",
11
12
  "version": "git add -A src",
12
13
  "postversion": "git push && git push --tags"
@@ -10,7 +10,7 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
10
10
  protected _lightDetection: boolean = false;
11
11
  protected _lightDetectionState: boolean = false;
12
12
  protected setSpeedLevel: number | null = null;
13
- protected autoPreferences: string[] = ['default', 'efficient', 'quiet'];
13
+ protected autoPreferences: string[];
14
14
  protected enabled: boolean = false;
15
15
  protected _mode: string = '';
16
16
  protected _speed: number = 0;
@@ -18,6 +18,7 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
18
18
 
19
19
  constructor(details: Record<string, any>, manager: VeSync) {
20
20
  super(details, manager);
21
+ this.autoPreferences = [...this.getConfigAutoPreferences(['default', 'efficient', 'quiet'])];
21
22
  logger.debug(`Initialized VeSyncAirBaseV2 device: ${this.deviceName}`);
22
23
  }
23
24
 
@@ -310,24 +311,41 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
310
311
  * Override setMode to send workMode payloads for bypassV2 purifiers.
311
312
  */
312
313
  override async setMode(mode: string): Promise<boolean> {
313
- if (!this.modes.includes(mode as any)) {
314
+ const targetMode = mode.toLowerCase();
315
+ const supportedModes = this.modes.map(m => m.toLowerCase());
316
+
317
+ if (!supportedModes.includes(targetMode)) {
314
318
  const error = `Invalid mode: ${mode}. Must be one of: ${this.modes.join(', ')}`;
315
319
  logger.error(`${error} for device: ${this.deviceName}`);
316
320
  throw new Error(error);
317
321
  }
318
322
 
319
323
  // Special handling for Core200S stays the same for all models
320
- if (this.deviceType.includes('Core200S') && mode === 'auto') {
324
+ if (this.deviceType.includes('Core200S') && targetMode === 'auto') {
321
325
  logger.warn(`Auto mode not supported for ${this.deviceType}, using manual mode instead`);
322
326
  return this.setMode('manual');
323
327
  }
324
328
 
329
+ // Manual mode should leverage changeFanSpeed to mirror pyvesync behaviour
330
+ if (targetMode === 'manual') {
331
+ const defaultLevel = this.config.levels && this.config.levels.length > 0
332
+ ? this.config.levels[0]
333
+ : 1;
334
+ const desiredLevel = this.details.manualSpeedLevel ?? this.speed ?? defaultLevel;
335
+ const success = await this.changeFanSpeed(desiredLevel);
336
+ if (success) {
337
+ this.details.mode = 'manual';
338
+ this.mode = 'manual';
339
+ }
340
+ return success;
341
+ }
342
+
325
343
  // BypassV2 purifiers need the workMode payload; other models use the base implementation
326
344
  if (this.requiresPowerSwitchPayload()) {
327
345
  logger.debug(`Using bypassV2 mode payload for ${this.deviceName}`);
328
346
  const [head, body] = this.buildApiDict('setPurifierMode');
329
347
  body.payload.data = {
330
- workMode: mode
348
+ workMode: targetMode
331
349
  };
332
350
 
333
351
  const [response, status] = await this.callApi(
@@ -339,8 +357,26 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
339
357
 
340
358
  const success = this.checkV2Response(response, status, 'setMode');
341
359
  if (success) {
342
- this.details.mode = mode;
343
- this._mode = mode;
360
+ this.details.mode = targetMode;
361
+ this.mode = targetMode;
362
+
363
+ // Update cached speed snapshot for special modes
364
+ if (targetMode === 'sleep') {
365
+ this.speed = 0;
366
+ this.details.speed = 0;
367
+ } else if (targetMode === 'turbo') {
368
+ const maxSpeed = this.config.levels && this.config.levels.length > 0
369
+ ? Math.max(...this.config.levels)
370
+ : this.speed;
371
+ if (typeof maxSpeed === 'number' && maxSpeed > 0) {
372
+ this.speed = maxSpeed;
373
+ this.details.speed = maxSpeed;
374
+ }
375
+ } else if (targetMode === 'auto') {
376
+ this.speed = 0;
377
+ this.details.speed = 0;
378
+ this.details.isAutoSentinel = true;
379
+ }
344
380
 
345
381
  // Force a details update to sync state
346
382
  setTimeout(() => {
@@ -351,7 +387,7 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
351
387
 
352
388
  return true;
353
389
  } else {
354
- logger.error(`Failed to set mode to ${mode} for device: ${this.deviceName}`);
390
+ logger.error(`Failed to set mode to ${targetMode} for device: ${this.deviceName}`);
355
391
  return false;
356
392
  }
357
393
  } else {
@@ -360,6 +396,28 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
360
396
  }
361
397
  }
362
398
 
399
+ /**
400
+ * Convenience helper to enter turbo mode when supported.
401
+ */
402
+ async turboMode(): Promise<boolean> {
403
+ if (!this.modes.map(m => m.toLowerCase()).includes('turbo')) {
404
+ logger.debug(`Turbo mode not supported for device: ${this.deviceName}`);
405
+ return false;
406
+ }
407
+ return this.setMode('turbo');
408
+ }
409
+
410
+ /**
411
+ * Convenience helper to enter pet mode when supported.
412
+ */
413
+ async petMode(): Promise<boolean> {
414
+ if (!this.modes.map(m => m.toLowerCase()).includes('pet')) {
415
+ logger.debug(`Pet mode not supported for device: ${this.deviceName}`);
416
+ return false;
417
+ }
418
+ return this.setMode('pet');
419
+ }
420
+
363
421
  /**
364
422
  * Override changeFanSpeed to use manualSpeedLevel for bypassV2 purifiers.
365
423
  */
@@ -395,6 +453,10 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
395
453
  if (success) {
396
454
  this.speed = speed;
397
455
  this.details.manualSpeedLevel = speed;
456
+ this.details.speed = speed;
457
+ this.details.mode = 'manual';
458
+ this.mode = 'manual';
459
+ this.details.isAutoSentinel = false;
398
460
 
399
461
  // Force a details update to sync state
400
462
  setTimeout(() => {
@@ -428,6 +490,10 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
428
490
  if (success) {
429
491
  this.speed = speed;
430
492
  this.details.manualSpeedLevel = speed;
493
+ this.details.speed = speed;
494
+ this.details.mode = 'manual';
495
+ this.mode = 'manual';
496
+ this.details.isAutoSentinel = false;
431
497
  return true;
432
498
  } else {
433
499
  logger.error(`Failed to change fan speed to ${speed} for device: ${this.deviceName}`);
@@ -441,7 +507,7 @@ export class VeSyncAirBaseV2 extends VeSyncAirBypass {
441
507
  */
442
508
  async setAutoPreference(preference: string = 'default', roomSize: number = 600): Promise<boolean> {
443
509
  if (!this.autoPreferences.includes(preference)) {
444
- logger.debug(`Invalid preference: ${preference} - valid preferences are default, efficient, quiet`);
510
+ logger.debug(`Invalid preference: ${preference} - valid preferences are ${this.autoPreferences.join(', ')}`);
445
511
  return false;
446
512
  }
447
513