Add upload and download sensors and component for asuswrt (#17757)

* Adds upload and download sensors for asuswrt and makes it a component.

* Rebase

* removes warnings

* Fixing review issues

* More robust connection phase

* Generate dependencies

* Not needed try catch

* Rename sensors

* Revorked tests so they can be turned on again

* Using component setup

* Test through correct setup

* Forgot we dont need to worry about older py
This commit is contained in:
kennedyshead
2018-11-07 18:32:13 +01:00
committed by Martin Hjelmare
parent d93716bd84
commit aa4da479b5
5 changed files with 252 additions and 42 deletions

View File

@ -0,0 +1,68 @@
"""
Support for ASUSWRT devices.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/asuswrt/
"""
import logging
import voluptuous as vol
from homeassistant.const import (
CONF_HOST, CONF_PASSWORD, CONF_USERNAME, CONF_PORT, CONF_MODE,
CONF_PROTOCOL)
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.discovery import async_load_platform
REQUIREMENTS = ['aioasuswrt==1.1.4']
_LOGGER = logging.getLogger(__name__)
DOMAIN = "asuswrt"
DATA_ASUSWRT = DOMAIN
CONF_PUB_KEY = 'pub_key'
CONF_SSH_KEY = 'ssh_key'
CONF_REQUIRE_IP = 'require_ip'
DEFAULT_SSH_PORT = 22
SECRET_GROUP = 'Password or SSH Key'
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_USERNAME): cv.string,
vol.Optional(CONF_PROTOCOL, default='ssh'): vol.In(['ssh', 'telnet']),
vol.Optional(CONF_MODE, default='router'): vol.In(['router', 'ap']),
vol.Optional(CONF_PORT, default=DEFAULT_SSH_PORT): cv.port,
vol.Optional(CONF_REQUIRE_IP, default=True): cv.boolean,
vol.Exclusive(CONF_PASSWORD, SECRET_GROUP): cv.string,
vol.Exclusive(CONF_SSH_KEY, SECRET_GROUP): cv.isfile,
vol.Exclusive(CONF_PUB_KEY, SECRET_GROUP): cv.isfile
}),
}, extra=vol.ALLOW_EXTRA)
async def async_setup(hass, config):
"""Set up the asuswrt component."""
from aioasuswrt.asuswrt import AsusWrt
conf = config[DOMAIN]
api = AsusWrt(conf[CONF_HOST], conf.get(CONF_PORT),
conf.get(CONF_PROTOCOL) == 'telnet',
conf[CONF_USERNAME],
conf.get(CONF_PASSWORD, ''),
conf.get('ssh_key', conf.get('pub_key', '')),
conf.get(CONF_MODE), conf.get(CONF_REQUIRE_IP))
await api.connection.async_connect()
if not api.is_connected:
_LOGGER.error("Unable to setup asuswrt component")
return False
hass.data[DATA_ASUSWRT] = api
hass.async_create_task(async_load_platform(
hass, 'sensor', DOMAIN, {}, config))
hass.async_create_task(async_load_platform(
hass, 'device_tracker', DOMAIN, {}, config))
return True

View File

