193 lines
5.9 KiB
Python
193 lines
5.9 KiB
Python
"""AsusRouter entity module."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from asusrouter.modules.homeassistant import convert_to_ha_state_bool
|
|
from asusrouter.modules.state import AsusState
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
from homeassistant.helpers.update_coordinator import (
|
|
CoordinatorEntity,
|
|
DataUpdateCoordinator,
|
|
)
|
|
|
|
from .const import ASUSROUTER, COORDINATOR, DOMAIN
|
|
from .dataclass import (
|
|
ARBinaryDescription,
|
|
AREntityDescription,
|
|
ARSwitchDescription,
|
|
)
|
|
from .helpers import to_unique_id
|
|
from .router import ARDevice
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
async def async_setup_ar_entry( # noqa: PLR0913
|
|
hass: HomeAssistant,
|
|
config_entry: ConfigEntry,
|
|
async_add_entities: AddEntitiesCallback,
|
|
sensors: list[AREntityDescription],
|
|
sensor_class: type[AREntity],
|
|
hide: list[str] | None = None,
|
|
) -> None:
|
|
"""Set up AsusRouter entities."""
|
|
|
|
router: ARDevice = hass.data[DOMAIN][config_entry.entry_id][ASUSROUTER]
|
|
entities = []
|
|
|
|
if not hide:
|
|
hide = []
|
|
|
|
for sensor_data in router.sensor_coordinator.values():
|
|
coordinator = sensor_data[COORDINATOR]
|
|
for sensor_description in sensors:
|
|
try:
|
|
sensor_type = sensor_description.key_group
|
|
|
|
# Make sure extra state attributes are dict
|
|
if not sensor_description.extra_state_attributes:
|
|
sensor_description.extra_state_attributes = {}
|
|
|
|
if (
|
|
sensor_type in sensor_data
|
|
and sensor_description.key in sensor_data[sensor_type]
|
|
):
|
|
# Hide protected values
|
|
sensor_description.extra_state_attributes = {
|
|
key: value
|
|
for key, value in sensor_description.extra_state_attributes.items() # noqa: E501
|
|
if value not in hide
|
|
}
|
|
|
|
entities.append(
|
|
sensor_class(coordinator, router, sensor_description)
|
|
)
|
|
except Exception as ex: # noqa: BLE001
|
|
_LOGGER.warning(
|
|
"Got an exception when creating entities: %s. "
|
|
"Please, report this. Sensor description: %s",
|
|
ex,
|
|
sensor_description,
|
|
)
|
|
|
|
async_add_entities(entities)
|
|
|
|
|
|
class AREntity(CoordinatorEntity):
|
|
"""AsusRouter entity."""
|
|
|
|
def __init__(
|
|
self,
|
|
coordinator: DataUpdateCoordinator,
|
|
router: ARDevice,
|
|
description: AREntityDescription,
|
|
) -> None:
|
|
"""Initialize AsusRouter entity."""
|
|
|
|
super().__init__(coordinator)
|
|
self.router = router
|
|
self.api = router.bridge.api
|
|
self.coordinator = coordinator
|
|
|
|
self._attr_name = f"{router._conf_name} {description.name}"
|
|
self._attr_unique_id = to_unique_id(f"{router.mac}_{description.name}")
|
|
self._attr_device_info = router.device_info
|
|
self._attr_capability_attributes = description.capabilities
|
|
|
|
@property
|
|
def extra_state_attributes(self) -> dict[str, Any]:
|
|
"""Return extra state attributes."""
|
|
|
|
# Check if description is of the needed class
|
|
if not isinstance(self.entity_description, AREntityDescription):
|
|
return {}
|
|
|
|
description = self.entity_description
|
|
_attributes = description.extra_state_attributes
|
|
if not _attributes:
|
|
return {}
|
|
|
|
# Mask attributes
|
|
attrs_to_mask = self.router.sensor_filters.get(
|
|
(description.key_group, description.key),
|
|
[],
|
|
)
|
|
for attr in attrs_to_mask:
|
|
if attr in _attributes:
|
|
_attributes.pop(attr, None)
|
|
|
|
attributes = {}
|
|
|
|
for attr in _attributes:
|
|
if attr in self.coordinator.data:
|
|
attributes[_attributes[attr]] = self.coordinator.data[attr]
|
|
|
|
return dict(sorted(attributes.items())) or {}
|
|
|
|
|
|
class ARBinaryEntity(AREntity):
|
|
"""AsusRouter binary entity."""
|
|
|
|
def __init__(
|
|
self,
|
|
coordinator: DataUpdateCoordinator,
|
|
router: ARDevice,
|
|
description: AREntityDescription,
|
|
) -> None:
|
|
"""Initialize AsusRouter binary entity."""
|
|
|
|
super().__init__(coordinator, router, description)
|
|
if isinstance(description, ARBinaryDescription | ARSwitchDescription):
|
|
self._icon_onoff = bool(
|
|
description.icon_on and description.icon_off
|
|
)
|
|
|
|
@property
|
|
def is_on(self) -> bool | None:
|
|
"""Get the state."""
|
|
|
|
return convert_to_ha_state_bool(
|
|
self.coordinator.data.get(self.entity_description.key)
|
|
)
|
|
|
|
@property
|
|
def icon(self) -> str | None:
|
|
"""Get the icon."""
|
|
|
|
if (
|
|
isinstance(
|
|
self.entity_description,
|
|
ARBinaryDescription | ARSwitchDescription,
|
|
)
|
|
and self._icon_onoff
|
|
):
|
|
if self.is_on:
|
|
return self.entity_description.icon_on
|
|
return self.entity_description.icon_off
|
|
if self.entity_description.icon:
|
|
return self.entity_description.icon
|
|
return None
|
|
|
|
async def _set_state(
|
|
self,
|
|
state: AsusState,
|
|
expect_modify: bool = False,
|
|
**kwargs: Any,
|
|
) -> None:
|
|
"""Set switch state."""
|
|
try:
|
|
_LOGGER.debug("Setting state to %s", state)
|
|
result = await self.api.async_set_state(
|
|
state=state, expect_modify=expect_modify, **kwargs
|
|
)
|
|
await self.coordinator.async_request_refresh()
|
|
if not result:
|
|
_LOGGER.debug("State was not set!")
|
|
except Exception as ex: # noqa: BLE001
|
|
_LOGGER.error("Unable to set state with an exception: %s", ex)
|