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

Refactor fan in vesync #135744

Open
wants to merge 14 commits into
base: dev
Choose a base branch
from
8 changes: 7 additions & 1 deletion homeassistant/components/vesync/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from homeassistant.core import HomeAssistant

from .const import VeSyncHumidifierDevice
from .const import VeSyncFanDevice, VeSyncHumidifierDevice

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -58,6 +58,12 @@ def is_humidifier(device: VeSyncBaseDevice) -> bool:
return isinstance(device, VeSyncHumidifierDevice)


def is_fan(device: VeSyncBaseDevice) -> bool:
"""Check if the device represents a fan."""

return isinstance(device, VeSyncFanDevice)


def is_outlet(device: VeSyncBaseDevice) -> bool:
"""Check if the device represents an outlet."""

Expand Down
30 changes: 29 additions & 1 deletion homeassistant/components/vesync/const.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
"""Constants for VeSync Component."""

from pyvesync.vesyncfan import VeSyncHumid200300S, VeSyncSuperior6000S
from pyvesync.vesyncfan import (
VeSyncAir131,
VeSyncAirBaseV2,
VeSyncAirBypass,
VeSyncHumid200300S,
VeSyncSuperior6000S,
)

DOMAIN = "vesync"
VS_DISCOVERY = "vesync_discovery_{}"
Expand Down Expand Up @@ -29,9 +35,31 @@
VS_HUMIDIFIER_MODE_MANUAL = "manual"
VS_HUMIDIFIER_MODE_SLEEP = "sleep"

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"
VS_FAN_MODE_NORMAL = "normal"

# not a full list as manual is used as speed not present
VS_FAN_MODE_PRESET_LIST_HA = [
VS_FAN_MODE_AUTO,
VS_FAN_MODE_SLEEP,
VS_FAN_MODE_ADVANCED_SLEEP,
VS_FAN_MODE_TURBO,
VS_FAN_MODE_PET,
VS_FAN_MODE_NORMAL,
]

VeSyncHumidifierDevice = VeSyncHumid200300S | VeSyncSuperior6000S
"""Humidifier device types"""

VeSyncFanDevice = VeSyncAirBypass | VeSyncAirBypass | VeSyncAirBaseV2 | VeSyncAir131
"""Fan device types"""


DEV_TYPE_TO_HA = {
"wifi-switch-1.3": "outlet",
"ESW03-USA": "outlet",
Expand Down
133 changes: 56 additions & 77 deletions homeassistant/components/vesync/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,43 +19,27 @@
)
from homeassistant.util.scaling import int_states_in_range

from .common import is_fan
from .const import (
DEV_TYPE_TO_HA,
DOMAIN,
SKU_TO_BASE_DEVICE,
VS_COORDINATOR,
VS_DEVICES,
VS_DISCOVERY,
VS_FAN_MODE_ADVANCED_SLEEP,
VS_FAN_MODE_AUTO,
VS_FAN_MODE_MANUAL,
VS_FAN_MODE_NORMAL,
VS_FAN_MODE_PET,
VS_FAN_MODE_PRESET_LIST_HA,
VS_FAN_MODE_SLEEP,
VS_FAN_MODE_TURBO,
)
from .coordinator import VeSyncDataCoordinator
from .entity import VeSyncBaseEntity

_LOGGER = logging.getLogger(__name__)

FAN_MODE_AUTO = "auto"
FAN_MODE_SLEEP = "sleep"
FAN_MODE_PET = "pet"
FAN_MODE_TURBO = "turbo"
FAN_MODE_ADVANCED_SLEEP = "advancedSleep"
FAN_MODE_NORMAL = "normal"


