Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(deps): update dependency libdyson-wg/ha-dyson to v1.4.2 #907

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 15 additions & 24 deletions custom_components/dyson_local/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from .vendor.libdyson import (
Dyson360Eye,
Dyson360Heurist,
Dyson360VisNav,
DysonPureHotCool,
DysonPureHotCoolLink,
DysonPurifierHumidifyCool,
Expand Down Expand Up @@ -94,11 +95,8 @@ async def async_setup_account(hass: HomeAssistant, entry: ConfigEntry) -> bool:
DATA_ACCOUNT: account,
DATA_DEVICES: devices,
}
for component in PLATFORMS:
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, component)
)

await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True


Expand All @@ -113,7 +111,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
entry.data[CONF_DEVICE_TYPE],
)

if not isinstance(device, Dyson360Eye) and not isinstance(device, Dyson360Heurist):
if (not isinstance(device, Dyson360Eye)
and not isinstance(device, Dyson360Heurist)
and not isinstance(device, Dyson360VisNav)):
# Set up coordinator
async def async_update_data():
"""Poll environmental data from the device."""
Expand All @@ -132,12 +132,6 @@ async def async_update_data():
else:
coordinator = None

async def _async_forward_entry_setup():
for component in _async_get_platforms(device):
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, component)
)

def setup_entry(host: str, is_discovery: bool = True) -> bool:
try:
device.connect(host)
Expand All @@ -153,7 +147,7 @@ def setup_entry(host: str, is_discovery: bool = True) -> bool:
hass.data[DOMAIN][DATA_DEVICES][entry.entry_id] = device
hass.data[DOMAIN][DATA_COORDINATORS][entry.entry_id] = coordinator
asyncio.run_coroutine_threadsafe(
_async_forward_entry_setup(), hass.loop
hass.config_entries.async_forward_entry_setups(entry, _async_get_platforms(device)), hass.loop
).result()

host = entry.data.get(CONF_HOST)
Expand Down Expand Up @@ -184,26 +178,23 @@ def stop_discovery(_):

async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload Dyson local."""
device = hass.data[DOMAIN][DATA_DEVICES][entry.entry_id]
ok = all(
await asyncio.gather(
*[
hass.config_entries.async_forward_entry_unload(entry, component)
for component in _async_get_platforms(device)
]
)
)
if ok:
device: DysonDevice = hass.data[DOMAIN][DATA_DEVICES][entry.entry_id]

unload_ok = await hass.config_entries.async_unload_platforms(entry, _async_get_platforms(device))

if unload_ok:
hass.data[DOMAIN][DATA_DEVICES].pop(entry.entry_id)
hass.data[DOMAIN][DATA_COORDINATORS].pop(entry.entry_id)
await hass.async_add_executor_job(device.disconnect)
# TODO: stop discovery
return ok
return unload_ok


@callback
def _async_get_platforms(device: DysonDevice) -> List[str]:
if isinstance(device, Dyson360Eye) or isinstance(device, Dyson360Heurist):
if (isinstance(device, Dyson360Eye)
or isinstance(device, Dyson360Heurist)
or isinstance(device, Dyson360VisNav)):
return ["binary_sensor", "sensor", "vacuum"]
platforms = ["fan", "select", "sensor", "switch"]
if isinstance(device, DysonPureHotCool):
Expand Down
40 changes: 39 additions & 1 deletion custom_components/dyson_local/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

from typing import Callable

from .vendor.libdyson import Dyson360Eye, Dyson360Heurist, DysonPureHotCoolLink
from .vendor.libdyson import (
Dyson360Eye,
Dyson360Heurist,
Dyson360VisNav,
DysonPureHotCoolLink,
)

from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass,
Expand All @@ -29,6 +34,13 @@ async def async_setup_entry(
if isinstance(device, Dyson360Eye):
entities.append(DysonVacuumBatteryChargingSensor(device, name))
if isinstance(device, Dyson360Heurist):
entities.extend(
[
DysonVacuumBatteryChargingSensor(device, name),
Dyson360VisNavBinFullSensor(device, name),
]
)
if isinstance(device, Dyson360VisNav):
entities.extend(
[
DysonVacuumBatteryChargingSensor(device, name),
Expand Down Expand Up @@ -92,6 +104,32 @@ def sub_unique_id(self):
return "bin_full"


class Dyson360VisNavBinFullSensor(DysonEntity, BinarySensorEntity):
"""Dyson 360 VisNav bin full sensor."""

_attr_entity_category = EntityCategory.DIAGNOSTIC

@property
def is_on(self) -> bool:
"""Return if the sensor is on."""
return self._device.is_bin_full

@property
def icon(self) -> str:
"""Return the sensor icon."""
return ICON_BIN_FULL

@property
def sub_name(self) -> str:
"""Return the name of the sensor."""
return "Bin Full"

@property
def sub_unique_id(self):
"""Return the sensor's unique id."""
return "bin_full"


