From 962381dc54c7b236cb183e05f33d466bcee08aeb Mon Sep 17 00:00:00 2001 From: Igor Panteleev Date: Tue, 18 Apr 2023 13:15:50 +0300 Subject: [PATCH] Fix modes for LV600S Humidifier (#136) * add mode map * change mode map auto->humidity * specify available_modes * Add support for python < 3.10 * Fix codesmells --------- Co-authored-by: Vincent Le Bourlot --- custom_components/vesync/const.py | 1 + custom_components/vesync/humidifier.py | 96 ++++++++++++++++++-------- requirements.txt | 2 +- 3 files changed, 69 insertions(+), 30 deletions(-) diff --git a/custom_components/vesync/const.py b/custom_components/vesync/const.py index 6e95e43..a0db6fe 100644 --- a/custom_components/vesync/const.py +++ b/custom_components/vesync/const.py @@ -18,6 +18,7 @@ VS_LEVELS = "levels" VS_MODES = "modes" VS_MODE_AUTO = "auto" +VS_MODE_HUMIDITY = "humidity" VS_MODE_MANUAL = "manual" VS_MODE_SLEEP = "sleep" diff --git a/custom_components/vesync/humidifier.py b/custom_components/vesync/humidifier.py index 6db857a..394fbf3 100644 --- a/custom_components/vesync/humidifier.py +++ b/custom_components/vesync/humidifier.py @@ -1,4 +1,8 @@ """Support for VeSync humidifiers.""" +from __future__ import annotations + +import logging +from typing import Any, Mapping from homeassistant.components.humidifier import HumidifierEntity from homeassistant.components.humidifier.const import ( @@ -11,21 +15,33 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback +from pyvesync.vesyncfan import VeSyncHumid200300S from .common import VeSyncDevice from .const import ( DOMAIN, VS_DISCOVERY, VS_HUMIDIFIERS, - VS_MODE_AUTO, + VS_MODE_HUMIDITY, VS_MODE_MANUAL, + VS_MODE_SLEEP, VS_TO_HA_ATTRIBUTES, ) +_LOGGER = logging.getLogger(__name__) + + MAX_HUMIDITY = 80 MIN_HUMIDITY = 30 -MODES = [MODE_AUTO, MODE_NORMAL, MODE_SLEEP] + +VS_TO_HA_MODE_MAP = { + VS_MODE_MANUAL: MODE_NORMAL, + VS_MODE_HUMIDITY: MODE_AUTO, + VS_MODE_SLEEP: MODE_SLEEP, +} + +HA_TO_VS_MODE_MAP = {v: k for k, v in VS_TO_HA_MODE_MAP.items()} async def async_setup_entry( @@ -57,21 +73,44 @@ def _setup_entities(devices, async_add_entities): ) +def _get_ha_mode(vs_mode: str) -> str | None: + ha_mode = VS_TO_HA_MODE_MAP.get(vs_mode) + if ha_mode is None: + _LOGGER.warning("Unknown mode '%s'", vs_mode) + return ha_mode + + +def _get_vs_mode(ha_mode: str) -> str | None: + vs_mode = HA_TO_VS_MODE_MAP.get(ha_mode) + if vs_mode is None: + _LOGGER.warning("Unknown mode '%s'", ha_mode) + return vs_mode + + class VeSyncHumidifierHA(VeSyncDevice, HumidifierEntity): """Representation of a VeSync humidifier.""" _attr_max_humidity = MAX_HUMIDITY _attr_min_humidity = MIN_HUMIDITY - def __init__(self, humidifier): + def __init__(self, humidifier: VeSyncHumid200300S): """Initialize the VeSync humidifier device.""" super().__init__(humidifier) self.smarthumidifier = humidifier @property - def available_modes(self): + def available_modes(self) -> list[str]: """Return the available mist modes.""" - return MODES + modes = [] + for vs_mode in self.smarthumidifier.mist_modes: + ha_mode = _get_ha_mode(vs_mode) + + if ha_mode is None: + continue + + modes.append(ha_mode) + + return modes @property def supported_features(self): @@ -79,35 +118,27 @@ class VeSyncHumidifierHA(VeSyncDevice, HumidifierEntity): return SUPPORT_MODES @property - def target_humidity(self): + def target_humidity(self) -> int: """Return the humidity we try to reach.""" return self.smarthumidifier.config["auto_target_humidity"] @property - def mode(self): + def mode(self) -> str | None: """Get the current preset mode.""" - if self.smarthumidifier.details["mode"] == VS_MODE_AUTO: - return MODE_AUTO - if self.smarthumidifier.details["mode"] == VS_MODE_MANUAL: - return ( - MODE_SLEEP - if self.smarthumidifier.details["mist_level"] == 1 - else MODE_NORMAL - ) - return None + return _get_ha_mode(self.smarthumidifier.details["mode"]) @property - def is_on(self): + def is_on(self) -> bool: """Return True if humidifier is on.""" return self.smarthumidifier.enabled # device_status is always on @property - def unique_info(self): + def unique_info(self) -> str: """Return the ID of this humidifier.""" return self.smarthumidifier.uuid @property - def extra_state_attributes(self): + def extra_state_attributes(self) -> Mapping[str, Any]: """Return the state attributes of the humidifier.""" attr = {} @@ -120,27 +151,26 @@ class VeSyncHumidifierHA(VeSyncDevice, HumidifierEntity): attr[k] = v return attr - def set_humidity(self, humidity): + def set_humidity(self, humidity: int) -> None: """Set the target humidity of the device.""" if humidity not in range(self.min_humidity, self.max_humidity + 1): raise ValueError( "{humidity} is not between {self.min_humidity} and {self.max_humidity} (inclusive)" ) - self.smarthumidifier.set_humidity(humidity) + success = self.smarthumidifier.set_humidity(humidity) + if not success: + raise ValueError("An error occurred while setting humidity.") self.schedule_update_ha_state() - def set_mode(self, mode): + def set_mode(self, mode: str) -> None: """Set the mode of the device.""" if mode not in self.available_modes: raise ValueError( "{mode} is not one of the valid available modes: {self.available_modes}" ) - if mode == MODE_AUTO: - self.smarthumidifier.set_humidity_mode(VS_MODE_AUTO) - else: - self.smarthumidifier.set_mist_level( - 1 if mode == MODE_SLEEP else 2 - ) # this sets manual mode at the same time. + success = self.smarthumidifier.set_humidity_mode(_get_vs_mode(mode)) + if not success: + raise ValueError("An error occurred while setting mode.") self.schedule_update_ha_state() def turn_on( @@ -148,4 +178,12 @@ class VeSyncHumidifierHA(VeSyncDevice, HumidifierEntity): **kwargs, ) -> None: """Turn the device on.""" - self.smarthumidifier.turn_on() + success = self.smarthumidifier.turn_on() + if not success: + raise ValueError("An error occurred while turning on.") + + def turn_off(self, **kwargs) -> None: + """Turn the device off.""" + success = self.smarthumidifier.turn_off() + if not success: + raise ValueError("An error occurred while turning off.") diff --git a/requirements.txt b/requirements.txt index ca5d9af..1601d53 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -pyvesync==2.1.6 +pyvesync==2.1.6 \ No newline at end of file