@ -6,43 +6,17 @@ https://home-assistant.io/components/device_tracker.asuswrt/
"""
import logging
import voluptuous as vol
from homeassistant.components.asuswrt import DATA_ASUSWRT
from homeassistant.components.device_tracker import DeviceScanner
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, CONF_PORT, CONF_MODE,
CONF_PROTOCOL)
REQUIREMENTS = ['aioasuswrt==1.1.2']
DEPENDENCIES = ['asuswrt']
_LOGGER = logging.getLogger(__name__)
CONF_PUB_KEY = 'pub_key'
CONF_SSH_KEY = 'ssh_key'
CONF_REQUIRE_IP = 'require_ip'
DEFAULT_SSH_PORT = 22
SECRET_GROUP = 'Password or SSH Key'
PLATFORM_SCHEMA = vol.All(
cv.has_at_least_one_key(CONF_PASSWORD, CONF_PUB_KEY, CONF_SSH_KEY),
PLATFORM_SCHEMA.extend({
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_USERNAME): cv.string,
vol.Optional(CONF_PROTOCOL, default='ssh'): vol.In(['ssh', 'telnet']),
vol.Optional(CONF_MODE, default='router'): vol.In(['router', 'ap']),
vol.Optional(CONF_PORT, default=DEFAULT_SSH_PORT): cv.port,
vol.Optional(CONF_REQUIRE_IP, default=True): cv.boolean,
vol.Exclusive(CONF_PASSWORD, SECRET_GROUP): cv.string,
vol.Exclusive(CONF_SSH_KEY, SECRET_GROUP): cv.isfile,
vol.Exclusive(CONF_PUB_KEY, SECRET_GROUP): cv.isfile
}))
async def async_get_scanner(hass, config):
"""Validate the configuration and return an ASUS-WRT scanner."""
scanner = AsusWrtDeviceScanner(config[DOMAIN])
scanner = AsusWrtDeviceScanner(hass.data[DATA_ASUSWRT])
await scanner.async_connect()
return scanner if scanner.success_init else None
@ -51,19 +25,11 @@ class AsusWrtDeviceScanner(DeviceScanner):
"""This class queries a router running ASUSWRT firmware."""
# Eighth attribute needed for mode (AP mode vs router mode)
def __init__(self, config):
def __init__(self, api):
"""Initialize the scanner."""
from aioasuswrt.asuswrt import AsusWrt
self.last_results = {}
self.success_init = False
self.connection = AsusWrt(config[CONF_HOST], config[CONF_PORT],
config[CONF_PROTOCOL] == 'telnet',
config[CONF_USERNAME],
config.get(CONF_PASSWORD, ''),
config.get('ssh_key',
config.get('pub_key', '')),
config[CONF_MODE], config[CONF_REQUIRE_IP])
self.connection = api
async def async_connect(self):
"""Initialize connection to the router."""

View File

@ -0,0 +1,126 @@
"""
Asuswrt status sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.asuswrt/
"""
import logging
from homeassistant.helpers.entity import Entity
from homeassistant.components.asuswrt import DATA_ASUSWRT
DEPENDENCIES = ['asuswrt']
_LOGGER = logging.getLogger(__name__)
async def async_setup_platform(
hass, config, add_entities, discovery_info=None):
"""Set up the asuswrt sensors."""
api = hass.data[DATA_ASUSWRT]
add_entities([
AsuswrtRXSensor(api),
AsuswrtTXSensor(api),
AsuswrtTotalRXSensor(api),
AsuswrtTotalTXSensor(api)
])
class AsuswrtSensor(Entity):
"""Representation of a asuswrt sensor."""
_name = 'generic'
def __init__(self, api):
"""Initialize the sensor."""
self._api = api
self._state = None
self._rates = None
self._speed = None
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def state(self):
"""Return the state of the sensor."""
return self._state
async def async_update(self):
"""Fetch status from asuswrt."""
self._rates = await self._api.async_get_packets_total()
self._speed = await self._api.async_get_current_transfer_rates()
class AsuswrtRXSensor(AsuswrtSensor):
"""Representation of a asuswrt download speed sensor."""
_name = 'Asuswrt Download Speed'
_unit = 'Mbit/s'
@property
def unit_of_measurement(self):
"""Return the unit of measurement."""
return self._unit
async def async_update(self):
"""Fetch new state data for the sensor."""
await super().async_update()
if self._speed is not None:
self._state = round(self._speed[0] / 125000, 2)
class AsuswrtTXSensor(AsuswrtSensor):
"""Representation of a asuswrt upload speed sensor."""
_name = 'Asuswrt Upload Speed'
_unit = 'Mbit/s'
@property
def unit_of_measurement(self):
"""Return the unit of measurement."""
return self._unit
async def async_update(self):
"""Fetch new state data for the sensor."""
await super().async_update()
if self._speed is not None:
self._state = round(self._speed[1] / 125000, 2)
class AsuswrtTotalRXSensor(AsuswrtSensor):
"""Representation of a asuswrt total download sensor."""
_name = 'Asuswrt Download'
_unit = 'Gigabyte'
@property
def unit_of_measurement(self):
"""Return the unit of measurement."""
return self._unit
async def async_update(self):
"""Fetch new state data for the sensor."""
await super().async_update()
if self._rates is not None:
self._state = round(self._rates[0] / 1000000000, 1)
class AsuswrtTotalTXSensor(AsuswrtSensor):
"""Representation of a asuswrt total upload sensor."""
_name = 'Asuswrt Upload'
_unit = 'Gigabyte'
@property
def unit_of_measurement(self):
"""Return the unit of measurement."""
return self._unit
async def async_update(self):
"""Fetch new state data for the sensor."""
await super().async_update()
if self._rates is not None:
self._state = round(self._rates[1] / 1000000000, 1)

View File

@ -85,8 +85,8 @@ abodepy==0.14.0
# homeassistant.components.media_player.frontier_silicon
afsapi==0.0.4
# homeassistant.components.device_tracker.asuswrt
aioasuswrt==1.1.2
# homeassistant.components.asuswrt
aioasuswrt==1.1.4
# homeassistant.components.device_tracker.automatic
aioautomatic==0.6.5

View File

@ -0,0 +1,50 @@
"""The tests for the ASUSWRT device tracker platform."""
from homeassistant.setup import async_setup_component
from homeassistant.components.asuswrt import (
CONF_PROTOCOL, CONF_MODE, DOMAIN, CONF_PORT, DATA_ASUSWRT)
from homeassistant.const import (CONF_PLATFORM, CONF_PASSWORD, CONF_USERNAME,
CONF_HOST)
from tests.common import MockDependency, mock_coro_func
FAKEFILE = None
VALID_CONFIG_ROUTER_SSH = {DOMAIN: {
CONF_PLATFORM: 'asuswrt',
CONF_HOST: 'fake_host',
CONF_USERNAME: 'fake_user',
CONF_PROTOCOL: 'ssh',
CONF_MODE: 'router',
CONF_PORT: '22'
}}
async def test_password_or_pub_key_required(hass):
"""Test creating an AsusWRT scanner without a pass or pubkey."""
with MockDependency('aioasuswrt.asuswrt')as mocked_asus:
mocked_asus.AsusWrt().connection.async_connect = mock_coro_func()
mocked_asus.AsusWrt().is_connected = False
result = await async_setup_component(
hass, DOMAIN, {DOMAIN: {
CONF_HOST: 'fake_host',
CONF_USERNAME: 'fake_user'
}})
assert not result
async def test_get_scanner_with_password_no_pubkey(hass):
"""Test creating an AsusWRT scanner with a password and no pubkey."""
with MockDependency('aioasuswrt.asuswrt')as mocked_asus:
mocked_asus.AsusWrt().connection.async_connect = mock_coro_func()
mocked_asus.AsusWrt(
).connection.async_get_connected_devices = mock_coro_func(
return_value={})
result = await async_setup_component(
hass, DOMAIN, {DOMAIN: {
CONF_HOST: 'fake_host',
CONF_USERNAME: 'fake_user',
CONF_PASSWORD: '4321'
}})
assert result
assert hass.data[DATA_ASUSWRT] is not None