mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Support presence detection using Hitron Coda router (#9682)
* Support presence detection using Hitron Coda router * at least 2 spaces before inline comment * Update hitron_coda.py * rewrote authentication code, it actually works now * make line slightly shorter to comply with hound * Removed hardcoded IP address * Fix string formatting, add timeout, and use generator * Update hitron_coda.py * Update hitron_coda.py * Update hitron_coda.py * typo * update .coveragerc * Update stale URL
This commit is contained in:
parent
3c135deec8
commit
2dcde12d38
@ -309,6 +309,7 @@ omit =
|
||||
homeassistant/components/device_tracker/cisco_ios.py
|
||||
homeassistant/components/device_tracker/fritz.py
|
||||
homeassistant/components/device_tracker/gpslogger.py
|
||||
homeassistant/components/device_tracker/hitron_coda.py
|
||||
homeassistant/components/device_tracker/huawei_router.py
|
||||
homeassistant/components/device_tracker/icloud.py
|
||||
homeassistant/components/device_tracker/keenetic_ndms2.py
|
||||
|
138
homeassistant/components/device_tracker/hitron_coda.py
Normal file
138
homeassistant/components/device_tracker/hitron_coda.py
Normal file
@ -0,0 +1,138 @@
|
||||
"""
|
||||
Support for the Hitron CODA-4582U, provided by Rogers.
|
||||
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/device_tracker.hitron_coda/
|
||||
"""
|
||||
import logging
|
||||
from collections import namedtuple
|
||||
|
||||
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.const import (
|
||||
CONF_HOST, CONF_PASSWORD, CONF_USERNAME
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_HOST): cv.string,
|
||||
vol.Required(CONF_USERNAME): cv.string,
|
||||
vol.Required(CONF_PASSWORD): cv.string
|
||||
})
|
||||
|
||||
|
||||
def get_scanner(_hass, config):
|
||||
"""Validate the configuration and return a Nmap scanner."""
|
||||
scanner = HitronCODADeviceScanner(config[DOMAIN])
|
||||
|
||||
return scanner if scanner.success_init else None
|
||||
|
||||
|
||||
Device = namedtuple('Device', ['mac', 'name'])
|
||||
|
||||
|
||||
class HitronCODADeviceScanner(DeviceScanner):
|
||||
"""This class scans for devices using the CODA's web interface."""
|
||||
|
||||
def __init__(self, config):
|
||||
"""Initialize the scanner."""
|
||||
self.last_results = []
|
||||
host = config[CONF_HOST]
|
||||
self._url = 'http://{}/data/getConnectInfo.asp'.format(host)
|
||||
self._loginurl = 'http://{}/goform/login'.format(host)
|
||||
|
||||
self._username = config.get(CONF_USERNAME)
|
||||
self._password = config.get(CONF_PASSWORD)
|
||||
|
||||
self._userid = None
|
||||
|
||||
self.success_init = self._update_info()
|
||||
_LOGGER.info("Scanner initialized")
|
||||
|
||||
def scan_devices(self):
|
||||
"""Scan for new devices and return a list with found device IDs."""
|
||||
self._update_info()
|
||||
|
||||
return [device.mac for device in self.last_results]
|
||||
|
||||
def get_device_name(self, mac):
|
||||
"""Return the name of the device with the given MAC address."""
|
||||
name = next((
|
||||
device.name for device in self.last_results
|
||||
if device.mac == mac), None)
|
||||
return name
|
||||
|
||||
def _login(self):
|
||||
"""Log in to the router. This is required for subsequent api calls."""
|
||||
_LOGGER.info("Logging in to CODA...")
|
||||
|
||||
try:
|
||||
data = [
|
||||
('user', self._username),
|
||||
('pws', self._password),
|
||||
]
|
||||
res = requests.post(self._loginurl, data=data, timeout=10)
|
||||
except requests.exceptions.Timeout:
|
||||
_LOGGER.error(
|
||||
"Connection to the router timed out at URL %s", self._url)
|
||||
return False
|
||||
if res.status_code != 200:
|
||||
_LOGGER.error(
|
||||
"Connection failed with http code %s", res.status_code)
|
||||
return False
|
||||
try:
|
||||
self._userid = res.cookies['userid']
|
||||
return True
|
||||
except KeyError:
|
||||
_LOGGER.error("Failed to log in to router")
|
||||
return False
|
||||
|
||||
def _update_info(self):
|
||||
"""Get ARP from router."""
|
||||
_LOGGER.info("Fetching...")
|
||||
|
||||
if self._userid is None:
|
||||
if not self._login():
|
||||
_LOGGER.error("Could not obtain a user ID from the router")
|
||||
return False
|
||||
last_results = []
|
||||
|
||||
# doing a request
|
||||
try:
|
||||
res = requests.get(self._url, timeout=10, cookies={
|
||||
'userid': self._userid
|
||||
})
|
||||
except requests.exceptions.Timeout:
|
||||
_LOGGER.error(
|
||||
"Connection to the router timed out at URL %s", self._url)
|
||||
return False
|
||||
if res.status_code != 200:
|
||||
_LOGGER.error(
|
||||
"Connection failed with http code %s", res.status_code)
|
||||
return False
|
||||
try:
|
||||
result = res.json()
|
||||
except ValueError:
|
||||
# If json decoder could not parse the response
|
||||
_LOGGER.error("Failed to parse response from router")
|
||||
return False
|
||||
|
||||
# parsing response
|
||||
for info in result:
|
||||
mac = info['macAddr']
|
||||
name = info['hostName']
|
||||
# No address = no item :)
|
||||
if mac is None:
|
||||
continue
|
||||
|
||||
last_results.append(Device(mac.upper(), name))
|
||||
|
||||
self.last_results = last_results
|
||||
|
||||
_LOGGER.info("Request successful")
|
||||
return True
|
Loading…
x
Reference in New Issue
Block a user