Add support for Dyson Purecool 2018 Air Purifiers models TP04 and DP04 (#22215)
* initial commit initial commit rewrite tests fix merge issue with fan component fix merge issue with fan component * correct line length * change to sync_setup_component for tests * rename services and move services.yaml * move hepa and carbon filter state from sensor to fan * add test for duplicate entities * fix method call tests * fix docstring
This commit is contained in:
parent
1ce622469d
commit
e78709c5f5
15 changed files with 946 additions and 133 deletions
|
@ -3,12 +3,12 @@ import logging
|
|||
|
||||
import voluptuous as vol
|
||||
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.const import (
|
||||
CONF_DEVICES, CONF_PASSWORD, CONF_TIMEOUT, CONF_USERNAME)
|
||||
from homeassistant.helpers import discovery
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
REQUIREMENTS = ['libpurecoollink==0.4.2']
|
||||
REQUIREMENTS = ['libpurecool==0.5.0']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -41,7 +41,7 @@ def setup(hass, config):
|
|||
if DYSON_DEVICES not in hass.data:
|
||||
hass.data[DYSON_DEVICES] = []
|
||||
|
||||
from libpurecoollink.dyson import DysonAccount
|
||||
from libpurecool.dyson import DysonAccount
|
||||
dyson_account = DysonAccount(config[DOMAIN].get(CONF_USERNAME),
|
||||
config[DOMAIN].get(CONF_PASSWORD),
|
||||
config[DOMAIN].get(CONF_LANGUAGE))
|
||||
|
|
|
@ -11,7 +11,6 @@ from homeassistant.components.climate.const import (
|
|||
STATE_COOL, STATE_HEAT, STATE_IDLE, SUPPORT_FAN_MODE,
|
||||
SUPPORT_OPERATION_MODE, SUPPORT_TARGET_TEMPERATURE)
|
||||
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
|
||||
|
||||
from . import DYSON_DEVICES
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -30,7 +29,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||
if discovery_info is None:
|
||||
return
|
||||
|
||||
from libpurecoollink.dyson_pure_hotcool_link import DysonPureHotCoolLink
|
||||
from libpurecool.dyson_pure_hotcool_link import DysonPureHotCoolLink
|
||||
# Get Dyson Devices from parent component.
|
||||
add_devices(
|
||||
[DysonPureHotCoolLinkDevice(device)
|
||||
|
@ -54,7 +53,7 @@ class DysonPureHotCoolLinkDevice(ClimateDevice):
|
|||
|
||||
def on_message(self, message):
|
||||
"""Call when new messages received from the climate."""
|
||||
from libpurecoollink.dyson_pure_state import DysonPureHotCoolState
|
||||
from libpurecool.dyson_pure_state import DysonPureHotCoolState
|
||||
|
||||
if isinstance(message, DysonPureHotCoolState):
|
||||
_LOGGER.debug("Message received for climate device %s : %s",
|
||||
|
@ -109,7 +108,7 @@ class DysonPureHotCoolLinkDevice(ClimateDevice):
|
|||
@property
|
||||
def current_operation(self):
|
||||
"""Return current operation ie. heat, cool, idle."""
|
||||
from libpurecoollink.const import HeatMode, HeatState
|
||||
from libpurecool.const import HeatMode, HeatState
|
||||
if self._device.state.heat_mode == HeatMode.HEAT_ON.value:
|
||||
if self._device.state.heat_state == HeatState.HEAT_STATE_ON.value:
|
||||
return STATE_HEAT
|
||||
|
@ -124,7 +123,7 @@ class DysonPureHotCoolLinkDevice(ClimateDevice):
|
|||
@property
|
||||
def current_fan_mode(self):
|
||||
"""Return the fan setting."""
|
||||
from libpurecoollink.const import FocusMode
|
||||
from libpurecool.const import FocusMode
|
||||
if self._device.state.focus_mode == FocusMode.FOCUS_ON.value:
|
||||
return STATE_FOCUS
|
||||
return STATE_DIFFUSE
|
||||
|
@ -144,7 +143,7 @@ class DysonPureHotCoolLinkDevice(ClimateDevice):
|
|||
# Limit the target temperature into acceptable range.
|
||||
target_temp = min(self.max_temp, target_temp)
|
||||
target_temp = max(self.min_temp, target_temp)
|
||||
from libpurecoollink.const import HeatTarget, HeatMode
|
||||
from libpurecool.const import HeatTarget, HeatMode
|
||||
self._device.set_configuration(
|
||||
heat_target=HeatTarget.celsius(target_temp),
|
||||
heat_mode=HeatMode.HEAT_ON)
|
||||
|
@ -152,7 +151,7 @@ class DysonPureHotCoolLinkDevice(ClimateDevice):
|
|||
def set_fan_mode(self, fan_mode):
|
||||
"""Set new fan mode."""
|
||||
_LOGGER.debug("Set %s focus mode %s", self.name, fan_mode)
|
||||
from libpurecoollink.const import FocusMode
|
||||
from libpurecool.const import FocusMode
|
||||
if fan_mode == STATE_FOCUS:
|
||||
self._device.set_configuration(focus_mode=FocusMode.FOCUS_ON)
|
||||
elif fan_mode == STATE_DIFFUSE:
|
||||
|
@ -161,7 +160,7 @@ class DysonPureHotCoolLinkDevice(ClimateDevice):
|
|||
def set_operation_mode(self, operation_mode):
|
||||
"""Set operation mode."""
|
||||
_LOGGER.debug("Set %s heat mode %s", self.name, operation_mode)
|
||||
from libpurecoollink.const import HeatMode
|
||||
from libpurecool.const import HeatMode
|
||||
if operation_mode == STATE_HEAT:
|
||||
self._device.set_configuration(heat_mode=HeatMode.HEAT_ON)
|
||||
elif operation_mode == STATE_COOL:
|
||||
|
|
|
@ -7,65 +7,150 @@ import logging
|
|||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.fan import (
|
||||
DOMAIN, SUPPORT_OSCILLATE, SUPPORT_SET_SPEED, FanEntity)
|
||||
from homeassistant.const import CONF_ENTITY_ID
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
from homeassistant.components.fan import (
|
||||
SUPPORT_OSCILLATE, SUPPORT_SET_SPEED, FanEntity,
|
||||
SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH)
|
||||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
from . import DYSON_DEVICES
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CONF_NIGHT_MODE = 'night_mode'
|
||||
|
||||
ATTR_IS_NIGHT_MODE = 'is_night_mode'
|
||||
ATTR_IS_AUTO_MODE = 'is_auto_mode'
|
||||
ATTR_NIGHT_MODE = 'night_mode'
|
||||
ATTR_AUTO_MODE = 'auto_mode'
|
||||
ATTR_ANGLE_LOW = 'angle_low'
|
||||
ATTR_ANGLE_HIGH = 'angle_high'
|
||||
ATTR_FLOW_DIRECTION_FRONT = 'flow_direction_front'
|
||||
ATTR_TIMER = 'timer'
|
||||
ATTR_HEPA_FILTER = 'hepa_filter'
|
||||
ATTR_CARBON_FILTER = 'carbon_filter'
|
||||
ATTR_DYSON_SPEED = 'dyson_speed'
|
||||
ATTR_DYSON_SPEED_LIST = 'dyson_speed_list'
|
||||
|
||||
DEPENDENCIES = ['dyson']
|
||||
DYSON_DOMAIN = 'dyson'
|
||||
DYSON_FAN_DEVICES = 'dyson_fan_devices'
|
||||
|
||||
SERVICE_SET_NIGHT_MODE = 'dyson_set_night_mode'
|
||||
SERVICE_SET_NIGHT_MODE = 'set_night_mode'
|
||||
SERVICE_SET_AUTO_MODE = 'set_auto_mode'
|
||||
SERVICE_SET_ANGLE = 'set_angle'
|
||||
SERVICE_SET_FLOW_DIRECTION_FRONT = 'set_flow_direction_front'
|
||||
SERVICE_SET_TIMER = 'set_timer'
|
||||
SERVICE_SET_DYSON_SPEED = 'set_speed'
|
||||
|
||||
DYSON_SET_NIGHT_MODE_SCHEMA = vol.Schema({
|
||||
vol.Required(CONF_ENTITY_ID): cv.entity_id,
|
||||
vol.Required(CONF_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({
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_id,
|
||||
vol.Required(ATTR_AUTO_MODE): cv.boolean,
|
||||
})
|
||||
|
||||
SET_ANGLE_SCHEMA = vol.Schema({
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_id,
|
||||
vol.Required(ATTR_ANGLE_LOW): cv.positive_int,
|
||||
vol.Required(ATTR_ANGLE_HIGH): cv.positive_int
|
||||
})
|
||||
|
||||
SET_FLOW_DIRECTION_FRONT_SCHEMA = vol.Schema({
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_id,
|
||||
vol.Required(ATTR_FLOW_DIRECTION_FRONT): cv.boolean
|
||||
})
|
||||
|
||||
SET_TIMER_SCHEMA = vol.Schema({
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_id,
|
||||
vol.Required(ATTR_TIMER): cv.positive_int
|
||||
})
|
||||
|
||||
SET_DYSON_SPEED_SCHEMA = vol.Schema({
|
||||
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):
|
||||
"""Set up the Dyson fan components."""
|
||||
from libpurecoollink.dyson_pure_cool_link import DysonPureCoolLink
|
||||
from libpurecool.dyson_pure_cool_link import DysonPureCoolLink
|
||||
from libpurecool.dyson_pure_cool import DysonPureCool
|
||||
|
||||
if discovery_info is None:
|
||||
return
|
||||
|
||||
_LOGGER.debug("Creating new Dyson fans")
|
||||
if DYSON_FAN_DEVICES not in hass.data:
|
||||
hass.data[DYSON_FAN_DEVICES] = []
|
||||
|
||||
# Get Dyson Devices from parent component
|
||||
for device in [d for d in hass.data[DYSON_DEVICES] if
|
||||
isinstance(d, DysonPureCoolLink)]:
|
||||
dyson_entity = DysonPureCoolLinkDevice(hass, device)
|
||||
hass.data[DYSON_FAN_DEVICES].append(dyson_entity)
|
||||
has_purecool_devices = False
|
||||
device_serials = [device.serial for device in hass.data[DYSON_FAN_DEVICES]]
|
||||
for device in hass.data[DYSON_DEVICES]:
|
||||
if device.serial not in device_serials:
|
||||
if isinstance(device, DysonPureCool):
|
||||
has_purecool_devices = True
|
||||
dyson_entity = DysonPureCoolDevice(device)
|
||||
hass.data[DYSON_FAN_DEVICES].append(dyson_entity)
|
||||
elif isinstance(device, DysonPureCoolLink):
|
||||
dyson_entity = DysonPureCoolLinkDevice(hass, device)
|
||||
hass.data[DYSON_FAN_DEVICES].append(dyson_entity)
|
||||
|
||||
add_entities(hass.data[DYSON_FAN_DEVICES])
|
||||
|
||||
def service_handle(service):
|
||||
"""Handle the Dyson services."""
|
||||
entity_id = service.data.get(CONF_ENTITY_ID)
|
||||
night_mode = service.data.get(CONF_NIGHT_MODE)
|
||||
fan_device = next([fan for fan in hass.data[DYSON_FAN_DEVICES] if
|
||||
fan.entity_id == entity_id].__iter__(), None)
|
||||
entity_id = service.data[ATTR_ENTITY_ID]
|
||||
fan_device = next((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.night_mode(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(
|
||||
DOMAIN, SERVICE_SET_NIGHT_MODE, service_handle,
|
||||
DYSON_DOMAIN, SERVICE_SET_NIGHT_MODE, service_handle,
|
||||
schema=DYSON_SET_NIGHT_MODE_SCHEMA)
|
||||
if has_purecool_devices:
|
||||
hass.services.register(
|
||||
DYSON_DOMAIN, SERVICE_SET_AUTO_MODE, service_handle,
|
||||
schema=SET_AUTO_MODE_SCHEMA)
|
||||
|
||||
hass.services.register(
|
||||
DYSON_DOMAIN, SERVICE_SET_ANGLE, service_handle,
|
||||
schema=SET_ANGLE_SCHEMA)
|
||||
|
||||
hass.services.register(
|
||||
DYSON_DOMAIN, SERVICE_SET_FLOW_DIRECTION_FRONT, service_handle,
|
||||
schema=SET_FLOW_DIRECTION_FRONT_SCHEMA)
|
||||
|
||||
hass.services.register(
|
||||
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 DysonPureCoolLinkDevice(FanEntity):
|
||||
|
@ -84,7 +169,7 @@ class DysonPureCoolLinkDevice(FanEntity):
|
|||
|
||||
def on_message(self, message):
|
||||
"""Call when new messages received from the fan."""
|
||||
from libpurecoollink.dyson_pure_state import DysonPureCoolState
|
||||
from libpurecool.dyson_pure_state import DysonPureCoolState
|
||||
|
||||
if isinstance(message, DysonPureCoolState):
|
||||
_LOGGER.debug("Message received for fan device %s: %s", self.name,
|
||||
|
@ -103,7 +188,7 @@ class DysonPureCoolLinkDevice(FanEntity):
|
|||
|
||||
def set_speed(self, speed: str) -> None:
|
||||
"""Set the speed of the fan. Never called ??."""
|
||||
from libpurecoollink.const import FanSpeed, FanMode
|
||||
from libpurecool.const import FanSpeed, FanMode
|
||||
|
||||
_LOGGER.debug("Set fan speed to: %s", speed)
|
||||
|
||||
|
@ -116,7 +201,7 @@ class DysonPureCoolLinkDevice(FanEntity):
|
|||
|
||||
def turn_on(self, speed: str = None, **kwargs) -> None:
|
||||
"""Turn on the fan."""
|
||||
from libpurecoollink.const import FanSpeed, FanMode
|
||||
from libpurecool.const import FanSpeed, FanMode
|
||||
|
||||
_LOGGER.debug("Turn on fan %s with speed %s", self.name, speed)
|
||||
if speed:
|
||||
|
@ -132,14 +217,14 @@ class DysonPureCoolLinkDevice(FanEntity):
|
|||
|
||||
def turn_off(self, **kwargs) -> None:
|
||||
"""Turn off the fan."""
|
||||
from libpurecoollink.const import FanMode
|
||||
from libpurecool.const import FanMode
|
||||
|
||||
_LOGGER.debug("Turn off fan %s", self.name)
|
||||
self._device.set_configuration(fan_mode=FanMode.OFF)
|
||||
|
||||
def oscillate(self, oscillating: bool) -> None:
|
||||
"""Turn on/off oscillating."""
|
||||
from libpurecoollink.const import Oscillation
|
||||
from libpurecool.const import Oscillation
|
||||
|
||||
_LOGGER.debug("Turn oscillation %s for device %s", oscillating,
|
||||
self.name)
|
||||
|
@ -166,7 +251,7 @@ class DysonPureCoolLinkDevice(FanEntity):
|
|||
@property
|
||||
def speed(self) -> str:
|
||||
"""Return the current speed."""
|
||||
from libpurecoollink.const import FanSpeed
|
||||
from libpurecool.const import FanSpeed
|
||||
|
||||
if self._device.state:
|
||||
if self._device.state.speed == FanSpeed.FAN_SPEED_AUTO.value:
|
||||
|
@ -180,13 +265,13 @@ class DysonPureCoolLinkDevice(FanEntity):
|
|||
return None
|
||||
|
||||
@property
|
||||
def is_night_mode(self):
|
||||
def night_mode(self):
|
||||
"""Return Night mode."""
|
||||
return self._device.state.night_mode == "ON"
|
||||
|
||||
def night_mode(self, night_mode: bool) -> None:
|
||||
def set_night_mode(self, night_mode: bool) -> None:
|
||||
"""Turn fan in night mode."""
|
||||
from libpurecoollink.const import NightMode
|
||||
from libpurecool.const import NightMode
|
||||
|
||||
_LOGGER.debug("Set %s night mode %s", self.name, night_mode)
|
||||
if night_mode:
|
||||
|
@ -195,13 +280,13 @@ class DysonPureCoolLinkDevice(FanEntity):
|
|||
self._device.set_configuration(night_mode=NightMode.NIGHT_MODE_OFF)
|
||||
|
||||
@property
|
||||
def is_auto_mode(self):
|
||||
def auto_mode(self):
|
||||
"""Return auto mode."""
|
||||
return self._device.state.fan_mode == "AUTO"
|
||||
|
||||
def auto_mode(self, auto_mode: bool) -> None:
|
||||
def set_auto_mode(self, auto_mode: bool) -> None:
|
||||
"""Turn fan in auto mode."""
|
||||
from libpurecoollink.const import FanMode
|
||||
from libpurecool.const import FanMode
|
||||
|
||||
_LOGGER.debug("Set %s auto mode %s", self.name, auto_mode)
|
||||
if auto_mode:
|
||||
|
@ -212,7 +297,7 @@ class DysonPureCoolLinkDevice(FanEntity):
|
|||
@property
|
||||
def speed_list(self) -> list:
|
||||
"""Get the list of available speeds."""
|
||||
from libpurecoollink.const import FanSpeed
|
||||
from libpurecool.const import FanSpeed
|
||||
|
||||
supported_speeds = [
|
||||
FanSpeed.FAN_SPEED_AUTO.value,
|
||||
|
@ -239,6 +324,256 @@ class DysonPureCoolLinkDevice(FanEntity):
|
|||
def device_state_attributes(self) -> dict:
|
||||
"""Return optional state attributes."""
|
||||
return {
|
||||
ATTR_IS_NIGHT_MODE: self.is_night_mode,
|
||||
ATTR_IS_AUTO_MODE: self.is_auto_mode
|
||||
ATTR_NIGHT_MODE: self.night_mode,
|
||||
ATTR_AUTO_MODE: self.auto_mode
|
||||
}
|
||||
|
||||
|
||||
class DysonPureCoolDevice(FanEntity):
|
||||
"""Representation of a Dyson Purecool (TP04/DP04) fan."""
|
||||
|
||||
def __init__(self, device):
|
||||
"""Initialize the fan."""
|
||||
self._device = device
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call when entity is added to hass."""
|
||||
self.hass.async_add_executor_job(
|
||||
self._device.add_message_listener, self.on_message)
|
||||
|
||||
def on_message(self, message):
|
||||
"""Call when new messages received from the fan."""
|
||||
from libpurecool.dyson_pure_state_v2 import DysonPureCoolV2State
|
||||
|
||||
if isinstance(message, DysonPureCoolV2State):
|
||||
_LOGGER.debug("Message received for fan device %s: %s", self.name,
|
||||
message)
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""No polling needed."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the display name of this fan."""
|
||||
return self._device.name
|
||||
|
||||
def turn_on(self, speed: str = None, **kwargs) -> None:
|
||||
"""Turn on the fan."""
|
||||
_LOGGER.debug("Turn on fan %s", self.name)
|
||||
|
||||
if speed is not None:
|
||||
self.set_speed(speed)
|
||||
else:
|
||||
self._device.turn_on()
|
||||
|
||||
def set_speed(self, speed: str) -> None:
|
||||
"""Set the speed of the fan."""
|
||||
from libpurecool.const import FanSpeed
|
||||
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):
|
||||
"""Turn off the fan."""
|
||||
_LOGGER.debug("Turn off fan %s", self.name)
|
||||
self._device.turn_off()
|
||||
|
||||
def set_dyson_speed(self, speed: str = None) -> None:
|
||||
"""Set the exact speed of the purecool fan."""
|
||||
from libpurecool.const import FanSpeed
|
||||
|
||||
_LOGGER.debug("Set exact speed for fan %s", self.name)
|
||||
|
||||
fan_speed = FanSpeed('{0:04d}'.format(int(speed)))
|
||||
self._device.set_fan_speed(fan_speed)
|
||||
|
||||
def oscillate(self, oscillating: bool) -> None:
|
||||
"""Turn on/off oscillating."""
|
||||
_LOGGER.debug("Turn oscillation %s for device %s", oscillating,
|
||||
self.name)
|
||||
|
||||
if oscillating:
|
||||
self._device.enable_oscillation()
|
||||
else:
|
||||
self._device.disable_oscillation()
|
||||
|
||||
def set_night_mode(self, night_mode: bool) -> None:
|
||||
"""Turn on/off night mode."""
|
||||
_LOGGER.debug("Turn night mode %s for device %s", night_mode,
|
||||
self.name)
|
||||
|
||||
if night_mode:
|
||||
self._device.enable_night_mode()
|
||||
else:
|
||||
self._device.disable_night_mode()
|
||||
|
||||
def set_auto_mode(self, auto_mode: bool) -> None:
|
||||
"""Turn auto mode on/off."""
|
||||
_LOGGER.debug("Turn auto mode %s for device %s", auto_mode,
|
||||
self.name)
|
||||
if auto_mode:
|
||||
self._device.enable_auto_mode()
|
||||
else:
|
||||
self._device.disable_auto_mode()
|
||||
|
||||
def set_angle(self, angle_low: int, angle_high: int) -> None:
|
||||
"""Set device angle."""
|
||||
_LOGGER.debug("set low %s and high angle %s for device %s",
|
||||
angle_low, angle_high, self.name)
|
||||
self._device.enable_oscillation(angle_low, angle_high)
|
||||
|
||||
def set_flow_direction_front(self,
|
||||
flow_direction_front: bool) -> None:
|
||||
"""Set frontal airflow direction."""
|
||||
_LOGGER.debug("Set frontal flow direction to %s for device %s",
|
||||
flow_direction_front,
|
||||
self.name)
|
||||
|
||||
if flow_direction_front:
|
||||
self._device.enable_frontal_direction()
|
||||
else:
|
||||
self._device.disable_frontal_direction()
|
||||
|
||||
def set_timer(self, timer) -> None:
|
||||
"""Set timer."""
|
||||
_LOGGER.debug("Set timer to %s for device %s", timer,
|
||||
self.name)
|
||||
|
||||
if timer == 0:
|
||||
self._device.disable_sleep_timer()
|
||||
else:
|
||||
self._device.enable_sleep_timer(timer)
|
||||
|
||||
@property
|
||||
def oscillating(self):
|
||||
"""Return the oscillation state."""
|
||||
return self._device.state and self._device.state.oscillation == "OION"
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if the entity is on."""
|
||||
if self._device.state:
|
||||
return self._device.state.fan_power == "ON"
|
||||
|
||||
@property
|
||||
def speed(self):
|
||||
"""Return the current speed."""
|
||||
from libpurecool.const import FanSpeed
|
||||
|
||||
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}
|
||||
|
||||
return speed_map[self._device.state.speed]
|
||||
|
||||
@property
|
||||
def dyson_speed(self):
|
||||
"""Return the current speed."""
|
||||
from libpurecool.const import FanSpeed
|
||||
|
||||
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
|
||||
def night_mode(self):
|
||||
"""Return Night mode."""
|
||||
return self._device.state.night_mode == "ON"
|
||||
|
||||
@property
|
||||
def auto_mode(self):
|
||||
"""Return Auto mode."""
|
||||
return self._device.state.auto_mode == "ON"
|
||||
|
||||
@property
|
||||
def angle_low(self):
|
||||
"""Return angle high."""
|
||||
return int(self._device.state.oscillation_angle_low)
|
||||
|
||||
@property
|
||||
def angle_high(self):
|
||||
"""Return angle low."""
|
||||
return int(self._device.state.oscillation_angle_high)
|
||||
|
||||
@property
|
||||
def flow_direction_front(self):
|
||||
"""Return frontal flow direction."""
|
||||
return self._device.state.front_direction == 'ON'
|
||||
|
||||
@property
|
||||
def timer(self):
|
||||
"""Return timer."""
|
||||
return self._device.state.sleep_timer
|
||||
|
||||
@property
|
||||
def hepa_filter(self):
|
||||
"""Return the HEPA filter state."""
|
||||
return int(self._device.state.hepa_filter_state)
|
||||
|
||||
@property
|
||||
def carbon_filter(self):
|
||||
"""Return the 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."""
|
||||
from libpurecool.const import FanSpeed
|
||||
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 device_serial(self):
|
||||
"""Return fan's serial number."""
|
||||
return self._device.serial
|
||||
|
||||
@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_ANGLE_LOW: self.angle_low,
|
||||
ATTR_ANGLE_HIGH: self.angle_high,
|
||||
ATTR_FLOW_DIRECTION_FRONT: self.flow_direction_front,
|
||||
ATTR_TIMER: self.timer,
|
||||
ATTR_HEPA_FILTER: self.hepa_filter,
|
||||
ATTR_CARBON_FILTER: self.carbon_filter,
|
||||
ATTR_DYSON_SPEED: self.dyson_speed,
|
||||
ATTR_DYSON_SPEED_LIST: self.dyson_speed_list
|
||||
}
|
||||
|
|
|
@ -37,9 +37,12 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||
devices = []
|
||||
unit = hass.config.units.temperature_unit
|
||||
# Get Dyson Devices from parent component
|
||||
from libpurecoollink.dyson_pure_cool_link import DysonPureCoolLink
|
||||
for device in [d for d in hass.data[DYSON_DEVICES] if
|
||||
isinstance(d, DysonPureCoolLink)]:
|
||||
from libpurecool.dyson_pure_cool import DysonPureCool
|
||||
from libpurecool.dyson_pure_cool_link import DysonPureCoolLink
|
||||
|
||||
for device in [d for d in hass.data[DYSON_DEVICES]
|
||||
if isinstance(d, DysonPureCoolLink) and
|
||||
not isinstance(d, DysonPureCool)]:
|
||||
devices.append(DysonFilterLifeSensor(device))
|
||||
devices.append(DysonDustSensor(device))
|
||||
devices.append(DysonHumiditySensor(device))
|
||||
|
|
64
homeassistant/components/dyson/services.yaml
Normal file
64
homeassistant/components/dyson/services.yaml
Normal file
|
@ -0,0 +1,64 @@
|
|||
# Describes the format for available fan services
|
||||
|
||||
set_night_mode:
|
||||
description: Set the fan in night mode.
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of the entities to enable/disable night mode
|
||||
example: 'fan.living_room'
|
||||
night_mode:
|
||||
description: Night mode status
|
||||
example: true
|
||||
|
||||
set_auto_mode:
|
||||
description: Set the fan in auto mode.
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of the entities to enable/disable auto mode
|
||||
example: 'fan.living_room'
|
||||
auto_mode:
|
||||
description: Auto mode status
|
||||
example: true
|
||||
|
||||
set_angle:
|
||||
description: Set the oscillation angle of the selected fan(s).
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of the entities for which to set the angle
|
||||
example: 'fan.living_room'
|
||||
angle_low:
|
||||
description: The angle at which the oscillation should start
|
||||
example: 1
|
||||
angle_high:
|
||||
description: The angle at which the oscillation should end
|
||||
example: 255
|
||||
|
||||
flow_direction_front:
|
||||
description: Set the fan flow direction.
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of the entities to set frontal flow direction for
|
||||
example: 'fan.living_room'
|
||||
flow_direction_front:
|
||||
description: Frontal flow direction
|
||||
example: true
|
||||
|
||||
set_timer:
|
||||
description: Set the sleep timer.
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of the entities to set the sleep timer for
|
||||
example: 'fan.living_room'
|
||||
timer:
|
||||
description: The value in minutes to set the timer to, 0 to disable it
|
||||
example: 30
|
||||
|
||||
set_speed:
|
||||
description: Set the exact speed of the fan.
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of the entities to set the speed for
|
||||
example: 'fan.living_room'
|
||||
timer:
|
||||
description: Speed
|
||||
example: 1
|
|
@ -31,7 +31,7 @@ SUPPORT_DYSON = SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_PAUSE | \
|
|||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Dyson 360 Eye robot vacuum platform."""
|
||||
from libpurecoollink.dyson_360_eye import Dyson360Eye
|
||||
from libpurecool.dyson_360_eye import Dyson360Eye
|
||||
|
||||
_LOGGER.debug("Creating new Dyson 360 Eye robot vacuum")
|
||||
if DYSON_360_EYE_DEVICES not in hass.data:
|
||||
|
@ -81,7 +81,7 @@ class Dyson360EyeDevice(VacuumDevice):
|
|||
@property
|
||||
def status(self):
|
||||
"""Return the status of the vacuum cleaner."""
|
||||
from libpurecoollink.const import Dyson360EyeMode
|
||||
from libpurecool.const import Dyson360EyeMode
|
||||
dyson_labels = {
|
||||
Dyson360EyeMode.INACTIVE_CHARGING: "Stopped - Charging",
|
||||
Dyson360EyeMode.INACTIVE_CHARGED: "Stopped - Charged",
|
||||
|
@ -106,7 +106,7 @@ class Dyson360EyeDevice(VacuumDevice):
|
|||
@property
|
||||
def fan_speed(self):
|
||||
"""Return the fan speed of the vacuum cleaner."""
|
||||
from libpurecoollink.const import PowerMode
|
||||
from libpurecool.const import PowerMode
|
||||
speed_labels = {
|
||||
PowerMode.MAX: "Max",
|
||||
PowerMode.QUIET: "Quiet"
|
||||
|
@ -128,7 +128,7 @@ class Dyson360EyeDevice(VacuumDevice):
|
|||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return True if entity is on."""
|
||||
from libpurecoollink.const import Dyson360EyeMode
|
||||
from libpurecool.const import Dyson360EyeMode
|
||||
|
||||
return self._device.state.state in [
|
||||
Dyson360EyeMode.FULL_CLEAN_INITIATED,
|
||||
|
@ -149,7 +149,7 @@ class Dyson360EyeDevice(VacuumDevice):
|
|||
@property
|
||||
def battery_icon(self):
|
||||
"""Return the battery icon for the vacuum cleaner."""
|
||||
from libpurecoollink.const import Dyson360EyeMode
|
||||
from libpurecool.const import Dyson360EyeMode
|
||||
|
||||
charging = self._device.state.state in [
|
||||
Dyson360EyeMode.INACTIVE_CHARGING]
|
||||
|
@ -158,7 +158,7 @@ class Dyson360EyeDevice(VacuumDevice):
|
|||
|
||||
def turn_on(self, **kwargs):
|
||||
"""Turn the vacuum on."""
|
||||
from libpurecoollink.const import Dyson360EyeMode
|
||||
from libpurecool.const import Dyson360EyeMode
|
||||
|
||||
_LOGGER.debug("Turn on device %s", self.name)
|
||||
if self._device.state.state in [Dyson360EyeMode.FULL_CLEAN_PAUSED]:
|
||||
|
@ -178,7 +178,7 @@ class Dyson360EyeDevice(VacuumDevice):
|
|||
|
||||
def set_fan_speed(self, fan_speed, **kwargs):
|
||||
"""Set fan speed."""
|
||||
from libpurecoollink.const import PowerMode
|
||||
from libpurecool.const import PowerMode
|
||||
|
||||
_LOGGER.debug("Set fan speed %s on device %s", fan_speed, self.name)
|
||||
power_modes = {
|
||||
|
@ -189,7 +189,7 @@ class Dyson360EyeDevice(VacuumDevice):
|
|||
|
||||
def start_pause(self, **kwargs):
|
||||
"""Start, pause or resume the cleaning task."""
|
||||
from libpurecoollink.const import Dyson360EyeMode
|
||||
from libpurecool.const import Dyson360EyeMode
|
||||
|
||||
if self._device.state.state in [Dyson360EyeMode.FULL_CLEAN_PAUSED]:
|
||||
_LOGGER.debug("Resume device %s", self.name)
|
||||
|
|
|
@ -54,16 +54,6 @@ set_direction:
|
|||
description: The direction to rotate. Either 'forward' or 'reverse'
|
||||
example: 'forward'
|
||||
|
||||
dyson_set_night_mode:
|
||||
description: Set the fan in night mode.
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name(s) of the entities to enable/disable night mode
|
||||
example: 'fan.living_room'
|
||||
night_mode:
|
||||
description: Night mode status
|
||||
example: true
|
||||
|
||||
xiaomi_miio_set_buzzer_on:
|
||||
description: Turn the buzzer on.
|
||||
fields:
|
||||
|
|
|
@ -628,7 +628,7 @@ konnected==0.1.5
|
|||
lakeside==0.12
|
||||
|
||||
# homeassistant.components.dyson
|
||||
libpurecoollink==0.4.2
|
||||
libpurecool==0.5.0
|
||||
|
||||
# homeassistant.components.foscam.camera
|
||||
libpyfoscam==1.0
|
||||
|
|
|
@ -145,7 +145,7 @@ influxdb==5.2.0
|
|||
jsonpath==0.75
|
||||
|
||||
# homeassistant.components.dyson
|
||||
libpurecoollink==0.4.2
|
||||
libpurecool==0.5.0
|
||||
|
||||
# homeassistant.components.soundtouch.media_player
|
||||
libsoundtouch==0.7.2
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Generate an updated requirements_all.txt."""
|
||||
import fnmatch
|
||||
import importlib
|
||||
import os
|
||||
import pkgutil
|
||||
import re
|
||||
import sys
|
||||
import fnmatch
|
||||
|
||||
COMMENT_REQUIREMENTS = (
|
||||
'Adafruit-DHT',
|
||||
|
@ -74,7 +74,7 @@ TEST_REQUIREMENTS = (
|
|||
'homematicip',
|
||||
'influxdb',
|
||||
'jsonpath',
|
||||
'libpurecoollink',
|
||||
'libpurecool',
|
||||
'libsoundtouch',
|
||||
'luftdaten',
|
||||
'mbddns',
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
from libpurecoollink.const import (FocusMode, HeatMode, HeatState, HeatTarget,
|
||||
TiltState)
|
||||
from libpurecoollink.dyson_pure_state import DysonPureHotCoolState
|
||||
from libpurecoollink.dyson_pure_hotcool_link import DysonPureHotCoolLink
|
||||
from homeassistant.components.dyson import climate as dyson
|
||||
from libpurecool.const import (FocusMode, HeatMode,
|
||||
HeatState, HeatTarget, TiltState)
|
||||
from libpurecool.dyson_pure_hotcool_link import DysonPureHotCoolLink
|
||||
from libpurecool.dyson_pure_state import DysonPureHotCoolState
|
||||
|
||||
from homeassistant.components import dyson as dyson_parent
|
||||
from homeassistant.components.dyson import climate as dyson
|
||||
from homeassistant.const import TEMP_CELSIUS, ATTR_TEMPERATURE
|
||||
from homeassistant.setup import setup_component
|
||||
from tests.common import get_test_home_assistant
|
||||
|
@ -110,9 +111,9 @@ class DysonTest(unittest.TestCase):
|
|||
"""Stop everything that was started."""
|
||||
self.hass.stop()
|
||||
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.devices',
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_device_heat_on(), _get_device_cool()])
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True)
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
def test_setup_component_with_parent_discovery(self, mocked_login,
|
||||
mocked_devices):
|
||||
"""Test setup_component using discovery."""
|
||||
|
|
|
@ -1,16 +1,28 @@
|
|||
"""Test the Dyson fan component."""
|
||||
import json
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
from homeassistant.setup import setup_component
|
||||
import asynctest
|
||||
from libpurecool.const import FanSpeed, FanMode, NightMode, Oscillation
|
||||
from libpurecool.dyson_pure_cool import DysonPureCool
|
||||
from libpurecool.dyson_pure_cool_link import DysonPureCoolLink
|
||||
from libpurecool.dyson_pure_state import DysonPureCoolState
|
||||
from libpurecool.dyson_pure_state_v2 import DysonPureCoolV2State
|
||||
|
||||
import homeassistant.components.dyson.fan as dyson
|
||||
from homeassistant.components import dyson as dyson_parent
|
||||
from homeassistant.components.dyson import DYSON_DEVICES, fan as dyson
|
||||
from homeassistant.components.fan import (ATTR_SPEED, ATTR_SPEED_LIST,
|
||||
ATTR_OSCILLATING)
|
||||
from homeassistant.components.dyson import DYSON_DEVICES
|
||||
from homeassistant.components.fan import (DOMAIN, ATTR_SPEED, ATTR_SPEED_LIST,
|
||||
ATTR_OSCILLATING, SPEED_LOW,
|
||||
SPEED_MEDIUM, SPEED_HIGH,
|
||||
SERVICE_OSCILLATE)
|
||||
from homeassistant.const import (SERVICE_TURN_ON,
|
||||
SERVICE_TURN_OFF,
|
||||
ATTR_ENTITY_ID)
|
||||
from homeassistant.helpers import discovery
|
||||
from homeassistant.setup import setup_component, async_setup_component
|
||||
from tests.common import get_test_home_assistant
|
||||
from libpurecoollink.const import FanSpeed, FanMode, NightMode, Oscillation
|
||||
from libpurecoollink.dyson_pure_state import DysonPureCoolState
|
||||
from libpurecoollink.dyson_pure_cool_link import DysonPureCoolLink
|
||||
|
||||
|
||||
class MockDysonState(DysonPureCoolState):
|
||||
|
@ -21,6 +33,58 @@ class MockDysonState(DysonPureCoolState):
|
|||
pass
|
||||
|
||||
|
||||
def _get_dyson_purecool_device():
|
||||
"""Return a valid device as provided by the Dyson web services."""
|
||||
device = mock.Mock(spec=DysonPureCool)
|
||||
device.serial = "XX-XXXXX-XX"
|
||||
device.name = "Living room"
|
||||
device.connect = mock.Mock(return_value=True)
|
||||
device.auto_connect = mock.Mock(return_value=True)
|
||||
device.state = mock.Mock()
|
||||
device.state.oscillation = "OION"
|
||||
device.state.fan_power = "ON"
|
||||
device.state.speed = FanSpeed.FAN_SPEED_AUTO.value
|
||||
device.state.night_mode = "OFF"
|
||||
device.state.auto_mode = "ON"
|
||||
device.state.oscillation_angle_low = "0090"
|
||||
device.state.oscillation_angle_high = "0180"
|
||||
device.state.front_direction = "ON"
|
||||
device.state.sleep_timer = 60
|
||||
device.state.hepa_filter_state = "0090"
|
||||
device.state.carbon_filter_state = "0080"
|
||||
return device
|
||||
|
||||
|
||||
def _get_supported_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),
|
||||
]
|
||||
|
||||
|
||||
def _get_config():
|
||||
"""Return a config dictionary."""
|
||||
return {dyson_parent.DOMAIN: {
|
||||
dyson_parent.CONF_USERNAME: "email",
|
||||
dyson_parent.CONF_PASSWORD: "password",
|
||||
dyson_parent.CONF_LANGUAGE: "GB",
|
||||
dyson_parent.CONF_DEVICES: [
|
||||
{
|
||||
"device_id": "XX-XXXXX-XX",
|
||||
"device_ip": "192.168.0.1"
|
||||
}
|
||||
]
|
||||
}}
|
||||
|
||||
|
||||
def _get_device_with_no_state():
|
||||
"""Return a device with no state."""
|
||||
device = mock.Mock()
|
||||
|
@ -64,8 +128,8 @@ def _get_device_on():
|
|||
return device
|
||||
|
||||
|
||||
class DysonTest(unittest.TestCase):
|
||||
"""Dyson Sensor component test class."""
|
||||
class DysonSetupTest(unittest.TestCase):
|
||||
"""Dyson component setup tests."""
|
||||
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Set up things to be run when tests are started."""
|
||||
|
@ -79,24 +143,39 @@ class DysonTest(unittest.TestCase):
|
|||
"""Test setup component with no devices."""
|
||||
self.hass.data[dyson.DYSON_DEVICES] = []
|
||||
add_entities = mock.MagicMock()
|
||||
dyson.setup_platform(self.hass, None, add_entities)
|
||||
dyson.setup_platform(self.hass, None, add_entities, mock.Mock())
|
||||
add_entities.assert_called_with([])
|
||||
|
||||
def test_setup_component(self):
|
||||
"""Test setup component with devices."""
|
||||
def _add_device(devices):
|
||||
assert len(devices) == 1
|
||||
assert len(devices) == 2
|
||||
assert devices[0].name == "Device_name"
|
||||
|
||||
device_fan = _get_device_on()
|
||||
device_purecool_fan = _get_dyson_purecool_device()
|
||||
device_non_fan = _get_device_off()
|
||||
|
||||
self.hass.data[dyson.DYSON_DEVICES] = [device_fan, device_non_fan]
|
||||
self.hass.data[dyson.DYSON_DEVICES] = [device_fan,
|
||||
device_purecool_fan,
|
||||
device_non_fan]
|
||||
dyson.setup_platform(self.hass, None, _add_device)
|
||||
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.devices',
|
||||
|
||||
class DysonTest(unittest.TestCase):
|
||||
"""Dyson fan component test class."""
|
||||
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Set up things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
|
||||
def tearDown(self): # pylint: disable=invalid-name
|
||||
"""Stop everything that was started."""
|
||||
self.hass.stop()
|
||||
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_device_on()])
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True)
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
def test_get_state_attributes(self, mocked_login, mocked_devices):
|
||||
"""Test async added to hass."""
|
||||
setup_component(self.hass, dyson_parent.DOMAIN, {
|
||||
|
@ -108,18 +187,18 @@ class DysonTest(unittest.TestCase):
|
|||
})
|
||||
self.hass.block_till_done()
|
||||
state = self.hass.states.get("{}.{}".format(
|
||||
dyson.DOMAIN,
|
||||
DOMAIN,
|
||||
mocked_devices.return_value[0].name))
|
||||
|
||||
assert dyson.ATTR_IS_NIGHT_MODE in state.attributes
|
||||
assert dyson.ATTR_IS_AUTO_MODE in state.attributes
|
||||
assert dyson.ATTR_NIGHT_MODE in state.attributes
|
||||
assert dyson.ATTR_AUTO_MODE in state.attributes
|
||||
assert ATTR_SPEED in state.attributes
|
||||
assert ATTR_SPEED_LIST in state.attributes
|
||||
assert ATTR_OSCILLATING in state.attributes
|
||||
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.devices',
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_device_on()])
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True)
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
def test_async_added_to_hass(self, mocked_login, mocked_devices):
|
||||
"""Test async added to hass."""
|
||||
setup_component(self.hass, dyson_parent.DOMAIN, {
|
||||
|
@ -161,11 +240,11 @@ class DysonTest(unittest.TestCase):
|
|||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
assert not component.should_poll
|
||||
component.night_mode(True)
|
||||
component.set_night_mode(True)
|
||||
set_config = device.set_configuration
|
||||
set_config.assert_called_with(night_mode=NightMode.NIGHT_MODE_ON)
|
||||
|
||||
component.night_mode(False)
|
||||
component.set_night_mode(False)
|
||||
set_config = device.set_configuration
|
||||
set_config.assert_called_with(night_mode=NightMode.NIGHT_MODE_OFF)
|
||||
|
||||
|
@ -173,22 +252,22 @@ class DysonTest(unittest.TestCase):
|
|||
"""Test night mode."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
assert not component.is_night_mode
|
||||
assert not component.night_mode
|
||||
|
||||
device = _get_device_off()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
assert component.is_night_mode
|
||||
assert component.night_mode
|
||||
|
||||
def test_dyson_turn_auto_mode(self):
|
||||
"""Test turn on/off fan with auto mode."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
assert not component.should_poll
|
||||
component.auto_mode(True)
|
||||
component.set_auto_mode(True)
|
||||
set_config = device.set_configuration
|
||||
set_config.assert_called_with(fan_mode=FanMode.AUTO)
|
||||
|
||||
component.auto_mode(False)
|
||||
component.set_auto_mode(False)
|
||||
set_config = device.set_configuration
|
||||
set_config.assert_called_with(fan_mode=FanMode.FAN)
|
||||
|
||||
|
@ -196,11 +275,11 @@ class DysonTest(unittest.TestCase):
|
|||
"""Test auto mode."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
assert not component.is_auto_mode
|
||||
assert not component.auto_mode
|
||||
|
||||
device = _get_device_auto()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
assert component.is_auto_mode
|
||||
assert component.auto_mode
|
||||
|
||||
def test_dyson_turn_on_speed(self):
|
||||
"""Test turn on fan with specified speed."""
|
||||
|
@ -320,14 +399,355 @@ class DysonTest(unittest.TestCase):
|
|||
self.hass.data[DYSON_DEVICES] = []
|
||||
dyson_device.entity_id = 'fan.living_room'
|
||||
self.hass.data[dyson.DYSON_FAN_DEVICES] = [dyson_device]
|
||||
dyson.setup_platform(self.hass, None, mock.MagicMock())
|
||||
dyson.setup_platform(self.hass, None,
|
||||
mock.MagicMock(), mock.MagicMock())
|
||||
|
||||
self.hass.services.call(dyson.DOMAIN, dyson.SERVICE_SET_NIGHT_MODE,
|
||||
self.hass.services.call(dyson.DYSON_DOMAIN,
|
||||
dyson.SERVICE_SET_NIGHT_MODE,
|
||||
{"entity_id": "fan.bed_room",
|
||||
"night_mode": True}, True)
|
||||
assert not dyson_device.night_mode.called
|
||||
assert dyson_device.set_night_mode.call_count == 0
|
||||
|
||||
self.hass.services.call(dyson.DOMAIN, dyson.SERVICE_SET_NIGHT_MODE,
|
||||
self.hass.services.call(dyson.DYSON_DOMAIN,
|
||||
dyson.SERVICE_SET_NIGHT_MODE,
|
||||
{"entity_id": "fan.living_room",
|
||||
"night_mode": True}, True)
|
||||
dyson_device.night_mode.assert_called_with(True)
|
||||
dyson_device.set_night_mode.assert_called_with(True)
|
||||
|
||||
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_purecool_device()])
|
||||
async def test_purecool_turn_on(devices, login, hass):
|
||||
"""Test turn on."""
|
||||
device = devices.return_value[0]
|
||||
await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config())
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(DOMAIN, SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "fan.bed_room"}, True)
|
||||
assert device.turn_on.call_count == 0
|
||||
|
||||
await hass.services.async_call(DOMAIN, SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "fan.living_room"}, True)
|
||||
assert device.turn_on.call_count == 1
|
||||
|
||||
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_purecool_device()])
|
||||
async def test_purecool_set_speed(devices, login, hass):
|
||||
"""Test set speed."""
|
||||
device = devices.return_value[0]
|
||||
await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config())
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(DOMAIN, SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "fan.bed_room",
|
||||
ATTR_SPEED: SPEED_LOW}, True)
|
||||
assert device.set_fan_speed.call_count == 0
|
||||
|
||||
await hass.services.async_call(DOMAIN, SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "fan.living_room",
|
||||
ATTR_SPEED: SPEED_LOW}, True)
|
||||
device.set_fan_speed.assert_called_with(FanSpeed.FAN_SPEED_4)
|
||||
|
||||
await hass.services.async_call(DOMAIN, SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "fan.living_room",
|
||||
ATTR_SPEED: SPEED_MEDIUM}, True)
|
||||
device.set_fan_speed.assert_called_with(FanSpeed.FAN_SPEED_7)
|
||||
|
||||
await hass.services.async_call(DOMAIN, SERVICE_TURN_ON,
|
||||
{ATTR_ENTITY_ID: "fan.living_room",
|
||||
ATTR_SPEED: SPEED_HIGH}, True)
|
||||
device.set_fan_speed.assert_called_with(FanSpeed.FAN_SPEED_10)
|
||||
|
||||
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_purecool_device()])
|
||||
async def test_purecool_turn_off(devices, login, hass):
|
||||
"""Test turn off."""
|
||||
device = devices.return_value[0]
|
||||
await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config())
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(DOMAIN, SERVICE_TURN_OFF,
|
||||
{ATTR_ENTITY_ID: "fan.bed_room"}, True)
|
||||
assert device.turn_off.call_count == 0
|
||||
|
||||
await hass.services.async_call(DOMAIN, SERVICE_TURN_OFF,
|
||||
{ATTR_ENTITY_ID: "fan.living_room"}, True)
|
||||
assert device.turn_off.call_count == 1
|
||||
|
||||
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_purecool_device()])
|
||||
async def test_purecool_set_dyson_speed(devices, login, hass):
|
||||
"""Test set exact dyson speed."""
|
||||
device = devices.return_value[0]
|
||||
await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config())
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(dyson.DYSON_DOMAIN,
|
||||
dyson.SERVICE_SET_DYSON_SPEED,
|
||||
{ATTR_ENTITY_ID: "fan.bed_room",
|
||||
dyson.ATTR_DYSON_SPEED:
|
||||
int(FanSpeed.FAN_SPEED_2.value)},
|
||||
True)
|
||||
assert device.set_fan_speed.call_count == 0
|
||||
|
||||
await hass.services.async_call(dyson.DYSON_DOMAIN,
|
||||
dyson.SERVICE_SET_DYSON_SPEED,
|
||||
{ATTR_ENTITY_ID: "fan.living_room",
|
||||
dyson.ATTR_DYSON_SPEED:
|
||||
int(FanSpeed.FAN_SPEED_2.value)},
|
||||
True)
|
||||
device.set_fan_speed.assert_called_with(FanSpeed.FAN_SPEED_2)
|
||||
|
||||
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_purecool_device()])
|
||||
async def test_purecool_oscillate(devices, login, hass):
|
||||
"""Test set oscillation."""
|
||||
device = devices.return_value[0]
|
||||
await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config())
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(DOMAIN, SERVICE_OSCILLATE,
|
||||
{ATTR_ENTITY_ID: "fan.bed_room",
|
||||
ATTR_OSCILLATING: True}, True)
|
||||
assert device.enable_oscillation.call_count == 0
|
||||
|
||||
await hass.services.async_call(DOMAIN, SERVICE_OSCILLATE,
|
||||
{ATTR_ENTITY_ID: "fan.living_room",
|
||||
ATTR_OSCILLATING: True}, True)
|
||||
assert device.enable_oscillation.call_count == 1
|
||||
|
||||
await hass.services.async_call(DOMAIN, SERVICE_OSCILLATE,
|
||||
{ATTR_ENTITY_ID: "fan.living_room",
|
||||
ATTR_OSCILLATING: False}, True)
|
||||
assert device.disable_oscillation.call_count == 1
|
||||
|
||||
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_purecool_device()])
|
||||
async def test_purecool_set_night_mode(devices, login, hass):
|
||||
"""Test set night mode."""
|
||||
device = devices.return_value[0]
|
||||
await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config())
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(dyson.DYSON_DOMAIN,
|
||||
dyson.SERVICE_SET_NIGHT_MODE,
|
||||
{"entity_id": "fan.bed_room",
|
||||
"night_mode": True}, True)
|
||||
assert device.enable_night_mode.call_count == 0
|
||||
|
||||
await hass.services.async_call(dyson.DYSON_DOMAIN,
|
||||
dyson.SERVICE_SET_NIGHT_MODE,
|
||||
{"entity_id": "fan.living_room",
|
||||
"night_mode": True}, True)
|
||||
assert device.enable_night_mode.call_count == 1
|
||||
|
||||
await hass.services.async_call(dyson.DYSON_DOMAIN,
|
||||
dyson.SERVICE_SET_NIGHT_MODE,
|
||||
{"entity_id": "fan.living_room",
|
||||
"night_mode": False}, True)
|
||||
assert device.disable_night_mode.call_count == 1
|
||||
|
||||
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_purecool_device()])
|
||||
async def test_purecool_set_auto_mode(devices, login, hass):
|
||||
"""Test set auto mode."""
|
||||
device = devices.return_value[0]
|
||||
await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config())
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(dyson.DYSON_DOMAIN,
|
||||
dyson.SERVICE_SET_AUTO_MODE,
|
||||
{ATTR_ENTITY_ID: "fan.bed_room",
|
||||
dyson.ATTR_AUTO_MODE: True}, True)
|
||||
assert device.enable_auto_mode.call_count == 0
|
||||
|
||||
await hass.services.async_call(dyson.DYSON_DOMAIN,
|
||||
dyson.SERVICE_SET_AUTO_MODE,
|
||||
{ATTR_ENTITY_ID: "fan.living_room",
|
||||
dyson.ATTR_AUTO_MODE: True}, True)
|
||||
assert device.enable_auto_mode.call_count == 1
|
||||
|
||||
await hass.services.async_call(dyson.DYSON_DOMAIN,
|
||||
dyson.SERVICE_SET_AUTO_MODE,
|
||||
{ATTR_ENTITY_ID: "fan.living_room",
|
||||
dyson.ATTR_AUTO_MODE: False}, True)
|
||||
assert device.disable_auto_mode.call_count == 1
|
||||
|
||||
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_purecool_device()])
|
||||
async def test_purecool_set_angle(devices, login, hass):
|
||||
"""Test set angle."""
|
||||
device = devices.return_value[0]
|
||||
await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config())
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(dyson.DYSON_DOMAIN, dyson.SERVICE_SET_ANGLE,
|
||||
{ATTR_ENTITY_ID: "fan.bed_room",
|
||||
dyson.ATTR_ANGLE_LOW: 90,
|
||||
dyson.ATTR_ANGLE_HIGH: 180}, True)
|
||||
assert device.enable_oscillation.call_count == 0
|
||||
|
||||
await hass.services.async_call(dyson.DYSON_DOMAIN, dyson.SERVICE_SET_ANGLE,
|
||||
{ATTR_ENTITY_ID: "fan.living_room",
|
||||
dyson.ATTR_ANGLE_LOW: 90,
|
||||
dyson.ATTR_ANGLE_HIGH: 180}, True)
|
||||
device.enable_oscillation.assert_called_with(90, 180)
|
||||
|
||||
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_purecool_device()])
|
||||
async def test_purecool_set_flow_direction_front(devices, login, hass):
|
||||
"""Test set frontal flow direction."""
|
||||
device = devices.return_value[0]
|
||||
await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config())
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(dyson.DYSON_DOMAIN,
|
||||
dyson.SERVICE_SET_FLOW_DIRECTION_FRONT,
|
||||
{ATTR_ENTITY_ID: "fan.bed_room",
|
||||
dyson.ATTR_FLOW_DIRECTION_FRONT: True},
|
||||
True)
|
||||
assert device.enable_frontal_direction.call_count == 0
|
||||
|
||||
await hass.services.async_call(dyson.DYSON_DOMAIN,
|
||||
dyson.SERVICE_SET_FLOW_DIRECTION_FRONT,
|
||||
{ATTR_ENTITY_ID: "fan.living_room",
|
||||
dyson.ATTR_FLOW_DIRECTION_FRONT: True},
|
||||
True)
|
||||
assert device.enable_frontal_direction.call_count == 1
|
||||
|
||||
await hass.services.async_call(dyson.DYSON_DOMAIN,
|
||||
dyson.SERVICE_SET_FLOW_DIRECTION_FRONT,
|
||||
{ATTR_ENTITY_ID: "fan.living_room",
|
||||
dyson.ATTR_FLOW_DIRECTION_FRONT: False},
|
||||
True)
|
||||
assert device.disable_frontal_direction.call_count == 1
|
||||
|
||||
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_purecool_device()])
|
||||
async def test_purecool_set_timer(devices, login, hass):
|
||||
"""Test set timer."""
|
||||
device = devices.return_value[0]
|
||||
await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config())
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(dyson.DYSON_DOMAIN, dyson.SERVICE_SET_TIMER,
|
||||
{ATTR_ENTITY_ID: "fan.bed_room",
|
||||
dyson.ATTR_TIMER: 60},
|
||||
True)
|
||||
assert device.enable_frontal_direction.call_count == 0
|
||||
|
||||
await hass.services.async_call(dyson.DYSON_DOMAIN, dyson.SERVICE_SET_TIMER,
|
||||
{ATTR_ENTITY_ID: "fan.living_room",
|
||||
dyson.ATTR_TIMER: 60},
|
||||
True)
|
||||
device.enable_sleep_timer.assert_called_with(60)
|
||||
|
||||
await hass.services.async_call(dyson.DYSON_DOMAIN, dyson.SERVICE_SET_TIMER,
|
||||
{ATTR_ENTITY_ID: "fan.living_room",
|
||||
dyson.ATTR_TIMER: 0},
|
||||
True)
|
||||
assert device.disable_sleep_timer.call_count == 1
|
||||
|
||||
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_purecool_device()])
|
||||
async def test_purecool_attributes(devices, login, hass):
|
||||
"""Test state attributes."""
|
||||
await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config())
|
||||
await hass.async_block_till_done()
|
||||
fan_state = hass.states.get("fan.living_room")
|
||||
attributes = fan_state.attributes
|
||||
|
||||
assert fan_state.state == "on"
|
||||
assert attributes[dyson.ATTR_NIGHT_MODE] is False
|
||||
assert attributes[dyson.ATTR_AUTO_MODE] is True
|
||||
assert attributes[dyson.ATTR_ANGLE_LOW] == 90
|
||||
assert attributes[dyson.ATTR_ANGLE_HIGH] == 180
|
||||
assert attributes[dyson.ATTR_FLOW_DIRECTION_FRONT] is True
|
||||
assert attributes[dyson.ATTR_TIMER] == 60
|
||||
assert attributes[dyson.ATTR_HEPA_FILTER] == 90
|
||||
assert attributes[dyson.ATTR_CARBON_FILTER] == 80
|
||||
assert attributes[dyson.ATTR_DYSON_SPEED] == FanSpeed.FAN_SPEED_AUTO.value
|
||||
assert attributes[ATTR_SPEED] == SPEED_MEDIUM
|
||||
assert attributes[ATTR_OSCILLATING] is True
|
||||
assert attributes[dyson.ATTR_DYSON_SPEED_LIST] == _get_supported_speeds()
|
||||
|
||||
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_purecool_device()])
|
||||
async def test_purecool_update_state(devices, login, hass):
|
||||
"""Test state update."""
|
||||
device = devices.return_value[0]
|
||||
await async_setup_component(hass, dyson.DYSON_DOMAIN, _get_config())
|
||||
await hass.async_block_till_done()
|
||||
event = {"msg": "CURRENT-STATE",
|
||||
"product-state": {"fpwr": "OFF", "fdir": "OFF", "auto": "OFF",
|
||||
"oscs": "ON", "oson": "ON", "nmod": "OFF",
|
||||
"rhtm": "ON", "fnst": "FAN", "ercd": "11E1",
|
||||
"wacd": "NONE", "nmdv": "0004", "fnsp": "0002",
|
||||
"bril": "0002", "corf": "ON", "cflr": "0085",
|
||||
"hflr": "0095", "sltm": "OFF", "osal": "0045",
|
||||
"osau": "0095", "ancp": "CUST"}}
|
||||
device.state = DysonPureCoolV2State(json.dumps(event))
|
||||
|
||||
callback = device.add_message_listener.call_args_list[0][0][0]
|
||||
callback(device.state)
|
||||
await hass.async_block_till_done()
|
||||
fan_state = hass.states.get("fan.living_room")
|
||||
attributes = fan_state.attributes
|
||||
|
||||
assert fan_state.state == "off"
|
||||
assert attributes[dyson.ATTR_NIGHT_MODE] is False
|
||||
assert attributes[dyson.ATTR_AUTO_MODE] is False
|
||||
assert attributes[dyson.ATTR_ANGLE_LOW] == 45
|
||||
assert attributes[dyson.ATTR_ANGLE_HIGH] == 95
|
||||
assert attributes[dyson.ATTR_FLOW_DIRECTION_FRONT] is False
|
||||
assert attributes[dyson.ATTR_TIMER] == "OFF"
|
||||
assert attributes[dyson.ATTR_HEPA_FILTER] == 95
|
||||
assert attributes[dyson.ATTR_CARBON_FILTER] == 85
|
||||
assert attributes[dyson.ATTR_DYSON_SPEED] == \
|
||||
int(FanSpeed.FAN_SPEED_2.value)
|
||||
assert attributes[ATTR_SPEED] is SPEED_LOW
|
||||
assert attributes[ATTR_OSCILLATING] is False
|
||||
assert attributes[dyson.ATTR_DYSON_SPEED_LIST] == _get_supported_speeds()
|
||||
|
||||
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
@asynctest.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_purecool_device()])
|
||||
async def test_purecool_component_setup_only_once(devices, login, hass):
|
||||
"""Test if entities are created only once."""
|
||||
config = _get_config()
|
||||
await async_setup_component(hass, dyson_parent.DOMAIN, config)
|
||||
await hass.async_block_till_done()
|
||||
discovery.load_platform(hass, "fan", dyson_parent.DOMAIN, {}, config)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
fans = [fan for fan in hass.data[DOMAIN].entities
|
||||
if fan.platform.platform_name == dyson_parent.DOMAIN]
|
||||
|
||||
assert len(fans) == 1
|
||||
assert fans[0].device_serial == "XX-XXXXX-XX"
|
||||
|
|
|
@ -43,7 +43,7 @@ class DysonTest(unittest.TestCase):
|
|||
"""Stop everything that was started."""
|
||||
self.hass.stop()
|
||||
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=False)
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.login', return_value=False)
|
||||
def test_dyson_login_failed(self, mocked_login):
|
||||
"""Test if Dyson connection failed."""
|
||||
dyson.setup(self.hass, {dyson.DOMAIN: {
|
||||
|
@ -53,8 +53,8 @@ class DysonTest(unittest.TestCase):
|
|||
}})
|
||||
assert mocked_login.call_count == 1
|
||||
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.devices', return_value=[])
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True)
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.devices', return_value=[])
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
def test_dyson_login(self, mocked_login, mocked_devices):
|
||||
"""Test valid connection to dyson web service."""
|
||||
dyson.setup(self.hass, {dyson.DOMAIN: {
|
||||
|
@ -67,9 +67,9 @@ class DysonTest(unittest.TestCase):
|
|||
assert len(self.hass.data[dyson.DYSON_DEVICES]) == 0
|
||||
|
||||
@mock.patch('homeassistant.helpers.discovery.load_platform')
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.devices',
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_account_device_available()])
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True)
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
def test_dyson_custom_conf(self, mocked_login, mocked_devices,
|
||||
mocked_discovery):
|
||||
"""Test device connection using custom configuration."""
|
||||
|
@ -89,9 +89,9 @@ class DysonTest(unittest.TestCase):
|
|||
assert len(self.hass.data[dyson.DYSON_DEVICES]) == 1
|
||||
assert mocked_discovery.call_count == 4
|
||||
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.devices',
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_account_device_not_available()])
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True)
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
def test_dyson_custom_conf_device_not_available(self, mocked_login,
|
||||
mocked_devices):
|
||||
"""Test device connection with an invalid device."""
|
||||
|
@ -110,9 +110,9 @@ class DysonTest(unittest.TestCase):
|
|||
assert mocked_devices.call_count == 1
|
||||
assert len(self.hass.data[dyson.DYSON_DEVICES]) == 0
|
||||
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.devices',
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_account_device_error()])
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True)
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
def test_dyson_custom_conf_device_error(self, mocked_login,
|
||||
mocked_devices):
|
||||
"""Test device connection with device raising an exception."""
|
||||
|
@ -132,9 +132,9 @@ class DysonTest(unittest.TestCase):
|
|||
assert len(self.hass.data[dyson.DYSON_DEVICES]) == 0
|
||||
|
||||
@mock.patch('homeassistant.helpers.discovery.load_platform')
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.devices',
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_account_device_available()])
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True)
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
def test_dyson_custom_conf_with_unknown_device(self, mocked_login,
|
||||
mocked_devices,
|
||||
mocked_discovery):
|
||||
|
@ -156,9 +156,9 @@ class DysonTest(unittest.TestCase):
|
|||
assert mocked_discovery.call_count == 0
|
||||
|
||||
@mock.patch('homeassistant.helpers.discovery.load_platform')
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.devices',
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_account_device_available()])
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True)
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
def test_dyson_discovery(self, mocked_login, mocked_devices,
|
||||
mocked_discovery):
|
||||
"""Test device connection using discovery."""
|
||||
|
@ -174,9 +174,9 @@ class DysonTest(unittest.TestCase):
|
|||
assert len(self.hass.data[dyson.DYSON_DEVICES]) == 1
|
||||
assert mocked_discovery.call_count == 4
|
||||
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.devices',
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.devices',
|
||||
return_value=[_get_dyson_account_device_not_available()])
|
||||
@mock.patch('libpurecoollink.dyson.DysonAccount.login', return_value=True)
|
||||
@mock.patch('libpurecool.dyson.DysonAccount.login', return_value=True)
|
||||
def test_dyson_discovery_device_not_available(self, mocked_login,
|
||||
mocked_devices):
|
||||
"""Test device connection with discovery and invalid device."""
|
||||
|
|
|
@ -2,16 +2,17 @@
|
|||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
from libpurecool.dyson_pure_cool_link import DysonPureCoolLink
|
||||
|
||||
from homeassistant.components.dyson import sensor as dyson
|
||||
from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT, \
|
||||
STATE_OFF
|
||||
from homeassistant.components.dyson import sensor as dyson
|
||||
from tests.common import get_test_home_assistant
|
||||
from libpurecoollink.dyson_pure_cool_link import DysonPureCoolLink
|
||||
|
||||
|
||||
def _get_device_without_state():
|
||||
"""Return a valid device provide by Dyson web services."""
|
||||
device = mock.Mock(spec=DysonPureCoolLink)
|
||||
device = mock.Mock()
|
||||
device.name = "Device_name"
|
||||
device.state = None
|
||||
device.environmental_state = None
|
||||
|
@ -20,7 +21,7 @@ def _get_device_without_state():
|
|||
|
||||
def _get_with_state():
|
||||
"""Return a valid device with state values."""
|
||||
device = mock.Mock()
|
||||
device = mock.Mock(spec=DysonPureCoolLink)
|
||||
device.name = "Device_name"
|
||||
device.state = mock.Mock()
|
||||
device.state.filter_life = 100
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
from libpurecoollink.dyson_360_eye import Dyson360Eye
|
||||
from libpurecoollink.const import Dyson360EyeMode, PowerMode
|
||||
from libpurecool.const import Dyson360EyeMode, PowerMode
|
||||
from libpurecool.dyson_360_eye import Dyson360Eye
|
||||
|
||||
from homeassistant.components.dyson import vacuum as dyson
|
||||
from homeassistant.components.dyson.vacuum import Dyson360EyeDevice
|
||||
|
|
Loading…
Add table
Reference in a new issue