mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 21:57:51 +00:00
ASUSWRT Autodetect protocol (#2300)
This commit is contained in:
parent
39913075f4
commit
38030fcfca
@ -6,8 +6,10 @@ https://home-assistant.io/components/device_tracker.asuswrt/
|
|||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
import socket
|
||||||
import telnetlib
|
import telnetlib
|
||||||
import threading
|
import threading
|
||||||
|
from collections import namedtuple
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
from homeassistant.components.device_tracker import DOMAIN
|
from homeassistant.components.device_tracker import DOMAIN
|
||||||
@ -68,6 +70,8 @@ def get_scanner(hass, config):
|
|||||||
|
|
||||||
return scanner if scanner.success_init else None
|
return scanner if scanner.success_init else None
|
||||||
|
|
||||||
|
AsusWrtResult = namedtuple('AsusWrtResult', 'neighbors leases arp')
|
||||||
|
|
||||||
|
|
||||||
class AsusWrtDeviceScanner(object):
|
class AsusWrtDeviceScanner(object):
|
||||||
"""This class queries a router running ASUSWRT firmware."""
|
"""This class queries a router running ASUSWRT firmware."""
|
||||||
@ -130,7 +134,7 @@ class AsusWrtDeviceScanner(object):
|
|||||||
|
|
||||||
def ssh_connection(self):
|
def ssh_connection(self):
|
||||||
"""Retrieve data from ASUSWRT via the ssh protocol."""
|
"""Retrieve data from ASUSWRT via the ssh protocol."""
|
||||||
from pexpect import pxssh
|
from pexpect import pxssh, exceptions
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ssh = pxssh.pxssh()
|
ssh = pxssh.pxssh()
|
||||||
@ -140,7 +144,7 @@ class AsusWrtDeviceScanner(object):
|
|||||||
ssh.login(self.host, self.username, self.password)
|
ssh.login(self.host, self.username, self.password)
|
||||||
else:
|
else:
|
||||||
_LOGGER.error('No password or public key specified')
|
_LOGGER.error('No password or public key specified')
|
||||||
return('', '', '')
|
return None
|
||||||
ssh.sendline(_IP_NEIGH_CMD)
|
ssh.sendline(_IP_NEIGH_CMD)
|
||||||
ssh.prompt()
|
ssh.prompt()
|
||||||
neighbors = ssh.before.split(b'\n')[1:-1]
|
neighbors = ssh.before.split(b'\n')[1:-1]
|
||||||
@ -157,10 +161,13 @@ class AsusWrtDeviceScanner(object):
|
|||||||
ssh.prompt()
|
ssh.prompt()
|
||||||
leases_result = ssh.before.split(b'\n')[1:-1]
|
leases_result = ssh.before.split(b'\n')[1:-1]
|
||||||
ssh.logout()
|
ssh.logout()
|
||||||
return (neighbors, leases_result, arp_result)
|
return AsusWrtResult(neighbors, leases_result, arp_result)
|
||||||
except pxssh.ExceptionPxssh as exc:
|
except pxssh.ExceptionPxssh as exc:
|
||||||
_LOGGER.exception('Unexpected response from router: %s', exc)
|
_LOGGER.error('Unexpected response from router: %s', exc)
|
||||||
return ('', '', '')
|
return None
|
||||||
|
except exceptions.EOF:
|
||||||
|
_LOGGER.error('Connection refused or no route to host')
|
||||||
|
return None
|
||||||
|
|
||||||
def telnet_connection(self):
|
def telnet_connection(self):
|
||||||
"""Retrieve data from ASUSWRT via the telnet protocol."""
|
"""Retrieve data from ASUSWRT via the telnet protocol."""
|
||||||
@ -186,25 +193,42 @@ class AsusWrtDeviceScanner(object):
|
|||||||
leases_result = (telnet.read_until(prompt_string).
|
leases_result = (telnet.read_until(prompt_string).
|
||||||
split(b'\n')[1:-1])
|
split(b'\n')[1:-1])
|
||||||
telnet.write('exit\n'.encode('ascii'))
|
telnet.write('exit\n'.encode('ascii'))
|
||||||
return (neighbors, leases_result, arp_result)
|
return AsusWrtResult(neighbors, leases_result, arp_result)
|
||||||
except EOFError:
|
except EOFError:
|
||||||
_LOGGER.exception("Unexpected response from router")
|
_LOGGER.error("Unexpected response from router")
|
||||||
return ('', '', '')
|
return None
|
||||||
except ConnectionRefusedError:
|
except ConnectionRefusedError:
|
||||||
_LOGGER.exception("Connection refused by router,"
|
_LOGGER.error("Connection refused by router, is telnet enabled?")
|
||||||
" is telnet enabled?")
|
return None
|
||||||
return ('', '', '')
|
except socket.gaierror as exc:
|
||||||
|
_LOGGER.error("Socket exception: %s", exc)
|
||||||
|
return None
|
||||||
|
except OSError as exc:
|
||||||
|
_LOGGER.error("OSError: %s", exc)
|
||||||
|
return None
|
||||||
|
|
||||||
def get_asuswrt_data(self):
|
def get_asuswrt_data(self):
|
||||||
"""Retrieve data from ASUSWRT and return parsed result."""
|
"""Retrieve data from ASUSWRT and return parsed result."""
|
||||||
if self.protocol == 'telnet':
|
if self.protocol == 'ssh':
|
||||||
neighbors, leases_result, arp_result = self.telnet_connection()
|
result = self.ssh_connection()
|
||||||
|
elif self.protocol == 'telnet':
|
||||||
|
result = self.telnet_connection()
|
||||||
else:
|
else:
|
||||||
neighbors, leases_result, arp_result = self.ssh_connection()
|
# autodetect protocol
|
||||||
|
result = self.ssh_connection()
|
||||||
|
if result:
|
||||||
|
self.protocol = 'ssh'
|
||||||
|
else:
|
||||||
|
result = self.telnet_connection()
|
||||||
|
if result:
|
||||||
|
self.protocol = 'telnet'
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
return {}
|
||||||
|
|
||||||
devices = {}
|
devices = {}
|
||||||
if self.mode == 'ap':
|
if self.mode == 'ap':
|
||||||
for lease in leases_result:
|
for lease in result.leases:
|
||||||
match = _WL_REGEX.search(lease.decode('utf-8'))
|
match = _WL_REGEX.search(lease.decode('utf-8'))
|
||||||
|
|
||||||
if not match:
|
if not match:
|
||||||
@ -214,7 +238,7 @@ class AsusWrtDeviceScanner(object):
|
|||||||
host = ''
|
host = ''
|
||||||
|
|
||||||
# match mac addresses to IP addresses in ARP table
|
# match mac addresses to IP addresses in ARP table
|
||||||
for arp in arp_result:
|
for arp in result.arp:
|
||||||
if match.group('mac').lower() in arp.decode('utf-8'):
|
if match.group('mac').lower() in arp.decode('utf-8'):
|
||||||
arp_match = _ARP_REGEX.search(arp.decode('utf-8'))
|
arp_match = _ARP_REGEX.search(arp.decode('utf-8'))
|
||||||
if not arp_match:
|
if not arp_match:
|
||||||
@ -228,7 +252,7 @@ class AsusWrtDeviceScanner(object):
|
|||||||
'mac': match.group('mac').upper(),
|
'mac': match.group('mac').upper(),
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
for lease in leases_result:
|
for lease in result.leases:
|
||||||
match = _LEASES_REGEX.search(lease.decode('utf-8'))
|
match = _LEASES_REGEX.search(lease.decode('utf-8'))
|
||||||
|
|
||||||
if not match:
|
if not match:
|
||||||
@ -248,7 +272,7 @@ class AsusWrtDeviceScanner(object):
|
|||||||
'mac': match.group('mac').upper(),
|
'mac': match.group('mac').upper(),
|
||||||
}
|
}
|
||||||
|
|
||||||
for neighbor in neighbors:
|
for neighbor in result.neighbors:
|
||||||
match = _IP_NEIGH_REGEX.search(neighbor.decode('utf-8'))
|
match = _IP_NEIGH_REGEX.search(neighbor.decode('utf-8'))
|
||||||
if not match:
|
if not match:
|
||||||
_LOGGER.warning("Could not parse neighbor row: %s", neighbor)
|
_LOGGER.warning("Could not parse neighbor row: %s", neighbor)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user