Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor bond integration to be completely async #38066

Merged
merged 1 commit into from
Jul 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
prystupa marked this conversation as resolved.
Show resolved Hide resolved
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