Add missed call sensor to Freebox (#36895)
This commit is contained in:
parent
c1ec8971ae
commit
01ba578016
4 changed files with 83 additions and 36 deletions
|
@ -46,6 +46,15 @@ CONNECTION_SENSORS = {
|
|||
},
|
||||
}
|
||||
|
||||
CALL_SENSORS = {
|
||||
"missed": {
|
||||
SENSOR_NAME: "Freebox missed calls",
|
||||
SENSOR_UNIT: None,
|
||||
SENSOR_ICON: "mdi:phone-missed",
|
||||
SENSOR_DEVICE_CLASS: None,
|
||||
},
|
||||
}
|
||||
|
||||
TEMPERATURE_SENSOR_TEMPLATE = {
|
||||
SENSOR_NAME: None,
|
||||
SENSOR_UNIT: TEMP_CELSIUS,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"""Support for Freebox devices (Freebox v6 and Freebox mini 4K)."""
|
||||
from datetime import datetime
|
||||
import logging
|
||||
from typing import Dict
|
||||
|
||||
from homeassistant.components.device_tracker import SOURCE_TYPE_ROUTER
|
||||
|
@ -14,8 +13,6 @@ from homeassistant.helpers.typing import HomeAssistantType
|
|||
from .const import DEFAULT_DEVICE_NAME, DEVICE_ICONS, DOMAIN
|
||||
from .router import FreeboxRouter
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistantType, entry: ConfigEntry, async_add_entities
|
||||
|
@ -65,9 +62,8 @@ class FreeboxDevice(ScannerEntity):
|
|||
self._active = False
|
||||
self._attrs = {}
|
||||
|
||||
self._unsub_dispatcher = None
|
||||
|
||||
def update(self) -> None:
|
||||
@callback
|
||||
def async_update_state(self) -> None:
|
||||
"""Update the Freebox device."""
|
||||
device = self._router.devices[self._mac]
|
||||
self._active = device["active"]
|
||||
|
@ -128,21 +124,24 @@ class FreeboxDevice(ScannerEntity):
|
|||
"""No polling needed."""
|
||||
return False
|
||||
|
||||
async def async_on_demand_update(self):
|
||||
@callback
|
||||
def async_on_demand_update(self):
|
||||
"""Update state."""
|
||||
self.async_schedule_update_ha_state(True)
|
||||
self.async_update_state()
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Register state update callback."""
|
||||
self._unsub_dispatcher = async_dispatcher_connect(
|
||||
self.hass, self._router.signal_device_update, self.async_on_demand_update
|
||||
self.async_update_state()
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
self._router.signal_device_update,
|
||||
self.async_on_demand_update,
|
||||
)
|
||||
)
|
||||
|
||||
async def async_will_remove_from_hass(self):
|
||||
"""Clean up after entity before removal."""
|
||||
self._unsub_dispatcher()
|
||||
|
||||
|
||||
def icon_for_freebox_device(device) -> str:
|
||||
"""Return a host icon from his type."""
|
||||
"""Return a device icon from its type."""
|
||||
return DEVICE_ICONS.get(device["host_type"], "mdi:help-network")
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
from datetime import datetime, timedelta
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Dict, Optional
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from aiofreepybox import Freepybox
|
||||
from aiofreepybox.api.wifi import Wifi
|
||||
|
@ -47,9 +47,10 @@ class FreeboxRouter:
|
|||
self._sw_v = None
|
||||
self._attrs = {}
|
||||
|
||||
self.devices: Dict[str, any] = {}
|
||||
self.devices: Dict[str, Any] = {}
|
||||
self.sensors_temperature: Dict[str, int] = {}
|
||||
self.sensors_connection: Dict[str, float] = {}
|
||||
self.call_list: List[Dict[str, Any]] = []
|
||||
|
||||
self.listeners = []
|
||||
|
||||
|
@ -81,7 +82,7 @@ class FreeboxRouter:
|
|||
async def update_devices(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(
|
||||
|
@ -111,7 +112,7 @@ class FreeboxRouter:
|
|||
async def update_sensors(self) -> None:
|
||||
"""Update Freebox sensors."""
|
||||
# System sensors
|
||||
syst_datas: Dict[str, any] = await self._api.system.get_config()
|
||||
syst_datas: Dict[str, Any] = await self._api.system.get_config()
|
||||
|
||||
# According to the doc `syst_datas["sensors"]` is temperature sensors in celsius degree.
|
||||
# Name and id of sensors may vary under Freebox devices.
|
||||
|
@ -119,7 +120,7 @@ class FreeboxRouter:
|
|||
self.sensors_temperature[sensor["name"]] = sensor["value"]
|
||||
|
||||
# Connection sensors
|
||||
connection_datas: Dict[str, any] = await self._api.connection.get_status()
|
||||
connection_datas: Dict[str, Any] = await self._api.connection.get_status()
|
||||
for sensor_key in CONNECTION_SENSORS:
|
||||
self.sensors_connection[sensor_key] = connection_datas[sensor_key]
|
||||
|
||||
|
@ -134,6 +135,8 @@ class FreeboxRouter:
|
|||
"serial": syst_datas["serial"],
|
||||
}
|
||||
|
||||
self.call_list = await self._api.call.get_call_list()
|
||||
|
||||
async_dispatcher_send(self.hass, self.signal_sensor_update)
|
||||
|
||||
async def reboot(self) -> None:
|
||||
|
@ -147,7 +150,7 @@ class FreeboxRouter:
|
|||
self._api = None
|
||||
|
||||
@property
|
||||
def device_info(self) -> Dict[str, any]:
|
||||
def device_info(self) -> Dict[str, Any]:
|
||||
"""Return the device information."""
|
||||
return {
|
||||
"connections": {(CONNECTION_NETWORK_MAC, self.mac)},
|
||||
|
@ -173,8 +176,8 @@ class FreeboxRouter:
|
|||
return f"{DOMAIN}-{self._host}-sensor-update"
|
||||
|
||||
@property
|
||||
def sensors(self) -> Wifi:
|
||||
"""Return the wifi."""
|
||||
def sensors(self) -> Dict[str, Any]:
|
||||
"""Return sensors."""
|
||||
return {**self.sensors_temperature, **self.sensors_connection}
|
||||
|
||||
@property
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
"""Support for Freebox devices (Freebox v6 and Freebox mini 4K)."""
|
||||
import logging
|
||||
from typing import Dict
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import DATA_RATE_KILOBYTES_PER_SECOND
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from .const import (
|
||||
CALL_SENSORS,
|
||||
CONNECTION_SENSORS,
|
||||
DOMAIN,
|
||||
SENSOR_DEVICE_CLASS,
|
||||
|
@ -19,8 +21,6 @@ from .const import (
|
|||
)
|
||||
from .router import FreeboxRouter
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistantType, entry: ConfigEntry, async_add_entities
|
||||
|
@ -43,6 +43,9 @@ async def async_setup_entry(
|
|||
FreeboxSensor(router, sensor_key, CONNECTION_SENSORS[sensor_key])
|
||||
)
|
||||
|
||||
for sensor_key in CALL_SENSORS:
|
||||
entities.append(FreeboxCallSensor(router, sensor_key, CALL_SENSORS[sensor_key]))
|
||||
|
||||
async_add_entities(entities, True)
|
||||
|
||||
|
||||
|
@ -62,9 +65,8 @@ class FreeboxSensor(Entity):
|
|||
self._device_class = sensor[SENSOR_DEVICE_CLASS]
|
||||
self._unique_id = f"{self._router.mac} {self._name}"
|
||||
|
||||
self._unsub_dispatcher = None
|
||||
|
||||
def update(self) -> None:
|
||||
@callback
|
||||
def async_update_state(self) -> None:
|
||||
"""Update the Freebox sensor."""
|
||||
state = self._router.sensors[self._sensor_type]
|
||||
if self._unit == DATA_RATE_KILOBYTES_PER_SECOND:
|
||||
|
@ -112,16 +114,50 @@ class FreeboxSensor(Entity):
|
|||
"""No polling needed."""
|
||||
return False
|
||||
|
||||
async def async_on_demand_update(self):
|
||||
@callback
|
||||
def async_on_demand_update(self):
|
||||
"""Update state."""
|
||||
self.async_schedule_update_ha_state(True)
|
||||
self.async_update_state()
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Register state update callback."""
|
||||
self._unsub_dispatcher = async_dispatcher_connect(
|
||||
self.hass, self._router.signal_sensor_update, self.async_on_demand_update
|
||||
self.async_update_state()
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(
|
||||
self.hass,
|
||||
self._router.signal_sensor_update,
|
||||
self.async_on_demand_update,
|
||||
)
|
||||
)
|
||||
|
||||
async def async_will_remove_from_hass(self):
|
||||
"""Clean up after entity before removal."""
|
||||
self._unsub_dispatcher()
|
||||
|
||||
class FreeboxCallSensor(FreeboxSensor):
|
||||
"""Representation of a Freebox call sensor."""
|
||||
|
||||
def __init__(
|
||||
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)
|
||||
|
||||
@callback
|
||||
def async_update_state(self) -> None:
|
||||
"""Update the Freebox call sensor."""
|
||||
self._call_list_for_type = []
|
||||
for call in self._router.call_list:
|
||||
if not call["new"]:
|
||||
continue
|
||||
if call["type"] == self._sensor_type:
|
||||
self._call_list_for_type.append(call)
|
||||
|
||||
self._state = len(self._call_list_for_type)
|
||||
|
||||
@property
|
||||
def device_state_attributes(self) -> Dict[str, any]:
|
||||
"""Return device specific state attributes."""
|
||||
return {
|
||||
dt_util.utc_from_timestamp(call["datetime"]).isoformat(): call["name"]
|
||||
for call in self._call_list_for_type
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue