Skip to content

Instantly share code, notes, and snippets.

@chriszero
Last active August 25, 2016 09:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chriszero/8b354c5165b634966dc7 to your computer and use it in GitHub Desktop.
Save chriszero/8b354c5165b634966dc7 to your computer and use it in GitHub Desktop.
#!/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