mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Add humidifier entity for Vesync devices (#134333)
This commit is contained in:
parent
6fd73730cc
commit
d986fe7a07
@ -20,7 +20,13 @@ from .const import (
|
|||||||
)
|
)
|
||||||
from .coordinator import VeSyncDataCoordinator
|
from .coordinator import VeSyncDataCoordinator
|
||||||
|
|
||||||
PLATFORMS = [Platform.FAN, Platform.LIGHT, Platform.SENSOR, Platform.SWITCH]
|
PLATFORMS = [
|
||||||
|
Platform.FAN,
|
||||||
|
Platform.HUMIDIFIER,
|
||||||
|
Platform.LIGHT,
|
||||||
|
Platform.SENSOR,
|
||||||
|
Platform.SWITCH,
|
||||||
|
]
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@ from pyvesync.vesyncbasedevice import VeSyncBaseDevice
|
|||||||
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
from .const import VeSyncHumidifierDevice
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -24,3 +26,9 @@ async def async_generate_device_list(
|
|||||||
devices.extend(manager.switches)
|
devices.extend(manager.switches)
|
||||||
|
|
||||||
return devices
|
return devices
|
||||||
|
|
||||||
|
|
||||||
|
def is_humidifier(device: VeSyncBaseDevice) -> bool:
|
||||||
|
"""Check if the device represents a humidifier."""
|
||||||
|
|
||||||
|
return isinstance(device, VeSyncHumidifierDevice)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
"""Constants for VeSync Component."""
|
"""Constants for VeSync Component."""
|
||||||
|
|
||||||
|
from pyvesync.vesyncfan import VeSyncHumid200300S, VeSyncSuperior6000S
|
||||||
|
|
||||||
DOMAIN = "vesync"
|
DOMAIN = "vesync"
|
||||||
VS_DISCOVERY = "vesync_discovery_{}"
|
VS_DISCOVERY = "vesync_discovery_{}"
|
||||||
SERVICE_UPDATE_DEVS = "update_devices"
|
SERVICE_UPDATE_DEVS = "update_devices"
|
||||||
@ -21,6 +23,14 @@ VS_DEVICES = "devices"
|
|||||||
VS_COORDINATOR = "coordinator"
|
VS_COORDINATOR = "coordinator"
|
||||||
VS_MANAGER = "manager"
|
VS_MANAGER = "manager"
|
||||||
|
|
||||||
|
VS_HUMIDIFIER_MODE_AUTO = "auto"
|
||||||
|
VS_HUMIDIFIER_MODE_HUMIDITY = "humidity"
|
||||||
|
VS_HUMIDIFIER_MODE_MANUAL = "manual"
|
||||||
|
VS_HUMIDIFIER_MODE_SLEEP = "sleep"
|
||||||
|
|
||||||
|
VeSyncHumidifierDevice = VeSyncHumid200300S | VeSyncSuperior6000S
|
||||||
|
"""Humidifier device types"""
|
||||||
|
|
||||||
DEV_TYPE_TO_HA = {
|
DEV_TYPE_TO_HA = {
|
||||||
"wifi-switch-1.3": "outlet",
|
"wifi-switch-1.3": "outlet",
|
||||||
"ESW03-USA": "outlet",
|
"ESW03-USA": "outlet",
|
||||||
|
161
homeassistant/components/vesync/humidifier.py
Normal file
161
homeassistant/components/vesync/humidifier.py
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
"""Support for VeSync humidifiers."""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from pyvesync.vesyncbasedevice import VeSyncBaseDevice
|
||||||
|
|
||||||
|
from homeassistant.components.humidifier import (
|
||||||
|
ATTR_HUMIDITY,
|
||||||
|
MODE_AUTO,
|
||||||
|
MODE_NORMAL,
|
||||||
|
MODE_SLEEP,
|
||||||
|
HumidifierEntity,
|
||||||
|
HumidifierEntityFeature,
|
||||||
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
|
from .common import is_humidifier
|
||||||
|
from .const import (
|
||||||
|
DOMAIN,
|
||||||
|
VS_COORDINATOR,
|
||||||
|
VS_DEVICES,
|
||||||
|
VS_DISCOVERY,
|
||||||
|
VS_HUMIDIFIER_MODE_AUTO,
|
||||||
|
VS_HUMIDIFIER_MODE_HUMIDITY,
|
||||||
|
VS_HUMIDIFIER_MODE_MANUAL,
|
||||||
|
VS_HUMIDIFIER_MODE_SLEEP,
|
||||||
|
VeSyncHumidifierDevice,
|
||||||
|
)
|
||||||
|
from .coordinator import VeSyncDataCoordinator
|
||||||
|
from .entity import VeSyncBaseEntity
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
MIN_HUMIDITY = 30
|
||||||
|
MAX_HUMIDITY = 80
|
||||||
|
|
||||||
|
VS_TO_HA_ATTRIBUTES = {ATTR_HUMIDITY: "current_humidity"}
|
||||||
|
|
||||||
|
VS_TO_HA_MODE_MAP = {
|
||||||
|
VS_HUMIDIFIER_MODE_AUTO: MODE_AUTO,
|
||||||
|
VS_HUMIDIFIER_MODE_HUMIDITY: MODE_AUTO,
|
||||||
|
VS_HUMIDIFIER_MODE_MANUAL: MODE_NORMAL,
|
||||||
|
VS_HUMIDIFIER_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(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up the VeSync humidifier platform."""
|
||||||
|
|
||||||
|
coordinator = hass.data[DOMAIN][VS_COORDINATOR]
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def discover(devices):
|
||||||
|
"""Add new devices to platform."""
|
||||||
|
_setup_entities(devices, async_add_entities, coordinator)
|
||||||
|
|
||||||
|
config_entry.async_on_unload(
|
||||||
|
async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_DEVICES), discover)
|
||||||
|
)
|
||||||
|
|
||||||
|
_setup_entities(hass.data[DOMAIN][VS_DEVICES], async_add_entities, coordinator)
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _setup_entities(
|
||||||
|
devices: list[VeSyncBaseDevice],
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
coordinator: VeSyncDataCoordinator,
|
||||||
|
):
|
||||||
|
"""Add humidifier entities."""
|
||||||
|
async_add_entities(
|
||||||
|
VeSyncHumidifierHA(dev, coordinator) for dev in devices if is_humidifier(dev)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
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:
|
||||||
|
return HA_TO_VS_MODE_MAP.get(ha_mode)
|
||||||
|
|
||||||
|
|
||||||
|
class VeSyncHumidifierHA(VeSyncBaseEntity, HumidifierEntity):
|
||||||
|
"""Representation of a VeSync humidifier."""
|
||||||
|
|
||||||
|
# The base VeSyncBaseEntity has _attr_has_entity_name and this is to follow the device name
|
||||||
|
_attr_name = None
|
||||||
|
|
||||||
|
_attr_max_humidity = MAX_HUMIDITY
|
||||||
|
_attr_min_humidity = MIN_HUMIDITY
|
||||||
|
_attr_supported_features = HumidifierEntityFeature.MODES
|
||||||
|
|
||||||
|
device: VeSyncHumidifierDevice
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available_modes(self) -> list[str]:
|
||||||
|
"""Return the available mist modes."""
|
||||||
|
return [
|
||||||
|
ha_mode
|
||||||
|
for ha_mode in (_get_ha_mode(vs_mode) for vs_mode in self.device.mist_modes)
|
||||||
|
if ha_mode
|
||||||
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def target_humidity(self) -> int:
|
||||||
|
"""Return the humidity we try to reach."""
|
||||||
|
return self.device.config["auto_target_humidity"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mode(self) -> str | None:
|
||||||
|
"""Get the current preset mode."""
|
||||||
|
return _get_ha_mode(self.device.details["mode"])
|
||||||
|
|
||||||
|
def set_humidity(self, humidity: int) -> None:
|
||||||
|
"""Set the target humidity of the device."""
|
||||||
|
if not self.device.set_humidity(humidity):
|
||||||
|
raise HomeAssistantError(
|
||||||
|
f"An error occurred while setting humidity {humidity}."
|
||||||
|
)
|
||||||
|
|
||||||
|
def set_mode(self, mode: str) -> None:
|
||||||
|
"""Set the mode of the device."""
|
||||||
|
if mode not in self.available_modes:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
"{mode} is not one of the valid available modes: {self.available_modes}"
|
||||||
|
)
|
||||||
|
if not self.device.set_humidity_mode(_get_vs_mode(mode)):
|
||||||
|
raise HomeAssistantError(f"An error occurred while setting mode {mode}.")
|
||||||
|
|
||||||
|
def turn_on(self, **kwargs: Any) -> None:
|
||||||
|
"""Turn the device on."""
|
||||||
|
success = self.device.turn_on()
|
||||||
|
if not success:
|
||||||
|
raise HomeAssistantError("An error occurred while turning on.")
|
||||||
|
|
||||||
|
def turn_off(self, **kwargs: Any) -> None:
|
||||||
|
"""Turn the device off."""
|
||||||
|
success = self.device.turn_off()
|
||||||
|
if not success:
|
||||||
|
raise HomeAssistantError("An error occurred while turning off.")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self) -> bool:
|
||||||
|
"""Return True if device is on."""
|
||||||
|
return self.device.device_status == "on"
|
@ -7,9 +7,6 @@ from dataclasses import dataclass
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from pyvesync.vesyncbasedevice import VeSyncBaseDevice
|
from pyvesync.vesyncbasedevice import VeSyncBaseDevice
|
||||||
from pyvesync.vesyncfan import VeSyncAirBypass
|
|
||||||
from pyvesync.vesyncoutlet import VeSyncOutlet
|
|
||||||
from pyvesync.vesyncswitch import VeSyncSwitch
|
|
||||||
|
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
SensorDeviceClass,
|
SensorDeviceClass,
|
||||||
@ -31,6 +28,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
|||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import StateType
|
from homeassistant.helpers.typing import StateType
|
||||||
|
|
||||||
|
from .common import is_humidifier
|
||||||
from .const import (
|
from .const import (
|
||||||
DEV_TYPE_TO_HA,
|
DEV_TYPE_TO_HA,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
@ -49,14 +47,10 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
class VeSyncSensorEntityDescription(SensorEntityDescription):
|
class VeSyncSensorEntityDescription(SensorEntityDescription):
|
||||||
"""Describe VeSync sensor entity."""
|
"""Describe VeSync sensor entity."""
|
||||||
|
|
||||||
value_fn: Callable[[VeSyncAirBypass | VeSyncOutlet | VeSyncSwitch], StateType]
|
value_fn: Callable[[VeSyncBaseDevice], StateType]
|
||||||
|
|
||||||
exists_fn: Callable[[VeSyncAirBypass | VeSyncOutlet | VeSyncSwitch], bool] = (
|
exists_fn: Callable[[VeSyncBaseDevice], bool] = lambda _: True
|
||||||
lambda _: True
|
update_fn: Callable[[VeSyncBaseDevice], None] = lambda _: None
|
||||||
)
|
|
||||||
update_fn: Callable[[VeSyncAirBypass | VeSyncOutlet | VeSyncSwitch], None] = (
|
|
||||||
lambda _: None
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def update_energy(device):
|
def update_energy(device):
|
||||||
@ -186,6 +180,14 @@ SENSORS: tuple[VeSyncSensorEntityDescription, ...] = (
|
|||||||
update_fn=update_energy,
|
update_fn=update_energy,
|
||||||
exists_fn=lambda device: ha_dev_type(device) == "outlet",
|
exists_fn=lambda device: ha_dev_type(device) == "outlet",
|
||||||
),
|
),
|
||||||
|
VeSyncSensorEntityDescription(
|
||||||
|
key="humidity",
|
||||||
|
device_class=SensorDeviceClass.HUMIDITY,
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
value_fn=lambda device: device.details["humidity"],
|
||||||
|
exists_fn=is_humidifier,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -213,7 +215,7 @@ async def async_setup_entry(
|
|||||||
@callback
|
@callback
|
||||||
def _setup_entities(
|
def _setup_entities(
|
||||||
devices: list[VeSyncBaseDevice],
|
devices: list[VeSyncBaseDevice],
|
||||||
async_add_entities,
|
async_add_entities: AddEntitiesCallback,
|
||||||
coordinator: VeSyncDataCoordinator,
|
coordinator: VeSyncDataCoordinator,
|
||||||
):
|
):
|
||||||
"""Check if device is online and add entity."""
|
"""Check if device is online and add entity."""
|
||||||
@ -236,9 +238,9 @@ class VeSyncSensorEntity(VeSyncBaseEntity, SensorEntity):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
device: VeSyncAirBypass | VeSyncOutlet | VeSyncSwitch,
|
device: VeSyncBaseDevice,
|
||||||
description: VeSyncSensorEntityDescription,
|
description: VeSyncSensorEntityDescription,
|
||||||
coordinator,
|
coordinator: VeSyncDataCoordinator,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the VeSync outlet device."""
|
"""Initialize the VeSync outlet device."""
|
||||||
super().__init__(device, coordinator)
|
super().__init__(device, coordinator)
|
||||||
|
@ -16,7 +16,7 @@ ALL_DEVICE_NAMES: list[str] = [
|
|||||||
]
|
]
|
||||||
DEVICE_FIXTURES: dict[str, list[tuple[str, str, str]]] = {
|
DEVICE_FIXTURES: dict[str, list[tuple[str, str, str]]] = {
|
||||||
"Humidifier 200s": [
|
"Humidifier 200s": [
|
||||||
("post", "/cloud/v2/deviceManaged/bypassV2", "device-detail.json")
|
("post", "/cloud/v2/deviceManaged/bypassV2", "humidifier-200s.json")
|
||||||
],
|
],
|
||||||
"Humidifier 600S": [
|
"Humidifier 600S": [
|
||||||
("post", "/cloud/v2/deviceManaged/bypassV2", "device-detail.json")
|
("post", "/cloud/v2/deviceManaged/bypassV2", "device-detail.json")
|
||||||
|
@ -7,9 +7,10 @@ from unittest.mock import Mock, patch
|
|||||||
import pytest
|
import pytest
|
||||||
from pyvesync import VeSync
|
from pyvesync import VeSync
|
||||||
from pyvesync.vesyncbulb import VeSyncBulb
|
from pyvesync.vesyncbulb import VeSyncBulb
|
||||||
from pyvesync.vesyncfan import VeSyncAirBypass
|
from pyvesync.vesyncfan import VeSyncAirBypass, VeSyncHumid200300S
|
||||||
from pyvesync.vesyncoutlet import VeSyncOutlet
|
from pyvesync.vesyncoutlet import VeSyncOutlet
|
||||||
from pyvesync.vesyncswitch import VeSyncSwitch
|
from pyvesync.vesyncswitch import VeSyncSwitch
|
||||||
|
import requests_mock
|
||||||
|
|
||||||
from homeassistant.components.vesync import DOMAIN
|
from homeassistant.components.vesync import DOMAIN
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
@ -17,6 +18,8 @@ from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
|
||||||
|
from .common import mock_multiple_device_responses
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
@ -100,3 +103,29 @@ def dimmable_switch_fixture():
|
|||||||
def outlet_fixture():
|
def outlet_fixture():
|
||||||
"""Create a mock VeSync outlet fixture."""
|
"""Create a mock VeSync outlet fixture."""
|
||||||
return Mock(VeSyncOutlet)
|
return Mock(VeSyncOutlet)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="humidifier")
|
||||||
|
def humidifier_fixture():
|
||||||
|
"""Create a mock VeSync humidifier fixture."""
|
||||||
|
return Mock(VeSyncHumid200300S)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="humidifier_config_entry")
|
||||||
|
async def humidifier_config_entry(
|
||||||
|
hass: HomeAssistant, requests_mock: requests_mock.Mocker, config
|
||||||
|
) -> MockConfigEntry:
|
||||||
|
"""Create a mock VeSync config entry for Humidifier 200s."""
|
||||||
|
entry = MockConfigEntry(
|
||||||
|
title="VeSync",
|
||||||
|
domain=DOMAIN,
|
||||||
|
data=config[DOMAIN],
|
||||||
|
)
|
||||||
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
device_name = "Humidifier 200s"
|
||||||
|
mock_multiple_device_responses(requests_mock, [device_name])
|
||||||
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
return entry
|
||||||
|
26
tests/components/vesync/fixtures/humidifier-200s.json
Normal file
26
tests/components/vesync/fixtures/humidifier-200s.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"result": {
|
||||||
|
"result": {
|
||||||
|
"humidity": 35,
|
||||||
|
"mist_virtual_level": 6,
|
||||||
|
"mode": "manual",
|
||||||
|
"water_lacks": true,
|
||||||
|
"water_tank_lifted": true,
|
||||||
|
"automatic_stop_reach_target": true,
|
||||||
|
"night_light_brightness": 10,
|
||||||
|
"enabled": true,
|
||||||
|
"level": 1,
|
||||||
|
"display": true,
|
||||||
|
"display_forever": false,
|
||||||
|
"child_lock": false,
|
||||||
|
"night_light": "off",
|
||||||
|
"configuration": {
|
||||||
|
"auto_target_humidity": 40,
|
||||||
|
"display": true,
|
||||||
|
"automatic_stop": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"code": 0
|
||||||
|
}
|
||||||
|
}
|
@ -464,6 +464,36 @@
|
|||||||
# ---
|
# ---
|
||||||
# name: test_fan_state[Humidifier 200s][devices]
|
# name: test_fan_state[Humidifier 200s][devices]
|
||||||
list([
|
list([
|
||||||
|
DeviceRegistryEntrySnapshot({
|
||||||
|
'area_id': None,
|
||||||
|
'config_entries': <ANY>,
|
||||||
|
'configuration_url': None,
|
||||||
|
'connections': set({
|
||||||
|
}),
|
||||||
|
'disabled_by': None,
|
||||||
|
'entry_type': None,
|
||||||
|
'hw_version': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'identifiers': set({
|
||||||
|
tuple(
|
||||||
|
'vesync',
|
||||||
|
'200s-humidifier',
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
'is_new': False,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'manufacturer': 'VeSync',
|
||||||
|
'model': 'Classic200S',
|
||||||
|
'model_id': None,
|
||||||
|
'name': 'Humidifier 200s',
|
||||||
|
'name_by_user': None,
|
||||||
|
'primary_config_entry': <ANY>,
|
||||||
|
'serial_number': None,
|
||||||
|
'suggested_area': None,
|
||||||
|
'sw_version': None,
|
||||||
|
'via_device_id': None,
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
# ---
|
# ---
|
||||||
# name: test_fan_state[Humidifier 200s][entities]
|
# name: test_fan_state[Humidifier 200s][entities]
|
||||||
@ -472,6 +502,36 @@
|
|||||||
# ---
|
# ---
|
||||||
# name: test_fan_state[Humidifier 600S][devices]
|
# name: test_fan_state[Humidifier 600S][devices]
|
||||||
list([
|
list([
|
||||||
|
DeviceRegistryEntrySnapshot({
|
||||||
|
'area_id': None,
|
||||||
|
'config_entries': <ANY>,
|
||||||
|
'configuration_url': None,
|
||||||
|
'connections': set({
|
||||||
|
}),
|
||||||
|
'disabled_by': None,
|
||||||
|
'entry_type': None,
|
||||||
|
'hw_version': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'identifiers': set({
|
||||||
|
tuple(
|
||||||
|
'vesync',
|
||||||
|
'600s-humidifier',
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
'is_new': False,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'manufacturer': 'VeSync',
|
||||||
|
'model': 'LUH-A602S-WUS',
|
||||||
|
'model_id': None,
|
||||||
|
'name': 'Humidifier 600S',
|
||||||
|
'name_by_user': None,
|
||||||
|
'primary_config_entry': <ANY>,
|
||||||
|
'serial_number': None,
|
||||||
|
'suggested_area': None,
|
||||||
|
'sw_version': None,
|
||||||
|
'via_device_id': None,
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
# ---
|
# ---
|
||||||
# name: test_fan_state[Humidifier 600S][entities]
|
# name: test_fan_state[Humidifier 600S][entities]
|
||||||
|
@ -335,6 +335,36 @@
|
|||||||
# ---
|
# ---
|
||||||
# name: test_light_state[Humidifier 200s][devices]
|
# name: test_light_state[Humidifier 200s][devices]
|
||||||
list([
|
list([
|
||||||
|
DeviceRegistryEntrySnapshot({
|
||||||
|
'area_id': None,
|
||||||
|
'config_entries': <ANY>,
|
||||||
|
'configuration_url': None,
|
||||||
|
'connections': set({
|
||||||
|
}),
|
||||||
|
'disabled_by': None,
|
||||||
|
'entry_type': None,
|
||||||
|
'hw_version': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'identifiers': set({
|
||||||
|
tuple(
|
||||||
|
'vesync',
|
||||||
|
'200s-humidifier',
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
'is_new': False,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'manufacturer': 'VeSync',
|
||||||
|
'model': 'Classic200S',
|
||||||
|
'model_id': None,
|
||||||
|
'name': 'Humidifier 200s',
|
||||||
|
'name_by_user': None,
|
||||||
|
'primary_config_entry': <ANY>,
|
||||||
|
'serial_number': None,
|
||||||
|
'suggested_area': None,
|
||||||
|
'sw_version': None,
|
||||||
|
'via_device_id': None,
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
# ---
|
# ---
|
||||||
# name: test_light_state[Humidifier 200s][entities]
|
# name: test_light_state[Humidifier 200s][entities]
|
||||||
@ -343,6 +373,36 @@
|
|||||||
# ---
|
# ---
|
||||||
# name: test_light_state[Humidifier 600S][devices]
|
# name: test_light_state[Humidifier 600S][devices]
|
||||||
list([
|
list([
|
||||||
|
DeviceRegistryEntrySnapshot({
|
||||||
|
'area_id': None,
|
||||||
|
'config_entries': <ANY>,
|
||||||
|
'configuration_url': None,
|
||||||
|
'connections': set({
|
||||||
|
}),
|
||||||
|
'disabled_by': None,
|
||||||
|
'entry_type': None,
|
||||||
|
'hw_version': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'identifiers': set({
|
||||||
|
tuple(
|
||||||
|
'vesync',
|
||||||
|
'600s-humidifier',
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
'is_new': False,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'manufacturer': 'VeSync',
|
||||||
|
'model': 'LUH-A602S-WUS',
|
||||||
|
'model_id': None,
|
||||||
|
'name': 'Humidifier 600S',
|
||||||
|
'name_by_user': None,
|
||||||
|
'primary_config_entry': <ANY>,
|
||||||
|
'serial_number': None,
|
||||||
|
'suggested_area': None,
|
||||||
|
'sw_version': None,
|
||||||
|
'via_device_id': None,
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
# ---
|
# ---
|
||||||
# name: test_light_state[Humidifier 600S][entities]
|
# name: test_light_state[Humidifier 600S][entities]
|
||||||
|
@ -651,20 +651,178 @@
|
|||||||
# ---
|
# ---
|
||||||
# name: test_sensor_state[Humidifier 200s][devices]
|
# name: test_sensor_state[Humidifier 200s][devices]
|
||||||
list([
|
list([
|
||||||
|
DeviceRegistryEntrySnapshot({
|
||||||
|
'area_id': None,
|
||||||
|
'config_entries': <ANY>,
|
||||||
|
'configuration_url': None,
|
||||||
|
'connections': set({
|
||||||
|
}),
|
||||||
|
'disabled_by': None,
|
||||||
|
'entry_type': None,
|
||||||
|
'hw_version': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'identifiers': set({
|
||||||
|
tuple(
|
||||||
|
'vesync',
|
||||||
|
'200s-humidifier',
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
'is_new': False,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'manufacturer': 'VeSync',
|
||||||
|
'model': 'Classic200S',
|
||||||
|
'model_id': None,
|
||||||
|
'name': 'Humidifier 200s',
|
||||||
|
'name_by_user': None,
|
||||||
|
'primary_config_entry': <ANY>,
|
||||||
|
'serial_number': None,
|
||||||
|
'suggested_area': None,
|
||||||
|
'sw_version': None,
|
||||||
|
'via_device_id': None,
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
# ---
|
# ---
|
||||||
# name: test_sensor_state[Humidifier 200s][entities]
|
# name: test_sensor_state[Humidifier 200s][entities]
|
||||||
list([
|
list([
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'sensor',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'sensor.humidifier_200s_humidity',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <SensorDeviceClass.HUMIDITY: 'humidity'>,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Humidity',
|
||||||
|
'platform': 'vesync',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': None,
|
||||||
|
'unique_id': '200s-humidifier-humidity',
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
# ---
|
# ---
|
||||||
|
# name: test_sensor_state[Humidifier 200s][sensor.humidifier_200s_humidity]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'device_class': 'humidity',
|
||||||
|
'friendly_name': 'Humidifier 200s Humidity',
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'sensor.humidifier_200s_humidity',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': '35',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
# name: test_sensor_state[Humidifier 600S][devices]
|
# name: test_sensor_state[Humidifier 600S][devices]
|
||||||
list([
|
list([
|
||||||
|
DeviceRegistryEntrySnapshot({
|
||||||
|
'area_id': None,
|
||||||
|
'config_entries': <ANY>,
|
||||||
|
'configuration_url': None,
|
||||||
|
'connections': set({
|
||||||
|
}),
|
||||||
|
'disabled_by': None,
|
||||||
|
'entry_type': None,
|
||||||
|
'hw_version': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'identifiers': set({
|
||||||
|
tuple(
|
||||||
|
'vesync',
|
||||||
|
'600s-humidifier',
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
'is_new': False,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'manufacturer': 'VeSync',
|
||||||
|
'model': 'LUH-A602S-WUS',
|
||||||
|
'model_id': None,
|
||||||
|
'name': 'Humidifier 600S',
|
||||||
|
'name_by_user': None,
|
||||||
|
'primary_config_entry': <ANY>,
|
||||||
|
'serial_number': None,
|
||||||
|
'suggested_area': None,
|
||||||
|
'sw_version': None,
|
||||||
|
'via_device_id': None,
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
# ---
|
# ---
|
||||||
# name: test_sensor_state[Humidifier 600S][entities]
|
# name: test_sensor_state[Humidifier 600S][entities]
|
||||||
list([
|
list([
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'sensor',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'sensor.humidifier_600s_humidity',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <SensorDeviceClass.HUMIDITY: 'humidity'>,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Humidity',
|
||||||
|
'platform': 'vesync',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': None,
|
||||||
|
'unique_id': '600s-humidifier-humidity',
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
# ---
|
# ---
|
||||||
|
# name: test_sensor_state[Humidifier 600S][sensor.humidifier_600s_humidity]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'device_class': 'humidity',
|
||||||
|
'friendly_name': 'Humidifier 600S Humidity',
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'sensor.humidifier_600s_humidity',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': '35',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
# name: test_sensor_state[Outlet][devices]
|
# name: test_sensor_state[Outlet][devices]
|
||||||
list([
|
list([
|
||||||
DeviceRegistryEntrySnapshot({
|
DeviceRegistryEntrySnapshot({
|
||||||
|
@ -229,6 +229,36 @@
|
|||||||
# ---
|
# ---
|
||||||
# name: test_switch_state[Humidifier 200s][devices]
|
# name: test_switch_state[Humidifier 200s][devices]
|
||||||
list([
|
list([
|
||||||
|
DeviceRegistryEntrySnapshot({
|
||||||
|
'area_id': None,
|
||||||
|
'config_entries': <ANY>,
|
||||||
|
'configuration_url': None,
|
||||||
|
'connections': set({
|
||||||
|
}),
|
||||||
|
'disabled_by': None,
|
||||||
|
'entry_type': None,
|
||||||
|
'hw_version': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'identifiers': set({
|
||||||
|
tuple(
|
||||||
|
'vesync',
|
||||||
|
'200s-humidifier',
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
'is_new': False,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'manufacturer': 'VeSync',
|
||||||
|
'model': 'Classic200S',
|
||||||
|
'model_id': None,
|
||||||
|
'name': 'Humidifier 200s',
|
||||||
|
'name_by_user': None,
|
||||||
|
'primary_config_entry': <ANY>,
|
||||||
|
'serial_number': None,
|
||||||
|
'suggested_area': None,
|
||||||
|
'sw_version': None,
|
||||||
|
'via_device_id': None,
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
# ---
|
# ---
|
||||||
# name: test_switch_state[Humidifier 200s][entities]
|
# name: test_switch_state[Humidifier 200s][entities]
|
||||||
@ -237,6 +267,36 @@
|
|||||||
# ---
|
# ---
|
||||||
# name: test_switch_state[Humidifier 600S][devices]
|
# name: test_switch_state[Humidifier 600S][devices]
|
||||||
list([
|
list([
|
||||||
|
DeviceRegistryEntrySnapshot({
|
||||||
|
'area_id': None,
|
||||||
|
'config_entries': <ANY>,
|
||||||
|
'configuration_url': None,
|
||||||
|
'connections': set({
|
||||||
|
}),
|
||||||
|
'disabled_by': None,
|
||||||
|
'entry_type': None,
|
||||||
|
'hw_version': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'identifiers': set({
|
||||||
|
tuple(
|
||||||
|
'vesync',
|
||||||
|
'600s-humidifier',
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
'is_new': False,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'manufacturer': 'VeSync',
|
||||||
|
'model': 'LUH-A602S-WUS',
|
||||||
|
'model_id': None,
|
||||||
|
'name': 'Humidifier 600S',
|
||||||
|
'name_by_user': None,
|
||||||
|
'primary_config_entry': <ANY>,
|
||||||
|
'serial_number': None,
|
||||||
|
'suggested_area': None,
|
||||||
|
'sw_version': None,
|
||||||
|
'via_device_id': None,
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
# ---
|
# ---
|
||||||
# name: test_switch_state[Humidifier 600S][entities]
|
# name: test_switch_state[Humidifier 600S][entities]
|
||||||
|
201
tests/components/vesync/test_humidifier.py
Normal file
201
tests/components/vesync/test_humidifier.py
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
"""Tests for the humidifer module."""
|
||||||
|
|
||||||
|
from contextlib import nullcontext
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.humidifier import (
|
||||||
|
ATTR_HUMIDITY,
|
||||||
|
ATTR_MODE,
|
||||||
|
DOMAIN as HUMIDIFIER_DOMAIN,
|
||||||
|
SERVICE_SET_HUMIDITY,
|
||||||
|
SERVICE_SET_MODE,
|
||||||
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
|
from homeassistant.const import (
|
||||||
|
ATTR_ENTITY_ID,
|
||||||
|
SERVICE_TURN_OFF,
|
||||||
|
SERVICE_TURN_ON,
|
||||||
|
STATE_UNAVAILABLE,
|
||||||
|
)
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
NoException = nullcontext()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_humidifier_state(
|
||||||
|
hass: HomeAssistant, humidifier_config_entry: MockConfigEntry
|
||||||
|
) -> None:
|
||||||
|
"""Test the resulting setup state is as expected for the platform."""
|
||||||
|
|
||||||
|
humidifier_id = "humidifier.humidifier_200s"
|
||||||
|
expected_entities = [
|
||||||
|
humidifier_id,
|
||||||
|
"sensor.humidifier_200s_humidity",
|
||||||
|
]
|
||||||
|
|
||||||
|
assert humidifier_config_entry.state is ConfigEntryState.LOADED
|
||||||
|
|
||||||
|
for entity_id in expected_entities:
|
||||||
|
assert hass.states.get(entity_id).state != STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
assert hass.states.get("sensor.humidifier_200s_humidity").state == "35"
|
||||||
|
|
||||||
|
state = hass.states.get(humidifier_id)
|
||||||
|
|
||||||
|
# ATTR_HUMIDITY represents the target_humidity which comes from configuration.auto_target_humidity node
|
||||||
|
assert state.attributes.get(ATTR_HUMIDITY) == 40
|
||||||
|
|
||||||
|
|
||||||
|
async def test_set_target_humidity_invalid(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
humidifier_config_entry: MockConfigEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Test handling of invalid value in set_humidify method."""
|
||||||
|
|
||||||
|
humidifier_entity_id = "humidifier.humidifier_200s"
|
||||||
|
|
||||||
|
# Setting value out of range results in ServiceValidationError and
|
||||||
|
# VeSyncHumid200300S.set_humidity does not get called.
|
||||||
|
with (
|
||||||
|
patch("pyvesync.vesyncfan.VeSyncHumid200300S.set_humidity") as method_mock,
|
||||||
|
pytest.raises(ServiceValidationError),
|
||||||
|
):
|
||||||
|
await hass.services.async_call(
|
||||||
|
HUMIDIFIER_DOMAIN,
|
||||||
|
SERVICE_SET_HUMIDITY,
|
||||||
|
{ATTR_ENTITY_ID: humidifier_entity_id, ATTR_HUMIDITY: 20},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
method_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("api_response", "expectation"),
|
||||||
|
[(True, NoException), (False, pytest.raises(HomeAssistantError))],
|
||||||
|
)
|
||||||
|
async def test_set_target_humidity_VeSync(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
humidifier_config_entry: MockConfigEntry,
|
||||||
|
api_response: bool,
|
||||||
|
expectation,
|
||||||
|
) -> None:
|
||||||
|
"""Test handling of return value from VeSyncHumid200300S.set_humidity."""
|
||||||
|
|
||||||
|
humidifier_entity_id = "humidifier.humidifier_200s"
|
||||||
|
|
||||||
|
# If VeSyncHumid200300S.set_humidity fails (returns False), then HomeAssistantError is raised
|
||||||
|
with (
|
||||||
|
expectation,
|
||||||
|
patch(
|
||||||
|
"pyvesync.vesyncfan.VeSyncHumid200300S.set_humidity",
|
||||||
|
return_value=api_response,
|
||||||
|
) as method_mock,
|
||||||
|
):
|
||||||
|
await hass.services.async_call(
|
||||||
|
HUMIDIFIER_DOMAIN,
|
||||||
|
SERVICE_SET_HUMIDITY,
|
||||||
|
{ATTR_ENTITY_ID: humidifier_entity_id, ATTR_HUMIDITY: 54},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
method_mock.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("turn_on", "api_response", "expectation"),
|
||||||
|
[
|
||||||
|
(False, False, pytest.raises(HomeAssistantError)),
|
||||||
|
(False, True, NoException),
|
||||||
|
(True, False, pytest.raises(HomeAssistantError)),
|
||||||
|
(True, True, NoException),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_turn_on_off(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
humidifier_config_entry: MockConfigEntry,
|
||||||
|
turn_on: bool,
|
||||||
|
api_response: bool,
|
||||||
|
expectation,
|
||||||
|
) -> None:
|
||||||
|
"""Test turn_on/off methods."""
|
||||||
|
|
||||||
|
humidifier_entity_id = "humidifier.humidifier_200s"
|
||||||
|
|
||||||
|
# turn_on/turn_off returns False indicating failure in which case humidifier.turn_on/turn_off
|
||||||
|
# raises HomeAssistantError.
|
||||||
|
with (
|
||||||
|
expectation,
|
||||||
|
patch(
|
||||||
|
f"pyvesync.vesyncfan.VeSyncHumid200300S.{"turn_on" if turn_on else "turn_off"}",
|
||||||
|
return_value=api_response,
|
||||||
|
) as method_mock,
|
||||||
|
):
|
||||||
|
await hass.services.async_call(
|
||||||
|
HUMIDIFIER_DOMAIN,
|
||||||
|
SERVICE_TURN_ON if turn_on else SERVICE_TURN_OFF,
|
||||||
|
{ATTR_ENTITY_ID: humidifier_entity_id},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
method_mock.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_set_mode_invalid(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
humidifier_config_entry: MockConfigEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Test handling of invalid value in set_mode method."""
|
||||||
|
|
||||||
|
humidifier_entity_id = "humidifier.humidifier_200s"
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"pyvesync.vesyncfan.VeSyncHumid200300S.set_humidity_mode"
|
||||||
|
) as method_mock:
|
||||||
|
with pytest.raises(HomeAssistantError):
|
||||||
|
await hass.services.async_call(
|
||||||
|
HUMIDIFIER_DOMAIN,
|
||||||
|
SERVICE_SET_MODE,
|
||||||
|
{ATTR_ENTITY_ID: humidifier_entity_id, ATTR_MODE: "something_invalid"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
method_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("api_response", "expectation"),
|
||||||
|
[(True, NoException), (False, pytest.raises(HomeAssistantError))],
|
||||||
|
)
|
||||||
|
async def test_set_mode_VeSync(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
humidifier_config_entry: MockConfigEntry,
|
||||||
|
api_response: bool,
|
||||||
|
expectation,
|
||||||
|
) -> None:
|
||||||
|
"""Test handling of value in set_mode method."""
|
||||||
|
|
||||||
|
humidifier_entity_id = "humidifier.humidifier_200s"
|
||||||
|
|
||||||
|
# If VeSyncHumid200300S.set_humidity_mode fails (returns False), then HomeAssistantError is raised
|
||||||
|
with (
|
||||||
|
expectation,
|
||||||
|
patch(
|
||||||
|
"pyvesync.vesyncfan.VeSyncHumid200300S.set_humidity_mode",
|
||||||
|
return_value=api_response,
|
||||||
|
) as method_mock,
|
||||||
|
):
|
||||||
|
await hass.services.async_call(
|
||||||
|
HUMIDIFIER_DOMAIN,
|
||||||
|
SERVICE_SET_MODE,
|
||||||
|
{ATTR_ENTITY_ID: humidifier_entity_id, ATTR_MODE: "auto"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
method_mock.assert_called_once()
|
@ -49,6 +49,7 @@ async def test_async_setup_entry__no_devices(
|
|||||||
assert setups_mock.call_args.args[0] == config_entry
|
assert setups_mock.call_args.args[0] == config_entry
|
||||||
assert setups_mock.call_args.args[1] == [
|
assert setups_mock.call_args.args[1] == [
|
||||||
Platform.FAN,
|
Platform.FAN,
|
||||||
|
Platform.HUMIDIFIER,
|
||||||
Platform.LIGHT,
|
Platform.LIGHT,
|
||||||
Platform.SENSOR,
|
Platform.SENSOR,
|
||||||
Platform.SWITCH,
|
Platform.SWITCH,
|
||||||
@ -77,6 +78,7 @@ async def test_async_setup_entry__loads_fans(
|
|||||||
assert setups_mock.call_args.args[0] == config_entry
|
assert setups_mock.call_args.args[0] == config_entry
|
||||||
assert setups_mock.call_args.args[1] == [
|
assert setups_mock.call_args.args[1] == [
|
||||||
Platform.FAN,
|
Platform.FAN,
|
||||||
|
Platform.HUMIDIFIER,
|
||||||
Platform.LIGHT,
|
Platform.LIGHT,
|
||||||
Platform.SENSOR,
|
Platform.SENSOR,
|
||||||
Platform.SWITCH,
|
Platform.SWITCH,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user