Change Dyson PureCoolLink fan speeds to adhere the standard (#45331)

This commit is contained in:
Xiaonan Shen 2021-01-21 05:27:16 +08:00 committed by GitHub
parent a7741be9bb
commit 96448c6778
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 198 additions and 237 deletions

View File

@ -1,5 +1,6 @@
"""Support for Dyson Pure Cool link fan.""" """Support for Dyson Pure Cool link fan."""
import logging import logging
from typing import Optional
from libpurecool.const import FanMode, FanSpeed, NightMode, Oscillation from libpurecool.const import FanMode, FanSpeed, NightMode, Oscillation
from libpurecool.dyson_pure_cool import DysonPureCool from libpurecool.dyson_pure_cool import DysonPureCool
@ -16,8 +17,7 @@ from homeassistant.components.fan import (
SUPPORT_SET_SPEED, SUPPORT_SET_SPEED,
FanEntity, FanEntity,
) )
from homeassistant.const import ATTR_ENTITY_ID from homeassistant.helpers import config_validation as cv, entity_platform
import homeassistant.helpers.config_validation as cv
from . import DYSON_DEVICES, DysonEntity from . import DYSON_DEVICES, DysonEntity
@ -44,51 +44,69 @@ SERVICE_SET_FLOW_DIRECTION_FRONT = "set_flow_direction_front"
SERVICE_SET_TIMER = "set_timer" SERVICE_SET_TIMER = "set_timer"
SERVICE_SET_DYSON_SPEED = "set_speed" SERVICE_SET_DYSON_SPEED = "set_speed"
DYSON_SET_NIGHT_MODE_SCHEMA = vol.Schema( SET_NIGHT_MODE_SCHEMA = {
{ vol.Required(ATTR_NIGHT_MODE): cv.boolean,
vol.Required(ATTR_ENTITY_ID): cv.entity_id, }
vol.Required(ATTR_NIGHT_MODE): cv.boolean,
}
)
SET_AUTO_MODE_SCHEMA = vol.Schema( SET_AUTO_MODE_SCHEMA = {
{ vol.Required(ATTR_AUTO_MODE): cv.boolean,
vol.Required(ATTR_ENTITY_ID): cv.entity_id, }
vol.Required(ATTR_AUTO_MODE): cv.boolean,
}
)
SET_ANGLE_SCHEMA = vol.Schema( SET_ANGLE_SCHEMA = {
{ vol.Required(ATTR_ANGLE_LOW): cv.positive_int,
vol.Required(ATTR_ENTITY_ID): cv.entity_id, vol.Required(ATTR_ANGLE_HIGH): cv.positive_int,
vol.Required(ATTR_ANGLE_LOW): cv.positive_int, }
vol.Required(ATTR_ANGLE_HIGH): cv.positive_int,
}
)
SET_FLOW_DIRECTION_FRONT_SCHEMA = vol.Schema( SET_FLOW_DIRECTION_FRONT_SCHEMA = {
{ vol.Required(ATTR_FLOW_DIRECTION_FRONT): cv.boolean,
vol.Required(ATTR_ENTITY_ID): cv.entity_id, }
vol.Required(ATTR_FLOW_DIRECTION_FRONT): cv.boolean,
}
)
SET_TIMER_SCHEMA = vol.Schema( SET_TIMER_SCHEMA = {
{ vol.Required(ATTR_TIMER): cv.positive_int,
vol.Required(ATTR_ENTITY_ID): cv.entity_id, }
vol.Required(ATTR_TIMER): cv.positive_int,
}
)
SET_DYSON_SPEED_SCHEMA = vol.Schema( SET_DYSON_SPEED_SCHEMA = {
{ vol.Required(ATTR_DYSON_SPEED): cv.positive_int,
vol.Required(ATTR_ENTITY_ID): cv.entity_id, }
vol.Required(ATTR_DYSON_SPEED): cv.positive_int,
}
)
def setup_platform(hass, config, add_entities, discovery_info=None): SPEED_LIST_HA = [SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH]
SPEED_LIST_DYSON = [
int(FanSpeed.FAN_SPEED_1.value),
int(FanSpeed.FAN_SPEED_2.value),
int(FanSpeed.FAN_SPEED_3.value),
int(FanSpeed.FAN_SPEED_4.value),
int(FanSpeed.FAN_SPEED_5.value),
int(FanSpeed.FAN_SPEED_6.value),
int(FanSpeed.FAN_SPEED_7.value),
int(FanSpeed.FAN_SPEED_8.value),
int(FanSpeed.FAN_SPEED_9.value),
int(FanSpeed.FAN_SPEED_10.value),
]
SPEED_DYSON_TO_HA = {
FanSpeed.FAN_SPEED_1.value: SPEED_LOW,
FanSpeed.FAN_SPEED_2.value: SPEED_LOW,
FanSpeed.FAN_SPEED_3.value: SPEED_LOW,
FanSpeed.FAN_SPEED_4.value: SPEED_LOW,
FanSpeed.FAN_SPEED_AUTO.value: SPEED_MEDIUM,
FanSpeed.FAN_SPEED_5.value: SPEED_MEDIUM,
FanSpeed.FAN_SPEED_6.value: SPEED_MEDIUM,
FanSpeed.FAN_SPEED_7.value: SPEED_MEDIUM,
FanSpeed.FAN_SPEED_8.value: SPEED_HIGH,
FanSpeed.FAN_SPEED_9.value: SPEED_HIGH,
FanSpeed.FAN_SPEED_10.value: SPEED_HIGH,
}
SPEED_HA_TO_DYSON = {
SPEED_LOW: FanSpeed.FAN_SPEED_4,
SPEED_MEDIUM: FanSpeed.FAN_SPEED_7,
SPEED_HIGH: FanSpeed.FAN_SPEED_10,
}
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the Dyson fan components.""" """Set up the Dyson fan components."""
if discovery_info is None: if discovery_info is None:
@ -111,82 +129,102 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
dyson_entity = DysonPureCoolLinkEntity(device) dyson_entity = DysonPureCoolLinkEntity(device)
hass.data[DYSON_FAN_DEVICES].append(dyson_entity) hass.data[DYSON_FAN_DEVICES].append(dyson_entity)
add_entities(hass.data[DYSON_FAN_DEVICES]) async_add_entities(hass.data[DYSON_FAN_DEVICES])
def service_handle(service): # Register custom services
"""Handle the Dyson services.""" platform = entity_platform.current_platform.get()
entity_id = service.data[ATTR_ENTITY_ID] platform.async_register_entity_service(
fan_device = next( SERVICE_SET_NIGHT_MODE, SET_NIGHT_MODE_SCHEMA, "set_night_mode"
(fan for fan in hass.data[DYSON_FAN_DEVICES] if fan.entity_id == entity_id),
None,
)
if fan_device is None:
_LOGGER.warning("Unable to find Dyson fan device %s", str(entity_id))
return
if service.service == SERVICE_SET_NIGHT_MODE:
fan_device.set_night_mode(service.data[ATTR_NIGHT_MODE])
if service.service == SERVICE_SET_AUTO_MODE:
fan_device.set_auto_mode(service.data[ATTR_AUTO_MODE])
if service.service == SERVICE_SET_ANGLE:
fan_device.set_angle(
service.data[ATTR_ANGLE_LOW], service.data[ATTR_ANGLE_HIGH]
)
if service.service == SERVICE_SET_FLOW_DIRECTION_FRONT:
fan_device.set_flow_direction_front(service.data[ATTR_FLOW_DIRECTION_FRONT])
if service.service == SERVICE_SET_TIMER:
fan_device.set_timer(service.data[ATTR_TIMER])
if service.service == SERVICE_SET_DYSON_SPEED:
fan_device.set_dyson_speed(service.data[ATTR_DYSON_SPEED])
# Register dyson service(s)
hass.services.register(
DYSON_DOMAIN,
SERVICE_SET_NIGHT_MODE,
service_handle,
schema=DYSON_SET_NIGHT_MODE_SCHEMA,
) )
platform.async_register_entity_service(
hass.services.register( SERVICE_SET_AUTO_MODE, SET_AUTO_MODE_SCHEMA, "set_auto_mode"
DYSON_DOMAIN, SERVICE_SET_AUTO_MODE, service_handle, schema=SET_AUTO_MODE_SCHEMA )
platform.async_register_entity_service(
SERVICE_SET_DYSON_SPEED, SET_DYSON_SPEED_SCHEMA, "service_set_dyson_speed"
) )
if has_purecool_devices: if has_purecool_devices:
hass.services.register( platform.async_register_entity_service(
DYSON_DOMAIN, SERVICE_SET_ANGLE, service_handle, schema=SET_ANGLE_SCHEMA SERVICE_SET_ANGLE, SET_ANGLE_SCHEMA, "set_angle"
) )
platform.async_register_entity_service(
hass.services.register(
DYSON_DOMAIN,
SERVICE_SET_FLOW_DIRECTION_FRONT, SERVICE_SET_FLOW_DIRECTION_FRONT,
service_handle, SET_FLOW_DIRECTION_FRONT_SCHEMA,
schema=SET_FLOW_DIRECTION_FRONT_SCHEMA, "set_flow_direction_front",
) )
platform.async_register_entity_service(
hass.services.register( SERVICE_SET_TIMER, SET_TIMER_SCHEMA, "set_timer"
DYSON_DOMAIN, SERVICE_SET_TIMER, service_handle, schema=SET_TIMER_SCHEMA
)
hass.services.register(
DYSON_DOMAIN,
SERVICE_SET_DYSON_SPEED,
service_handle,
schema=SET_DYSON_SPEED_SCHEMA,
) )
class DysonFanEntity(DysonEntity, FanEntity): class DysonFanEntity(DysonEntity, FanEntity):
"""Representation of a Dyson fan.""" """Representation of a Dyson fan."""
@property
def speed(self):
"""Return the current speed."""
return SPEED_DYSON_TO_HA[self._device.state.speed]
@property
def speed_list(self) -> list:
"""Get the list of available speeds."""
return SPEED_LIST_HA
@property
def dyson_speed(self):
"""Return the current speed."""
if self._device.state.speed == FanSpeed.FAN_SPEED_AUTO.value:
return self._device.state.speed
return int(self._device.state.speed)
@property
def dyson_speed_list(self) -> list:
"""Get the list of available dyson speeds."""
return SPEED_LIST_DYSON
@property @property
def night_mode(self): def night_mode(self):
"""Return Night mode.""" """Return Night mode."""
return self._device.state.night_mode == "ON" return self._device.state.night_mode == "ON"
@property
def auto_mode(self):
"""Return auto mode."""
raise NotImplementedError
@property
def supported_features(self) -> int:
"""Flag supported features."""
return SUPPORT_OSCILLATE | SUPPORT_SET_SPEED
@property
def device_state_attributes(self) -> dict:
"""Return optional state attributes."""
return {
ATTR_NIGHT_MODE: self.night_mode,
ATTR_AUTO_MODE: self.auto_mode,
ATTR_DYSON_SPEED: self.dyson_speed,
ATTR_DYSON_SPEED_LIST: self.dyson_speed_list,
}
def set_speed(self, speed: str) -> None:
"""Set the speed of the fan."""
if speed not in SPEED_LIST_HA:
raise ValueError(f'"{speed}" is not a valid speed')
_LOGGER.debug("Set fan speed to: %s", speed)
self.set_dyson_speed(SPEED_HA_TO_DYSON[speed])
def set_dyson_speed(self, speed: FanSpeed) -> None:
"""Set the exact speed of the fan."""
raise NotImplementedError
def service_set_dyson_speed(self, dyson_speed: str) -> None:
"""Handle the service to set dyson speed."""
if dyson_speed not in SPEED_LIST_DYSON:
raise ValueError(f'"{dyson_speed}" is not a valid Dyson speed')
_LOGGER.debug("Set exact speed to %s", dyson_speed)
speed = FanSpeed(f"{int(dyson_speed):04d}")
self.set_dyson_speed(speed)
class DysonPureCoolLinkEntity(DysonFanEntity): class DysonPureCoolLinkEntity(DysonFanEntity):
"""Representation of a Dyson fan.""" """Representation of a Dyson fan."""
@ -195,27 +233,11 @@ class DysonPureCoolLinkEntity(DysonFanEntity):
"""Initialize the fan.""" """Initialize the fan."""
super().__init__(device, DysonPureCoolState) super().__init__(device, DysonPureCoolState)
def set_speed(self, speed: str) -> None: def turn_on(self, speed: Optional[str] = None, **kwargs) -> None:
"""Set the speed of the fan. Never called ??."""
_LOGGER.debug("Set fan speed to: %s", speed)
if speed == FanSpeed.FAN_SPEED_AUTO.value:
self._device.set_configuration(fan_mode=FanMode.AUTO)
else:
fan_speed = FanSpeed(f"{int(speed):04d}")
self._device.set_configuration(fan_mode=FanMode.FAN, fan_speed=fan_speed)
def turn_on(self, speed: str = None, **kwargs) -> None:
"""Turn on the fan.""" """Turn on the fan."""
_LOGGER.debug("Turn on fan %s with speed %s", self.name, speed) _LOGGER.debug("Turn on fan %s with speed %s", self.name, speed)
if speed: if speed is not None:
if speed == FanSpeed.FAN_SPEED_AUTO.value: self.set_speed(speed)
self._device.set_configuration(fan_mode=FanMode.AUTO)
else:
fan_speed = FanSpeed(f"{int(speed):04d}")
self._device.set_configuration(
fan_mode=FanMode.FAN, fan_speed=fan_speed
)
else: else:
# Speed not set, just turn on # Speed not set, just turn on
self._device.set_configuration(fan_mode=FanMode.FAN) self._device.set_configuration(fan_mode=FanMode.FAN)
@ -225,6 +247,10 @@ class DysonPureCoolLinkEntity(DysonFanEntity):
_LOGGER.debug("Turn off fan %s", self.name) _LOGGER.debug("Turn off fan %s", self.name)
self._device.set_configuration(fan_mode=FanMode.OFF) self._device.set_configuration(fan_mode=FanMode.OFF)
def set_dyson_speed(self, speed: FanSpeed) -> None:
"""Set the exact speed of the fan."""
self._device.set_configuration(fan_mode=FanMode.FAN, fan_speed=speed)
def oscillate(self, oscillating: bool) -> None: def oscillate(self, oscillating: bool) -> None:
"""Turn on/off oscillating.""" """Turn on/off oscillating."""
_LOGGER.debug("Turn oscillation %s for device %s", oscillating, self.name) _LOGGER.debug("Turn oscillation %s for device %s", oscillating, self.name)
@ -244,13 +270,6 @@ class DysonPureCoolLinkEntity(DysonFanEntity):
"""Return true if the entity is on.""" """Return true if the entity is on."""
return self._device.state.fan_mode in ["FAN", "AUTO"] return self._device.state.fan_mode in ["FAN", "AUTO"]
@property
def speed(self) -> str:
"""Return the current speed."""
if self._device.state.speed == FanSpeed.FAN_SPEED_AUTO.value:
return self._device.state.speed
return int(self._device.state.speed)
def set_night_mode(self, night_mode: bool) -> None: def set_night_mode(self, night_mode: bool) -> None:
"""Turn fan in night mode.""" """Turn fan in night mode."""
_LOGGER.debug("Set %s night mode %s", self.name, night_mode) _LOGGER.debug("Set %s night mode %s", self.name, night_mode)
@ -272,35 +291,6 @@ class DysonPureCoolLinkEntity(DysonFanEntity):
else: else:
self._device.set_configuration(fan_mode=FanMode.FAN) self._device.set_configuration(fan_mode=FanMode.FAN)
@property
def speed_list(self) -> list:
"""Get the list of available speeds."""
supported_speeds = [
FanSpeed.FAN_SPEED_AUTO.value,
int(FanSpeed.FAN_SPEED_1.value),
int(FanSpeed.FAN_SPEED_2.value),
int(FanSpeed.FAN_SPEED_3.value),
int(FanSpeed.FAN_SPEED_4.value),
int(FanSpeed.FAN_SPEED_5.value),
int(FanSpeed.FAN_SPEED_6.value),
int(FanSpeed.FAN_SPEED_7.value),
int(FanSpeed.FAN_SPEED_8.value),
int(FanSpeed.FAN_SPEED_9.value),
int(FanSpeed.FAN_SPEED_10.value),
]
return supported_speeds
@property
def supported_features(self) -> int:
"""Flag supported features."""
return SUPPORT_OSCILLATE | SUPPORT_SET_SPEED
@property
def device_state_attributes(self) -> dict:
"""Return optional state attributes."""
return {ATTR_NIGHT_MODE: self.night_mode, ATTR_AUTO_MODE: self.auto_mode}
class DysonPureCoolEntity(DysonFanEntity): class DysonPureCoolEntity(DysonFanEntity):
"""Representation of a Dyson Purecool (TP04/DP04) fan.""" """Representation of a Dyson Purecool (TP04/DP04) fan."""
@ -309,7 +299,7 @@ class DysonPureCoolEntity(DysonFanEntity):
"""Initialize the fan.""" """Initialize the fan."""
super().__init__(device, DysonPureCoolV2State) super().__init__(device, DysonPureCoolV2State)
def turn_on(self, speed: str = None, **kwargs) -> None: def turn_on(self, speed: Optional[str] = None, **kwargs) -> None:
"""Turn on the fan.""" """Turn on the fan."""
_LOGGER.debug("Turn on fan %s", self.name) _LOGGER.debug("Turn on fan %s", self.name)
@ -318,26 +308,14 @@ class DysonPureCoolEntity(DysonFanEntity):
else: else:
self._device.turn_on() self._device.turn_on()
def set_speed(self, speed: str) -> None:
"""Set the speed of the fan."""
if speed == SPEED_LOW:
self._device.set_fan_speed(FanSpeed.FAN_SPEED_4)
elif speed == SPEED_MEDIUM:
self._device.set_fan_speed(FanSpeed.FAN_SPEED_7)
elif speed == SPEED_HIGH:
self._device.set_fan_speed(FanSpeed.FAN_SPEED_10)
def turn_off(self, **kwargs): def turn_off(self, **kwargs):
"""Turn off the fan.""" """Turn off the fan."""
_LOGGER.debug("Turn off fan %s", self.name) _LOGGER.debug("Turn off fan %s", self.name)
self._device.turn_off() self._device.turn_off()
def set_dyson_speed(self, speed: str = None) -> None: def set_dyson_speed(self, speed: FanSpeed) -> None:
"""Set the exact speed of the purecool fan.""" """Set the exact speed of the purecool fan."""
_LOGGER.debug("Set exact speed for fan %s", self.name) self._device.set_fan_speed(speed)
fan_speed = FanSpeed(f"{int(speed):04d}")
self._device.set_fan_speed(fan_speed)
def oscillate(self, oscillating: bool) -> None: def oscillate(self, oscillating: bool) -> None:
"""Turn on/off oscillating.""" """Turn on/off oscillating."""
@ -407,33 +385,6 @@ class DysonPureCoolEntity(DysonFanEntity):
"""Return true if the entity is on.""" """Return true if the entity is on."""
return self._device.state.fan_power == "ON" return self._device.state.fan_power == "ON"
@property
def speed(self):
"""Return the current speed."""
speed_map = {
FanSpeed.FAN_SPEED_1.value: SPEED_LOW,
FanSpeed.FAN_SPEED_2.value: SPEED_LOW,
FanSpeed.FAN_SPEED_3.value: SPEED_LOW,
FanSpeed.FAN_SPEED_4.value: SPEED_LOW,
FanSpeed.FAN_SPEED_AUTO.value: SPEED_MEDIUM,
FanSpeed.FAN_SPEED_5.value: SPEED_MEDIUM,
FanSpeed.FAN_SPEED_6.value: SPEED_MEDIUM,
FanSpeed.FAN_SPEED_7.value: SPEED_MEDIUM,
FanSpeed.FAN_SPEED_8.value: SPEED_HIGH,
FanSpeed.FAN_SPEED_9.value: SPEED_HIGH,
FanSpeed.FAN_SPEED_10.value: SPEED_HIGH,
}
return speed_map[self._device.state.speed]
@property
def dyson_speed(self):
"""Return the current speed."""
if self._device.state:
if self._device.state.speed == FanSpeed.FAN_SPEED_AUTO.value:
return self._device.state.speed
return int(self._device.state.speed)
@property @property
def auto_mode(self): def auto_mode(self):
"""Return Auto mode.""" """Return Auto mode."""
@ -471,44 +422,15 @@ class DysonPureCoolEntity(DysonFanEntity):
return self._device.state.carbon_filter_state return self._device.state.carbon_filter_state
return int(self._device.state.carbon_filter_state) return int(self._device.state.carbon_filter_state)
@property
def speed_list(self) -> list:
"""Get the list of available speeds."""
return [SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH]
@property
def dyson_speed_list(self) -> list:
"""Get the list of available dyson speeds."""
return [
int(FanSpeed.FAN_SPEED_1.value),
int(FanSpeed.FAN_SPEED_2.value),
int(FanSpeed.FAN_SPEED_3.value),
int(FanSpeed.FAN_SPEED_4.value),
int(FanSpeed.FAN_SPEED_5.value),
int(FanSpeed.FAN_SPEED_6.value),
int(FanSpeed.FAN_SPEED_7.value),
int(FanSpeed.FAN_SPEED_8.value),
int(FanSpeed.FAN_SPEED_9.value),
int(FanSpeed.FAN_SPEED_10.value),
]
@property
def supported_features(self) -> int:
"""Flag supported features."""
return SUPPORT_OSCILLATE | SUPPORT_SET_SPEED
@property @property
def device_state_attributes(self) -> dict: def device_state_attributes(self) -> dict:
"""Return optional state attributes.""" """Return optional state attributes."""
return { return {
ATTR_NIGHT_MODE: self.night_mode, **super().device_state_attributes,
ATTR_AUTO_MODE: self.auto_mode,
ATTR_ANGLE_LOW: self.angle_low, ATTR_ANGLE_LOW: self.angle_low,
ATTR_ANGLE_HIGH: self.angle_high, ATTR_ANGLE_HIGH: self.angle_high,
ATTR_FLOW_DIRECTION_FRONT: self.flow_direction_front, ATTR_FLOW_DIRECTION_FRONT: self.flow_direction_front,
ATTR_TIMER: self.timer, ATTR_TIMER: self.timer,
ATTR_HEPA_FILTER: self.hepa_filter, ATTR_HEPA_FILTER: self.hepa_filter,
ATTR_CARBON_FILTER: self.carbon_filter, ATTR_CARBON_FILTER: self.carbon_filter,
ATTR_DYSON_SPEED: self.dyson_speed,
ATTR_DYSON_SPEED_LIST: self.dyson_speed_list,
} }

View File

@ -15,7 +15,7 @@ from tests.common import async_setup_component
BASE_PATH = "homeassistant.components.dyson" BASE_PATH = "homeassistant.components.dyson"
@pytest.fixture @pytest.fixture()
async def device(hass: HomeAssistant, request) -> DysonDevice: async def device(hass: HomeAssistant, request) -> DysonDevice:
"""Fixture to provide Dyson 360 Eye device.""" """Fixture to provide Dyson 360 Eye device."""
platform = request.module.PLATFORM_DOMAIN platform = request.module.PLATFORM_DOMAIN

View File

@ -93,10 +93,10 @@ async def test_state_purecoollink(
attributes = state.attributes attributes = state.attributes
assert attributes[ATTR_NIGHT_MODE] is True assert attributes[ATTR_NIGHT_MODE] is True
assert attributes[ATTR_OSCILLATING] is True assert attributes[ATTR_OSCILLATING] is True
assert attributes[ATTR_SPEED] == 1 assert attributes[ATTR_SPEED] == SPEED_LOW
assert attributes[ATTR_SPEED_LIST] == [FanSpeed.FAN_SPEED_AUTO.value] + list( assert attributes[ATTR_SPEED_LIST] == [SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH]
range(1, 11) assert attributes[ATTR_DYSON_SPEED] == 1
) assert attributes[ATTR_DYSON_SPEED_LIST] == list(range(1, 11))
assert attributes[ATTR_AUTO_MODE] is False assert attributes[ATTR_AUTO_MODE] is False
assert attributes[ATTR_SUPPORTED_FEATURES] == SUPPORT_OSCILLATE | SUPPORT_SET_SPEED assert attributes[ATTR_SUPPORTED_FEATURES] == SUPPORT_OSCILLATE | SUPPORT_SET_SPEED
@ -115,7 +115,8 @@ async def test_state_purecoollink(
attributes = state.attributes attributes = state.attributes
assert attributes[ATTR_NIGHT_MODE] is False assert attributes[ATTR_NIGHT_MODE] is False
assert attributes[ATTR_OSCILLATING] is False assert attributes[ATTR_OSCILLATING] is False
assert attributes[ATTR_SPEED] == "AUTO" assert attributes[ATTR_SPEED] == SPEED_MEDIUM
assert attributes[ATTR_DYSON_SPEED] == "AUTO"
assert attributes[ATTR_AUTO_MODE] is True assert attributes[ATTR_AUTO_MODE] is True
@ -173,11 +174,10 @@ async def test_state_purecool(hass: HomeAssistant, device: DysonPureCool) -> Non
"service,service_data,configuration_args", "service,service_data,configuration_args",
[ [
(SERVICE_TURN_ON, {}, {"fan_mode": FanMode.FAN}), (SERVICE_TURN_ON, {}, {"fan_mode": FanMode.FAN}),
(SERVICE_TURN_ON, {ATTR_SPEED: "AUTO"}, {"fan_mode": FanMode.AUTO}),
( (
SERVICE_TURN_ON, SERVICE_TURN_ON,
{ATTR_SPEED: 5}, {ATTR_SPEED: SPEED_LOW},
{"fan_mode": FanMode.FAN, "fan_speed": FanSpeed("0005")}, {"fan_mode": FanMode.FAN, "fan_speed": FanSpeed.FAN_SPEED_4},
), ),
(SERVICE_TURN_OFF, {}, {"fan_mode": FanMode.OFF}), (SERVICE_TURN_OFF, {}, {"fan_mode": FanMode.OFF}),
( (
@ -190,11 +190,20 @@ async def test_state_purecool(hass: HomeAssistant, device: DysonPureCool) -> Non
{ATTR_OSCILLATING: False}, {ATTR_OSCILLATING: False},
{"oscillation": Oscillation.OSCILLATION_OFF}, {"oscillation": Oscillation.OSCILLATION_OFF},
), ),
(SERVICE_SET_SPEED, {ATTR_SPEED: "AUTO"}, {"fan_mode": FanMode.AUTO}),
( (
SERVICE_SET_SPEED, SERVICE_SET_SPEED,
{ATTR_SPEED: 5}, {ATTR_SPEED: SPEED_LOW},
{"fan_mode": FanMode.FAN, "fan_speed": FanSpeed("0005")}, {"fan_mode": FanMode.FAN, "fan_speed": FanSpeed.FAN_SPEED_4},
),
(
SERVICE_SET_SPEED,
{ATTR_SPEED: SPEED_MEDIUM},
{"fan_mode": FanMode.FAN, "fan_speed": FanSpeed.FAN_SPEED_7},
),
(
SERVICE_SET_SPEED,
{ATTR_SPEED: SPEED_HIGH},
{"fan_mode": FanMode.FAN, "fan_speed": FanSpeed.FAN_SPEED_10},
), ),
], ],
) )
@ -289,6 +298,11 @@ async def test_commands_purecool(
), ),
(SERVICE_SET_AUTO_MODE, {"auto_mode": True}, {"fan_mode": FanMode.AUTO}), (SERVICE_SET_AUTO_MODE, {"auto_mode": True}, {"fan_mode": FanMode.AUTO}),
(SERVICE_SET_AUTO_MODE, {"auto_mode": False}, {"fan_mode": FanMode.FAN}), (SERVICE_SET_AUTO_MODE, {"auto_mode": False}, {"fan_mode": FanMode.FAN}),
(
SERVICE_SET_DYSON_SPEED,
{ATTR_DYSON_SPEED: "4"},
{"fan_mode": FanMode.FAN, "fan_speed": FanSpeed.FAN_SPEED_4},
),
], ],
) )
@pytest.mark.parametrize("device", [DysonPureCoolLink], indirect=True) @pytest.mark.parametrize("device", [DysonPureCoolLink], indirect=True)
@ -368,3 +382,28 @@ async def test_custom_services_purecool(
blocking=True, blocking=True,
) )
getattr(device, command).assert_called_once_with(*command_args) getattr(device, command).assert_called_once_with(*command_args)
@pytest.mark.parametrize(
"domain,service,data",
[
(PLATFORM_DOMAIN, SERVICE_TURN_ON, {ATTR_SPEED: "AUTO"}),
(PLATFORM_DOMAIN, SERVICE_SET_SPEED, {ATTR_SPEED: "AUTO"}),
(DOMAIN, SERVICE_SET_DYSON_SPEED, {ATTR_DYSON_SPEED: "11"}),
],
)
@pytest.mark.parametrize("device", [DysonPureCool], indirect=True)
async def test_custom_services_invalid_data(
hass: HomeAssistant, device: DysonPureCool, domain: str, service: str, data: dict
) -> None:
"""Test custom services calling with invalid data."""
with pytest.raises(ValueError):
await hass.services.async_call(
domain,
service,
{
ATTR_ENTITY_ID: ENTITY_ID,
**data,
},
blocking=True,
)