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 <vlebourl@gmail.com>
This commit is contained in:
Igor Panteleev 2023-04-18 13:15:50 +03:00 committed by GitHub
parent 08d7acd045
commit 962381dc54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 30 deletions

View File

@ -18,6 +18,7 @@ VS_LEVELS = "levels"
VS_MODES = "modes" VS_MODES = "modes"
VS_MODE_AUTO = "auto" VS_MODE_AUTO = "auto"
VS_MODE_HUMIDITY = "humidity"
VS_MODE_MANUAL = "manual" VS_MODE_MANUAL = "manual"
VS_MODE_SLEEP = "sleep" VS_MODE_SLEEP = "sleep"

View File

@ -1,4 +1,8 @@
"""Support for VeSync humidifiers.""" """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 import HumidifierEntity
from homeassistant.components.humidifier.const import ( from homeassistant.components.humidifier.const import (
@ -11,21 +15,33 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from pyvesync.vesyncfan import VeSyncHumid200300S
from .common import VeSyncDevice from .common import VeSyncDevice
from .const import ( from .const import (
DOMAIN, DOMAIN,
VS_DISCOVERY, VS_DISCOVERY,
VS_HUMIDIFIERS, VS_HUMIDIFIERS,
VS_MODE_AUTO, VS_MODE_HUMIDITY,
VS_MODE_MANUAL, VS_MODE_MANUAL,
VS_MODE_SLEEP,
VS_TO_HA_ATTRIBUTES, VS_TO_HA_ATTRIBUTES,
) )
_LOGGER = logging.getLogger(__name__)
MAX_HUMIDITY = 80 MAX_HUMIDITY = 80
MIN_HUMIDITY = 30 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( 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): class VeSyncHumidifierHA(VeSyncDevice, HumidifierEntity):
"""Representation of a VeSync humidifier.""" """Representation of a VeSync humidifier."""
_attr_max_humidity = MAX_HUMIDITY _attr_max_humidity = MAX_HUMIDITY
_attr_min_humidity = MIN_HUMIDITY _attr_min_humidity = MIN_HUMIDITY
def __init__(self, humidifier): def __init__(self, humidifier: VeSyncHumid200300S):
"""Initialize the VeSync humidifier device.""" """Initialize the VeSync humidifier device."""
super().__init__(humidifier) super().__init__(humidifier)
self.smarthumidifier = humidifier self.smarthumidifier = humidifier
@property @property
def available_modes(self): def available_modes(self) -> list[str]:
"""Return the available mist modes.""" """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 @property
def supported_features(self): def supported_features(self):
@ -79,35 +118,27 @@ class VeSyncHumidifierHA(VeSyncDevice, HumidifierEntity):
return SUPPORT_MODES return SUPPORT_MODES
@property @property
def target_humidity(self): def target_humidity(self) -> int:
"""Return the humidity we try to reach.""" """Return the humidity we try to reach."""
return self.smarthumidifier.config["auto_target_humidity"] return self.smarthumidifier.config["auto_target_humidity"]
@property @property
def mode(self): def mode(self) -> str | None:
"""Get the current preset mode.""" """Get the current preset mode."""
if self.smarthumidifier.details["mode"] == VS_MODE_AUTO: return _get_ha_mode(self.smarthumidifier.details["mode"])
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
@property @property
def is_on(self): def is_on(self) -> bool:
"""Return True if humidifier is on.""" """Return True if humidifier is on."""
return self.smarthumidifier.enabled # device_status is always on return self.smarthumidifier.enabled # device_status is always on
@property @property
def unique_info(self): def unique_info(self) -> str:
"""Return the ID of this humidifier.""" """Return the ID of this humidifier."""
return self.smarthumidifier.uuid return self.smarthumidifier.uuid
@property @property
def extra_state_attributes(self): def extra_state_attributes(self) -> Mapping[str, Any]:
"""Return the state attributes of the humidifier.""" """Return the state attributes of the humidifier."""
attr = {} attr = {}
@ -120,27 +151,26 @@ class VeSyncHumidifierHA(VeSyncDevice, HumidifierEntity):
attr[k] = v attr[k] = v
return attr return attr
def set_humidity(self, humidity): def set_humidity(self, humidity: int) -> None:
"""Set the target humidity of the device.""" """Set the target humidity of the device."""
if humidity not in range(self.min_humidity, self.max_humidity + 1): if humidity not in range(self.min_humidity, self.max_humidity + 1):
raise ValueError( raise ValueError(
"{humidity} is not between {self.min_humidity} and {self.max_humidity} (inclusive)" "{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() self.schedule_update_ha_state()
def set_mode(self, mode): def set_mode(self, mode: str) -> None:
"""Set the mode of the device.""" """Set the mode of the device."""
if mode not in self.available_modes: if mode not in self.available_modes:
raise ValueError( raise ValueError(
"{mode} is not one of the valid available modes: {self.available_modes}" "{mode} is not one of the valid available modes: {self.available_modes}"
) )
if mode == MODE_AUTO: success = self.smarthumidifier.set_humidity_mode(_get_vs_mode(mode))
self.smarthumidifier.set_humidity_mode(VS_MODE_AUTO) if not success:
else: raise ValueError("An error occurred while setting mode.")
self.smarthumidifier.set_mist_level(
1 if mode == MODE_SLEEP else 2
) # this sets manual mode at the same time.
self.schedule_update_ha_state() self.schedule_update_ha_state()
def turn_on( def turn_on(
@ -148,4 +178,12 @@ class VeSyncHumidifierHA(VeSyncDevice, HumidifierEntity):
**kwargs, **kwargs,
) -> None: ) -> None:
"""Turn the device on.""" """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.")