Add WAN information to SFR Box (#89678)

This commit is contained in:
epenet 2023-03-15 18:49:57 +01:00 committed by GitHub
parent cb74b934dc
commit c416d18506
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 165 additions and 20 deletions

View File

@ -1,11 +1,13 @@
"""SFR Box."""
from __future__ import annotations
import asyncio
from sfrbox_api.bridge import SFRBox
from sfrbox_api.exceptions import SFRBoxAuthenticationError, SFRBoxError
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME, Platform
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr
@ -37,15 +39,17 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
system=SFRDataUpdateCoordinator(
hass, box, "system", lambda b: b.system_get_info()
),
wan=SFRDataUpdateCoordinator(hass, box, "wan", lambda b: b.wan_get_info()),
)
# Preload system information
await data.system.async_config_entry_first_refresh()
system_info = data.system.data
# Preload other coordinators (based on net infrastructure)
tasks = [data.wan.async_config_entry_first_refresh()]
if system_info.net_infra == "adsl":
await data.dsl.async_config_entry_first_refresh()
else:
platforms = list(platforms)
platforms.remove(Platform.BINARY_SENSOR)
tasks.append(data.dsl.async_config_entry_first_refresh())
await asyncio.gather(*tasks)
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = data

View File

@ -5,7 +5,7 @@ from collections.abc import Callable
from dataclasses import dataclass
from typing import Generic, TypeVar
from sfrbox_api.models import DslInfo, SystemInfo
from sfrbox_api.models import DslInfo, SystemInfo, WanInfo
from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass,
@ -48,6 +48,15 @@ DSL_SENSOR_TYPES: tuple[SFRBoxBinarySensorEntityDescription[DslInfo], ...] = (
value_fn=lambda x: x.status == "up",
),
)
WAN_SENSOR_TYPES: tuple[SFRBoxBinarySensorEntityDescription[WanInfo], ...] = (
SFRBoxBinarySensorEntityDescription[WanInfo](
key="status",
name="WAN status",
device_class=BinarySensorDeviceClass.CONNECTIVITY,
entity_category=EntityCategory.DIAGNOSTIC,
value_fn=lambda x: x.status == "up",
),
)
async def async_setup_entry(
@ -56,10 +65,15 @@ async def async_setup_entry(
"""Set up the sensors."""
data: DomainData = hass.data[DOMAIN][entry.entry_id]
entities = [
SFRBoxBinarySensor(data.dsl, description, data.system.data)
for description in DSL_SENSOR_TYPES
entities: list[SFRBoxBinarySensor] = [
SFRBoxBinarySensor(data.wan, description, data.system.data)
for description in WAN_SENSOR_TYPES
]
if data.system.data.net_infra == "adsl":
entities.extend(
SFRBoxBinarySensor(data.dsl, description, data.system.data)
for description in DSL_SENSOR_TYPES
)
async_add_entities(entities)

View File

@ -11,7 +11,7 @@ from homeassistant.core import HomeAssistant
from .const import DOMAIN
from .models import DomainData
TO_REDACT = {"mac_addr", "serial_number"}
TO_REDACT = {"mac_addr", "serial_number", "ip_addr", "ipv6_addr"}
async def async_get_config_entry_diagnostics(
@ -33,8 +33,6 @@ async def async_get_config_entry_diagnostics(
"system": async_redact_data(
dataclasses.asdict(data.system.data), TO_REDACT
),
"wan": async_redact_data(
dataclasses.asdict(await data.system.box.wan_get_info()), TO_REDACT
),
"wan": async_redact_data(dataclasses.asdict(data.wan.data), TO_REDACT),
},
}

View File

@ -2,7 +2,7 @@
from dataclasses import dataclass
from sfrbox_api.bridge import SFRBox
from sfrbox_api.models import DslInfo, SystemInfo
from sfrbox_api.models import DslInfo, SystemInfo, WanInfo
from .coordinator import SFRDataUpdateCoordinator
@ -14,3 +14,4 @@ class DomainData:
box: SFRBox
dsl: SFRDataUpdateCoordinator[DslInfo]
system: SFRDataUpdateCoordinator[SystemInfo]
wan: SFRDataUpdateCoordinator[WanInfo]

View File

@ -3,7 +3,7 @@ from collections.abc import Callable
from dataclasses import dataclass
from typing import Generic, TypeVar
from sfrbox_api.models import DslInfo, SystemInfo
from sfrbox_api.models import DslInfo, SystemInfo, WanInfo
from homeassistant.components.sensor import (
SensorDeviceClass,
@ -195,6 +195,24 @@ SYSTEM_SENSOR_TYPES: tuple[SFRBoxSensorEntityDescription[SystemInfo], ...] = (
value_fn=lambda x: x.temperature / 1000,
),
)
WAN_SENSOR_TYPES: tuple[SFRBoxSensorEntityDescription[WanInfo], ...] = (
SFRBoxSensorEntityDescription[WanInfo](
key="mode",
name="WAN mode",
device_class=SensorDeviceClass.ENUM,
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
options=[
"adsl_ppp",
"adsl_routed",
"ftth_routed",
"grps_ppp",
"unknown",
],
translation_key="wan_mode",
value_fn=lambda x: x.mode.replace("/", "_"),
),
)
async def async_setup_entry(
@ -207,6 +225,10 @@ async def async_setup_entry(
SFRBoxSensor(data.system, description, data.system.data)
for description in SYSTEM_SENSOR_TYPES
]
entities.extend(
SFRBoxSensor(data.wan, description, data.system.data)
for description in WAN_SENSOR_TYPES
)
if data.system.data.net_infra == "adsl":
entities.extend(
SFRBoxSensor(data.dsl, description, data.system.data)

View File

@ -63,6 +63,15 @@
"showtime": "Showtime",
"unknown": "Unknown"
}
},
"wan_mode": {
"state": {
"adsl_ppp": "ADSL (PPP)",
"adsl_routed": "ADSL (Routed)",
"ftth_routed": "FTTH (Routed)",
"grps_ppp": "GPRS (PPP)",
"unknown": "Unknown"
}
}
}
}

View File

@ -30,6 +30,34 @@
# ---
# name: test_binary_sensors.1
list([
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'binary_sensor.sfr_box_wan_status',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.CONNECTIVITY: 'connectivity'>,
'original_icon': None,
'original_name': 'WAN status',
'platform': 'sfr_box',
'supported_features': 0,
'translation_key': None,
'unique_id': 'e4:5d:51:00:11:22_wan_status',
'unit_of_measurement': None,
}),
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@ -73,3 +101,16 @@
'state': 'on',
})
# ---
# name: test_binary_sensors[binary_sensor.sfr_box_wan_status]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'connectivity',
'friendly_name': 'SFR Box WAN status',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.sfr_box_wan_status',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---

