Skip to content

Commit

Permalink
Add sensors , buttons , device_tracker
Browse files Browse the repository at this point in the history
  • Loading branch information
cyr-ius committed Aug 24, 2023
1 parent 9e18291 commit c54f600
Show file tree
Hide file tree
Showing 9 changed files with 199 additions and 77 deletions.
2 changes: 1 addition & 1 deletion custom_components/bbox2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from .coordinator import BboxDataUpdateCoordinator
from .const import DOMAIN

PLATFORMS: list[Platform] = [Platform.SENSOR, Platform.BINARY_SENSOR, Platform.DEVICE_TRACKER]
PLATFORMS: list[Platform] = [Platform.SENSOR, Platform.BINARY_SENSOR, Platform.DEVICE_TRACKER, Platform.BUTTON]


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
Expand Down
40 changes: 17 additions & 23 deletions custom_components/bbox2/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"""Support for Bbox binary sensors."""
from __future__ import annotations

import logging

from homeassistant.components.binary_sensor import (
BinarySensorEntityDescription,
BinarySensorDeviceClass,
BinarySensorEntity,
)
from homeassistant.config_entries import ConfigEntry
Expand All @@ -11,27 +13,16 @@

from .const import DOMAIN
from .entity import BboxEntity
from .helpers import BboxBinarySensorDescription, finditem

