From 49c354d64dcadf653844afd05923becadc24c4d3 Mon Sep 17 00:00:00 2001 From: Joe Trabulsy Date: Sat, 10 Jan 2026 18:24:33 -0500 Subject: [PATCH 1/2] fix: attribute type consistency across devices (#497) --- src/pyvesync/base_devices/fan_base.py | 2 +- src/pyvesync/base_devices/humidifier_base.py | 4 ++-- src/pyvesync/device_map.py | 4 ++-- src/pyvesync/devices/vesyncfan.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pyvesync/base_devices/fan_base.py b/src/pyvesync/base_devices/fan_base.py index e6e28a7..43ae110 100644 --- a/src/pyvesync/base_devices/fan_base.py +++ b/src/pyvesync/base_devices/fan_base.py @@ -90,7 +90,7 @@ def __init__( self.mode: str | None = None self.fan_level: int | None = None self.fan_set_level: int | None = None - self.child_lock: str | None = None + self.child_lock: bool | None = None self.humidity: float | None = None self.temperature: float | None = None self.thermal_comfort: int | None = None diff --git a/src/pyvesync/base_devices/humidifier_base.py b/src/pyvesync/base_devices/humidifier_base.py index 5f4e303..7b4e5d2 100644 --- a/src/pyvesync/base_devices/humidifier_base.py +++ b/src/pyvesync/base_devices/humidifier_base.py @@ -261,9 +261,9 @@ def __init__( self._reverse_mist_modes: dict[str, str] = {} for k, v in self.mist_modes.items(): self._reverse_mist_modes[v] = k - self.mist_levels: list[str | int] = feature_map.mist_levels + self.mist_levels: list[int] = feature_map.mist_levels self.features: list[str] = feature_map.features - self.warm_mist_levels: list[int | str] = feature_map.warm_mist_levels + self.warm_mist_levels: list[int] = feature_map.warm_mist_levels self.target_minmax: tuple[int, int] = feature_map.target_minmax @property diff --git a/src/pyvesync/device_map.py b/src/pyvesync/device_map.py index 88aa919..320c298 100644 --- a/src/pyvesync/device_map.py +++ b/src/pyvesync/device_map.py @@ -273,11 +273,11 @@ class HumidifierMap(DeviceMapTemplate): product_line: str = ProductLines.WIFI_AIR mist_modes: dict[str, str] = field(default_factory=dict) - mist_levels: list[int | str] = field(default_factory=list) + mist_levels: list[int] = field(default_factory=list) product_type: str = ProductTypes.HUMIDIFIER module: ModuleType = vesynchumidifier target_minmax: tuple[int, int] = (30, 80) - warm_mist_levels: list[int | str] = field(default_factory=list) + warm_mist_levels: list[int] = field(default_factory=list) @dataclass(kw_only=True) diff --git a/src/pyvesync/devices/vesyncfan.py b/src/pyvesync/devices/vesyncfan.py index 51a99da..25c117f 100644 --- a/src/pyvesync/devices/vesyncfan.py +++ b/src/pyvesync/devices/vesyncfan.py @@ -259,7 +259,7 @@ def _set_fan_state(self, res: PedestalFanResult) -> None: self.state.horizontal_oscillation_status = DeviceStatus.from_int( res.horizontalOscillationState ) - self.state.child_lock = DeviceStatus.from_int(res.childLock) + self.state.child_lock = bool(res.childLock) if res.sleepPreference is not None: self.state.sleep_change_fan_level = DeviceStatus.from_int( res.sleepPreference.initFanSpeedLevel From 2f2511f27acc8162722f2bf2eee5e74134d07cdd Mon Sep 17 00:00:00 2001 From: arsiesys <12686720+arsiesys@users.noreply.github.com> Date: Sun, 18 Jan 2026 23:41:57 -0500 Subject: [PATCH 2/2] fix: Add LEH-S602S-WUS model alternate (#496) Thank you for the lib allowing us to manage our levoit devices in home assistant ! The levoit 6000s I received in Canada wasn't working when using the test script as it wasn't matching current mapping list. I updated it and re-ran the test script and can now see the informations: ``` Caller: VeSyncSuperior6000S.call_bypassv2_api [devices.vesynchumidifier] API CALL to endpoint: /cloud/v2/deviceManaged/bypassV2 Host: smartapi.vesync.com Full URL: https://smartapi.vesync.com/cloud/v2/deviceManaged/bypassV2 Response Status: 200 Method: POST ---------------Request----------------- Request Headers: { "Content-Type": "application/json; charset=UTF-8", "User-Agent": "okhttp/3.12.1" } Request Body: { "acceptLanguage": "en", "accountID": "##_REDACTED_##", "appVersion": "5.6.60", "cid": "##_REDACTED_##", "configModule": "VS_WFON_AHM_LEH-S602S-WUS_US", "debugMode": false, "method": "bypassV2", "phoneBrand": "pyvesync", "phoneOS": "Android", "traceId": "1767886110", "timeZone": "America/New_York", "token": "##_REDACTED_##", "userCountryCode": "CA", "deviceId": "vsaq2a123d34875ac14f97a24f06c8c3", "configModel": "VS_WFON_AHM_LEH-S602S-WUS_US", "payload": { "data": {}, "method": "getHumidifierStatus", "source": "APP" } } ---------------Response----------------- Response Headers: { "Date": "Thu, 08 Jan 2026 15:28:31 GMT", "Content-Type": "application/json;charset=UTF-8", "Transfer-Encoding": "chunked", "Connection": "keep-alive", "Content-Encoding": "gzip" } Response Body: { "traceId": "1767886110", "code": 0, "msg": "request success", "module": null, "stacktrace": null, "result": { "traceId": "1767886110", "code": 0, "result": { "powerSwitch": 1, "humidity": 50, "targetHumidity": 50, "virtualLevel": 9, "mistLevel": 3, "workMode": "humidity", "waterLacksState": 0, "waterTankLifted": 0, "autoStopSwitch": 1, "autoStopState": 1, "screenSwitch": 1, "screenState": 1, "scheduleCount": 0, "timerRemain": 0, "errorCode": 0, "totalWorkTime": 57360, "autoPreference": 1, "childLockSwitch": 0, "filterLifePercent": 100, "temperature": 629, "maxLevelNotify": 0, "waterShortageDryingSwitch": 1, "humidityPreference": 1, "dryingMode": { "dryingLevel": 2, "autoDryingSwitch": 1, "dryingState": 2, "dryingRemain": 7200 }, "isSupportSensor": 1, "sensorContent": { "sensorStatus": "noDevices" }, "lastDryingCompletedTime": 1767816954, "afterDryLastHumidityTime": 1767833536 } } } 2026-01-08 10:28:31 - DEBUG - pyvesync.devices.vesynchumidifier - Superior 6000S for LEH-S602S-WUS API from get_details returned code: 0, message: Success Random await finished Device list pulled successfully. 2026-01-08 10:28:32 - DEBUG - pyvesync.vesync - Closing session, exiting context manager 2026-01-08 10:28:32 - DEBUG - pyvesync.vesync - Closing session, exiting context manager ``` --------- Co-authored-by: Joe Trabulsy --- pyproject.toml | 2 +- src/pyvesync/device_map.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ab41ace..035ecdb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "pyvesync" -version = "3.4.0" +version = "3.4.1" description = "pyvesync is a library to manage Etekcity Devices, Cosori Air Fryers, and Levoit Air Purifiers run on the VeSync app." readme = "README.md" requires-python = ">=3.11" diff --git a/src/pyvesync/device_map.py b/src/pyvesync/device_map.py index 320c298..d467eb1 100644 --- a/src/pyvesync/device_map.py +++ b/src/pyvesync/device_map.py @@ -750,7 +750,7 @@ class ThermostatMap(DeviceMapTemplate): ), HumidifierMap( class_name='VeSyncSuperior6000S', - dev_types=['LEH-S601S-WUS', 'LEH-S601S-WUSR', 'LEH-S601S-WEUR'], + dev_types=['LEH-S601S-WUS', 'LEH-S601S-WUSR', 'LEH-S601S-WEUR', 'LEH-S602S-WUS'], features=[HumidifierFeatures.DRYING_MODE, HumidifierFeatures.AUTO_STOP], mist_modes={ HumidifierModes.AUTO: 'autoPro',