View File

@ -41,7 +41,7 @@
'wan': dict({
'infra': 'adsl',
'infra6': '',
'ip_addr': '1.2.3.4',
'ip_addr': '**REDACTED**',
'ipv6_addr': '',
'mode': 'adsl/routed',
'status': 'up',

View File

@ -119,6 +119,42 @@
'unique_id': 'e4:5d:51:00:11:22_system_temperature',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'adsl_ppp',
'adsl_routed',
'ftth_routed',
'grps_ppp',
'unknown',
]),
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': <RegistryEntryDisabler.INTEGRATION: 'integration'>,
'domain': 'sensor',
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.sfr_box_wan_mode',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
'original_icon': None,
'original_name': 'WAN mode',
'platform': 'sfr_box',
'supported_features': 0,
'translation_key': 'wan_mode',
'unique_id': 'e4:5d:51:00:11:22_wan_mode',
'unit_of_measurement': None,
}),
EntityRegistryEntrySnapshot({
'aliases': set({
}),
@ -682,3 +718,23 @@
'state': '12251',
})
# ---
# name: test_sensors[sensor.sfr_box_wan_mode]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'enum',
'friendly_name': 'SFR Box WAN mode',
'options': list([
'adsl_ppp',
'adsl_routed',
'ftth_routed',
'grps_ppp',
'unknown',
]),
}),
'context': <ANY>,
'entity_id': 'sensor.sfr_box_wan_mode',
'last_changed': <ANY>,
'last_updated': <ANY>,
'state': 'adsl_routed',
})
# ---

View File

@ -10,7 +10,7 @@ from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
pytestmark = pytest.mark.usefixtures("system_get_info", "dsl_get_info")
pytestmark = pytest.mark.usefixtures("system_get_info", "dsl_get_info", "wan_get_info")
@pytest.fixture(autouse=True)

View File

@ -13,7 +13,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import device_registry as dr, entity_registry as er
pytestmark = pytest.mark.usefixtures("system_get_info", "dsl_get_info")
pytestmark = pytest.mark.usefixtures("system_get_info", "dsl_get_info", "wan_get_info")
@pytest.fixture(autouse=True)

View File

@ -17,7 +17,7 @@ def override_platforms() -> Generator[None, None, None]:
yield
@pytest.mark.usefixtures("system_get_info", "dsl_get_info")
@pytest.mark.usefixtures("system_get_info", "dsl_get_info", "wan_get_info")
async def test_setup_unload_entry(
hass: HomeAssistant, config_entry: ConfigEntry
) -> None:

View File

@ -11,7 +11,7 @@ from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
pytestmark = pytest.mark.usefixtures("system_get_info", "dsl_get_info")
pytestmark = pytest.mark.usefixtures("system_get_info", "dsl_get_info", "wan_get_info")
@pytest.fixture(autouse=True)