Improve dyson code (#45172)
* Improve air_quality * Improve climate * Improve sensor * Improve vacuum * Improve fan * Fix pylint * Improve on_message * Change unique ID back * Remove unused attribute * Remove redundant current_humidity * Merge current_temperature * Rename fan device to fan entity * Fix filter life sensors * Remove unneeded context switch * Remove entity_type * Fix pylint * Add comment on humidity check
This commit is contained in:
parent
28a611f3da
commit
a42d43d054
7 changed files with 179 additions and 310 deletions
|
@ -7,6 +7,7 @@ import voluptuous as vol
|
|||
from homeassistant.const import CONF_DEVICES, CONF_PASSWORD, CONF_TIMEOUT, CONF_USERNAME
|
||||
from homeassistant.helpers import discovery
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -108,3 +109,45 @@ def setup(hass, config):
|
|||
discovery.load_platform(hass, platform, DOMAIN, {}, config)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class DysonEntity(Entity):
|
||||
"""Representation of a Dyson entity."""
|
||||
|
||||
def __init__(self, device, state_type):
|
||||
"""Initialize the entity."""
|
||||
self._device = device
|
||||
self._state_type = state_type
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call when entity is added to hass."""
|
||||
self._device.add_message_listener(self.on_message_filter)
|
||||
|
||||
def on_message_filter(self, message):
|
||||
"""Filter new messages received."""
|
||||
if self._state_type is None or isinstance(message, self._state_type):
|
||||
_LOGGER.debug(
|
||||
"Message received for device %s : %s",
|
||||
self.name,
|
||||
message,
|
||||
)
|
||||
self.on_message(message)
|
||||
|
||||
def on_message(self, message):
|
||||
"""Handle new messages received."""
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""No polling needed."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the Dyson sensor."""
|
||||
return self._device.name
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return the sensor's unique id."""
|
||||
return self._device.serial
|
||||
|
|
|
@ -4,9 +4,9 @@ import logging
|
|||
from libpurecool.dyson_pure_cool import DysonPureCool
|
||||
from libpurecool.dyson_pure_state_v2 import DysonEnvironmentalSensorV2State
|
||||
|
||||
from homeassistant.components.air_quality import DOMAIN, AirQualityEntity
|
||||
from homeassistant.components.air_quality import AirQualityEntity
|
||||
|
||||
from . import DYSON_DEVICES
|
||||
from . import DYSON_DEVICES, DysonEntity
|
||||
|
||||
ATTRIBUTION = "Dyson purifier air quality sensor"
|
||||
|
||||
|
@ -39,41 +39,23 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||
add_entities(hass.data[DYSON_AIQ_DEVICES])
|
||||
|
||||
|
||||
class DysonAirSensor(AirQualityEntity):
|
||||
class DysonAirSensor(DysonEntity, AirQualityEntity):
|
||||
"""Representation of a generic Dyson air quality sensor."""
|
||||
|
||||
def __init__(self, device):
|
||||
"""Create a new generic air quality Dyson sensor."""
|
||||
self._device = device
|
||||
super().__init__(device, DysonEnvironmentalSensorV2State)
|
||||
self._old_value = None
|
||||
self._name = device.name
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call when entity is added to hass."""
|
||||
self._device.add_message_listener(self.on_message)
|
||||
|
||||
def on_message(self, message):
|
||||
"""Handle new messages which are received from the fan."""
|
||||
_LOGGER.debug(
|
||||
"%s: Message received for %s device: %s", DOMAIN, self.name, message
|
||||
)
|
||||
if (
|
||||
self._old_value is None
|
||||
or self._old_value != self._device.environmental_state
|
||||
) and isinstance(message, DysonEnvironmentalSensorV2State):
|
||||
):
|
||||
self._old_value = self._device.environmental_state
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""No polling needed."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the Dyson sensor."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def attribution(self):
|
||||
"""Return the attribution."""
|
||||
|
@ -117,11 +99,6 @@ class DysonAirSensor(AirQualityEntity):
|
|||
return int(self._device.environmental_state.volatile_organic_compounds)
|
||||
return None
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return the sensor's unique id."""
|
||||
return self._device.serial
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
"""Return the device state attributes."""
|
||||
|
|
|
@ -37,13 +37,13 @@ from homeassistant.components.climate.const import (
|
|||
)
|
||||
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
|
||||
|
||||
from . import DYSON_DEVICES
|
||||
from . import DYSON_DEVICES, DysonEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SUPPORT_FAN = [FAN_FOCUS, FAN_DIFFUSE]
|
||||
SUPPORT_FAN_PCOOL = [FAN_OFF, FAN_AUTO, FAN_LOW, FAN_MEDIUM, FAN_HIGH]
|
||||
SUPPORT_HVAG = [HVAC_MODE_COOL, HVAC_MODE_HEAT]
|
||||
SUPPORT_HVAC = [HVAC_MODE_COOL, HVAC_MODE_HEAT]
|
||||
SUPPORT_HVAC_PCOOL = [HVAC_MODE_COOL, HVAC_MODE_HEAT, HVAC_MODE_OFF]
|
||||
SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_FAN_MODE
|
||||
|
||||
|
@ -88,41 +88,14 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||
add_entities(new_entities)
|
||||
|
||||
|
||||
class DysonPureHotCoolLinkEntity(ClimateEntity):
|
||||
class DysonClimateEntity(DysonEntity, ClimateEntity):
|
||||
"""Representation of a Dyson climate fan."""
|
||||
|
||||
def __init__(self, device):
|
||||
"""Initialize the fan."""
|
||||
self._device = device
|
||||
self._current_temp = None
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call when entity is added to hass."""
|
||||
self._device.add_message_listener(self.on_message)
|
||||
|
||||
def on_message(self, message):
|
||||
"""Call when new messages received from the climate."""
|
||||
if isinstance(message, DysonPureHotCoolState):
|
||||
_LOGGER.debug(
|
||||
"Message received for climate device %s : %s", self.name, message
|
||||
)
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""No polling needed."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Return the list of supported features."""
|
||||
return SUPPORT_FLAGS
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the display name of this climate."""
|
||||
return self._device.name
|
||||
|
||||
@property
|
||||
def temperature_unit(self):
|
||||
"""Return the unit of measurement."""
|
||||
|
@ -131,11 +104,13 @@ class DysonPureHotCoolLinkEntity(ClimateEntity):
|
|||
@property
|
||||
def current_temperature(self):
|
||||
"""Return the current temperature."""
|
||||
if self._device.environmental_state:
|
||||
if (
|
||||
self._device.environmental_state
|
||||
and self._device.environmental_state.temperature
|
||||
):
|
||||
temperature_kelvin = self._device.environmental_state.temperature
|
||||
if temperature_kelvin != 0:
|
||||
self._current_temp = float(f"{(temperature_kelvin - 273):.1f}")
|
||||
return self._current_temp
|
||||
return float("{:.1f}".format(temperature_kelvin - 273))
|
||||
return None
|
||||
|
||||
@property
|
||||
def target_temperature(self):
|
||||
|
@ -146,12 +121,49 @@ class DysonPureHotCoolLinkEntity(ClimateEntity):
|
|||
@property
|
||||
def current_humidity(self):
|
||||
"""Return the current humidity."""
|
||||
if self._device.environmental_state:
|
||||
if self._device.environmental_state.humidity == 0:
|
||||
return None
|
||||
# Humidity equaling to 0 means invalid value so we don't check for None here
|
||||
# https://github.com/home-assistant/core/pull/45172#discussion_r559069756
|
||||
if (
|
||||
self._device.environmental_state
|
||||
and self._device.environmental_state.humidity
|
||||
):
|
||||
return self._device.environmental_state.humidity
|
||||
return None
|
||||
|
||||
@property
|
||||
def min_temp(self):
|
||||
"""Return the minimum temperature."""
|
||||
return 1
|
||||
|
||||
@property
|
||||
def max_temp(self):
|
||||
"""Return the maximum temperature."""
|
||||
return 37
|
||||
|
||||
def set_temperature(self, **kwargs):
|
||||
"""Set new target temperature."""
|
||||
target_temp = kwargs.get(ATTR_TEMPERATURE)
|
||||
if target_temp is None:
|
||||
_LOGGER.error("Missing target temperature %s", kwargs)
|
||||
return
|
||||
target_temp = int(target_temp)
|
||||
_LOGGER.debug("Set %s temperature %s", self.name, target_temp)
|
||||
# Limit the target temperature into acceptable range.
|
||||
target_temp = min(self.max_temp, target_temp)
|
||||
target_temp = max(self.min_temp, target_temp)
|
||||
self.set_heat_target(HeatTarget.celsius(target_temp))
|
||||
|
||||
def set_heat_target(self, heat_target):
|
||||
"""Set heating target temperature."""
|
||||
|
||||
|
||||
class DysonPureHotCoolLinkEntity(DysonClimateEntity):
|
||||
"""Representation of a Dyson climate fan."""
|
||||
|
||||
def __init__(self, device):
|
||||
"""Initialize the fan."""
|
||||
super().__init__(device, DysonPureHotCoolState)
|
||||
|
||||
@property
|
||||
def hvac_mode(self):
|
||||
"""Return hvac operation ie. heat, cool mode.
|
||||
|
@ -168,7 +180,7 @@ class DysonPureHotCoolLinkEntity(ClimateEntity):
|
|||
|
||||
Need to be a subset of HVAC_MODES.
|
||||
"""
|
||||
return SUPPORT_HVAG
|
||||
return SUPPORT_HVAC
|
||||
|
||||
@property
|
||||
def hvac_action(self):
|
||||
|
@ -194,18 +206,10 @@ class DysonPureHotCoolLinkEntity(ClimateEntity):
|
|||
"""Return the list of available fan modes."""
|
||||
return SUPPORT_FAN
|
||||
|
||||
def set_temperature(self, **kwargs):
|
||||
"""Set new target temperature."""
|
||||
target_temp = kwargs.get(ATTR_TEMPERATURE)
|
||||
if target_temp is None:
|
||||
return
|
||||
target_temp = int(target_temp)
|
||||
_LOGGER.debug("Set %s temperature %s", self.name, target_temp)
|
||||
# Limit the target temperature into acceptable range.
|
||||
target_temp = min(self.max_temp, target_temp)
|
||||
target_temp = max(self.min_temp, target_temp)
|
||||
def set_heat_target(self, heat_target):
|
||||
"""Set heating target temperature."""
|
||||
self._device.set_configuration(
|
||||
heat_target=HeatTarget.celsius(target_temp), heat_mode=HeatMode.HEAT_ON
|
||||
heat_target=heat_target, heat_mode=HeatMode.HEAT_ON
|
||||
)
|
||||
|
||||
def set_fan_mode(self, fan_mode):
|
||||
|
@ -224,78 +228,13 @@ class DysonPureHotCoolLinkEntity(ClimateEntity):
|
|||
elif hvac_mode == HVAC_MODE_COOL:
|
||||
self._device.set_configuration(heat_mode=HeatMode.HEAT_OFF)
|
||||
|
||||
@property
|
||||
def min_temp(self):
|
||||
"""Return the minimum temperature."""
|
||||
return 1
|
||||
|
||||
@property
|
||||
def max_temp(self):
|
||||
"""Return the maximum temperature."""
|
||||
return 37
|
||||
|
||||
|
||||
class DysonPureHotCoolEntity(ClimateEntity):
|
||||
class DysonPureHotCoolEntity(DysonClimateEntity):
|
||||
"""Representation of a Dyson climate hot+cool 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._device.add_message_listener(self.on_message)
|
||||
|
||||
def on_message(self, message):
|
||||
"""Call when new messages received from the climate device."""
|
||||
if isinstance(message, DysonPureHotCoolV2State):
|
||||
_LOGGER.debug(
|
||||
"Message received for climate device %s : %s", self.name, message
|
||||
)
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""No polling needed."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Return the list of supported features."""
|
||||
return SUPPORT_FLAGS
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the display name of this climate."""
|
||||
return self._device.name
|
||||
|
||||
@property
|
||||
def temperature_unit(self):
|
||||
"""Return the unit of measurement."""
|
||||
return TEMP_CELSIUS
|
||||
|
||||
@property
|
||||
def current_temperature(self):
|
||||
"""Return the current temperature."""
|
||||
if self._device.environmental_state.temperature is not None:
|
||||
temperature_kelvin = self._device.environmental_state.temperature
|
||||
if temperature_kelvin != 0:
|
||||
return float("{:.1f}".format(temperature_kelvin - 273))
|
||||
return None
|
||||
|
||||
@property
|
||||
def target_temperature(self):
|
||||
"""Return the target temperature."""
|
||||
heat_target = int(self._device.state.heat_target) / 10
|
||||
return int(heat_target - 273)
|
||||
|
||||
@property
|
||||
def current_humidity(self):
|
||||
"""Return the current humidity."""
|
||||
if self._device.environmental_state.humidity is not None:
|
||||
if self._device.environmental_state.humidity != 0:
|
||||
return self._device.environmental_state.humidity
|
||||
return None
|
||||
super().__init__(device, DysonPureHotCoolV2State)
|
||||
|
||||
@property
|
||||
def hvac_mode(self):
|
||||
|
@ -347,18 +286,9 @@ class DysonPureHotCoolEntity(ClimateEntity):
|
|||
"""Return the list of available fan modes."""
|
||||
return SUPPORT_FAN_PCOOL
|
||||
|
||||
def set_temperature(self, **kwargs):
|
||||
"""Set new target temperature."""
|
||||
target_temp = kwargs.get(ATTR_TEMPERATURE)
|
||||
if target_temp is None:
|
||||
_LOGGER.error("Missing target temperature %s", kwargs)
|
||||
return
|
||||
target_temp = int(target_temp)
|
||||
_LOGGER.debug("Set %s temperature %s", self.name, target_temp)
|
||||
# Limit the target temperature into acceptable range.
|
||||
target_temp = min(self.max_temp, target_temp)
|
||||
target_temp = max(self.min_temp, target_temp)
|
||||
self._device.set_heat_target(HeatTarget.celsius(target_temp))
|
||||
def set_heat_target(self, heat_target):
|
||||
"""Set heating target temperature."""
|
||||
self._device.set_heat_target(heat_target)
|
||||
|
||||
def set_fan_mode(self, fan_mode):
|
||||
"""Set new fan mode."""
|
||||
|
@ -385,13 +315,3 @@ class DysonPureHotCoolEntity(ClimateEntity):
|
|||
self._device.enable_heat_mode()
|
||||
elif hvac_mode == HVAC_MODE_COOL:
|
||||
self._device.disable_heat_mode()
|
||||
|
||||
@property
|
||||
def min_temp(self):
|
||||
"""Return the minimum temperature."""
|
||||
return 1
|
||||
|
||||
@property
|
||||
def max_temp(self):
|
||||
"""Return the maximum temperature."""
|
||||
return 37
|
||||
|
|
|
@ -19,7 +19,7 @@ from homeassistant.components.fan import (
|
|||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
from . import DYSON_DEVICES
|
||||
from . import DYSON_DEVICES, DysonEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -105,10 +105,10 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||
if device.serial not in device_serials:
|
||||
if isinstance(device, DysonPureCool):
|
||||
has_purecool_devices = True
|
||||
dyson_entity = DysonPureCoolDevice(device)
|
||||
dyson_entity = DysonPureCoolEntity(device)
|
||||
hass.data[DYSON_FAN_DEVICES].append(dyson_entity)
|
||||
elif isinstance(device, DysonPureCoolLink):
|
||||
dyson_entity = DysonPureCoolLinkDevice(hass, device)
|
||||
dyson_entity = DysonPureCoolLinkEntity(device)
|
||||
hass.data[DYSON_FAN_DEVICES].append(dyson_entity)
|
||||
|
||||
add_entities(hass.data[DYSON_FAN_DEVICES])
|
||||
|
@ -179,35 +179,21 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||
)
|
||||
|
||||
|
||||
class DysonPureCoolLinkDevice(FanEntity):
|
||||
class DysonFanEntity(DysonEntity, FanEntity):
|
||||
"""Representation of a Dyson fan."""
|
||||
|
||||
def __init__(self, hass, device):
|
||||
@property
|
||||
def night_mode(self):
|
||||
"""Return Night mode."""
|
||||
return self._device.state.night_mode == "ON"
|
||||
|
||||
|
||||
class DysonPureCoolLinkEntity(DysonFanEntity):
|
||||
"""Representation of a Dyson fan."""
|
||||
|
||||
def __init__(self, device):
|
||||
"""Initialize the fan."""
|
||||
_LOGGER.debug("Creating device %s", device.name)
|
||||
self.hass = hass
|
||||
self._device = device
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call when entity is added to hass."""
|
||||
self._device.add_message_listener(self.on_message)
|
||||
|
||||
def on_message(self, message):
|
||||
"""Call when new messages received from the fan."""
|
||||
|
||||
if isinstance(message, DysonPureCoolState):
|
||||
_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
|
||||
super().__init__(device, DysonPureCoolState)
|
||||
|
||||
def set_speed(self, speed: str) -> None:
|
||||
"""Set the speed of the fan. Never called ??."""
|
||||
|
@ -274,11 +260,6 @@ class DysonPureCoolLinkDevice(FanEntity):
|
|||
"""Return direction of the fan [forward, reverse]."""
|
||||
return None
|
||||
|
||||
@property
|
||||
def night_mode(self):
|
||||
"""Return Night mode."""
|
||||
return self._device.state.night_mode == "ON"
|
||||
|
||||
def set_night_mode(self, night_mode: bool) -> None:
|
||||
"""Turn fan in night mode."""
|
||||
_LOGGER.debug("Set %s night mode %s", self.name, night_mode)
|
||||
|
@ -330,32 +311,12 @@ class DysonPureCoolLinkDevice(FanEntity):
|
|||
return {ATTR_NIGHT_MODE: self.night_mode, ATTR_AUTO_MODE: self.auto_mode}
|
||||
|
||||
|
||||
class DysonPureCoolDevice(FanEntity):
|
||||
class DysonPureCoolEntity(DysonFanEntity):
|
||||
"""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._device.add_message_listener(self.on_message)
|
||||
|
||||
def on_message(self, message):
|
||||
"""Call when new messages received from the fan."""
|
||||
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
|
||||
super().__init__(device, DysonPureCoolV2State)
|
||||
|
||||
def turn_on(self, speed: str = None, **kwargs) -> None:
|
||||
"""Turn on the fan."""
|
||||
|
@ -455,6 +416,7 @@ class DysonPureCoolDevice(FanEntity):
|
|||
"""Return true if the entity is on."""
|
||||
if self._device.state:
|
||||
return self._device.state.fan_power == "ON"
|
||||
return False
|
||||
|
||||
@property
|
||||
def speed(self):
|
||||
|
@ -483,11 +445,6 @@ class DysonPureCoolDevice(FanEntity):
|
|||
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."""
|
||||
|
|
|
@ -7,7 +7,7 @@ from libpurecool.dyson_pure_cool_link import DysonPureCoolLink
|
|||
from homeassistant.const import PERCENTAGE, STATE_OFF, TEMP_CELSIUS, TIME_HOURS
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from . import DYSON_DEVICES
|
||||
from . import DYSON_DEVICES, DysonEntity
|
||||
|
||||
SENSOR_UNITS = {
|
||||
"air_quality": None,
|
||||
|
@ -15,6 +15,7 @@ SENSOR_UNITS = {
|
|||
"filter_life": TIME_HOURS,
|
||||
"carbon_filter_state": PERCENTAGE,
|
||||
"hepa_filter_state": PERCENTAGE,
|
||||
"combi_filter_state": PERCENTAGE,
|
||||
"humidity": PERCENTAGE,
|
||||
}
|
||||
|
||||
|
@ -24,10 +25,22 @@ SENSOR_ICONS = {
|
|||
"filter_life": "mdi:filter-outline",
|
||||
"carbon_filter_state": "mdi:filter-outline",
|
||||
"hepa_filter_state": "mdi:filter-outline",
|
||||
"combi_filter_state": "mdi:filter-outline",
|
||||
"humidity": "mdi:water-percent",
|
||||
"temperature": "mdi:thermometer",
|
||||
}
|
||||
|
||||
SENSOR_NAMES = {
|
||||
"air_quality": "AQI",
|
||||
"dust": "Dust",
|
||||
"filter_life": "Filter Life",
|
||||
"humidity": "Humidity",
|
||||
"carbon_filter_state": "Carbon Filter Remaining Life",
|
||||
"hepa_filter_state": "HEPA Filter Remaining Life",
|
||||
"combi_filter_state": "Combi Filter Remaining Life",
|
||||
"temperature": "Temperature",
|
||||
}
|
||||
|
||||
DYSON_SENSOR_DEVICES = "dyson_sensor_devices"
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -57,7 +70,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||
# It's reported with the HEPA state, while the Carbon state is set to INValid.
|
||||
if device.state and device.state.carbon_filter_state == "INV":
|
||||
if f"{device.serial}-hepa_filter_state" not in device_ids:
|
||||
new_entities.append(DysonHepaFilterLifeSensor(device, "Combi"))
|
||||
new_entities.append(DysonHepaFilterLifeSensor(device, "combi"))
|
||||
else:
|
||||
if f"{device.serial}-hepa_filter_state" not in device_ids:
|
||||
new_entities.append(DysonHepaFilterLifeSensor(device))
|
||||
|
@ -77,37 +90,31 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||
add_entities(devices)
|
||||
|
||||
|
||||
class DysonSensor(Entity):
|
||||
class DysonSensor(DysonEntity, Entity):
|
||||
"""Representation of a generic Dyson sensor."""
|
||||
|
||||
def __init__(self, device, sensor_type):
|
||||
"""Create a new generic Dyson sensor."""
|
||||
self._device = device
|
||||
super().__init__(device, None)
|
||||
self._old_value = None
|
||||
self._name = None
|
||||
self._sensor_type = sensor_type
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call when entity is added to hass."""
|
||||
self._device.add_message_listener(self.on_message)
|
||||
|
||||
def on_message(self, message):
|
||||
"""Handle new messages which are received from the fan."""
|
||||
# Prevent refreshing if not needed
|
||||
if self._old_value is None or self._old_value != self.state:
|
||||
_LOGGER.debug("Message received for %s device: %s", self.name, message)
|
||||
self._old_value = self.state
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""No polling needed."""
|
||||
return False
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the Dyson sensor name."""
|
||||
return self._name
|
||||
return f"{super().name} {SENSOR_NAMES[self._sensor_type]}"
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return the sensor's unique id."""
|
||||
return f"{self._device.serial}-{self._sensor_type}"
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
|
@ -119,11 +126,6 @@ class DysonSensor(Entity):
|
|||
"""Return the icon for this sensor."""
|
||||
return SENSOR_ICONS[self._sensor_type]
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return the sensor's unique id."""
|
||||
return f"{self._device.serial}-{self._sensor_type}"
|
||||
|
||||
|
||||
class DysonFilterLifeSensor(DysonSensor):
|
||||
"""Representation of Dyson Filter Life sensor (in hours)."""
|
||||
|
@ -131,7 +133,6 @@ class DysonFilterLifeSensor(DysonSensor):
|
|||
def __init__(self, device):
|
||||
"""Create a new Dyson Filter Life sensor."""
|
||||
super().__init__(device, "filter_life")
|
||||
self._name = f"{self._device.name} Filter Life"
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
|
@ -147,7 +148,6 @@ class DysonCarbonFilterLifeSensor(DysonSensor):
|
|||
def __init__(self, device):
|
||||
"""Create a new Dyson Carbon Filter Life sensor."""
|
||||
super().__init__(device, "carbon_filter_state")
|
||||
self._name = f"{self._device.name} Carbon Filter Remaining Life"
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
|
@ -160,10 +160,9 @@ class DysonCarbonFilterLifeSensor(DysonSensor):
|
|||
class DysonHepaFilterLifeSensor(DysonSensor):
|
||||
"""Representation of Dyson HEPA (or Combi) Filter Life sensor (in percent)."""
|
||||
|
||||
def __init__(self, device, filter_type="HEPA"):
|
||||
def __init__(self, device, filter_type="hepa"):
|
||||
"""Create a new Dyson Filter Life sensor."""
|
||||
super().__init__(device, "hepa_filter_state")
|
||||
self._name = f"{self._device.name} {filter_type} Filter Remaining Life"
|
||||
super().__init__(device, f"{filter_type}_filter_state")
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
|
@ -179,7 +178,6 @@ class DysonDustSensor(DysonSensor):
|
|||
def __init__(self, device):
|
||||
"""Create a new Dyson Dust sensor."""
|
||||
super().__init__(device, "dust")
|
||||
self._name = f"{self._device.name} Dust"
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
|
@ -195,7 +193,6 @@ class DysonHumiditySensor(DysonSensor):
|
|||
def __init__(self, device):
|
||||
"""Create a new Dyson Humidity sensor."""
|
||||
super().__init__(device, "humidity")
|
||||
self._name = f"{self._device.name} Humidity"
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
|
@ -213,7 +210,6 @@ class DysonTemperatureSensor(DysonSensor):
|
|||
def __init__(self, device, unit):
|
||||
"""Create a new Dyson Temperature sensor."""
|
||||
super().__init__(device, "temperature")
|
||||
self._name = f"{self._device.name} Temperature"
|
||||
self._unit = unit
|
||||
|
||||
@property
|
||||
|
@ -240,7 +236,6 @@ class DysonAirQualitySensor(DysonSensor):
|
|||
def __init__(self, device):
|
||||
"""Create a new Dyson Air Quality sensor."""
|
||||
super().__init__(device, "air_quality")
|
||||
self._name = f"{self._device.name} AQI"
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
|
|
|
@ -17,7 +17,7 @@ from homeassistant.components.vacuum import (
|
|||
)
|
||||
from homeassistant.helpers.icon import icon_for_battery_level
|
||||
|
||||
from . import DYSON_DEVICES
|
||||
from . import DYSON_DEVICES, DysonEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -54,35 +54,12 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||
return True
|
||||
|
||||
|
||||
class Dyson360EyeDevice(VacuumEntity):
|
||||
class Dyson360EyeDevice(DysonEntity, VacuumEntity):
|
||||
"""Dyson 360 Eye robot vacuum device."""
|
||||
|
||||
def __init__(self, device):
|
||||
"""Dyson 360 Eye robot vacuum device."""
|
||||
_LOGGER.debug("Creating device %s", device.name)
|
||||
self._device = device
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call when entity is added to hass."""
|
||||
self._device.add_message_listener(self.on_message)
|
||||
|
||||
def on_message(self, message):
|
||||
"""Handle a new messages that was received from the vacuum."""
|
||||
_LOGGER.debug("Message received for %s device: %s", self.name, message)
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def should_poll(self) -> bool:
|
||||
"""Return True if entity has to be polled for state.
|
||||
|
||||
False if entity pushes its state to HA.
|
||||
"""
|
||||
return False
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the device."""
|
||||
return self._device.name
|
||||
super().__init__(device, None)
|
||||
|
||||
@property
|
||||
def status(self):
|
||||
|
|
|
@ -187,7 +187,7 @@ class DysonTest(unittest.TestCase):
|
|||
def test_dyson_set_speed(self):
|
||||
"""Test set fan speed."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert not component.should_poll
|
||||
component.set_speed("1")
|
||||
set_config = device.set_configuration
|
||||
|
@ -202,7 +202,7 @@ class DysonTest(unittest.TestCase):
|
|||
def test_dyson_turn_on(self):
|
||||
"""Test turn on fan."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert not component.should_poll
|
||||
component.turn_on()
|
||||
set_config = device.set_configuration
|
||||
|
@ -211,7 +211,7 @@ class DysonTest(unittest.TestCase):
|
|||
def test_dyson_turn_night_mode(self):
|
||||
"""Test turn on fan with night mode."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert not component.should_poll
|
||||
component.set_night_mode(True)
|
||||
set_config = device.set_configuration
|
||||
|
@ -224,17 +224,17 @@ class DysonTest(unittest.TestCase):
|
|||
def test_is_night_mode(self):
|
||||
"""Test night mode."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert not component.night_mode
|
||||
|
||||
device = _get_device_off()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
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)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert not component.should_poll
|
||||
component.set_auto_mode(True)
|
||||
set_config = device.set_configuration
|
||||
|
@ -247,17 +247,17 @@ class DysonTest(unittest.TestCase):
|
|||
def test_is_auto_mode(self):
|
||||
"""Test auto mode."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert not component.auto_mode
|
||||
|
||||
device = _get_device_auto()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert component.auto_mode
|
||||
|
||||
def test_dyson_turn_on_speed(self):
|
||||
"""Test turn on fan with specified speed."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert not component.should_poll
|
||||
component.turn_on("1")
|
||||
set_config = device.set_configuration
|
||||
|
@ -272,7 +272,7 @@ class DysonTest(unittest.TestCase):
|
|||
def test_dyson_turn_off(self):
|
||||
"""Test turn off fan."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert not component.should_poll
|
||||
component.turn_off()
|
||||
set_config = device.set_configuration
|
||||
|
@ -281,7 +281,7 @@ class DysonTest(unittest.TestCase):
|
|||
def test_dyson_oscillate_off(self):
|
||||
"""Test turn off oscillation."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
component.oscillate(False)
|
||||
set_config = device.set_configuration
|
||||
set_config.assert_called_with(oscillation=Oscillation.OSCILLATION_OFF)
|
||||
|
@ -289,7 +289,7 @@ class DysonTest(unittest.TestCase):
|
|||
def test_dyson_oscillate_on(self):
|
||||
"""Test turn on oscillation."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
component.oscillate(True)
|
||||
set_config = device.set_configuration
|
||||
set_config.assert_called_with(oscillation=Oscillation.OSCILLATION_ON)
|
||||
|
@ -297,71 +297,71 @@ class DysonTest(unittest.TestCase):
|
|||
def test_dyson_oscillate_value_on(self):
|
||||
"""Test get oscillation value on."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert component.oscillating
|
||||
|
||||
def test_dyson_oscillate_value_off(self):
|
||||
"""Test get oscillation value off."""
|
||||
device = _get_device_off()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert not component.oscillating
|
||||
|
||||
def test_dyson_on(self):
|
||||
"""Test device is on."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert component.is_on
|
||||
|
||||
def test_dyson_off(self):
|
||||
"""Test device is off."""
|
||||
device = _get_device_off()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert not component.is_on
|
||||
|
||||
device = _get_device_with_no_state()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert not component.is_on
|
||||
|
||||
def test_dyson_get_speed(self):
|
||||
"""Test get device speed."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert component.speed == 1
|
||||
|
||||
device = _get_device_off()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert component.speed == 4
|
||||
|
||||
device = _get_device_with_no_state()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert component.speed is None
|
||||
|
||||
device = _get_device_auto()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert component.speed == "AUTO"
|
||||
|
||||
def test_dyson_get_direction(self):
|
||||
"""Test get device direction."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert component.current_direction is None
|
||||
|
||||
def test_dyson_get_speed_list(self):
|
||||
"""Test get speeds list."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert len(component.speed_list) == 11
|
||||
|
||||
def test_dyson_supported_features(self):
|
||||
"""Test supported features."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
assert component.supported_features == 3
|
||||
|
||||
def test_on_message(self):
|
||||
"""Test when message is received."""
|
||||
device = _get_device_on()
|
||||
component = dyson.DysonPureCoolLinkDevice(self.hass, device)
|
||||
component = dyson.DysonPureCoolLinkEntity(device)
|
||||
component.entity_id = "entity_id"
|
||||
component.schedule_update_ha_state = mock.Mock()
|
||||
component.on_message(MockDysonState())
|
||||
|
@ -788,7 +788,7 @@ async def test_purecool_update_state(devices, login, hass):
|
|||
|
||||
for call in device.add_message_listener.call_args_list:
|
||||
callback = call[0][0]
|
||||
if type(callback.__self__) == dyson.DysonPureCoolDevice:
|
||||
if type(callback.__self__) == dyson.DysonPureCoolEntity:
|
||||
callback(device.state)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
@ -849,7 +849,7 @@ async def test_purecool_update_state_filter_inv(devices, login, hass):
|
|||
|
||||
for call in device.add_message_listener.call_args_list:
|
||||
callback = call[0][0]
|
||||
if type(callback.__self__) == dyson.DysonPureCoolDevice:
|
||||
if type(callback.__self__) == dyson.DysonPureCoolEntity:
|
||||
callback(device.state)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue