#!/usr/bin/env python # -*- coding: utf-8 -*- import json try: from httplib import HTTPConnection except ImportError: from http.client import HTTPConnection kelvin2mired = lambda k: 10**6 / k huedegree2hue = lambda d: d* 182 def cmyk2hsb(c, m, y, k): pass def rgb2xy(r, g, b): X = 0.412453 * r + 0.357580 * g + 0.180423 * b Y = 0.212671 * r + 0.715160 * g + 0.072169 * b Z = 0.019334 * r + 0.119193 * g + 0.950227 * b x = X / (X+Y+Z) y = Y / (X+Y+Z) return x, y class HueException(Exception): pass class Bridge(object): def __init__(self, ip_address, username): self.ip_address = ip_address self.username = username def _request(self, method, route, data={}): content = json.dumps(data).lower() str_route = '/'.join(['/api', self.username] + route) try: conn = HTTPConnection(self.ip_address) conn.request(method, str_route, content) response = conn.getresponse() return json.loads(response.read().decode()) except: raise HueException("Not able to connect to the bridge") def __get_api_objects(self, cls): result = self._request('GET', [cls.ROUTE]) objects = [cls(self, i) for i in result.keys()] return sorted(objects, key=lambda x: x.id) @property def lights(self): return self.__get_api_objects(Light) @property def groups(self): return [Group(self, "0")] + self.__get_api_objects(Group) @property def schedules(self): return self.__get_api_objects(Schedule) def get_light(self, light_id): return Light(self, light_id) def add_schedule(self, schedule_attrs): return self._request('POST', ['schedules'], schedule_attrs) class AssignableSetattr(type): def __new__(mcls, name, bases, attrs): # @NoSelf def __setattr__(self, attr, value): object.__setattr__(self, attr, value) init_attrs = dict(attrs) init_attrs['__setattr__'] = __setattr__ base = super(AssignableSetattr, mcls) init_cls = base.__new__(mcls, name, bases, init_attrs) real_cls = base.__new__(mcls, name, (init_cls,), attrs) init_cls.__real_cls = real_cls return init_cls def __call__(cls, *args, **kwargs): # @NoSelf self = super(AssignableSetattr, cls).__call__(*args, **kwargs) real_cls = cls.__real_cls self.__class__ = real_cls return self class ApiObject(object): __metaclass__ = AssignableSetattr def __init__(self, bridge, _id): result = bridge._request('GET', [self.ROUTE, _id]) if any('error' in x for x in result): raise HueException(result[0]['error']['description']) self.bridge = bridge self.id = _id for attr, value in result.items(): setattr(self, attr, value) def set(self, attr, value): object.__setattr__(self, attr, value) api_route = [self.ROUTE, self.id] return self.bridge._request('PUT', api_route, {attr: value}) class Light(ApiObject): ROUTE = 'lights' def update(self, **kw): self.state.update(kw) api_route = [self.ROUTE, self.id, 'state'] return self.bridge._request('PUT', api_route, kw) def __setattr__(self, attr, value): if attr in self.state: result = self.update(**{attr: value}) else: result = self.set(attr, value) if any('error' in confirmation for confirmation in result): raise HueException("Invalid attribute") def __getattr__(self, attr): if attr in self.state: return self.state[attr] else: return object.__getattr__(self, attr) class Group(ApiObject): ROUTE = 'groups' def update(self, **kw): self.action.update(kw) api_route = [self.ROUTE, self.id, 'action'] return self.bridge._request('PUT', api_route, kw) def __setattr__(self, attr, value): if attr in self.action: result = self.update(**{attr: value}) else: result = self.set(attr, value) if any('error' in confirmation for confirmation in result): raise HueException("Invalid attribute") def __getattr__(self, attr): if attr in self.action: return self.action[attr] else: return object.__getattribute__(self, attr) class Schedule(ApiObject): ROUTE = 'schedules' def __setattr__(self, attr, value): result = self.set(attr, value) if any('error' in confirmation for confirmation in result): raise HueException("Invalid attribute") def __del__(self): self.bridge._request('DELETE', [self.ROUTE, self.id])