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
140 changes: 136 additions & 4 deletions src/pyvesync/base_devices/fan_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from pyvesync.base_devices.vesyncbasedevice import DeviceState, VeSyncBaseToggleDevice
from pyvesync.const import FanFeatures, FanModes
from pyvesync.utils.helpers import OscillationCoordinates, OscillationRange

if TYPE_CHECKING:
from pyvesync import VeSync
Expand Down Expand Up @@ -48,23 +49,28 @@ class FanState(DeviceState):
"""

__slots__ = (
'_oscillation_status',
'child_lock',
'display_set_status',
'display_status',
'displaying_type',
'fan_level',
'fan_set_level',
'horizontal_oscillation_status',
'humidity',
'mode',
'mute_set_status',
'mute_status',
'oscillation_coordinates',
'oscillation_range',
'oscillation_set_status',
'oscillation_status',
'sleep_change_fan_level',
'sleep_fallasleep_remain',
'sleep_oscillation_switch',
'sleep_preference_type',
'temperature',
'thermal_comfort',
'vertical_oscillation_status',
)

def __init__(
Expand All @@ -84,20 +90,45 @@ def __init__(
self.mode: str = FanModes.UNKNOWN
self.fan_level: int | None = None
self.fan_set_level: int | None = None
self.humidity: int | None = None
self.temperature: int | None = None
self.child_lock: str | None = None
self.humidity: float | None = None
self.temperature: float | None = None
self.thermal_comfort: int | None = None
self.sleep_preference_type: str | None = None
self.sleep_fallasleep_remain: str | None = None
self.sleep_oscillation_switch: str | None = None
self.sleep_change_fan_level: str | None = None
self.mute_status: str | None = None
self.mute_set_status: str | None = None
self.oscillation_status: str | None = None
self.horizontal_oscillation_status: str | None = None
self.vertical_oscillation_status: str | None = None
self._oscillation_status: str | None = None
self.oscillation_set_status: str | None = None
self.display_status: str | None = None
self.display_set_status: str | None = None
self.displaying_type: str | None = None
self.oscillation_coordinates: OscillationCoordinates | None = None
if FanFeatures.SET_OSCILLATION_RANGE in feature_map.features:
self.oscillation_range: OscillationRange | None = OscillationRange(
left=0, right=0, top=0, bottom=0
)
else:
self.oscillation_range = None

@property
def oscillation_status(self) -> str | None:
"""Get oscillation status.

Returns:
str | None: Oscillation status.
"""
if self.horizontal_oscillation_status and self.vertical_oscillation_status:
return self.horizontal_oscillation_status or self.vertical_oscillation_status
return self._oscillation_status

@oscillation_status.setter
def oscillation_status(self, value: str | None) -> None:
self._oscillation_status = value


class VeSyncFanBase(VeSyncBaseToggleDevice):
Expand Down Expand Up @@ -147,6 +178,21 @@ def supports_oscillation(self) -> bool:
"""Return True if device supports oscillation."""
return FanFeatures.OSCILLATION in self.features

@property
def supports_set_oscillation_range(self) -> bool:
"""Return True if device supports setting oscillation range."""
return FanFeatures.SET_OSCILLATION_RANGE in self.features

@property
def supports_vertical_oscillation(self) -> bool:
"""Return True if device supports vertical oscillation."""
return FanFeatures.VERTICAL_OSCILLATION in self.features

@property
def supports_horizontal_oscillation(self) -> bool:
"""Return True if device supports horizontal oscillation."""
return FanFeatures.HORIZONTAL_OSCILLATION in self.features

@property
def supports_mute(self) -> bool:
"""Return True if device supports mute."""
Expand Down Expand Up @@ -323,6 +369,92 @@ async def turn_off_oscillation(self) -> bool:
"""Set toggle_oscillation to off."""
return await self.toggle_oscillation(False)

async def toggle_vertical_oscillation(self, toggle: bool) -> bool:
"""Toggle Vertical Oscillation on/off.

Args:
toggle (bool): Vertical Oscillation state.

