From 00c6da8f0af96a6c1a89af15cd2c3fb3fd8248bc Mon Sep 17 00:00:00 2001 From: Micke Nordin Date: Wed, 5 May 2021 10:43:10 +0200 Subject: [PATCH] Implement Groups --- main.py | 6 +-- tinge/HueBridge/__init__.py | 60 ++++++++++++++++++++- tinge/HueGroup/__init__.py | 105 ++++++++++++++++++++++++++++++++++++ tinge/HueLight/__init__.py | 10 ++-- 4 files changed, 170 insertions(+), 11 deletions(-) create mode 100644 tinge/HueGroup/__init__.py diff --git a/main.py b/main.py index 34445b2..1c39b89 100644 --- a/main.py +++ b/main.py @@ -5,7 +5,5 @@ from tinge import Tinge if __name__ == "__main__": m_tinge = Tinge() bridge = m_tinge.get_bridges()[0] - for light in bridge.get_lights(): - print("Light: {} is reachable: {} and on:{}".format(light, light.is_reachable(), light.is_on())) - light.toggle() - print("Light: {} is reachable: {} and on:{}".format(light, light.is_reachable(), light.is_on())) + print(bridge.discover_new_lights()) + print(bridge.append_new_lights()) diff --git a/tinge/HueBridge/__init__.py b/tinge/HueBridge/__init__.py index 7330f7b..96c6a6e 100644 --- a/tinge/HueBridge/__init__.py +++ b/tinge/HueBridge/__init__.py @@ -2,24 +2,80 @@ # -*- coding: utf-8 -*- import json +from ..HueGroup import HueGroup from ..HueLight import HueLight from ..HueUtils import make_request -class HueBridge(): +class HueBridge: def __init__(self, ipaddress: str, username: str): self.m_ipaddress: str = ipaddress self.m_username: str = username self.m_lights: list[HueLight] = self.discover_lights() + self.m_groups: list[HueGroup] = self.discover_groups() + + def discover_groups(self) -> list[HueGroup]: + path: str = "{}/groups".format(self.m_username) + response = make_request(self.m_ipaddress, path) + groups: list[HueGroup] = list() + for key, value in json.loads(response.text).items(): + lights: list[HueLight] = list() + for light in value['lights']: + lights.append(self.get_light_by_id(int(light))) + groups.append(HueGroup(int(key), lights, value, self.get_ipaddress(), self.get_user())) + return groups + + def create_group(self, lights: list[HueLight], name: str, group_type: str = "LightGroup", + group_class: str = "Other") -> bool: + path = "{}/groups".format(self.get_user()) + method = "POST" + data: dict = {'lights': [], 'name': name, 'type': group_type, 'class': group_class} + for light in lights: + data['lights'].append(str(light.get_id())) + response = make_request(self.get_ipaddress(), path, method, json.dumps(data)) + r_json = response.json() + if 'success' in r_json.keys(): + new_id = r_json['success']['id'] + new_path = "{}/groups/{}".format(self.get_user(), new_id) + new_group = make_request(self.get_ipaddress(), new_path).json() + self.m_groups.append(HueGroup(int(new_id), lights, new_group, self.get_ipaddress(), self.get_user())) + return True + else: + return False def discover_lights(self) -> list[HueLight]: path: str = "{}/lights".format(self.m_username) response = make_request(self.m_ipaddress, path) lights: list[HueLight] = list() for key, value in json.loads(response.text).items(): - lights.append(HueLight(key, value, self.get_ipaddress(), self.get_user())) + lights.append(HueLight(int(key), value, self.get_ipaddress(), self.get_user())) return lights + def discover_new_lights(self, device_id_list=None) -> bool: + body: str = "" + if device_id_list is not None: + body_dict = {'deviceid': []} + for device in device_id_list: + body_dict['deviceid'].append(device) + body = json.dumps(body_dict) + path: str = "{}/lights".format(self.m_username) + method: str = "POST" + response = make_request(self.m_ipaddress, path, method, body) + return 'success' in response.json()[0].keys() + + def append_new_lights(self) -> bool: + path: str = "{}/lights/new".format(self.m_username) + response = make_request(self.m_ipaddress, path) + for key, value in json.loads(response.text).items(): + if key != 'lastscan': + path: str = "{}/lights/{}".format(self.m_username, key) + response = make_request(self.m_ipaddress, path) + self.m_lights.append(HueLight(int(key), response.json(), self.get_ipaddress(), self.get_user())) + return response.ok + + def get_groups(self): + return self.m_groups + def get_lights(self): return self.m_lights diff --git a/tinge/HueGroup/__init__.py b/tinge/HueGroup/__init__.py new file mode 100644 index 0000000..05ddb0c --- /dev/null +++ b/tinge/HueGroup/__init__.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import json + +import requests + +from ..HueLight import HueLight +from ..HueUtils import make_request + + +class HueGroup: + class Action: + def __init__(self, data_slice: dict): + keys = data_slice.keys() + self.m_on: bool = data_slice['on'] + self.m_bri: int = data_slice['bri'] + self.m_alert: str = data_slice['alert'] + if 'hue' in keys: + self.m_hue: int = data_slice['hue'] + else: + self.m_hue = 0 + if 'sat' in keys: + self.m_sat: int = data_slice['sat'] + else: + self.m_sat = 0 + if 'effect' in keys: + self.m_effect: str = data_slice['effect'] + else: + self.m_effect = str() + if 'xy' in keys: + self.m_xy: list[float] = data_slice['xy'] + else: + self.m_xy = list() + if 'ct' in keys: + self.m_ct: int = data_slice['ct'] + else: + self.m_ct = 0 + if 'colormode' in keys: + self.m_colormode: str = data_slice['colormode'] + else: + self.m_colormode = str() + + class State: + def __init__(self, data_slice: dict): + self.m_all_on: bool = data_slice['all_on'] + self.m_any_on: bool = data_slice['any_on'] + + def is_all_on(self) -> bool: + return self.m_all_on + + def is_any_on(self) -> bool: + return self.m_any_on + + def __init__(self, id: int, lights: list[HueLight], data: dict, parent_bridge_ip: str, parent_bridge_user: str): + self.m_id: int = id + self.m_parent_bridge_ip = parent_bridge_ip + self.m_parent_bridge_user = parent_bridge_user + self.m_name: str = data['name'] + self.m_lights = lights + self.m_sensors: list[str] = data['sensors'] + self.m_type: str = data['type'] + self.m_state: HueGroup.State = HueGroup.State(data['state']) + self.m_recycle: bool = data['recycle'] + if 'class' in data.keys(): + self.m_class: str = data['class'] + else: + self.m_class: str = str() + self.m_action: HueGroup.Action(data['action']) + + def __str__(self): + return self.m_name + + def get_id(self) -> int: + return self.m_id + + def is_all_on(self) -> bool: + return self.m_state.is_all_on() + + def is_any_on(self) -> bool: + return self.m_state.is_any_on() + + def toggle(self): + for light in self.m_lights: + light.toggle() + self.update_state() + + def turn_off(self): + state: str = '{"on": false}' + self.set_state(state) + + def turn_on(self): + state: str = '{"on": true}' + self.set_state(state) + + def set_state(self, state: str) -> requests.Response: + path: str = "{}/groups/{}/action".format(self.m_parent_bridge_user, self.m_id) + method: str = "PUT" + response = make_request(self.m_parent_bridge_ip, path, method, state) + self.update_state() + return response + + def update_state(self): + path: str = "{}/groups/{}".format(self.m_parent_bridge_user, self.m_id) + response = make_request(self.m_parent_bridge_ip, path) + self.m_state = HueGroup.State(json.loads(response.text)['state']) diff --git a/tinge/HueLight/__init__.py b/tinge/HueLight/__init__.py index 96f45ed..401c20e 100644 --- a/tinge/HueLight/__init__.py +++ b/tinge/HueLight/__init__.py @@ -111,11 +111,6 @@ class HueLight: def __str__(self) -> str: return self.m_name - def update_state(self): - path: str = "{}/lights/{}".format(self.m_parent_bridge_user, self.m_id) - response = make_request(self.m_parent_bridge_ip, path) - self.m_state = HueLight.State(json.loads(response.text)['state']) - def get_state(self): return self.m_state @@ -141,3 +136,8 @@ class HueLight: if self.is_on(): state = '{"on":false}' self.set_state(state) + + def update_state(self): + path: str = "{}/lights/{}".format(self.m_parent_bridge_user, self.m_id) + response = make_request(self.m_parent_bridge_ip, path) + self.m_state = HueLight.State(json.loads(response.text)['state'])