class DysonPureHotCoolLinkTiltSensor(DysonEntity, BinarySensorEntity):
"""Dyson Pure Hot+Cool Link tilt sensor."""

Expand Down
8 changes: 8 additions & 0 deletions custom_components/dyson_local/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ async def async_setup_entry(
class DysonClimateEntity(DysonEntity, ClimateEntity):
"""Dyson climate entity base class."""

_enable_turn_on_off_backwards_compatibility = False

@property
def hvac_mode(self) -> str:
"""Return hvac operation."""
Expand Down Expand Up @@ -76,6 +78,12 @@ def supported_features(self) -> int:
"""Return the list of supported features."""
return SUPPORT_FLAGS

def turn_on(self) -> None:
self._device.turn_on()

def turn_off(self) -> None:
self._device.turn_off()

@property
def temperature_unit(self) -> str:
"""Return the unit of measurement."""
Expand Down
10 changes: 9 additions & 1 deletion custom_components/dyson_local/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,13 @@

SPEED_RANGE = (1, 10)

COMMON_FEATURES = FanEntityFeature.OSCILLATE | FanEntityFeature.SET_SPEED | FanEntityFeature.PRESET_MODE
COMMON_FEATURES = (
FanEntityFeature.OSCILLATE
| FanEntityFeature.SET_SPEED
| FanEntityFeature.PRESET_MODE
| FanEntityFeature.TURN_ON
| FanEntityFeature.TURN_OFF
)


async def async_setup_entry(
Expand Down Expand Up @@ -82,6 +88,8 @@ async def async_setup_entry(
class DysonFanEntity(DysonEntity, FanEntity):
"""Dyson fan entity base class."""

_enable_turn_on_off_backwards_compatibility = False

_MESSAGE_TYPE = MessageType.STATE

@property
Expand Down
3 changes: 1 addition & 2 deletions custom_components/dyson_local/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,5 @@
"import_executor": true,
"iot_class": "local_push",
"issue_tracker": "https://github.com/libdyson-wg/ha-dyson/issues",
"version": "1.3.11",
"import_executor": true
"version": "1.4.2"
}
3 changes: 2 additions & 1 deletion custom_components/dyson_local/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .vendor.libdyson import (
Dyson360Eye,
Dyson360Heurist,
Dyson360VisNav,
DysonDevice,
DysonPureCoolLink,
DysonPurifierHumidifyCool,
Expand Down Expand Up @@ -44,7 +45,7 @@ async def async_setup_entry(
"""Set up Dyson sensor from a config entry."""
device = hass.data[DOMAIN][DATA_DEVICES][config_entry.entry_id]
name = config_entry.data[CONF_NAME]
if isinstance(device, Dyson360Eye) or isinstance(device, Dyson360Heurist):
if isinstance(device, Dyson360Eye) or isinstance(device, Dyson360Heurist) or isinstance(device, Dyson360VisNav):
entities = [DysonBatterySensor(device, name)]
else:
coordinator = hass.data[DOMAIN][DATA_COORDINATORS][config_entry.entry_id]
Expand Down
33 changes: 33 additions & 0 deletions custom_components/dyson_local/vacuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

from .vendor.libdyson import (
Dyson360Eye,
Dyson360VisNav,
VacuumEyePowerMode,
VacuumHeuristPowerMode,
VacuumVisNavPowerMode,
VacuumState,
)

Expand Down Expand Up @@ -68,6 +70,7 @@
VacuumState.MAPPING_NEEDS_CHARGE: "Mapping - Needs charging",
VacuumState.MAPPING_PAUSED: "Mapping - Paused",
VacuumState.MAPPING_RUNNING: "Mapping - Running",
VacuumState.MACHINE_OFF: "Off",
}

DYSON_STATES = {
Expand Down Expand Up @@ -103,6 +106,7 @@
VacuumState.MAPPING_NEEDS_CHARGE: STATE_RETURNING,
VacuumState.MAPPING_PAUSED: STATE_PAUSED,
VacuumState.MAPPING_RUNNING: STATE_CLEANING,
VacuumState.MACHINE_OFF: STATE_DOCKED,
}

EYE_POWER_MODE_ENUM_TO_STR = {
Expand All @@ -120,6 +124,15 @@
HEURIST_POWER_MODE_STR_TO_ENUM = {
value: key for key, value in HEURIST_POWER_MODE_ENUM_TO_STR.items()
}
VIS_NAV_POWER_MODE_ENUM_TO_STR = {
VacuumVisNavPowerMode.AUTO: "Auto",
VacuumVisNavPowerMode.QUICK: "Quick",
VacuumVisNavPowerMode.QUIET: "Quiet",
VacuumVisNavPowerMode.BOOST: "Boost",
}
VIS_NAV_POWER_MODE_STR_TO_ENUM = {
value: key for key, value in VIS_NAV_POWER_MODE_ENUM_TO_STR.items()
}

ATTR_POSITION = "position"

Expand All @@ -132,6 +145,8 @@ async def async_setup_entry(
name = config_entry.data[CONF_NAME]
if isinstance(device, Dyson360Eye):
entity = Dyson360EyeEntity(device, name)
elif isinstance(device, Dyson360VisNav): # Dyson360VisNav
entity = Dyson360VisNavEntity(device, name)
else: # Dyson360Heurist
entity = Dyson360HeuristEntity(device, name)
async_add_entities([entity])
Expand Down Expand Up @@ -230,3 +245,21 @@ def start(self) -> None:
def set_fan_speed(self, fan_speed: str, **kwargs) -> None:
"""Set fan speed."""
self._device.set_default_power_mode(HEURIST_POWER_MODE_STR_TO_ENUM[fan_speed])


class Dyson360VisNavEntity(Dyson360HeuristEntity):
"""Dyson 360 Vis Nav robot vacuum entity."""

@property
def fan_speed(self) -> str:
"""Return the fan speed of the vacuum cleaner."""
return VIS_NAV_POWER_MODE_ENUM_TO_STR[self._device.current_power_mode]

@property
def fan_speed_list(self) -> List[str]:
"""Get the list of available fan speed steps of the vacuum cleaner."""
return list(VIS_NAV_POWER_MODE_STR_TO_ENUM.keys())

def set_fan_speed(self, fan_speed: str, **kwargs) -> None:
"""Set fan speed."""
self._device.set_default_power_mode(VIS_NAV_POWER_MODE_STR_TO_ENUM[fan_speed])
6 changes: 6 additions & 0 deletions custom_components/dyson_local/vendor/libdyson/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from .const import (
DEVICE_TYPE_360_EYE,
DEVICE_TYPE_360_HEURIST,
DEVICE_TYPE_360_VIS_NAV,
DEVICE_TYPE_PURE_COOL,
DEVICE_TYPE_PURIFIER_COOL_E,
DEVICE_TYPE_PURIFIER_COOL_K,
Expand All @@ -27,11 +28,13 @@
from .const import MessageType # noqa: F401
from .const import VacuumEyePowerMode # noqa: F401
from .const import VacuumHeuristPowerMode # noqa: F401
from .const import VacuumVisNavPowerMode # noqa: F401
from .const import VacuumState # noqa: F401
from .const import WaterHardness # noqa: F401
from .discovery import DysonDiscovery # noqa: F401
from .dyson_360_eye import Dyson360Eye
from .dyson_360_heurist import Dyson360Heurist
from .dyson_360_vis_nav import Dyson360VisNav
from .dyson_device import DysonDevice
from .dyson_pure_cool import DysonPureCool
from .dyson_pure_cool_link import DysonPureCoolLink
Expand All @@ -48,6 +51,8 @@ def get_device(serial: str, credential: str, device_type: str) -> Optional[Dyson
return Dyson360Eye(serial, credential)
if device_type == DEVICE_TYPE_360_HEURIST:
return Dyson360Heurist(serial, credential)
if device_type == DEVICE_TYPE_360_VIS_NAV:
return Dyson360VisNav(serial, credential)
if device_type in [
DEVICE_TYPE_PURE_COOL_LINK_DESK,
DEVICE_TYPE_PURE_COOL_LINK,
Expand Down Expand Up @@ -79,3 +84,4 @@ def get_device(serial: str, credential: str, device_type: str) -> Optional[Dyson
}:
return DysonBigQuiet(serial, credential, device_type)
return None

Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

FILE_PATH = pathlib.Path(__file__).parent.absolute()


class HTTPBearerAuth(AuthBase):
"""Attaches HTTP Bearder Authentication to the given Request object."""

Expand Down
12 changes: 12 additions & 0 deletions custom_components/dyson_local/vendor/libdyson/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

DEVICE_TYPE_360_EYE = "N223"
DEVICE_TYPE_360_HEURIST = "276"
DEVICE_TYPE_360_VIS_NAV = "277"
DEVICE_TYPE_PURE_COOL_LINK_DESK = "469" # DP01? DP02? This one's a bit older, and scraping the Dyson website is unclear
DEVICE_TYPE_PURE_COOL_DESK = "520" # AM06? This one's also a bit older, and also hard to scrape off the Dyson website
DEVICE_TYPE_PURE_COOL_LINK = "475" # TP02
Expand All @@ -21,6 +22,7 @@
DEVICE_TYPE_NAMES = {
DEVICE_TYPE_360_EYE: "360 Eye robot vacuum",
DEVICE_TYPE_360_HEURIST: "360 Heurist robot vacuum",
DEVICE_TYPE_360_VIS_NAV: "360 Vis Nav robot vacuum",
DEVICE_TYPE_PURE_COOL: "Pure Cool",
DEVICE_TYPE_PURIFIER_COOL_K: "Purifier Cool",
DEVICE_TYPE_PURIFIER_COOL_E: "Purifier Cool",
Expand Down Expand Up @@ -111,6 +113,7 @@ class VacuumState(Enum):
MAPPING_NEEDS_CHARGE = "MAPPING_NEEDS_CHARGE"
MAPPING_PAUSED = "MAPPING_PAUSED"
MAPPING_RUNNING = "MAPPING_RUNNING"
MACHINE_OFF = "MACHINE_OFF"


class VacuumEyePowerMode(Enum):
Expand All @@ -128,6 +131,15 @@ class VacuumHeuristPowerMode(Enum):
MAX = "3"


class VacuumVisNavPowerMode(Enum):
"""Dyson 360 Heurist power mode."""

AUTO = "1"
QUICK = "2"
QUIET = "3"
BOOST = "4"


class CleaningType(Enum):
"""Vacuum cleaning type."""

Expand Down
Loading