Skip to content
Merged
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
2 changes: 0 additions & 2 deletions homeassistant/components/vesync/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@

VS_FAN_MODE_AUTO = "auto"
VS_FAN_MODE_SLEEP = "sleep"
VS_FAN_MODE_ADVANCED_SLEEP = "advancedSleep"
VS_FAN_MODE_TURBO = "turbo"
VS_FAN_MODE_PET = "pet"
VS_FAN_MODE_MANUAL = "manual"
Expand All @@ -42,7 +41,6 @@
VS_FAN_MODE_PRESET_LIST_HA = [
VS_FAN_MODE_AUTO,
VS_FAN_MODE_SLEEP,
VS_FAN_MODE_ADVANCED_SLEEP,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this removal intentional?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Library converted that into sleep. It previously didn't work either way. It is fixed now.

VS_FAN_MODE_TURBO,
VS_FAN_MODE_PET,
VS_FAN_MODE_NORMAL,
Expand Down
101 changes: 64 additions & 37 deletions homeassistant/components/vesync/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
import logging
from typing import Any

from pyvesync.base_devices.vesyncbasedevice import VeSyncBaseDevice
from pyvesync.device_container import DeviceContainer
from pyvesync.base_devices import VeSyncFanBase, VeSyncPurifier

from homeassistant.components.fan import FanEntity, FanEntityFeature
from homeassistant.core import HomeAssistant, callback
Expand All @@ -22,7 +21,6 @@
from .const import (
VS_DEVICES,
VS_DISCOVERY,
VS_FAN_MODE_ADVANCED_SLEEP,
VS_FAN_MODE_AUTO,
VS_FAN_MODE_MANUAL,
VS_FAN_MODE_NORMAL,
Expand All @@ -40,7 +38,6 @@
VS_TO_HA_MODE_MAP = {
VS_FAN_MODE_AUTO: VS_FAN_MODE_AUTO,
VS_FAN_MODE_SLEEP: VS_FAN_MODE_SLEEP,
VS_FAN_MODE_ADVANCED_SLEEP: "advanced_sleep",
VS_FAN_MODE_TURBO: VS_FAN_MODE_TURBO,
VS_FAN_MODE_PET: VS_FAN_MODE_PET,
VS_FAN_MODE_MANUAL: VS_FAN_MODE_MANUAL,
Expand All @@ -60,26 +57,33 @@ async def async_setup_entry(
coordinator = config_entry.runtime_data

@callback
def discover(devices: list[VeSyncBaseDevice]) -> None:
def discover(devices: list[VeSyncFanBase | VeSyncPurifier]) -> None:
"""Add new devices to platform."""
_setup_entities(devices, async_add_entities, coordinator)
_setup_entities(
[dev for dev in devices if is_fan(dev) or is_purifier(dev)],
async_add_entities,
coordinator,
)

config_entry.async_on_unload(
async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_DEVICES), discover)
)

_setup_entities(
config_entry.runtime_data.manager.devices, async_add_entities, coordinator
config_entry.runtime_data.manager.devices.air_purifiers
+ config_entry.runtime_data.manager.devices.fans,
async_add_entities,
coordinator,
)


@callback
def _setup_entities(
devices: DeviceContainer | list[VeSyncBaseDevice],
devices: list[VeSyncFanBase | VeSyncPurifier],
async_add_entities: AddConfigEntryEntitiesCallback,
coordinator: VeSyncDataCoordinator,
) -> None:
"""Check if device is fan and add entity."""
"""Check if device is fan or purifier and add entity."""

async_add_entities(
VeSyncFanHA(dev, coordinator)
Expand All @@ -95,7 +99,7 @@ def _get_ha_mode(vs_mode: str) -> str | None:
return ha_mode


class VeSyncFanHA(VeSyncBaseEntity, FanEntity):
class VeSyncFanHA(VeSyncBaseEntity[VeSyncFanBase | VeSyncPurifier], FanEntity):
"""Representation of a VeSync fan."""

_attr_supported_features = (
Expand All @@ -109,7 +113,7 @@ class VeSyncFanHA(VeSyncBaseEntity, FanEntity):

def __init__(
self,
device: VeSyncBaseDevice,
device: VeSyncFanBase | VeSyncPurifier,
coordinator: VeSyncDataCoordinator,
) -> None:
"""Initialize the fan."""
Expand Down Expand Up @@ -179,7 +183,7 @@ def preset_mode(self) -> str | None:
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes of the fan."""
attr = {}
attr: dict[str, Any] = {}

if hasattr(self.device.state, "active_time"):
attr["active_time"] = self.device.state.active_time
Expand Down Expand Up @@ -219,37 +223,47 @@ async def async_set_percentage(self, percentage: int) -> None:
if percentage == 0:
# Turning off is a special case: do not set speed or mode
if not await self.device.turn_off():
raise HomeAssistantError(
"An error occurred while turning off: "
+ self.device.last_response.message
)
if self.device.last_response:
raise HomeAssistantError(
"An error occurred while turning off: "
+ self.device.last_response.message
)
raise HomeAssistantError("Failed to turn off fan, no response found.")
self.async_write_ha_state()
return

# If the fan is off, turn it on first
if not self.device.is_on:
if not await self.device.turn_on():
raise HomeAssistantError(
"An error occurred while turning on: "
+ self.device.last_response.message
)
if self.device.last_response:
raise HomeAssistantError(
"An error occurred while turning on: "
+ self.device.last_response.message
)
raise HomeAssistantError("Failed to turn on fan, no response found.")

# Switch to manual mode if not already set
if self.device.state.mode not in (VS_FAN_MODE_MANUAL, VS_FAN_MODE_NORMAL):
if not await self.device.set_manual_mode():
if self.device.last_response:
raise HomeAssistantError(
"An error occurred while setting manual mode."
+ self.device.last_response.message
)
raise HomeAssistantError(
"An error occurred while setting manual mode."
+ self.device.last_response.message
"Failed to set manual mode, no response found."
)

# Calculate the speed level and set it
if not await self.device.set_fan_speed(
percentage_to_ordered_list_item(self.device.fan_levels, percentage)
):
raise HomeAssistantError(
"An error occurred while changing fan speed: "
+ self.device.last_response.message
)
if self.device.last_response:
raise HomeAssistantError(
"An error occurred while changing fan speed: "
+ self.device.last_response.message
)
raise HomeAssistantError("Failed to set fan speed, no response found.")

self.async_write_ha_state()

Expand All @@ -270,17 +284,19 @@ async def async_set_preset_mode(self, preset_mode: str) -> None:
success = await self.device.set_auto_mode()
elif vs_mode == VS_FAN_MODE_SLEEP:
success = await self.device.set_sleep_mode()
elif vs_mode == VS_FAN_MODE_ADVANCED_SLEEP:
success = await self.device.set_advanced_sleep_mode()
elif vs_mode == VS_FAN_MODE_PET:
success = await self.device.set_pet_mode()
if hasattr(self.device, "set_pet_mode"):
success = await self.device.set_pet_mode()
elif vs_mode == VS_FAN_MODE_TURBO:
success = await self.device.set_turbo_mode()
elif vs_mode == VS_FAN_MODE_NORMAL:
success = await self.device.set_normal_mode()
if hasattr(self.device, "set_normal_mode"):
success = await self.device.set_normal_mode()

if not success:
raise HomeAssistantError(self.device.last_response.message)
if self.device.last_response:
raise HomeAssistantError(self.device.last_response.message)
raise HomeAssistantError("Failed to set preset mode, no response found.")

self.async_write_ha_state()

Expand All @@ -297,7 +313,9 @@ async def async_turn_on(
if percentage is None:
success = await self.device.turn_on()
if not success:
raise HomeAssistantError(self.device.last_response.message)
if self.device.last_response:
raise HomeAssistantError(self.device.last_response.message)
raise HomeAssistantError("Failed to turn on fan, no response found.")
self.async_write_ha_state()
else:
await self.async_set_percentage(percentage)
Expand All @@ -306,12 +324,21 @@ async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the device off."""
success = await self.device.turn_off()
if not success:
raise HomeAssistantError(self.device.last_response.message)
if self.device.last_response:
raise HomeAssistantError(self.device.last_response.message)
raise HomeAssistantError("Failed to turn off fan, no response found.")
self.async_write_ha_state()

async def async_oscillate(self, oscillating: bool) -> None:
"""Set oscillation."""
success = await self.device.toggle_oscillation(oscillating)
if not success:
raise HomeAssistantError(self.device.last_response.message)
self.async_write_ha_state()
if hasattr(self.device, "toggle_oscillation"):
success = await self.device.toggle_oscillation(oscillating)
if not success:
if self.device.last_response:
raise HomeAssistantError(self.device.last_response.message)
raise HomeAssistantError(
"Failed to set oscillation, no response found."
)
self.async_write_ha_state()
else:
raise HomeAssistantError("Oscillation not supported by this device.")
46 changes: 33 additions & 13 deletions homeassistant/components/vesync/humidifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import logging
from typing import TYPE_CHECKING, Any

from pyvesync.base_devices.vesyncbasedevice import VeSyncBaseDevice
from pyvesync.base_devices.humidifier_base import VeSyncHumidifier

from homeassistant.components.humidifier import (
MODE_AUTO,
Expand All @@ -17,6 +17,7 @@
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from .common import is_humidifier
from .const import (
VS_DEVICES,
VS_DISCOVERY,
Expand Down Expand Up @@ -51,24 +52,32 @@ async def async_setup_entry(
coordinator = config_entry.runtime_data

@callback
def discover(devices: list[VeSyncBaseDevice]) -> None:
def discover(devices: list[VeSyncHumidifier]) -> None:
"""Add new devices to platform."""
_setup_entities(devices, async_add_entities, coordinator)
_setup_entities(
[dev for dev in devices if is_humidifier(dev)],
async_add_entities,
coordinator,
)

config_entry.async_on_unload(
async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_DEVICES), discover)
)

_setup_entities(
config_entry.runtime_data.manager.devices.humidifiers,
[
dev
for dev in config_entry.runtime_data.manager.devices.humidifiers
if is_humidifier(dev)
],
async_add_entities,
coordinator,
)


@callback
def _setup_entities(
devices: list[VeSyncBaseDevice],
devices: list[VeSyncHumidifier],
async_add_entities: AddConfigEntryEntitiesCallback,
coordinator: VeSyncDataCoordinator,
) -> None:
Expand All @@ -83,7 +92,7 @@ def _get_ha_mode(vs_mode: str) -> str | None:
return ha_mode


class VeSyncHumidifierHA(VeSyncBaseEntity, HumidifierEntity):
class VeSyncHumidifierHA(VeSyncBaseEntity[VeSyncHumidifier], HumidifierEntity):
"""Representation of a VeSync humidifier."""

# The base VeSyncBaseEntity has _attr_has_entity_name and this is to follow the device name
Expand All @@ -95,7 +104,7 @@ class VeSyncHumidifierHA(VeSyncBaseEntity, HumidifierEntity):

def __init__(
self,
device: VeSyncBaseDevice,
device: VeSyncHumidifier,
coordinator: VeSyncDataCoordinator,
) -> None:
"""Initialize the VeSyncHumidifierHA device."""
Expand All @@ -119,8 +128,8 @@ def __init__(

self._available_modes.sort()

def _get_vs_mode(self, ha_mode: str) -> str | None:
return self._ha_to_vs_mode_map.get(ha_mode)
def _get_vs_mode(self, ha_mode: str) -> str:
return self._ha_to_vs_mode_map[ha_mode]

@property
def available_modes(self) -> list[str]:
Expand Down Expand Up @@ -153,16 +162,23 @@ def mode(self) -> str | None:
async def async_set_humidity(self, humidity: int) -> None:
"""Set the target humidity of the device."""
if not await self.device.set_humidity(humidity):
raise HomeAssistantError(self.device.last_response.message)
if self.device.last_response:
raise HomeAssistantError(self.device.last_response.message)
raise HomeAssistantError("Failed to set humidity.")

async def async_set_mode(self, mode: str) -> None:
"""Set the mode of the device."""
if mode not in self.available_modes:
raise HomeAssistantError(
f"Invalid mode {mode}. Available modes: {self.available_modes}"
)
set_mode = self._get_vs_mode(mode)
if set_mode is None:
raise HomeAssistantError(f"Could not map mode {mode} to VeSync mode.")
if not await self.device.set_mode(self._get_vs_mode(mode)):
raise HomeAssistantError(self.device.last_response.message)
if self.device.last_response:
raise HomeAssistantError(self.device.last_response.message)
raise HomeAssistantError("Failed to set mode.")

if mode == MODE_SLEEP:
# We successfully changed the mode. Consider it a success even if display operation fails.
Expand All @@ -174,15 +190,19 @@ async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the device on."""
success = await self.device.turn_on()
if not success:
raise HomeAssistantError(self.device.last_response.message)
if self.device.last_response:
raise HomeAssistantError(self.device.last_response.message)
raise HomeAssistantError("Failed to turn on humidifier.")

self.async_write_ha_state()

async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the device off."""
success = await self.device.turn_off()
if not success:
raise HomeAssistantError(self.device.last_response.message)
if self.device.last_response:
raise HomeAssistantError(self.device.last_response.message)
raise HomeAssistantError("Failed to turn off humidifier.")

self.async_write_ha_state()

Expand Down
Loading
Loading