Fix for #5 Manually add bridge
This patch intruduces more robust handling of situations where a bridge can not be discovered by means of UPnP. A modal now pops up, which allows you to manually enter an ipaddress if no bridge can be discovered.
This commit is contained in:
parent
0a0e616c2d
commit
b23acb58d5
3 changed files with 55 additions and 18 deletions
28
main.py
28
main.py
|
@ -5,7 +5,7 @@ from typing import Union
|
|||
import wx
|
||||
import wx.lib.scrolledpanel as scrolled
|
||||
|
||||
from tinge import Tinge, HueBridge, HueGroup, HueLight, HueUtils
|
||||
from tinge import Tinge, HueBridge, HueGroup, HueLight, HueUtils, is_bridge
|
||||
|
||||
|
||||
class Hui(wx.Frame):
|
||||
|
@ -108,6 +108,29 @@ class Hui(wx.Frame):
|
|||
lambda event, mgroupid=groupid: self.goto_group(mgroupid), group_btn)
|
||||
self.sizer.Add(inner_sizer, 0, wx.EXPAND)
|
||||
|
||||
def add_manual_discovery_dialog(self) -> bool:
|
||||
self.sizer.Clear(delete_windows=True)
|
||||
found_any: bool = False
|
||||
text_entry: wx.TextEntryDialog = wx.TextEntryDialog(self.pnl, "Manually enter IP address of bridge:",
|
||||
caption="Auto discovery failure")
|
||||
warn_label: wx.StaticText = wx.StaticText(self.pnl, label="Waiting for Button Press on Bridge")
|
||||
if text_entry.ShowModal() == wx.ID_OK:
|
||||
ipaddress: str = text_entry.GetValue()
|
||||
if is_bridge(ipaddress):
|
||||
self.sizer.Add(warn_label, 0, wx.ALIGN_CENTER)
|
||||
self.sizer.Layout()
|
||||
user_or_error = HueUtils.connect(ipaddress)
|
||||
while user_or_error.is_error():
|
||||
user_or_error = HueUtils.connect(ipaddress)
|
||||
self.m_tinge.append_bridge(HueBridge(ipaddress, user_or_error.get_user(), ipaddress))
|
||||
found_any = True
|
||||
self.m_tinge.write_all_bridges_to_conf()
|
||||
else:
|
||||
label = "Supplied IP Address did not match a Bridge.",
|
||||
failure_msg: wx.GenericMessageDialog = wx.GenericMessageDialog(self.pnl, label, caption="Try again!")
|
||||
failure_msg.ShowModal()
|
||||
return found_any
|
||||
|
||||
@redraw
|
||||
def add_lights(self, lights: list[HueLight]):
|
||||
"""This will add the lights from a group to the sizer
|
||||
|
@ -245,6 +268,9 @@ class Hui(wx.Frame):
|
|||
found_any = True
|
||||
self.m_tinge.write_all_bridges_to_conf()
|
||||
self.add_bridges()
|
||||
else:
|
||||
found_any = self.add_manual_discovery_dialog()
|
||||
self.add_bridges()
|
||||
return found_any
|
||||
|
||||
def get_ok_cancel_answer_from_modal(self, message: str) -> bool:
|
||||
|
|
|
@ -47,6 +47,25 @@ def is_valid_config(filename: str) -> bool:
|
|||
return os.path.exists(filename) and os.path.getsize(filename) > 0
|
||||
|
||||
|
||||
def is_bridge(ipaddress: str):
|
||||
try:
|
||||
response = make_request(ipaddress, "1234/lights")
|
||||
discovered = False
|
||||
if response:
|
||||
resp = response.json()[0]
|
||||
if 'error' in resp.keys():
|
||||
m_keys = resp['error'].keys()
|
||||
if 'description' in m_keys and 'address' in m_keys and 'type' in m_keys:
|
||||
# This is kinda ugly but line is too long with and statement
|
||||
if resp['error']['description'] == "unauthorized user":
|
||||
if resp['error']['address'] == "/lights":
|
||||
if resp['error']['type'] == 1:
|
||||
discovered = True
|
||||
except simplejson.errors.JSONDecodeError:
|
||||
pass
|
||||
return discovered
|
||||
|
||||
|
||||
def make_request(ipaddress: str, path: str, method: str = "GET",
|
||||
body: str = '') -> Union[None, requests.Response]:
|
||||
"""Helper function to make an API call to the Hue API on the bridge
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import http
|
||||
import os
|
||||
from typing import Union
|
||||
|
||||
|
@ -8,7 +9,7 @@ import toml
|
|||
from upnpy import UPnP
|
||||
|
||||
from .HueBridge import HueBridge
|
||||
from .HueUtils import connect, is_valid_config, make_request
|
||||
from .HueUtils import connect, is_valid_config, make_request, is_bridge
|
||||
from .UserOrError import UserOrError
|
||||
|
||||
|
||||
|
@ -39,7 +40,12 @@ class Tinge:
|
|||
"""Use UPnP to discover bridges on the current network
|
||||
"""
|
||||
upnp: UPnP = UPnP()
|
||||
discovered_devices = upnp.discover()
|
||||
discovered_devices = list()
|
||||
try:
|
||||
discovered_devices = upnp.discover()
|
||||
except http.client.BadStatusLine:
|
||||
print("UPnP discovery failed")
|
||||
return None
|
||||
discovered_bridges: list[dict] = list()
|
||||
seen_ips: list[str] = list()
|
||||
if not discovered_devices:
|
||||
|
@ -54,21 +60,7 @@ class Tinge:
|
|||
discovered = True
|
||||
# If not we try to do a request against the api and see if we get an answer we can understand
|
||||
else:
|
||||
try:
|
||||
response = make_request(device.host, "1234/lights")
|
||||
if response:
|
||||
resp = response.json()[0]
|
||||
if 'error' in resp.keys():
|
||||
m_keys = resp['error'].keys()
|
||||
if 'description' in m_keys and 'address' in m_keys and 'type' in m_keys:
|
||||
# This is kinda ugly but line is too long with and statement
|
||||
if resp['error']['description'] == "unauthorized user":
|
||||
if resp['error']['address'] == "/lights":
|
||||
if resp['error']['type'] == 1:
|
||||
discovered = True
|
||||
except simplejson.errors.JSONDecodeError:
|
||||
pass
|
||||
|
||||
discovered = is_bridge(device.host)
|
||||
if discovered:
|
||||
bridge = {'ipaddress': device.host, 'name': device.get_friendly_name()}
|
||||
if bridge not in discovered_bridges:
|
||||
|
|
Loading…
Add table
Reference in a new issue