2022-04-01 15:02:13 +02:00
|
|
|
"""Support for VeSync humidifiers."""
|
2023-04-18 13:15:50 +03:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2024-03-21 11:44:36 +01:00
|
|
|
from collections.abc import Mapping
|
2023-04-18 13:15:50 +03:00
|
|
|
import logging
|
2024-03-21 11:44:36 +01:00
|
|
|
from typing import Any
|
|
|
|
|
|
|
|
from pyvesync.vesyncfan import VeSyncHumid200300S
|
2022-04-01 15:02:13 +02:00
|
|
|
|
|
|
|
from homeassistant.components.humidifier import HumidifierEntity
|
2022-04-01 16:49:02 +02:00
|
|
|
from homeassistant.components.humidifier.const import (
|
|
|
|
MODE_AUTO,
|
2022-04-03 23:22:01 +02:00
|
|
|
MODE_NORMAL,
|
2022-04-01 16:49:02 +02:00
|
|
|
MODE_SLEEP,
|
2024-03-21 11:44:36 +01:00
|
|
|
HumidifierEntityFeature,
|
2022-04-01 16:49:02 +02:00
|
|
|
)
|
2022-04-01 15:02:13 +02:00
|
|
|
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
|
|
|
|
|
2022-11-08 08:34:52 +01:00
|
|
|
from .common import VeSyncDevice
|
2022-06-08 11:08:19 +02:00
|
|
|
from .const import (
|
|
|
|
DOMAIN,
|
|
|
|
VS_DISCOVERY,
|
|
|
|
VS_HUMIDIFIERS,
|
2023-04-28 09:57:43 +02:00
|
|
|
VS_MODE_AUTO,
|
2023-04-18 13:15:50 +03:00
|
|
|
VS_MODE_HUMIDITY,
|
2022-06-08 11:08:19 +02:00
|
|
|
VS_MODE_MANUAL,
|
2023-04-18 13:15:50 +03:00
|
|
|
VS_MODE_SLEEP,
|
2022-06-08 11:08:19 +02:00
|
|
|
VS_TO_HA_ATTRIBUTES,
|
|
|
|
)
|
2022-04-01 15:02:13 +02:00
|
|
|
|
2023-04-18 13:15:50 +03:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2022-04-01 15:02:13 +02:00
|
|
|
MAX_HUMIDITY = 80
|
|
|
|
MIN_HUMIDITY = 30
|
|
|
|
|
2023-04-18 13:15:50 +03:00
|
|
|
|
|
|
|
VS_TO_HA_MODE_MAP = {
|
2023-04-28 09:57:43 +02:00
|
|
|
VS_MODE_AUTO: MODE_AUTO,
|
2023-04-18 13:15:50 +03:00
|
|
|
VS_MODE_HUMIDITY: MODE_AUTO,
|
2023-04-28 09:57:43 +02:00
|
|
|
VS_MODE_MANUAL: MODE_NORMAL,
|
2023-04-18 13:15:50 +03:00
|
|
|
VS_MODE_SLEEP: MODE_SLEEP,
|
|
|
|
}
|
|
|
|
|
|
|
|
HA_TO_VS_MODE_MAP = {v: k for k, v in VS_TO_HA_MODE_MAP.items()}
|
2022-04-01 16:49:02 +02:00
|
|
|
|
2022-04-01 15:02:13 +02:00
|
|
|
|
|
|
|
async def async_setup_entry(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
config_entry: ConfigEntry,
|
|
|
|
async_add_entities: AddEntitiesCallback,
|
|
|
|
) -> None:
|
|
|
|
"""Set up the VeSync humidifier platform."""
|
|
|
|
|
2023-04-28 09:57:43 +02:00
|
|
|
coordinator = hass.data[DOMAIN][config_entry.entry_id]["coordinator"]
|
|
|
|
|
2022-04-01 15:02:13 +02:00
|
|
|
@callback
|
|
|
|
def discover(devices):
|
|
|
|
"""Add new devices to platform."""
|
2023-04-28 09:57:43 +02:00
|
|
|
_setup_entities(devices, async_add_entities, coordinator)
|
2022-04-01 15:02:13 +02:00
|
|
|
|
|
|
|
config_entry.async_on_unload(
|
|
|
|
async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_HUMIDIFIERS), discover)
|
|
|
|
)
|
|
|
|
|
|
|
|
_setup_entities(
|
2023-04-28 09:57:43 +02:00
|
|
|
hass.data[DOMAIN][config_entry.entry_id][VS_HUMIDIFIERS],
|
|
|
|
async_add_entities,
|
|
|
|
coordinator,
|
2022-04-01 15:02:13 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@callback
|
2023-04-28 09:57:43 +02:00
|
|
|
def _setup_entities(devices, async_add_entities, coordinator):
|
2022-04-01 15:02:13 +02:00
|
|
|
"""Check if device is online and add entity."""
|
2022-11-08 08:34:52 +01:00
|
|
|
async_add_entities(
|
2023-04-28 09:57:43 +02:00
|
|
|
[VeSyncHumidifierHA(dev, coordinator) for dev in devices],
|
|
|
|
update_before_add=True,
|
2022-11-08 08:34:52 +01:00
|
|
|
)
|
2022-04-01 15:02:13 +02:00
|
|
|
|
|
|
|
|
2023-04-18 13:15:50 +03:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2022-04-01 15:02:13 +02:00
|
|
|
class VeSyncHumidifierHA(VeSyncDevice, HumidifierEntity):
|
|
|
|
"""Representation of a VeSync humidifier."""
|
|
|
|
|
|
|
|
_attr_max_humidity = MAX_HUMIDITY
|
|
|
|
_attr_min_humidity = MIN_HUMIDITY
|
|
|
|
|
2023-10-27 08:33:05 +01:00
|
|
|
def __init__(self, humidifier: VeSyncHumid200300S, coordinator) -> None:
|
2022-04-01 15:02:13 +02:00
|
|
|
"""Initialize the VeSync humidifier device."""
|
2023-04-28 09:57:43 +02:00
|
|
|
super().__init__(humidifier, coordinator)
|
2022-04-01 15:02:13 +02:00
|
|
|
self.smarthumidifier = humidifier
|
|
|
|
|
|
|
|
@property
|
2023-04-18 13:15:50 +03:00
|
|
|
def available_modes(self) -> list[str]:
|
2022-04-01 15:02:13 +02:00
|
|
|
"""Return the available mist modes."""
|
2023-04-18 13:15:50 +03:00
|
|
|
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
|
2022-04-01 15:02:13 +02:00
|
|
|
|
|
|
|
@property
|
|
|
|
def supported_features(self):
|
|
|
|
"""Flag supported features."""
|
2024-03-21 11:44:36 +01:00
|
|
|
return HumidifierEntityFeature.MODES
|
2022-04-01 15:02:13 +02:00
|
|
|
|
|
|
|
@property
|
2023-04-18 13:15:50 +03:00
|
|
|
def target_humidity(self) -> int:
|
2022-04-01 15:02:13 +02:00
|
|
|
"""Return the humidity we try to reach."""
|
|
|
|
return self.smarthumidifier.config["auto_target_humidity"]
|
|
|
|
|
|
|
|
@property
|
2023-04-18 13:15:50 +03:00
|
|
|
def mode(self) -> str | None:
|
2022-04-01 15:02:13 +02:00
|
|
|
"""Get the current preset mode."""
|
2023-04-18 13:15:50 +03:00
|
|
|
return _get_ha_mode(self.smarthumidifier.details["mode"])
|
2022-04-01 15:02:13 +02:00
|
|
|
|
|
|
|
@property
|
2023-04-18 13:15:50 +03:00
|
|
|
def is_on(self) -> bool:
|
2022-04-01 15:02:13 +02:00
|
|
|
"""Return True if humidifier is on."""
|
|
|
|
return self.smarthumidifier.enabled # device_status is always on
|
|
|
|
|
|
|
|
@property
|
2023-04-18 13:15:50 +03:00
|
|
|
def unique_info(self) -> str:
|
2022-04-01 15:02:13 +02:00
|
|
|
"""Return the ID of this humidifier."""
|
|
|
|
return self.smarthumidifier.uuid
|
|
|
|
|
|
|
|
@property
|
2023-04-18 13:15:50 +03:00
|
|
|
def extra_state_attributes(self) -> Mapping[str, Any]:
|
2022-04-01 15:02:13 +02:00
|
|
|
"""Return the state attributes of the humidifier."""
|
2022-04-08 14:46:42 +01:00
|
|
|
|
2022-06-04 18:59:00 +02:00
|
|
|
attr = {}
|
|
|
|
for k, v in self.smarthumidifier.details.items():
|
2022-06-08 11:08:19 +02:00
|
|
|
if k in VS_TO_HA_ATTRIBUTES:
|
|
|
|
attr[VS_TO_HA_ATTRIBUTES[k]] = v
|
|
|
|
elif k in self.state_attributes:
|
|
|
|
attr[f"vs_{k}"] = v
|
|
|
|
else:
|
2022-06-04 18:59:00 +02:00
|
|
|
attr[k] = v
|
2022-04-01 15:02:13 +02:00
|
|
|
return attr
|
|
|
|
|
2023-04-18 13:15:50 +03:00
|
|
|
def set_humidity(self, humidity: int) -> None:
|
2022-04-01 15:02:13 +02:00
|
|
|
"""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)"
|
|
|
|
)
|
2023-04-28 09:57:43 +02:00
|
|
|
if self.smarthumidifier.set_humidity(humidity):
|
|
|
|
self.schedule_update_ha_state()
|
|
|
|
else:
|
2023-04-18 13:15:50 +03:00
|
|
|
raise ValueError("An error occurred while setting humidity.")
|
2022-04-01 15:02:13 +02:00
|
|
|
|
2023-04-18 13:15:50 +03:00
|
|
|
def set_mode(self, mode: str) -> None:
|
2022-04-01 15:02:13 +02:00
|
|
|
"""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}"
|
|
|
|
)
|
2023-04-28 09:57:43 +02:00
|
|
|
if self.smarthumidifier.set_humidity_mode(_get_vs_mode(mode)):
|
|
|
|
self.schedule_update_ha_state()
|
|
|
|
else:
|
2023-04-18 13:15:50 +03:00
|
|
|
raise ValueError("An error occurred while setting mode.")
|
2022-04-01 15:02:13 +02:00
|
|
|
|
|
|
|
def turn_on(
|
|
|
|
self,
|
|
|
|
**kwargs,
|
|
|
|
) -> None:
|
|
|
|
"""Turn the device on."""
|
2023-04-18 13:15:50 +03:00
|
|
|
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.")
|