Skip to content

Commit

Permalink
Refactor bond integration to be completely async (#38066)
Browse files Browse the repository at this point in the history
  • Loading branch information
prystupa authored Jul 23, 2020
1 parent 15fe727 commit 3480fb6
Show file tree
Hide file tree
Showing 16 changed files with 252 additions and 260 deletions.
6 changes: 3 additions & 3 deletions homeassistant/components/bond/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""The Bond integration."""
import asyncio

from bond import Bond
from bond_api import Bond

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_HOST
Expand All @@ -25,9 +25,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
host = entry.data[CONF_HOST]
token = entry.data[CONF_ACCESS_TOKEN]

bond = Bond(bondIp=host, bondToken=token)
bond = Bond(host=host, token=token)
hub = BondHub(bond)
await hass.async_add_executor_job(hub.setup)
await hub.setup()
hass.data[DOMAIN][entry.entry_id] = hub

device_registry = await dr.async_get_registry(hass)
Expand Down
37 changes: 16 additions & 21 deletions homeassistant/components/bond/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
"""Config flow for Bond integration."""
from json import JSONDecodeError
import logging

from bond import Bond
from requests.exceptions import ConnectionError as RequestConnectionError
from aiohttp import ClientConnectionError, ClientResponseError
from bond_api import Bond
import voluptuous as vol

from homeassistant import config_entries, core, exceptions
from homeassistant import config_entries, exceptions
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_HOST

from .const import DOMAIN # pylint:disable=unused-import
Expand All @@ -18,24 +17,20 @@
)


async def validate_input(hass: core.HomeAssistant, data):
async def validate_input(data):
"""Validate the user input allows us to connect."""

def authenticate(bond_hub: Bond) -> bool:
try:
bond_hub.getDeviceIds()
return True
except RequestConnectionError:
raise CannotConnect
except JSONDecodeError:
return False

bond = Bond(data[CONF_HOST], data[CONF_ACCESS_TOKEN])

if not await hass.async_add_executor_job(authenticate, bond):
raise InvalidAuth

# Return info that you want to store in the config entry.
try:
bond = Bond(data[CONF_HOST], data[CONF_ACCESS_TOKEN])
await bond.devices()
except ClientConnectionError:
raise CannotConnect
except ClientResponseError as error:
if error.status == 401:
raise InvalidAuth
raise

# Return info to be stored in the config entry.
return {"title": data[CONF_HOST]}


Expand All @@ -50,7 +45,7 @@ async def async_step_user(self, user_input=None):
errors = {}
if user_input is not None:
try:
info = await validate_input(self.hass, user_input)
info = await validate_input(user_input)
except CannotConnect:
errors["base"] = "cannot_connect"
except InvalidAuth:
Expand Down
20 changes: 10 additions & 10 deletions homeassistant/components/bond/cover.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Support for Bond covers."""
from typing import Any, Callable, List, Optional

from bond import DeviceTypes
from bond_api import Action, DeviceType

from homeassistant.components.cover import DEVICE_CLASS_SHADE, CoverEntity
from homeassistant.config_entries import ConfigEntry
Expand All @@ -24,7 +24,7 @@ async def async_setup_entry(
covers = [
BondCover(hub, device)
for device in hub.devices
if device.type == DeviceTypes.MOTORIZED_SHADES
if device.type == DeviceType.MOTORIZED_SHADES
]

async_add_entities(covers, True)
Expand All @@ -44,9 +44,9 @@ def device_class(self) -> Optional[str]:
"""Get device class."""
return DEVICE_CLASS_SHADE

def update(self):
async def async_update(self):
"""Fetch assumed state of the cover from the hub using API."""
state: dict = self._hub.bond.getDeviceState(self._device.device_id)
state: dict = await self._hub.bond.device_state(self._device.device_id)
cover_open = state.get("open")
self._closed = True if cover_open == 0 else False if cover_open == 1 else None

Expand All @@ -55,14 +55,14 @@ def is_closed(self):
"""Return if the cover is closed or not."""
return self._closed

def open_cover(self, **kwargs: Any) -> None:
async def async_open_cover(self, **kwargs: Any) -> None:
"""Open the cover."""
self._hub.bond.open(self._device.device_id)
await self._hub.bond.action(self._device.device_id, Action.open())

def close_cover(self, **kwargs: Any) -> None:
async def async_close_cover(self, **kwargs: Any) -> None:
"""Close cover."""
self._hub.bond.close(self._device.device_id)
await self._hub.bond.action(self._device.device_id, Action.close())

def stop_cover(self, **kwargs):
async def async_stop_cover(self, **kwargs):
"""Hold cover."""
self._hub.bond.hold(self._device.device_id)
await self._hub.bond.action(self._device.device_id, Action.hold())
40 changes: 22 additions & 18 deletions homeassistant/components/bond/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import math
from typing import Any, Callable, List, Optional

from bond import DeviceTypes, Directions
from bond_api import Action, DeviceType, Direction

from homeassistant.components.fan import (
DIRECTION_FORWARD,
Expand Down Expand Up @@ -33,9 +33,7 @@ async def async_setup_entry(
hub: BondHub = hass.data[DOMAIN][entry.entry_id]

fans = [
BondFan(hub, device)
for device in hub.devices
if device.type == DeviceTypes.CEILING_FAN
BondFan(hub, device) for device in hub.devices if DeviceType.is_fan(device.type)
]

async_add_entities(fans, True)
Expand Down Expand Up @@ -85,21 +83,21 @@ def speed_list(self) -> list:
def current_direction(self) -> Optional[str]:
"""Return fan rotation direction."""
direction = None
if self._direction == Directions.FORWARD:
if self._direction == Direction.FORWARD:
direction = DIRECTION_FORWARD
elif self._direction == Directions.REVERSE:
elif self._direction == Direction.REVERSE:
direction = DIRECTION_REVERSE

return direction

def update(self):
async def async_update(self):
"""Fetch assumed state of the fan from the hub using API."""
state: dict = self._hub.bond.getDeviceState(self._device.device_id)
state: dict = await self._hub.bond.device_state(self._device.device_id)
self._power = state.get("power")
self._speed = state.get("speed")
self._direction = state.get("direction")

def set_speed(self, speed: str) -> None:
async def async_set_speed(self, speed: str) -> None:
"""Set the desired speed for the fan."""
max_speed = self._device.props.get("max_speed", 3)
if speed == SPEED_LOW:
Expand All @@ -108,21 +106,27 @@ def set_speed(self, speed: str) -> None:
bond_speed = max_speed
else:
bond_speed = math.ceil(max_speed / 2)
self._hub.bond.setSpeed(self._device.device_id, speed=bond_speed)

def turn_on(self, speed: Optional[str] = None, **kwargs) -> None:
await self._hub.bond.action(
self._device.device_id, Action.set_speed(bond_speed)
)

async def async_turn_on(self, speed: Optional[str] = None, **kwargs) -> None:
"""Turn on the fan."""
if speed is not None:
self.set_speed(speed)
self._hub.bond.turnOn(self._device.device_id)
await self.async_set_speed(speed)
else:
await self._hub.bond.action(self._device.device_id, Action.turn_on())

def turn_off(self, **kwargs: Any) -> None:
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the fan off."""
self._hub.bond.turnOff(self._device.device_id)
await self._hub.bond.action(self._device.device_id, Action.turn_off())

def set_direction(self, direction: str) -> None:
async def async_set_direction(self, direction: str):
"""Set fan rotation direction."""
bond_direction = (
Directions.REVERSE if direction == DIRECTION_REVERSE else Directions.FORWARD
Direction.REVERSE if direction == DIRECTION_REVERSE else Direction.FORWARD
)
await self._hub.bond.action(
self._device.device_id, Action.set_direction(bond_direction)
)
self._hub.bond.setDirection(self._device.device_id, bond_direction)
34 changes: 17 additions & 17 deletions homeassistant/components/bond/light.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Support for Bond lights."""
from typing import Any, Callable, List, Optional

from bond import DeviceTypes
from bond_api import Action, DeviceType

from homeassistant.components.light import (
ATTR_BRIGHTNESS,
Expand Down Expand Up @@ -29,13 +29,13 @@ async def async_setup_entry(
lights: List[Entity] = [
BondLight(hub, device)
for device in hub.devices
if device.type == DeviceTypes.CEILING_FAN and device.supports_light()
if DeviceType.is_fan(device.type) and device.supports_light()
]

fireplaces: List[Entity] = [
BondFireplace(hub, device)
for device in hub.devices
if device.type == DeviceTypes.FIREPLACE
if DeviceType.is_fireplace(device.type)
]

async_add_entities(lights + fireplaces, True)
Expand All @@ -55,18 +55,18 @@ def is_on(self) -> bool:
"""Return if light is currently on."""
return self._light == 1

def update(self):
async def async_update(self):
"""Fetch assumed state of the light from the hub using API."""
state: dict = self._hub.bond.getDeviceState(self._device.device_id)
state: dict = await self._hub.bond.device_state(self._device.device_id)
self._light = state.get("light")

def turn_on(self, **kwargs: Any) -> None:
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn on the light."""
self._hub.bond.turnLightOn(self._device.device_id)
await self._hub.bond.action(self._device.device_id, Action.turn_light_on())

def turn_off(self, **kwargs: Any) -> None:
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off the light."""
self._hub.bond.turnLightOff(self._device.device_id)
await self._hub.bond.action(self._device.device_id, Action.turn_light_off())


class BondFireplace(BondEntity, LightEntity):
Expand All @@ -90,18 +90,18 @@ def is_on(self) -> bool:
"""Return True if power is on."""
return self._power == 1

def turn_on(self, **kwargs: Any) -> None:
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the fireplace on."""
self._hub.bond.turnOn(self._device.device_id)

brightness = kwargs.get(ATTR_BRIGHTNESS)
if brightness:
flame = round((brightness * 100) / 255)
self._hub.bond.setFlame(self._device.device_id, flame)
await self._hub.bond.action(self._device.device_id, Action.set_flame(flame))
else:
await self._hub.bond.action(self._device.device_id, Action.turn_on())

def turn_off(self, **kwargs: Any) -> None:
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the fireplace off."""
self._hub.bond.turnOff(self._device.device_id)
await self._hub.bond.action(self._device.device_id, Action.turn_off())

@property
def brightness(self):
Expand All @@ -113,8 +113,8 @@ def icon(self) -> Optional[str]:
"""Show fireplace icon for the entity."""
return "mdi:fireplace" if self._power == 1 else "mdi:fireplace-off"

def update(self):
async def async_update(self):
"""Fetch assumed state of the device from the hub using API."""
state: dict = self._hub.bond.getDeviceState(self._device.device_id)
state: dict = await self._hub.bond.device_state(self._device.device_id)
self._power = state.get("power")
self._flame = state.get("flame")
2 changes: 1 addition & 1 deletion homeassistant/components/bond/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/bond",
"requirements": [
"bond-home==0.0.9"
"bond-api==0.1.4"
],
"codeowners": [
"@prystupa"
Expand Down
18 changes: 9 additions & 9 deletions homeassistant/components/bond/switch.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
"""Support for Bond generic devices."""
from typing import Any, Callable, List, Optional

from bond import DeviceTypes
from bond_api import Action, DeviceType

from homeassistant.components.switch import SwitchEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity

from ..switch import SwitchEntity
from .const import DOMAIN
from .entity import BondEntity
from .utils import BondDevice, BondHub
Expand All @@ -24,7 +24,7 @@ async def async_setup_entry(
switches = [
BondSwitch(hub, device)
for device in hub.devices
if device.type == DeviceTypes.GENERIC_DEVICE
if DeviceType.is_generic(device.type)
]

async_add_entities(switches, True)
Expand All @@ -44,15 +44,15 @@ def is_on(self) -> bool:
"""Return True if power is on."""
return self._power == 1

def turn_on(self, **kwargs: Any) -> None:
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the device on."""
self._hub.bond.turnOn(self._device.device_id)
await self._hub.bond.action(self._device.device_id, Action.turn_on())

def turn_off(self, **kwargs: Any) -> None:
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the device off."""
self._hub.bond.turnOff(self._device.device_id)
await self._hub.bond.action(self._device.device_id, Action.turn_off())

def update(self):
async def async_update(self):
"""Fetch assumed state of the device from the hub using API."""
state: dict = self._hub.bond.getDeviceState(self._device.device_id)
state: dict = await self._hub.bond.device_state(self._device.device_id)
self._power = state.get("power")
Loading

0 comments on commit 3480fb6

Please sign in to comment.