Skip to content

Commit

Permalink
Add HTTP protocol support to AsusWRT (home-assistant#95720)
Browse files Browse the repository at this point in the history
  • Loading branch information
ollo69 authored Nov 16, 2023
1 parent 654c4b6 commit b4797e2
Show file tree
Hide file tree
Showing 12 changed files with 666 additions and 131 deletions.
123 changes: 123 additions & 0 deletions homeassistant/components/asuswrt/bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from typing import Any, TypeVar, cast

from aioasuswrt.asuswrt import AsusWrt as AsusWrtLegacy
from aiohttp import ClientSession
from pyasuswrt import AsusWrtError, AsusWrtHttp

from homeassistant.const import (
CONF_HOST,
Expand All @@ -19,6 +21,7 @@
CONF_USERNAME,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.device_registry import format_mac
from homeassistant.helpers.update_coordinator import UpdateFailed

Expand All @@ -31,6 +34,8 @@
DEFAULT_INTERFACE,
KEY_METHOD,
KEY_SENSORS,
PROTOCOL_HTTP,
PROTOCOL_HTTPS,
PROTOCOL_TELNET,
SENSORS_BYTES,
SENSORS_LOAD_AVG,
Expand Down Expand Up @@ -74,6 +79,8 @@ async def _wrapper(self: _AsusWrtBridgeT) -> dict[str, Any]:
raise UpdateFailed("Received invalid data type")
return data

if isinstance(data, dict):
return dict(zip(keys, list(data.values())))
if not isinstance(data, list):
raise UpdateFailed("Received invalid data type")
return dict(zip(keys, data))
Expand All @@ -91,6 +98,9 @@ def get_bridge(
hass: HomeAssistant, conf: dict[str, Any], options: dict[str, Any] | None = None
) -> AsusWrtBridge:
"""Get Bridge instance."""
if conf[CONF_PROTOCOL] in (PROTOCOL_HTTPS, PROTOCOL_HTTP):
session = async_get_clientsession(hass)
return AsusWrtHttpBridge(conf, session)
return AsusWrtLegacyBridge(conf, options)

def __init__(self, host: str) -> None:
Expand Down Expand Up @@ -286,3 +296,116 @@ async def _get_load_avg(self) -> Any:
async def _get_temperatures(self) -> Any:
"""Fetch temperatures information from the router."""
return await self._api.async_get_temperature()


class AsusWrtHttpBridge(AsusWrtBridge):
"""The Bridge that use HTTP library."""

def __init__(self, conf: dict[str, Any], session: ClientSession) -> None:
"""Initialize Bridge that use HTTP library."""
super().__init__(conf[CONF_HOST])
self._api: AsusWrtHttp = self._get_api(conf, session)

@staticmethod
def _get_api(conf: dict[str, Any], session: ClientSession) -> AsusWrtHttp:
"""Get the AsusWrtHttp API."""
return AsusWrtHttp(
conf[CONF_HOST],
conf[CONF_USERNAME],
conf.get(CONF_PASSWORD, ""),
use_https=conf[CONF_PROTOCOL] == PROTOCOL_HTTPS,
port=conf.get(CONF_PORT),
session=session,
)

@property
def is_connected(self) -> bool:
"""Get connected status."""
return cast(bool, self._api.is_connected)

async def async_connect(self) -> None:
"""Connect to the device."""
await self._api.async_connect()

# get main router properties
if mac := self._api.mac:
self._label_mac = format_mac(mac)
self._firmware = self._api.firmware
self._model = self._api.model

async def async_disconnect(self) -> None:
"""Disconnect to the device."""
await self._api.async_disconnect()

async def async_get_connected_devices(self) -> dict[str, WrtDevice]:
"""Get list of connected devices."""
try:
api_devices = await self._api.async_get_connected_devices()
except AsusWrtError as exc:
raise UpdateFailed(exc) from exc
return {
format_mac(mac): WrtDevice(dev.ip, dev.name, dev.node)
for mac, dev in api_devices.items()
}

async def async_get_available_sensors(self) -> dict[str, dict[str, Any]]:
"""Return a dictionary of available sensors for this bridge."""
sensors_temperatures = await self._get_available_temperature_sensors()
sensors_types = {
SENSORS_TYPE_BYTES: {
KEY_SENSORS: SENSORS_BYTES,
KEY_METHOD: self._get_bytes,
},
SENSORS_TYPE_LOAD_AVG: {
KEY_SENSORS: SENSORS_LOAD_AVG,
KEY_METHOD: self._get_load_avg,
},
SENSORS_TYPE_RATES: {
KEY_SENSORS: SENSORS_RATES,
KEY_METHOD: self._get_rates,
},
SENSORS_TYPE_TEMPERATURES: {
KEY_SENSORS: sensors_temperatures,
KEY_METHOD: self._get_temperatures,
},
}
return sensors_types

async def _get_available_temperature_sensors(self) -> list[str]:
"""Check which temperature information is available on the router."""
try:
available_temps = await self._api.async_get_temperatures()
available_sensors = [
t for t in SENSORS_TEMPERATURES if t in available_temps
]
except AsusWrtError as exc:
_LOGGER.warning(
(
"Failed checking temperature sensor availability for ASUS router"
" %s. Exception: %s"
),
self.host,
exc,
)
return []
return available_sensors

@handle_errors_and_zip(AsusWrtError, SENSORS_BYTES)
async def _get_bytes(self) -> Any:
"""Fetch byte information from the router."""
return await self._api.async_get_traffic_bytes()

@handle_errors_and_zip(AsusWrtError, SENSORS_RATES)
async def _get_rates(self) -> Any:
"""Fetch rates information from the router."""
return await self._api.async_get_traffic_rates()

@handle_errors_and_zip(AsusWrtError, SENSORS_LOAD_AVG)
async def _get_load_avg(self) -> Any:
"""Fetch cpu load avg information from the router."""
return await self._api.async_get_loadavg()

@handle_errors_and_zip(AsusWrtError, None)
async def _get_temperatures(self) -> Any:
"""Fetch temperatures information from the router."""
return await self._api.async_get_temperatures()
Loading

0 comments on commit b4797e2

Please sign in to comment.