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.
Micke Nordin 3 years ago committed by Micke Nordin
parent 0a0e616c2d
commit c7934e973b
Signed by: micke
GPG Key ID: 014B273D614BE877

@ -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…
Cancel
Save