tsvesync 1.4.0 → 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.
- package/dist/lib/fans/airBypass.js +25 -3
- package/dist/lib/vesyncFan.d.ts +5 -0
- package/dist/lib/vesyncFan.js +49 -10
- package/package.json +1 -1
- package/src/lib/fans/airBypass.ts +28 -3
- package/src/lib/vesyncFan.ts +58 -10
|
@@ -71,16 +71,30 @@ class VeSyncAirBypass extends vesyncFan_1.VeSyncFan {
|
|
|
71
71
|
logger_1.logger.debug(`${this.deviceName}: API response structure:`, JSON.stringify(result, null, 2));
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
+
// Parse air quality with fallback support for multiple API response formats
|
|
75
|
+
// Some devices (like Core 400S) may use PascalCase (AQLevel, PM25)
|
|
76
|
+
// while others use snake_case (air_quality, air_quality_value)
|
|
77
|
+
const airQualityLevel = result.air_quality || result.AQLevel || 0;
|
|
78
|
+
const airQualityValue = result.air_quality_value || result.PM25 || 0;
|
|
79
|
+
// Debug logging to diagnose air quality field availability
|
|
80
|
+
logger_1.logger.debug(`${this.deviceName}: Air quality API response fields:`, {
|
|
81
|
+
air_quality: result.air_quality,
|
|
82
|
+
AQLevel: result.AQLevel,
|
|
83
|
+
air_quality_value: result.air_quality_value,
|
|
84
|
+
PM25: result.PM25,
|
|
85
|
+
parsed_level: airQualityLevel,
|
|
86
|
+
parsed_value: airQualityValue
|
|
87
|
+
});
|
|
74
88
|
this.details = {
|
|
75
89
|
mode: result.mode || '',
|
|
76
90
|
speed: result.level || 0,
|
|
77
91
|
filter_life: filterLife,
|
|
78
92
|
screen_status: result.display ? 'on' : 'off',
|
|
79
93
|
child_lock: result.child_lock || false,
|
|
80
|
-
air_quality:
|
|
81
|
-
air_quality_value:
|
|
94
|
+
air_quality: airQualityLevel,
|
|
95
|
+
air_quality_value: airQualityValue
|
|
82
96
|
};
|
|
83
|
-
const normalizedAirQuality = helpers_1.Helpers.normalizeAirQuality(
|
|
97
|
+
const normalizedAirQuality = helpers_1.Helpers.normalizeAirQuality(airQualityLevel);
|
|
84
98
|
if (normalizedAirQuality.level >= 1) {
|
|
85
99
|
this.details.air_quality_level = normalizedAirQuality.level;
|
|
86
100
|
}
|
|
@@ -92,6 +106,14 @@ class VeSyncAirBypass extends vesyncFan_1.VeSyncFan {
|
|
|
92
106
|
this.details.pm10 = result.PM10;
|
|
93
107
|
if ('AQPercent' in result)
|
|
94
108
|
this.details.aq_percent = result.AQPercent;
|
|
109
|
+
// Debug log additional air quality fields for diagnostics
|
|
110
|
+
if (result.PM1 !== undefined || result.PM10 !== undefined || result.AQPercent !== undefined) {
|
|
111
|
+
logger_1.logger.debug(`${this.deviceName}: Additional air quality data:`, {
|
|
112
|
+
PM1: result.PM1,
|
|
113
|
+
PM10: result.PM10,
|
|
114
|
+
AQPercent: result.AQPercent
|
|
115
|
+
});
|
|
116
|
+
}
|
|
95
117
|
// Don't overwrite config as it contains features array
|
|
96
118
|
if (result.configuration) {
|
|
97
119
|
this.details.configuration = result.configuration;
|
package/dist/lib/vesyncFan.d.ts
CHANGED
|
@@ -47,6 +47,11 @@ export declare abstract class VeSyncFan extends VeSyncBaseDevice {
|
|
|
47
47
|
} | null;
|
|
48
48
|
protected config: FanConfigEntry;
|
|
49
49
|
constructor(details: Record<string, any>, manager: VeSync);
|
|
50
|
+
/**
|
|
51
|
+
* Find config entry by substring matching for variant device types
|
|
52
|
+
* Maps LAP variants to their base model configs (e.g., LAP-C401S-WUSR → Core400S)
|
|
53
|
+
*/
|
|
54
|
+
private findConfigBySubstring;
|
|
50
55
|
/**
|
|
51
56
|
* Check if feature is supported
|
|
52
57
|
*/
|
package/dist/lib/vesyncFan.js
CHANGED
|
@@ -52,63 +52,63 @@ exports.fanConfig = {
|
|
|
52
52
|
},
|
|
53
53
|
'LAP-C301S-WJP': {
|
|
54
54
|
module: 'VeSyncAirBypass',
|
|
55
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
55
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
56
56
|
levels: [1, 2, 3, 4],
|
|
57
57
|
modes: ['sleep', 'manual', 'auto'],
|
|
58
58
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
59
59
|
},
|
|
60
60
|
'LAP-C302S-WUSB': {
|
|
61
61
|
module: 'VeSyncAirBypass',
|
|
62
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
62
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
63
63
|
levels: [1, 2, 3, 4],
|
|
64
64
|
modes: ['sleep', 'manual', 'auto'],
|
|
65
65
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
66
66
|
},
|
|
67
67
|
'LAP-C301S-WAAA': {
|
|
68
68
|
module: 'VeSyncAirBypass',
|
|
69
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
69
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
70
70
|
levels: [1, 2, 3, 4],
|
|
71
71
|
modes: ['sleep', 'manual', 'auto'],
|
|
72
72
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
73
73
|
},
|
|
74
74
|
'LAP-C401S-WJP': {
|
|
75
75
|
module: 'VeSyncAirBypass',
|
|
76
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
76
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
77
77
|
levels: [1, 2, 3, 4],
|
|
78
78
|
modes: ['sleep', 'manual', 'auto'],
|
|
79
79
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
80
80
|
},
|
|
81
81
|
'LAP-C401S-WUSR': {
|
|
82
82
|
module: 'VeSyncAirBypass',
|
|
83
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
83
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
84
84
|
levels: [1, 2, 3, 4],
|
|
85
85
|
modes: ['sleep', 'manual', 'auto'],
|
|
86
86
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
87
87
|
},
|
|
88
88
|
'LAP-C401S-WAAA': {
|
|
89
89
|
module: 'VeSyncAirBypass',
|
|
90
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
90
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
91
91
|
levels: [1, 2, 3, 4],
|
|
92
92
|
modes: ['sleep', 'manual', 'auto'],
|
|
93
93
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
94
94
|
},
|
|
95
95
|
'LAP-C601S-WUS': {
|
|
96
96
|
module: 'VeSyncAirBypass',
|
|
97
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
97
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
98
98
|
levels: [1, 2, 3, 4],
|
|
99
99
|
modes: ['sleep', 'manual', 'auto'],
|
|
100
100
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
101
101
|
},
|
|
102
102
|
'LAP-C601S-WUSR': {
|
|
103
103
|
module: 'VeSyncAirBypass',
|
|
104
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
104
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
105
105
|
levels: [1, 2, 3, 4],
|
|
106
106
|
modes: ['sleep', 'manual', 'auto'],
|
|
107
107
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
108
108
|
},
|
|
109
109
|
'LAP-C601S-WEU': {
|
|
110
110
|
module: 'VeSyncAirBypass',
|
|
111
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
111
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
112
112
|
levels: [1, 2, 3, 4],
|
|
113
113
|
modes: ['sleep', 'manual', 'auto'],
|
|
114
114
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
@@ -370,7 +370,13 @@ class VeSyncFan extends vesyncBaseDevice_1.VeSyncBaseDevice {
|
|
|
370
370
|
this.speed_dict = {};
|
|
371
371
|
this._timer = null;
|
|
372
372
|
this.details = details;
|
|
373
|
-
|
|
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
|
+
}
|
|
374
380
|
if (entry) {
|
|
375
381
|
this.config = {
|
|
376
382
|
...entry,
|
|
@@ -390,6 +396,39 @@ class VeSyncFan extends vesyncBaseDevice_1.VeSyncBaseDevice {
|
|
|
390
396
|
};
|
|
391
397
|
}
|
|
392
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;
|
|
431
|
+
}
|
|
393
432
|
/**
|
|
394
433
|
* Check if feature is supported
|
|
395
434
|
*/
|
package/package.json
CHANGED
|
@@ -79,17 +79,33 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
// Parse air quality with fallback support for multiple API response formats
|
|
83
|
+
// Some devices (like Core 400S) may use PascalCase (AQLevel, PM25)
|
|
84
|
+
// while others use snake_case (air_quality, air_quality_value)
|
|
85
|
+
const airQualityLevel = result.air_quality || result.AQLevel || 0;
|
|
86
|
+
const airQualityValue = result.air_quality_value || result.PM25 || 0;
|
|
87
|
+
|
|
88
|
+
// Debug logging to diagnose air quality field availability
|
|
89
|
+
logger.debug(`${this.deviceName}: Air quality API response fields:`, {
|
|
90
|
+
air_quality: result.air_quality,
|
|
91
|
+
AQLevel: result.AQLevel,
|
|
92
|
+
air_quality_value: result.air_quality_value,
|
|
93
|
+
PM25: result.PM25,
|
|
94
|
+
parsed_level: airQualityLevel,
|
|
95
|
+
parsed_value: airQualityValue
|
|
96
|
+
});
|
|
97
|
+
|
|
82
98
|
this.details = {
|
|
83
99
|
mode: result.mode || '',
|
|
84
100
|
speed: result.level || 0,
|
|
85
101
|
filter_life: filterLife,
|
|
86
102
|
screen_status: result.display ? 'on' : 'off',
|
|
87
103
|
child_lock: result.child_lock || false,
|
|
88
|
-
air_quality:
|
|
89
|
-
air_quality_value:
|
|
104
|
+
air_quality: airQualityLevel,
|
|
105
|
+
air_quality_value: airQualityValue
|
|
90
106
|
};
|
|
91
107
|
|
|
92
|
-
const normalizedAirQuality = Helpers.normalizeAirQuality(
|
|
108
|
+
const normalizedAirQuality = Helpers.normalizeAirQuality(airQualityLevel);
|
|
93
109
|
if (normalizedAirQuality.level >= 1) {
|
|
94
110
|
this.details.air_quality_level = normalizedAirQuality.level;
|
|
95
111
|
}
|
|
@@ -100,6 +116,15 @@ export class VeSyncAirBypass extends VeSyncFan {
|
|
|
100
116
|
if ('PM10' in result) this.details.pm10 = result.PM10;
|
|
101
117
|
if ('AQPercent' in result) this.details.aq_percent = result.AQPercent;
|
|
102
118
|
|
|
119
|
+
// Debug log additional air quality fields for diagnostics
|
|
120
|
+
if (result.PM1 !== undefined || result.PM10 !== undefined || result.AQPercent !== undefined) {
|
|
121
|
+
logger.debug(`${this.deviceName}: Additional air quality data:`, {
|
|
122
|
+
PM1: result.PM1,
|
|
123
|
+
PM10: result.PM10,
|
|
124
|
+
AQPercent: result.AQPercent
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
103
128
|
// Don't overwrite config as it contains features array
|
|
104
129
|
if (result.configuration) {
|
|
105
130
|
this.details.configuration = result.configuration;
|
package/src/lib/vesyncFan.ts
CHANGED
|
@@ -65,63 +65,63 @@ export const fanConfig: FanConfig = {
|
|
|
65
65
|
},
|
|
66
66
|
'LAP-C301S-WJP': {
|
|
67
67
|
module: 'VeSyncAirBypass',
|
|
68
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
68
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
69
69
|
levels: [1, 2, 3, 4],
|
|
70
70
|
modes: ['sleep', 'manual', 'auto'],
|
|
71
71
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
72
72
|
},
|
|
73
73
|
'LAP-C302S-WUSB': {
|
|
74
74
|
module: 'VeSyncAirBypass',
|
|
75
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
75
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
76
76
|
levels: [1, 2, 3, 4],
|
|
77
77
|
modes: ['sleep', 'manual', 'auto'],
|
|
78
78
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
79
79
|
},
|
|
80
80
|
'LAP-C301S-WAAA': {
|
|
81
81
|
module: 'VeSyncAirBypass',
|
|
82
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
82
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
83
83
|
levels: [1, 2, 3, 4],
|
|
84
84
|
modes: ['sleep', 'manual', 'auto'],
|
|
85
85
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
86
86
|
},
|
|
87
87
|
'LAP-C401S-WJP': {
|
|
88
88
|
module: 'VeSyncAirBypass',
|
|
89
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
89
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
90
90
|
levels: [1, 2, 3, 4],
|
|
91
91
|
modes: ['sleep', 'manual', 'auto'],
|
|
92
92
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
93
93
|
},
|
|
94
94
|
'LAP-C401S-WUSR': {
|
|
95
95
|
module: 'VeSyncAirBypass',
|
|
96
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
96
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
97
97
|
levels: [1, 2, 3, 4],
|
|
98
98
|
modes: ['sleep', 'manual', 'auto'],
|
|
99
99
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
100
100
|
},
|
|
101
101
|
'LAP-C401S-WAAA': {
|
|
102
102
|
module: 'VeSyncAirBypass',
|
|
103
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
103
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
104
104
|
levels: [1, 2, 3, 4],
|
|
105
105
|
modes: ['sleep', 'manual', 'auto'],
|
|
106
106
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
107
107
|
},
|
|
108
108
|
'LAP-C601S-WUS': {
|
|
109
109
|
module: 'VeSyncAirBypass',
|
|
110
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
110
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
111
111
|
levels: [1, 2, 3, 4],
|
|
112
112
|
modes: ['sleep', 'manual', 'auto'],
|
|
113
113
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
114
114
|
},
|
|
115
115
|
'LAP-C601S-WUSR': {
|
|
116
116
|
module: 'VeSyncAirBypass',
|
|
117
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
117
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
118
118
|
levels: [1, 2, 3, 4],
|
|
119
119
|
modes: ['sleep', 'manual', 'auto'],
|
|
120
120
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
121
121
|
},
|
|
122
122
|
'LAP-C601S-WEU': {
|
|
123
123
|
module: 'VeSyncAirBypass',
|
|
124
|
-
features: ['display', 'child_lock', 'night_light', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
124
|
+
features: ['display', 'child_lock', 'night_light', 'air_quality', 'timer', 'fan_speed', 'auto_mode', 'sleep_mode', 'filter_life'],
|
|
125
125
|
levels: [1, 2, 3, 4],
|
|
126
126
|
modes: ['sleep', 'manual', 'auto'],
|
|
127
127
|
autoPreferences: ['default', 'efficient', 'quiet']
|
|
@@ -410,7 +410,16 @@ export abstract class VeSyncFan extends VeSyncBaseDevice {
|
|
|
410
410
|
constructor(details: Record<string, any>, manager: VeSync) {
|
|
411
411
|
super(details, manager);
|
|
412
412
|
this.details = details;
|
|
413
|
-
|
|
413
|
+
|
|
414
|
+
// Try exact match first
|
|
415
|
+
let entry: FanConfigEntry | undefined = fanConfig[this.deviceType];
|
|
416
|
+
|
|
417
|
+
// If no exact match, try substring matching for LAP variants
|
|
418
|
+
// This handles cases where device reports as "LAP-C401S-WUSR" but we only have "Core400S" config
|
|
419
|
+
if (!entry) {
|
|
420
|
+
entry = this.findConfigBySubstring(this.deviceType);
|
|
421
|
+
}
|
|
422
|
+
|
|
414
423
|
if (entry) {
|
|
415
424
|
this.config = {
|
|
416
425
|
...entry,
|
|
@@ -430,6 +439,45 @@ export abstract class VeSyncFan extends VeSyncBaseDevice {
|
|
|
430
439
|
}
|
|
431
440
|
}
|
|
432
441
|
|
|
442
|
+
/**
|
|
443
|
+
* Find config entry by substring matching for variant device types
|
|
444
|
+
* Maps LAP variants to their base model configs (e.g., LAP-C401S-WUSR → Core400S)
|
|
445
|
+
*/
|
|
446
|
+
private findConfigBySubstring(deviceType: string): FanConfigEntry | undefined {
|
|
447
|
+
// Define model number mappings
|
|
448
|
+
const modelMappings: Array<{ patterns: string[]; configKey: string }> = [
|
|
449
|
+
// Core series air purifiers
|
|
450
|
+
{ patterns: ['Core300S', '301S', '302S'], configKey: 'Core300S' },
|
|
451
|
+
{ patterns: ['Core400S', '401S'], configKey: 'Core400S' },
|
|
452
|
+
{ patterns: ['Core600S', '601S', '602S'], configKey: 'Core600S' },
|
|
453
|
+
{ patterns: ['Core200S', '201S', '202S'], configKey: 'Core200S' },
|
|
454
|
+
|
|
455
|
+
// Vital series
|
|
456
|
+
{ patterns: ['V102S'], configKey: 'LAP-V102S-AASR' },
|
|
457
|
+
{ patterns: ['V201S'], configKey: 'LAP-V201S-AASR' },
|
|
458
|
+
|
|
459
|
+
// LV-PUR series
|
|
460
|
+
{ patterns: ['LV-PUR131S', 'LV-RH131S'], configKey: 'LV-PUR131S' },
|
|
461
|
+
|
|
462
|
+
// Everest series
|
|
463
|
+
{ patterns: ['LAP-EL551S'], configKey: 'LAP-EL551S-AUS' },
|
|
464
|
+
];
|
|
465
|
+
|
|
466
|
+
// Check each mapping
|
|
467
|
+
for (const mapping of modelMappings) {
|
|
468
|
+
// If device type contains any of the patterns, use the config key
|
|
469
|
+
if (mapping.patterns.some(pattern => deviceType.includes(pattern))) {
|
|
470
|
+
const config = fanConfig[mapping.configKey];
|
|
471
|
+
if (config) {
|
|
472
|
+
logger.debug(`${deviceType}: Using fallback config from ${mapping.configKey} via substring match`);
|
|
473
|
+
return config;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return undefined;
|
|
479
|
+
}
|
|
480
|
+
|
|
433
481
|
/**
|
|
434
482
|
* Check if feature is supported
|
|
435
483
|
*/
|