Skip to content

Commit

Permalink
Fix bt_home_hub_5 device tracker (#15096)
Browse files Browse the repository at this point in the history
* Fix bt_home_hub_5 device tracker

Updated BT Home Hub 5 device tracker component to get it working again. The old parsing method of the DNS table has been broken for a while causing the component to fail to get connected devices. A new parsing method has been implemened and fixes all previous issues.

* Moved part of code to a published PyPi library

* Fixed Violations

* Fixed bugs in device tracker

* Moved API Specific Code to PyPi Repository

* Updated to fit requested changes, removed test as it is no longer valid and updated requirement_all.txt

* Update to fit style requirements and remove redundant code

* Removed Unnecessary Comment
  • Loading branch information
ahobsonsayers authored and MartinHjelmare committed Aug 6, 2018
1 parent ac4674f commit e4b2ae2
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 120 deletions.
85 changes: 18 additions & 67 deletions homeassistant/components/device_tracker/bt_home_hub_5.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,22 @@
https://home-assistant.io/components/device_tracker.bt_home_hub_5/
"""
import logging
import re
import xml.etree.ElementTree as ET
import json
from urllib.parse import unquote

import requests
import voluptuous as vol

import homeassistant.helpers.config_validation as cv
from homeassistant.components.device_tracker import (
DOMAIN, PLATFORM_SCHEMA, DeviceScanner)
from homeassistant.components.device_tracker import (DOMAIN, PLATFORM_SCHEMA,
DeviceScanner)
from homeassistant.const import CONF_HOST

REQUIREMENTS = ['bthomehub5-devicelist==0.1.1']

_LOGGER = logging.getLogger(__name__)
_MAC_REGEX = re.compile(r'(([0-9A-Fa-f]{1,2}\:){5}[0-9A-Fa-f]{1,2})')

CONF_DEFAULT_IP = '192.168.1.254'

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string
vol.Optional(CONF_HOST, default=CONF_DEFAULT_IP): cv.string,
})


Expand All @@ -38,90 +36,43 @@ class BTHomeHub5DeviceScanner(DeviceScanner):

def __init__(self, config):
"""Initialise the scanner."""
import bthomehub5_devicelist

_LOGGER.info("Initialising BT Home Hub 5")
self.host = config.get(CONF_HOST, '192.168.1.254')
self.host = config[CONF_HOST]
self.last_results = {}
self.url = 'http://{}/nonAuth/home_status.xml'.format(self.host)

# Test the router is accessible
data = _get_homehub_data(self.url)
data = bthomehub5_devicelist.get_devicelist(self.host)
self.success_init = data is not None

def scan_devices(self):
"""Scan for new devices and return a list with found device IDs."""
self._update_info()
self.update_info()

return (device for device in self.last_results)

def get_device_name(self, device):
"""Return the name of the given device or None if we don't know."""
# If not initialised and not already scanned and not found.
if device not in self.last_results:
self._update_info()
self.update_info()

if not self.last_results:
return None

return self.last_results.get(device)

def _update_info(self):
"""Ensure the information from the BT Home Hub 5 is up to date.
Return boolean if scanning successful.
"""
if not self.success_init:
return False
def update_info(self):
"""Ensure the information from the BT Home Hub 5 is up to date."""
import bthomehub5_devicelist

_LOGGER.info("Scanning")

data = _get_homehub_data(self.url)
data = bthomehub5_devicelist.get_devicelist(self.host)

if not data:
_LOGGER.warning("Error scanning devices")
return False
return

self.last_results = data

return True


def _get_homehub_data(url):
"""Retrieve data from BT Home Hub 5 and return parsed result."""
try:
response = requests.get(url, timeout=5)
except requests.exceptions.Timeout:
_LOGGER.exception("Connection to the router timed out")
return
if response.status_code == 200:
return _parse_homehub_response(response.text)
_LOGGER.error("Invalid response from Home Hub: %s", response)


def _parse_homehub_response(data_str):
"""Parse the BT Home Hub 5 data format."""
root = ET.fromstring(data_str)

dirty_json = root.find('known_device_list').get('value')

# Normalise the JavaScript data to JSON.
clean_json = unquote(dirty_json.replace('\'', '\"')
.replace('{', '{\"')
.replace(':\"', '\":\"')
.replace('\",', '\",\"'))

known_devices = [x for x in json.loads(clean_json) if x]

devices = {}

for device in known_devices:
name = device.get('name')
mac = device.get('mac')

if _MAC_REGEX.match(mac) or ',' in mac:
for mac_addr in mac.split(','):
if _MAC_REGEX.match(mac_addr):
devices[mac_addr] = name
else:
devices[mac] = name

return devices
3 changes: 3 additions & 0 deletions requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ brunt==0.1.2
# homeassistant.components.device_tracker.bluetooth_tracker
bt_proximity==0.1.2

# homeassistant.components.device_tracker.bt_home_hub_5
bthomehub5-devicelist==0.1.1

# homeassistant.components.sensor.buienradar
# homeassistant.components.weather.buienradar
buienradar==0.91
Expand Down
53 changes: 0 additions & 53 deletions tests/components/device_tracker/test_bt_home_hub_5.py

This file was deleted.

0 comments on commit e4b2ae2

Please sign in to comment.