diff --git a/homeassistant/components/freebox/const.py b/homeassistant/components/freebox/const.py index e47211f0926..df251dcf954 100644 --- a/homeassistant/components/freebox/const.py +++ b/homeassistant/components/freebox/const.py @@ -4,6 +4,7 @@ import socket from homeassistant.const import ( DATA_RATE_KILOBYTES_PER_SECOND, DEVICE_CLASS_TEMPERATURE, + PERCENTAGE, TEMP_CELSIUS, ) @@ -56,6 +57,15 @@ CALL_SENSORS = { }, } +DISK_PARTITION_SENSORS = { + "partition_free_space": { + SENSOR_NAME: "free space", + SENSOR_UNIT: PERCENTAGE, + SENSOR_ICON: "mdi:harddisk", + SENSOR_DEVICE_CLASS: None, + }, +} + TEMPERATURE_SENSOR_TEMPLATE = { SENSOR_NAME: None, SENSOR_UNIT: TEMP_CELSIUS, diff --git a/homeassistant/components/freebox/router.py b/homeassistant/components/freebox/router.py index 623c1fcc564..a38992320eb 100644 --- a/homeassistant/components/freebox/router.py +++ b/homeassistant/components/freebox/router.py @@ -55,12 +55,13 @@ class FreeboxRouter: self._port = entry.data[CONF_PORT] self._api: Freepybox = None - self._name = None + self.name = None self.mac = None self._sw_v = None self._attrs = {} - self.devices: Dict[str, Any] = {} + self.devices: Dict[str, Dict[str, Any]] = {} + self.disks: Dict[int, Dict[str, Any]] = {} self.sensors_temperature: Dict[str, int] = {} self.sensors_connection: Dict[str, float] = {} self.call_list: List[Dict[str, Any]] = [] @@ -81,7 +82,7 @@ class FreeboxRouter: # System fbx_config = await self._api.system.get_config() self.mac = fbx_config["mac"] - self._name = fbx_config["model_info"]["pretty_name"] + self.name = fbx_config["model_info"]["pretty_name"] self._sw_v = fbx_config["firmware_version"] # Devices & sensors @@ -92,18 +93,18 @@ class FreeboxRouter: async def update_all(self, now: Optional[datetime] = None) -> None: """Update all Freebox platforms.""" + await self.update_device_trackers() await self.update_sensors() - await self.update_devices() - async def update_devices(self) -> None: + async def update_device_trackers(self) -> None: """Update Freebox devices.""" new_device = False - fbx_devices: Dict[str, Any] = await self._api.lan.get_hosts_list() + fbx_devices: [Dict[str, Any]] = await self._api.lan.get_hosts_list() # Adds the Freebox itself fbx_devices.append( { - "primary_name": self._name, + "primary_name": self.name, "l2ident": {"id": self.mac}, "vendor_name": "Freebox SAS", "host_type": "router", @@ -153,8 +154,18 @@ class FreeboxRouter: self.call_list = await self._api.call.get_calls_log() + await self._update_disks_sensors() + async_dispatcher_send(self.hass, self.signal_sensor_update) + async def _update_disks_sensors(self) -> None: + """Update Freebox disks.""" + # None at first request + fbx_disks: [Dict[str, Any]] = await self._api.storage.get_disks() or [] + + for fbx_disk in fbx_disks: + self.disks[fbx_disk["id"]] = fbx_disk + async def reboot(self) -> None: """Reboot the Freebox.""" await self._api.system.reboot() @@ -172,7 +183,7 @@ class FreeboxRouter: return { "connections": {(CONNECTION_NETWORK_MAC, self.mac)}, "identifiers": {(DOMAIN, self.mac)}, - "name": self._name, + "name": self.name, "manufacturer": "Freebox SAS", "sw_version": self._sw_v, } diff --git a/homeassistant/components/freebox/sensor.py b/homeassistant/components/freebox/sensor.py index aeeaba438ff..b8881ad7949 100644 --- a/homeassistant/components/freebox/sensor.py +++ b/homeassistant/components/freebox/sensor.py @@ -1,4 +1,5 @@ """Support for Freebox devices (Freebox v6 and Freebox mini 4K).""" +import logging from typing import Dict from homeassistant.config_entries import ConfigEntry @@ -12,6 +13,7 @@ import homeassistant.util.dt as dt_util from .const import ( CALL_SENSORS, CONNECTION_SENSORS, + DISK_PARTITION_SENSORS, DOMAIN, SENSOR_DEVICE_CLASS, SENSOR_ICON, @@ -21,6 +23,8 @@ from .const import ( ) from .router import FreeboxRouter +_LOGGER = logging.getLogger(__name__) + async def async_setup_entry( hass: HomeAssistantType, entry: ConfigEntry, async_add_entities @@ -29,6 +33,12 @@ async def async_setup_entry( router = hass.data[DOMAIN][entry.unique_id] entities = [] + _LOGGER.debug( + "%s - %s - %s temperature sensors", + router.name, + router.mac, + len(router.sensors_temperature), + ) for sensor_name in router.sensors_temperature: entities.append( FreeboxSensor( @@ -46,6 +56,20 @@ async def async_setup_entry( for sensor_key in CALL_SENSORS: entities.append(FreeboxCallSensor(router, sensor_key, CALL_SENSORS[sensor_key])) + _LOGGER.debug("%s - %s - %s disk(s)", router.name, router.mac, len(router.disks)) + for disk in router.disks.values(): + for partition in disk["partitions"]: + for sensor_key in DISK_PARTITION_SENSORS: + entities.append( + FreeboxDiskSensor( + router, + disk, + partition, + sensor_key, + DISK_PARTITION_SENSORS[sensor_key], + ) + ) + async_add_entities(entities, True) @@ -139,8 +163,8 @@ class FreeboxCallSensor(FreeboxSensor): self, router: FreeboxRouter, sensor_type: str, sensor: Dict[str, any] ) -> None: """Initialize a Freebox call sensor.""" - self._call_list_for_type = [] super().__init__(router, sensor_type, sensor) + self._call_list_for_type = [] @callback def async_update_state(self) -> None: @@ -162,3 +186,43 @@ class FreeboxCallSensor(FreeboxSensor): dt_util.utc_from_timestamp(call["datetime"]).isoformat(): call["name"] for call in self._call_list_for_type } + + +class FreeboxDiskSensor(FreeboxSensor): + """Representation of a Freebox disk sensor.""" + + def __init__( + self, + router: FreeboxRouter, + disk: Dict[str, any], + partition: Dict[str, any], + sensor_type: str, + sensor: Dict[str, any], + ) -> None: + """Initialize a Freebox disk sensor.""" + super().__init__(router, sensor_type, sensor) + self._disk = disk + self._partition = partition + self._name = f"{partition['label']} {sensor[SENSOR_NAME]}" + self._unique_id = f"{self._router.mac} {sensor_type} {self._disk['id']} {self._partition['id']}" + + @property + def device_info(self) -> Dict[str, any]: + """Return the device information.""" + return { + "identifiers": {(DOMAIN, self._disk["id"])}, + "name": f"Disk {self._disk['id']}", + "model": self._disk["model"], + "sw_version": self._disk["firmware"], + "via_device": ( + DOMAIN, + self._router.mac, + ), + } + + @callback + def async_update_state(self) -> None: + """Update the Freebox disk sensor.""" + self._state = round( + self._partition["free_bytes"] * 100 / self._partition["total_bytes"], 2 + )