2013-12-11 08:07:30 +00:00
|
|
|
"""
|
2014-01-05 01:55:05 +00:00
|
|
|
homeassistant.components.light
|
2013-12-11 08:07:30 +00:00
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Provides functionality to interact with lights.
|
2014-03-26 07:08:50 +00:00
|
|
|
|
|
|
|
It offers the following services:
|
|
|
|
|
|
|
|
TURN_OFF - Turns one or multiple lights off.
|
|
|
|
|
|
|
|
Supports following parameters:
|
|
|
|
- transition
|
|
|
|
Integer that represents the time the light should take to transition to
|
|
|
|
the new state.
|
|
|
|
- entity_id
|
|
|
|
String or list of strings that point at entity_ids of lights.
|
|
|
|
|
|
|
|
TURN_ON - Turns one or multiple lights on and change attributes.
|
|
|
|
|
|
|
|
Supports following parameters:
|
|
|
|
- transition
|
|
|
|
Integer that represents the time the light should take to transition to
|
|
|
|
the new state.
|
|
|
|
|
|
|
|
- entity_id
|
|
|
|
String or list of strings that point at entity_ids of lights.
|
|
|
|
|
|
|
|
- profile
|
|
|
|
String with the name of one of the built-in profiles (relax, energize,
|
|
|
|
concentrate, reading) or one of the custom profiles defined in
|
|
|
|
light_profiles.csv in the current working directory.
|
|
|
|
|
|
|
|
Light profiles define a xy color and a brightness.
|
|
|
|
|
|
|
|
If a profile is given and a brightness or xy color then the profile values
|
|
|
|
will be overwritten.
|
|
|
|
|
|
|
|
- xy_color
|
|
|
|
A list containing two floats representing the xy color you want the light
|
|
|
|
to be.
|
|
|
|
|
|
|
|
- rgb_color
|
|
|
|
A list containing three integers representing the xy color you want the
|
|
|
|
light to be.
|
|
|
|
|
|
|
|
- brightness
|
|
|
|
Integer between 0 and 255 representing how bright you want the light to be.
|
|
|
|
|
2013-12-11 08:07:30 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
import logging
|
2014-03-15 07:24:28 +00:00
|
|
|
import socket
|
2013-12-11 08:07:30 +00:00
|
|
|
from datetime import datetime, timedelta
|
2014-03-16 22:00:59 +00:00
|
|
|
from collections import namedtuple
|
2014-03-26 07:08:50 +00:00
|
|
|
import os
|
|
|
|
import csv
|
2013-12-11 08:07:30 +00:00
|
|
|
|
|
|
|
import homeassistant as ha
|
|
|
|
import homeassistant.util as util
|
2014-03-25 03:34:35 +00:00
|
|
|
from homeassistant.components import (group, extract_entity_ids,
|
|
|
|
STATE_ON, STATE_OFF,
|
2014-03-15 07:24:28 +00:00
|
|
|
SERVICE_TURN_ON, SERVICE_TURN_OFF,
|
2014-03-23 19:31:24 +00:00
|
|
|
ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME)
|
2014-03-15 07:24:28 +00:00
|
|
|
|
2013-12-11 08:07:30 +00:00
|
|
|
|
|
|
|
DOMAIN = "light"
|
|
|
|
|
2014-01-20 07:37:40 +00:00
|
|
|
GROUP_NAME_ALL_LIGHTS = 'all_lights'
|
|
|
|
ENTITY_ID_ALL_LIGHTS = group.ENTITY_ID_FORMAT.format(
|
|
|
|
GROUP_NAME_ALL_LIGHTS)
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-01-20 07:37:40 +00:00
|
|
|
ENTITY_ID_FORMAT = DOMAIN + ".{}"
|
2013-12-11 08:07:30 +00:00
|
|
|
|
|
|
|
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
|
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
# integer that represents transition time in seconds to make change
|
|
|
|
ATTR_TRANSITION = "transition"
|
|
|
|
|
|
|
|
# lists holding color values
|
|
|
|
ATTR_RGB_COLOR = "rgb_color"
|
|
|
|
ATTR_XY_COLOR = "xy_color"
|
|
|
|
|
|
|
|
# int with value 0 .. 255 representing brightness of the light
|
|
|
|
ATTR_BRIGHTNESS = "brightness"
|
|
|
|
|
2014-03-26 07:08:50 +00:00
|
|
|
# String representing a profile (built-in ones or external defined)
|
|
|
|
ATTR_PROFILE = "profile"
|
|
|
|
|
|
|
|
LIGHT_PROFILES_FILE = "light_profiles.csv"
|
|
|
|
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-01-21 07:23:02 +00:00
|
|
|
def is_on(statemachine, entity_id=None):
|
2013-12-11 08:07:30 +00:00
|
|
|
""" Returns if the lights are on based on the statemachine. """
|
2014-01-21 07:23:02 +00:00
|
|
|
entity_id = entity_id or ENTITY_ID_ALL_LIGHTS
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-15 07:24:28 +00:00
|
|
|
return statemachine.is_state(entity_id, STATE_ON)
|
2013-12-11 08:07:30 +00:00
|
|
|
|
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
# pylint: disable=too-many-arguments
|
|
|
|
def turn_on(bus, entity_id=None, transition=None, brightness=None,
|
2014-03-26 07:08:50 +00:00
|
|
|
rgb_color=None, xy_color=None, profile=None):
|
2013-12-11 08:07:30 +00:00
|
|
|
""" Turns all or specified light on. """
|
|
|
|
data = {}
|
|
|
|
|
2014-01-21 07:23:02 +00:00
|
|
|
if entity_id:
|
2014-03-15 07:24:28 +00:00
|
|
|
data[ATTR_ENTITY_ID] = entity_id
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-26 07:08:50 +00:00
|
|
|
if profile:
|
|
|
|
data[ATTR_PROFILE] = profile
|
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
if transition is not None:
|
|
|
|
data[ATTR_TRANSITION] = transition
|
|
|
|
|
|
|
|
if brightness is not None:
|
|
|
|
data[ATTR_BRIGHTNESS] = brightness
|
|
|
|
|
2014-03-26 07:08:50 +00:00
|
|
|
if rgb_color:
|
2014-03-16 22:00:59 +00:00
|
|
|
data[ATTR_RGB_COLOR] = rgb_color
|
|
|
|
|
2014-03-26 07:08:50 +00:00
|
|
|
if xy_color:
|
2014-03-16 22:00:59 +00:00
|
|
|
data[ATTR_XY_COLOR] = xy_color
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-15 07:24:28 +00:00
|
|
|
bus.call_service(DOMAIN, SERVICE_TURN_ON, data)
|
2013-12-11 08:07:30 +00:00
|
|
|
|
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
def turn_off(bus, entity_id=None, transition=None):
|
2013-12-11 08:07:30 +00:00
|
|
|
""" Turns all or specified light off. """
|
|
|
|
data = {}
|
|
|
|
|
2014-01-21 07:23:02 +00:00
|
|
|
if entity_id:
|
2014-03-15 07:24:28 +00:00
|
|
|
data[ATTR_ENTITY_ID] = entity_id
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
if transition is not None:
|
|
|
|
data[ATTR_TRANSITION] = transition
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-15 07:24:28 +00:00
|
|
|
bus.call_service(DOMAIN, SERVICE_TURN_OFF, data)
|
2013-12-11 08:07:30 +00:00
|
|
|
|
|
|
|
|
2014-03-26 07:08:50 +00:00
|
|
|
# pylint: disable=too-many-branches, too-many-locals
|
2013-12-11 08:07:30 +00:00
|
|
|
def setup(bus, statemachine, light_control):
|
|
|
|
""" Exposes light control via statemachine and services. """
|
|
|
|
|
2014-01-05 01:55:05 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2014-03-15 07:24:28 +00:00
|
|
|
ent_to_light = {}
|
|
|
|
light_to_ent = {}
|
2014-01-24 06:03:13 +00:00
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
def _update_light_state(light_id, light_state):
|
|
|
|
""" Update statemachine based on the LightState passed in. """
|
2014-03-23 19:31:24 +00:00
|
|
|
name = light_control.get_name(light_id) or "Unknown Light"
|
|
|
|
|
2013-12-11 08:07:30 +00:00
|
|
|
try:
|
2014-03-16 22:00:59 +00:00
|
|
|
entity_id = light_to_ent[light_id]
|
|
|
|
except KeyError:
|
|
|
|
# We have not seen this light before, set it up
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-23 19:31:24 +00:00
|
|
|
# Create entity id
|
2014-04-14 07:10:24 +00:00
|
|
|
logger.info("Found new light {}".format(name))
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-23 19:31:24 +00:00
|
|
|
entity_id = util.ensure_unique_string(
|
|
|
|
ENTITY_ID_FORMAT.format(util.slugify(name)),
|
2014-04-14 07:10:24 +00:00
|
|
|
list(ent_to_light.keys()))
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
ent_to_light[entity_id] = light_id
|
|
|
|
light_to_ent[light_id] = entity_id
|
2014-03-15 07:24:28 +00:00
|
|
|
|
2014-03-23 19:31:24 +00:00
|
|
|
state_attr = {ATTR_FRIENDLY_NAME: name}
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
if light_state.on:
|
|
|
|
state = STATE_ON
|
2014-03-15 07:24:28 +00:00
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
if light_state.brightness:
|
|
|
|
state_attr[ATTR_BRIGHTNESS] = light_state.brightness
|
2014-03-15 07:24:28 +00:00
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
if light_state.color:
|
|
|
|
state_attr[ATTR_XY_COLOR] = light_state.color
|
|
|
|
|
|
|
|
else:
|
|
|
|
state = STATE_OFF
|
|
|
|
|
|
|
|
statemachine.set_state(entity_id, state, state_attr)
|
|
|
|
|
|
|
|
def update_light_state(light_id):
|
|
|
|
""" Update the state of specified light. """
|
|
|
|
_update_light_state(light_id, light_control.get_state(light_id))
|
|
|
|
|
|
|
|
# pylint: disable=unused-argument
|
|
|
|
def update_lights_state(time, force_reload=False):
|
|
|
|
""" Update the state of all the lights. """
|
|
|
|
|
|
|
|
# First time this method gets called, force_reload should be True
|
|
|
|
if (force_reload or
|
|
|
|
datetime.now() - update_lights_state.last_updated >
|
|
|
|
MIN_TIME_BETWEEN_SCANS):
|
|
|
|
|
|
|
|
logger.info("Updating light status")
|
|
|
|
update_lights_state.last_updated = datetime.now()
|
|
|
|
|
|
|
|
for light_id, light_state in light_control.get_states().items():
|
|
|
|
_update_light_state(light_id, light_state)
|
2014-03-15 07:24:28 +00:00
|
|
|
|
|
|
|
# Update light state and discover lights for tracking the group
|
2014-03-16 22:00:59 +00:00
|
|
|
update_lights_state(None, True)
|
2014-01-05 01:55:05 +00:00
|
|
|
|
2014-03-26 07:08:50 +00:00
|
|
|
if len(ent_to_light) == 0:
|
|
|
|
logger.error("No lights found")
|
|
|
|
return False
|
|
|
|
|
2014-03-15 07:24:28 +00:00
|
|
|
# Track all lights in a group
|
|
|
|
group.setup(bus, statemachine,
|
|
|
|
GROUP_NAME_ALL_LIGHTS, light_to_ent.values())
|
2014-01-05 01:55:05 +00:00
|
|
|
|
2014-03-26 07:08:50 +00:00
|
|
|
# Load built-in profiles and custom profiles
|
|
|
|
profile_paths = [os.path.dirname(__file__), os.getcwd()]
|
|
|
|
profiles = {}
|
|
|
|
|
|
|
|
for dir_path in profile_paths:
|
|
|
|
file_path = os.path.join(dir_path, LIGHT_PROFILES_FILE)
|
|
|
|
|
|
|
|
if os.path.isfile(file_path):
|
2014-04-14 07:10:24 +00:00
|
|
|
with open(file_path) as inp:
|
2014-03-26 07:08:50 +00:00
|
|
|
reader = csv.reader(inp)
|
|
|
|
|
|
|
|
# Skip the header
|
|
|
|
next(reader, None)
|
|
|
|
|
|
|
|
try:
|
|
|
|
for profile_id, color_x, color_y, brightness in reader:
|
|
|
|
profiles[profile_id] = (float(color_x), float(color_y),
|
|
|
|
int(brightness))
|
|
|
|
|
|
|
|
except ValueError:
|
|
|
|
# ValueError if not 4 values per row
|
|
|
|
# ValueError if convert to float/int failed
|
|
|
|
logger.error(
|
|
|
|
"Error parsing light profiles from {}".format(
|
|
|
|
file_path))
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
2014-01-05 01:55:05 +00:00
|
|
|
def handle_light_service(service):
|
2013-12-11 08:07:30 +00:00
|
|
|
""" Hande a turn light on or off service call. """
|
2014-03-16 22:00:59 +00:00
|
|
|
# Get and validate data
|
|
|
|
dat = service.data
|
|
|
|
|
2014-03-25 03:34:35 +00:00
|
|
|
# Convert the entity ids to valid light ids
|
|
|
|
light_ids = [ent_to_light[entity_id] for entity_id
|
|
|
|
in extract_entity_ids(statemachine, service)
|
|
|
|
if entity_id in ent_to_light]
|
|
|
|
|
|
|
|
if not light_ids:
|
2014-04-14 07:10:24 +00:00
|
|
|
light_ids = list(ent_to_light.values())
|
2014-03-16 22:00:59 +00:00
|
|
|
|
2014-03-26 07:08:50 +00:00
|
|
|
transition = util.convert(dat.get(ATTR_TRANSITION), int)
|
2014-03-16 22:00:59 +00:00
|
|
|
|
|
|
|
if service.service == SERVICE_TURN_OFF:
|
2014-03-25 03:34:35 +00:00
|
|
|
light_control.turn_light_off(light_ids, transition)
|
2013-12-11 08:07:30 +00:00
|
|
|
|
|
|
|
else:
|
2014-03-16 22:00:59 +00:00
|
|
|
# Processing extra data for turn light on request
|
|
|
|
|
2014-03-26 07:08:50 +00:00
|
|
|
# We process the profile first so that we get the desired
|
|
|
|
# behavior that extra service data attributes overwrite
|
|
|
|
# profile values
|
|
|
|
profile = profiles.get(dat.get(ATTR_PROFILE))
|
|
|
|
|
|
|
|
if profile:
|
|
|
|
color = profile[0:2]
|
|
|
|
bright = profile[2]
|
|
|
|
else:
|
|
|
|
color = None
|
|
|
|
bright = None
|
|
|
|
|
|
|
|
if ATTR_BRIGHTNESS in dat:
|
|
|
|
bright = util.convert(dat.get(ATTR_BRIGHTNESS), int)
|
2014-03-16 22:00:59 +00:00
|
|
|
|
2014-03-26 07:08:50 +00:00
|
|
|
if ATTR_XY_COLOR in dat:
|
2014-03-16 22:00:59 +00:00
|
|
|
try:
|
|
|
|
# xy_color should be a list containing 2 floats
|
2014-03-26 07:08:50 +00:00
|
|
|
xy_color = [float(val) for val in dat.get(ATTR_XY_COLOR)]
|
2014-03-16 22:00:59 +00:00
|
|
|
|
|
|
|
if len(xy_color) == 2:
|
|
|
|
color = xy_color
|
|
|
|
|
|
|
|
except (TypeError, ValueError):
|
2014-03-26 07:08:50 +00:00
|
|
|
# TypeError if dat[ATTR_XY_COLOR] is not iterable
|
2014-03-16 22:00:59 +00:00
|
|
|
# ValueError if value could not be converted to float
|
|
|
|
pass
|
|
|
|
|
2014-03-26 07:08:50 +00:00
|
|
|
if ATTR_RGB_COLOR in dat:
|
2014-03-16 22:00:59 +00:00
|
|
|
try:
|
|
|
|
# rgb_color should be a list containing 3 ints
|
2014-03-26 07:08:50 +00:00
|
|
|
rgb_color = [int(val) for val in dat.get(ATTR_RGB_COLOR)]
|
2014-03-16 22:00:59 +00:00
|
|
|
|
|
|
|
if len(rgb_color) == 3:
|
|
|
|
color = util.color_RGB_to_xy(rgb_color[0],
|
|
|
|
rgb_color[1],
|
|
|
|
rgb_color[2])
|
|
|
|
|
|
|
|
except (TypeError, ValueError):
|
2014-03-26 07:08:50 +00:00
|
|
|
# TypeError if dat[ATTR_RGB_COLOR] is not iterable
|
|
|
|
# ValueError if not all values can be converted to int
|
2014-03-25 03:34:35 +00:00
|
|
|
pass
|
2014-03-16 22:00:59 +00:00
|
|
|
|
2014-03-25 03:34:35 +00:00
|
|
|
light_control.turn_light_on(light_ids, transition, bright, color)
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-25 03:34:35 +00:00
|
|
|
# Update state of lights touched. If there was only 1 light selected
|
|
|
|
# then just update that light else update all
|
|
|
|
if len(light_ids) == 1:
|
|
|
|
update_light_state(light_ids[0])
|
2014-03-16 22:00:59 +00:00
|
|
|
else:
|
|
|
|
update_lights_state(None, True)
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-15 07:24:28 +00:00
|
|
|
# Update light state every 30 seconds
|
2014-03-16 22:00:59 +00:00
|
|
|
ha.track_time_change(bus, update_lights_state, second=[0, 30])
|
2014-03-15 07:24:28 +00:00
|
|
|
|
|
|
|
# Listen for light on and light off service calls
|
|
|
|
bus.register_service(DOMAIN, SERVICE_TURN_ON,
|
2014-01-05 01:55:05 +00:00
|
|
|
handle_light_service)
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-15 07:24:28 +00:00
|
|
|
bus.register_service(DOMAIN, SERVICE_TURN_OFF,
|
2014-01-05 01:55:05 +00:00
|
|
|
handle_light_service)
|
2013-12-11 08:07:30 +00:00
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
LightState = namedtuple("LightState", ['on', 'brightness', 'color'])
|
|
|
|
|
|
|
|
|
|
|
|
def _hue_to_light_state(info):
|
|
|
|
""" Helper method to convert a Hue state to a LightState. """
|
|
|
|
try:
|
|
|
|
return LightState(info['state']['reachable'] and info['state']['on'],
|
|
|
|
info['state']['bri'], info['state']['xy'])
|
|
|
|
except KeyError:
|
|
|
|
# KeyError if one of the keys didn't exist
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
2013-12-11 08:07:30 +00:00
|
|
|
class HueLightControl(object):
|
|
|
|
""" Class to interface with the Hue light system. """
|
|
|
|
|
|
|
|
def __init__(self, host=None):
|
2014-01-12 20:35:10 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2013-12-11 08:07:30 +00:00
|
|
|
try:
|
|
|
|
import phue
|
|
|
|
except ImportError:
|
2014-01-12 20:35:10 +00:00
|
|
|
logger.exception(
|
|
|
|
"HueLightControl:Error while importing dependency phue.")
|
2013-12-11 08:07:30 +00:00
|
|
|
|
|
|
|
self.success_init = False
|
|
|
|
|
|
|
|
return
|
|
|
|
|
2014-01-12 20:35:10 +00:00
|
|
|
try:
|
|
|
|
self._bridge = phue.Bridge(host)
|
|
|
|
except socket.error: # Error connecting using Phue
|
|
|
|
logger.exception((
|
|
|
|
"HueLightControl:Error while connecting to the bridge. "
|
|
|
|
"Is phue registered?"))
|
|
|
|
|
|
|
|
self.success_init = False
|
|
|
|
|
|
|
|
return
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
# Dict mapping light_id to name
|
|
|
|
self._lights = {}
|
|
|
|
self._update_lights()
|
|
|
|
|
|
|
|
if len(self._lights) == 0:
|
2014-01-12 20:35:10 +00:00
|
|
|
logger.error("HueLightControl:Could not find any lights. ")
|
|
|
|
|
|
|
|
self.success_init = False
|
|
|
|
else:
|
|
|
|
self.success_init = True
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
def _update_lights(self):
|
|
|
|
""" Helper method to update the known names from Hue. """
|
2014-03-15 07:24:28 +00:00
|
|
|
try:
|
2014-03-16 22:00:59 +00:00
|
|
|
self._lights = {int(item[0]): item[1]['name'] for item
|
|
|
|
in self._bridge.get_light().items()}
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-15 07:24:28 +00:00
|
|
|
except (socket.error, KeyError):
|
|
|
|
# socket.error because sometimes we cannot reach Hue
|
|
|
|
# KeyError if we got unexpected data
|
2014-03-16 22:00:59 +00:00
|
|
|
# We don't do anything, keep old values
|
|
|
|
pass
|
|
|
|
|
|
|
|
def get_name(self, light_id):
|
|
|
|
""" Return name for specified light_id or None if no name known. """
|
|
|
|
if not light_id in self._lights:
|
|
|
|
self._update_lights()
|
|
|
|
|
|
|
|
return self._lights.get(light_id)
|
|
|
|
|
|
|
|
def get_state(self, light_id):
|
|
|
|
""" Return a LightState representing light light_id. """
|
|
|
|
try:
|
|
|
|
info = self._bridge.get_light(light_id)
|
|
|
|
|
|
|
|
return _hue_to_light_state(info)
|
|
|
|
|
|
|
|
except socket.error:
|
|
|
|
# socket.error when we cannot reach Hue
|
|
|
|
return None
|
2014-01-12 20:35:10 +00:00
|
|
|
|
2014-03-15 07:24:28 +00:00
|
|
|
def get_states(self):
|
2014-03-16 22:00:59 +00:00
|
|
|
""" Return a dict with id mapped to LightState objects. """
|
|
|
|
states = {}
|
2014-01-12 20:35:10 +00:00
|
|
|
|
2014-03-15 07:24:28 +00:00
|
|
|
try:
|
2014-03-16 22:00:59 +00:00
|
|
|
api = self._bridge.get_api()
|
2014-01-12 19:29:08 +00:00
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
except socket.error:
|
|
|
|
# socket.error when we cannot reach Hue
|
|
|
|
return states
|
|
|
|
|
|
|
|
api_states = api.get('lights')
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
if not isinstance(api_states, dict):
|
|
|
|
return states
|
|
|
|
|
|
|
|
for light_id, info in api_states.items():
|
|
|
|
state = _hue_to_light_state(info)
|
|
|
|
|
|
|
|
if state:
|
|
|
|
states[int(light_id)] = state
|
|
|
|
|
|
|
|
return states
|
|
|
|
|
2014-03-25 03:34:35 +00:00
|
|
|
def turn_light_on(self, light_ids, transition, brightness, xy_color):
|
2013-12-11 08:07:30 +00:00
|
|
|
""" Turn the specified or all lights on. """
|
2014-03-16 22:00:59 +00:00
|
|
|
command = {'on': True}
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
if transition is not None:
|
|
|
|
# Transition time is in 1/10th seconds and cannot exceed
|
|
|
|
# 900 seconds.
|
|
|
|
command['transitiontime'] = min(9000, transition * 10)
|
|
|
|
|
|
|
|
if brightness is not None:
|
|
|
|
command['bri'] = brightness
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
if xy_color:
|
|
|
|
command['xy'] = xy_color
|
|
|
|
|
2014-03-25 03:34:35 +00:00
|
|
|
self._bridge.set_light(light_ids, command)
|
2014-03-16 22:00:59 +00:00
|
|
|
|
2014-03-25 03:34:35 +00:00
|
|
|
def turn_light_off(self, light_ids, transition):
|
2014-03-16 22:00:59 +00:00
|
|
|
""" Turn the specified or all lights off. """
|
|
|
|
command = {'on': False}
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-16 22:00:59 +00:00
|
|
|
if transition is not None:
|
2013-12-11 08:07:30 +00:00
|
|
|
# Transition time is in 1/10th seconds and cannot exceed
|
2014-01-12 20:35:10 +00:00
|
|
|
# 900 seconds.
|
2014-03-16 22:00:59 +00:00
|
|
|
command['transitiontime'] = min(9000, transition * 10)
|
2013-12-11 08:07:30 +00:00
|
|
|
|
2014-03-25 03:34:35 +00:00
|
|
|
self._bridge.set_light(light_ids, command)
|