Browse Source

Initial structure

tags/0.0.1
Micke Nordin 5 months ago
parent
commit
a582539b41
Signed by: Micke Nordin <hej@mic.ke> GPG Key ID: 014B273D614BE877
5 changed files with 179 additions and 0 deletions
  1. 2
    0
      .gitignore
  2. 14
    0
      tinge/HueBridge/__init__.py
  3. 26
    0
      tinge/UserOrError/__init__.py
  4. 89
    0
      tinge/__init__.py
  5. 48
    0
      tinge/__init__.py.bak

+ 2
- 0
.gitignore View File

@@ -114,3 +114,5 @@ dmypy.json
114 114
 # Pyre type checker
115 115
 .pyre/
116 116
 
117
+# Pycharm
118
+.idea/

+ 14
- 0
tinge/HueBridge/__init__.py View File

@@ -0,0 +1,14 @@
1
+#!/usr/bin/env python3
2
+# -*- coding: utf-8 -*-
3
+
4
+
5
+class HueBridge():
6
+    def __init__(self, ipaddress: str, username: str):
7
+        self.mipaddress: str = ipaddress
8
+        self.musername: str = username
9
+
10
+    def get_ipaddress(self):
11
+        return self.mipaddress
12
+
13
+    def get_user(self):
14
+        return self.musername

+ 26
- 0
tinge/UserOrError/__init__.py View File

@@ -0,0 +1,26 @@
1
+#!/usr/bin/env python3
2
+# -*- coding: utf-8 -*-
3
+
4
+
5
+class UserOrError:
6
+    def __init__(self):
7
+        self.muser: str = str()
8
+        self.merror: bool = True
9
+        self.mcode: int = 0
10
+
11
+    def get_error_code(self) -> int:
12
+        return self.mcode
13
+
14
+    def get_user(self) -> str:
15
+        return self.muser
16
+
17
+    def is_error(self) -> bool:
18
+        return self.merror
19
+
20
+    def set_error(self, code: int):
21
+        self.merror = True
22
+        self.mcode = code
23
+
24
+    def set_user(self, username: str):
25
+        self.merror = False
26
+        self.muser = username

+ 89
- 0
tinge/__init__.py View File

@@ -0,0 +1,89 @@
1
+#!/usr/bin/env python3
2
+# -*- coding: utf-8 -*-
3
+import json
4
+import os
5
+import time
6
+import uuid
7
+
8
+import requests
9
+import toml
10
+from upnpy import UPnP
11
+
12
+import tinge
13
+
14
+
15
+def connect(ipaddress: str, appid: uuid.UUID = uuid.uuid4()) -> UserOrError:
16
+    user_or_error = UserOrError()
17
+    body: dict = json.loads('{"devicetype":"{}#{}"}'.format("tinge", appid))
18
+    path: str = "api"
19
+    method: str = "POST"
20
+    response: requests.Response = make_request(ipaddress, path, method, body)
21
+
22
+    data: dict = response.json()[0]
23
+    if 'error' in data.keys():
24
+        user_or_error.set_error(data['error']['type'])
25
+    elif 'success' in data.keys():
26
+        user_or_error.set_user(data['success']['username'])
27
+    else:
28
+        user_or_error.set_error(9999)
29
+    return user_or_error
30
+
31
+
32
+def is_valid_config(filename: str) -> bool:
33
+    return os.path.exists(filename) and os.path.getsize(filename) > 0
34
+
35
+
36
+def make_request(ipaddress: str, path: str, method: str = "GET",
37
+                 body: dict = json.loads('{}')) -> requests.Response:
38
+    rfunct = requests.get
39
+    url = "http://{}/{}".format(ipaddress, path)
40
+    if method == "PUT":
41
+        rfunct = requests.put
42
+    elif method == "POST":
43
+        rfunct = requests.post
44
+    elif method == "DELETE":
45
+        rfunct = requests.delete
46
+    response: requests.Response = requests.Response()
47
+    if body:
48
+        response = rfunct(url, data=body)
49
+    else:
50
+        response = rfunct(url)
51
+    return response
52
+
53
+
54
+class Tinge:
55
+    def __init__(self):
56
+        self.mbridges: list[HueBridge] = list()
57
+        self.mdiscovered: list[str] = list()
58
+
59
+    def discover_new_bridges(self):
60
+        upnp: UPnP = UPnP()
61
+        for device in upnp.discover():
62
+            if device.get_friendly_name().startswith("Philips hue") and device.host not in self.mdiscovered:
63
+                user_or_error: UserOrError = connect(device.host)
64
+                while user_or_error.is_error():
65
+                    if user_or_error.get_error_code() == 101:
66
+                        print("Please press the button on your Hue Bridge")
67
+                    time.sleep(5)
68
+                    user_or_error = connect(device.host)
69
+                bridge: HueBridge = HueBridge(device.host, user_or_error.get_user)
70
+
71
+                self.mbridges.append(bridge)
72
+                self.mdiscovered.append(device.host)
73
+
74
+    def get_bridges_from_file(self):
75
+        if is_valid_config(self.config):
76
+            with open(self.config, 'r') as configfile:
77
+                mbridges = toml.loads(configfile.read())
78
+                for bridge, value in mbridges.items():
79
+                    print(bridge, value['user'])
80
+                    if bridge not in self.mdiscovered:
81
+                        bridge: HueBridge = HueBridge(bridge, value['user'])
82
+                        bridge.connect()
83
+                        self.mbridges.append(bridge)
84
+                        self.mdiscovered.append(bridge)
85
+
86
+    def write_all_bridges_to_conf(self):
87
+        with open(self.config, 'w') as configfile:
88
+            for bridge in self.mbridges:
89
+                configfile.write('["{}"]\nuser = "{}"\n'.format(bridge.ip, bridge.username))

+ 48
- 0
tinge/__init__.py.bak View File

@@ -0,0 +1,48 @@
1
+#!/usr/bin/env python3
2
+# -*- coding: utf-8 -*-
3
+import os
4
+
5
+import time
6
+import toml
7
+import wx
8
+import HueBridge
9
+from upnpy import UPnP
10
+
11
+
12
+def connect_new_bridge(ipaddress) -> Bridge:
13
+    bridge: Bridge = Bridge(ipaddress)
14
+    connected: bool = False
15
+    while not connected:
16
+        try:
17
+            bridge.register_app()
18
+        except Exception as mexception: # PhueRegistrationException as mexception:
19
+            print(mexception)
20
+            time.sleep(5)
21
+        else:
22
+            connected = True
23
+    bridge.connect()
24
+    return bridge
25
+
26
+
27
+
28
+
29
+
30
+class Hui(wx.Frame):
31
+    def __init__(self, *args, **kw):
32
+        super().__init__(*args, **kw)
33
+        self.bridges: list[Bridge] = list()
34
+        self.discovered: list[str] = list()
35
+        self.config = os.path.join(os.getenv('HOME'), '.tinge')
36
+        if is_valid_config(self.config):
37
+            self.get_bridges_from_file()
38
+        self.discover_new_bridges()
39
+        self.write_all_bridges_to_conf()
40
+
41
+
42
+
43
+
44
+if __name__ == "__main__":
45
+    app = wx.App()
46
+    frm = Hui()
47
+    # frm.show()
48
+    app.MainLoop()

Loading…
Cancel
Save