mirror of
https://github.com/home-assistant/core.git
synced 2026-05-06 08:36:42 +02:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b0f98ed98d | |||
| 40e797ca6d |
@@ -1,19 +1,61 @@
|
||||
"""Support for Freebox devices (Freebox v6 and Freebox mini 4K)."""
|
||||
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from freebox_api.exceptions import HttpRequestError
|
||||
|
||||
from homeassistant.const import CONF_HOST, CONF_PORT, EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.core import Event, HomeAssistant
|
||||
from homeassistant.const import CONF_HOST, CONF_PORT, EVENT_HOMEASSISTANT_STOP, Platform
|
||||
from homeassistant.core import Event, HomeAssistant, callback
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.event import async_track_time_interval
|
||||
|
||||
from .const import PLATFORMS
|
||||
from .const import DOMAIN, PLATFORMS
|
||||
from .router import FreeboxConfigEntry, FreeboxRouter, get_api
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SCAN_INTERVAL = timedelta(seconds=30)
|
||||
|
||||
# Old entity name suffixes that need rewriting to the entity description key.
|
||||
# Format: (platform, old name suffix, new key)
|
||||
_STATIC_UNIQUE_ID_MIGRATIONS: tuple[tuple[Platform, str, str], ...] = (
|
||||
(Platform.SENSOR, "Freebox download speed", "rate_down"),
|
||||
(Platform.SENSOR, "Freebox upload speed", "rate_up"),
|
||||
(Platform.SENSOR, "Freebox missed calls", "missed"),
|
||||
(Platform.BUTTON, "Reboot Freebox", "reboot"),
|
||||
(Platform.BUTTON, "Mark calls as read", "mark_calls_as_read"),
|
||||
(Platform.SWITCH, "Freebox WiFi", "wifi"),
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def _migrate_unique_ids(hass: HomeAssistant, router: FreeboxRouter) -> None:
|
||||
"""Migrate name-based unique ids to key-based ones."""
|
||||
entity_registry = er.async_get(hass)
|
||||
mac = router.mac
|
||||
|
||||
for platform, old_suffix, new_key in _STATIC_UNIQUE_ID_MIGRATIONS:
|
||||
old_uid = f"{mac} {old_suffix}"
|
||||
new_uid = f"{mac} {new_key}"
|
||||
if entity_id := entity_registry.async_get_entity_id(platform, DOMAIN, old_uid):
|
||||
_LOGGER.debug(
|
||||
"Migrating %s unique_id from %s to %s", entity_id, old_uid, new_uid
|
||||
)
|
||||
entity_registry.async_update_entity(entity_id, new_unique_id=new_uid)
|
||||
|
||||
for sensor_id, sensor_name in router.sensors_temperature_names.items():
|
||||
old_uid = f"{mac} Freebox {sensor_name}"
|
||||
new_uid = f"{mac} {sensor_id}"
|
||||
if entity_id := entity_registry.async_get_entity_id(
|
||||
Platform.SENSOR, DOMAIN, old_uid
|
||||
):
|
||||
_LOGGER.debug(
|
||||
"Migrating %s unique_id from %s to %s", entity_id, old_uid, new_uid
|
||||
)
|
||||
entity_registry.async_update_entity(entity_id, new_unique_id=new_uid)
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: FreeboxConfigEntry) -> bool:
|
||||
"""Set up Freebox entry."""
|
||||
@@ -31,6 +73,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: FreeboxConfigEntry) -> b
|
||||
async_track_time_interval(hass, router.update_all, SCAN_INTERVAL)
|
||||
)
|
||||
|
||||
_migrate_unique_ids(hass, router)
|
||||
|
||||
entry.runtime_data = router
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
@@ -48,6 +48,7 @@ class FreeboxAlarm(FreeboxHomeEntity, AlarmControlPanelEntity):
|
||||
"""Representation of a Freebox alarm."""
|
||||
|
||||
_attr_code_arm_required = False
|
||||
_attr_name = None
|
||||
|
||||
def __init__(self, router: FreeboxRouter, node: dict[str, Any]) -> None:
|
||||
"""Initialize an alarm."""
|
||||
|
||||
@@ -23,7 +23,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||
RAID_SENSORS: tuple[BinarySensorEntityDescription, ...] = (
|
||||
BinarySensorEntityDescription(
|
||||
key="raid_degraded",
|
||||
name="degraded",
|
||||
translation_key="raid_degraded",
|
||||
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
@@ -68,7 +68,7 @@ async def async_setup_entry(
|
||||
class FreeboxHomeBinarySensor(FreeboxHomeEntity, BinarySensorEntity):
|
||||
"""Representation of a Freebox binary sensor."""
|
||||
|
||||
_sensor_name = "trigger"
|
||||
_endpoint_name = "trigger"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -79,9 +79,11 @@ class FreeboxHomeBinarySensor(FreeboxHomeEntity, BinarySensorEntity):
|
||||
"""Initialize a Freebox binary sensor."""
|
||||
super().__init__(router, node, sub_node)
|
||||
self._command_id = self.get_command_id(
|
||||
node["type"]["endpoints"], "signal", self._sensor_name
|
||||
node["type"]["endpoints"], "signal", self._endpoint_name
|
||||
)
|
||||
self._attr_is_on = self._edit_state(
|
||||
self.get_value("signal", self._endpoint_name)
|
||||
)
|
||||
self._attr_is_on = self._edit_state(self.get_value("signal", self._sensor_name))
|
||||
|
||||
async def async_update_signal(self) -> None:
|
||||
"""Update name & state."""
|
||||
@@ -91,10 +93,10 @@ class FreeboxHomeBinarySensor(FreeboxHomeEntity, BinarySensorEntity):
|
||||
await FreeboxHomeEntity.async_update_signal(self)
|
||||
|
||||
def _edit_state(self, state: bool | None) -> bool | None:
|
||||
"""Edit state depending on sensor name."""
|
||||
"""Edit state depending on endpoint name."""
|
||||
if state is None:
|
||||
return None
|
||||
if self._sensor_name == "trigger":
|
||||
if self._endpoint_name == "trigger":
|
||||
return not state
|
||||
return state
|
||||
|
||||
@@ -103,12 +105,14 @@ class FreeboxPirSensor(FreeboxHomeBinarySensor):
|
||||
"""Representation of a Freebox motion binary sensor."""
|
||||
|
||||
_attr_device_class = BinarySensorDeviceClass.MOTION
|
||||
_attr_name = None
|
||||
|
||||
|
||||
class FreeboxDwsSensor(FreeboxHomeBinarySensor):
|
||||
"""Representation of a Freebox door opener binary sensor."""
|
||||
|
||||
_attr_device_class = BinarySensorDeviceClass.DOOR
|
||||
_attr_name = None
|
||||
|
||||
|
||||
class FreeboxCoverSensor(FreeboxHomeBinarySensor):
|
||||
@@ -117,14 +121,15 @@ class FreeboxCoverSensor(FreeboxHomeBinarySensor):
|
||||
_attr_device_class = BinarySensorDeviceClass.SAFETY
|
||||
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||
_attr_entity_registry_enabled_default = False
|
||||
_attr_translation_key = "cover"
|
||||
|
||||
_sensor_name = "cover"
|
||||
_endpoint_name = "cover"
|
||||
|
||||
def __init__(self, router: FreeboxRouter, node: dict[str, Any]) -> None:
|
||||
"""Initialize a cover for another device."""
|
||||
cover_node = next(
|
||||
filter(
|
||||
lambda x: x["name"] == self._sensor_name and x["ep_type"] == "signal",
|
||||
lambda x: x["name"] == self._endpoint_name and x["ep_type"] == "signal",
|
||||
node["type"]["endpoints"],
|
||||
),
|
||||
None,
|
||||
@@ -149,7 +154,7 @@ class FreeboxRaidDegradedSensor(BinarySensorEntity):
|
||||
self._router = router
|
||||
self._attr_device_info = router.device_info
|
||||
self._raid = raid
|
||||
self._attr_name = f"Raid array {raid['id']} {description.name}"
|
||||
self._attr_translation_placeholders = {"id": str(raid["id"])}
|
||||
self._attr_unique_id = (
|
||||
f"{router.mac} {description.key} {raid['name']} {raid['id']}"
|
||||
)
|
||||
|
||||
@@ -25,14 +25,14 @@ class FreeboxButtonEntityDescription(ButtonEntityDescription):
|
||||
BUTTON_DESCRIPTIONS: tuple[FreeboxButtonEntityDescription, ...] = (
|
||||
FreeboxButtonEntityDescription(
|
||||
key="reboot",
|
||||
name="Reboot Freebox",
|
||||
translation_key="reboot",
|
||||
device_class=ButtonDeviceClass.RESTART,
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
async_press=lambda router: router.reboot(),
|
||||
),
|
||||
FreeboxButtonEntityDescription(
|
||||
key="mark_calls_as_read",
|
||||
name="Mark calls as read",
|
||||
translation_key="mark_calls_as_read",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
async_press=lambda router: router.call.mark_calls_log_as_read(),
|
||||
),
|
||||
@@ -55,6 +55,7 @@ async def async_setup_entry(
|
||||
class FreeboxButton(ButtonEntity):
|
||||
"""Representation of a Freebox button."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
entity_description: FreeboxButtonEntityDescription
|
||||
|
||||
def __init__(
|
||||
@@ -64,7 +65,7 @@ class FreeboxButton(ButtonEntity):
|
||||
self.entity_description = description
|
||||
self._router = router
|
||||
self._attr_device_info = router.device_info
|
||||
self._attr_unique_id = f"{router.mac} {description.name}"
|
||||
self._attr_unique_id = f"{router.mac} {description.key}"
|
||||
|
||||
async def async_press(self) -> None:
|
||||
"""Press the button."""
|
||||
|
||||
@@ -66,6 +66,8 @@ def add_entities(
|
||||
class FreeboxCamera(FreeboxHomeEntity, FFmpegCamera):
|
||||
"""Representation of a Freebox camera."""
|
||||
|
||||
_attr_name = None
|
||||
|
||||
def __init__(
|
||||
self, hass: HomeAssistant, router: FreeboxRouter, node: dict[str, Any]
|
||||
) -> None:
|
||||
@@ -89,6 +91,16 @@ class FreeboxCamera(FreeboxHomeEntity, FFmpegCamera):
|
||||
self._attr_extra_state_attributes = {}
|
||||
self.update_node(node)
|
||||
|
||||
@property
|
||||
def name(self) -> str | None: # type: ignore[override]
|
||||
"""Return None so the device name is used as entity name.
|
||||
|
||||
FFmpegCamera defines its own `name` property that takes precedence
|
||||
over the base Entity class's name resolution (which would use
|
||||
`_attr_name`). Override here to honor `_attr_name = None`.
|
||||
"""
|
||||
return self._attr_name
|
||||
|
||||
async def async_enable_motion_detection(self) -> None:
|
||||
"""Enable motion detection in the camera."""
|
||||
if await self.set_home_endpoint_value(self._command_motion_detection, True):
|
||||
@@ -106,8 +118,6 @@ class FreeboxCamera(FreeboxHomeEntity, FFmpegCamera):
|
||||
|
||||
def update_node(self, node: dict[str, Any]) -> None:
|
||||
"""Update params."""
|
||||
self._name = node["label"].strip()
|
||||
|
||||
# Get status
|
||||
if self._node["status"] == "active":
|
||||
self._attr_is_streaming = True
|
||||
|
||||
@@ -55,6 +55,7 @@ def add_entities(
|
||||
class FreeboxDevice(ScannerEntity):
|
||||
"""Representation of a Freebox device."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
_attr_should_poll = False
|
||||
|
||||
def __init__(self, router: FreeboxRouter, device: dict[str, Any]) -> None:
|
||||
|
||||
@@ -16,6 +16,8 @@ _LOGGER = logging.getLogger(__name__)
|
||||
class FreeboxHomeEntity(Entity):
|
||||
"""Representation of a Freebox base entity."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
router: FreeboxRouter,
|
||||
@@ -27,12 +29,9 @@ class FreeboxHomeEntity(Entity):
|
||||
self._node = node
|
||||
self._sub_node = sub_node
|
||||
self._id = node["id"]
|
||||
self._attr_name = node["label"].strip()
|
||||
self._device_name = self._attr_name
|
||||
self._attr_unique_id = f"{self._router.mac}-node_{self._id}"
|
||||
|
||||
if sub_node is not None:
|
||||
self._attr_name += " " + sub_node["label"].strip()
|
||||
self._attr_unique_id += "-" + sub_node["name"].strip()
|
||||
|
||||
self._available = True
|
||||
@@ -52,7 +51,7 @@ class FreeboxHomeEntity(Entity):
|
||||
identifiers={(DOMAIN, self._id)},
|
||||
manufacturer=self._manufacturer,
|
||||
model=self._model,
|
||||
name=self._device_name,
|
||||
name=node["label"].strip(),
|
||||
sw_version=self._firmware,
|
||||
via_device=(DOMAIN, router.mac),
|
||||
)
|
||||
@@ -60,13 +59,6 @@ class FreeboxHomeEntity(Entity):
|
||||
async def async_update_signal(self) -> None:
|
||||
"""Update signal."""
|
||||
self._node = self._router.home_devices[self._id]
|
||||
# Update name
|
||||
if self._sub_node is None:
|
||||
self._attr_name = self._node["label"].strip()
|
||||
else:
|
||||
self._attr_name = (
|
||||
self._node["label"].strip() + " " + self._sub_node["label"].strip()
|
||||
)
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def set_home_endpoint_value(
|
||||
|
||||
@@ -1,7 +1,26 @@
|
||||
{
|
||||
"services": {
|
||||
"reboot": {
|
||||
"service": "mdi:restart"
|
||||
"entity": {
|
||||
"sensor": {
|
||||
"missed": {
|
||||
"default": "mdi:phone-missed"
|
||||
},
|
||||
"partition_free_space": {
|
||||
"default": "mdi:harddisk"
|
||||
},
|
||||
"rate_down": {
|
||||
"default": "mdi:download-network"
|
||||
},
|
||||
"rate_up": {
|
||||
"default": "mdi:upload-network"
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
"wifi": {
|
||||
"default": "mdi:wifi",
|
||||
"state": {
|
||||
"off": "mdi:wifi-off"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +125,7 @@ class FreeboxRouter:
|
||||
self.supports_raid = True
|
||||
self.raids: dict[int, dict[str, Any]] = {}
|
||||
self.sensors_temperature: dict[str, int] = {}
|
||||
self.sensors_temperature_names: dict[str, str] = {}
|
||||
self.sensors_connection: dict[str, float] = {}
|
||||
self.call_list: list[dict[str, Any]] = []
|
||||
self.home_granted = True
|
||||
@@ -183,7 +184,11 @@ class FreeboxRouter:
|
||||
# According to the doc `syst_datas["sensors"]` is temperature sensors in celsius degree.
|
||||
# Name and id of sensors may vary under Freebox devices.
|
||||
for sensor in syst_datas["sensors"]:
|
||||
self.sensors_temperature[sensor["name"]] = sensor.get("value")
|
||||
sensor_id = sensor["id"]
|
||||
self.sensors_temperature[sensor_id] = sensor.get("value")
|
||||
# Names are static per-device; only populate once.
|
||||
if sensor_id not in self.sensors_temperature_names:
|
||||
self.sensors_temperature_names[sensor_id] = sensor["name"]
|
||||
|
||||
# Connection sensors
|
||||
connection_datas: dict[str, Any] = await self._api.connection.get_status()
|
||||
|
||||
@@ -25,36 +25,34 @@ _LOGGER = logging.getLogger(__name__)
|
||||
CONNECTION_SENSORS: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
key="rate_down",
|
||||
name="Freebox download speed",
|
||||
translation_key="rate_down",
|
||||
device_class=SensorDeviceClass.DATA_RATE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfDataRate.KILOBYTES_PER_SECOND,
|
||||
icon="mdi:download-network",
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="rate_up",
|
||||
name="Freebox upload speed",
|
||||
translation_key="rate_up",
|
||||
device_class=SensorDeviceClass.DATA_RATE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfDataRate.KILOBYTES_PER_SECOND,
|
||||
icon="mdi:upload-network",
|
||||
),
|
||||
)
|
||||
|
||||
CALL_SENSORS: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
key="missed",
|
||||
name="Freebox missed calls",
|
||||
icon="mdi:phone-missed",
|
||||
translation_key="missed",
|
||||
native_unit_of_measurement="calls",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
)
|
||||
|
||||
DISK_PARTITION_SENSORS: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
key="partition_free_space",
|
||||
name="free space",
|
||||
translation_key="partition_free_space",
|
||||
native_unit_of_measurement=PERCENTAGE,
|
||||
icon="mdi:harddisk",
|
||||
),
|
||||
)
|
||||
|
||||
@@ -77,14 +75,14 @@ async def async_setup_entry(
|
||||
FreeboxSensor(
|
||||
router,
|
||||
SensorEntityDescription(
|
||||
key=sensor_name,
|
||||
name=f"Freebox {sensor_name}",
|
||||
key=sensor_id,
|
||||
name=sensor_name,
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
),
|
||||
)
|
||||
for sensor_name in router.sensors_temperature
|
||||
for sensor_id, sensor_name in router.sensors_temperature_names.items()
|
||||
]
|
||||
|
||||
entities.extend(
|
||||
@@ -121,6 +119,7 @@ class FreeboxSensor(SensorEntity):
|
||||
"""Representation of a Freebox sensor."""
|
||||
|
||||
_attr_should_poll = False
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(
|
||||
self, router: FreeboxRouter, description: SensorEntityDescription
|
||||
@@ -128,7 +127,7 @@ class FreeboxSensor(SensorEntity):
|
||||
"""Initialize a Freebox sensor."""
|
||||
self.entity_description = description
|
||||
self._router = router
|
||||
self._attr_unique_id = f"{router.mac} {description.name}"
|
||||
self._attr_unique_id = f"{router.mac} {description.key}"
|
||||
self._attr_device_info = router.device_info
|
||||
|
||||
@callback
|
||||
@@ -204,7 +203,7 @@ class FreeboxDiskSensor(FreeboxSensor):
|
||||
super().__init__(router, description)
|
||||
self._disk_id = disk["id"]
|
||||
self._partition_id = partition["id"]
|
||||
self._attr_name = f"{partition['label']} {description.name}"
|
||||
self._attr_translation_placeholders = {"partition": partition["label"]}
|
||||
self._attr_unique_id = (
|
||||
f"{router.mac} {description.key} {disk['id']} {partition['id']}"
|
||||
)
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Freebox service entries description.
|
||||
|
||||
reboot:
|
||||
@@ -25,10 +25,41 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"reboot": {
|
||||
"description": "Reboots the Freebox.",
|
||||
"name": "Reboot"
|
||||
"entity": {
|
||||
"binary_sensor": {
|
||||
"cover": {
|
||||
"name": "Cover"
|
||||
},
|
||||
"raid_degraded": {
|
||||
"name": "RAID array {id} degraded"
|
||||
}
|
||||
},
|
||||
"button": {
|
||||
"mark_calls_as_read": {
|
||||
"name": "Mark calls as read"
|
||||
},
|
||||
"reboot": {
|
||||
"name": "Reboot"
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
"missed": {
|
||||
"name": "Missed calls"
|
||||
},
|
||||
"partition_free_space": {
|
||||
"name": "{partition} free space"
|
||||
},
|
||||
"rate_down": {
|
||||
"name": "Download speed"
|
||||
},
|
||||
"rate_up": {
|
||||
"name": "Upload speed"
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
"wifi": {
|
||||
"name": "Wi-Fi"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||
SWITCH_DESCRIPTIONS = [
|
||||
SwitchEntityDescription(
|
||||
key="wifi",
|
||||
name="Freebox WiFi",
|
||||
translation_key="wifi",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
)
|
||||
]
|
||||
@@ -41,6 +41,8 @@ async def async_setup_entry(
|
||||
class FreeboxSwitch(SwitchEntity):
|
||||
"""Representation of a freebox switch."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(
|
||||
self, router: FreeboxRouter, entity_description: SwitchEntityDescription
|
||||
) -> None:
|
||||
@@ -48,7 +50,7 @@ class FreeboxSwitch(SwitchEntity):
|
||||
self.entity_description = entity_description
|
||||
self._router = router
|
||||
self._attr_device_info = router.device_info
|
||||
self._attr_unique_id = f"{router.mac} {entity_description.name}"
|
||||
self._attr_unique_id = f"{router.mac} {entity_description.key}"
|
||||
|
||||
async def _async_set_state(self, enabled: bool) -> None:
|
||||
"""Turn the switch on or off."""
|
||||
|
||||
@@ -63,7 +63,7 @@ async def test_home(
|
||||
== BinarySensorDeviceClass.DOOR
|
||||
)
|
||||
assert (
|
||||
hass.states.get("binary_sensor.ouverture_porte_couvercle").attributes[
|
||||
hass.states.get("binary_sensor.ouverture_porte_cover").attributes[
|
||||
ATTR_DEVICE_CLASS
|
||||
]
|
||||
== BinarySensorDeviceClass.SAFETY
|
||||
@@ -71,9 +71,9 @@ async def test_home(
|
||||
|
||||
# Initial state
|
||||
assert hass.states.get("binary_sensor.detecteur").state == "on"
|
||||
assert hass.states.get("binary_sensor.detecteur_couvercle").state == "off"
|
||||
assert hass.states.get("binary_sensor.detecteur_cover").state == "off"
|
||||
assert hass.states.get("binary_sensor.ouverture_porte").state == "unknown"
|
||||
assert hass.states.get("binary_sensor.ouverture_porte_couvercle").state == "off"
|
||||
assert hass.states.get("binary_sensor.ouverture_porte_cover").state == "off"
|
||||
|
||||
# Now simulate a changed status
|
||||
data_home_get_values_changed = deepcopy(DATA_HOME_PIR_GET_VALUE)
|
||||
@@ -86,6 +86,6 @@ async def test_home(
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get("binary_sensor.detecteur").state == "off"
|
||||
assert hass.states.get("binary_sensor.detecteur_couvercle").state == "on"
|
||||
assert hass.states.get("binary_sensor.detecteur_cover").state == "on"
|
||||
assert hass.states.get("binary_sensor.ouverture_porte").state == "off"
|
||||
assert hass.states.get("binary_sensor.ouverture_porte_couvercle").state == "on"
|
||||
assert hass.states.get("binary_sensor.ouverture_porte_cover").state == "on"
|
||||
|
||||
@@ -28,7 +28,7 @@ async def test_reboot(hass: HomeAssistant, router: Mock) -> None:
|
||||
BUTTON_DOMAIN,
|
||||
SERVICE_PRESS,
|
||||
service_data={
|
||||
ATTR_ENTITY_ID: "button.freebox_server_r2_reboot_freebox",
|
||||
ATTR_ENTITY_ID: "button.freebox_server_r2_reboot",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
from unittest.mock import ANY, Mock
|
||||
|
||||
import pytest
|
||||
from pytest_unordered import unordered
|
||||
|
||||
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN
|
||||
from homeassistant.components.device_tracker import DOMAIN as DT_DOMAIN
|
||||
from homeassistant.components.freebox.const import DOMAIN
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
@@ -11,12 +13,15 @@ from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import CONF_HOST, CONF_PORT, STATE_UNAVAILABLE
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from .const import MOCK_HOST, MOCK_PORT
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
MOCK_MAC = "68:A3:78:00:00:00"
|
||||
|
||||
|
||||
async def test_setup(hass: HomeAssistant, router: Mock) -> None:
|
||||
"""Test setup of integration."""
|
||||
@@ -56,8 +61,8 @@ async def test_setup_import(hass: HomeAssistant, router: Mock) -> None:
|
||||
async def test_unload_remove(hass: HomeAssistant, router: Mock) -> None:
|
||||
"""Test unload and remove of integration."""
|
||||
entity_id_dt = f"{DT_DOMAIN}.freebox_server_r2"
|
||||
entity_id_sensor = f"{SENSOR_DOMAIN}.freebox_server_r2_freebox_download_speed"
|
||||
entity_id_switch = f"{SWITCH_DOMAIN}.freebox_server_r2_freebox_wifi"
|
||||
entity_id_sensor = f"{SENSOR_DOMAIN}.freebox_server_r2_download_speed"
|
||||
entity_id_switch = f"{SWITCH_DOMAIN}.freebox_server_r2_wi_fi"
|
||||
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
@@ -103,3 +108,54 @@ async def test_unload_remove(hass: HomeAssistant, router: Mock) -> None:
|
||||
assert state_sensor is None
|
||||
state_switch = hass.states.get(entity_id_switch)
|
||||
assert state_switch is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("platform", "old_suffix", "new_key"),
|
||||
[
|
||||
(SENSOR_DOMAIN, "Freebox download speed", "rate_down"),
|
||||
(SENSOR_DOMAIN, "Freebox upload speed", "rate_up"),
|
||||
(SENSOR_DOMAIN, "Freebox missed calls", "missed"),
|
||||
(SENSOR_DOMAIN, "Freebox Disque dur", "temp_hdd"),
|
||||
(SENSOR_DOMAIN, "Freebox Disque dur 2", "temp_hdd2"),
|
||||
(SENSOR_DOMAIN, "Freebox Température Switch", "temp_sw"),
|
||||
(SENSOR_DOMAIN, "Freebox Température CPU M", "temp_cpum"),
|
||||
(SENSOR_DOMAIN, "Freebox Température CPU B", "temp_cpub"),
|
||||
(BUTTON_DOMAIN, "Reboot Freebox", "reboot"),
|
||||
(BUTTON_DOMAIN, "Mark calls as read", "mark_calls_as_read"),
|
||||
(SWITCH_DOMAIN, "Freebox WiFi", "wifi"),
|
||||
],
|
||||
)
|
||||
async def test_unique_id_migration(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
router: Mock,
|
||||
platform: str,
|
||||
old_suffix: str,
|
||||
new_key: str,
|
||||
) -> None:
|
||||
"""Test migration of name-based unique ids to key-based ones."""
|
||||
old_unique_id = f"{MOCK_MAC} {old_suffix}"
|
||||
new_unique_id = f"{MOCK_MAC} {new_key}"
|
||||
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={CONF_HOST: MOCK_HOST, CONF_PORT: MOCK_PORT},
|
||||
unique_id=MOCK_HOST,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
entity_registry.async_get_or_create(
|
||||
platform,
|
||||
DOMAIN,
|
||||
old_unique_id,
|
||||
config_entry=entry,
|
||||
)
|
||||
|
||||
assert await async_setup_component(hass, DOMAIN, {})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entity_registry.async_get_entity_id(platform, DOMAIN, old_unique_id) is None
|
||||
assert (
|
||||
entity_registry.async_get_entity_id(platform, DOMAIN, new_unique_id) is not None
|
||||
)
|
||||
|
||||
@@ -25,14 +25,8 @@ async def test_network_speed(
|
||||
"""Test missed call sensor."""
|
||||
await setup_platform(hass, SENSOR_DOMAIN)
|
||||
|
||||
assert (
|
||||
hass.states.get("sensor.freebox_server_r2_freebox_download_speed").state
|
||||
== "198.9"
|
||||
)
|
||||
assert (
|
||||
hass.states.get("sensor.freebox_server_r2_freebox_upload_speed").state
|
||||
== "1440.0"
|
||||
)
|
||||
assert hass.states.get("sensor.freebox_server_r2_download_speed").state == "198.9"
|
||||
assert hass.states.get("sensor.freebox_server_r2_upload_speed").state == "1440.0"
|
||||
|
||||
# Simulate a changed speed
|
||||
data_connection_get_status_changed = deepcopy(DATA_CONNECTION_GET_STATUS)
|
||||
@@ -44,14 +38,8 @@ async def test_network_speed(
|
||||
async_fire_time_changed(hass)
|
||||
# To execute the save
|
||||
await hass.async_block_till_done()
|
||||
assert (
|
||||
hass.states.get("sensor.freebox_server_r2_freebox_download_speed").state
|
||||
== "123.4"
|
||||
)
|
||||
assert (
|
||||
hass.states.get("sensor.freebox_server_r2_freebox_upload_speed").state
|
||||
== "432.1"
|
||||
)
|
||||
assert hass.states.get("sensor.freebox_server_r2_download_speed").state == "123.4"
|
||||
assert hass.states.get("sensor.freebox_server_r2_upload_speed").state == "432.1"
|
||||
|
||||
|
||||
async def test_call(
|
||||
@@ -60,7 +48,7 @@ async def test_call(
|
||||
"""Test missed call sensor."""
|
||||
await setup_platform(hass, SENSOR_DOMAIN)
|
||||
|
||||
assert hass.states.get("sensor.freebox_server_r2_freebox_missed_calls").state == "3"
|
||||
assert hass.states.get("sensor.freebox_server_r2_missed_calls").state == "3"
|
||||
|
||||
# Simulate we marked calls as read
|
||||
data_call_get_calls_marked_as_read = []
|
||||
@@ -70,7 +58,7 @@ async def test_call(
|
||||
async_fire_time_changed(hass)
|
||||
# To execute the save
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get("sensor.freebox_server_r2_freebox_missed_calls").state == "0"
|
||||
assert hass.states.get("sensor.freebox_server_r2_missed_calls").state == "0"
|
||||
|
||||
|
||||
async def test_disk(
|
||||
@@ -104,15 +92,25 @@ async def test_disk(
|
||||
assert hass.states.get("sensor.disk_3000_freebox_free_space").state == "44.9"
|
||||
|
||||
|
||||
async def test_temperature(hass: HomeAssistant, router: Mock) -> None:
|
||||
"""Test temperature sensors expose API names and values."""
|
||||
await setup_platform(hass, SENSOR_DOMAIN)
|
||||
|
||||
assert hass.states.get("sensor.freebox_server_r2_disque_dur").state == "40"
|
||||
assert hass.states.get("sensor.freebox_server_r2_temperature_switch").state == "50"
|
||||
assert hass.states.get("sensor.freebox_server_r2_temperature_cpu_m").state == "60"
|
||||
assert hass.states.get("sensor.freebox_server_r2_temperature_cpu_b").state == "56"
|
||||
|
||||
|
||||
async def test_battery(
|
||||
hass: HomeAssistant, freezer: FrozenDateTimeFactory, router: Mock
|
||||
) -> None:
|
||||
"""Test battery sensor."""
|
||||
await setup_platform(hass, SENSOR_DOMAIN)
|
||||
|
||||
assert hass.states.get("sensor.telecommande_niveau_de_batterie").state == "100"
|
||||
assert hass.states.get("sensor.ouverture_porte_niveau_de_batterie").state == "100"
|
||||
assert hass.states.get("sensor.detecteur_niveau_de_batterie").state == "100"
|
||||
assert hass.states.get("sensor.telecommande_battery").state == "100"
|
||||
assert hass.states.get("sensor.ouverture_porte_battery").state == "100"
|
||||
assert hass.states.get("sensor.detecteur_battery").state == "100"
|
||||
|
||||
# Simulate a changed battery
|
||||
data_home_get_nodes_changed = deepcopy(DATA_HOME_GET_NODES)
|
||||
@@ -125,6 +123,6 @@ async def test_battery(
|
||||
async_fire_time_changed(hass)
|
||||
# To execute the save
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get("sensor.telecommande_niveau_de_batterie").state == "25"
|
||||
assert hass.states.get("sensor.ouverture_porte_niveau_de_batterie").state == "50"
|
||||
assert hass.states.get("sensor.detecteur_niveau_de_batterie").state == "75"
|
||||
assert hass.states.get("sensor.telecommande_battery").state == "25"
|
||||
assert hass.states.get("sensor.ouverture_porte_battery").state == "50"
|
||||
assert hass.states.get("sensor.detecteur_battery").state == "75"
|
||||
|
||||
Reference in New Issue
Block a user