Complete fan speed transition from #59781 (#67743)

This commit is contained in:
J. Nick Koston 2022-03-09 10:38:12 +01:00 committed by GitHub
parent c6952a0ee3
commit 723dcbafca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
58 changed files with 303 additions and 847 deletions

View file

@ -10,7 +10,6 @@ from homeassistant.components.climate.const import (
HVAC_MODE_HEAT, HVAC_MODE_HEAT,
HVAC_MODE_OFF, HVAC_MODE_OFF,
) )
from homeassistant.components.fan import SPEED_HIGH, SPEED_LOW, SPEED_OFF
from homeassistant.const import Platform from homeassistant.const import Platform
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -21,7 +20,6 @@ CLIMATE_SUPPORTED_FANSTATES = [FAN_OFF, FAN_LOW, FAN_MEDIUM, FAN_HIGH]
CLIMATE_SUPPORTED_MODES = [HVAC_MODE_AUTO, HVAC_MODE_HEAT, HVAC_MODE_OFF] CLIMATE_SUPPORTED_MODES = [HVAC_MODE_AUTO, HVAC_MODE_HEAT, HVAC_MODE_OFF]
CONF_SYNC_TIME = "sync_time" CONF_SYNC_TIME = "sync_time"
DEFAULT_SYNC_TIME = False DEFAULT_SYNC_TIME = False
FAN_SUPPORTED_SPEEDS = [SPEED_OFF, SPEED_LOW, SPEED_HIGH]
PLATFORMS = [Platform.BINARY_SENSOR, Platform.CLIMATE] PLATFORMS = [Platform.BINARY_SENSOR, Platform.CLIMATE]
AUX = "Aux" AUX = "Aux"

View file

