Complete fan speed transition from #59781 (#67743)

pull/67900/head
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_OFF,
)
from homeassistant.components.fan import SPEED_HIGH, SPEED_LOW, SPEED_OFF
from homeassistant.const import Platform
_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]
CONF_SYNC_TIME = "sync_time"
DEFAULT_SYNC_TIME = False
FAN_SUPPORTED_SPEEDS = [SPEED_OFF, SPEED_LOW, SPEED_HIGH]
PLATFORMS = [Platform.BINARY_SENSOR, Platform.CLIMATE]
AUX = "Aux"

View File

@ -10,7 +10,6 @@ from bond_api import Action, BPUPSubscriptions, DeviceType, Direction
import voluptuous as vol
from homeassistant.components.fan import (
ATTR_SPEED,
DIRECTION_FORWARD,
DIRECTION_REVERSE,
SUPPORT_DIRECTION,
@ -57,7 +56,7 @@ async def async_setup_entry(
platform.async_register_entity_service(
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",
)
@ -107,7 +106,9 @@ class BondFan(BondEntity, FanEntity):
"""Return the current speed percentage for the fan."""
if not self._speed or not self._power:
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
def speed_count(self) -> int:
@ -183,7 +184,6 @@ class BondFan(BondEntity, FanEntity):
async def async_turn_on(
self,
speed: str | None = None,
percentage: int | None = None,
preset_mode: str | None = None,
**kwargs: Any,

View File

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

View File

@ -13,15 +13,7 @@ from pydeconz.light import (
Fan,
)
from homeassistant.components.fan import (
DOMAIN,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
SUPPORT_SET_SPEED,
FanEntity,
)
from homeassistant.components.fan import DOMAIN, SUPPORT_SET_SPEED, FanEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
@ -41,19 +33,6 @@ ORDERED_NAMED_FAN_SPEEDS = [
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(
hass: HomeAssistant,
@ -130,41 +109,6 @@ class DeconzFan(DeconzDevice, FanEntity):
"""Return the number of speeds the fan supports."""
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
def async_update_callback(self) -> None:
"""Store latest configured speed from the device."""
@ -174,36 +118,23 @@ class DeconzFan(DeconzDevice, FanEntity):
async def async_set_percentage(self, percentage: int) -> None:
"""Set the speed percentage of the fan."""
if percentage == 0:
return await self.async_turn_off()
await self._device.set_speed(
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(
self,
speed: str | None = None,
percentage: int | None = None,
preset_mode: str | None = None,
**kwargs: Any,
) -> None:
"""Turn on fan."""
new_speed = self._default_on_speed
if percentage is not None:
new_speed = percentage_to_ordered_list_item(
ORDERED_NAMED_FAN_SPEEDS, percentage
)
await self._device.set_speed(new_speed)
await self.async_set_percentage(percentage)
return
await self._device.set_speed(self._default_on_speed)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off fan."""

View File

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

View File

@ -26,14 +26,7 @@ from homeassistant.components.cover import (
ATTR_POSITION,
SUPPORT_SET_POSITION,
)
from homeassistant.components.fan import (
ATTR_SPEED,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
SUPPORT_SET_SPEED,
)
from homeassistant.components.fan import ATTR_PERCENTAGE, SUPPORT_SET_SPEED
from homeassistant.components.http import HomeAssistantView
from homeassistant.components.humidifier.const import (
ATTR_HUMIDITY,
@ -540,14 +533,7 @@ class HueOneLightChangeView(HomeAssistantView):
):
domain = entity.domain
# Convert 0-100 to a fan speed
if (brightness := parsed[STATE_BRIGHTNESS]) == 0:
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
data[ATTR_PERCENTAGE] = parsed[STATE_BRIGHTNESS]
# Map the off command to on
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
data[STATE_BRIGHTNESS] = round(min(1.0, level) * HUE_API_STATE_BRI_MAX)
elif entity.domain == fan.DOMAIN:
speed = entity.attributes.get(ATTR_SPEED, 0)
# Convert 0.0-1.0 to 0-254
data[STATE_BRIGHTNESS] = 0
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
percentage = entity.attributes.get(ATTR_PERCENTAGE) or 0
# Convert 0-100 to 0-254
data[STATE_BRIGHTNESS] = round(percentage * HUE_API_STATE_BRI_MAX / 100)
elif entity.domain == cover.DOMAIN:
level = entity.attributes.get(ATTR_CURRENT_POSITION, 0)
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(
self,
speed: str | None = None,
percentage: int | None = None,
preset_mode: str | None = None,
**kwargs: Any,

View File

@ -28,8 +28,6 @@ from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.typing import ConfigType
from homeassistant.loader import bind_hass
from homeassistant.util.percentage import (
ordered_list_item_to_percentage,
percentage_to_ordered_list_item,
percentage_to_ranged_value,
ranged_value_to_percentage,
)
@ -47,7 +45,6 @@ SUPPORT_OSCILLATE = 2
SUPPORT_DIRECTION = 4
SUPPORT_PRESET_MODE = 8
SERVICE_SET_SPEED = "set_speed"
SERVICE_INCREASE_SPEED = "increase_speed"
SERVICE_DECREASE_SPEED = "decrease_speed"
SERVICE_OSCILLATE = "oscillate"
@ -55,37 +52,16 @@ SERVICE_SET_DIRECTION = "set_direction"
SERVICE_SET_PERCENTAGE = "set_percentage"
SERVICE_SET_PRESET_MODE = "set_preset_mode"
SPEED_OFF = "off"
SPEED_LOW = "low"
SPEED_MEDIUM = "medium"
SPEED_HIGH = "high"
DIRECTION_FORWARD = "forward"
DIRECTION_REVERSE = "reverse"
ATTR_SPEED = "speed"
ATTR_PERCENTAGE = "percentage"
ATTR_PERCENTAGE_STEP = "percentage_step"
ATTR_SPEED_LIST = "speed_list"
ATTR_OSCILLATING = "oscillating"
ATTR_DIRECTION = "direction"
ATTR_PRESET_MODE = "preset_mode"
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):
"""Exception class when the preset_mode in not in the preset_modes list."""
@ -94,10 +70,7 @@ class NotValidPresetModeError(ValueError):
@bind_hass
def is_on(hass, entity_id: str) -> bool:
"""Return if the fans are on based on the statemachine."""
state = hass.states.get(entity_id)
if ATTR_SPEED in state.attributes:
return state.attributes[ATTR_SPEED] not in OFF_SPEED_VALUES
return state.state == STATE_ON
return hass.states.get(entity_id).state == STATE_ON
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(
SERVICE_TURN_ON,
{
vol.Optional(ATTR_SPEED): cv.string,
vol.Optional(ATTR_PERCENTAGE): vol.All(
vol.Coerce(int), vol.Range(min=0, max=100)
),
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_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(
SERVICE_INCREASE_SPEED,
{
@ -212,29 +176,6 @@ class FanEntity(ToggleEntity):
_attr_speed_count: int
_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:
"""Set the speed of the fan, as a percentage."""
raise NotImplementedError()
@ -301,7 +242,6 @@ class FanEntity(ToggleEntity):
# pylint: disable=arguments-differ
def turn_on(
self,
speed: str | None = None,
percentage: int | None = None,
preset_mode: str | None = None,
**kwargs,
@ -309,64 +249,22 @@ class FanEntity(ToggleEntity):
"""Turn on the fan."""
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
async def async_turn_on(
self,
speed: str | None = None,
percentage: int | None = None,
preset_mode: str | None = None,
**kwargs,
) -> None:
"""Turn on the fan."""
if speed == SPEED_OFF:
await self.async_turn_off()
else:
await self.hass.async_add_executor_job(
ft.partial(
self.turn_on,
speed=speed,
percentage=percentage,
preset_mode=preset_mode,
**kwargs,
)
await self.hass.async_add_executor_job(
ft.partial(
self.turn_on,
percentage=percentage,
preset_mode=preset_mode,
**kwargs,
)
)
def oscillate(self, oscillating: bool) -> None:
"""Oscillate the fan."""
@ -379,16 +277,9 @@ class FanEntity(ToggleEntity):
@property
def is_on(self):
"""Return true if the entity is on."""
return self.speed not in [SPEED_OFF, None]
@property
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)
return (
self.percentage is not None and self.percentage > 0
) or self.preset_mode is not None
@property
def percentage(self) -> int | None:
@ -409,14 +300,6 @@ class FanEntity(ToggleEntity):
"""Return the step size for percentage."""
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
def current_direction(self) -> str | None:
"""Return the current direction of the fan."""
@ -431,8 +314,6 @@ class FanEntity(ToggleEntity):
def capability_attributes(self):
"""Return capability attributes."""
attrs = {}
if self.supported_features & SUPPORT_SET_SPEED:
attrs[ATTR_SPEED_LIST] = self.speed_list
if (
self.supported_features & SUPPORT_SET_SPEED
@ -442,22 +323,6 @@ class FanEntity(ToggleEntity):
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
@property
def state_attributes(self) -> dict:
@ -472,7 +337,6 @@ class FanEntity(ToggleEntity):
data[ATTR_OSCILLATING] = self.oscillating
if supported_features & SUPPORT_SET_SPEED:
data[ATTR_SPEED] = self.speed
data[ATTR_PERCENTAGE] = self.percentage
data[ATTR_PERCENTAGE_STEP] = self.percentage_step

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -12,10 +12,6 @@ from homeassistant.components.fan import (
ATTR_OSCILLATING,
ATTR_PERCENTAGE,
ATTR_PRESET_MODE,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
SUPPORT_OSCILLATE,
SUPPORT_PRESET_MODE,
SUPPORT_SET_SPEED,
@ -163,10 +159,6 @@ _PLATFORM_SCHEMA_BASE = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend(
vol.Optional(
CONF_PAYLOAD_RESET_PRESET_MODE, default=DEFAULT_PAYLOAD_RESET
): 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_ON, default=DEFAULT_PAYLOAD_ON): cv.string,
vol.Optional(
@ -176,10 +168,6 @@ _PLATFORM_SCHEMA_BASE = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend(
CONF_PAYLOAD_OSCILLATION_ON, default=OSCILLATE_ON_PAYLOAD
): cv.string,
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_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)
async def async_turn_on(
self,
speed: str = None,
percentage: int = None,
preset_mode: str = None,
**kwargs,
@ -605,9 +592,7 @@ class MqttFan(MqttEntity, FanEntity):
This method is a coroutine.
"""
if preset_mode not in self.preset_modes:
_LOGGER.warning("'%s'is not a valid preset mode", preset_mode)
return
self._valid_preset_mode_or_raise(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))
self.values.primary.send_value(zwave_speed)
async def async_turn_on(
self, speed=None, percentage=None, preset_mode=None, **kwargs
):
async def async_turn_on(self, percentage=None, preset_mode=None, **kwargs):
"""Turn the device on."""
await self.async_set_percentage(percentage)

View File

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

View File

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

View File

@ -99,9 +99,9 @@ class SmartyFan(FanEntity):
self._smarty_fan_speed = fan_speed
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."""
_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)
def turn_off(self, **kwargs):

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -83,7 +83,6 @@ class ZwaveFan(ZWaveBaseEntity, FanEntity):
async def async_turn_on(
self,
speed: str | None = None,
percentage: int | None = None,
preset_mode: str | None = None,
**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.fan import (
ATTR_DIRECTION,
ATTR_PERCENTAGE,
ATTR_PRESET_MODE,
ATTR_PRESET_MODES,
ATTR_SPEED,
ATTR_SPEED_LIST,
DIRECTION_FORWARD,
DIRECTION_REVERSE,
DOMAIN as FAN_DOMAIN,
SERVICE_SET_DIRECTION,
SERVICE_SET_PERCENTAGE,
SERVICE_SET_PRESET_MODE,
SERVICE_SET_SPEED,
SPEED_OFF,
)
from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON
from homeassistant.exceptions import HomeAssistantError
@ -66,7 +64,6 @@ def ceiling_fan_with_breeze(name: str):
async def turn_fan_on(
hass: core.HomeAssistant,
fan_id: str,
speed: str | None = None,
percentage: int | None = None,
preset_mode: str | None = None,
) -> None:
@ -74,9 +71,7 @@ async def turn_fan_on(
service_data = {ATTR_ENTITY_ID: fan_id}
if preset_mode:
service_data[fan.ATTR_PRESET_MODE] = preset_mode
if speed:
service_data[fan.ATTR_SPEED] = speed
if percentage:
if percentage is not None:
service_data[fan.ATTR_PERCENTAGE] = percentage
await hass.services.async_call(
FAN_DOMAIN,
@ -116,35 +111,27 @@ async def test_non_standard_speed_list(hass: core.HomeAssistant):
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_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(
"test-device-id", Action.set_speed(2)
)
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(
"test-device-id", Action.set_speed(4)
)
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(
"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."""
await setup_platform(
hass,
@ -155,7 +142,7 @@ async def test_fan_speed_with_no_max_seed(hass: core.HomeAssistant):
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):
@ -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():
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))
@ -264,9 +251,7 @@ async def test_turn_on_fan_preset_mode_not_supported(hass: core.HomeAssistant):
props={"max_speed": 6},
)
with patch_bond_action(), patch_bond_device_state(), pytest.raises(
fan.NotValidPresetModeError
):
with patch_bond_action(), patch_bond_device_state(), pytest.raises(ValueError):
await turn_fan_on(hass, "fan.name_1", preset_mode=PRESET_MODE_BREEZE)
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():
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 == [
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())
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."""
await setup_platform(
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():
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())
@ -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():
await hass.services.async_call(
FAN_DOMAIN,
SERVICE_SET_SPEED,
service_data={ATTR_ENTITY_ID: "fan.name_1", ATTR_SPEED: SPEED_OFF},
SERVICE_SET_PERCENTAGE,
service_data={ATTR_ENTITY_ID: "fan.name_1", ATTR_PERCENTAGE: 0},
blocking=True,
)
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(
BOND_DOMAIN,
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,
)
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(
BOND_DOMAIN,
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,
)
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(
BOND_DOMAIN,
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,
)
await hass.async_block_till_done()

View File

@ -3,19 +3,14 @@
from unittest.mock import patch
import pytest
from voluptuous.error import MultipleInvalid
from homeassistant.components.fan import (
ATTR_PERCENTAGE,
ATTR_SPEED,
DOMAIN as FAN_DOMAIN,
SERVICE_SET_PERCENTAGE,
SERVICE_SET_SPEED,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
)
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},
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
@ -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 hass.states.get("fan.ceiling_fan").state == STATE_ON
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_SPEED] == SPEED_HIGH
# 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").attributes[ATTR_PERCENTAGE] == 25
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_SPEED] == SPEED_LOW
event_changed_light = {
"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").attributes[ATTR_PERCENTAGE] == 50
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_SPEED] == SPEED_MEDIUM
event_changed_light = {
"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").attributes[ATTR_PERCENTAGE] == 75
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_SPEED] == SPEED_MEDIUM
event_changed_light = {
"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").attributes[ATTR_PERCENTAGE] == 100
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_SPEED] == SPEED_HIGH
event_changed_light = {
"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").attributes[ATTR_PERCENTAGE] == 0
assert hass.states.get("fan.ceiling_fan").attributes[ATTR_SPEED] == SPEED_OFF
# 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(
FAN_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: SPEED_OFF},
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 0},
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
# async_turn_on_compat use speed_to_percentage which will convert to SPEED_MEDIUM -> 2
await hass.services.async_call(
FAN_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: "bad"},
blocking=True,
)
assert aioclient_mock.mock_calls[3][2] == {"speed": 2}
with pytest.raises(MultipleInvalid):
await hass.services.async_call(
FAN_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: "bad"},
blocking=True,
)
# Service turn on fan to low speed
await hass.services.async_call(
FAN_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: SPEED_LOW},
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 25},
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
await hass.services.async_call(
FAN_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: SPEED_MEDIUM},
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 50},
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
await hass.services.async_call(
FAN_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: SPEED_HIGH},
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 100},
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
await hass.services.async_call(
FAN_DOMAIN,
SERVICE_SET_SPEED,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: SPEED_LOW},
SERVICE_SET_PERCENTAGE,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 25},
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
await hass.services.async_call(
FAN_DOMAIN,
SERVICE_SET_SPEED,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: SPEED_MEDIUM},
SERVICE_SET_PERCENTAGE,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 50},
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
await hass.services.async_call(
FAN_DOMAIN,
SERVICE_SET_SPEED,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: SPEED_HIGH},
SERVICE_SET_PERCENTAGE,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 100},
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
await hass.services.async_call(
FAN_DOMAIN,
SERVICE_SET_SPEED,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: SPEED_OFF},
SERVICE_SET_PERCENTAGE,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: 0},
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
with pytest.raises(ValueError):
with pytest.raises(MultipleInvalid):
await hass.services.async_call(
FAN_DOMAIN,
SERVICE_SET_SPEED,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_SPEED: "bad value"},
SERVICE_SET_PERCENTAGE,
{ATTR_ENTITY_ID: "fan.ceiling_fan", ATTR_PERCENTAGE: "bad value"},
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()
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)

View File

@ -55,39 +55,6 @@ async def test_turn_on_with_speed_and_percentage(hass, fan_entity_id):
"""Test turning on the device."""
state = hass.states.get(fan_entity_id)
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(
fan.DOMAIN,
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)
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(
@ -107,7 +73,6 @@ async def test_turn_on_with_speed_and_percentage(hass, fan_entity_id):
)
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(
@ -118,7 +83,36 @@ async def test_turn_on_with_speed_and_percentage(hass, fan_entity_id):
)
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(
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
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)
assert state.state == STATE_OFF
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_OFF
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)
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
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] == [
PRESET_MODE_AUTO,
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)
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_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)
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_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)
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_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)
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_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
@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)
async def test_set_preset_mode(hass, fan_entity_id):
"""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)
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
@ -422,7 +355,6 @@ async def test_set_percentage(hass, fan_entity_id):
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_LOW
assert state.attributes[fan.ATTR_PERCENTAGE] == 33
@ -440,7 +372,6 @@ async def test_increase_decrease_speed(hass, fan_entity_id):
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_LOW
assert state.attributes[fan.ATTR_PERCENTAGE] == 33
await hass.services.async_call(
@ -450,7 +381,6 @@ async def test_increase_decrease_speed(hass, fan_entity_id):
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_MEDIUM
assert state.attributes[fan.ATTR_PERCENTAGE] == 66
await hass.services.async_call(
@ -460,7 +390,6 @@ async def test_increase_decrease_speed(hass, fan_entity_id):
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_HIGH
assert state.attributes[fan.ATTR_PERCENTAGE] == 100
await hass.services.async_call(
@ -470,7 +399,6 @@ async def test_increase_decrease_speed(hass, fan_entity_id):
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_HIGH
assert state.attributes[fan.ATTR_PERCENTAGE] == 100
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)
assert state.attributes[fan.ATTR_PERCENTAGE] == 66
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_MEDIUM
await hass.services.async_call(
fan.DOMAIN,
@ -490,7 +417,6 @@ async def test_increase_decrease_speed(hass, fan_entity_id):
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_LOW
assert state.attributes[fan.ATTR_PERCENTAGE] == 33
await hass.services.async_call(
@ -500,7 +426,6 @@ async def test_increase_decrease_speed(hass, fan_entity_id):
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_OFF
assert state.attributes[fan.ATTR_PERCENTAGE] == 0
await hass.services.async_call(
@ -510,7 +435,6 @@ async def test_increase_decrease_speed(hass, fan_entity_id):
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_OFF
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,
)
state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_LOW
assert state.attributes[fan.ATTR_PERCENTAGE] == 25
await hass.services.async_call(
@ -534,7 +457,6 @@ async def test_increase_decrease_speed_with_percentage_step(hass, fan_entity_id)
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_MEDIUM
assert state.attributes[fan.ATTR_PERCENTAGE] == 50
await hass.services.async_call(
@ -544,7 +466,6 @@ async def test_increase_decrease_speed_with_percentage_step(hass, fan_entity_id)
blocking=True,
)
state = hass.states.get(fan_entity_id)
assert state.attributes[fan.ATTR_SPEED] == fan.SPEED_HIGH
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")
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
# We also check non-cached GET value to exercise the code.
await perform_put_light_state(
hass_hue, hue_client, "fan.living_room_fan", True, brightness=0
)
assert (
hass_hue.states.get("fan.living_room_fan").attributes[fan.ATTR_SPEED]
== fan.SPEED_OFF
)
assert hass_hue.states.get("fan.living_room_fan").state == STATE_OFF
await perform_put_light_state(
hass_hue,
hue_client,
@ -1052,8 +1049,7 @@ async def test_put_light_state_fan(hass_hue, hue_client):
brightness=round(33 * 254 / 100),
)
assert (
hass_hue.states.get("fan.living_room_fan").attributes[fan.ATTR_SPEED]
== fan.SPEED_LOW
hass_hue.states.get("fan.living_room_fan").attributes[fan.ATTR_PERCENTAGE] == 33
)
with patch.object(hue_api, "STATE_CACHED_TIMEOUT", 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),
)
assert (
hass_hue.states.get("fan.living_room_fan").attributes[fan.ATTR_SPEED]
== fan.SPEED_MEDIUM
hass_hue.states.get("fan.living_room_fan").attributes[fan.ATTR_PERCENTAGE] == 66
)
with patch.object(hue_api, "STATE_CACHED_TIMEOUT", 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
)
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
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),
)
assert (
hass_hue.states.get("fan.living_room_fan").attributes[fan.ATTR_SPEED]
== fan.SPEED_HIGH
hass_hue.states.get("fan.living_room_fan").attributes[fan.ATTR_PERCENTAGE]
== 100
)
with patch.object(hue_api, "STATE_CACHED_TIMEOUT", 0.000001):
await asyncio.sleep(0.000001)

View File

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

View File

@ -9,7 +9,6 @@ from homeassistant.components.fan import (
ATTR_PERCENTAGE,
ATTR_PERCENTAGE_STEP,
ATTR_PRESET_MODE,
ATTR_SPEED,
DOMAIN,
SERVICE_DECREASE_SPEED,
SERVICE_INCREASE_SPEED,
@ -17,7 +16,6 @@ from homeassistant.components.fan import (
SERVICE_SET_DIRECTION,
SERVICE_SET_PERCENTAGE,
SERVICE_SET_PRESET_MODE,
SERVICE_SET_SPEED,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
@ -30,7 +28,6 @@ from homeassistant.const import (
async def async_turn_on(
hass,
entity_id=ENTITY_MATCH_ALL,
speed: str = None,
percentage: int = None,
preset_mode: str = None,
) -> None:
@ -39,7 +36,6 @@ async def async_turn_on(
key: value
for key, value in [
(ATTR_ENTITY_ID, entity_id),
(ATTR_SPEED, speed),
(ATTR_PERCENTAGE, percentage),
(ATTR_PRESET_MODE, preset_mode),
]
@ -72,17 +68,6 @@ async def async_oscillate(
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(
hass, entity_id=ENTITY_MATCH_ALL, preset_mode: str = None
) -> None:

View File

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

View File

@ -8,7 +8,7 @@ async def test_reproducing_states(hass, caplog):
"""Test reproducing Fan states."""
hass.states.async_set("fan.entity_off", "off", {})
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_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")
set_direction_calls = async_mock_service(hass, "fan", "set_direction")
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
await hass.helpers.state.async_reproduce_state(
[
State("fan.entity_off", "off"),
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_direction", "on", {"direction": "forward"}),
],
@ -33,7 +33,6 @@ async def test_reproducing_states(hass, caplog):
assert len(turn_off_calls) == 0
assert len(set_direction_calls) == 0
assert len(oscillate_calls) == 0
assert len(set_speed_calls) == 0
# Test invalid state is handled
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(set_direction_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
await hass.helpers.state.async_reproduce_state(
[
State("fan.entity_on", "off"),
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_direction", "on", {"direction": "reverse"}),
# Should not raise
@ -78,9 +77,12 @@ async def test_reproducing_states(hass, caplog):
"oscillating": False,
}
assert len(set_speed_calls) == 1
assert set_speed_calls[0].domain == "fan"
assert set_speed_calls[0].data == {"entity_id": "fan.entity_speed", "speed": "low"}
assert len(set_percentage_calls) == 1
assert set_percentage_calls[0].domain == "fan"
assert set_percentage_calls[0].data == {
"entity_id": "fan.entity_speed",
"percentage": 25,
}
assert len(turn_off_calls) == 1
assert turn_off_calls[0].domain == "fan"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,6 +3,9 @@ import json
from unittest.mock import AsyncMock, Mock, patch
from homeassistant.components.climate.const import (
FAN_HIGH,
FAN_LOW,
FAN_MEDIUM,
HVAC_MODE_COOL,
HVAC_MODE_DRY,
HVAC_MODE_FAN_ONLY,
@ -11,7 +14,6 @@ from homeassistant.components.climate.const import (
SUPPORT_FAN_MODE,
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.climate import MelissaClimate
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]
thermostat = MelissaClimate(api, _SERIAL, device)
await thermostat.async_update()
assert thermostat.fan_mode == SPEED_LOW
assert thermostat.fan_mode == FAN_LOW
thermostat._cur_settings = None
assert thermostat.fan_mode is None
@ -162,7 +164,7 @@ async def test_fan_modes(hass):
api = melissa_mock()
device = (await api.async_fetch_devices())[_SERIAL]
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):
@ -247,9 +249,9 @@ async def test_fan_mode(hass):
thermostat = MelissaClimate(api, _SERIAL, device)
await thermostat.async_update()
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()
assert thermostat.fan_mode == SPEED_HIGH
assert thermostat.fan_mode == FAN_HIGH
async def test_set_operation_mode(hass):
@ -275,12 +277,12 @@ async def test_send(hass):
await hass.async_block_till_done()
await thermostat.async_send({"fan": api.FAN_MEDIUM})
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)
thermostat._cur_settings = None
await thermostat.async_send({"fan": api.FAN_LOW})
await hass.async_block_till_done()
assert SPEED_LOW != thermostat.fan_mode
assert FAN_LOW != thermostat.fan_mode
assert thermostat._cur_settings is None
@ -293,7 +295,7 @@ async def test_update(hass):
device = (await api.async_fetch_devices())[_SERIAL]
thermostat = MelissaClimate(api, _SERIAL, device)
await thermostat.async_update()
assert thermostat.fan_mode == SPEED_LOW
assert thermostat.fan_mode == FAN_LOW
assert thermostat.state == HVAC_MODE_HEAT
api.async_status = AsyncMock(side_effect=KeyError("boom"))
await thermostat.async_update()
@ -322,9 +324,9 @@ async def test_melissa_fan_to_hass(hass):
device = (await api.async_fetch_devices())[_SERIAL]
thermostat = MelissaClimate(api, _SERIAL, device)
assert thermostat.melissa_fan_to_hass(0) == "auto"
assert thermostat.melissa_fan_to_hass(1) == SPEED_LOW
assert thermostat.melissa_fan_to_hass(2) == SPEED_MEDIUM
assert thermostat.melissa_fan_to_hass(3) == SPEED_HIGH
assert thermostat.melissa_fan_to_hass(1) == FAN_LOW
assert thermostat.melissa_fan_to_hass(2) == FAN_MEDIUM
assert thermostat.melissa_fan_to_hass(3) == FAN_HIGH
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]
thermostat = MelissaClimate(api, _SERIAL, device)
assert thermostat.hass_fan_to_melissa("auto") == 0
assert thermostat.hass_fan_to_melissa(SPEED_LOW) == 1
assert thermostat.hass_fan_to_melissa(SPEED_MEDIUM) == 2
assert thermostat.hass_fan_to_melissa(SPEED_HIGH) == 3
assert thermostat.hass_fan_to_melissa(FAN_LOW) == 1
assert thermostat.hass_fan_to_melissa(FAN_MEDIUM) == 2
assert thermostat.hass_fan_to_melissa(FAN_HIGH) == 3
thermostat.hass_fan_to_melissa("test")
mocked_warning.assert_called_once_with(
"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")
state = hass.states.get("fan.test")
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")
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(ATTR_ASSUMED_STATE)
await common.async_set_preset_mode(hass, "fan.test", "low")
assert "not a valid preset mode" in caplog.text
caplog.clear()
with pytest.raises(NotValidPresetModeError):
await common.async_set_preset_mode(hass, "fan.test", "low")
await common.async_set_preset_mode(hass, "fan.test", "whoosh")
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(ATTR_ASSUMED_STATE)
await common.async_set_preset_mode(hass, "fan.test", "low")
assert "not a valid preset mode" in caplog.text
caplog.clear()
with pytest.raises(NotValidPresetModeError):
await common.async_set_preset_mode(hass, "fan.test", "low")
await common.async_set_preset_mode(hass, "fan.test", "auto")
assert "not a valid preset mode" in caplog.text
caplog.clear()
with pytest.raises(NotValidPresetModeError):
await common.async_set_preset_mode(hass, "fan.test", "auto")
await common.async_set_preset_mode(hass, "fan.test", "whoosh")
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(ATTR_ASSUMED_STATE)
await common.async_set_preset_mode(hass, "fan.test", "low")
assert "not a valid preset mode" in caplog.text
caplog.clear()
with pytest.raises(NotValidPresetModeError):
await common.async_set_preset_mode(hass, "fan.test", "low")
await common.async_set_preset_mode(hass, "fan.test", "medium")
assert "not a valid preset mode" in caplog.text
caplog.clear()
with pytest.raises(NotValidPresetModeError):
await common.async_set_preset_mode(hass, "fan.test", "medium")
await common.async_set_preset_mode(hass, "fan.test", "whoosh")
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.attributes.get(ATTR_ASSUMED_STATE)
await common.async_set_preset_mode(hass, "fan.test", "medium")
assert "not a valid preset mode" in caplog.text
caplog.clear()
with pytest.raises(NotValidPresetModeError):
await common.async_set_preset_mode(hass, "fan.test", "medium")
await common.async_set_preset_mode(hass, "fan.test", "whoosh")
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):
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")
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):
await common.async_set_percentage(hass, "fan.test", 101)
await common.async_set_preset_mode(hass, "fan.test", "low")
assert "not a valid preset mode" in caplog.text
caplog.clear()
with pytest.raises(NotValidPresetModeError):
await common.async_set_preset_mode(hass, "fan.test", "low")
await common.async_set_preset_mode(hass, "fan.test", "medium")
assert "not a valid preset mode" in caplog.text
caplog.clear()
with pytest.raises(NotValidPresetModeError):
await common.async_set_preset_mode(hass, "fan.test", "medium")
await common.async_set_preset_mode(hass, "fan.test", "whoosh")
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.attributes.get(ATTR_ASSUMED_STATE)
await common.async_set_preset_mode(hass, "fan.test", "freaking-high")
assert "not a valid preset mode" in caplog.text
caplog.clear()
with pytest.raises(NotValidPresetModeError):
await common.async_set_preset_mode(hass, "fan.test", "freaking-high")
mqtt_mock.async_publish.reset_mock()
state = hass.states.get("fan.test")

View File

@ -1,5 +1,4 @@
"""Test Z-Wave Fans."""
import pytest
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")
assert state is not None
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 homeassistant.components.fan import (
ATTR_SPEED,
ATTR_SPEED_LIST,
ATTR_PERCENTAGE,
DOMAIN as FAN_DOMAIN,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
SUPPORT_SET_SPEED,
)
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")
assert state.state == "on"
assert state.attributes[ATTR_SUPPORTED_FEATURES] == SUPPORT_SET_SPEED
assert state.attributes[ATTR_SPEED] == SPEED_MEDIUM
assert state.attributes[ATTR_SPEED_LIST] == [
SPEED_OFF,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_HIGH,
]
assert state.attributes[ATTR_PERCENTAGE] == 66
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(
"fan",
"turn_on",
{ATTR_ENTITY_ID: "fan.fan_1", ATTR_SPEED: SPEED_HIGH},
{ATTR_ENTITY_ID: "fan.fan_1", ATTR_PERCENTAGE: 100},
blocking=True,
)
# Assert
state = hass.states.get("fan.fan_1")
assert state is not None
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."""
# Arrange
device = device_factory(
@ -150,15 +139,15 @@ async def test_set_speed(hass, device_factory):
# Act
await hass.services.async_call(
"fan",
"set_speed",
{ATTR_ENTITY_ID: "fan.fan_1", ATTR_SPEED: SPEED_HIGH},
"set_percentage",
{ATTR_ENTITY_ID: "fan.fan_1", ATTR_PERCENTAGE: 100},
blocking=True,
)
# Assert
state = hass.states.get("fan.fan_1")
assert state is not None
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):

View File

@ -8,17 +8,11 @@ from homeassistant.components.fan import (
ATTR_OSCILLATING,
ATTR_PERCENTAGE,
ATTR_PRESET_MODE,
ATTR_SPEED,
DIRECTION_FORWARD,
DIRECTION_REVERSE,
DOMAIN,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
SUPPORT_PRESET_MODE,
SUPPORT_SET_SPEED,
NotValidSpeedError,
)
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):
"""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)])
@ -165,26 +159,26 @@ async def test_wrong_template_config(hass, start_ha):
)
async def test_templates_with_entities(hass, start_ha):
"""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(_PERCENTAGE_INPUT_NUMBER, 66)
hass.states.async_set(_OSC_INPUT, "True")
for set_state, set_value, speed, value in [
(_DIRECTION_INPUT_SELECT, DIRECTION_FORWARD, SPEED_MEDIUM, 66),
(_PERCENTAGE_INPUT_NUMBER, 33, SPEED_LOW, 33),
(_PERCENTAGE_INPUT_NUMBER, 66, SPEED_MEDIUM, 66),
(_PERCENTAGE_INPUT_NUMBER, 100, SPEED_HIGH, 100),
(_PERCENTAGE_INPUT_NUMBER, "dog", None, 0),
for set_state, set_value, value in [
(_DIRECTION_INPUT_SELECT, DIRECTION_FORWARD, 66),
(_PERCENTAGE_INPUT_NUMBER, 33, 33),
(_PERCENTAGE_INPUT_NUMBER, 66, 66),
(_PERCENTAGE_INPUT_NUMBER, 100, 100),
(_PERCENTAGE_INPUT_NUMBER, "dog", 0),
]:
hass.states.async_set(set_state, set_value)
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)
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)])
@ -207,12 +201,12 @@ async def test_templates_with_entities(hass, start_ha):
},
"sensor.percentage",
[
("0", 0, SPEED_OFF, None),
("33", 33, SPEED_LOW, None),
("invalid", 0, None, None),
("5000", 0, None, None),
("100", 100, SPEED_HIGH, None),
("0", 0, SPEED_OFF, None),
("0", 0, None),
("33", 33, None),
("invalid", 0, None),
("5000", 0, None),
("100", 100, None),
("0", 0, None),
],
),
(
@ -232,21 +226,21 @@ async def test_templates_with_entities(hass, start_ha):
},
"sensor.preset_mode",
[
("0", None, None, None),
("invalid", None, None, None),
("auto", None, None, "auto"),
("smart", None, None, "smart"),
("invalid", None, None, None),
("0", None, None),
("invalid", None, None),
("auto", None, "auto"),
("smart", None, "smart"),
("invalid", None, None),
],
),
],
)
async def test_templates_with_entities2(hass, entity, tests, start_ha):
"""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)
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)])
@ -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):
"""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)])
@ -399,42 +393,7 @@ async def test_on_off(hass):
]:
await func(hass, _TEST_FAN)
assert hass.states.get(_STATE_INPUT_BOOLEAN).state == state
_verify(hass, state, None, 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")
_verify(hass, state, 0, None, None, None)
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")
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):
@ -456,7 +415,7 @@ async def test_set_osc(hass):
for state in [True, False]:
await common.async_oscillate(hass, _TEST_FAN, 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):
@ -467,7 +426,7 @@ async def test_set_direction(hass):
for cmd in [DIRECTION_FORWARD, DIRECTION_REVERSE]:
await common.async_set_direction(hass, _TEST_FAN, 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):
@ -478,17 +437,7 @@ async def test_set_invalid_direction(hass):
for cmd in [DIRECTION_FORWARD, "invalid"]:
await common.async_set_direction(hass, _TEST_FAN, cmd)
assert hass.states.get(_DIRECTION_INPUT_SELECT).state == DIRECTION_FORWARD
_verify(hass, STATE_ON, None, 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)
_verify(hass, STATE_ON, 0, None, DIRECTION_FORWARD, None)
async def test_preset_modes(hass):
@ -515,18 +464,18 @@ async def test_set_percentage(hass):
await _register_components(hass)
await common.async_turn_on(hass, _TEST_FAN)
for type, state, value in [
(SPEED_HIGH, STATE_ON, 100),
(SPEED_MEDIUM, STATE_ON, 66),
(SPEED_OFF, STATE_OFF, 0),
for state, value in [
(STATE_ON, 100),
(STATE_ON, 66),
(STATE_OFF, 0),
]:
await common.async_set_percentage(hass, _TEST_FAN, 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)
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):
@ -534,16 +483,16 @@ async def test_increase_decrease_speed(hass):
await _register_components(hass, speed_count=3)
await common.async_turn_on(hass, _TEST_FAN)
for func, extra, state, type, value in [
(common.async_set_percentage, 100, STATE_ON, SPEED_HIGH, 100),
(common.async_decrease_speed, None, STATE_ON, SPEED_MEDIUM, 66),
(common.async_decrease_speed, None, STATE_ON, SPEED_LOW, 33),
(common.async_decrease_speed, None, STATE_OFF, SPEED_OFF, 0),
(common.async_increase_speed, None, STATE_ON, SPEED_LOW, 33),
for func, extra, state, value in [
(common.async_set_percentage, 100, STATE_ON, 100),
(common.async_decrease_speed, None, STATE_ON, 66),
(common.async_decrease_speed, None, STATE_ON, 33),
(common.async_decrease_speed, None, STATE_OFF, 0),
(common.async_increase_speed, None, STATE_ON, 33),
]:
await func(hass, _TEST_FAN, extra)
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):
@ -551,16 +500,16 @@ async def test_increase_decrease_speed_default_speed_count(hass):
await _register_components(hass)
await common.async_turn_on(hass, _TEST_FAN)
for func, extra, state, type, value in [
(common.async_set_percentage, 100, STATE_ON, SPEED_HIGH, 100),
(common.async_decrease_speed, None, STATE_ON, SPEED_HIGH, 99),
(common.async_decrease_speed, None, STATE_ON, SPEED_HIGH, 98),
(common.async_decrease_speed, 31, STATE_ON, SPEED_HIGH, 67),
(common.async_decrease_speed, None, STATE_ON, SPEED_MEDIUM, 66),
for func, extra, state, value in [
(common.async_set_percentage, 100, STATE_ON, 100),
(common.async_decrease_speed, None, STATE_ON, 99),
(common.async_decrease_speed, None, STATE_ON, 98),
(common.async_decrease_speed, 31, STATE_ON, 67),
(common.async_decrease_speed, None, STATE_ON, 66),
]:
await func(hass, _TEST_FAN, extra)
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):
@ -571,7 +520,7 @@ async def test_set_invalid_osc_from_initial_state(hass):
with pytest.raises(vol.Invalid):
await common.async_oscillate(hass, _TEST_FAN, "invalid")
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):
@ -581,18 +530,17 @@ async def test_set_invalid_osc(hass):
await common.async_turn_on(hass, _TEST_FAN)
await common.async_oscillate(hass, _TEST_FAN, 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):
await common.async_oscillate(hass, _TEST_FAN, None)
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(
hass,
expected_state,
expected_speed,
expected_percentage,
expected_oscillating,
expected_direction,
@ -602,7 +550,6 @@ def _verify(
state = hass.states.get(_TEST_FAN)
attributes = state.attributes
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_OSCILLATING) == expected_oscillating
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.foundation as zcl_f
from homeassistant.components import fan
from homeassistant.components.fan import (
ATTR_PERCENTAGE,
ATTR_PERCENTAGE_STEP,
ATTR_PRESET_MODE,
ATTR_SPEED,
DOMAIN as FAN_DOMAIN,
SERVICE_SET_PERCENTAGE,
SERVICE_SET_PRESET_MODE,
SERVICE_SET_SPEED,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
NotValidPresetModeError,
)
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
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 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,))
async def async_turn_on(hass, entity_id, speed=None):
async def async_turn_on(hass, entity_id, percentage=None):
"""Turn fan on."""
data = {
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
}
@ -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)
async def async_set_speed(hass, entity_id, speed=None):
"""Set speed for specified fan."""
async def async_set_percentage(hass, entity_id, percentage=None):
"""Set percentage for specified fan."""
data = {
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
}
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):
@ -321,7 +317,7 @@ async def test_zha_group_fan_entity(hass, device_fan_1, device_fan_2, coordinato
# change speed from HA
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 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(
"plug_read, expected_state, expected_speed, expected_percentage",
"plug_read, expected_state, expected_percentage",
(
(None, STATE_OFF, None, None),
({"fan_mode": 0}, STATE_OFF, SPEED_OFF, 0),
({"fan_mode": 1}, STATE_ON, SPEED_LOW, 33),
({"fan_mode": 2}, STATE_ON, SPEED_MEDIUM, 66),
({"fan_mode": 3}, STATE_ON, SPEED_HIGH, 100),
(None, STATE_OFF, None),
({"fan_mode": 0}, STATE_OFF, 0),
({"fan_mode": 1}, STATE_ON, 33),
({"fan_mode": 2}, STATE_ON, 66),
({"fan_mode": 3}, STATE_ON, 100),
),
)
async def test_fan_init(
@ -443,7 +439,6 @@ async def test_fan_init(
zigpy_device,
plug_read,
expected_state,
expected_speed,
expected_percentage,
):
"""Test zha fan platform."""
@ -455,7 +450,6 @@ async def test_fan_init(
entity_id = await find_entity_id(Platform.FAN, zha_device, hass)
assert entity_id is not None
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_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)
assert entity_id is not None
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_PRESET_MODE] is None
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
)
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
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).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_PERCENTAGE_STEP] == 100 / 3
assert cluster.read_attributes.await_count == 4

View File

@ -1,16 +1,10 @@
"""Test Z-Wave fans."""
import pytest
from homeassistant.components.fan import (
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SPEED_OFF,
SUPPORT_SET_SPEED,
)
from homeassistant.components.fan import SUPPORT_SET_SPEED
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
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={})
assert isinstance(device, fan.ZwaveFan)
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):
@ -96,31 +89,3 @@ def test_fan_turn_off(mock_openzwave):
value_id, brightness = node.set_dimmer.mock_calls[0][1]
assert value_id == value.value_id
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 pytest
from voluptuous.error import MultipleInvalid
from zwave_js_server.event import Event
from homeassistant.components.fan import (
ATTR_PERCENTAGE,
ATTR_PERCENTAGE_STEP,
ATTR_SPEED,
SPEED_MEDIUM,
)
from homeassistant.components.fan import ATTR_PERCENTAGE, ATTR_PERCENTAGE_STEP
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(
"fan",
"turn_on",
{"entity_id": entity_id, "speed": SPEED_MEDIUM},
{"entity_id": entity_id, "percentage": 66},
blocking=True,
)
@ -54,11 +50,11 @@ async def test_generic_fan(hass, client, fan_generic, integration):
client.async_send_command.reset_mock()
# Test setting unknown speed
with pytest.raises(ValueError):
with pytest.raises(MultipleInvalid):
await hass.services.async_call(
"fan",
"set_speed",
{"entity_id": entity_id, "speed": 99},
"set_percentage",
{"entity_id": entity_id, "percentage": "bad"},
blocking=True,
)
@ -150,7 +146,7 @@ async def test_generic_fan(hass, client, fan_generic, integration):
state = hass.states.get(entity_id)
assert state.state == "on"
assert state.attributes[ATTR_SPEED] == "high"
assert state.attributes[ATTR_PERCENTAGE] == 100
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)
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):