Last active
August 25, 2016 09:37
-
-
Save chriszero/8b354c5165b634966dc7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# encoding: utf-8 | |
''' | |
boblighthue -- shortdesc | |
boblighthue connects a hue light to boblightd | |
@author: Christian Völlinger | |
@copyright: 2016 Christian Völlinger. All rights reserved. | |
@license: GNU GENERAL PUBLIC LICENSE v3 | |
@contact: zerov83@gmail.com | |
@deffield updated: Updated | |
''' | |
import os | |
import sys | |
import atexit | |
from select import select | |
from colormath.color_objects import sRGBColor, xyYColor | |
from colormath.color_conversions import convert_color | |
from argparse import ArgumentParser | |
from argparse import RawDescriptionHelpFormatter | |
from beautifulhue.api import Bridge | |
# pip install beautifulhue | |
# pip install colormath | |
__all__ = [] | |
__version__ = 0.2 | |
__date__ = '2016-01-24' | |
__updated__ = '2016-01-28' | |
class boblighthue(object): | |
def __init__(self, ip, id, user, timeout): | |
self._ip = ip | |
self._id = id | |
self._user = user | |
self._timeout = timeout | |
self._scaled = 0 | |
self._bridge = Bridge(device={'ip':self._ip}, user={'name':self._user}) | |
def connect(self): | |
response = self._getSystemData() | |
if 'lights' in response: | |
print 'Connected to the Hub' | |
elif 'error' in response[0]: | |
error = response[0]['error'] | |
if error['type'] == 1: | |
self._createConfig() | |
def popen(self): | |
# switch off at script exit | |
def cleanup(): | |
self.switch_off() | |
atexit.register(cleanup) | |
while True: | |
rlist, _, _ = select([sys.stdin], [], [], self._timeout) | |
if rlist: | |
input = sys.stdin.readline() | |
self.set_color(input) | |
else: | |
print "timeout, no data..." | |
self.switch_off() | |
def switch_off(self): | |
resource = { | |
'which': self._id, | |
'data': { | |
'state': {'on': False} | |
} | |
} | |
self._bridge.light.update(resource) | |
def set_color(self, rgb): | |
if len(rgb) > 0: | |
rgb = rgb.split(' ') | |
r = float(rgb[0]) | |
g = float(rgb[1]) | |
b = float(rgb[2]) | |
if self._scaled == 0: | |
if (r > 0 and r <= 1) or (g > 0 and g <= 1) or (b > 0 and b <= 1): | |
# 0 -1 | |
self._scaled = 1 | |
else: | |
self._scaled = 2 | |
# 0 - 255 | |
if self._scaled == 2: | |
r /= 255.0 | |
g /= 255.0 | |
b /= 255.0 | |
if all(x > 0 for x in (r, g, b)): | |
on = True | |
else: | |
return | |
r, g, b = self._gamma_correction(r, g, b) | |
xy = convert_color(sRGBColor(r, g, b, is_upscaled=False), xyYColor, observer=2, target_illuminant='d65') | |
bri = int(max(b, max(r, g)) * 255) | |
resource = { | |
'which': self._id, | |
'data': { | |
'state': { | |
'on': on, | |
'xy': [xy.xyy_x, xy.xyy_y], | |
'bri': bri | |
} | |
} | |
} | |
self._bridge.light.update(resource) | |
def _gamma_correction(self, red, green, blue): | |
red = (red > 0.04045) if pow((red + 0.055) / (1.0 + 0.055), 2.0) else (red / 12.92) | |
green = (green > 0.04045) if pow((green + 0.055) / (1.0 + 0.055), 2.4) else (green / 12.92) | |
blue = (blue > 0.04045) if pow((blue + 0.055) / (1.0 + 0.055), 2.4) else (blue / 12.92) | |
return (red, green, blue) | |
def _rgb_to_xy_bri(self, red, green, blue): | |
# Convert the RGB values to XYZ using the Wide RGB D65 conversion formula | |
X = red * 0.664511 + green * 0.154324 + blue * 0.162028 | |
Y = red * 0.283881 + green * 0.668433 + blue * 0.047685 | |
Z = red * 0.000088 + green * 0.072310 + blue * 0.986039 | |
x = X / (X + Y + Z) | |
y = Y / (X + Y + Z) | |
return {'xy': [x, y], 'bri': int(Y)} | |
def _getSystemData(self): | |
resource = {'which':'system'} | |
return self._bridge.config.get(resource)['resource'] | |
def _createConfig(self): | |
created = False | |
print 'Press the button on the Hue bridge' | |
while not created: | |
resource = {'user':{'devicetype': 'boblighthue', 'name': self._user}} | |
response = self._bridge.config.create(resource)['resource'] | |
if 'error' in response[0]: | |
if response[0]['error']['type'] != 101: | |
print 'Unhandled error creating configuration on the Hue' | |
sys.exit(response) | |
else: | |
created = True | |
def main(argv=None): | |
'''Command line options.''' | |
if argv is None: | |
argv = sys.argv | |
else: | |
sys.argv.extend(argv) | |
program_name = os.path.basename(sys.argv[0]) | |
program_version = "v%s" % __version__ | |
program_build_date = str(__updated__) | |
program_version_message = '%%(prog)s %s (%s)' % (program_version, program_build_date) | |
program_shortdesc = __import__('__main__').__doc__.split("\n")[1] | |
program_license = '''%s | |
Created by chriszero on %s. | |
Copyright 2013 organization_name. All rights reserved. | |
Licensed under the GNU GENERAL PUBLIC LICENSE v3 | |
https://www.gnu.org/licenses/gpl-3.0.de.html | |
Distributed on an "AS IS" basis without warranties | |
or conditions of any kind, either express or implied. | |
USAGE | |
''' % (program_shortdesc, str(__date__)) | |
try: | |
# Setup argument parser | |
parser = ArgumentParser(description=program_license, formatter_class=RawDescriptionHelpFormatter) | |
parser.add_argument("-H", "--host", type=str, required=True, help="Host (ip) of the bridge") | |
parser.add_argument("-i", "--lightid", type=int, required=True, help="Id of the light you want to control") | |
parser.add_argument("-t", "--timeout", type=int, default=30, help='If no data is received for "Timeout", light is switched off') | |
parser.add_argument("-u", "--user", default="boblighthue", help="Set the username, it will be created if it doesn't exist") | |
parser.add_argument("--testcolor", help='Test color, you have to quote "R G B"') | |
parser.add_argument("--off", action='store_true', help='Switch off') | |
parser.add_argument('--version', action='version', version=program_version_message) | |
# Process arguments | |
args = parser.parse_args() | |
con = boblighthue(args.host, args.lightid, args.user, args.timeout) | |
con.connect() | |
if args.off: | |
con.switch_off() | |
return 0 | |
if args.testcolor: | |
con.set_color(args.testcolor) | |
else: | |
con.popen() | |
except Exception as e: | |
print e | |
return 2 | |
if __name__ == "__main__": | |
sys.exit(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment