Skip to content

Commit

Permalink
Add WiLight Fan (home-assistant#39541)
Browse files Browse the repository at this point in the history
* Add WiLight Fan

Add fan to WiLigt integration

* Updated fan.py and test_fan.py

* Creating new fan test

* Update homeassistant/components/wilight/__init__.py

OK!
Done!

Co-authored-by: Martin Hjelmare <[email protected]>

* Update homeassistant/components/wilight/fan.py

Co-authored-by: Martin Hjelmare <[email protected]>

* Update homeassistant/components/wilight/fan.py

Co-authored-by: Martin Hjelmare <[email protected]>

* Update homeassistant/components/wilight/fan.py

Co-authored-by: Martin Hjelmare <[email protected]>

* As MartinHjelmare requested

* Update fan.py

* Update tests/components/wilight/test_fan.py

Co-authored-by: Martin Hjelmare <[email protected]>

* Update tests/components/wilight/test_fan.py

Co-authored-by: Martin Hjelmare <[email protected]>

* Update test_fan.py

As Martin Hjelmare suggested

Co-authored-by: Martin Hjelmare <[email protected]>
  • Loading branch information
leofig-rj and MartinHjelmare authored Jan 25, 2021
1 parent edfb8c3 commit d174c82
Show file tree
Hide file tree
Showing 9 changed files with 352 additions and 14 deletions.
2 changes: 1 addition & 1 deletion homeassistant/components/wilight/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from .parent_device import WiLightParent

# List the platforms that you want to support.
PLATFORMS = ["light"]
PLATFORMS = ["fan", "light"]


async def async_setup(hass: HomeAssistant, config: dict):
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/wilight/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
WILIGHT_MANUFACTURER = "All Automacao Ltda"

# List the components supported by this integration.
ALLOWED_WILIGHT_COMPONENTS = ["light"]
ALLOWED_WILIGHT_COMPONENTS = ["light", "fan"]


class WiLightFlowHandler(ConfigFlow, domain=DOMAIN):
Expand Down
122 changes: 122 additions & 0 deletions homeassistant/components/wilight/fan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
"""Support for WiLight Fan."""

from pywilight.const import (
DOMAIN,
FAN_V1,
ITEM_FAN,
WL_DIRECTION_FORWARD,
WL_DIRECTION_OFF,
WL_DIRECTION_REVERSE,
WL_SPEED_HIGH,
WL_SPEED_LOW,
WL_SPEED_MEDIUM,
)

from homeassistant.components.fan import (
DIRECTION_FORWARD,
SPEED_HIGH,
SPEED_LOW,
SPEED_MEDIUM,
SUPPORT_DIRECTION,
SUPPORT_SET_SPEED,
FanEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant

from . import WiLightDevice

SUPPORTED_SPEEDS = [SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH]

SUPPORTED_FEATURES = SUPPORT_SET_SPEED | SUPPORT_DIRECTION


async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities
):
"""Set up WiLight lights from a config entry."""
parent = hass.data[DOMAIN][entry.entry_id]

# Handle a discovered WiLight device.
entities = []
for item in parent.api.items:
if item["type"] != ITEM_FAN:
continue
index = item["index"]
item_name = item["name"]
if item["sub_type"] != FAN_V1:
continue
entity = WiLightFan(parent.api, index, item_name)
entities.append(entity)

async_add_entities(entities)


class WiLightFan(WiLightDevice, FanEntity):
"""Representation of a WiLights fan."""

def __init__(self, api_device, index, item_name):
"""Initialize the device."""
super().__init__(api_device, index, item_name)
# Initialize the WiLights fan.
self._direction = WL_DIRECTION_FORWARD

@property
def supported_features(self):
"""Flag supported features."""
return SUPPORTED_FEATURES

@property
def icon(self):
"""Return the icon of device based on its type."""
return "mdi:fan"

@property
def is_on(self):
"""Return true if device is on."""
return self._status.get("direction", WL_DIRECTION_OFF) != WL_DIRECTION_OFF

@property
def speed(self) -> str:
"""Return the current speed."""
return self._status.get("speed", SPEED_HIGH)

@property
def speed_list(self) -> list:
"""Get the list of available speeds."""
return SUPPORTED_SPEEDS

@property
def current_direction(self) -> str:
"""Return the current direction of the fan."""
if "direction" in self._status:
if self._status["direction"] != WL_DIRECTION_OFF:
self._direction = self._status["direction"]
return self._direction

async def async_turn_on(self, speed: str = None, **kwargs):
"""Turn on the fan."""
if speed is None:
await self._client.set_fan_direction(self._index, self._direction)
else:
await self.async_set_speed(speed)

async def async_set_speed(self, speed: str):
"""Set the speed of the fan."""
wl_speed = WL_SPEED_HIGH
if speed == SPEED_LOW:
wl_speed = WL_SPEED_LOW
if speed == SPEED_MEDIUM:
wl_speed = WL_SPEED_MEDIUM
await self._client.set_fan_speed(self._index, wl_speed)

async def async_set_direction(self, direction: str):
"""Set the direction of the fan."""
wl_direction = WL_DIRECTION_REVERSE
if direction == DIRECTION_FORWARD:
wl_direction = WL_DIRECTION_FORWARD
await self._client.set_fan_direction(self._index, wl_direction)

async def async_turn_off(self, **kwargs):
"""Turn the fan off."""
await self._client.set_fan_direction(self._index, WL_DIRECTION_OFF)
2 changes: 1 addition & 1 deletion homeassistant/components/wilight/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "WiLight",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/wilight",
"requirements": ["pywilight==0.0.65"],
"requirements": ["pywilight==0.0.66"],
"ssdp": [
{
"manufacturer": "All Automacao Ltda"
Expand Down
8 changes: 3 additions & 5 deletions homeassistant/components/wilight/parent_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,9 @@ async def connect(api_device):
async def async_reset(self):
"""Reset api."""

# If the initialization was wrong.
if self._api is None:
return True

self._api.client.stop()
# If the initialization was not wrong.
if self._api is not None:
self._api.client.stop()


def create_api_device(host):
Expand Down
2 changes: 1 addition & 1 deletion requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1892,7 +1892,7 @@ pywebpush==1.9.2
pywemo==0.6.1

# homeassistant.components.wilight
pywilight==0.0.65
pywilight==0.0.66

# homeassistant.components.xeoma
pyxeoma==1.4.1
Expand Down
2 changes: 1 addition & 1 deletion requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -939,7 +939,7 @@ pywebpush==1.9.2
pywemo==0.6.1

# homeassistant.components.wilight
pywilight==0.0.65
pywilight==0.0.66

# homeassistant.components.zerproc
pyzerproc==0.4.7
Expand Down
20 changes: 16 additions & 4 deletions tests/components/wilight/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from tests.components.wilight import (
CONF_COMPONENTS,
HOST,
MOCK_SSDP_DISCOVERY_INFO_LIGHT_FAN,
MOCK_SSDP_DISCOVERY_INFO_MISSING_MANUFACTORER,
MOCK_SSDP_DISCOVERY_INFO_P_B,
MOCK_SSDP_DISCOVERY_INFO_WRONG_MANUFACTORER,
Expand All @@ -32,7 +31,7 @@


@pytest.fixture(name="dummy_get_components_from_model_clear")
def mock_dummy_get_components_from_model():
def mock_dummy_get_components_from_model_clear():
"""Mock a clear components list."""
components = []
with patch(
Expand All @@ -42,6 +41,17 @@ def mock_dummy_get_components_from_model():
yield components


@pytest.fixture(name="dummy_get_components_from_model_wrong")
def mock_dummy_get_components_from_model_wrong():
"""Mock a clear components list."""
components = ["wrong"]
with patch(
"pywilight.get_components_from_model",
return_value=components,
):
yield components


async def test_show_ssdp_form(hass: HomeAssistantType) -> None:
"""Test that the ssdp confirmation form is served."""

Expand Down Expand Up @@ -96,10 +106,12 @@ async def test_ssdp_not_wilight_abort_3(
assert result["reason"] == "not_wilight_device"


async def test_ssdp_not_supported_abort(hass: HomeAssistantType) -> None:
async def test_ssdp_not_supported_abort(
hass: HomeAssistantType, dummy_get_components_from_model_wrong
) -> None:
"""Test that the ssdp aborts not_supported."""

discovery_info = MOCK_SSDP_DISCOVERY_INFO_LIGHT_FAN.copy()
discovery_info = MOCK_SSDP_DISCOVERY_INFO_P_B.copy()
result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_SSDP}, data=discovery_info
)
Expand Down
Loading

0 comments on commit d174c82

Please sign in to comment.