Skip to content

Commit

Permalink
0.33.0 (#859)
Browse files Browse the repository at this point in the history
Co-authored-by: GaryHuang-ASUS <164834485 [email protected]>
  • Loading branch information
Vaskivskyi and GaryHuang-ASUS authored Aug 28, 2024
1 parent 5363a55 commit 82dc41a
Show file tree
Hide file tree
Showing 12 changed files with 610 additions and 170 deletions.
196 changes: 103 additions & 93 deletions README.md

Large diffs are not rendered by default.

82 changes: 60 additions & 22 deletions custom_components/asusrouter/bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 7,18 @@
from typing import Any, Callable, Optional

import aiohttp
from homeassistant.const import (
CONF_HOST,
CONF_PASSWORD,
CONF_PORT,
CONF_SSL,
CONF_USERNAME,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.aiohttp_client import async_create_clientsession
from homeassistant.helpers.update_coordinator import UpdateFailed

from asusrouter import AsusRouter
from asusrouter.error import AsusRouterError
from asusrouter.modules.aimesh import AiMeshDevice
Expand All @@ -20,20 32,10 @@
)
from asusrouter.modules.identity import AsusDevice
from asusrouter.modules.parental_control import ParentalControlRule, PCRuleType
from homeassistant.const import (
CONF_HOST,
CONF_PASSWORD,
CONF_PORT,
CONF_SSL,
CONF_USERNAME,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.aiohttp_client import async_create_clientsession
from homeassistant.helpers.update_coordinator import UpdateFailed

from . import helpers
from .const import (
AURA,
BOOTTIME,
CONF_CACHE_TIME,
CONF_DEFAULT_CACHE_TIME,
Expand Down Expand Up @@ -66,6 68,8 @@
TEMPERATURE,
WLAN,
)
from .modules.aura import aura_to_ha
from .modules.firmware import to_ha as firmware_to_ha

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -100,7 104,9 @@ def __init__(
self._active: bool = False

@staticmethod
def _get_api(configs: dict[str, Any], session: aiohttp.ClientSession) -> AsusRouter:
def _get_api(
configs: dict[str, Any], session: aiohttp.ClientSession
) -> AsusRouter:
"""Get AsusRouter API."""

return AsusRouter(
Expand Down Expand Up @@ -169,14 175,18 @@ async def async_clean(self) -> None:
# <-- Connection
# --------------------

async def async_cleanup_sensors(self, sensors: dict[str, Any]) -> dict[str, Any]:
async def async_cleanup_sensors(
self, sensors: dict[str, Any]
) -> dict[str, Any]:
"""Cleanup sensors depending on the device mode."""

mode = self._configs.get(CONF_MODE, CONF_DEFAULT_MODE)
available = MODE_SENSORS[mode]
_LOGGER.debug("Available sensors for mode=`%s`: %s", mode, available)
sensors = {
group: details for group, details in sensors.items() if group in available
group: details
for group, details in sensors.items()
if group in available
}

return sensors
Expand All @@ -185,7 195,14 @@ async def async_get_available_sensors(self) -> dict[str, dict[str, Any]]:
"""Get available sensors."""

sensors = {
BOOTTIME: {SENSORS: SENSORS_BOOTTIME, METHOD: self._get_data_boottime},
AURA: {
SENSORS: await self._get_sensors_modern(AsusData.AURA),
METHOD: self._get_data_aura,
},
BOOTTIME: {
SENSORS: SENSORS_BOOTTIME,
METHOD: self._get_data_boottime,
},
CPU: {
SENSORS: await self._get_sensors_modern(AsusData.CPU),
METHOD: self._get_data_cpu,
Expand All @@ -207,7 224,9 @@ async def async_get_available_sensors(self) -> dict[str, dict[str, Any]]:
METHOD: self._get_data_network,
},
"ovpn_client": {
SENSORS: await self._get_sensors_modern(AsusData.OPENVPN_CLIENT),
SENSORS: await self._get_sensors_modern(
AsusData.OPENVPN_CLIENT
),
METHOD: self._get_data_ovpn_client,
},
"ovpn_server": {
Expand Down Expand Up @@ -240,11 259,15 @@ async def async_get_available_sensors(self) -> dict[str, dict[str, Any]]:
METHOD: self._get_data_wan,
},
"wireguard_client": {
SENSORS: await self._get_sensors_modern(AsusData.WIREGUARD_CLIENT),
SENSORS: await self._get_sensors_modern(
AsusData.WIREGUARD_CLIENT
),
METHOD: self._get_data_wireguard_client,
},
"wireguard_server": {
SENSORS: await self._get_sensors_modern(AsusData.WIREGUARD_SERVER),
SENSORS: await self._get_sensors_modern(
AsusData.WIREGUARD_SERVER
),
METHOD: self._get_data_wireguard_server,
},
WLAN: {
Expand Down Expand Up @@ -304,6 327,13 @@ async def async_get_clients(self) -> dict[str, AsusClient]:
return await self._get_data(AsusData.CLIENTS, force=True)

# Sensor-specific methods
async def _get_data_aura(self) -> dict[str, Any]:
"""Get Aura data from the device."""

data = await self._get_data_modern(AsusData.AURA)

return aura_to_ha(data)

async def _get_data_boottime(self) -> dict[str, Any]:
"""Get `boottime` data from the device."""

Expand All @@ -317,7 347,9 @@ async def _get_data_cpu(self) -> dict[str, Any]:
async def _get_data_firmware(self) -> dict[str, Any]:
"""Get firmware data from the device."""

return await self._get_data(AsusData.FIRMWARE)
data = await self._get_data_modern(AsusData.FIRMWARE)

return firmware_to_ha(data)

async def _get_data_gwlan(self) -> dict[str, Any]:
"""Get GWLAN data from the device."""
Expand Down Expand Up @@ -492,7 524,9 @@ async def _get_sensors(
"Raw `%s` sensors of type (%s): %s", datatype, type(data), data
)
sensors = (
process(data) if process is not None else self._process_sensors(data)
process(data)
if process is not None
else self._process_sensors(data)
)
_LOGGER.debug("Available `%s` sensors: %s", sensor_type, sensors)
except AsusRouterError as ex:
Expand All @@ -516,7 550,9 @@ async def _get_sensors_modern(self, datatype: AsusData) -> list[str]:
"Raw `%s` sensors of type (%s): %s", datatype, type(data), data
)
sensors = convert_to_ha_sensors_list(data)
_LOGGER.debug("Available `%s` sensors: %s", datatype.value, sensors)
_LOGGER.debug(
"Available `%s` sensors: %s", datatype.value, sensors
)
except AsusRouterError as ex:
if datatype.value in DEFAULT_SENSORS:
sensors = DEFAULT_SENSORS[datatype.value]
Expand Down Expand Up @@ -637,7 673,9 @@ async def async_pc_rule(self, **kwargs: Any) -> bool:
reg_value = entity_reg.async_get(entity)
if not isinstance(reg_value, er.RegistryEntry):
continue
capabilities: dict[str, Any] = helpers.as_dict(reg_value.capabilities)
capabilities: dict[str, Any] = helpers.as_dict(
reg_value.capabilities
)
devices.append(capabilities)

# Convert devices to rules
Expand Down
55 changes: 38 additions & 17 deletions custom_components/asusrouter/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 5,17 @@
from datetime import datetime, timezone
from typing import Any, Callable, Optional

from homeassistant.core import callback
from homeassistant.helpers.device_registry import format_mac

from asusrouter.modules.client import (
AsusClient,
AsusClientConnection,
AsusClientConnectionWlan,
AsusClientDescription,
)
from asusrouter.modules.connection import ConnectionState
from asusrouter.modules.homeassistant import (
convert_to_ha_state_bool,
convert_to_ha_string,
)
from homeassistant.core import callback
from homeassistant.helpers.device_registry import format_mac
from asusrouter.modules.connection import ConnectionState, ConnectionType
from asusrouter.modules.homeassistant import convert_to_ha_state_bool

from .helpers import clean_dict

Expand Down Expand Up @@ -49,6 47,9 @@ def __init__(

# Connection state
self._state: ConnectionState = ConnectionState.UNKNOWN
self._connection_type: ConnectionType = ConnectionType.DISCONNECTED
self._guest: bool = False
self._guest_id: int = 0

# Device last active
self._last_activity: Optional[datetime] = None
Expand All @@ -58,7 59,9 @@ def update(
self,
client_info: Optional[AsusClient] = None,
consider_home: int = 0,
event_call: Optional[Callable[[str, Optional[dict[str, Any]]], None]] = None,
event_call: Optional[
Callable[[str, Optional[dict[str, Any]]], None]
] = None,
):
"""Update client information."""

Expand All @@ -77,7 80,7 @@ def update(
# Connected state
state = client_info.state

self._identity = self.generate_identity()
self._identity = self.generate_identity(state)
self._extra_state_attributes = self.generate_extra_state_attributes()

# If is connected
Expand Down Expand Up @@ -111,7 114,9 @@ def update(
self.identity,
)

def generate_identity(self) -> dict[str, Any]:
def generate_identity(
self, state: Optional[ConnectionState]
) -> dict[str, Any]:
"""Generate client identity."""

identity: dict[str, Any] = {
Expand All @@ -121,22 126,32 @@ def generate_identity(self) -> dict[str, Any]:
}

if isinstance(self.connection, AsusClientConnection):
identity["connection_type"] = convert_to_ha_string(self.connection.type)
# Rewrite guest from last known state if needed
if state == ConnectionState.DISCONNECTED:
identity["guest"] = self._guest
identity["guest_id"] = self._guest_id
if self.connection.type != ConnectionType.DISCONNECTED:
self._connection_type = self.connection.type
identity["connection_type"] = self._connection_type
identity["node"] = (
format_mac(self.connection.node) if self.connection.node else None
format_mac(self.connection.node)
if self.connection.node
else None
)

if isinstance(self.connection, AsusClientConnectionWlan):
identity["guest"] = self.connection.guest
identity["guest_id"] = self.connection.guest_id
identity["guest"] = self._guest = self.connection.guest
identity["guest_id"] = self._guest_id = self.connection.guest_id
identity["connected"] = self.connection.since

return clean_dict(identity)

def generate_extra_state_attributes(self) -> dict[str, Any]:
"""Generate extra state attributes."""

attributes: dict[str, Any] = self._identity.copy() if self._identity else {}
attributes: dict[str, Any] = (
self._identity.copy() if self._identity else {}
)

attributes["last_activity"] = self._last_activity

Expand Down Expand Up @@ -165,7 180,9 @@ def state(self) -> Optional[bool]:
def ip_address(self) -> Optional[str]:
"""Return IP address."""

return self.connection.ip_address if self.connection is not None else None
return (
self.connection.ip_address if self.connection is not None else None
)

@property
def mac_address(self) -> str:
Expand All @@ -177,7 194,11 @@ def mac_address(self) -> str:
def name(self) -> Optional[str]:
"""Return name."""

return self.description.name if self.description is not None else self._name
return (
self.description.name
if self.description is not None
else self._name
)

@property
def extra_state_attributes(self) -> dict[str, Any]:
Expand Down
Loading

0 comments on commit 82dc41a

Please sign in to comment.