PRESET_MODES = {
"LV-PUR131S": [FAN_MODE_AUTO, FAN_MODE_SLEEP],
"Core200S": [FAN_MODE_SLEEP],
"Core300S": [FAN_MODE_AUTO, FAN_MODE_SLEEP],
"Core400S": [FAN_MODE_AUTO, FAN_MODE_SLEEP],
"Core600S": [FAN_MODE_AUTO, FAN_MODE_SLEEP],
"EverestAir": [FAN_MODE_AUTO, FAN_MODE_SLEEP, FAN_MODE_TURBO],
"Vital200S": [FAN_MODE_AUTO, FAN_MODE_SLEEP, FAN_MODE_PET],
"Vital100S": [FAN_MODE_AUTO, FAN_MODE_SLEEP, FAN_MODE_PET],
"SmartTowerFan": [
FAN_MODE_ADVANCED_SLEEP,
FAN_MODE_AUTO,
FAN_MODE_TURBO,
FAN_MODE_NORMAL,
],
}
SPEED_RANGE = { # off is not included
"LV-PUR131S": (1, 3),
"Core200S": (1, 3),
Expand Down Expand Up @@ -97,13 +81,8 @@
coordinator: VeSyncDataCoordinator,
):
"""Check if device is fan and add entity."""
entities = [
VeSyncFanHA(dev, coordinator)
for dev in devices
if DEV_TYPE_TO_HA.get(SKU_TO_BASE_DEVICE.get(dev.device_type, "")) == "fan"
]

async_add_entities(entities, update_before_add=True)
async_add_entities(VeSyncFanHA(dev, coordinator) for dev in devices if is_fan(dev))


class VeSyncFanHA(VeSyncBaseEntity, FanEntity):
Expand All @@ -118,13 +97,6 @@
_attr_name = None
_attr_translation_key = "vesync"

def __init__(
self, fan: VeSyncBaseDevice, coordinator: VeSyncDataCoordinator
) -> None:
"""Initialize the VeSync fan device."""
super().__init__(fan, coordinator)
self.smartfan = fan

