diff --git a/get-groups.py b/get-groups.py new file mode 100755 index 0000000..d1c6446 --- /dev/null +++ b/get-groups.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +# +# Copyright 2019, Mischa Peters , High5!. +# Version 1.0 - 20191028 +# +# Get all light IDs +# +# For example: +# $ get-lights.py +# +# Follow the steps at the Hue Developer site to get the username/token +# https://developers.meethue.com/develop/get-started-2/ +# +# Requires: +# - Python >3.6 +# +import argparse +import ssl +import urllib.request +import json + +parser = argparse.ArgumentParser(description="Get all sensors from Hue Bridge") +parser.add_argument("bridge", type=str, help="Hue Bridge IP") +parser.add_argument("token", type=str, help="Hue API Token") + +try: + args = parser.parse_args() + bridge = args.bridge + token = args.token + +except argparse.ArgumentError as e: + print(str(e)) + +no_cert_check = ssl.create_default_context() +no_cert_check.check_hostname=False +no_cert_check.verify_mode=ssl.CERT_NONE + +url = f"https://{bridge}/api/{token}/groups" +req = urllib.request.Request(url) +with urllib.request.urlopen(req, context=no_cert_check) as response: + content = response.read() +json_data = json.loads(content) + +print(f"{'ID':>2s}: {'Name':<30s} Type") +print ("################################################################################") +for key in json_data: + print(f"{key:>2s}: {json_data[key]['name']:<30s} {json_data[key]['type']}") diff --git a/get-sensors.py b/get-sensors.py index d656a29..ab5f50f 100755 --- a/get-sensors.py +++ b/get-sensors.py @@ -60,9 +60,9 @@ for key in sensors: for i in sensors[key]: if json_data.get(i)['type'] == 'ZLLPresence': print(json_data.get(i)['name']) - print(f"{i}: {json_data.get(i)['productname']}") + print(f"\t{i}: {json_data.get(i)['productname']}") if json_data.get(i)['type'] == 'ZLLLightLevel': - print(f"{i}: {json_data.get(i)['productname']}") + print(f"\t{i}: {json_data.get(i)['productname']}") if json_data.get(i)['type'] == 'ZLLTemperature': - print(f"{i}: {json_data.get(i)['productname']}") + print(f"\t{i}: {json_data.get(i)['productname']}") diff --git a/groupctl.py b/groupctl.py new file mode 100755 index 0000000..559fa47 --- /dev/null +++ b/groupctl.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +# +# Copyright 2019, Mischa Peters , High5!. +# Version 1.0 - 20191102 +# +# Control a light or plug +# +# For example: +# $ groupctl.py -i 24 -a on +# +# Follow the steps at the Hue Developer site to get the username/token +# https://developers.meethue.com/develop/get-started-2/ +# +# Requires: +# - Python >3.6 +# +import argparse +import ssl +import urllib.request +import json + +parser = argparse.ArgumentParser(description="Control group lights (room)") +parser.add_argument("bridge", type=str, help="Hue Bridge IP") +parser.add_argument("token", type=str, help="Hue API Token") +parser.add_argument("-i", "--id", type=int, required=True, help="light id#") +parser.add_argument("-a", "--action", type=str, default='on', help="on|off|relax|bright|dimmed|nightlight") +parser.add_argument("-v", "--verbose", action='store_true', help="verbose") +parser.add_argument("-d", "--debug", action='store_true', help="debug") + +try: + args = parser.parse_args() + bridge = args.bridge + token = args.token + group_id = args.id + action = args.action + verbose = args.verbose + debug = args.debug + +except argparse.ArgumentError as e: + print(str(e)) + +no_cert_check = ssl.create_default_context() +no_cert_check.check_hostname=False +no_cert_check.verify_mode=ssl.CERT_NONE + +scenes = {'br': {}, 'ct': {}, 'xt': {}} +scenes['br']['bright'] = b'{"on": true, "bri": 254, "alert": "none"}' +scenes['br']['relax'] = b'{"on": true, "bri": 144, "alert": "none"}' +scenes['br']['dimmed'] = b'{"on": true, "bri": 77, "alert": "none"}' +scenes['br']['nightlight'] = b'{"on": true, "bri": 1, "alert": "none"}' +scenes['ct']['bright'] = b'{"on": true, "bri": 254, "ct": 367, "alert": "none", "colormode": "ct"}' +scenes['ct']['relax'] = b'{"on": true, "bri": 144, "ct": 447, "alert": "none", "colormode": "ct"}' +scenes['ct']['dimmed'] = b'{"on": true, "bri": 77, "ct": 367, "alert": "none", "colormode": "ct"}' +scenes['ct']['nightlight'] = b'{"on": true, "bri": 1, "ct": 447, "alert": "none", "colormode": "ct"}' +scenes['xt']['bright'] = b'{"on": true, "bri": 254, "hue": 8402, "sat": 140, "effect": "none", "xy": [0.4578, 0.41], "ct": 367, "alert": "none", "colormode": "xy"}' +scenes['xt']['relax'] = b'{"on": true, "bri": 144, "hue": 8402, "sat": 140, "effect": "none", "xy": [0.5019, 0.4152], "ct": 447, "alert": "none", "colormode": "xy"}' +scenes['xt']['dimmed'] = b'{"on": true, "bri": 77, "hue": 8402, "sat": 140, "effect": "none", "xy": [0.4578, 0.41], "ct": 367, "alert": "none", "colormode": "xy"}' +scenes['xt']['nightlight'] = b'{"on": true, "bri": 1, "hue": 8402, "sat": 140, "effect": "none", "xy": [0.561, 0.4042], "ct": 367, "alert": "none", "colormode": "xy"}' + +def get_state(id): + url = f"https://{bridge}/api/{token}/groups/{id}" + req = urllib.request.Request(url) + with urllib.request.urlopen(req, context=no_cert_check) as response: + content = response.read() + json_data = json.loads(content) + if debug: print (f"State for group id {id}:\n{json_data['state']}") + return (json_data['state']) + +def put_state(id, state): + if not 'colormode' in state: + if debug: print("state[colormode] not found, colormode set to: br") + colormode = "br" + else: + if debug: print(f"state[colormode] found, colormode set to: {state['colormode']}") + colormode = state['colormode'] + + if action == 'off': + if verbose or debug: print("Light {action}!") + data = b'{"on": false}' + elif action == 'on': + if verbose or debug: print("Light {action}!") + data = b'{"on": true}' + elif action in scenes[colormode]: + if verbose or debug: print("Light {action}!") + if debug: print(f"Light set to: {scenes[colormode][action]}") + data = scenes[colormode][action] + + url = f"https://{bridge}/api/{token}/groups/{id}/action" + req = urllib.request.Request(url=url, data=data, method='PUT') + res = urllib.request.urlopen(req, context=no_cert_check) + if debug: print (f"PUT response: {res.status} {res.reason}") + if verbose or debug: print (f"{res.status} {res.reason}") + return(res) + +group_state = get_state(group_id) +put_state(group_id, group_state) diff --git a/lightctl.py b/lightctl.py index 7bbd8e5..bd6550c 100755 --- a/lightctl.py +++ b/lightctl.py @@ -6,7 +6,7 @@ # Control a light or plug # # For example: -# $ lightctl.py -l 24 -a on +# $ lightctl.py -i 24 -a relax # # Follow the steps at the Hue Developer site to get the username/token # https://developers.meethue.com/develop/get-started-2/ @@ -19,11 +19,11 @@ import ssl import urllib.request import json -parser = argparse.ArgumentParser(description="Turn light on") +parser = argparse.ArgumentParser(description="Control light") parser.add_argument("bridge", type=str, help="Hue Bridge IP") parser.add_argument("token", type=str, help="Hue API Token") -parser.add_argument("-l", "--light", type=int, required=True, help="light id#") -parser.add_argument("-a", "--action", type=str, default='on', help="on|pff") +parser.add_argument("-i", "--id", type=int, required=True, help="light id#") +parser.add_argument("-a", "--action", type=str, default='on', help="on|off|relax|bright|dimmed|nightlight") parser.add_argument("-v", "--verbose", action='store_true', help="verbose") parser.add_argument("-d", "--debug", action='store_true', help="debug") @@ -31,7 +31,7 @@ try: args = parser.parse_args() bridge = args.bridge token = args.token - light = args.light + light_id = args.id action = args.action verbose = args.verbose debug = args.debug @@ -43,34 +43,55 @@ no_cert_check = ssl.create_default_context() no_cert_check.check_hostname=False no_cert_check.verify_mode=ssl.CERT_NONE -def get_state(type, id): - url = f"https://{bridge}/api/{token}/{type}/{id}" +scenes = {'br': {}, 'ct': {}, 'xt': {}} +scenes['br']['bright'] = b'{"on": true, "bri": 254, "alert": "none"}' +scenes['br']['relax'] = b'{"on": true, "bri": 144, "alert": "none"}' +scenes['br']['dimmed'] = b'{"on": true, "bri": 77, "alert": "none"}' +scenes['br']['nightlight'] = b'{"on": true, "bri": 1, "alert": "none"}' +scenes['ct']['bright'] = b'{"on": true, "bri": 254, "ct": 367, "alert": "none", "colormode": "ct"}' +scenes['ct']['relax'] = b'{"on": true, "bri": 144, "ct": 447, "alert": "none", "colormode": "ct"}' +scenes['ct']['dimmed'] = b'{"on": true, "bri": 77, "ct": 367, "alert": "none", "colormode": "ct"}' +scenes['ct']['nightlight'] = b'{"on": true, "bri": 1, "ct": 447, "alert": "none", "colormode": "ct"}' +scenes['xt']['bright'] = b'{"on": true, "bri": 254, "hue": 8402, "sat": 140, "effect": "none", "xy": [0.4578, 0.41], "ct": 367, "alert": "none", "colormode": "xy"}' +scenes['xt']['relax'] = b'{"on": true, "bri": 144, "hue": 8402, "sat": 140, "effect": "none", "xy": [0.5019, 0.4152], "ct": 447, "alert": "none", "colormode": "xy"}' +scenes['xt']['dimmed'] = b'{"on": true, "bri": 77, "hue": 8402, "sat": 140, "effect": "none", "xy": [0.4578, 0.41], "ct": 367, "alert": "none", "colormode": "xy"}' +scenes['xt']['nightlight'] = b'{"on": true, "bri": 1, "hue": 8402, "sat": 140, "effect": "none", "xy": [0.561, 0.4042], "ct": 367, "alert": "none", "colormode": "xy"}' + +def get_state(id): + url = f"https://{bridge}/api/{token}/lights/{id}" req = urllib.request.Request(url) with urllib.request.urlopen(req, context=no_cert_check) as response: content = response.read() json_data = json.loads(content) - if debug: print (f"State for {type[:-1]} id {id}:\n{json_data['state']}") - if debug: print (f"Type for {type[:-1]} id {id}: {json_data['config']['archetype']}") + if debug: print (f"State for light id {id}:\n{json_data['state']}") + if debug: print (f"Type for light id {id}: {json_data['config']['archetype']}") return (json_data['state']) -def put_state(type, id, action): - if action == "on": - data = b'{"on": true, "bri": 77, "hue": 8402, "sat": 254, "effect": "none", "xy": [0.4578, 0.41], "ct": 367, "alert": "none", "colormode": "xy"}' - if action == "off": - data = b'{"on":false}' +def put_state(id, state): + if not 'colormode' in state: + if debug: print("state[colormode] not found, colormode set to: br") + colormode = "br" + else: + if debug: print(f"state[colormode] found, colormode set to: {state['colormode']}") + colormode = state['colormode'] - url = f"https://{bridge}/api/{token}/{type}/{id}/state" + if action == 'off': + if verbose or debug: print("Light {action}!") + data = b'{"on": false}' + elif action == 'on': + if verbose or debug: print("Light {action}!") + data = b'{"on": true}' + elif action in scenes[colormode]: + if verbose or debug: print("Light {action}!") + if debug: print(f"Light set to: {scenes[colormode][action]}") + data = scenes[colormode][action] + + url = f"https://{bridge}/api/{token}/lights/{id}/state" req = urllib.request.Request(url=url, data=data, method='PUT') res = urllib.request.urlopen(req, context=no_cert_check) if debug: print (f"PUT response: {res.status} {res.reason}") if verbose or debug: print (f"{res.status} {res.reason}") return(res) -light_state = get_state("lights", light) - -if action == 'on' and not light_state['on']: - if verbose or debug: print ("Light ON!") - put_state("lights", light, "on") -if action == 'off' and light_state['on']: - if verbose or debug: print ("Light OFF!") - put_state("lights", light, "off") +light_state = get_state(light_id) +put_state(light_id, light_state)