Xiaomi Philips Lights integration (#9087)
* Adds support for the Xiaomi Philips LED Ball and Ceiling Lamp * Documentation url updated. * New component to .coveragerc added. * Unused import removed. * translate labeled as static method. * Mixed parameters in log message fixed. * Order of requirements_all.txt fixed. * Plattform updated. It's async now. * Simplifiable if-statement fixed. * Some more clean-up of unneeded stuff. * Platform schema updated. * Component is called xiaomi_philipslight now. * Requirements all updated. * Initialization of some variables updated. * Raise PlatformNotReady exception if light cannot be discovered. * Import of math removed. Missing space added. * Remove unnecessary updatespull/9139/head
parent
8775c54d29
commit
56083c0c64
|
@ -328,6 +328,7 @@ omit =
|
|||
homeassistant/components/light/tplink.py
|
||||
homeassistant/components/light/tradfri.py
|
||||
homeassistant/components/light/x10.py
|
||||
homeassistant/components/light/xiaomi_philipslight.py
|
||||
homeassistant/components/light/yeelight.py
|
||||
homeassistant/components/light/yeelightsunflower.py
|
||||
homeassistant/components/light/zengge.py
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
"""
|
||||
Support for Xiaomi Philips Lights (LED Ball & Ceil).
|
||||
|
||||
For more details about this platform, please refer to the documentation
|
||||
https://home-assistant.io/components/light.xiaomi_philipslight/
|
||||
"""
|
||||
import asyncio
|
||||
from functools import partial
|
||||
import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.components.light import (
|
||||
PLATFORM_SCHEMA, ATTR_BRIGHTNESS, SUPPORT_BRIGHTNESS,
|
||||
ATTR_COLOR_TEMP, SUPPORT_COLOR_TEMP, Light, )
|
||||
|
||||
from homeassistant.const import (CONF_NAME, CONF_HOST, CONF_TOKEN, )
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_NAME = 'Xiaomi Philips Light'
|
||||
PLATFORM = 'xiaomi_philipslight'
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_HOST): cv.string,
|
||||
vol.Required(CONF_TOKEN): vol.All(cv.string, vol.Length(min=32, max=32)),
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
})
|
||||
|
||||
REQUIREMENTS = ['python-mirobo==0.1.3']
|
||||
|
||||
# The light does not accept cct values < 1
|
||||
CCT_MIN = 1
|
||||
CCT_MAX = 100
|
||||
|
||||
SUCCESS = ['ok']
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
@asyncio.coroutine
|
||||
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||
"""Set up the light from config."""
|
||||
from mirobo import Ceil, DeviceException
|
||||
if PLATFORM not in hass.data:
|
||||
hass.data[PLATFORM] = {}
|
||||
|
||||
host = config.get(CONF_HOST)
|
||||
name = config.get(CONF_NAME)
|
||||
token = config.get(CONF_TOKEN)
|
||||
|
||||
_LOGGER.info("Initializing with host %s (token %s...)", host, token[:5])
|
||||
|
||||
try:
|
||||
light = Ceil(host, token)
|
||||
|
||||
philips_light = XiaomiPhilipsLight(name, light)
|
||||
hass.data[PLATFORM][host] = philips_light
|
||||
except DeviceException:
|
||||
raise PlatformNotReady
|
||||
|
||||
async_add_devices([philips_light], update_before_add=True)
|
||||
|
||||
|
||||
class XiaomiPhilipsLight(Light):
|
||||
"""Representation of a Xiaomi Philips Light."""
|
||||
|
||||
def __init__(self, name, light):
|
||||
"""Initialize the light device."""
|
||||
self._name = name
|
||||
|
||||
self._brightness = None
|
||||
self._color_temp = None
|
||||
|
||||
self._light = light
|
||||
self._state = None
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Poll the light."""
|
||||
return True
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the device if any."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def available(self):
|
||||
"""Return true when state is known."""
|
||||
return self._state is not None
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if light is on."""
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def brightness(self):
|
||||
"""Return the brightness of this light between 0..255."""
|
||||
return self._brightness
|
||||
|
||||
@property
|
||||
def color_temp(self):
|
||||
"""Return the color temperature."""
|
||||
return self._color_temp
|
||||
|
||||
@property
|
||||
def min_mireds(self):
|
||||
"""Return the coldest color_temp that this light supports."""
|
||||
return 175
|
||||
|
||||
@property
|
||||
def max_mireds(self):
|
||||
"""Return the warmest color_temp that this light supports."""
|
||||
return 333
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Return the supported features."""
|
||||
return SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP
|
||||
|
||||
@asyncio.coroutine
|
||||
def _try_command(self, mask_error, func, *args, **kwargs):
|
||||
"""Call a light command handling error messages."""
|
||||
from mirobo import DeviceException
|
||||
try:
|
||||
result = yield from self.hass.async_add_job(
|
||||
partial(func, *args, **kwargs))
|
||||
|
||||
_LOGGER.debug("Response received from light: %s", result)
|
||||
|
||||
return result == SUCCESS
|
||||
except DeviceException as exc:
|
||||
_LOGGER.error(mask_error, exc)
|
||||
return False
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_turn_on(self, **kwargs):
|
||||
"""Turn the light on."""
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
brightness = kwargs[ATTR_BRIGHTNESS]
|
||||
percent_brightness = int(100 * brightness / 255)
|
||||
|
||||
_LOGGER.debug(
|
||||
"Setting brightness: %s %s%%",
|
||||
self.brightness, percent_brightness)
|
||||
|
||||
result = yield from self._try_command(
|
||||
"Setting brightness failed: %s",
|
||||
self._light.set_bright, percent_brightness)
|
||||
|
||||
if result:
|
||||
self._brightness = brightness
|
||||
|
||||
if ATTR_COLOR_TEMP in kwargs:
|
||||
color_temp = kwargs[ATTR_COLOR_TEMP]
|
||||
percent_color_temp = self.translate(
|
||||
color_temp, self.max_mireds,
|
||||
self.min_mireds, CCT_MIN, CCT_MAX)
|
||||
|
||||
_LOGGER.debug(
|
||||
"Setting color temperature: "
|
||||
"%s mireds, %s%% cct",
|
||||
color_temp, percent_color_temp)
|
||||
|
||||
result = yield from self._try_command(
|
||||
"Setting color temperature failed: %s cct",
|
||||
self._light.set_cct, percent_color_temp)
|
||||
|
||||
if result:
|
||||
self._color_temp = color_temp
|
||||
|
||||
result = yield from self._try_command(
|
||||
"Turning the light on failed.", self._light.on)
|
||||
|
||||
if result:
|
||||
self._state = True
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_turn_off(self, **kwargs):
|
||||
"""Turn the light off."""
|
||||
result = yield from self._try_command(
|
||||
"Turning the light off failed.", self._light.off)
|
||||
|
||||
if result:
|
||||
self._state = True
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_update(self):
|
||||
"""Fetch state from the device."""
|
||||
from mirobo import DeviceException
|
||||
try:
|
||||
state = yield from self.hass.async_add_job(self._light.status)
|
||||
_LOGGER.debug("Got new state: %s", state.data)
|
||||
|
||||
self._state = state.is_on
|
||||
self._brightness = int(255 * 0.01 * state.bright)
|
||||
self._color_temp = self.translate(state.cct, CCT_MIN, CCT_MAX,
|
||||
self.max_mireds,
|
||||
self.min_mireds)
|
||||
|
||||
except DeviceException as ex:
|
||||
_LOGGER.error("Got exception while fetching the state: %s", ex)
|
||||
|
||||
@staticmethod
|
||||
def translate(value, left_min, left_max, right_min, right_max):
|
||||
"""Map a value from left span to right span."""
|
||||
left_span = left_max - left_min
|
||||
right_span = right_max - right_min
|
||||
value_scaled = float(value - left_min) / float(left_span)
|
||||
return int(right_min + (value_scaled * right_span))
|
|
@ -21,7 +21,7 @@ from homeassistant.const import (
|
|||
ATTR_ENTITY_ID, CONF_HOST, CONF_NAME, CONF_TOKEN, STATE_OFF, STATE_ON)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
REQUIREMENTS = ['python-mirobo==0.1.2']
|
||||
REQUIREMENTS = ['python-mirobo==0.1.3']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
|
|
@ -740,8 +740,9 @@ python-juicenet==0.0.5
|
|||
# homeassistant.components.lirc
|
||||
# python-lirc==1.2.3
|
||||
|
||||
# homeassistant.components.light.xiaomi_philipslight
|
||||
# homeassistant.components.vacuum.xiaomi
|
||||
python-mirobo==0.1.2
|
||||
python-mirobo==0.1.3
|
||||
|
||||
# homeassistant.components.media_player.mpd
|
||||
python-mpd2==0.5.5
|
||||
|
|
Loading…
Reference in New Issue