core/homeassistant/components/light/lifx.py

278 lines
8.2 KiB
Python
Raw Normal View History

2016-01-18 18:10:32 +00:00
"""
2016-03-07 21:08:21 +00:00
Support for the LIFX platform that implements lights.
2016-01-18 18:10:32 +00:00
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.lifx/
2016-01-18 18:10:32 +00:00
"""
import colorsys
2016-02-19 05:27:50 +00:00
import logging
2016-09-11 08:04:07 +00:00
import voluptuous as vol
2016-02-19 05:27:50 +00:00
from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_RGB_COLOR, ATTR_TRANSITION,
SUPPORT_BRIGHTNESS, SUPPORT_COLOR_TEMP, SUPPORT_RGB_COLOR,
2016-09-11 08:04:07 +00:00
SUPPORT_TRANSITION, Light, PLATFORM_SCHEMA)
2016-01-18 18:10:32 +00:00
from homeassistant.helpers.event import track_time_change
2016-09-11 08:04:07 +00:00
import homeassistant.helpers.config_validation as cv
2016-01-18 18:10:32 +00:00
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['liffylights==0.9.4']
2016-01-18 18:10:32 +00:00
2016-09-11 08:04:07 +00:00
BYTE_MAX = 255
CONF_BROADCAST = 'broadcast'
CONF_SERVER = 'server'
SHORT_MAX = 65535
TEMP_MAX = 9000
TEMP_MAX_HASS = 500
TEMP_MIN = 2500
TEMP_MIN_HASS = 154
2016-01-18 18:10:32 +00:00
SUPPORT_LIFX = (SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP | SUPPORT_RGB_COLOR |
SUPPORT_TRANSITION)
2016-09-11 08:04:07 +00:00
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_SERVER, default=None): cv.string,
vol.Optional(CONF_BROADCAST, default=None): cv.string,
})
2016-01-18 18:10:32 +00:00
2016-09-11 08:04:07 +00:00
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the LIFX platform."""
server_addr = config.get(CONF_SERVER)
broadcast_addr = config.get(CONF_BROADCAST)
lifx_library = LIFX(add_devices, server_addr, broadcast_addr)
# Register our poll service
track_time_change(hass, lifx_library.poll, second=[10, 40])
lifx_library.probe()
class LIFX(object):
2016-03-07 21:08:21 +00:00
"""Representation of a LIFX light."""
2016-09-11 08:04:07 +00:00
def __init__(self, add_devices_callback, server_addr=None,
broadcast_addr=None):
2016-03-07 21:08:21 +00:00
"""Initialize the light."""
2016-01-25 15:19:50 +00:00
import liffylights
2016-01-24 01:13:51 +00:00
2016-01-23 22:14:57 +00:00
self._devices = []
2016-01-18 18:10:32 +00:00
2016-01-23 22:14:57 +00:00
self._add_devices_callback = add_devices_callback
2016-01-18 18:10:32 +00:00
2016-01-25 15:19:50 +00:00
self._liffylights = liffylights.LiffyLights(
2016-09-11 08:04:07 +00:00
self.on_device, self.on_power, self.on_color, server_addr,
2016-01-25 15:19:50 +00:00
broadcast_addr)
2016-01-18 18:10:32 +00:00
2016-01-23 22:14:57 +00:00
def find_bulb(self, ipaddr):
2016-03-07 21:08:21 +00:00
"""Search for bulbs."""
2016-01-23 22:14:57 +00:00
bulb = None
for device in self._devices:
if device.ipaddr == ipaddr:
bulb = device
break
return bulb
2016-01-18 18:10:32 +00:00
2016-01-23 22:14:57 +00:00
def on_device(self, ipaddr, name, power, hue, sat, bri, kel):
2016-03-07 21:08:21 +00:00
"""Initialize the light."""
2016-01-23 22:14:57 +00:00
bulb = self.find_bulb(ipaddr)
if bulb is None:
_LOGGER.debug("new bulb %s %s %d %d %d %d %d",
ipaddr, name, power, hue, sat, bri, kel)
2016-09-11 08:04:07 +00:00
bulb = LIFXLight(
self._liffylights, ipaddr, name, power, hue, sat, bri, kel)
2016-01-23 22:14:57 +00:00
self._devices.append(bulb)
self._add_devices_callback([bulb])
else:
_LOGGER.debug("update bulb %s %s %d %d %d %d %d",
ipaddr, name, power, hue, sat, bri, kel)
bulb.set_power(power)
bulb.set_color(hue, sat, bri, kel)
bulb.update_ha_state()
2016-01-23 22:14:57 +00:00
def on_color(self, ipaddr, hue, sat, bri, kel):
2016-03-07 21:08:21 +00:00
"""Initialize the light."""
2016-01-23 22:14:57 +00:00
bulb = self.find_bulb(ipaddr)
if bulb is not None:
bulb.set_color(hue, sat, bri, kel)
bulb.update_ha_state()
def on_power(self, ipaddr, power):
2016-03-07 21:08:21 +00:00
"""Initialize the light."""
2016-01-23 22:14:57 +00:00
bulb = self.find_bulb(ipaddr)
if bulb is not None:
bulb.set_power(power)
bulb.update_ha_state()
2016-01-24 01:00:02 +00:00
# pylint: disable=unused-argument
2016-01-23 22:14:57 +00:00
def poll(self, now):
2016-08-11 10:00:37 +00:00
"""Polling for the light."""
2016-01-23 22:14:57 +00:00
self.probe()
def probe(self, address=None):
2016-08-11 10:00:37 +00:00
"""Probe the light."""
2016-01-23 22:14:57 +00:00
self._liffylights.probe(address)
2016-01-18 18:10:32 +00:00
def convert_rgb_to_hsv(rgb):
2016-03-07 21:08:21 +00:00
"""Convert Home Assistant RGB values to HSV values."""
2016-01-18 18:10:32 +00:00
red, green, blue = [_ / BYTE_MAX for _ in rgb]
hue, saturation, brightness = colorsys.rgb_to_hsv(red, green, blue)
2016-01-23 22:14:57 +00:00
return [int(hue * SHORT_MAX),
int(saturation * SHORT_MAX),
int(brightness * SHORT_MAX)]
2016-01-18 18:10:32 +00:00
class LIFXLight(Light):
2016-03-07 21:08:21 +00:00
"""Representation of a LIFX light."""
2016-09-11 08:04:07 +00:00
def __init__(self, liffy, ipaddr, name, power, hue, saturation, brightness,
kelvin):
2016-03-07 21:08:21 +00:00
"""Initialize the light."""
2016-09-11 08:04:07 +00:00
_LOGGER.debug("LIFXLight: %s %s", ipaddr, name)
2016-01-24 01:00:02 +00:00
self._liffylights = liffy
2016-01-18 18:10:32 +00:00
self._ip = ipaddr
self.set_name(name)
self.set_power(power)
self.set_color(hue, saturation, brightness, kelvin)
@property
def should_poll(self):
2016-03-07 21:08:21 +00:00
"""No polling needed for LIFX light."""
2016-01-18 18:10:32 +00:00
return False
@property
def name(self):
2016-03-07 21:08:21 +00:00
"""Return the name of the device."""
2016-01-18 18:10:32 +00:00
return self._name
@property
def ipaddr(self):
2016-03-07 21:08:21 +00:00
"""Return the IP address of the device."""
2016-01-18 18:10:32 +00:00
return self._ip
@property
def rgb_color(self):
2016-03-07 21:08:21 +00:00
"""Return the RGB value."""
2016-09-11 08:04:07 +00:00
_LOGGER.debug(
"rgb_color: [%d %d %d]", self._rgb[0], self._rgb[1], self._rgb[2])
2016-01-18 18:10:32 +00:00
return self._rgb
@property
def brightness(self):
2016-03-07 21:08:21 +00:00
"""Return the brightness of this light between 0..255."""
brightness = int(self._bri / (BYTE_MAX + 1))
2016-03-07 21:08:21 +00:00
_LOGGER.debug("brightness: %d", brightness)
return brightness
2016-01-18 18:10:32 +00:00
@property
def color_temp(self):
2016-03-07 21:08:21 +00:00
"""Return the color temperature."""
temperature = int(TEMP_MIN_HASS + (TEMP_MAX_HASS - TEMP_MIN_HASS) *
(self._kel - TEMP_MIN) / (TEMP_MAX - TEMP_MIN))
2016-03-07 21:08:21 +00:00
_LOGGER.debug("color_temp: %d", temperature)
return temperature
2016-01-18 18:10:32 +00:00
@property
def is_on(self):
2016-03-07 21:08:21 +00:00
"""Return true if device is on."""
_LOGGER.debug("is_on: %d", self._power)
2016-01-18 18:10:32 +00:00
return self._power != 0
@property
def supported_features(self):
"""Flag supported features."""
return SUPPORT_LIFX
2016-01-18 18:10:32 +00:00
def turn_on(self, **kwargs):
2016-03-07 21:08:21 +00:00
"""Turn the device on."""
if ATTR_TRANSITION in kwargs:
fade = kwargs[ATTR_TRANSITION] * 1000
else:
fade = 0
2016-01-18 18:10:32 +00:00
if ATTR_RGB_COLOR in kwargs:
hue, saturation, brightness = \
convert_rgb_to_hsv(kwargs[ATTR_RGB_COLOR])
else:
hue = self._hue
saturation = self._sat
brightness = self._bri
if ATTR_BRIGHTNESS in kwargs:
brightness = kwargs[ATTR_BRIGHTNESS] * (BYTE_MAX + 1)
else:
brightness = self._bri
2016-01-18 18:10:32 +00:00
if ATTR_COLOR_TEMP in kwargs:
# pylint: disable=fixme
# TODO: Use color_temperature_mired_to_kelvin from util.color
2016-01-18 18:10:32 +00:00
kelvin = int(((TEMP_MAX - TEMP_MIN) *
(kwargs[ATTR_COLOR_TEMP] - TEMP_MIN_HASS) /
(TEMP_MAX_HASS - TEMP_MIN_HASS)) + TEMP_MIN)
else:
kelvin = self._kel
_LOGGER.debug("turn_on: %s (%d) %d %d %d %d %d",
self._ip, self._power,
hue, saturation, brightness, kelvin, fade)
2016-01-23 22:14:57 +00:00
if self._power == 0:
self._liffylights.set_power(self._ip, 65535, fade)
2016-01-18 18:10:32 +00:00
2016-01-23 22:14:57 +00:00
self._liffylights.set_color(self._ip, hue, saturation,
brightness, kelvin, fade)
2016-01-18 18:10:32 +00:00
def turn_off(self, **kwargs):
2016-03-07 21:08:21 +00:00
"""Turn the device off."""
if ATTR_TRANSITION in kwargs:
fade = kwargs[ATTR_TRANSITION] * 1000
else:
fade = 0
2016-03-07 21:08:21 +00:00
_LOGGER.debug("turn_off: %s %d", self._ip, fade)
self._liffylights.set_power(self._ip, 0, fade)
2016-01-18 18:10:32 +00:00
def set_name(self, name):
2016-03-07 21:08:21 +00:00
"""Set name of the light."""
2016-01-18 18:10:32 +00:00
self._name = name
def set_power(self, power):
2016-03-07 21:08:21 +00:00
"""Set power state value."""
_LOGGER.debug("set_power: %d", power)
2016-01-18 18:10:32 +00:00
self._power = (power != 0)
def set_color(self, hue, sat, bri, kel):
2016-03-07 21:08:21 +00:00
"""Set color state values."""
2016-01-18 18:10:32 +00:00
self._hue = hue
self._sat = sat
self._bri = bri
self._kel = kel
2016-01-23 22:14:57 +00:00
red, green, blue = colorsys.hsv_to_rgb(hue / SHORT_MAX,
sat / SHORT_MAX,
bri / SHORT_MAX)
2016-01-18 18:10:32 +00:00
red = int(red * BYTE_MAX)
green = int(green * BYTE_MAX)
blue = int(blue * BYTE_MAX)
_LOGGER.debug("set_color: %d %d %d %d [%d %d %d]",
hue, sat, bri, kel, red, green, blue)
self._rgb = [red, green, blue]