Add basic support for IKEA Fyrtur blinds (#26659)

* Add basic support for IKEA Fyrtur blinds

* Update coveragerc

* Fix typo

* Fix typos

* Update following review

* Fix incorrect rebase

* Fix error

* Update to new format of unique id

* Add cover

* Remove reference to cover in unique id
This commit is contained in:
Patrik 2019-09-22 23:01:32 +02:00 committed by Martin Hjelmare
parent 2d906b111a
commit 49fef9a6a0
6 changed files with 161 additions and 17 deletions

View File

@ -669,6 +669,7 @@ omit =
homeassistant/components/trackr/device_tracker.py homeassistant/components/trackr/device_tracker.py
homeassistant/components/tradfri/* homeassistant/components/tradfri/*
homeassistant/components/tradfri/light.py homeassistant/components/tradfri/light.py
homeassistant/components/tradfri/cover.py
homeassistant/components/trafikverket_train/sensor.py homeassistant/components/trafikverket_train/sensor.py
homeassistant/components/trafikverket_weatherstation/sensor.py homeassistant/components/trafikverket_weatherstation/sensor.py
homeassistant/components/transmission/* homeassistant/components/transmission/*

View File

@ -131,6 +131,9 @@ async def async_setup_entry(hass, entry):
sw_version=gateway_info.firmware_version, sw_version=gateway_info.firmware_version,
) )
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, "cover")
)
hass.async_create_task( hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, "light") hass.config_entries.async_forward_entry_setup(entry, "light")
) )

View File

@ -0,0 +1,149 @@
"""Support for IKEA Tradfri covers."""
import logging
from pytradfri.error import PytradfriError
from homeassistant.components.cover import (
CoverDevice,
ATTR_POSITION,
SUPPORT_OPEN,
SUPPORT_CLOSE,
SUPPORT_SET_POSITION,
)
from homeassistant.core import callback
from . import DOMAIN as TRADFRI_DOMAIN, KEY_API, KEY_GATEWAY
from .const import CONF_GATEWAY_ID
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Load Tradfri covers based on a config entry."""
gateway_id = config_entry.data[CONF_GATEWAY_ID]
api = hass.data[KEY_API][config_entry.entry_id]
gateway = hass.data[KEY_GATEWAY][config_entry.entry_id]
devices_commands = await api(gateway.get_devices())
devices = await api(devices_commands)
covers = [dev for dev in devices if dev.has_blind_control]
if covers:
async_add_entities(TradfriCover(cover, api, gateway_id) for cover in covers)
class TradfriCover(CoverDevice):
"""The platform class required by Home Assistant."""
def __init__(self, cover, api, gateway_id):
"""Initialize a cover."""
self._api = api
self._unique_id = f"{gateway_id}-{cover.id}"
self._cover = None
self._cover_control = None
self._cover_data = None
self._name = None
self._available = True
self._gateway_id = gateway_id
self._refresh(cover)
@property
def supported_features(self):
"""Flag supported features."""
return SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_SET_POSITION
@property
def unique_id(self):
"""Return unique ID for cover."""
return self._unique_id
@property
def device_info(self):
"""Return the device info."""
info = self._cover.device_info
return {
"identifiers": {(TRADFRI_DOMAIN, self._cover.id)},
"name": self._name,
"manufacturer": info.manufacturer,
"model": info.model_number,
"sw_version": info.firmware_version,
"via_device": (TRADFRI_DOMAIN, self._gateway_id),
}
async def async_added_to_hass(self):
"""Start thread when added to hass."""
self._async_start_observe()
@property
def available(self):
"""Return True if entity is available."""
return self._available
@property
def should_poll(self):
"""No polling needed for tradfri cover."""
return False
@property
def name(self):
"""Return the display name of this cover."""
return self._name
@property
def current_cover_position(self):
"""Return current position of cover.
None is unknown, 0 is closed, 100 is fully open.
"""
return 100 - self._cover_data.current_cover_position
async def async_set_cover_position(self, **kwargs):
"""Move the cover to a specific position."""
await self._api(self._cover_control.set_state(100 - kwargs[ATTR_POSITION]))
async def async_open_cover(self, **kwargs):
"""Open the cover."""
await self._api(self._cover_control.set_state(0))
async def async_close_cover(self, **kwargs):
"""Close cover."""
await self._api(self._cover_control.set_state(100))
@property
def is_closed(self):
"""Return if the cover is closed or not."""
return self.current_cover_position == 0
@callback
def _async_start_observe(self, exc=None):
"""Start observation of cover."""
if exc:
self._available = False
self.async_schedule_update_ha_state()
_LOGGER.warning("Observation failed for %s", self._name, exc_info=exc)
try:
cmd = self._cover.observe(
callback=self._observe_update,
err_callback=self._async_start_observe,
duration=0,
)
self.hass.async_create_task(self._api(cmd))
except PytradfriError as err:
_LOGGER.warning("Observation failed, trying again", exc_info=err)
self._async_start_observe()
def _refresh(self, cover):
"""Refresh the cover data."""
self._cover = cover
# Caching of BlindControl and cover object
self._available = cover.reachable
self._cover_control = cover.blind_control
self._cover_data = cover.blind_control.blinds[0]
self._name = cover.name
@callback
def _observe_update(self, tradfri_device):
"""Receive new state data for this cover."""
self._refresh(tradfri_device)
self.async_schedule_update_ha_state()

View File

@ -1,6 +1,9 @@
"""Support for IKEA Tradfri lights.""" """Support for IKEA Tradfri lights."""
import logging import logging
from pytradfri.error import PytradfriError
import homeassistant.util.color as color_util
from homeassistant.components.light import ( from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP, ATTR_COLOR_TEMP,
@ -14,8 +17,6 @@ from homeassistant.components.light import (
Light, Light,
) )
from homeassistant.core import callback from homeassistant.core import callback
import homeassistant.util.color as color_util
from . import DOMAIN as TRADFRI_DOMAIN, KEY_API, KEY_GATEWAY from . import DOMAIN as TRADFRI_DOMAIN, KEY_API, KEY_GATEWAY
from .const import CONF_GATEWAY_ID, CONF_IMPORT_GROUPS from .const import CONF_GATEWAY_ID, CONF_IMPORT_GROUPS
@ -26,7 +27,6 @@ ATTR_HUE = "hue"
ATTR_SAT = "saturation" ATTR_SAT = "saturation"
ATTR_TRANSITION_TIME = "transition_time" ATTR_TRANSITION_TIME = "transition_time"
PLATFORM_SCHEMA = LIGHT_PLATFORM_SCHEMA PLATFORM_SCHEMA = LIGHT_PLATFORM_SCHEMA
IKEA = "IKEA of Sweden"
TRADFRI_LIGHT_MANAGER = "Tradfri Light Manager" TRADFRI_LIGHT_MANAGER = "Tradfri Light Manager"
SUPPORTED_FEATURES = SUPPORT_TRANSITION SUPPORTED_FEATURES = SUPPORT_TRANSITION
SUPPORTED_GROUP_FEATURES = SUPPORT_BRIGHTNESS | SUPPORT_TRANSITION SUPPORTED_GROUP_FEATURES = SUPPORT_BRIGHTNESS | SUPPORT_TRANSITION
@ -113,9 +113,6 @@ class TradfriGroup(Light):
@callback @callback
def _async_start_observe(self, exc=None): def _async_start_observe(self, exc=None):
"""Start observation of light.""" """Start observation of light."""
# pylint: disable=import-error
from pytradfri.error import PytradfriError
if exc: if exc:
_LOGGER.warning("Observation failed for %s", self._name, exc_info=exc) _LOGGER.warning("Observation failed for %s", self._name, exc_info=exc)
@ -339,8 +336,6 @@ class TradfriLight(Light):
@callback @callback
def _async_start_observe(self, exc=None): def _async_start_observe(self, exc=None):
"""Start observation of light.""" """Start observation of light."""
# pylint: disable=import-error
from pytradfri.error import PytradfriError
if exc: if exc:
self._available = False self._available = False

View File

@ -1,10 +1,11 @@
"""Support for IKEA Tradfri sensors.""" """Support for IKEA Tradfri sensors."""
from datetime import timedelta
import logging import logging
from datetime import timedelta
from pytradfri.error import PytradfriError
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from . import KEY_API, KEY_GATEWAY from . import KEY_API, KEY_GATEWAY
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -79,9 +80,6 @@ class TradfriDevice(Entity):
@callback @callback
def _async_start_observe(self, exc=None): def _async_start_observe(self, exc=None):
"""Start observation of light.""" """Start observation of light."""
# pylint: disable=import-error
from pytradfri.error import PytradfriError
if exc: if exc:
_LOGGER.warning("Observation failed for %s", self._name, exc_info=exc) _LOGGER.warning("Observation failed for %s", self._name, exc_info=exc)

View File

@ -1,15 +1,15 @@
"""Support for IKEA Tradfri switches.""" """Support for IKEA Tradfri switches."""
import logging import logging
from pytradfri.error import PytradfriError
from homeassistant.components.switch import SwitchDevice from homeassistant.components.switch import SwitchDevice
from homeassistant.core import callback from homeassistant.core import callback
from . import DOMAIN as TRADFRI_DOMAIN, KEY_API, KEY_GATEWAY from . import DOMAIN as TRADFRI_DOMAIN, KEY_API, KEY_GATEWAY
from .const import CONF_GATEWAY_ID from .const import CONF_GATEWAY_ID
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
IKEA = "IKEA of Sweden"
TRADFRI_SWITCH_MANAGER = "Tradfri Switch Manager" TRADFRI_SWITCH_MANAGER = "Tradfri Switch Manager"
@ -98,8 +98,6 @@ class TradfriSwitch(SwitchDevice):
@callback @callback
def _async_start_observe(self, exc=None): def _async_start_observe(self, exc=None):
"""Start observation of switch.""" """Start observation of switch."""
from pytradfri.error import PytradfriError
if exc: if exc:
self._available = False self._available = False
self.async_schedule_update_ha_state() self.async_schedule_update_ha_state()