diff --git a/.gitignore b/.gitignore index e61bca2..8f0d67a 100644 --- a/.gitignore +++ b/.gitignore @@ -114,3 +114,5 @@ dmypy.json # Pyre type checker .pyre/ +# Pycharm +.idea/ diff --git a/tinge/HueBridge/__init__.py b/tinge/HueBridge/__init__.py new file mode 100644 index 0000000..96e6e46 --- /dev/null +++ b/tinge/HueBridge/__init__.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + + +class HueBridge(): + def __init__(self, ipaddress: str, username: str): + self.mipaddress: str = ipaddress + self.musername: str = username + + def get_ipaddress(self): + return self.mipaddress + + def get_user(self): + return self.musername diff --git a/tinge/UserOrError/__init__.py b/tinge/UserOrError/__init__.py new file mode 100644 index 0000000..73a9f96 --- /dev/null +++ b/tinge/UserOrError/__init__.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + + +class UserOrError: + def __init__(self): + self.muser: str = str() + self.merror: bool = True + self.mcode: int = 0 + + def get_error_code(self) -> int: + return self.mcode + + def get_user(self) -> str: + return self.muser + + def is_error(self) -> bool: + return self.merror + + def set_error(self, code: int): + self.merror = True + self.mcode = code + + def set_user(self, username: str): + self.merror = False + self.muser = username diff --git a/tinge/__init__.py b/tinge/__init__.py new file mode 100644 index 0000000..f59ac89 --- /dev/null +++ b/tinge/__init__.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import json +import os +import time +import uuid + +import requests +import toml +from upnpy import UPnP + +import tinge + + +def connect(ipaddress: str, appid: uuid.UUID = uuid.uuid4()) -> UserOrError: + user_or_error = UserOrError() + body: dict = json.loads('{"devicetype":"{}#{}"}'.format("tinge", appid)) + path: str = "api" + method: str = "POST" + response: requests.Response = make_request(ipaddress, path, method, body) + + data: dict = response.json()[0] + if 'error' in data.keys(): + user_or_error.set_error(data['error']['type']) + elif 'success' in data.keys(): + user_or_error.set_user(data['success']['username']) + else: + user_or_error.set_error(9999) + return user_or_error + + +def is_valid_config(filename: str) -> bool: + return os.path.exists(filename) and os.path.getsize(filename) > 0 + + +def make_request(ipaddress: str, path: str, method: str = "GET", + body: dict = json.loads('{}')) -> requests.Response: + rfunct = requests.get + url = "http://{}/{}".format(ipaddress, path) + if method == "PUT": + rfunct = requests.put + elif method == "POST": + rfunct = requests.post + elif method == "DELETE": + rfunct = requests.delete + response: requests.Response = requests.Response() + if body: + response = rfunct(url, data=body) + else: + response = rfunct(url) + return response + + +class Tinge: + def __init__(self): + self.mbridges: list[HueBridge] = list() + self.mdiscovered: list[str] = list() + + def discover_new_bridges(self): + upnp: UPnP = UPnP() + for device in upnp.discover(): + if device.get_friendly_name().startswith("Philips hue") and device.host not in self.mdiscovered: + user_or_error: UserOrError = connect(device.host) + while user_or_error.is_error(): + if user_or_error.get_error_code() == 101: + print("Please press the button on your Hue Bridge") + time.sleep(5) + user_or_error = connect(device.host) + bridge: HueBridge = HueBridge(device.host, user_or_error.get_user) + + self.mbridges.append(bridge) + self.mdiscovered.append(device.host) + + def get_bridges_from_file(self): + if is_valid_config(self.config): + with open(self.config, 'r') as configfile: + mbridges = toml.loads(configfile.read()) + for bridge, value in mbridges.items(): + print(bridge, value['user']) + if bridge not in self.mdiscovered: + bridge: HueBridge = HueBridge(bridge, value['user']) + bridge.connect() + self.mbridges.append(bridge) + self.mdiscovered.append(bridge) + + def write_all_bridges_to_conf(self): + with open(self.config, 'w') as configfile: + for bridge in self.mbridges: + configfile.write('["{}"]\nuser = "{}"\n'.format(bridge.ip, bridge.username)) diff --git a/tinge/__init__.py.bak b/tinge/__init__.py.bak new file mode 100644 index 0000000..eca6852 --- /dev/null +++ b/tinge/__init__.py.bak @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import os + +import time +import toml +import wx +import HueBridge +from upnpy import UPnP + + +def connect_new_bridge(ipaddress) -> Bridge: + bridge: Bridge = Bridge(ipaddress) + connected: bool = False + while not connected: + try: + bridge.register_app() + except Exception as mexception: # PhueRegistrationException as mexception: + print(mexception) + time.sleep(5) + else: + connected = True + bridge.connect() + return bridge + + + + + +class Hui(wx.Frame): + def __init__(self, *args, **kw): + super().__init__(*args, **kw) + self.bridges: list[Bridge] = list() + self.discovered: list[str] = list() + self.config = os.path.join(os.getenv('HOME'), '.tinge') + if is_valid_config(self.config): + self.get_bridges_from_file() + self.discover_new_bridges() + self.write_all_bridges_to_conf() + + + + +if __name__ == "__main__": + app = wx.App() + frm = Hui() + # frm.show() + app.MainLoop()