@property
def is_on(self) -> bool:
"""Return True if device is on."""
Expand All @@ -134,8 +106,8 @@
def percentage(self) -> int | None:
"""Return the current speed."""
if (
self.smartfan.mode == "manual"
and (current_level := self.smartfan.fan_level) is not None
self.device.mode == VS_FAN_MODE_MANUAL
and (current_level := self.device.fan_level) is not None
):
return ranged_value_to_percentage(
SPEED_RANGE[SKU_TO_BASE_DEVICE[self.device.device_type]], current_level
Expand All @@ -152,48 +124,54 @@
@property
def preset_modes(self) -> list[str]:
"""Get the list of available preset modes."""
return PRESET_MODES[SKU_TO_BASE_DEVICE[self.device.device_type]]
if hasattr(self.device, "modes"):
return sorted(
[
mode
for mode in self.device.modes
if mode in VS_FAN_MODE_PRESET_LIST_HA
]
)
return []

Check warning on line 135 in homeassistant/components/vesync/fan.py

View check run for this annotation

Codecov / codecov/patch

homeassistant/components/vesync/fan.py#L135

Added line #L135 was not covered by tests

@property
def preset_mode(self) -> str | None:
"""Get the current preset mode."""
if self.smartfan.mode in (FAN_MODE_AUTO, FAN_MODE_SLEEP, FAN_MODE_TURBO):
return self.smartfan.mode
if self.device.mode in VS_FAN_MODE_PRESET_LIST_HA:
return self.device.mode
return None

@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes of the fan."""
attr = {}

if hasattr(self.smartfan, "active_time"):
attr["active_time"] = self.smartfan.active_time
if hasattr(self.device, "active_time"):
attr["active_time"] = self.device.active_time

Check warning on line 150 in homeassistant/components/vesync/fan.py

View check run for this annotation

Codecov / codecov/patch

homeassistant/components/vesync/fan.py#L150

Added line #L150 was not covered by tests

if hasattr(self.smartfan, "screen_status"):
attr["screen_status"] = self.smartfan.screen_status
if hasattr(self.device, "screen_status"):
attr["screen_status"] = self.device.screen_status

if hasattr(self.smartfan, "child_lock"):
attr["child_lock"] = self.smartfan.child_lock
if hasattr(self.device, "child_lock"):
attr["child_lock"] = self.device.child_lock

if hasattr(self.smartfan, "night_light"):
attr["night_light"] = self.smartfan.night_light
if hasattr(self.device, "night_light"):
attr["night_light"] = self.device.night_light

if hasattr(self.smartfan, "mode"):
attr["mode"] = self.smartfan.mode
if hasattr(self.device, "mode"):
attr["mode"] = self.device.mode

return attr

def set_percentage(self, percentage: int) -> None:
"""Set the speed of the device."""
if percentage == 0:
self.smartfan.turn_off()
return

if not self.smartfan.is_on:
self.smartfan.turn_on()
self.device.turn_off()
elif not self.device.is_on:
self.device.turn_on()

Check warning on line 171 in homeassistant/components/vesync/fan.py

View check run for this annotation

Codecov / codecov/patch

homeassistant/components/vesync/fan.py#L169-L171

Added lines #L169 - L171 were not covered by tests

self.smartfan.manual_mode()
self.smartfan.change_fan_speed(
self.device.manual_mode()
self.device.change_fan_speed(

Check warning on line 174 in homeassistant/components/vesync/fan.py

View check run for this annotation

Codecov / codecov/patch

homeassistant/components/vesync/fan.py#L173-L174

Added lines #L173 - L174 were not covered by tests
math.ceil(
percentage_to_ranged_value(
SPEED_RANGE[SKU_TO_BASE_DEVICE[self.device.device_type]], percentage
Expand All @@ -204,27 +182,27 @@

def set_preset_mode(self, preset_mode: str) -> None:
"""Set the preset mode of device."""
if preset_mode not in self.preset_modes:
if preset_mode not in VS_FAN_MODE_PRESET_LIST_HA:

Check warning on line 185 in homeassistant/components/vesync/fan.py

View check run for this annotation

Codecov / codecov/patch

homeassistant/components/vesync/fan.py#L185

Added line #L185 was not covered by tests
raise ValueError(
f"{preset_mode} is not one of the valid preset modes: "
f"{self.preset_modes}"
f"{VS_FAN_MODE_PRESET_LIST_HA}"
)

if not self.smartfan.is_on:
self.smartfan.turn_on()

if preset_mode == FAN_MODE_AUTO:
self.smartfan.auto_mode()
elif preset_mode == FAN_MODE_SLEEP:
self.smartfan.sleep_mode()
elif preset_mode == FAN_MODE_ADVANCED_SLEEP:
self.smartfan.advanced_sleep_mode()
elif preset_mode == FAN_MODE_PET:
self.smartfan.pet_mode()
elif preset_mode == FAN_MODE_TURBO:
self.smartfan.turbo_mode()
elif preset_mode == FAN_MODE_NORMAL:
self.smartfan.normal_mode()
if not self.device.is_on:
self.device.turn_on()

Check warning on line 192 in homeassistant/components/vesync/fan.py

View check run for this annotation

Codecov / codecov/patch

homeassistant/components/vesync/fan.py#L191-L192

Added lines #L191 - L192 were not covered by tests

if preset_mode == VS_FAN_MODE_AUTO:
self.device.auto_mode()
elif preset_mode == VS_FAN_MODE_SLEEP:
self.device.sleep_mode()
elif preset_mode == VS_FAN_MODE_ADVANCED_SLEEP:
self.device.advanced_sleep_mode()
elif preset_mode == VS_FAN_MODE_PET:
self.device.pet_mode()
elif preset_mode == VS_FAN_MODE_TURBO:
self.device.turbo_mode()
elif preset_mode == VS_FAN_MODE_NORMAL:
self.device.normal_mode()

Check warning on line 205 in homeassistant/components/vesync/fan.py

View check run for this annotation

Codecov / codecov/patch

homeassistant/components/vesync/fan.py#L194-L205

Added lines #L194 - L205 were not covered by tests

self.schedule_update_ha_state()

Expand All @@ -245,3 +223,4 @@
def turn_off(self, **kwargs: Any) -> None:
"""Turn the device off."""
self.device.turn_off()
self.schedule_update_ha_state()

Check warning on line 226 in homeassistant/components/vesync/fan.py

View check run for this annotation

Codecov / codecov/patch

homeassistant/components/vesync/fan.py#L226

Added line #L226 was not covered by tests
6 changes: 3 additions & 3 deletions tests/components/vesync/snapshots/test_fan.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -620,8 +620,8 @@
'preset_modes': list([
'advancedSleep',
'auto',
'turbo',
'normal',
'turbo',
]),
}),
'config_entry_id': <ANY>,
Expand Down Expand Up @@ -661,12 +661,12 @@
'night_light': 'off',
'percentage': None,
'percentage_step': 7.6923076923076925,
'preset_mode': None,
'preset_mode': 'normal',
'preset_modes': list([
'advancedSleep',
'auto',
'turbo',
'normal',
'turbo',
]),
'screen_status': False,
'supported_features': <FanEntityFeature: 57>,
Expand Down