SENSOR_TYPES: tuple[BinarySensorEntityDescription, ...] = (
BinarySensorEntityDescription(
key="ipv4",
name="IPV4 Enabled",
),
BinarySensorEntityDescription(
key="ipv6",
name="IPV6 Enabled",
),
BinarySensorEntityDescription(
key="ftth",
name="FTTH enabled",
),
BinarySensorEntityDescription(
key="adsl",
name="Adsl",
),
BinarySensorEntityDescription(
key="vdsl",
name="Vdsl",
_LOGGER = logging.getLogger(__name__)

SENSOR_TYPES: tuple[BboxBinarySensorDescription, ...] = (
BboxBinarySensorDescription(
key="info.device.status",
name="Link status",
device_class=BinarySensorDeviceClass.CONNECTIVITY,
value_fn=lambda x: x == 1,
),
)

Expand All @@ -55,5 +46,8 @@ class BboxBinarySensor(BboxEntity, BinarySensorEntity):
@property
def is_on(self):
"""Return sensor state."""
device = self.coordinator.data.get("info", {}).get("device", {})
return device[self.entity_description.key] == 1
_LOGGER.debug("%s %s", self.name, self.entity_description.key)
data = finditem(self.coordinator.data, self.entity_description)
if self.entity_description.value_fn is not None:
return self.entity_description.value_fn(data)
return data
36 changes: 36 additions & 0 deletions custom_components/bbox2/button.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Button for Bbox router."""
import logging

from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from bboxpy.exceptions import BboxException
from .const import DOMAIN
from .entity import BboxEntity

_LOGGER = logging.getLogger(__name__)

BUTTON_RESTART: tuple[ButtonEntityDescription, ...] = ButtonEntityDescription(
key="restart", name="Restart", icon="mdi:restart-alert"
)


async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up sensor."""
coordinator = hass.data[DOMAIN][entry.entry_id]
entities = [RestartButton(coordinator, BUTTON_RESTART)]
async_add_entities(entities)


class RestartButton(BboxEntity, ButtonEntity):
"""Representation of a button for reboot router."""

async def async_press(self) -> None:
"""Handle the button press."""
try:
await self.coordinator.bbox.device.async_reboot()
except BboxException as error:
_LOGGER.error(error)
40 changes: 13 additions & 27 deletions custom_components/bbox2/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,33 +37,9 @@ def __init__(
async def _async_update_data(self) -> dict:
"""Fetch datas."""
try:
rslt = await self.bbox.device.async_get_bbox_info()
if len(rslt) == 1:
bbox_info = rslt[0]
else:
bbox_info = rslt

rslt = await self.bbox.lan.async_get_connected_devices()
if len(rslt) == 1:
devices = rslt[0]
else:
devices = rslt

rslt = await self.bbox.wan.async_get_wan_ip_stats()
if len(rslt) == 1:
wan_ip_stats = rslt[0]
else:
wan_ip_stats = rslt

# if (
# bbox_info.get("device", {}).get("adsl") == 1
# or bbox_info("device", {}).get("vdsl") == 1
# ):
# physical_stats = await self.bbox.wan.async_get_wan_xdsl()
# elif bbox_info("device", {}).get("ftth") == 1:
# physical_stats = await self.bbox.wan.async_get_wan_ftth()
# else:
# physical_stats = {}
bbox_info = self.check_list({await self.bbox.device.async_get_bbox_info()})
devices = self.check_list(await self.bbox.lan.async_get_connected_devices())
wan_ip_stats = self.check_list(await self.bbox.wan.async_get_wan_ip_stats())

return {
"info": bbox_info,
Expand All @@ -79,3 +55,13 @@ async def _async_update_data(self) -> dict:
except Exception as error:
_LOGGER.error(error)
raise UpdateFailed from error

@staticmethod
def check_list(obj):
"""Return element if one only."""
if isinstance(obj, list) and len(obj) == 1:
return obj[0]
else:
raise UpdateFailed(
"The call is not a list or it contains more than one element"
)
34 changes: 28 additions & 6 deletions custom_components/bbox2/device_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ async def async_setup_entry(

entities = [
BboxDeviceTracker(coordinator, description, device)
for device in coordinator.data["devices"]
for device in coordinator.data.get("devices", {})
.get("hosts", {})
.get("list", [])
]

async_add_entities(entities)
Expand All @@ -35,6 +37,9 @@ async def async_setup_entry(
class BboxDeviceTracker(BboxEntity, ScannerEntity):
"""Representation of a tracked device."""

_attr_has_entity_name = True
_attr_entity_registry_enabled_default = False

def __init__(self, coordinator, description, device) -> None:
"""Initialize."""
super().__init__(coordinator, description)
Expand All @@ -43,7 +48,7 @@ def __init__(self, coordinator, description, device) -> None:
@property
def unique_id(self):
"""Return unique_id."""
return f"{self.box_id}-{self._device['id']}"
return self._device["macaddress"]

@property
def source_type(self):
Expand All @@ -63,14 +68,22 @@ def ip_address(self):
@property
def is_connected(self):
"""Return connecting status."""
for device in self.coordinator.data.get("devices", {}):
if device["id"] == self._device["id"]:
return device["active"] == 1
for device in (
self.coordinator.data.get("devices", {}).get("hosts", {}).get("list", [])
):
if device["macaddress"] == self._device["macaddress"]:
return device.get("active", 0) == 1

@property
def name(self):
"""Return name."""
return self._device["hostname"]
if self._device["userfriendlyname"] != "":
name = self._device["userfriendlyname"]
elif self._device["hostname"] != "":
name = self._device["hostname"]
else:
name = self._device["macaddress"]
return name

@property
def device_info(self):
Expand All @@ -80,3 +93,12 @@ def device_info(self):
"identifiers": {(DOMAIN, self.unique_id)},
"via_device": (DOMAIN, self.box_id),
}

@property
def extra_state_attributes(self):
"""Return extra attributes."""
return {
"link": self._device.get("link"),
"last_seen": self._device.get("lastseen"),
"ip_address": self._device.get("ipaddress"),
}
5 changes: 3 additions & 2 deletions custom_components/bbox2/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from .const import BBOX_NAME, DOMAIN, MANUFACTURER
from .const import BBOX_NAME, DOMAIN, MANUFACTURER, CONF_HOST
from .coordinator import BboxDataUpdateCoordinator

_LOGGER = logging.getLogger(__name__)
Expand All @@ -23,11 +23,12 @@ def __init__(self, coordinator: BboxDataUpdateCoordinator, description) -> None:
device = coordinator.data.get("info", {}).get("device", {})
self.box_id = device.get("serialnumber", "ABC12345")
self._attr_unique_id = f"{self.box_id}-{description.key}"
self._attr_name = description.key.capitalize().replace("_", " ")
self.entity_description = description
self._attr_device_info = {
"identifiers": {(DOMAIN, self.box_id)},
"manufacturer": MANUFACTURER,
"name": BBOX_NAME,
"model": device.get("modelname"),
"sw_version": device.get("main", {}).get("version"),
"configuration_url": f'https://{coordinator.config_entry.data[CONF_HOST]}',
}
32 changes: 32 additions & 0 deletions custom_components/bbox2/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Helpers for component."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from homeassistant.helpers.typing import StateType
from homeassistant.components.sensor import SensorEntityDescription
from homeassistant.components.binary_sensor import BinarySensorEntityDescription


@dataclass
class BboxValueFnMixin:
"""Mixin for Audi sensor."""

value_fn: Callable[..., StateType] | None = None


@dataclass
class BboxSensorDescription(BboxValueFnMixin, SensorEntityDescription):
"""Describes a sensor."""


@dataclass
class BboxBinarySensorDescription(BboxValueFnMixin, BinarySensorEntityDescription):
"""Describes a sensor."""


def finditem(data, entity_description):
if (keys := entity_description.key.split(".")) and isinstance(keys, list):
for key in keys:
if isinstance(data, dict):
data = data.get(key)
return data
1 change: 0 additions & 1 deletion custom_components/bbox2/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"dependencies": [],
"documentation": "https://github.com/cyr-ius/hass-bbox2",
"homekit": {},
"integration_type": "hub",
"iot_class": "local_polling",
"issue_tracker": "https://github.com/cyr-ius/hass-bbox2/issues",
"loggers": ["bboxpy"],
Expand Down
Loading

0 comments on commit c54f600

Please sign in to comment.