Returns:
bool: true if success.
"""
del toggle
if self.supports_vertical_oscillation:
logger.debug('Vertical Oscillation not configured for this device.')
else:
logger.debug('Vertical Oscillation not supported for this device.')
return False

async def turn_on_vertical_oscillation(self) -> bool:
"""Set toggle_vertical_oscillation to on."""
return await self.toggle_vertical_oscillation(True)

async def turn_off_vertical_oscillation(self) -> bool:
"""Set toggle_vertical_oscillation to off."""
return await self.toggle_vertical_oscillation(False)

async def toggle_horizontal_oscillation(self, toggle: bool) -> bool:
"""Toggle Horizontal Oscillation on/off.

Args:
toggle (bool): Horizontal Oscillation state.

Returns:
bool: true if success.
"""
del toggle
if self.supports_horizontal_oscillation:
logger.debug('Horizontal Oscillation not configured for this device.')
else:
logger.debug('Horizontal Oscillation not supported for this device.')
return False

async def turn_on_horizontal_oscillation(self) -> bool:
"""Set toggle_horizontal_oscillation to on."""
return await self.toggle_horizontal_oscillation(True)

async def turn_off_horizontal_oscillation(self) -> bool:
"""Set toggle_horizontal_oscillation to off."""
return await self.toggle_horizontal_oscillation(False)

async def set_vertical_oscillation_range(
self, *, top: int = 0, bottom: int = 0
) -> bool:
"""Set Vertical Oscillation Range.

Args:
top (int): Top range.
bottom (int): Bottom range.

Returns:
bool: true if success.
"""
del top, bottom
if self.supports_set_oscillation_range:
logger.debug('Vertical oscillation range not configured for this device.')
else:
logger.debug('Vertical oscillation range not supported for this device.')
return False

async def set_horizontal_oscillation_range(
self, *, left: int = 0, right: int = 0
) -> bool:
"""Set Horizontal Oscillation Range.

Args:
left (int): Left range.
right (int): Right range.

Returns:
bool: true if success.
"""
del left, right
if self.supports_set_oscillation_range:
logger.debug('Horizontal oscillation range not configured for this device.')
else:
logger.debug('Horizontal oscillation range not supported for this device.')
return False

async def toggle_mute(self, toggle: bool) -> bool:
"""Toggle mute on/off.

Expand Down
4 changes: 4 additions & 0 deletions src/pyvesync/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -604,8 +604,11 @@ class FanFeatures(Features):
"""VeSync fan features."""

OSCILLATION = 'oscillation'
SET_OSCILLATION_RANGE = 'set_oscillation_range'
SOUND = 'sound'
DISPLAYING_TYPE = 'displaying_type' # Unknown functionality
HORIZONTAL_OSCILLATION = 'horizontal_oscillation'
VERTICAL_OSCILLATION = 'vertical_oscillation'


# Modes
Expand Down Expand Up @@ -675,6 +678,7 @@ class FanModes(StrEnum):
SLEEP = 'advancedSleep'
TURBO = 'turbo'
PET = 'pet'
ECO = 'eco'
UNKNOWN = 'unknown'
ADVANCED_SLEEP = 'advancedSleep'

Expand Down
27 changes: 27 additions & 0 deletions src/pyvesync/device_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,33 @@ class ThermostatMap(DeviceMapTemplate):
model_name='Classic 42-Inch Tower Fan',
setup_entry='LTF-F422S',
),
FanMap(
class_name='VeSyncPedestalFan',
dev_types=['LPF-R432S-AEU', 'LPF-R432S-AUS'],
modes=[
FanModes.NORMAL,
FanModes.TURBO,
FanModes.ECO,
FanModes.ADVANCED_SLEEP,
],
setup_entry='LPF-R423S',
features=[
FanFeatures.SET_OSCILLATION_RANGE,
FanFeatures.HORIZONTAL_OSCILLATION,
FanFeatures.VERTICAL_OSCILLATION,
],
fan_levels=list(range(1, 13)),
set_mode_method='setFanMode',
device_alias='Pedestal Fan',
sleep_preferences=[
FanSleepPreference.DEFAULT,
FanSleepPreference.ADVANCED,
FanSleepPreference.TURBO,
FanSleepPreference.QUIET,
], # Unknown sleep preferences, need to be verified
model_display='LPF-R432S Pedestal Fan Series',
model_name='Pedestal Fan',
),
]
"""List of ['FanMap'][pyvesync.device_map.FanMap] configuration
objects for fan devices."""
Expand Down
Loading