@ -10,7 +10,6 @@ from bond_api import Action, BPUPSubscriptions, DeviceType, Direction
import voluptuous as vol import voluptuous as vol
from homeassistant.components.fan import ( from homeassistant.components.fan import (
ATTR_SPEED,
DIRECTION_FORWARD, DIRECTION_FORWARD,
DIRECTION_REVERSE, DIRECTION_REVERSE,
SUPPORT_DIRECTION, SUPPORT_DIRECTION,
@ -57,7 +56,7 @@ async def async_setup_entry(
platform.async_register_entity_service( platform.async_register_entity_service(
SERVICE_SET_FAN_SPEED_TRACKED_STATE, SERVICE_SET_FAN_SPEED_TRACKED_STATE,
{vol.Required(ATTR_SPEED): vol.All(vol.Number(scale=0), vol.Range(0, 100))}, {vol.Required("speed"): vol.All(vol.Number(scale=0), vol.Range(0, 100))},
"async_set_speed_belief", "async_set_speed_belief",
) )
@ -107,7 +106,9 @@ class BondFan(BondEntity, FanEntity):
"""Return the current speed percentage for the fan.""" """Return the current speed percentage for the fan."""
if not self._speed or not self._power: if not self._speed or not self._power:
return 0 return 0
return ranged_value_to_percentage(self._speed_range, self._speed) return min(
100, max(0, ranged_value_to_percentage(self._speed_range, self._speed))
)
@property @property
def speed_count(self) -> int: def speed_count(self) -> int:
@ -183,7 +184,6 @@ class BondFan(BondEntity, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs: Any, **kwargs: Any,

View file

@ -120,7 +120,6 @@ class ComfoConnectFan(FanEntity):
def turn_on( def turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs, **kwargs,

View file

@ -13,15 +13,7 @@ from pydeconz.light import (
Fan, Fan,
) )
from homeassistant.components.fan import ( from homeassistant.components.fan import DOMAIN, SUPPORT_SET_SPEED, FanEntity
DOMAIN,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
SUPPORT_SET_SPEED,
FanEntity,
)
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
@ -41,19 +33,6 @@ ORDERED_NAMED_FAN_SPEEDS = [
FAN_SPEED_100_PERCENT, FAN_SPEED_100_PERCENT,
] ]
LEGACY_SPEED_TO_DECONZ = {
SPEED_OFF: FAN_SPEED_OFF,
SPEED_LOW: FAN_SPEED_25_PERCENT,
SPEED_MEDIUM: FAN_SPEED_50_PERCENT,
SPEED_HIGH: FAN_SPEED_100_PERCENT,
}
LEGACY_DECONZ_TO_SPEED = {
FAN_SPEED_OFF: SPEED_OFF,
FAN_SPEED_25_PERCENT: SPEED_LOW,
FAN_SPEED_50_PERCENT: SPEED_MEDIUM,
FAN_SPEED_100_PERCENT: SPEED_HIGH,
}
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
@ -130,41 +109,6 @@ class DeconzFan(DeconzDevice, FanEntity):
"""Return the number of speeds the fan supports.""" """Return the number of speeds the fan supports."""
return len(ORDERED_NAMED_FAN_SPEEDS) return len(ORDERED_NAMED_FAN_SPEEDS)
@property
def speed_list(self) -> list:
"""Get the list of available speeds.
Legacy fan support.
"""
return list(LEGACY_SPEED_TO_DECONZ)
def speed_to_percentage(self, speed: str) -> int:
"""Convert speed to percentage.
Legacy fan support.
"""
if speed == SPEED_OFF:
return 0
if speed not in LEGACY_SPEED_TO_DECONZ:
speed = SPEED_MEDIUM
return ordered_list_item_to_percentage(
ORDERED_NAMED_FAN_SPEEDS, LEGACY_SPEED_TO_DECONZ[speed]
)
def percentage_to_speed(self, percentage: int) -> str:
"""Convert percentage to speed.
Legacy fan support.
"""
if percentage == 0:
return SPEED_OFF
return LEGACY_DECONZ_TO_SPEED.get(
percentage_to_ordered_list_item(ORDERED_NAMED_FAN_SPEEDS, percentage),
SPEED_MEDIUM,
)
@callback @callback
def async_update_callback(self) -> None: def async_update_callback(self) -> None:
"""Store latest configured speed from the device.""" """Store latest configured speed from the device."""
@ -174,36 +118,23 @@ class DeconzFan(DeconzDevice, FanEntity):
async def async_set_percentage(self, percentage: int) -> None: async def async_set_percentage(self, percentage: int) -> None:
"""Set the speed percentage of the fan.""" """Set the speed percentage of the fan."""
if percentage == 0:
return await self.async_turn_off()
await self._device.set_speed( await self._device.set_speed(
percentage_to_ordered_list_item(ORDERED_NAMED_FAN_SPEEDS, percentage) percentage_to_ordered_list_item(ORDERED_NAMED_FAN_SPEEDS, percentage)
) )
async def async_set_speed(self, speed: str) -> None:
"""Set the speed of the fan.
Legacy fan support.
"""
if speed not in LEGACY_SPEED_TO_DECONZ:
raise ValueError(f"Unsupported speed {speed}")
await self._device.set_speed(LEGACY_SPEED_TO_DECONZ[speed])
async def async_turn_on( async def async_turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs: Any, **kwargs: Any,
) -> None: ) -> None:
"""Turn on fan.""" """Turn on fan."""
new_speed = self._default_on_speed
if percentage is not None: if percentage is not None:
new_speed = percentage_to_ordered_list_item( await self.async_set_percentage(percentage)
ORDERED_NAMED_FAN_SPEEDS, percentage return
) await self._device.set_speed(self._default_on_speed)
await self._device.set_speed(new_speed)
async def async_turn_off(self, **kwargs: Any) -> None: async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off fan.""" """Turn off fan."""

View file

@ -196,7 +196,6 @@ class DemoPercentageFan(BaseDemoFan, FanEntity):
def turn_on( def turn_on(
self, self,
speed: str = None,
percentage: int = None, percentage: int = None,
preset_mode: str = None, preset_mode: str = None,
**kwargs, **kwargs,
@ -267,7 +266,6 @@ class AsyncDemoPercentageFan(BaseDemoFan, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str = None,
percentage: int = None, percentage: int = None,
preset_mode: str = None, preset_mode: str = None,
**kwargs, **kwargs,

View file

@ -26,14 +26,7 @@ from homeassistant.components.cover import (
ATTR_POSITION, ATTR_POSITION,
SUPPORT_SET_POSITION, SUPPORT_SET_POSITION,
) )
from homeassistant.components.fan import ( from homeassistant.components.fan import ATTR_PERCENTAGE, SUPPORT_SET_SPEED
ATTR_SPEED,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
SUPPORT_SET_SPEED,
)
from homeassistant.components.http import HomeAssistantView from homeassistant.components.http import HomeAssistantView
from homeassistant.components.humidifier.const import ( from homeassistant.components.humidifier.const import (
ATTR_HUMIDITY, ATTR_HUMIDITY,
@ -540,14 +533,7 @@ class HueOneLightChangeView(HomeAssistantView):
): ):
domain = entity.domain domain = entity.domain
# Convert 0-100 to a fan speed # Convert 0-100 to a fan speed
if (brightness := parsed[STATE_BRIGHTNESS]) == 0: data[ATTR_PERCENTAGE] = parsed[STATE_BRIGHTNESS]
data[ATTR_SPEED] = SPEED_OFF
elif 0 < brightness <= 33.3:
data[ATTR_SPEED] = SPEED_LOW
elif 33.3 < brightness <= 66.6:
data[ATTR_SPEED] = SPEED_MEDIUM
elif 66.6 < brightness <= 100:
data[ATTR_SPEED] = SPEED_HIGH
# Map the off command to on # Map the off command to on
if entity.domain in config.off_maps_to_on_domains: if entity.domain in config.off_maps_to_on_domains:
@ -679,15 +665,9 @@ def get_entity_state(config, entity):
# Convert 0.0-1.0 to 0-254 # Convert 0.0-1.0 to 0-254
data[STATE_BRIGHTNESS] = round(min(1.0, level) * HUE_API_STATE_BRI_MAX) data[STATE_BRIGHTNESS] = round(min(1.0, level) * HUE_API_STATE_BRI_MAX)
elif entity.domain == fan.DOMAIN: elif entity.domain == fan.DOMAIN:
speed = entity.attributes.get(ATTR_SPEED, 0) percentage = entity.attributes.get(ATTR_PERCENTAGE) or 0
# Convert 0.0-1.0 to 0-254 # Convert 0-100 to 0-254
data[STATE_BRIGHTNESS] = 0 data[STATE_BRIGHTNESS] = round(percentage * HUE_API_STATE_BRI_MAX / 100)
if speed == SPEED_LOW:
data[STATE_BRIGHTNESS] = 85
elif speed == SPEED_MEDIUM:
data[STATE_BRIGHTNESS] = 170
elif speed == SPEED_HIGH:
data[STATE_BRIGHTNESS] = HUE_API_STATE_BRI_MAX
elif entity.domain == cover.DOMAIN: elif entity.domain == cover.DOMAIN:
level = entity.attributes.get(ATTR_CURRENT_POSITION, 0) level = entity.attributes.get(ATTR_CURRENT_POSITION, 0)
data[STATE_BRIGHTNESS] = round(level / 100 * HUE_API_STATE_BRI_MAX) data[STATE_BRIGHTNESS] = round(level / 100 * HUE_API_STATE_BRI_MAX)

View file

@ -92,7 +92,6 @@ class EsphomeFan(EsphomeEntity[FanInfo, FanState], FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs: Any, **kwargs: Any,

View file

@ -28,8 +28,6 @@ from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from homeassistant.loader import bind_hass from homeassistant.loader import bind_hass
from homeassistant.util.percentage import ( from homeassistant.util.percentage import (
ordered_list_item_to_percentage,
percentage_to_ordered_list_item,
percentage_to_ranged_value, percentage_to_ranged_value,
ranged_value_to_percentage, ranged_value_to_percentage,
) )
@ -47,7 +45,6 @@ SUPPORT_OSCILLATE = 2
SUPPORT_DIRECTION = 4 SUPPORT_DIRECTION = 4
SUPPORT_PRESET_MODE = 8 SUPPORT_PRESET_MODE = 8
SERVICE_SET_SPEED = "set_speed"
SERVICE_INCREASE_SPEED = "increase_speed" SERVICE_INCREASE_SPEED = "increase_speed"
SERVICE_DECREASE_SPEED = "decrease_speed" SERVICE_DECREASE_SPEED = "decrease_speed"
SERVICE_OSCILLATE = "oscillate" SERVICE_OSCILLATE = "oscillate"
@ -55,37 +52,16 @@ SERVICE_SET_DIRECTION = "set_direction"
SERVICE_SET_PERCENTAGE = "set_percentage" SERVICE_SET_PERCENTAGE = "set_percentage"
SERVICE_SET_PRESET_MODE = "set_preset_mode" SERVICE_SET_PRESET_MODE = "set_preset_mode"
SPEED_OFF = "off"
SPEED_LOW = "low"
SPEED_MEDIUM = "medium"
SPEED_HIGH = "high"
DIRECTION_FORWARD = "forward" DIRECTION_FORWARD = "forward"
DIRECTION_REVERSE = "reverse" DIRECTION_REVERSE = "reverse"
ATTR_SPEED = "speed"
ATTR_PERCENTAGE = "percentage" ATTR_PERCENTAGE = "percentage"
ATTR_PERCENTAGE_STEP = "percentage_step" ATTR_PERCENTAGE_STEP = "percentage_step"
ATTR_SPEED_LIST = "speed_list"
ATTR_OSCILLATING = "oscillating" ATTR_OSCILLATING = "oscillating"
ATTR_DIRECTION = "direction" ATTR_DIRECTION = "direction"
ATTR_PRESET_MODE = "preset_mode" ATTR_PRESET_MODE = "preset_mode"
ATTR_PRESET_MODES = "preset_modes" ATTR_PRESET_MODES = "preset_modes"
_NOT_SPEED_OFF = "off"
OFF_SPEED_VALUES = [SPEED_OFF, None]
LEGACY_SPEED_LIST = [SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH]
class NoValidSpeedsError(ValueError):
"""Exception class when there are no valid speeds."""
class NotValidSpeedError(ValueError):
"""Exception class when the speed in not in the speed list."""
class NotValidPresetModeError(ValueError): class NotValidPresetModeError(ValueError):
"""Exception class when the preset_mode in not in the preset_modes list.""" """Exception class when the preset_mode in not in the preset_modes list."""
@ -94,10 +70,7 @@ class NotValidPresetModeError(ValueError):
@bind_hass @bind_hass
def is_on(hass, entity_id: str) -> bool: def is_on(hass, entity_id: str) -> bool:
"""Return if the fans are on based on the statemachine.""" """Return if the fans are on based on the statemachine."""
state = hass.states.get(entity_id) return hass.states.get(entity_id).state == STATE_ON
if ATTR_SPEED in state.attributes:
return state.attributes[ATTR_SPEED] not in OFF_SPEED_VALUES
return state.state == STATE_ON
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
@ -113,24 +86,15 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_TURN_ON, SERVICE_TURN_ON,
{ {
vol.Optional(ATTR_SPEED): cv.string,
vol.Optional(ATTR_PERCENTAGE): vol.All( vol.Optional(ATTR_PERCENTAGE): vol.All(
vol.Coerce(int), vol.Range(min=0, max=100) vol.Coerce(int), vol.Range(min=0, max=100)
), ),
vol.Optional(ATTR_PRESET_MODE): cv.string, vol.Optional(ATTR_PRESET_MODE): cv.string,
}, },
"async_turn_on_compat", "async_turn_on",
) )
component.async_register_entity_service(SERVICE_TURN_OFF, {}, "async_turn_off") component.async_register_entity_service(SERVICE_TURN_OFF, {}, "async_turn_off")
component.async_register_entity_service(SERVICE_TOGGLE, {}, "async_toggle") component.async_register_entity_service(SERVICE_TOGGLE, {}, "async_toggle")
# After the transition to percentage and preset_modes concludes,
# remove this service
component.async_register_entity_service(
SERVICE_SET_SPEED,
{vol.Required(ATTR_SPEED): cv.string},
"async_set_speed_deprecated",
[SUPPORT_SET_SPEED],
)
component.async_register_entity_service( component.async_register_entity_service(
SERVICE_INCREASE_SPEED, SERVICE_INCREASE_SPEED,
{ {
@ -212,29 +176,6 @@ class FanEntity(ToggleEntity):
_attr_speed_count: int _attr_speed_count: int
_attr_supported_features: int = 0 _attr_supported_features: int = 0
def set_speed(self, speed: str) -> None:
"""Set the speed of the fan."""
raise NotImplementedError()
async def async_set_speed_deprecated(self, speed: str):
"""Set the speed of the fan."""
_LOGGER.error(
"The fan.set_speed service is deprecated and will fail in 2022.3 and later, use fan.set_percentage or fan.set_preset_mode instead"
)
await self.async_set_speed(speed)
async def async_set_speed(self, speed: str):
"""Set the speed of the fan."""
if speed == SPEED_OFF:
await self.async_turn_off()
return
if self.preset_modes and speed in self.preset_modes:
await self.async_set_preset_mode(speed)
return
await self.async_set_percentage(self.speed_to_percentage(speed))
def set_percentage(self, percentage: int) -> None: def set_percentage(self, percentage: int) -> None:
"""Set the speed of the fan, as a percentage.""" """Set the speed of the fan, as a percentage."""
raise NotImplementedError() raise NotImplementedError()
@ -301,7 +242,6 @@ class FanEntity(ToggleEntity):
# pylint: disable=arguments-differ # pylint: disable=arguments-differ
def turn_on( def turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs, **kwargs,
@ -309,64 +249,22 @@ class FanEntity(ToggleEntity):
"""Turn on the fan.""" """Turn on the fan."""
raise NotImplementedError() raise NotImplementedError()
async def async_turn_on_compat(
self,
speed: str | None = None,
percentage: int | None = None,
preset_mode: str | None = None,
**kwargs,
) -> None:
"""Turn on the fan.
This _compat version wraps async_turn_on with
backwards and forward compatibility.
This compatibility shim will be removed in 2022.3
"""
if preset_mode is not None:
self._valid_preset_mode_or_raise(preset_mode)
speed = preset_mode
percentage = None
elif speed is not None:
_LOGGER.error(
"Calling fan.turn_on with the speed argument is deprecated and will fail in 2022.3 and later, use percentage or preset_mode instead"
)
if self.preset_modes and speed in self.preset_modes:
preset_mode = speed
percentage = None
else:
percentage = self.speed_to_percentage(speed)
elif percentage is not None:
speed = self.percentage_to_speed(percentage)
await self.async_turn_on(
speed=speed,
percentage=percentage,
preset_mode=preset_mode,
**kwargs,
)
# pylint: disable=arguments-differ # pylint: disable=arguments-differ
async def async_turn_on( async def async_turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs, **kwargs,
) -> None: ) -> None:
"""Turn on the fan.""" """Turn on the fan."""
if speed == SPEED_OFF: await self.hass.async_add_executor_job(
await self.async_turn_off() ft.partial(
else: self.turn_on,
await self.hass.async_add_executor_job( percentage=percentage,
ft.partial( preset_mode=preset_mode,
self.turn_on, **kwargs,
speed=speed,
percentage=percentage,
preset_mode=preset_mode,
**kwargs,
)
) )
)
def oscillate(self, oscillating: bool) -> None: def oscillate(self, oscillating: bool) -> None:
"""Oscillate the fan.""" """Oscillate the fan."""
@ -379,16 +277,9 @@ class FanEntity(ToggleEntity):
@property @property
def is_on(self): def is_on(self):
"""Return true if the entity is on.""" """Return true if the entity is on."""
return self.speed not in [SPEED_OFF, None] return (
self.percentage is not None and self.percentage > 0
@property ) or self.preset_mode is not None
def speed(self) -> str | None:
"""Return the current speed."""
if preset_mode := self.preset_mode:
return preset_mode
if (percentage := self.percentage) is None:
return None
return self.percentage_to_speed(percentage)
@property @property
def percentage(self) -> int | None: def percentage(self) -> int | None:
@ -409,14 +300,6 @@ class FanEntity(ToggleEntity):
"""Return the step size for percentage.""" """Return the step size for percentage."""
return 100 / self.speed_count return 100 / self.speed_count
@property
def speed_list(self) -> list:
"""Get the list of available speeds."""
speeds = [SPEED_OFF, *LEGACY_SPEED_LIST]
if preset_modes := self.preset_modes:
speeds.extend(preset_modes)
return speeds
@property @property
def current_direction(self) -> str | None: def current_direction(self) -> str | None:
"""Return the current direction of the fan.""" """Return the current direction of the fan."""
@ -431,8 +314,6 @@ class FanEntity(ToggleEntity):
def capability_attributes(self): def capability_attributes(self):
"""Return capability attributes.""" """Return capability attributes."""
attrs = {} attrs = {}
if self.supported_features & SUPPORT_SET_SPEED:
attrs[ATTR_SPEED_LIST] = self.speed_list
if ( if (
self.supported_features & SUPPORT_SET_SPEED self.supported_features & SUPPORT_SET_SPEED
@ -442,22 +323,6 @@ class FanEntity(ToggleEntity):
return attrs return attrs
def speed_to_percentage(self, speed: str) -> int: # pylint: disable=no-self-use
"""Map a legacy speed to a percentage."""
if speed in OFF_SPEED_VALUES:
return 0
if speed not in LEGACY_SPEED_LIST:
raise NotValidSpeedError(f"The speed {speed} is not a valid speed.")
return ordered_list_item_to_percentage(LEGACY_SPEED_LIST, speed)
def percentage_to_speed( # pylint: disable=no-self-use
self, percentage: int
) -> str:
"""Map a percentage to a legacy speed."""
if percentage == 0:
return SPEED_OFF
return percentage_to_ordered_list_item(LEGACY_SPEED_LIST, percentage)
@final @final
@property @property
def state_attributes(self) -> dict: def state_attributes(self) -> dict:
@ -472,7 +337,6 @@ class FanEntity(ToggleEntity):
data[ATTR_OSCILLATING] = self.oscillating data[ATTR_OSCILLATING] = self.oscillating
if supported_features & SUPPORT_SET_SPEED: if supported_features & SUPPORT_SET_SPEED:
data[ATTR_SPEED] = self.speed
data[ATTR_PERCENTAGE] = self.percentage data[ATTR_PERCENTAGE] = self.percentage
data[ATTR_PERCENTAGE_STEP] = self.percentage_step data[ATTR_PERCENTAGE_STEP] = self.percentage_step

View file

@ -20,13 +20,11 @@ from . import (
ATTR_OSCILLATING, ATTR_OSCILLATING,
ATTR_PERCENTAGE, ATTR_PERCENTAGE,
ATTR_PRESET_MODE, ATTR_PRESET_MODE,
ATTR_SPEED,
DOMAIN, DOMAIN,
SERVICE_OSCILLATE, SERVICE_OSCILLATE,
SERVICE_SET_DIRECTION, SERVICE_SET_DIRECTION,
SERVICE_SET_PERCENTAGE, SERVICE_SET_PERCENTAGE,
SERVICE_SET_PRESET_MODE, SERVICE_SET_PRESET_MODE,
SERVICE_SET_SPEED,
) )
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -35,7 +33,6 @@ VALID_STATES = {STATE_ON, STATE_OFF}
ATTRIBUTES = { # attribute: service ATTRIBUTES = { # attribute: service
ATTR_DIRECTION: SERVICE_SET_DIRECTION, ATTR_DIRECTION: SERVICE_SET_DIRECTION,
ATTR_OSCILLATING: SERVICE_OSCILLATE, ATTR_OSCILLATING: SERVICE_OSCILLATE,
ATTR_SPEED: SERVICE_SET_SPEED,
ATTR_PERCENTAGE: SERVICE_SET_PERCENTAGE, ATTR_PERCENTAGE: SERVICE_SET_PERCENTAGE,
ATTR_PRESET_MODE: SERVICE_SET_PRESET_MODE, ATTR_PRESET_MODE: SERVICE_SET_PRESET_MODE,
} }

View file

@ -100,7 +100,6 @@ class Fan(CoordinatorEntity[State], FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str = None,
percentage: int = None, percentage: int = None,
preset_mode: str = None, preset_mode: str = None,
**kwargs, **kwargs,

View file

@ -92,9 +92,7 @@ class FreedomproFan(CoordinatorEntity, FanEntity):
await super().async_added_to_hass() await super().async_added_to_hass()
self._handle_coordinator_update() self._handle_coordinator_update()
async def async_turn_on( async def async_turn_on(self, percentage=None, preset_mode=None, **kwargs):
self, speed=None, percentage=None, preset_mode=None, **kwargs
):
"""Async function to turn on the fan.""" """Async function to turn on the fan."""
payload = {"on": True} payload = {"on": True}
payload = json.dumps(payload) payload = json.dumps(payload)

View file

@ -208,7 +208,6 @@ class FanGroup(GroupEntity, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs: Any, **kwargs: Any,

View file

@ -117,7 +117,6 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs: Any, **kwargs: Any,

View file

@ -65,7 +65,6 @@ class InsteonFanEntity(InsteonEntity, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str = None,
percentage: int = None, percentage: int = None,
preset_mode: str = None, preset_mode: str = None,
**kwargs, **kwargs,

View file

@ -76,7 +76,6 @@ class ISYFanEntity(ISYNodeEntity, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs: Any, **kwargs: Any,
@ -121,7 +120,6 @@ class ISYFanProgramEntity(ISYProgramEntity, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs: Any, **kwargs: Any,

View file

@ -106,7 +106,6 @@ class KNXFan(KnxEntity, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs: Any, **kwargs: Any,

View file

@ -72,7 +72,6 @@ class LutronCasetaFan(LutronCasetaDevice, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str = None,
percentage: int = None, percentage: int = None,
preset_mode: str = None, preset_mode: str = None,
**kwargs, **kwargs,

View file

@ -39,7 +39,6 @@ class ModbusFan(BaseSwitch, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs: Any, **kwargs: Any,

View file

@ -129,7 +129,6 @@ class ModernFormsFanEntity(FanEntity, ModernFormsDeviceEntity):
@modernforms_exception_handler @modernforms_exception_handler
async def async_turn_on( async def async_turn_on(
self, self,
speed: int | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: int | None = None, preset_mode: int | None = None,
**kwargs: Any, **kwargs: Any,

View file

@ -12,10 +12,6 @@ from homeassistant.components.fan import (
ATTR_OSCILLATING, ATTR_OSCILLATING,
ATTR_PERCENTAGE, ATTR_PERCENTAGE,
ATTR_PRESET_MODE, ATTR_PRESET_MODE,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
SUPPORT_OSCILLATE, SUPPORT_OSCILLATE,
SUPPORT_PRESET_MODE, SUPPORT_PRESET_MODE,
SUPPORT_SET_SPEED, SUPPORT_SET_SPEED,
@ -163,10 +159,6 @@ _PLATFORM_SCHEMA_BASE = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend(
vol.Optional( vol.Optional(
CONF_PAYLOAD_RESET_PRESET_MODE, default=DEFAULT_PAYLOAD_RESET CONF_PAYLOAD_RESET_PRESET_MODE, default=DEFAULT_PAYLOAD_RESET
): cv.string, ): cv.string,
vol.Optional(CONF_PAYLOAD_HIGH_SPEED, default=SPEED_HIGH): cv.string,
vol.Optional(CONF_PAYLOAD_LOW_SPEED, default=SPEED_LOW): cv.string,
vol.Optional(CONF_PAYLOAD_MEDIUM_SPEED, default=SPEED_MEDIUM): cv.string,
vol.Optional(CONF_PAYLOAD_OFF_SPEED, default=SPEED_OFF): cv.string,
vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string, vol.Optional(CONF_PAYLOAD_OFF, default=DEFAULT_PAYLOAD_OFF): cv.string,
vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string, vol.Optional(CONF_PAYLOAD_ON, default=DEFAULT_PAYLOAD_ON): cv.string,
vol.Optional( vol.Optional(
@ -176,10 +168,6 @@ _PLATFORM_SCHEMA_BASE = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend(
CONF_PAYLOAD_OSCILLATION_ON, default=OSCILLATE_ON_PAYLOAD CONF_PAYLOAD_OSCILLATION_ON, default=OSCILLATE_ON_PAYLOAD
): cv.string, ): cv.string,
vol.Optional(CONF_SPEED_COMMAND_TOPIC): mqtt.valid_publish_topic, vol.Optional(CONF_SPEED_COMMAND_TOPIC): mqtt.valid_publish_topic,
vol.Optional(
CONF_SPEED_LIST,
default=[SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH],
): cv.ensure_list,
vol.Optional(CONF_SPEED_STATE_TOPIC): mqtt.valid_subscribe_topic, vol.Optional(CONF_SPEED_STATE_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_SPEED_VALUE_TEMPLATE): cv.template, vol.Optional(CONF_SPEED_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_STATE_VALUE_TEMPLATE): cv.template, vol.Optional(CONF_STATE_VALUE_TEMPLATE): cv.template,
@ -537,7 +525,6 @@ class MqttFan(MqttEntity, FanEntity):
# The speed attribute deprecated in the schema, support will be removed after a quarter (2021.7) # The speed attribute deprecated in the schema, support will be removed after a quarter (2021.7)
async def async_turn_on( async def async_turn_on(
self, self,
speed: str = None,
percentage: int = None, percentage: int = None,
preset_mode: str = None, preset_mode: str = None,
**kwargs, **kwargs,
@ -605,9 +592,7 @@ class MqttFan(MqttEntity, FanEntity):
This method is a coroutine. This method is a coroutine.
""" """
if preset_mode not in self.preset_modes: self._valid_preset_mode_or_raise(preset_mode)
_LOGGER.warning("'%s'is not a valid preset mode", preset_mode)
return
mqtt_payload = self._command_templates[ATTR_PRESET_MODE](preset_mode) mqtt_payload = self._command_templates[ATTR_PRESET_MODE](preset_mode)

View file

@ -55,9 +55,7 @@ class ZwaveFan(ZWaveDeviceEntity, FanEntity):
zwave_speed = math.ceil(percentage_to_ranged_value(SPEED_RANGE, percentage)) zwave_speed = math.ceil(percentage_to_ranged_value(SPEED_RANGE, percentage))
self.values.primary.send_value(zwave_speed) self.values.primary.send_value(zwave_speed)
async def async_turn_on( async def async_turn_on(self, percentage=None, preset_mode=None, **kwargs):
self, speed=None, percentage=None, preset_mode=None, **kwargs
):
"""Turn the device on.""" """Turn the device on."""
await self.async_set_percentage(percentage) await self.async_set_percentage(percentage)

View file

@ -84,7 +84,6 @@ class HASensemeFan(SensemeEntity, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs: Any, **kwargs: Any,

View file

@ -65,7 +65,6 @@ class SmartThingsFan(SmartThingsEntity, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs, **kwargs,

View file

@ -99,9 +99,9 @@ class SmartyFan(FanEntity):
self._smarty_fan_speed = fan_speed self._smarty_fan_speed = fan_speed
self.schedule_update_ha_state() self.schedule_update_ha_state()
def turn_on(self, speed=None, percentage=None, preset_mode=None, **kwargs): def turn_on(self, percentage=None, preset_mode=None, **kwargs):
"""Turn on the fan.""" """Turn on the fan."""
_LOGGER.debug("Turning on fan. Speed is %s", speed) _LOGGER.debug("Turning on fan. percentage is %s", percentage)
self.set_percentage(percentage or DEFAULT_ON_PERCENTAGE) self.set_percentage(percentage or DEFAULT_ON_PERCENTAGE)
def turn_off(self, **kwargs): def turn_off(self, **kwargs):

View file

@ -113,7 +113,6 @@ class TasmotaFan(
async def async_turn_on( async def async_turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs: Any, **kwargs: Any,

View file

@ -11,7 +11,6 @@ from homeassistant.components.fan import (
ATTR_OSCILLATING, ATTR_OSCILLATING,
ATTR_PERCENTAGE, ATTR_PERCENTAGE,
ATTR_PRESET_MODE, ATTR_PRESET_MODE,
ATTR_SPEED,
DIRECTION_FORWARD, DIRECTION_FORWARD,
DIRECTION_REVERSE, DIRECTION_REVERSE,
ENTITY_ID_FORMAT, ENTITY_ID_FORMAT,
@ -250,7 +249,6 @@ class TemplateFan(TemplateEntity, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str = None,
percentage: int = None, percentage: int = None,
preset_mode: str = None, preset_mode: str = None,
**kwargs, **kwargs,
@ -258,7 +256,6 @@ class TemplateFan(TemplateEntity, FanEntity):
"""Turn on the fan.""" """Turn on the fan."""
await self._on_script.async_run( await self._on_script.async_run(
{ {
ATTR_SPEED: speed,
ATTR_PERCENTAGE: percentage, ATTR_PERCENTAGE: percentage,
ATTR_PRESET_MODE: preset_mode, ATTR_PRESET_MODE: preset_mode,
}, },
@ -270,8 +267,6 @@ class TemplateFan(TemplateEntity, FanEntity):
await self.async_set_preset_mode(preset_mode) await self.async_set_preset_mode(preset_mode)
elif percentage is not None: elif percentage is not None:
await self.async_set_percentage(percentage) await self.async_set_percentage(percentage)
elif speed is not None:
await self.async_set_speed(speed)
async def async_turn_off(self, **kwargs: Any) -> None: async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off the fan.""" """Turn off the fan."""

View file

@ -43,7 +43,6 @@ class ToloFan(ToloSaunaCoordinatorEntity, FanEntity):
def turn_on( def turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs: Any, **kwargs: Any,

View file

@ -148,7 +148,6 @@ class TradfriAirPurifierFan(TradfriBaseEntity, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs: Any, **kwargs: Any,

View file

@ -161,7 +161,6 @@ class TuyaFanEntity(TuyaEntity, FanEntity):
def turn_on( def turn_on(
self, self,
speed: str = None,
percentage: int = None, percentage: int = None,
preset_mode: str = None, preset_mode: str = None,
**kwargs: Any, **kwargs: Any,

View file

@ -168,7 +168,6 @@ class ValloxFan(CoordinatorEntity, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs: Any, **kwargs: Any,

View file

@ -179,7 +179,6 @@ class VeSyncFanHA(VeSyncDevice, FanEntity):
def turn_on( def turn_on(
self, self,
speed: str = None,
percentage: int = None, percentage: int = None,
preset_mode: str = None, preset_mode: str = None,
**kwargs, **kwargs,

View file

@ -138,7 +138,6 @@ class WemoHumidifier(WemoBinaryStateEntity, FanEntity):
def turn_on( def turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs: Any, **kwargs: Any,

View file

@ -108,7 +108,6 @@ class WiLightFan(WiLightDevice, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str = None,
percentage: int = None, percentage: int = None,
preset_mode: str = None, preset_mode: str = None,
**kwargs, **kwargs,

View file

@ -326,7 +326,6 @@ class XiaomiGenericDevice(XiaomiCoordinatedMiioEntity, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str = None,
percentage: int = None, percentage: int = None,
preset_mode: str = None, preset_mode: str = None,
**kwargs, **kwargs,

View file

@ -91,9 +91,7 @@ class BaseFan(FanEntity):
"""Return the number of speeds the fan supports.""" """Return the number of speeds the fan supports."""
return int_states_in_range(SPEED_RANGE) return int_states_in_range(SPEED_RANGE)
async def async_turn_on( async def async_turn_on(self, percentage=None, preset_mode=None, **kwargs) -> None:
self, speed=None, percentage=None, preset_mode=None, **kwargs
) -> None:
"""Turn the entity on.""" """Turn the entity on."""
if percentage is None: if percentage is None:
percentage = DEFAULT_ON_PERCENTAGE percentage = DEFAULT_ON_PERCENTAGE

View file

@ -62,7 +62,7 @@ class ZwaveFan(ZWaveDeviceEntity, FanEntity):
zwave_speed = math.ceil(percentage_to_ranged_value(SPEED_RANGE, percentage)) zwave_speed = math.ceil(percentage_to_ranged_value(SPEED_RANGE, percentage))
self.node.set_dimmer(self.values.primary.value_id, zwave_speed) self.node.set_dimmer(self.values.primary.value_id, zwave_speed)
def turn_on(self, speed=None, percentage=None, preset_mode=None, **kwargs): def turn_on(self, percentage=None, preset_mode=None, **kwargs):
"""Turn the device on.""" """Turn the device on."""
self.set_percentage(percentage) self.set_percentage(percentage)

View file

@ -83,7 +83,6 @@ class ZwaveFan(ZWaveBaseEntity, FanEntity):
async def async_turn_on( async def async_turn_on(
self, self,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
**kwargs: Any, **kwargs: Any,

View file

@ -16,17 +16,15 @@ from homeassistant.components.bond.const import (
from homeassistant.components.bond.fan import PRESET_MODE_BREEZE from homeassistant.components.bond.fan import PRESET_MODE_BREEZE
from homeassistant.components.fan import ( from homeassistant.components.fan import (
ATTR_DIRECTION, ATTR_DIRECTION,
ATTR_PERCENTAGE,
ATTR_PRESET_MODE, ATTR_PRESET_MODE,
ATTR_PRESET_MODES, ATTR_PRESET_MODES,
ATTR_SPEED,
ATTR_SPEED_LIST,
DIRECTION_FORWARD, DIRECTION_FORWARD,
DIRECTION_REVERSE, DIRECTION_REVERSE,
DOMAIN as FAN_DOMAIN, DOMAIN as FAN_DOMAIN,
SERVICE_SET_DIRECTION, SERVICE_SET_DIRECTION,
SERVICE_SET_PERCENTAGE,
SERVICE_SET_PRESET_MODE, SERVICE_SET_PRESET_MODE,
SERVICE_SET_SPEED,
SPEED_OFF,
) )
from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
@ -66,7 +64,6 @@ def ceiling_fan_with_breeze(name: str):
async def turn_fan_on( async def turn_fan_on(
hass: core.HomeAssistant, hass: core.HomeAssistant,
fan_id: str, fan_id: str,
speed: str | None = None,
percentage: int | None = None, percentage: int | None = None,
preset_mode: str | None = None, preset_mode: str | None = None,
) -> None: ) -> None:
@ -74,9 +71,7 @@ async def turn_fan_on(
service_data = {ATTR_ENTITY_ID: fan_id} service_data = {ATTR_ENTITY_ID: fan_id}
if preset_mode: if preset_mode:
service_data[fan.ATTR_PRESET_MODE] = preset_mode service_data[fan.ATTR_PRESET_MODE] = preset_mode
if speed: if percentage is not None:
service_data[fan.ATTR_SPEED] = speed
if percentage:
service_data[fan.ATTR_PERCENTAGE] = percentage service_data[fan.ATTR_PERCENTAGE] = percentage
await hass.services.async_call( await hass.services.async_call(
FAN_DOMAIN, FAN_DOMAIN,
@ -116,35 +111,27 @@ async def test_non_standard_speed_list(hass: core.HomeAssistant):
props={"max_speed": 6}, props={"max_speed": 6},
) )
actual_speeds = hass.states.get("fan.name_1").attributes[ATTR_SPEED_LIST]
assert actual_speeds == [
fan.SPEED_OFF,
fan.SPEED_LOW,
fan.SPEED_MEDIUM,
fan.SPEED_HIGH,
]
with patch_bond_device_state(): with patch_bond_device_state():
with patch_bond_action() as mock_set_speed_low: with patch_bond_action() as mock_set_speed_low:
await turn_fan_on(hass, "fan.name_1", fan.SPEED_LOW) await turn_fan_on(hass, "fan.name_1", percentage=100 / 6 * 2)
mock_set_speed_low.assert_called_once_with( mock_set_speed_low.assert_called_once_with(
"test-device-id", Action.set_speed(2) "test-device-id", Action.set_speed(2)
) )
with patch_bond_action() as mock_set_speed_medium: with patch_bond_action() as mock_set_speed_medium:
await turn_fan_on(hass, "fan.name_1", fan.SPEED_MEDIUM) await turn_fan_on(hass, "fan.name_1", percentage=100 / 6 * 4)
mock_set_speed_medium.assert_called_once_with( mock_set_speed_medium.assert_called_once_with(
"test-device-id", Action.set_speed(4) "test-device-id", Action.set_speed(4)
) )
with patch_bond_action() as mock_set_speed_high: with patch_bond_action() as mock_set_speed_high:
await turn_fan_on(hass, "fan.name_1", fan.SPEED_HIGH) await turn_fan_on(hass, "fan.name_1", percentage=100)
mock_set_speed_high.assert_called_once_with( mock_set_speed_high.assert_called_once_with(
"test-device-id", Action.set_speed(6) "test-device-id", Action.set_speed(6)
) )
async def test_fan_speed_with_no_max_seed(hass: core.HomeAssistant): async def test_fan_speed_with_no_max_speed(hass: core.HomeAssistant):
"""Tests that fans without max speed (increase/decrease controls) map speed to HA standard.""" """Tests that fans without max speed (increase/decrease controls) map speed to HA standard."""
await setup_platform( await setup_platform(
hass, hass,
@ -155,7 +142,7 @@ async def test_fan_speed_with_no_max_seed(hass: core.HomeAssistant):
state={"power": 1, "speed": 14}, state={"power": 1, "speed": 14},
) )
assert hass.states.get("fan.name_1").attributes["speed"] == fan.SPEED_HIGH assert hass.states.get("fan.name_1").attributes["percentage"] == 100
async def test_turn_on_fan_with_speed(hass: core.HomeAssistant): async def test_turn_on_fan_with_speed(hass: core.HomeAssistant):
@ -165,7 +152,7 @@ async def test_turn_on_fan_with_speed(hass: core.HomeAssistant):
) )
with patch_bond_action() as mock_set_speed, patch_bond_device_state(): with patch_bond_action() as mock_set_speed, patch_bond_device_state():
await turn_fan_on(hass, "fan.name_1", fan.SPEED_LOW) await turn_fan_on(hass, "fan.name_1", percentage=1)
mock_set_speed.assert_called_with("test-device-id", Action.set_speed(1)) mock_set_speed.assert_called_with("test-device-id", Action.set_speed(1))
@ -264,9 +251,7 @@ async def test_turn_on_fan_preset_mode_not_supported(hass: core.HomeAssistant):
props={"max_speed": 6}, props={"max_speed": 6},
) )
with patch_bond_action(), patch_bond_device_state(), pytest.raises( with patch_bond_action(), patch_bond_device_state(), pytest.raises(ValueError):
fan.NotValidPresetModeError
):
await turn_fan_on(hass, "fan.name_1", preset_mode=PRESET_MODE_BREEZE) await turn_fan_on(hass, "fan.name_1", preset_mode=PRESET_MODE_BREEZE)
with patch_bond_action(), patch_bond_device_state(), pytest.raises(ValueError): with patch_bond_action(), patch_bond_device_state(), pytest.raises(ValueError):
@ -296,7 +281,7 @@ async def test_turn_on_fan_with_off_with_breeze(hass: core.HomeAssistant):
) )
with patch_bond_action() as mock_actions, patch_bond_device_state(): with patch_bond_action() as mock_actions, patch_bond_device_state():
await turn_fan_on(hass, "fan.name_1", fan.SPEED_OFF) await turn_fan_on(hass, "fan.name_1", percentage=0)
assert mock_actions.mock_calls == [ assert mock_actions.mock_calls == [
call("test-device-id", Action(Action.BREEZE_OFF)), call("test-device-id", Action(Action.BREEZE_OFF)),
@ -316,14 +301,14 @@ async def test_turn_on_fan_without_speed(hass: core.HomeAssistant):
mock_turn_on.assert_called_with("test-device-id", Action.turn_on()) mock_turn_on.assert_called_with("test-device-id", Action.turn_on())
async def test_turn_on_fan_with_off_speed(hass: core.HomeAssistant): async def test_turn_on_fan_with_off_percentage(hass: core.HomeAssistant):
"""Tests that turn off command delegates to turn off API.""" """Tests that turn off command delegates to turn off API."""
await setup_platform( await setup_platform(
hass, FAN_DOMAIN, ceiling_fan("name-1"), bond_device_id="test-device-id" hass, FAN_DOMAIN, ceiling_fan("name-1"), bond_device_id="test-device-id"
) )
with patch_bond_action() as mock_turn_off, patch_bond_device_state(): with patch_bond_action() as mock_turn_off, patch_bond_device_state():
await turn_fan_on(hass, "fan.name_1", fan.SPEED_OFF) await turn_fan_on(hass, "fan.name_1", percentage=0)
mock_turn_off.assert_called_with("test-device-id", Action.turn_off()) mock_turn_off.assert_called_with("test-device-id", Action.turn_off())
@ -337,8 +322,8 @@ async def test_set_speed_off(hass: core.HomeAssistant):
with patch_bond_action() as mock_turn_off, patch_bond_device_state(): with patch_bond_action() as mock_turn_off, patch_bond_device_state():
await hass.services.async_call( await hass.services.async_call(
FAN_DOMAIN, FAN_DOMAIN,
SERVICE_SET_SPEED, SERVICE_SET_PERCENTAGE,
service_data={ATTR_ENTITY_ID: "fan.name_1", ATTR_SPEED: SPEED_OFF}, service_data={ATTR_ENTITY_ID: "fan.name_1", ATTR_PERCENTAGE: 0},
blocking=True, blocking=True,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -374,7 +359,7 @@ async def test_set_speed_belief_speed_zero(hass: core.HomeAssistant):
await hass.services.async_call( await hass.services.async_call(
BOND_DOMAIN, BOND_DOMAIN,
SERVICE_SET_FAN_SPEED_TRACKED_STATE, SERVICE_SET_FAN_SPEED_TRACKED_STATE,
{ATTR_ENTITY_ID: "fan.name_1", ATTR_SPEED: 0}, {ATTR_ENTITY_ID: "fan.name_1", "speed": 0},
blocking=True, blocking=True,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -396,7 +381,7 @@ async def test_set_speed_belief_speed_api_error(hass: core.HomeAssistant):
await hass.services.async_call( await hass.services.async_call(
BOND_DOMAIN, BOND_DOMAIN,
SERVICE_SET_FAN_SPEED_TRACKED_STATE, SERVICE_SET_FAN_SPEED_TRACKED_STATE,
{ATTR_ENTITY_ID: "fan.name_1", ATTR_SPEED: 100}, {ATTR_ENTITY_ID: "fan.name_1", "speed": 100},
blocking=True, blocking=True,
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -412,7 +397,7 @@ async def test_set_speed_belief_speed_100(hass: core.HomeAssistant):
await hass.services.async_call( await hass.services.async_call(
BOND_DOMAIN, BOND_DOMAIN,
SERVICE_SET_FAN_SPEED_TRACKED_STATE, SERVICE_SET_FAN_SPEED_TRACKED_STATE,
{ATTR_ENTITY_ID: "fan.name_1", ATTR_SPEED: 100}, {ATTR_ENTITY_ID: "fan.name_1", "speed": 100},
blocking=True, blocking=True,
) )
await hass.async_block_till_done() await hass.async_block_till_done()

View file

@ -3,19 +3,14 @@
from unittest.mock import patch from unittest.mock import patch
import pytest import pytest
from voluptuous.error import MultipleInvalid
from homeassistant.components.fan import ( from homeassistant.components.fan import (
ATTR_PERCENTAGE, ATTR_PERCENTAGE,
ATTR_SPEED,
DOMAIN as FAN_DOMAIN, DOMAIN as FAN_DOMAIN,
SERVICE_SET_PERCENTAGE, SERVICE_SET_PERCENTAGE,
SERVICE_SET_SPEED,
SERVICE_TURN_OFF, SERVICE_TURN_OFF,
SERVICE_TURN_ON, SERVICE_TURN_ON,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
) )
from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON, STATE_UNAVAILABLE from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON, STATE_UNAVAILABLE
@ -212,7 +207,7 @@ async def test_fans(hass, aioclient_mock, mock_deconz_websocket):
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 0}, {ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 0},
blocking=True, blocking=True,
) )
assert aioclient_mock.mock_calls[8][2] == {"speed": 1} assert aioclient_mock.mock_calls[8][2] == {"speed": 0}
# Events with an unsupported speed does not get converted # Events with an unsupported speed does not get converted
@ -273,7 +268,6 @@ async def test_fans_legacy_speed_modes(hass, aioclient_mock, mock_deconz_websock
assert len(hass.states.async_all()) == 2 # Light and fan assert len(hass.states.async_all()) == 2 # Light and fan
assert hass.states.get("fan.ceiling_fan").state == STATE_ON assert hass.states.get("fan.ceiling_fan").state == STATE_ON
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_SPEED] == SPEED_HIGH
# Test states # Test states
@ -289,7 +283,6 @@ async def test_fans_legacy_speed_modes(hass, aioclient_mock, mock_deconz_websock
assert hass.states.get("fan.ceiling_fan").state == STATE_ON assert hass.states.get("fan.ceiling_fan").state == STATE_ON
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_PERCENTAGE] == 25 assert hass.states.get("fan.ceiling_fan").attributes[ATTR_PERCENTAGE] == 25
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_SPEED] == SPEED_LOW
event_changed_light = { event_changed_light = {
"t": "event", "t": "event",
@ -303,7 +296,6 @@ async def test_fans_legacy_speed_modes(hass, aioclient_mock, mock_deconz_websock
assert hass.states.get("fan.ceiling_fan").state == STATE_ON assert hass.states.get("fan.ceiling_fan").state == STATE_ON
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_PERCENTAGE] == 50 assert hass.states.get("fan.ceiling_fan").attributes[ATTR_PERCENTAGE] == 50
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_SPEED] == SPEED_MEDIUM
event_changed_light = { event_changed_light = {
"t": "event", "t": "event",
@ -317,7 +309,6 @@ async def test_fans_legacy_speed_modes(hass, aioclient_mock, mock_deconz_websock
assert hass.states.get("fan.ceiling_fan").state == STATE_ON assert hass.states.get("fan.ceiling_fan").state == STATE_ON
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_PERCENTAGE] == 75 assert hass.states.get("fan.ceiling_fan").attributes[ATTR_PERCENTAGE] == 75
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_SPEED] == SPEED_MEDIUM
event_changed_light = { event_changed_light = {
"t": "event", "t": "event",
@ -331,7 +322,6 @@ async def test_fans_legacy_speed_modes(hass, aioclient_mock, mock_deconz_websock
assert hass.states.get("fan.ceiling_fan").state == STATE_ON assert hass.states.get("fan.ceiling_fan").state == STATE_ON
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_PERCENTAGE] == 100 assert hass.states.get("fan.ceiling_fan").attributes[ATTR_PERCENTAGE] == 100
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_SPEED] == SPEED_HIGH
event_changed_light = { event_changed_light = {
"t": "event", "t": "event",
@ -345,7 +335,6 @@ async def test_fans_legacy_speed_modes(hass, aioclient_mock, mock_deconz_websock
assert hass.states.get("fan.ceiling_fan").state == STATE_OFF assert hass.states.get("fan.ceiling_fan").state == STATE_OFF
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_PERCENTAGE] == 0 assert hass.states.get("fan.ceiling_fan").attributes[ATTR_PERCENTAGE] == 0
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_SPEED] == SPEED_OFF
# Test service calls # Test service calls
@ -367,99 +356,99 @@ async def test_fans_legacy_speed_modes(hass, aioclient_mock, mock_deconz_websock
await hass.services.async_call( await hass.services.async_call(
FAN_DOMAIN, FAN_DOMAIN,
SERVICE_TURN_ON, SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: SPEED_OFF}, {ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 0},
blocking=True, blocking=True,
) )
assert aioclient_mock.mock_calls[2][2] == {"speed": 1} assert aioclient_mock.mock_calls[2][2] == {"speed": 0}
# Service turn on fan with bad speed # Service turn on fan with bad speed
# async_turn_on_compat use speed_to_percentage which will convert to SPEED_MEDIUM -> 2 # async_turn_on_compat use speed_to_percentage which will convert to SPEED_MEDIUM -> 2
await hass.services.async_call( with pytest.raises(MultipleInvalid):
FAN_DOMAIN, await hass.services.async_call(
SERVICE_TURN_ON, FAN_DOMAIN,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: "bad"}, SERVICE_TURN_ON,
blocking=True, {ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: "bad"},
) blocking=True,
assert aioclient_mock.mock_calls[3][2] == {"speed": 2} )
# Service turn on fan to low speed # Service turn on fan to low speed
await hass.services.async_call( await hass.services.async_call(
FAN_DOMAIN, FAN_DOMAIN,
SERVICE_TURN_ON, SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: SPEED_LOW}, {ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 25},
blocking=True, blocking=True,
) )
assert aioclient_mock.mock_calls[4][2] == {"speed": 1} assert aioclient_mock.mock_calls[3][2] == {"speed": 1}
# Service turn on fan to medium speed # Service turn on fan to medium speed
await hass.services.async_call( await hass.services.async_call(
FAN_DOMAIN, FAN_DOMAIN,
SERVICE_TURN_ON, SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: SPEED_MEDIUM}, {ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 50},
blocking=True, blocking=True,
) )
assert aioclient_mock.mock_calls[5][2] == {"speed": 2} assert aioclient_mock.mock_calls[4][2] == {"speed": 2}
# Service turn on fan to high speed # Service turn on fan to high speed
await hass.services.async_call( await hass.services.async_call(
FAN_DOMAIN, FAN_DOMAIN,
SERVICE_TURN_ON, SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: SPEED_HIGH}, {ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 100},
blocking=True, blocking=True,
) )
assert aioclient_mock.mock_calls[6][2] == {"speed": 4} assert aioclient_mock.mock_calls[5][2] == {"speed": 4}
# Service set fan speed to low # Service set fan speed to low
await hass.services.async_call( await hass.services.async_call(
FAN_DOMAIN, FAN_DOMAIN,
SERVICE_SET_SPEED, SERVICE_SET_PERCENTAGE,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: SPEED_LOW}, {ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 25},
blocking=True, blocking=True,
) )
assert aioclient_mock.mock_calls[7][2] == {"speed": 1} assert aioclient_mock.mock_calls[6][2] == {"speed": 1}
# Service set fan speed to medium # Service set fan speed to medium
await hass.services.async_call( await hass.services.async_call(
FAN_DOMAIN, FAN_DOMAIN,
SERVICE_SET_SPEED, SERVICE_SET_PERCENTAGE,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: SPEED_MEDIUM}, {ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 50},
blocking=True, blocking=True,
) )
assert aioclient_mock.mock_calls[8][2] == {"speed": 2} assert aioclient_mock.mock_calls[7][2] == {"speed": 2}
# Service set fan speed to high # Service set fan speed to high
await hass.services.async_call( await hass.services.async_call(
FAN_DOMAIN, FAN_DOMAIN,
SERVICE_SET_SPEED, SERVICE_SET_PERCENTAGE,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: SPEED_HIGH}, {ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 100},
blocking=True, blocking=True,
) )
assert aioclient_mock.mock_calls[9][2] == {"speed": 4} assert aioclient_mock.mock_calls[8][2] == {"speed": 4}
# Service set fan speed to off # Service set fan speed to off
await hass.services.async_call( await hass.services.async_call(
FAN_DOMAIN, FAN_DOMAIN,
SERVICE_SET_SPEED, SERVICE_SET_PERCENTAGE,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: SPEED_OFF}, {ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 0},
blocking=True, blocking=True,
) )
assert aioclient_mock.mock_calls[10][2] == {"speed": 0} assert aioclient_mock.mock_calls[9][2] == {"speed": 0}
# Service set fan speed to unsupported value # Service set fan speed to unsupported value
with pytest.raises(ValueError): with pytest.raises(MultipleInvalid):
await hass.services.async_call( await hass.services.async_call(
FAN_DOMAIN, FAN_DOMAIN,
SERVICE_SET_SPEED, SERVICE_SET_PERCENTAGE,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: "bad value"}, {ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: "bad value"},
blocking=True, blocking=True,
) )
@ -476,7 +465,7 @@ async def test_fans_legacy_speed_modes(hass, aioclient_mock, mock_deconz_websock
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get("fan.ceiling_fan").state == STATE_ON assert hass.states.get("fan.ceiling_fan").state == STATE_ON
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_SPEED] == SPEED_MEDIUM assert hass.states.get("fan.ceiling_fan").attributes[ATTR_PERCENTAGE] == 75
await hass.config_entries.async_unload(config_entry.entry_id) await hass.config_entries.async_unload(config_entry.entry_id)

View file

@ -55,39 +55,6 @@ async def test_turn_on_with_speed_and_percentage(hass, fan_entity_id):
"""Test turning on the device.""" """Test turning on the device."""
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.state == STATE_OFF assert state.state == STATE_OFF
await hass.services.async_call(
fan.DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: fan_entity_id, fan.ATTR_SPEED: fan.SPEED_HIGH},
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.state == STATE_ON
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_HIGH
assert state.attributes[fan.ATTR_PERCENTAGE] == 100
await hass.services.async_call(
fan.DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: fan_entity_id, fan.ATTR_SPEED: fan.SPEED_MEDIUM},
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.state == STATE_ON
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_MEDIUM
assert state.attributes[fan.ATTR_PERCENTAGE] == 66
await hass.services.async_call(
fan.DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: fan_entity_id, fan.ATTR_SPEED: fan.SPEED_LOW},
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.state == STATE_ON
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_LOW
assert state.attributes[fan.ATTR_PERCENTAGE] == 33
await hass.services.async_call( await hass.services.async_call(
fan.DOMAIN, fan.DOMAIN,
SERVICE_TURN_ON, SERVICE_TURN_ON,
@ -96,7 +63,6 @@ async def test_turn_on_with_speed_and_percentage(hass, fan_entity_id):
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.state == STATE_ON assert state.state == STATE_ON
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_HIGH
assert state.attributes[fan.ATTR_PERCENTAGE] == 100 assert state.attributes[fan.ATTR_PERCENTAGE] == 100
await hass.services.async_call( await hass.services.async_call(
@ -107,7 +73,6 @@ async def test_turn_on_with_speed_and_percentage(hass, fan_entity_id):
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.state == STATE_ON assert state.state == STATE_ON
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_MEDIUM
assert state.attributes[fan.ATTR_PERCENTAGE] == 66 assert state.attributes[fan.ATTR_PERCENTAGE] == 66
await hass.services.async_call( await hass.services.async_call(
@ -118,7 +83,36 @@ async def test_turn_on_with_speed_and_percentage(hass, fan_entity_id):
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.state == STATE_ON assert state.state == STATE_ON
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_LOW assert state.attributes[fan.ATTR_PERCENTAGE] == 33
await hass.services.async_call(
fan.DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: fan_entity_id, fan.ATTR_PERCENTAGE: 100},
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.state == STATE_ON
assert state.attributes[fan.ATTR_PERCENTAGE] == 100
await hass.services.async_call(
fan.DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: fan_entity_id, fan.ATTR_PERCENTAGE: 66},
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.state == STATE_ON
assert state.attributes[fan.ATTR_PERCENTAGE] == 66
await hass.services.async_call(
fan.DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: fan_entity_id, fan.ATTR_PERCENTAGE: 33},
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.state == STATE_ON
assert state.attributes[fan.ATTR_PERCENTAGE] == 33 assert state.attributes[fan.ATTR_PERCENTAGE] == 33
await hass.services.async_call( await hass.services.async_call(
@ -129,7 +123,6 @@ async def test_turn_on_with_speed_and_percentage(hass, fan_entity_id):
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.state == STATE_OFF assert state.state == STATE_OFF
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_OFF
assert state.attributes[fan.ATTR_PERCENTAGE] == 0 assert state.attributes[fan.ATTR_PERCENTAGE] == 0
@ -198,19 +191,8 @@ async def test_turn_on_with_preset_mode_and_speed(hass, fan_entity_id):
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.state == STATE_ON assert state.state == STATE_ON
assert state.attributes[fan.ATTR_SPEED] == PRESET_MODE_AUTO
assert state.attributes[fan.ATTR_PERCENTAGE] is None assert state.attributes[fan.ATTR_PERCENTAGE] is None
assert state.attributes[fan.ATTR_PRESET_MODE] == PRESET_MODE_AUTO assert state.attributes[fan.ATTR_PRESET_MODE] == PRESET_MODE_AUTO
assert state.attributes[fan.ATTR_SPEED_LIST] == [
fan.SPEED_OFF,
fan.SPEED_LOW,
fan.SPEED_MEDIUM,
fan.SPEED_HIGH,
PRESET_MODE_AUTO,
PRESET_MODE_SMART,
PRESET_MODE_SLEEP,
PRESET_MODE_ON,
]
assert state.attributes[fan.ATTR_PRESET_MODES] == [ assert state.attributes[fan.ATTR_PRESET_MODES] == [
PRESET_MODE_AUTO, PRESET_MODE_AUTO,
PRESET_MODE_SMART, PRESET_MODE_SMART,
@ -226,7 +208,6 @@ async def test_turn_on_with_preset_mode_and_speed(hass, fan_entity_id):
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.state == STATE_ON assert state.state == STATE_ON
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_HIGH
assert state.attributes[fan.ATTR_PERCENTAGE] == 100 assert state.attributes[fan.ATTR_PERCENTAGE] == 100
assert state.attributes[fan.ATTR_PRESET_MODE] is None assert state.attributes[fan.ATTR_PRESET_MODE] is None
@ -238,7 +219,6 @@ async def test_turn_on_with_preset_mode_and_speed(hass, fan_entity_id):
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.state == STATE_ON assert state.state == STATE_ON
assert state.attributes[fan.ATTR_SPEED] == PRESET_MODE_SMART
assert state.attributes[fan.ATTR_PERCENTAGE] is None assert state.attributes[fan.ATTR_PERCENTAGE] is None
assert state.attributes[fan.ATTR_PRESET_MODE] == PRESET_MODE_SMART assert state.attributes[fan.ATTR_PRESET_MODE] == PRESET_MODE_SMART
@ -247,7 +227,6 @@ async def test_turn_on_with_preset_mode_and_speed(hass, fan_entity_id):
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.state == STATE_OFF assert state.state == STATE_OFF
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_OFF
assert state.attributes[fan.ATTR_PERCENTAGE] == 0 assert state.attributes[fan.ATTR_PERCENTAGE] == 0
assert state.attributes[fan.ATTR_PRESET_MODE] is None assert state.attributes[fan.ATTR_PRESET_MODE] is None
@ -262,7 +241,6 @@ async def test_turn_on_with_preset_mode_and_speed(hass, fan_entity_id):
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.state == STATE_OFF assert state.state == STATE_OFF
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_OFF
assert state.attributes[fan.ATTR_PERCENTAGE] == 0 assert state.attributes[fan.ATTR_PERCENTAGE] == 0
assert state.attributes[fan.ATTR_PRESET_MODE] is None assert state.attributes[fan.ATTR_PRESET_MODE] is None
@ -321,50 +299,6 @@ async def test_set_direction(hass, fan_entity_id):
assert state.attributes[fan.ATTR_DIRECTION] == fan.DIRECTION_REVERSE assert state.attributes[fan.ATTR_DIRECTION] == fan.DIRECTION_REVERSE
@pytest.mark.parametrize("fan_entity_id", LIMITED_AND_FULL_FAN_ENTITY_IDS)
async def test_set_speed(hass, fan_entity_id):
"""Test setting the speed of the device."""
state = hass.states.get(fan_entity_id)
assert state.state == STATE_OFF
await hass.services.async_call(
fan.DOMAIN,
fan.SERVICE_SET_SPEED,
{ATTR_ENTITY_ID: fan_entity_id, fan.ATTR_SPEED: fan.SPEED_LOW},
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_LOW
await hass.services.async_call(
fan.DOMAIN,
fan.SERVICE_SET_SPEED,
{ATTR_ENTITY_ID: fan_entity_id, fan.ATTR_SPEED: fan.SPEED_OFF},
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_OFF
@pytest.mark.parametrize("fan_entity_id", FANS_WITH_PRESET_MODES)
async def test_set_preset_mode_with_legacy_speed_service(hass, fan_entity_id):
"""Test setting the preset mode is possible with the legacy service for backwards compat."""
state = hass.states.get(fan_entity_id)
assert state.state == STATE_OFF
await hass.services.async_call(
fan.DOMAIN,
fan.SERVICE_SET_SPEED,
{ATTR_ENTITY_ID: fan_entity_id, fan.ATTR_SPEED: PRESET_MODE_AUTO},
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.state == STATE_ON
assert state.attributes[fan.ATTR_SPEED] == PRESET_MODE_AUTO
assert state.attributes[fan.ATTR_PERCENTAGE] is None
assert state.attributes[fan.ATTR_PRESET_MODE] == PRESET_MODE_AUTO
@pytest.mark.parametrize("fan_entity_id", FANS_WITH_PRESET_MODES) @pytest.mark.parametrize("fan_entity_id", FANS_WITH_PRESET_MODES)
async def test_set_preset_mode(hass, fan_entity_id): async def test_set_preset_mode(hass, fan_entity_id):
"""Test setting the preset mode of the device.""" """Test setting the preset mode of the device."""
@ -379,7 +313,6 @@ async def test_set_preset_mode(hass, fan_entity_id):
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.state == STATE_ON assert state.state == STATE_ON
assert state.attributes[fan.ATTR_SPEED] == PRESET_MODE_AUTO
assert state.attributes[fan.ATTR_PERCENTAGE] is None assert state.attributes[fan.ATTR_PERCENTAGE] is None
assert state.attributes[fan.ATTR_PRESET_MODE] == PRESET_MODE_AUTO assert state.attributes[fan.ATTR_PRESET_MODE] == PRESET_MODE_AUTO
@ -422,7 +355,6 @@ async def test_set_percentage(hass, fan_entity_id):
blocking=True, blocking=True,
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_LOW
assert state.attributes[fan.ATTR_PERCENTAGE] == 33 assert state.attributes[fan.ATTR_PERCENTAGE] == 33
@ -440,7 +372,6 @@ async def test_increase_decrease_speed(hass, fan_entity_id):
blocking=True, blocking=True,
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_LOW
assert state.attributes[fan.ATTR_PERCENTAGE] == 33 assert state.attributes[fan.ATTR_PERCENTAGE] == 33
await hass.services.async_call( await hass.services.async_call(
@ -450,7 +381,6 @@ async def test_increase_decrease_speed(hass, fan_entity_id):
blocking=True, blocking=True,
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_MEDIUM
assert state.attributes[fan.ATTR_PERCENTAGE] == 66 assert state.attributes[fan.ATTR_PERCENTAGE] == 66
await hass.services.async_call( await hass.services.async_call(
@ -460,7 +390,6 @@ async def test_increase_decrease_speed(hass, fan_entity_id):
blocking=True, blocking=True,
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_HIGH
assert state.attributes[fan.ATTR_PERCENTAGE] == 100 assert state.attributes[fan.ATTR_PERCENTAGE] == 100
await hass.services.async_call( await hass.services.async_call(
@ -470,7 +399,6 @@ async def test_increase_decrease_speed(hass, fan_entity_id):
blocking=True, blocking=True,
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_HIGH
assert state.attributes[fan.ATTR_PERCENTAGE] == 100 assert state.attributes[fan.ATTR_PERCENTAGE] == 100
await hass.services.async_call( await hass.services.async_call(
@ -481,7 +409,6 @@ async def test_increase_decrease_speed(hass, fan_entity_id):
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_PERCENTAGE] == 66 assert state.attributes[fan.ATTR_PERCENTAGE] == 66
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_MEDIUM
await hass.services.async_call( await hass.services.async_call(
fan.DOMAIN, fan.DOMAIN,
@ -490,7 +417,6 @@ async def test_increase_decrease_speed(hass, fan_entity_id):
blocking=True, blocking=True,
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_LOW
assert state.attributes[fan.ATTR_PERCENTAGE] == 33 assert state.attributes[fan.ATTR_PERCENTAGE] == 33
await hass.services.async_call( await hass.services.async_call(
@ -500,7 +426,6 @@ async def test_increase_decrease_speed(hass, fan_entity_id):
blocking=True, blocking=True,
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_OFF
assert state.attributes[fan.ATTR_PERCENTAGE] == 0 assert state.attributes[fan.ATTR_PERCENTAGE] == 0
await hass.services.async_call( await hass.services.async_call(
@ -510,7 +435,6 @@ async def test_increase_decrease_speed(hass, fan_entity_id):
blocking=True, blocking=True,
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_OFF
assert state.attributes[fan.ATTR_PERCENTAGE] == 0 assert state.attributes[fan.ATTR_PERCENTAGE] == 0
@ -524,7 +448,6 @@ async def test_increase_decrease_speed_with_percentage_step(hass, fan_entity_id)
blocking=True, blocking=True,
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_LOW
assert state.attributes[fan.ATTR_PERCENTAGE] == 25 assert state.attributes[fan.ATTR_PERCENTAGE] == 25
await hass.services.async_call( await hass.services.async_call(
@ -534,7 +457,6 @@ async def test_increase_decrease_speed_with_percentage_step(hass, fan_entity_id)
blocking=True, blocking=True,
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_MEDIUM
assert state.attributes[fan.ATTR_PERCENTAGE] == 50 assert state.attributes[fan.ATTR_PERCENTAGE] == 50
await hass.services.async_call( await hass.services.async_call(
@ -544,7 +466,6 @@ async def test_increase_decrease_speed_with_percentage_step(hass, fan_entity_id)
blocking=True, blocking=True,
) )
state = hass.states.get(fan_entity_id) state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_HIGH
assert state.attributes[fan.ATTR_PERCENTAGE] == 75 assert state.attributes[fan.ATTR_PERCENTAGE] == 75

View file

@ -1033,17 +1033,14 @@ async def test_put_light_state_fan(hass_hue, hue_client):
living_room_fan = hass_hue.states.get("fan.living_room_fan") living_room_fan = hass_hue.states.get("fan.living_room_fan")
assert living_room_fan.state == "on" assert living_room_fan.state == "on"
assert living_room_fan.attributes[fan.ATTR_SPEED] == fan.SPEED_MEDIUM assert living_room_fan.attributes[fan.ATTR_PERCENTAGE] == 43
# Check setting the brightness of a fan to 0, 33%, 66% and 100% will respectively turn it off, low, medium or high # Check setting the brightness of a fan to 0, 33%, 66% and 100% will respectively turn it off, low, medium or high
# We also check non-cached GET value to exercise the code. # We also check non-cached GET value to exercise the code.
await perform_put_light_state( await perform_put_light_state(
hass_hue, hue_client, "fan.living_room_fan", True, brightness=0 hass_hue, hue_client, "fan.living_room_fan", True, brightness=0
) )
assert ( assert hass_hue.states.get("fan.living_room_fan").state == STATE_OFF
hass_hue.states.get("fan.living_room_fan").attributes[fan.ATTR_SPEED]
== fan.SPEED_OFF
)
await perform_put_light_state( await perform_put_light_state(
hass_hue, hass_hue,
hue_client, hue_client,
@ -1052,8 +1049,7 @@ async def test_put_light_state_fan(hass_hue, hue_client):
brightness=round(33 * 254 / 100), brightness=round(33 * 254 / 100),
) )
assert ( assert (
hass_hue.states.get("fan.living_room_fan").attributes[fan.ATTR_SPEED] hass_hue.states.get("fan.living_room_fan").attributes[fan.ATTR_PERCENTAGE] == 33
== fan.SPEED_LOW
) )
with patch.object(hue_api, "STATE_CACHED_TIMEOUT", 0.000001): with patch.object(hue_api, "STATE_CACHED_TIMEOUT", 0.000001):
await asyncio.sleep(0.000001) await asyncio.sleep(0.000001)
@ -1070,8 +1066,7 @@ async def test_put_light_state_fan(hass_hue, hue_client):
brightness=round(66 * 254 / 100), brightness=round(66 * 254 / 100),
) )
assert ( assert (
hass_hue.states.get("fan.living_room_fan").attributes[fan.ATTR_SPEED] hass_hue.states.get("fan.living_room_fan").attributes[fan.ATTR_PERCENTAGE] == 66
== fan.SPEED_MEDIUM
) )
with patch.object(hue_api, "STATE_CACHED_TIMEOUT", 0.000001): with patch.object(hue_api, "STATE_CACHED_TIMEOUT", 0.000001):
await asyncio.sleep(0.000001) await asyncio.sleep(0.000001)
@ -1079,7 +1074,7 @@ async def test_put_light_state_fan(hass_hue, hue_client):
hue_client, "fan.living_room_fan", HTTPStatus.OK hue_client, "fan.living_room_fan", HTTPStatus.OK
) )
assert ( assert (
round(fan_json["state"][HUE_API_STATE_BRI] * 100 / 254) == 67 round(fan_json["state"][HUE_API_STATE_BRI] * 100 / 254) == 66
) # small rounding error in inverse operation ) # small rounding error in inverse operation
await perform_put_light_state( await perform_put_light_state(
@ -1090,8 +1085,8 @@ async def test_put_light_state_fan(hass_hue, hue_client):
brightness=round(100 * 254 / 100), brightness=round(100 * 254 / 100),
) )
assert ( assert (
hass_hue.states.get("fan.living_room_fan").attributes[fan.ATTR_SPEED] hass_hue.states.get("fan.living_room_fan").attributes[fan.ATTR_PERCENTAGE]
== fan.SPEED_HIGH == 100
) )
with patch.object(hue_api, "STATE_CACHED_TIMEOUT", 0.000001): with patch.object(hue_api, "STATE_CACHED_TIMEOUT", 0.000001):
await asyncio.sleep(0.000001) await asyncio.sleep(0.000001)

View file

@ -9,9 +9,9 @@ from homeassistant.components.emulated_kasa.const import (
DOMAIN, DOMAIN,
) )
from homeassistant.components.fan import ( from homeassistant.components.fan import (
ATTR_SPEED, ATTR_PERCENTAGE,
DOMAIN as FAN_DOMAIN, DOMAIN as FAN_DOMAIN,
SERVICE_SET_SPEED, SERVICE_SET_PERCENTAGE,
) )
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
@ -57,15 +57,15 @@ CONFIG = {
ENTITY_FAN: { ENTITY_FAN: {
CONF_POWER: "{% if is_state_attr('" CONF_POWER: "{% if is_state_attr('"
+ ENTITY_FAN + ENTITY_FAN
+ "','speed', 'low') %} " + "','percentage', 33) %} "
+ str(ENTITY_FAN_SPEED_LOW) + str(ENTITY_FAN_SPEED_LOW)
+ "{% elif is_state_attr('" + "{% elif is_state_attr('"
+ ENTITY_FAN + ENTITY_FAN
+ "','speed', 'medium') %} " + "','percentage', 66) %} "
+ str(ENTITY_FAN_SPEED_MED) + str(ENTITY_FAN_SPEED_MED)
+ "{% elif is_state_attr('" + "{% elif is_state_attr('"
+ ENTITY_FAN + ENTITY_FAN
+ "','speed', 'high') %} " + "','percentage', 100) %} "
+ str(ENTITY_FAN_SPEED_HIGH) + str(ENTITY_FAN_SPEED_HIGH)
+ "{% endif %}" + "{% endif %}"
}, },
@ -109,15 +109,15 @@ CONFIG_FAN = {
ENTITY_FAN: { ENTITY_FAN: {
CONF_POWER: "{% if is_state_attr('" CONF_POWER: "{% if is_state_attr('"
+ ENTITY_FAN + ENTITY_FAN
+ "','speed', 'low') %} " + "','percentage', 33) %} "
+ str(ENTITY_FAN_SPEED_LOW) + str(ENTITY_FAN_SPEED_LOW)
+ "{% elif is_state_attr('" + "{% elif is_state_attr('"
+ ENTITY_FAN + ENTITY_FAN
+ "','speed', 'medium') %} " + "','percentage', 66) %} "
+ str(ENTITY_FAN_SPEED_MED) + str(ENTITY_FAN_SPEED_MED)
+ "{% elif is_state_attr('" + "{% elif is_state_attr('"
+ ENTITY_FAN + ENTITY_FAN
+ "','speed', 'high') %} " + "','percentage', 100) %} "
+ str(ENTITY_FAN_SPEED_HIGH) + str(ENTITY_FAN_SPEED_HIGH)
+ "{% endif %}" + "{% endif %}"
}, },
@ -125,6 +125,7 @@ CONFIG_FAN = {
} }
} }
CONFIG_SENSOR = { CONFIG_SENSOR = {
DOMAIN: { DOMAIN: {
CONF_ENTITIES: { CONF_ENTITIES: {
@ -281,8 +282,8 @@ async def test_template(hass):
) )
await hass.services.async_call( await hass.services.async_call(
FAN_DOMAIN, FAN_DOMAIN,
SERVICE_SET_SPEED, SERVICE_SET_PERCENTAGE,
{ATTR_ENTITY_ID: ENTITY_FAN, ATTR_SPEED: "low"}, {ATTR_ENTITY_ID: ENTITY_FAN, ATTR_PERCENTAGE: 33},
blocking=True, blocking=True,
) )
@ -299,8 +300,8 @@ async def test_template(hass):
# Fan High: # Fan High:
await hass.services.async_call( await hass.services.async_call(
FAN_DOMAIN, FAN_DOMAIN,
SERVICE_SET_SPEED, SERVICE_SET_PERCENTAGE,
{ATTR_ENTITY_ID: ENTITY_FAN, ATTR_SPEED: "high"}, {ATTR_ENTITY_ID: ENTITY_FAN, ATTR_PERCENTAGE: 100},
blocking=True, blocking=True,
) )
plug_it = emulated_kasa.get_plug_devices(hass, config) plug_it = emulated_kasa.get_plug_devices(hass, config)
@ -462,8 +463,8 @@ async def test_multiple_devices(hass):
) )
await hass.services.async_call( await hass.services.async_call(
FAN_DOMAIN, FAN_DOMAIN,
SERVICE_SET_SPEED, SERVICE_SET_PERCENTAGE,
{ATTR_ENTITY_ID: ENTITY_FAN, ATTR_SPEED: "medium"}, {ATTR_ENTITY_ID: ENTITY_FAN, ATTR_PERCENTAGE: 66},
blocking=True, blocking=True,
) )

View file

@ -9,7 +9,6 @@ from homeassistant.components.fan import (
ATTR_PERCENTAGE, ATTR_PERCENTAGE,
ATTR_PERCENTAGE_STEP, ATTR_PERCENTAGE_STEP,
ATTR_PRESET_MODE, ATTR_PRESET_MODE,
ATTR_SPEED,
DOMAIN, DOMAIN,
SERVICE_DECREASE_SPEED, SERVICE_DECREASE_SPEED,
SERVICE_INCREASE_SPEED, SERVICE_INCREASE_SPEED,
@ -17,7 +16,6 @@ from homeassistant.components.fan import (
SERVICE_SET_DIRECTION, SERVICE_SET_DIRECTION,
SERVICE_SET_PERCENTAGE, SERVICE_SET_PERCENTAGE,
SERVICE_SET_PRESET_MODE, SERVICE_SET_PRESET_MODE,
SERVICE_SET_SPEED,
) )
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
@ -30,7 +28,6 @@ from homeassistant.const import (
async def async_turn_on( async def async_turn_on(
hass, hass,
entity_id=ENTITY_MATCH_ALL, entity_id=ENTITY_MATCH_ALL,
speed: str = None,
percentage: int = None, percentage: int = None,
preset_mode: str = None, preset_mode: str = None,
) -> None: ) -> None:
@ -39,7 +36,6 @@ async def async_turn_on(
key: value key: value
for key, value in [ for key, value in [
(ATTR_ENTITY_ID, entity_id), (ATTR_ENTITY_ID, entity_id),
(ATTR_SPEED, speed),
(ATTR_PERCENTAGE, percentage), (ATTR_PERCENTAGE, percentage),
(ATTR_PRESET_MODE, preset_mode), (ATTR_PRESET_MODE, preset_mode),
] ]
@ -72,17 +68,6 @@ async def async_oscillate(
await hass.services.async_call(DOMAIN, SERVICE_OSCILLATE, data, blocking=True) await hass.services.async_call(DOMAIN, SERVICE_OSCILLATE, data, blocking=True)
async def async_set_speed(hass, entity_id=ENTITY_MATCH_ALL, speed: str = None) -> None:
"""Set speed for all or specified fan."""
data = {
key: value
for key, value in [(ATTR_ENTITY_ID, entity_id), (ATTR_SPEED, speed)]
if value is not None
}
await hass.services.async_call(DOMAIN, SERVICE_SET_SPEED, data, blocking=True)
async def async_set_preset_mode( async def async_set_preset_mode(
hass, entity_id=ENTITY_MATCH_ALL, preset_mode: str = None hass, entity_id=ENTITY_MATCH_ALL, preset_mode: str = None
) -> None: ) -> None:

View file

@ -16,7 +16,6 @@ def test_fanentity():
"""Test fan entity methods.""" """Test fan entity methods."""
fan = BaseFan() fan = BaseFan()
assert fan.state == "off" assert fan.state == "off"
assert len(fan.speed_list) == 4 # legacy compat off,low,medium,high
assert fan.preset_modes is None assert fan.preset_modes is None
assert fan.supported_features == 0 assert fan.supported_features == 0
assert fan.percentage_step == 1 assert fan.percentage_step == 1
@ -25,7 +24,7 @@ def test_fanentity():
# Test set_speed not required # Test set_speed not required
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
fan.oscillate(True) fan.oscillate(True)
with pytest.raises(NotImplementedError): with pytest.raises(AttributeError):
fan.set_speed("low") fan.set_speed("low")
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
fan.set_percentage(0) fan.set_percentage(0)
@ -42,7 +41,6 @@ async def test_async_fanentity(hass):
fan = BaseFan() fan = BaseFan()
fan.hass = hass fan.hass = hass
assert fan.state == "off" assert fan.state == "off"
assert len(fan.speed_list) == 4 # legacy compat off,low,medium,high
assert fan.preset_modes is None assert fan.preset_modes is None
assert fan.supported_features == 0 assert fan.supported_features == 0
assert fan.percentage_step == 1 assert fan.percentage_step == 1
@ -51,7 +49,7 @@ async def test_async_fanentity(hass):
# Test set_speed not required # Test set_speed not required
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
await fan.async_oscillate(True) await fan.async_oscillate(True)
with pytest.raises(NotImplementedError): with pytest.raises(AttributeError):
await fan.async_set_speed("low") await fan.async_set_speed("low")
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
await fan.async_set_percentage(0) await fan.async_set_percentage(0)

View file

@ -8,7 +8,7 @@ async def test_reproducing_states(hass, caplog):
"""Test reproducing Fan states.""" """Test reproducing Fan states."""
hass.states.async_set("fan.entity_off", "off", {}) hass.states.async_set("fan.entity_off", "off", {})
hass.states.async_set("fan.entity_on", "on", {}) hass.states.async_set("fan.entity_on", "on", {})
hass.states.async_set("fan.entity_speed", "on", {"speed": "high"}) hass.states.async_set("fan.entity_speed", "on", {"percentage": 100})
hass.states.async_set("fan.entity_oscillating", "on", {"oscillating": True}) hass.states.async_set("fan.entity_oscillating", "on", {"oscillating": True})
hass.states.async_set("fan.entity_direction", "on", {"direction": "forward"}) hass.states.async_set("fan.entity_direction", "on", {"direction": "forward"})
@ -16,14 +16,14 @@ async def test_reproducing_states(hass, caplog):
turn_off_calls = async_mock_service(hass, "fan", "turn_off") turn_off_calls = async_mock_service(hass, "fan", "turn_off")
set_direction_calls = async_mock_service(hass, "fan", "set_direction") set_direction_calls = async_mock_service(hass, "fan", "set_direction")
oscillate_calls = async_mock_service(hass, "fan", "oscillate") oscillate_calls = async_mock_service(hass, "fan", "oscillate")
set_speed_calls = async_mock_service(hass, "fan", "set_speed") set_percentage_calls = async_mock_service(hass, "fan", "set_percentage")
# These calls should do nothing as entities already in desired state # These calls should do nothing as entities already in desired state
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[ [
State("fan.entity_off", "off"), State("fan.entity_off", "off"),
State("fan.entity_on", "on"), State("fan.entity_on", "on"),
State("fan.entity_speed", "on", {"speed": "high"}), State("fan.entity_speed", "on", {"percentage": 100}),
State("fan.entity_oscillating", "on", {"oscillating": True}), State("fan.entity_oscillating", "on", {"oscillating": True}),
State("fan.entity_direction", "on", {"direction": "forward"}), State("fan.entity_direction", "on", {"direction": "forward"}),
], ],
@ -33,7 +33,6 @@ async def test_reproducing_states(hass, caplog):
assert len(turn_off_calls) == 0 assert len(turn_off_calls) == 0
assert len(set_direction_calls) == 0 assert len(set_direction_calls) == 0
assert len(oscillate_calls) == 0 assert len(oscillate_calls) == 0
assert len(set_speed_calls) == 0
# Test invalid state is handled # Test invalid state is handled
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
@ -45,14 +44,14 @@ async def test_reproducing_states(hass, caplog):
assert len(turn_off_calls) == 0 assert len(turn_off_calls) == 0
assert len(set_direction_calls) == 0 assert len(set_direction_calls) == 0
assert len(oscillate_calls) == 0 assert len(oscillate_calls) == 0
assert len(set_speed_calls) == 0 assert len(set_percentage_calls) == 0
# Make sure correct services are called # Make sure correct services are called
await hass.helpers.state.async_reproduce_state( await hass.helpers.state.async_reproduce_state(
[ [
State("fan.entity_on", "off"), State("fan.entity_on", "off"),
State("fan.entity_off", "on"), State("fan.entity_off", "on"),
State("fan.entity_speed", "on", {"speed": "low"}), State("fan.entity_speed", "on", {"percentage": 25}),
State("fan.entity_oscillating", "on", {"oscillating": False}), State("fan.entity_oscillating", "on", {"oscillating": False}),
State("fan.entity_direction", "on", {"direction": "reverse"}), State("fan.entity_direction", "on", {"direction": "reverse"}),
# Should not raise # Should not raise
@ -78,9 +77,12 @@ async def test_reproducing_states(hass, caplog):
"oscillating": False, "oscillating": False,
} }
assert len(set_speed_calls) == 1 assert len(set_percentage_calls) == 1
assert set_speed_calls[0].domain == "fan" assert set_percentage_calls[0].domain == "fan"
assert set_speed_calls[0].data == {"entity_id": "fan.entity_speed", "speed": "low"} assert set_percentage_calls[0].data == {
"entity_id": "fan.entity_speed",
"percentage": 25,
}
assert len(turn_off_calls) == 1 assert len(turn_off_calls) == 1
assert turn_off_calls[0].domain == "fan" assert turn_off_calls[0].domain == "fan"

View file

@ -1589,7 +1589,7 @@ async def test_fan_speed(hass):
hass, hass,
State( State(
"fan.living_room_fan", "fan.living_room_fan",
fan.SPEED_HIGH, STATE_ON,
attributes={ attributes={
"percentage": 33, "percentage": 33,
"percentage_step": 1.0, "percentage_step": 1.0,
@ -1633,7 +1633,7 @@ async def test_fan_reverse(hass, direction_state, direction_call):
hass, hass,
State( State(
"fan.living_room_fan", "fan.living_room_fan",
fan.SPEED_HIGH, STATE_ON,
attributes={ attributes={
"percentage": 33, "percentage": 33,
"percentage_step": 1.0, "percentage_step": 1.0,

View file

@ -59,7 +59,6 @@ async def test_haa_fan_setup(hass):
supported_features=SUPPORT_SET_SPEED, supported_features=SUPPORT_SET_SPEED,
capabilities={ capabilities={
"preset_modes": None, "preset_modes": None,
"speed_list": ["off", "low", "medium", "high"],
}, },
), ),
EntityTestInfo( EntityTestInfo(

View file

@ -55,7 +55,6 @@ async def test_homeassistant_bridge_fan_setup(hass):
), ),
capabilities={ capabilities={
"preset_modes": None, "preset_modes": None,
"speed_list": ["off", "low", "medium", "high"],
}, },
state="off", state="off",
) )

View file

@ -40,7 +40,6 @@ async def test_simpleconnect_fan_setup(hass):
supported_features=SUPPORT_DIRECTION | SUPPORT_SET_SPEED, supported_features=SUPPORT_DIRECTION | SUPPORT_SET_SPEED,
capabilities={ capabilities={
"preset_modes": None, "preset_modes": None,
"speed_list": ["off", "low", "medium", "high"],
}, },
state="off", state="off",
), ),

View file

@ -95,7 +95,7 @@ async def test_turn_on(hass, utcnow):
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"turn_on", "turn_on",
{"entity_id": "fan.testdevice", "speed": "high"}, {"entity_id": "fan.testdevice", "percentage": 100},
blocking=True, blocking=True,
) )
helper.async_assert_service_values( helper.async_assert_service_values(
@ -109,7 +109,7 @@ async def test_turn_on(hass, utcnow):
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"turn_on", "turn_on",
{"entity_id": "fan.testdevice", "speed": "medium"}, {"entity_id": "fan.testdevice", "percentage": 66},
blocking=True, blocking=True,
) )
helper.async_assert_service_values( helper.async_assert_service_values(
@ -123,7 +123,7 @@ async def test_turn_on(hass, utcnow):
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"turn_on", "turn_on",
{"entity_id": "fan.testdevice", "speed": "low"}, {"entity_id": "fan.testdevice", "percentage": 33},
blocking=True, blocking=True,
) )
helper.async_assert_service_values( helper.async_assert_service_values(
@ -196,8 +196,8 @@ async def test_set_speed(hass, utcnow):
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"set_speed", "set_percentage",
{"entity_id": "fan.testdevice", "speed": "high"}, {"entity_id": "fan.testdevice", "percentage": 100},
blocking=True, blocking=True,
) )
helper.async_assert_service_values( helper.async_assert_service_values(
@ -209,8 +209,8 @@ async def test_set_speed(hass, utcnow):
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"set_speed", "set_percentage",
{"entity_id": "fan.testdevice", "speed": "medium"}, {"entity_id": "fan.testdevice", "percentage": 66},
blocking=True, blocking=True,
) )
helper.async_assert_service_values( helper.async_assert_service_values(
@ -222,8 +222,8 @@ async def test_set_speed(hass, utcnow):
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"set_speed", "set_percentage",
{"entity_id": "fan.testdevice", "speed": "low"}, {"entity_id": "fan.testdevice", "percentage": 33},
blocking=True, blocking=True,
) )
helper.async_assert_service_values( helper.async_assert_service_values(
@ -235,8 +235,8 @@ async def test_set_speed(hass, utcnow):
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"set_speed", "set_percentage",
{"entity_id": "fan.testdevice", "speed": "off"}, {"entity_id": "fan.testdevice", "percentage": 0},
blocking=True, blocking=True,
) )
helper.async_assert_service_values( helper.async_assert_service_values(
@ -291,7 +291,6 @@ async def test_speed_read(hass, utcnow):
CharacteristicsTypes.ROTATION_SPEED: 100, CharacteristicsTypes.ROTATION_SPEED: 100,
}, },
) )
assert state.attributes["speed"] == "high"
assert state.attributes["percentage"] == 100 assert state.attributes["percentage"] == 100
assert state.attributes["percentage_step"] == 1.0 assert state.attributes["percentage_step"] == 1.0
@ -301,7 +300,6 @@ async def test_speed_read(hass, utcnow):
CharacteristicsTypes.ROTATION_SPEED: 50, CharacteristicsTypes.ROTATION_SPEED: 50,
}, },
) )
assert state.attributes["speed"] == "medium"
assert state.attributes["percentage"] == 50 assert state.attributes["percentage"] == 50
state = await helper.async_update( state = await helper.async_update(
@ -310,7 +308,6 @@ async def test_speed_read(hass, utcnow):
CharacteristicsTypes.ROTATION_SPEED: 25, CharacteristicsTypes.ROTATION_SPEED: 25,
}, },
) )
assert state.attributes["speed"] == "low"
assert state.attributes["percentage"] == 25 assert state.attributes["percentage"] == 25
state = await helper.async_update( state = await helper.async_update(
@ -320,7 +317,6 @@ async def test_speed_read(hass, utcnow):
CharacteristicsTypes.ROTATION_SPEED: 0, CharacteristicsTypes.ROTATION_SPEED: 0,
}, },
) )
assert state.attributes["speed"] == "off"
assert state.attributes["percentage"] == 0 assert state.attributes["percentage"] == 0
@ -392,7 +388,7 @@ async def test_v2_turn_on(hass, utcnow):
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"turn_on", "turn_on",
{"entity_id": "fan.testdevice", "speed": "high"}, {"entity_id": "fan.testdevice", "percentage": 100},
blocking=True, blocking=True,
) )
helper.async_assert_service_values( helper.async_assert_service_values(
@ -406,7 +402,7 @@ async def test_v2_turn_on(hass, utcnow):
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"turn_on", "turn_on",
{"entity_id": "fan.testdevice", "speed": "medium"}, {"entity_id": "fan.testdevice", "percentage": 66},
blocking=True, blocking=True,
) )
helper.async_assert_service_values( helper.async_assert_service_values(
@ -420,7 +416,7 @@ async def test_v2_turn_on(hass, utcnow):
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"turn_on", "turn_on",
{"entity_id": "fan.testdevice", "speed": "low"}, {"entity_id": "fan.testdevice", "percentage": 33},
blocking=True, blocking=True,
) )
helper.async_assert_service_values( helper.async_assert_service_values(
@ -488,8 +484,8 @@ async def test_v2_set_speed(hass, utcnow):
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"set_speed", "set_percentage",
{"entity_id": "fan.testdevice", "speed": "high"}, {"entity_id": "fan.testdevice", "percentage": 100},
blocking=True, blocking=True,
) )
helper.async_assert_service_values( helper.async_assert_service_values(
@ -501,8 +497,8 @@ async def test_v2_set_speed(hass, utcnow):
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"set_speed", "set_percentage",
{"entity_id": "fan.testdevice", "speed": "medium"}, {"entity_id": "fan.testdevice", "percentage": 66},
blocking=True, blocking=True,
) )
helper.async_assert_service_values( helper.async_assert_service_values(
@ -514,8 +510,8 @@ async def test_v2_set_speed(hass, utcnow):
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"set_speed", "set_percentage",
{"entity_id": "fan.testdevice", "speed": "low"}, {"entity_id": "fan.testdevice", "percentage": 33},
blocking=True, blocking=True,
) )
helper.async_assert_service_values( helper.async_assert_service_values(
@ -527,8 +523,8 @@ async def test_v2_set_speed(hass, utcnow):
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"set_speed", "set_percentage",
{"entity_id": "fan.testdevice", "speed": "off"}, {"entity_id": "fan.testdevice", "percentage": 0},
blocking=True, blocking=True,
) )
helper.async_assert_service_values( helper.async_assert_service_values(
@ -616,7 +612,6 @@ async def test_v2_speed_read(hass, utcnow):
CharacteristicsTypes.ROTATION_SPEED: 100, CharacteristicsTypes.ROTATION_SPEED: 100,
}, },
) )
assert state.attributes["speed"] == "high"
assert state.attributes["percentage"] == 100 assert state.attributes["percentage"] == 100
state = await helper.async_update( state = await helper.async_update(
@ -625,7 +620,6 @@ async def test_v2_speed_read(hass, utcnow):
CharacteristicsTypes.ROTATION_SPEED: 50, CharacteristicsTypes.ROTATION_SPEED: 50,
}, },
) )
assert state.attributes["speed"] == "medium"
assert state.attributes["percentage"] == 50 assert state.attributes["percentage"] == 50
state = await helper.async_update( state = await helper.async_update(
@ -634,7 +628,6 @@ async def test_v2_speed_read(hass, utcnow):
CharacteristicsTypes.ROTATION_SPEED: 25, CharacteristicsTypes.ROTATION_SPEED: 25,
}, },
) )
assert state.attributes["speed"] == "low"
assert state.attributes["percentage"] == 25 assert state.attributes["percentage"] == 25
state = await helper.async_update( state = await helper.async_update(
@ -644,7 +637,6 @@ async def test_v2_speed_read(hass, utcnow):
CharacteristicsTypes.ROTATION_SPEED: 0, CharacteristicsTypes.ROTATION_SPEED: 0,
}, },
) )
assert state.attributes["speed"] == "off"
assert state.attributes["percentage"] == 0 assert state.attributes["percentage"] == 0

View file

@ -3,6 +3,9 @@ import json
from unittest.mock import AsyncMock, Mock, patch from unittest.mock import AsyncMock, Mock, patch
from homeassistant.components.climate.const import ( from homeassistant.components.climate.const import (
FAN_HIGH,
FAN_LOW,
FAN_MEDIUM,
HVAC_MODE_COOL, HVAC_MODE_COOL,
HVAC_MODE_DRY, HVAC_MODE_DRY,
HVAC_MODE_FAN_ONLY, HVAC_MODE_FAN_ONLY,
@ -11,7 +14,6 @@ from homeassistant.components.climate.const import (
SUPPORT_FAN_MODE, SUPPORT_FAN_MODE,
SUPPORT_TARGET_TEMPERATURE, SUPPORT_TARGET_TEMPERATURE,
) )
from homeassistant.components.fan import SPEED_HIGH, SPEED_LOW, SPEED_MEDIUM
from homeassistant.components.melissa import DATA_MELISSA, climate as melissa from homeassistant.components.melissa import DATA_MELISSA, climate as melissa
from homeassistant.components.melissa.climate import MelissaClimate from homeassistant.components.melissa.climate import MelissaClimate
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
@ -94,7 +96,7 @@ async def test_current_fan_mode(hass):
device = (await api.async_fetch_devices())[_SERIAL] device = (await api.async_fetch_devices())[_SERIAL]
thermostat = MelissaClimate(api, _SERIAL, device) thermostat = MelissaClimate(api, _SERIAL, device)
await thermostat.async_update() await thermostat.async_update()
assert thermostat.fan_mode == SPEED_LOW assert thermostat.fan_mode == FAN_LOW
thermostat._cur_settings = None thermostat._cur_settings = None
assert thermostat.fan_mode is None assert thermostat.fan_mode is None
@ -162,7 +164,7 @@ async def test_fan_modes(hass):
api = melissa_mock() api = melissa_mock()
device = (await api.async_fetch_devices())[_SERIAL] device = (await api.async_fetch_devices())[_SERIAL]
thermostat = MelissaClimate(api, _SERIAL, device) thermostat = MelissaClimate(api, _SERIAL, device)
assert ["auto", SPEED_HIGH, SPEED_MEDIUM, SPEED_LOW] == thermostat.fan_modes assert ["auto", FAN_HIGH, FAN_MEDIUM, FAN_LOW] == thermostat.fan_modes
async def test_target_temperature(hass): async def test_target_temperature(hass):
@ -247,9 +249,9 @@ async def test_fan_mode(hass):
thermostat = MelissaClimate(api, _SERIAL, device) thermostat = MelissaClimate(api, _SERIAL, device)
await thermostat.async_update() await thermostat.async_update()
await hass.async_block_till_done() await hass.async_block_till_done()
await thermostat.async_set_fan_mode(SPEED_HIGH) await thermostat.async_set_fan_mode(FAN_HIGH)
await hass.async_block_till_done() await hass.async_block_till_done()
assert thermostat.fan_mode == SPEED_HIGH assert thermostat.fan_mode == FAN_HIGH
async def test_set_operation_mode(hass): async def test_set_operation_mode(hass):
@ -275,12 +277,12 @@ async def test_send(hass):
await hass.async_block_till_done() await hass.async_block_till_done()
await thermostat.async_send({"fan": api.FAN_MEDIUM}) await thermostat.async_send({"fan": api.FAN_MEDIUM})
await hass.async_block_till_done() await hass.async_block_till_done()
assert thermostat.fan_mode == SPEED_MEDIUM assert thermostat.fan_mode == FAN_MEDIUM
api.async_send.return_value = AsyncMock(return_value=False) api.async_send.return_value = AsyncMock(return_value=False)
thermostat._cur_settings = None thermostat._cur_settings = None
await thermostat.async_send({"fan": api.FAN_LOW}) await thermostat.async_send({"fan": api.FAN_LOW})
await hass.async_block_till_done() await hass.async_block_till_done()
assert SPEED_LOW != thermostat.fan_mode assert FAN_LOW != thermostat.fan_mode
assert thermostat._cur_settings is None assert thermostat._cur_settings is None
@ -293,7 +295,7 @@ async def test_update(hass):
device = (await api.async_fetch_devices())[_SERIAL] device = (await api.async_fetch_devices())[_SERIAL]
thermostat = MelissaClimate(api, _SERIAL, device) thermostat = MelissaClimate(api, _SERIAL, device)
await thermostat.async_update() await thermostat.async_update()
assert thermostat.fan_mode == SPEED_LOW assert thermostat.fan_mode == FAN_LOW
assert thermostat.state == HVAC_MODE_HEAT assert thermostat.state == HVAC_MODE_HEAT
api.async_status = AsyncMock(side_effect=KeyError("boom")) api.async_status = AsyncMock(side_effect=KeyError("boom"))
await thermostat.async_update() await thermostat.async_update()
@ -322,9 +324,9 @@ async def test_melissa_fan_to_hass(hass):
device = (await api.async_fetch_devices())[_SERIAL] device = (await api.async_fetch_devices())[_SERIAL]
thermostat = MelissaClimate(api, _SERIAL, device) thermostat = MelissaClimate(api, _SERIAL, device)
assert thermostat.melissa_fan_to_hass(0) == "auto" assert thermostat.melissa_fan_to_hass(0) == "auto"
assert thermostat.melissa_fan_to_hass(1) == SPEED_LOW assert thermostat.melissa_fan_to_hass(1) == FAN_LOW
assert thermostat.melissa_fan_to_hass(2) == SPEED_MEDIUM assert thermostat.melissa_fan_to_hass(2) == FAN_MEDIUM
assert thermostat.melissa_fan_to_hass(3) == SPEED_HIGH assert thermostat.melissa_fan_to_hass(3) == FAN_HIGH
assert thermostat.melissa_fan_to_hass(4) is None assert thermostat.melissa_fan_to_hass(4) is None
@ -355,9 +357,9 @@ async def test_hass_fan_to_melissa(hass):
device = (await api.async_fetch_devices())[_SERIAL] device = (await api.async_fetch_devices())[_SERIAL]
thermostat = MelissaClimate(api, _SERIAL, device) thermostat = MelissaClimate(api, _SERIAL, device)
assert thermostat.hass_fan_to_melissa("auto") == 0 assert thermostat.hass_fan_to_melissa("auto") == 0
assert thermostat.hass_fan_to_melissa(SPEED_LOW) == 1 assert thermostat.hass_fan_to_melissa(FAN_LOW) == 1
assert thermostat.hass_fan_to_melissa(SPEED_MEDIUM) == 2 assert thermostat.hass_fan_to_melissa(FAN_MEDIUM) == 2
assert thermostat.hass_fan_to_melissa(SPEED_HIGH) == 3 assert thermostat.hass_fan_to_melissa(FAN_HIGH) == 3
thermostat.hass_fan_to_melissa("test") thermostat.hass_fan_to_melissa("test")
mocked_warning.assert_called_once_with( mocked_warning.assert_called_once_with(
"Melissa have no setting for %s fan mode", "test" "Melissa have no setting for %s fan mode", "test"

View file

@ -194,7 +194,6 @@ async def test_controlling_state_via_topic(hass, mqtt_mock, caplog):
async_fire_mqtt_message(hass, "percentage-state-topic", "rEset_percentage") async_fire_mqtt_message(hass, "percentage-state-topic", "rEset_percentage")
state = hass.states.get("fan.test") state = hass.states.get("fan.test")
assert state.attributes.get(fan.ATTR_PERCENTAGE) is None assert state.attributes.get(fan.ATTR_PERCENTAGE) is None
assert state.attributes.get(fan.ATTR_SPEED) is None
async_fire_mqtt_message(hass, "state-topic", "None") async_fire_mqtt_message(hass, "state-topic", "None")
state = hass.states.get("fan.test") state = hass.states.get("fan.test")
@ -599,9 +598,8 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock, caplog):
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 0 assert state.attributes.get(fan.ATTR_PERCENTAGE) == 0
assert state.attributes.get(ATTR_ASSUMED_STATE) assert state.attributes.get(ATTR_ASSUMED_STATE)
await common.async_set_preset_mode(hass, "fan.test", "low") with pytest.raises(NotValidPresetModeError):
assert "not a valid preset mode" in caplog.text await common.async_set_preset_mode(hass, "fan.test", "low")
caplog.clear()
await common.async_set_preset_mode(hass, "fan.test", "whoosh") await common.async_set_preset_mode(hass, "fan.test", "whoosh")
mqtt_mock.async_publish.assert_called_once_with( mqtt_mock.async_publish.assert_called_once_with(
@ -799,13 +797,11 @@ async def test_sending_mqtt_commands_and_optimistic_no_legacy(hass, mqtt_mock, c
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 0 assert state.attributes.get(fan.ATTR_PERCENTAGE) == 0
assert state.attributes.get(ATTR_ASSUMED_STATE) assert state.attributes.get(ATTR_ASSUMED_STATE)
await common.async_set_preset_mode(hass, "fan.test", "low") with pytest.raises(NotValidPresetModeError):
assert "not a valid preset mode" in caplog.text await common.async_set_preset_mode(hass, "fan.test", "low")
caplog.clear()
await common.async_set_preset_mode(hass, "fan.test", "auto") with pytest.raises(NotValidPresetModeError):
assert "not a valid preset mode" in caplog.text await common.async_set_preset_mode(hass, "fan.test", "auto")
caplog.clear()
await common.async_set_preset_mode(hass, "fan.test", "whoosh") await common.async_set_preset_mode(hass, "fan.test", "whoosh")
mqtt_mock.async_publish.assert_called_once_with( mqtt_mock.async_publish.assert_called_once_with(
@ -938,13 +934,11 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog):
assert state.attributes.get(fan.ATTR_PERCENTAGE) == 0 assert state.attributes.get(fan.ATTR_PERCENTAGE) == 0
assert state.attributes.get(ATTR_ASSUMED_STATE) assert state.attributes.get(ATTR_ASSUMED_STATE)
await common.async_set_preset_mode(hass, "fan.test", "low") with pytest.raises(NotValidPresetModeError):
assert "not a valid preset mode" in caplog.text await common.async_set_preset_mode(hass, "fan.test", "low")
caplog.clear()
await common.async_set_preset_mode(hass, "fan.test", "medium") with pytest.raises(NotValidPresetModeError):
assert "not a valid preset mode" in caplog.text await common.async_set_preset_mode(hass, "fan.test", "medium")
caplog.clear()
await common.async_set_preset_mode(hass, "fan.test", "whoosh") await common.async_set_preset_mode(hass, "fan.test", "whoosh")
mqtt_mock.async_publish.assert_called_once_with( mqtt_mock.async_publish.assert_called_once_with(
@ -1035,9 +1029,8 @@ async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic(
assert state.state == STATE_UNKNOWN assert state.state == STATE_UNKNOWN
assert state.attributes.get(ATTR_ASSUMED_STATE) assert state.attributes.get(ATTR_ASSUMED_STATE)
await common.async_set_preset_mode(hass, "fan.test", "medium") with pytest.raises(NotValidPresetModeError):
assert "not a valid preset mode" in caplog.text await common.async_set_preset_mode(hass, "fan.test", "medium")
caplog.clear()
await common.async_set_preset_mode(hass, "fan.test", "whoosh") await common.async_set_preset_mode(hass, "fan.test", "whoosh")
mqtt_mock.async_publish.assert_called_once_with( mqtt_mock.async_publish.assert_called_once_with(
@ -1131,6 +1124,10 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca
with pytest.raises(NotValidPresetModeError): with pytest.raises(NotValidPresetModeError):
await common.async_turn_on(hass, "fan.test", preset_mode="auto") await common.async_turn_on(hass, "fan.test", preset_mode="auto")
assert mqtt_mock.async_publish.call_count == 1
# We can turn on, but the invalid preset mode will raise
mqtt_mock.async_publish.assert_any_call("command-topic", "ON", 0, False)
mqtt_mock.async_publish.reset_mock()
await common.async_turn_on(hass, "fan.test", preset_mode="whoosh") await common.async_turn_on(hass, "fan.test", preset_mode="whoosh")
assert mqtt_mock.async_publish.call_count == 2 assert mqtt_mock.async_publish.call_count == 2
@ -1259,13 +1256,11 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca
with pytest.raises(MultipleInvalid): with pytest.raises(MultipleInvalid):
await common.async_set_percentage(hass, "fan.test", 101) await common.async_set_percentage(hass, "fan.test", 101)
await common.async_set_preset_mode(hass, "fan.test", "low") with pytest.raises(NotValidPresetModeError):
assert "not a valid preset mode" in caplog.text await common.async_set_preset_mode(hass, "fan.test", "low")
caplog.clear()
await common.async_set_preset_mode(hass, "fan.test", "medium") with pytest.raises(NotValidPresetModeError):
assert "not a valid preset mode" in caplog.text await common.async_set_preset_mode(hass, "fan.test", "medium")
caplog.clear()
await common.async_set_preset_mode(hass, "fan.test", "whoosh") await common.async_set_preset_mode(hass, "fan.test", "whoosh")
mqtt_mock.async_publish.assert_called_once_with( mqtt_mock.async_publish.assert_called_once_with(
@ -1285,9 +1280,8 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca
assert state.state == STATE_OFF assert state.state == STATE_OFF
assert state.attributes.get(ATTR_ASSUMED_STATE) assert state.attributes.get(ATTR_ASSUMED_STATE)
await common.async_set_preset_mode(hass, "fan.test", "freaking-high") with pytest.raises(NotValidPresetModeError):
assert "not a valid preset mode" in caplog.text await common.async_set_preset_mode(hass, "fan.test", "freaking-high")
caplog.clear()
mqtt_mock.async_publish.reset_mock() mqtt_mock.async_publish.reset_mock()
state = hass.states.get("fan.test") state = hass.states.get("fan.test")

View file

@ -1,5 +1,4 @@
"""Test Z-Wave Fans.""" """Test Z-Wave Fans."""
import pytest
from .common import setup_ozw from .common import setup_ozw
@ -119,13 +118,3 @@ async def test_fan(hass, fan_data, fan_msg, sent_messages, caplog):
state = hass.states.get("fan.in_wall_smart_fan_control_level") state = hass.states.get("fan.in_wall_smart_fan_control_level")
assert state is not None assert state is not None
assert state.state == "off" assert state.state == "off"
# Test invalid speed
new_speed = "invalid"
with pytest.raises(ValueError):
await hass.services.async_call(
"fan",
"set_speed",
{"entity_id": "fan.in_wall_smart_fan_control_level", "speed": new_speed},
blocking=True,
)

View file

@ -7,13 +7,8 @@ real HTTP calls are not initiated during testing.
from pysmartthings import Attribute, Capability from pysmartthings import Attribute, Capability
from homeassistant.components.fan import ( from homeassistant.components.fan import (
ATTR_SPEED, ATTR_PERCENTAGE,
ATTR_SPEED_LIST,
DOMAIN as FAN_DOMAIN, DOMAIN as FAN_DOMAIN,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
SUPPORT_SET_SPEED, SUPPORT_SET_SPEED,
) )
from homeassistant.components.smartthings.const import DOMAIN, SIGNAL_SMARTTHINGS_UPDATE from homeassistant.components.smartthings.const import DOMAIN, SIGNAL_SMARTTHINGS_UPDATE
@ -42,13 +37,7 @@ async def test_entity_state(hass, device_factory):
state = hass.states.get("fan.fan_1") state = hass.states.get("fan.fan_1")
assert state.state == "on" assert state.state == "on"
assert state.attributes[ATTR_SUPPORTED_FEATURES] == SUPPORT_SET_SPEED assert state.attributes[ATTR_SUPPORTED_FEATURES] == SUPPORT_SET_SPEED
assert state.attributes[ATTR_SPEED] == SPEED_MEDIUM assert state.attributes[ATTR_PERCENTAGE] == 66
assert state.attributes[ATTR_SPEED_LIST] == [
SPEED_OFF,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_HIGH,
]
async def test_entity_and_device_attributes(hass, device_factory): async def test_entity_and_device_attributes(hass, device_factory):
@ -128,17 +117,17 @@ async def test_turn_on_with_speed(hass, device_factory):
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"turn_on", "turn_on",
{ATTR_ENTITY_ID: "fan.fan_1", ATTR_SPEED: SPEED_HIGH}, {ATTR_ENTITY_ID: "fan.fan_1", ATTR_PERCENTAGE: 100},
blocking=True, blocking=True,
) )
# Assert # Assert
state = hass.states.get("fan.fan_1") state = hass.states.get("fan.fan_1")
assert state is not None assert state is not None
assert state.state == "on" assert state.state == "on"
assert state.attributes[ATTR_SPEED] == SPEED_HIGH assert state.attributes[ATTR_PERCENTAGE] == 100
async def test_set_speed(hass, device_factory): async def test_set_percentage(hass, device_factory):
"""Test setting to specific fan speed.""" """Test setting to specific fan speed."""
# Arrange # Arrange
device = device_factory( device = device_factory(
@ -150,15 +139,15 @@ async def test_set_speed(hass, device_factory):
# Act # Act
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"set_speed", "set_percentage",
{ATTR_ENTITY_ID: "fan.fan_1", ATTR_SPEED: SPEED_HIGH}, {ATTR_ENTITY_ID: "fan.fan_1", ATTR_PERCENTAGE: 100},
blocking=True, blocking=True,
) )
# Assert # Assert
state = hass.states.get("fan.fan_1") state = hass.states.get("fan.fan_1")
assert state is not None assert state is not None
assert state.state == "on" assert state.state == "on"
assert state.attributes[ATTR_SPEED] == SPEED_HIGH assert state.attributes[ATTR_PERCENTAGE] == 100
async def test_update_from_signal(hass, device_factory): async def test_update_from_signal(hass, device_factory):

View file

@ -8,17 +8,11 @@ from homeassistant.components.fan import (
ATTR_OSCILLATING, ATTR_OSCILLATING,
ATTR_PERCENTAGE, ATTR_PERCENTAGE,
ATTR_PRESET_MODE, ATTR_PRESET_MODE,
ATTR_SPEED,
DIRECTION_FORWARD, DIRECTION_FORWARD,
DIRECTION_REVERSE, DIRECTION_REVERSE,
DOMAIN, DOMAIN,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
SUPPORT_PRESET_MODE, SUPPORT_PRESET_MODE,
SUPPORT_SET_SPEED, SUPPORT_SET_SPEED,
NotValidSpeedError,
) )
from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE
@ -60,7 +54,7 @@ _DIRECTION_INPUT_SELECT = "input_select.direction"
) )
async def test_missing_optional_config(hass, start_ha): async def test_missing_optional_config(hass, start_ha):
"""Test: missing optional template is ok.""" """Test: missing optional template is ok."""
_verify(hass, STATE_ON, None, None, None, None, None) _verify(hass, STATE_ON, None, None, None, None)
@pytest.mark.parametrize("count,domain", [(0, DOMAIN)]) @pytest.mark.parametrize("count,domain", [(0, DOMAIN)])
@ -165,26 +159,26 @@ async def test_wrong_template_config(hass, start_ha):
) )
async def test_templates_with_entities(hass, start_ha): async def test_templates_with_entities(hass, start_ha):
"""Test tempalates with values from other entities.""" """Test tempalates with values from other entities."""
_verify(hass, STATE_OFF, None, 0, None, None, None) _verify(hass, STATE_OFF, 0, None, None, None)
hass.states.async_set(_STATE_INPUT_BOOLEAN, True) hass.states.async_set(_STATE_INPUT_BOOLEAN, True)
hass.states.async_set(_PERCENTAGE_INPUT_NUMBER, 66) hass.states.async_set(_PERCENTAGE_INPUT_NUMBER, 66)
hass.states.async_set(_OSC_INPUT, "True") hass.states.async_set(_OSC_INPUT, "True")
for set_state, set_value, speed, value in [ for set_state, set_value, value in [
(_DIRECTION_INPUT_SELECT, DIRECTION_FORWARD, SPEED_MEDIUM, 66), (_DIRECTION_INPUT_SELECT, DIRECTION_FORWARD, 66),
(_PERCENTAGE_INPUT_NUMBER, 33, SPEED_LOW, 33), (_PERCENTAGE_INPUT_NUMBER, 33, 33),
(_PERCENTAGE_INPUT_NUMBER, 66, SPEED_MEDIUM, 66), (_PERCENTAGE_INPUT_NUMBER, 66, 66),
(_PERCENTAGE_INPUT_NUMBER, 100, SPEED_HIGH, 100), (_PERCENTAGE_INPUT_NUMBER, 100, 100),
(_PERCENTAGE_INPUT_NUMBER, "dog", None, 0), (_PERCENTAGE_INPUT_NUMBER, "dog", 0),
]: ]:
hass.states.async_set(set_state, set_value) hass.states.async_set(set_state, set_value)
await hass.async_block_till_done() await hass.async_block_till_done()
_verify(hass, STATE_ON, speed, value, True, DIRECTION_FORWARD, None) _verify(hass, STATE_ON, value, True, DIRECTION_FORWARD, None)
hass.states.async_set(_STATE_INPUT_BOOLEAN, False) hass.states.async_set(_STATE_INPUT_BOOLEAN, False)
await hass.async_block_till_done() await hass.async_block_till_done()
_verify(hass, STATE_OFF, None, 0, True, DIRECTION_FORWARD, None) _verify(hass, STATE_OFF, 0, True, DIRECTION_FORWARD, None)
@pytest.mark.parametrize("count,domain", [(1, DOMAIN)]) @pytest.mark.parametrize("count,domain", [(1, DOMAIN)])
@ -207,12 +201,12 @@ async def test_templates_with_entities(hass, start_ha):
}, },
"sensor.percentage", "sensor.percentage",
[ [
("0", 0, SPEED_OFF, None), ("0", 0, None),
("33", 33, SPEED_LOW, None), ("33", 33, None),
("invalid", 0, None, None), ("invalid", 0, None),
("5000", 0, None, None), ("5000", 0, None),
("100", 100, SPEED_HIGH, None), ("100", 100, None),
("0", 0, SPEED_OFF, None), ("0", 0, None),
], ],
), ),
( (
@ -232,21 +226,21 @@ async def test_templates_with_entities(hass, start_ha):
}, },
"sensor.preset_mode", "sensor.preset_mode",
[ [
("0", None, None, None), ("0", None, None),
("invalid", None, None, None), ("invalid", None, None),
("auto", None, None, "auto"), ("auto", None, "auto"),
("smart", None, None, "smart"), ("smart", None, "smart"),
("invalid", None, None, None), ("invalid", None, None),
], ],
), ),
], ],
) )
async def test_templates_with_entities2(hass, entity, tests, start_ha): async def test_templates_with_entities2(hass, entity, tests, start_ha):
"""Test templates with values from other entities.""" """Test templates with values from other entities."""
for set_percentage, test_percentage, speed, test_type in tests: for set_percentage, test_percentage, test_type in tests:
hass.states.async_set(entity, set_percentage) hass.states.async_set(entity, set_percentage)
await hass.async_block_till_done() await hass.async_block_till_done()
_verify(hass, STATE_ON, speed, test_percentage, None, None, test_type) _verify(hass, STATE_ON, test_percentage, None, None, test_type)
@pytest.mark.parametrize("count,domain", [(1, DOMAIN)]) @pytest.mark.parametrize("count,domain", [(1, DOMAIN)])
@ -295,7 +289,7 @@ async def test_availability_template_with_entities(hass, start_ha):
}, },
} }
}, },
[STATE_OFF, None, None, None, None], [STATE_OFF, None, None, None],
), ),
( (
{ {
@ -313,7 +307,7 @@ async def test_availability_template_with_entities(hass, start_ha):
}, },
} }
}, },
[STATE_ON, None, 0, None, None], [STATE_ON, 0, None, None],
), ),
( (
{ {
@ -331,7 +325,7 @@ async def test_availability_template_with_entities(hass, start_ha):
}, },
} }
}, },
[STATE_ON, SPEED_MEDIUM, 66, True, DIRECTION_FORWARD], [STATE_ON, 66, True, DIRECTION_FORWARD],
), ),
( (
{ {
@ -349,13 +343,13 @@ async def test_availability_template_with_entities(hass, start_ha):
}, },
} }
}, },
[STATE_OFF, None, 0, None, None], [STATE_OFF, 0, None, None],
), ),
], ],
) )
async def test_template_with_unavailable_entities(hass, states, start_ha): async def test_template_with_unavailable_entities(hass, states, start_ha):
"""Test unavailability with value_template.""" """Test unavailability with value_template."""
_verify(hass, states[0], states[1], states[2], states[3], states[4], None) _verify(hass, states[0], states[1], states[2], states[3], None)
@pytest.mark.parametrize("count,domain", [(1, DOMAIN)]) @pytest.mark.parametrize("count,domain", [(1, DOMAIN)])
@ -399,42 +393,7 @@ async def test_on_off(hass):
]: ]:
await func(hass, _TEST_FAN) await func(hass, _TEST_FAN)
assert hass.states.get(_STATE_INPUT_BOOLEAN).state == state assert hass.states.get(_STATE_INPUT_BOOLEAN).state == state
_verify(hass, state, None, 0, None, None, None) _verify(hass, state, 0, None, None, None)
async def test_set_speed(hass):
"""Test set valid speed."""
await _register_components(hass, preset_modes=["auto", "smart"])
await common.async_turn_on(hass, _TEST_FAN)
for cmd, type, state, value in [
(SPEED_HIGH, SPEED_HIGH, STATE_ON, 100),
(SPEED_MEDIUM, SPEED_MEDIUM, STATE_ON, 66),
(SPEED_OFF, SPEED_OFF, STATE_OFF, 0),
(SPEED_MEDIUM, SPEED_MEDIUM, STATE_ON, 66),
]:
await common.async_set_speed(hass, _TEST_FAN, cmd)
assert float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state) == value
_verify(hass, state, type, value, None, None, None)
with pytest.raises(NotValidSpeedError):
await common.async_set_speed(hass, _TEST_FAN, "invalid")
assert float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state) == 66
_verify(hass, STATE_ON, SPEED_MEDIUM, 66, None, None, None)
async def test_set_invalid_speed(hass):
"""Test set invalid speed when fan has valid speed."""
await _register_components(hass)
await common.async_turn_on(hass, _TEST_FAN)
await common.async_set_speed(hass, _TEST_FAN, SPEED_HIGH)
assert float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state) == 100
_verify(hass, STATE_ON, SPEED_HIGH, 100, None, None, None)
with pytest.raises(NotValidSpeedError):
await common.async_set_speed(hass, _TEST_FAN, "invalid")
async def test_set_invalid_direction_from_initial_stage(hass, calls): async def test_set_invalid_direction_from_initial_stage(hass, calls):
@ -445,7 +404,7 @@ async def test_set_invalid_direction_from_initial_stage(hass, calls):
await common.async_set_direction(hass, _TEST_FAN, "invalid") await common.async_set_direction(hass, _TEST_FAN, "invalid")
assert hass.states.get(_DIRECTION_INPUT_SELECT).state == "" assert hass.states.get(_DIRECTION_INPUT_SELECT).state == ""
_verify(hass, STATE_ON, None, 0, None, None, None) _verify(hass, STATE_ON, 0, None, None, None)
async def test_set_osc(hass): async def test_set_osc(hass):
@ -456,7 +415,7 @@ async def test_set_osc(hass):
for state in [True, False]: for state in [True, False]:
await common.async_oscillate(hass, _TEST_FAN, state) await common.async_oscillate(hass, _TEST_FAN, state)
assert hass.states.get(_OSC_INPUT).state == str(state) assert hass.states.get(_OSC_INPUT).state == str(state)
_verify(hass, STATE_ON, None, 0, state, None, None) _verify(hass, STATE_ON, 0, state, None, None)
async def test_set_direction(hass): async def test_set_direction(hass):
@ -467,7 +426,7 @@ async def test_set_direction(hass):
for cmd in [DIRECTION_FORWARD, DIRECTION_REVERSE]: for cmd in [DIRECTION_FORWARD, DIRECTION_REVERSE]:
await common.async_set_direction(hass, _TEST_FAN, cmd) await common.async_set_direction(hass, _TEST_FAN, cmd)
assert hass.states.get(_DIRECTION_INPUT_SELECT).state == cmd assert hass.states.get(_DIRECTION_INPUT_SELECT).state == cmd
_verify(hass, STATE_ON, None, 0, None, cmd, None) _verify(hass, STATE_ON, 0, None, cmd, None)
async def test_set_invalid_direction(hass): async def test_set_invalid_direction(hass):
@ -478,17 +437,7 @@ async def test_set_invalid_direction(hass):
for cmd in [DIRECTION_FORWARD, "invalid"]: for cmd in [DIRECTION_FORWARD, "invalid"]:
await common.async_set_direction(hass, _TEST_FAN, cmd) await common.async_set_direction(hass, _TEST_FAN, cmd)
assert hass.states.get(_DIRECTION_INPUT_SELECT).state == DIRECTION_FORWARD assert hass.states.get(_DIRECTION_INPUT_SELECT).state == DIRECTION_FORWARD
_verify(hass, STATE_ON, None, 0, None, DIRECTION_FORWARD, None) _verify(hass, STATE_ON, 0, None, DIRECTION_FORWARD, None)
async def test_on_with_speed(hass):
"""Test turn on with speed."""
await _register_components(hass)
await common.async_turn_on(hass, _TEST_FAN, SPEED_HIGH)
assert hass.states.get(_STATE_INPUT_BOOLEAN).state == STATE_ON
assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 100
_verify(hass, STATE_ON, SPEED_HIGH, 100, None, None, None)
async def test_preset_modes(hass): async def test_preset_modes(hass):
@ -515,18 +464,18 @@ async def test_set_percentage(hass):
await _register_components(hass) await _register_components(hass)
await common.async_turn_on(hass, _TEST_FAN) await common.async_turn_on(hass, _TEST_FAN)
for type, state, value in [ for state, value in [
(SPEED_HIGH, STATE_ON, 100), (STATE_ON, 100),
(SPEED_MEDIUM, STATE_ON, 66), (STATE_ON, 66),
(SPEED_OFF, STATE_OFF, 0), (STATE_OFF, 0),
]: ]:
await common.async_set_percentage(hass, _TEST_FAN, value) await common.async_set_percentage(hass, _TEST_FAN, value)
assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == value assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == value
_verify(hass, state, type, value, None, None, None) _verify(hass, state, value, None, None, None)
await common.async_turn_on(hass, _TEST_FAN, percentage=50) await common.async_turn_on(hass, _TEST_FAN, percentage=50)
assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 50 assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == 50
_verify(hass, STATE_ON, SPEED_MEDIUM, 50, None, None, None) _verify(hass, STATE_ON, 50, None, None, None)
async def test_increase_decrease_speed(hass): async def test_increase_decrease_speed(hass):
@ -534,16 +483,16 @@ async def test_increase_decrease_speed(hass):
await _register_components(hass, speed_count=3) await _register_components(hass, speed_count=3)
await common.async_turn_on(hass, _TEST_FAN) await common.async_turn_on(hass, _TEST_FAN)
for func, extra, state, type, value in [ for func, extra, state, value in [
(common.async_set_percentage, 100, STATE_ON, SPEED_HIGH, 100), (common.async_set_percentage, 100, STATE_ON, 100),
(common.async_decrease_speed, None, STATE_ON, SPEED_MEDIUM, 66), (common.async_decrease_speed, None, STATE_ON, 66),
(common.async_decrease_speed, None, STATE_ON, SPEED_LOW, 33), (common.async_decrease_speed, None, STATE_ON, 33),
(common.async_decrease_speed, None, STATE_OFF, SPEED_OFF, 0), (common.async_decrease_speed, None, STATE_OFF, 0),
(common.async_increase_speed, None, STATE_ON, SPEED_LOW, 33), (common.async_increase_speed, None, STATE_ON, 33),
]: ]:
await func(hass, _TEST_FAN, extra) await func(hass, _TEST_FAN, extra)
assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == value assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == value
_verify(hass, state, type, value, None, None, None) _verify(hass, state, value, None, None, None)
async def test_increase_decrease_speed_default_speed_count(hass): async def test_increase_decrease_speed_default_speed_count(hass):
@ -551,16 +500,16 @@ async def test_increase_decrease_speed_default_speed_count(hass):
await _register_components(hass) await _register_components(hass)
await common.async_turn_on(hass, _TEST_FAN) await common.async_turn_on(hass, _TEST_FAN)
for func, extra, state, type, value in [ for func, extra, state, value in [
(common.async_set_percentage, 100, STATE_ON, SPEED_HIGH, 100), (common.async_set_percentage, 100, STATE_ON, 100),
(common.async_decrease_speed, None, STATE_ON, SPEED_HIGH, 99), (common.async_decrease_speed, None, STATE_ON, 99),
(common.async_decrease_speed, None, STATE_ON, SPEED_HIGH, 98), (common.async_decrease_speed, None, STATE_ON, 98),
(common.async_decrease_speed, 31, STATE_ON, SPEED_HIGH, 67), (common.async_decrease_speed, 31, STATE_ON, 67),
(common.async_decrease_speed, None, STATE_ON, SPEED_MEDIUM, 66), (common.async_decrease_speed, None, STATE_ON, 66),
]: ]:
await func(hass, _TEST_FAN, extra) await func(hass, _TEST_FAN, extra)
assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == value assert int(float(hass.states.get(_PERCENTAGE_INPUT_NUMBER).state)) == value
_verify(hass, state, type, value, None, None, None) _verify(hass, state, value, None, None, None)
async def test_set_invalid_osc_from_initial_state(hass): async def test_set_invalid_osc_from_initial_state(hass):
@ -571,7 +520,7 @@ async def test_set_invalid_osc_from_initial_state(hass):
with pytest.raises(vol.Invalid): with pytest.raises(vol.Invalid):
await common.async_oscillate(hass, _TEST_FAN, "invalid") await common.async_oscillate(hass, _TEST_FAN, "invalid")
assert hass.states.get(_OSC_INPUT).state == "" assert hass.states.get(_OSC_INPUT).state == ""
_verify(hass, STATE_ON, None, 0, None, None, None) _verify(hass, STATE_ON, 0, None, None, None)
async def test_set_invalid_osc(hass): async def test_set_invalid_osc(hass):
@ -581,18 +530,17 @@ async def test_set_invalid_osc(hass):
await common.async_turn_on(hass, _TEST_FAN) await common.async_turn_on(hass, _TEST_FAN)
await common.async_oscillate(hass, _TEST_FAN, True) await common.async_oscillate(hass, _TEST_FAN, True)
assert hass.states.get(_OSC_INPUT).state == "True" assert hass.states.get(_OSC_INPUT).state == "True"
_verify(hass, STATE_ON, None, 0, True, None, None) _verify(hass, STATE_ON, 0, True, None, None)
with pytest.raises(vol.Invalid): with pytest.raises(vol.Invalid):
await common.async_oscillate(hass, _TEST_FAN, None) await common.async_oscillate(hass, _TEST_FAN, None)
assert hass.states.get(_OSC_INPUT).state == "True" assert hass.states.get(_OSC_INPUT).state == "True"
_verify(hass, STATE_ON, None, 0, True, None, None) _verify(hass, STATE_ON, 0, True, None, None)
def _verify( def _verify(
hass, hass,
expected_state, expected_state,
expected_speed,
expected_percentage, expected_percentage,
expected_oscillating, expected_oscillating,
expected_direction, expected_direction,
@ -602,7 +550,6 @@ def _verify(
state = hass.states.get(_TEST_FAN) state = hass.states.get(_TEST_FAN)
attributes = state.attributes attributes = state.attributes
assert state.state == str(expected_state) assert state.state == str(expected_state)
assert attributes.get(ATTR_SPEED) == expected_speed or SPEED_OFF
assert attributes.get(ATTR_PERCENTAGE) == expected_percentage assert attributes.get(ATTR_PERCENTAGE) == expected_percentage
assert attributes.get(ATTR_OSCILLATING) == expected_oscillating assert attributes.get(ATTR_OSCILLATING) == expected_oscillating
assert attributes.get(ATTR_DIRECTION) == expected_direction assert attributes.get(ATTR_DIRECTION) == expected_direction

View file

@ -8,19 +8,13 @@ import zigpy.zcl.clusters.general as general
import zigpy.zcl.clusters.hvac as hvac import zigpy.zcl.clusters.hvac as hvac
import zigpy.zcl.foundation as zcl_f import zigpy.zcl.foundation as zcl_f
from homeassistant.components import fan
from homeassistant.components.fan import ( from homeassistant.components.fan import (
ATTR_PERCENTAGE, ATTR_PERCENTAGE,
ATTR_PERCENTAGE_STEP, ATTR_PERCENTAGE_STEP,
ATTR_PRESET_MODE, ATTR_PRESET_MODE,
ATTR_SPEED,
DOMAIN as FAN_DOMAIN, DOMAIN as FAN_DOMAIN,
SERVICE_SET_PERCENTAGE,
SERVICE_SET_PRESET_MODE, SERVICE_SET_PRESET_MODE,
SERVICE_SET_SPEED,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
NotValidPresetModeError, NotValidPresetModeError,
) )
from homeassistant.components.zha.core.discovery import GROUP_PROBE from homeassistant.components.zha.core.discovery import GROUP_PROBE
@ -187,7 +181,7 @@ async def test_fan(hass, zha_device_joined_restored, zigpy_device):
# change speed from HA # change speed from HA
cluster.write_attributes.reset_mock() cluster.write_attributes.reset_mock()
await async_set_speed(hass, entity_id, speed=fan.SPEED_HIGH) await async_set_percentage(hass, entity_id, percentage=100)
assert len(cluster.write_attributes.mock_calls) == 1 assert len(cluster.write_attributes.mock_calls) == 1
assert cluster.write_attributes.call_args == call({"fan_mode": 3}) assert cluster.write_attributes.call_args == call({"fan_mode": 3})
@ -209,11 +203,11 @@ async def test_fan(hass, zha_device_joined_restored, zigpy_device):
await async_test_rejoin(hass, zigpy_device, [cluster], (1,)) await async_test_rejoin(hass, zigpy_device, [cluster], (1,))
async def async_turn_on(hass, entity_id, speed=None): async def async_turn_on(hass, entity_id, percentage=None):
"""Turn fan on.""" """Turn fan on."""
data = { data = {
key: value key: value
for key, value in [(ATTR_ENTITY_ID, entity_id), (ATTR_SPEED, speed)] for key, value in [(ATTR_ENTITY_ID, entity_id), (ATTR_PERCENTAGE, percentage)]
if value is not None if value is not None
} }
@ -227,15 +221,17 @@ async def async_turn_off(hass, entity_id):
await hass.services.async_call(Platform.FAN, SERVICE_TURN_OFF, data, blocking=True) await hass.services.async_call(Platform.FAN, SERVICE_TURN_OFF, data, blocking=True)
async def async_set_speed(hass, entity_id, speed=None): async def async_set_percentage(hass, entity_id, percentage=None):
"""Set speed for specified fan.""" """Set percentage for specified fan."""
data = { data = {
key: value key: value
for key, value in [(ATTR_ENTITY_ID, entity_id), (ATTR_SPEED, speed)] for key, value in [(ATTR_ENTITY_ID, entity_id), (ATTR_PERCENTAGE, percentage)]
if value is not None if value is not None
} }
await hass.services.async_call(Platform.FAN, SERVICE_SET_SPEED, data, blocking=True) await hass.services.async_call(
Platform.FAN, SERVICE_SET_PERCENTAGE, data, blocking=True
)
async def async_set_preset_mode(hass, entity_id, preset_mode=None): async def async_set_preset_mode(hass, entity_id, preset_mode=None):
@ -321,7 +317,7 @@ async def test_zha_group_fan_entity(hass, device_fan_1, device_fan_2, coordinato
# change speed from HA # change speed from HA
group_fan_cluster.write_attributes.reset_mock() group_fan_cluster.write_attributes.reset_mock()
await async_set_speed(hass, entity_id, speed=fan.SPEED_HIGH) await async_set_percentage(hass, entity_id, percentage=100)
assert len(group_fan_cluster.write_attributes.mock_calls) == 1 assert len(group_fan_cluster.write_attributes.mock_calls) == 1
assert group_fan_cluster.write_attributes.call_args[0][0] == {"fan_mode": 3} assert group_fan_cluster.write_attributes.call_args[0][0] == {"fan_mode": 3}
@ -428,13 +424,13 @@ async def test_zha_group_fan_entity_failure_state(
@pytest.mark.parametrize( @pytest.mark.parametrize(
"plug_read, expected_state, expected_speed, expected_percentage", "plug_read, expected_state, expected_percentage",
( (
(None, STATE_OFF, None, None), (None, STATE_OFF, None),
({"fan_mode": 0}, STATE_OFF, SPEED_OFF, 0), ({"fan_mode": 0}, STATE_OFF, 0),
({"fan_mode": 1}, STATE_ON, SPEED_LOW, 33), ({"fan_mode": 1}, STATE_ON, 33),
({"fan_mode": 2}, STATE_ON, SPEED_MEDIUM, 66), ({"fan_mode": 2}, STATE_ON, 66),
({"fan_mode": 3}, STATE_ON, SPEED_HIGH, 100), ({"fan_mode": 3}, STATE_ON, 100),
), ),
) )
async def test_fan_init( async def test_fan_init(
@ -443,7 +439,6 @@ async def test_fan_init(
zigpy_device, zigpy_device,
plug_read, plug_read,
expected_state, expected_state,
expected_speed,
expected_percentage, expected_percentage,
): ):
"""Test zha fan platform.""" """Test zha fan platform."""
@ -455,7 +450,6 @@ async def test_fan_init(
entity_id = await find_entity_id(Platform.FAN, zha_device, hass) entity_id = await find_entity_id(Platform.FAN, zha_device, hass)
assert entity_id is not None assert entity_id is not None
assert hass.states.get(entity_id).state == expected_state assert hass.states.get(entity_id).state == expected_state
assert hass.states.get(entity_id).attributes[ATTR_SPEED] == expected_speed
assert hass.states.get(entity_id).attributes[ATTR_PERCENTAGE] == expected_percentage assert hass.states.get(entity_id).attributes[ATTR_PERCENTAGE] == expected_percentage
assert hass.states.get(entity_id).attributes[ATTR_PRESET_MODE] is None assert hass.states.get(entity_id).attributes[ATTR_PRESET_MODE] is None
@ -474,7 +468,6 @@ async def test_fan_update_entity(
entity_id = await find_entity_id(Platform.FAN, zha_device, hass) entity_id = await find_entity_id(Platform.FAN, zha_device, hass)
assert entity_id is not None assert entity_id is not None
assert hass.states.get(entity_id).state == STATE_OFF assert hass.states.get(entity_id).state == STATE_OFF
assert hass.states.get(entity_id).attributes[ATTR_SPEED] == SPEED_OFF
assert hass.states.get(entity_id).attributes[ATTR_PERCENTAGE] == 0 assert hass.states.get(entity_id).attributes[ATTR_PERCENTAGE] == 0
assert hass.states.get(entity_id).attributes[ATTR_PRESET_MODE] is None assert hass.states.get(entity_id).attributes[ATTR_PRESET_MODE] is None
assert hass.states.get(entity_id).attributes[ATTR_PERCENTAGE_STEP] == 100 / 3 assert hass.states.get(entity_id).attributes[ATTR_PERCENTAGE_STEP] == 100 / 3
@ -487,7 +480,6 @@ async def test_fan_update_entity(
"homeassistant", "update_entity", {"entity_id": entity_id}, blocking=True "homeassistant", "update_entity", {"entity_id": entity_id}, blocking=True
) )
assert hass.states.get(entity_id).state == STATE_OFF assert hass.states.get(entity_id).state == STATE_OFF
assert hass.states.get(entity_id).attributes[ATTR_SPEED] == SPEED_OFF
assert cluster.read_attributes.await_count == 3 assert cluster.read_attributes.await_count == 3
cluster.PLUGGED_ATTR_READS = {"fan_mode": 1} cluster.PLUGGED_ATTR_READS = {"fan_mode": 1}
@ -496,7 +488,6 @@ async def test_fan_update_entity(
) )
assert hass.states.get(entity_id).state == STATE_ON assert hass.states.get(entity_id).state == STATE_ON
assert hass.states.get(entity_id).attributes[ATTR_PERCENTAGE] == 33 assert hass.states.get(entity_id).attributes[ATTR_PERCENTAGE] == 33
assert hass.states.get(entity_id).attributes[ATTR_SPEED] == SPEED_LOW
assert hass.states.get(entity_id).attributes[ATTR_PRESET_MODE] is None assert hass.states.get(entity_id).attributes[ATTR_PRESET_MODE] is None
assert hass.states.get(entity_id).attributes[ATTR_PERCENTAGE_STEP] == 100 / 3 assert hass.states.get(entity_id).attributes[ATTR_PERCENTAGE_STEP] == 100 / 3
assert cluster.read_attributes.await_count == 4 assert cluster.read_attributes.await_count == 4

View file

@ -1,16 +1,10 @@
"""Test Z-Wave fans.""" """Test Z-Wave fans."""
import pytest import pytest
from homeassistant.components.fan import ( from homeassistant.components.fan import SUPPORT_SET_SPEED
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
SUPPORT_SET_SPEED,
)
from homeassistant.components.zwave import fan from homeassistant.components.zwave import fan
from tests.mock.zwave import MockEntityValues, MockNode, MockValue, value_changed from tests.mock.zwave import MockEntityValues, MockNode, MockValue
# Integration is disabled # Integration is disabled
pytest.skip("Integration has been disabled in the manifest", allow_module_level=True) pytest.skip("Integration has been disabled in the manifest", allow_module_level=True)
@ -25,7 +19,6 @@ def test_get_device_detects_fan(mock_openzwave):
device = fan.get_device(node=node, values=values, node_config={}) device = fan.get_device(node=node, values=values, node_config={})
assert isinstance(device, fan.ZwaveFan) assert isinstance(device, fan.ZwaveFan)
assert device.supported_features == SUPPORT_SET_SPEED assert device.supported_features == SUPPORT_SET_SPEED
assert device.speed_list == [SPEED_OFF, SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH]
def test_fan_turn_on(mock_openzwave): def test_fan_turn_on(mock_openzwave):
@ -96,31 +89,3 @@ def test_fan_turn_off(mock_openzwave):
value_id, brightness = node.set_dimmer.mock_calls[0][1] value_id, brightness = node.set_dimmer.mock_calls[0][1]
assert value_id == value.value_id assert value_id == value.value_id
assert brightness == 0 assert brightness == 0
def test_fan_value_changed(mock_openzwave):
"""Test value changed for zwave fan."""
node = MockNode()
value = MockValue(data=0, node=node)
values = MockEntityValues(primary=value)
device = fan.get_device(node=node, values=values, node_config={})
assert not device.is_on
value.data = 10
value_changed(value)
assert device.is_on
assert device.speed == SPEED_LOW
value.data = 50
value_changed(value)
assert device.is_on
assert device.speed == SPEED_MEDIUM
value.data = 90
value_changed(value)
assert device.is_on
assert device.speed == SPEED_HIGH

View file

@ -2,14 +2,10 @@
import math import math
import pytest import pytest
from voluptuous.error import MultipleInvalid
from zwave_js_server.event import Event from zwave_js_server.event import Event
from homeassistant.components.fan import ( from homeassistant.components.fan import ATTR_PERCENTAGE, ATTR_PERCENTAGE_STEP
ATTR_PERCENTAGE,
ATTR_PERCENTAGE_STEP,
ATTR_SPEED,
SPEED_MEDIUM,
)
async def test_generic_fan(hass, client, fan_generic, integration): async def test_generic_fan(hass, client, fan_generic, integration):
@ -25,7 +21,7 @@ async def test_generic_fan(hass, client, fan_generic, integration):
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"turn_on", "turn_on",
{"entity_id": entity_id, "speed": SPEED_MEDIUM}, {"entity_id": entity_id, "percentage": 66},
blocking=True, blocking=True,
) )
@ -54,11 +50,11 @@ async def test_generic_fan(hass, client, fan_generic, integration):
client.async_send_command.reset_mock() client.async_send_command.reset_mock()
# Test setting unknown speed # Test setting unknown speed
with pytest.raises(ValueError): with pytest.raises(MultipleInvalid):
await hass.services.async_call( await hass.services.async_call(
"fan", "fan",
"set_speed", "set_percentage",
{"entity_id": entity_id, "speed": 99}, {"entity_id": entity_id, "percentage": "bad"},
blocking=True, blocking=True,
) )
@ -150,7 +146,7 @@ async def test_generic_fan(hass, client, fan_generic, integration):
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state.state == "on" assert state.state == "on"
assert state.attributes[ATTR_SPEED] == "high" assert state.attributes[ATTR_PERCENTAGE] == 100
client.async_send_command.reset_mock() client.async_send_command.reset_mock()
@ -175,7 +171,7 @@ async def test_generic_fan(hass, client, fan_generic, integration):
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
assert state.state == "off" assert state.state == "off"
assert state.attributes[ATTR_SPEED] == "off" assert state.attributes[ATTR_PERCENTAGE] == 0
async def test_configurable_speeds_fan(hass, client, hs_fc200, integration): async def test_configurable_speeds_fan(hass, client, hs_fc200, integration):