mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Merge fritzbox_netmonitor integration into fritz (#52264)
* Merge netmonitor integration * cleanup additional files * Use attrs instead of properties * Add state_class to relevant sensors * Update homeassistant/components/fritz/sensor.py Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/fritz/sensor.py Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/fritz/sensor.py Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/fritz/sensor.py Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/fritz/sensor.py Co-authored-by: Franck Nijhof <frenck@frenck.nl> * Update homeassistant/components/fritz/sensor.py Co-authored-by: Franck Nijhof <frenck@frenck.nl> * mypy fix + small cleanup * Round, GB and icons * Update homeassistant/components/fritz/sensor.py Co-authored-by: Franck Nijhof <frenck@frenck.nl> * remove state_class from no-reset counters Co-authored-by: Franck Nijhof <frenck@frenck.nl>
This commit is contained in:
parent
4b7442412a
commit
69b9a9c4ee
@ -348,7 +348,6 @@ omit =
|
|||||||
homeassistant/components/fritzbox_callmonitor/const.py
|
homeassistant/components/fritzbox_callmonitor/const.py
|
||||||
homeassistant/components/fritzbox_callmonitor/base.py
|
homeassistant/components/fritzbox_callmonitor/base.py
|
||||||
homeassistant/components/fritzbox_callmonitor/sensor.py
|
homeassistant/components/fritzbox_callmonitor/sensor.py
|
||||||
homeassistant/components/fritzbox_netmonitor/sensor.py
|
|
||||||
homeassistant/components/fronius/sensor.py
|
homeassistant/components/fronius/sensor.py
|
||||||
homeassistant/components/frontier_silicon/media_player.py
|
homeassistant/components/frontier_silicon/media_player.py
|
||||||
homeassistant/components/futurenow/light.py
|
homeassistant/components/futurenow/light.py
|
||||||
|
@ -8,7 +8,7 @@ from typing import Callable, TypedDict
|
|||||||
from fritzconnection.core.exceptions import FritzConnectionException
|
from fritzconnection.core.exceptions import FritzConnectionException
|
||||||
from fritzconnection.lib.fritzstatus import FritzStatus
|
from fritzconnection.lib.fritzstatus import FritzStatus
|
||||||
|
|
||||||
from homeassistant.components.sensor import SensorEntity
|
from homeassistant.components.sensor import STATE_CLASS_MEASUREMENT, SensorEntity
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import DEVICE_CLASS_TIMESTAMP
|
from homeassistant.const import DEVICE_CLASS_TIMESTAMP
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
@ -42,11 +42,43 @@ def _retrieve_external_ip_state(status: FritzStatus, last_value: str) -> str:
|
|||||||
return status.external_ip
|
return status.external_ip
|
||||||
|
|
||||||
|
|
||||||
class SensorData(TypedDict):
|
def _retrieve_kib_s_sent_state(status: FritzStatus, last_value: str) -> str:
|
||||||
|
"""Return upload transmission rate."""
|
||||||
|
return round(status.transmission_rate[0] * 8 / 1024, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def _retrieve_kib_s_received_state(status: FritzStatus, last_value: str) -> str:
|
||||||
|
"""Return download transmission rate."""
|
||||||
|
return round(status.transmission_rate[1] * 8 / 1024, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def _retrieve_max_kib_s_sent_state(status: FritzStatus, last_value: str) -> str:
|
||||||
|
"""Return upload max transmission rate."""
|
||||||
|
return round(status.max_bit_rate[0] / 1024, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def _retrieve_max_kib_s_received_state(status: FritzStatus, last_value: str) -> str:
|
||||||
|
"""Return download max transmission rate."""
|
||||||
|
return round(status.max_bit_rate[1] / 1024, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def _retrieve_gb_sent_state(status: FritzStatus, last_value: str) -> str:
|
||||||
|
"""Return upload total data."""
|
||||||
|
return round(status.bytes_sent * 8 / 1024 / 1024 / 1024, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def _retrieve_gb_received_state(status: FritzStatus, last_value: str) -> str:
|
||||||
|
"""Return download total data."""
|
||||||
|
return round(status.bytes_received * 8 / 1024 / 1024 / 1024, 1)
|
||||||
|
|
||||||
|
|
||||||
|
class SensorData(TypedDict, total=False):
|
||||||
"""Sensor data class."""
|
"""Sensor data class."""
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
device_class: str | None
|
device_class: str | None
|
||||||
|
state_class: str | None
|
||||||
|
unit_of_measurement: str | None
|
||||||
icon: str | None
|
icon: str | None
|
||||||
state_provider: Callable
|
state_provider: Callable
|
||||||
|
|
||||||
@ -54,16 +86,52 @@ class SensorData(TypedDict):
|
|||||||
SENSOR_DATA = {
|
SENSOR_DATA = {
|
||||||
"external_ip": SensorData(
|
"external_ip": SensorData(
|
||||||
name="External IP",
|
name="External IP",
|
||||||
device_class=None,
|
|
||||||
icon="mdi:earth",
|
icon="mdi:earth",
|
||||||
state_provider=_retrieve_external_ip_state,
|
state_provider=_retrieve_external_ip_state,
|
||||||
),
|
),
|
||||||
"uptime": SensorData(
|
"uptime": SensorData(
|
||||||
name="Uptime",
|
name="Uptime",
|
||||||
device_class=DEVICE_CLASS_TIMESTAMP,
|
device_class=DEVICE_CLASS_TIMESTAMP,
|
||||||
icon=None,
|
|
||||||
state_provider=_retrieve_uptime_state,
|
state_provider=_retrieve_uptime_state,
|
||||||
),
|
),
|
||||||
|
"kib_s_sent": SensorData(
|
||||||
|
name="KiB/s sent",
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
unit_of_measurement="KiB/s",
|
||||||
|
icon="mdi:upload",
|
||||||
|
state_provider=_retrieve_kib_s_sent_state,
|
||||||
|
),
|
||||||
|
"kib_s_received": SensorData(
|
||||||
|
name="KiB/s received",
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
unit_of_measurement="KiB/s",
|
||||||
|
icon="mdi:download",
|
||||||
|
state_provider=_retrieve_kib_s_received_state,
|
||||||
|
),
|
||||||
|
"max_kib_s_sent": SensorData(
|
||||||
|
name="Max KiB/s sent",
|
||||||
|
unit_of_measurement="KiB/s",
|
||||||
|
icon="mdi:upload",
|
||||||
|
state_provider=_retrieve_max_kib_s_sent_state,
|
||||||
|
),
|
||||||
|
"max_kib_s_received": SensorData(
|
||||||
|
name="Max KiB/s received",
|
||||||
|
unit_of_measurement="KiB/s",
|
||||||
|
icon="mdi:download",
|
||||||
|
state_provider=_retrieve_max_kib_s_received_state,
|
||||||
|
),
|
||||||
|
"mb_sent": SensorData(
|
||||||
|
name="GB sent",
|
||||||
|
unit_of_measurement="GB",
|
||||||
|
icon="mdi:upload",
|
||||||
|
state_provider=_retrieve_gb_sent_state,
|
||||||
|
),
|
||||||
|
"mb_received": SensorData(
|
||||||
|
name="GB received",
|
||||||
|
unit_of_measurement="GB",
|
||||||
|
icon="mdi:download",
|
||||||
|
state_provider=_retrieve_gb_received_state,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -97,11 +165,14 @@ class FritzBoxSensor(FritzBoxBaseEntity, SensorEntity):
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Init FRITZ!Box connectivity class."""
|
"""Init FRITZ!Box connectivity class."""
|
||||||
self._sensor_data: SensorData = SENSOR_DATA[sensor_type]
|
self._sensor_data: SensorData = SENSOR_DATA[sensor_type]
|
||||||
self._unique_id = f"{fritzbox_tools.unique_id}-{sensor_type}"
|
|
||||||
self._name = f"{device_friendly_name} {self._sensor_data['name']}"
|
|
||||||
self._is_available = True
|
|
||||||
self._last_value: str | None = None
|
self._last_value: str | None = None
|
||||||
self._state: str | None = None
|
self._attr_available = True
|
||||||
|
self._attr_device_class = self._sensor_data.get("device_class")
|
||||||
|
self._attr_icon = self._sensor_data.get("icon")
|
||||||
|
self._attr_name = f"{device_friendly_name} {self._sensor_data['name']}"
|
||||||
|
self._attr_state_class = self._sensor_data.get("state_class")
|
||||||
|
self._attr_unit_of_measurement = self._sensor_data.get("unit_of_measurement")
|
||||||
|
self._attr_unique_id = f"{fritzbox_tools.unique_id}-{sensor_type}"
|
||||||
super().__init__(fritzbox_tools, device_friendly_name)
|
super().__init__(fritzbox_tools, device_friendly_name)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -109,46 +180,18 @@ class FritzBoxSensor(FritzBoxBaseEntity, SensorEntity):
|
|||||||
"""Return the state provider for the binary sensor."""
|
"""Return the state provider for the binary sensor."""
|
||||||
return self._sensor_data["state_provider"]
|
return self._sensor_data["state_provider"]
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self) -> str:
|
|
||||||
"""Return name."""
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def device_class(self) -> str | None:
|
|
||||||
"""Return device class."""
|
|
||||||
return self._sensor_data["device_class"]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def icon(self) -> str | None:
|
|
||||||
"""Return icon."""
|
|
||||||
return self._sensor_data["icon"]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def unique_id(self) -> str:
|
|
||||||
"""Return unique id."""
|
|
||||||
return self._unique_id
|
|
||||||
|
|
||||||
@property
|
|
||||||
def state(self) -> str | None:
|
|
||||||
"""Return the state of the sensor."""
|
|
||||||
return self._state
|
|
||||||
|
|
||||||
@property
|
|
||||||
def available(self) -> bool:
|
|
||||||
"""Return availability."""
|
|
||||||
return self._is_available
|
|
||||||
|
|
||||||
def update(self) -> None:
|
def update(self) -> None:
|
||||||
"""Update data."""
|
"""Update data."""
|
||||||
_LOGGER.debug("Updating FRITZ!Box sensors")
|
_LOGGER.debug("Updating FRITZ!Box sensors")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
status: FritzStatus = self._fritzbox_tools.fritz_status
|
status: FritzStatus = self._fritzbox_tools.fritz_status
|
||||||
self._is_available = True
|
self._attr_available = True
|
||||||
except FritzConnectionException:
|
except FritzConnectionException:
|
||||||
_LOGGER.error("Error getting the state from the FRITZ!Box", exc_info=True)
|
_LOGGER.error("Error getting the state from the FRITZ!Box", exc_info=True)
|
||||||
self._is_available = False
|
self._attr_available = False
|
||||||
return
|
return
|
||||||
|
|
||||||
self._state = self._last_value = self._state_provider(status, self._last_value)
|
self._attr_state = self._last_value = self._state_provider(
|
||||||
|
status, self._last_value
|
||||||
|
)
|
||||||
|
@ -1 +0,0 @@
|
|||||||
"""The fritzbox_netmonitor component."""
|
|
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"domain": "fritzbox_netmonitor",
|
|
||||||
"name": "AVM FRITZ!Box Net Monitor",
|
|
||||||
"documentation": "https://www.home-assistant.io/integrations/fritzbox_netmonitor",
|
|
||||||
"requirements": ["fritzconnection==1.4.2"],
|
|
||||||
"codeowners": [],
|
|
||||||
"iot_class": "local_polling"
|
|
||||||
}
|
|
@ -1,131 +0,0 @@
|
|||||||
"""Support for monitoring an AVM Fritz!Box router."""
|
|
||||||
from datetime import timedelta
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from fritzconnection.core.exceptions import FritzConnectionException
|
|
||||||
from fritzconnection.lib.fritzstatus import FritzStatus
|
|
||||||
from requests.exceptions import RequestException
|
|
||||||
import voluptuous as vol
|
|
||||||
|
|
||||||
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity
|
|
||||||
from homeassistant.const import CONF_HOST, CONF_NAME, STATE_UNAVAILABLE
|
|
||||||
import homeassistant.helpers.config_validation as cv
|
|
||||||
from homeassistant.util import Throttle
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
DEFAULT_NAME = "fritz_netmonitor"
|
|
||||||
DEFAULT_HOST = "169.254.1.1" # This IP is valid for all FRITZ!Box routers.
|
|
||||||
|
|
||||||
ATTR_BYTES_RECEIVED = "bytes_received"
|
|
||||||
ATTR_BYTES_SENT = "bytes_sent"
|
|
||||||
ATTR_TRANSMISSION_RATE_UP = "transmission_rate_up"
|
|
||||||
ATTR_TRANSMISSION_RATE_DOWN = "transmission_rate_down"
|
|
||||||
ATTR_EXTERNAL_IP = "external_ip"
|
|
||||||
ATTR_IS_CONNECTED = "is_connected"
|
|
||||||
ATTR_IS_LINKED = "is_linked"
|
|
||||||
ATTR_MAX_BYTE_RATE_DOWN = "max_byte_rate_down"
|
|
||||||
ATTR_MAX_BYTE_RATE_UP = "max_byte_rate_up"
|
|
||||||
ATTR_UPTIME = "uptime"
|
|
||||||
|
|
||||||
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=5)
|
|
||||||
|
|
||||||
STATE_ONLINE = "online"
|
|
||||||
STATE_OFFLINE = "offline"
|
|
||||||
|
|
||||||
ICON = "mdi:web"
|
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|
||||||
{
|
|
||||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
|
||||||
vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
|
||||||
"""Set up the FRITZ!Box monitor sensors."""
|
|
||||||
name = config[CONF_NAME]
|
|
||||||
host = config[CONF_HOST]
|
|
||||||
|
|
||||||
try:
|
|
||||||
fstatus = FritzStatus(address=host)
|
|
||||||
except (ValueError, TypeError, FritzConnectionException):
|
|
||||||
fstatus = None
|
|
||||||
|
|
||||||
if fstatus is None:
|
|
||||||
_LOGGER.error("Failed to establish connection to FRITZ!Box: %s", host)
|
|
||||||
return 1
|
|
||||||
_LOGGER.info("Successfully connected to FRITZ!Box")
|
|
||||||
|
|
||||||
add_entities([FritzboxMonitorSensor(name, fstatus)], True)
|
|
||||||
|
|
||||||
|
|
||||||
class FritzboxMonitorSensor(SensorEntity):
|
|
||||||
"""Implementation of a fritzbox monitor sensor."""
|
|
||||||
|
|
||||||
def __init__(self, name, fstatus):
|
|
||||||
"""Initialize the sensor."""
|
|
||||||
self._name = name
|
|
||||||
self._fstatus = fstatus
|
|
||||||
self._state = STATE_UNAVAILABLE
|
|
||||||
self._is_linked = self._is_connected = None
|
|
||||||
self._external_ip = self._uptime = None
|
|
||||||
self._bytes_sent = self._bytes_received = None
|
|
||||||
self._transmission_rate_up = None
|
|
||||||
self._transmission_rate_down = None
|
|
||||||
self._max_byte_rate_up = self._max_byte_rate_down = None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the name of the sensor."""
|
|
||||||
return self._name.rstrip()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def icon(self):
|
|
||||||
"""Icon to use in the frontend, if any."""
|
|
||||||
return ICON
|
|
||||||
|
|
||||||
@property
|
|
||||||
def state(self):
|
|
||||||
"""Return the state of the device."""
|
|
||||||
return self._state
|
|
||||||
|
|
||||||
@property
|
|
||||||
def extra_state_attributes(self):
|
|
||||||
"""Return the device state attributes."""
|
|
||||||
# Don't return attributes if FritzBox is unreachable
|
|
||||||
if self._state == STATE_UNAVAILABLE:
|
|
||||||
return {}
|
|
||||||
return {
|
|
||||||
ATTR_IS_LINKED: self._is_linked,
|
|
||||||
ATTR_IS_CONNECTED: self._is_connected,
|
|
||||||
ATTR_EXTERNAL_IP: self._external_ip,
|
|
||||||
ATTR_UPTIME: self._uptime,
|
|
||||||
ATTR_BYTES_SENT: self._bytes_sent,
|
|
||||||
ATTR_BYTES_RECEIVED: self._bytes_received,
|
|
||||||
ATTR_TRANSMISSION_RATE_UP: self._transmission_rate_up,
|
|
||||||
ATTR_TRANSMISSION_RATE_DOWN: self._transmission_rate_down,
|
|
||||||
ATTR_MAX_BYTE_RATE_UP: self._max_byte_rate_up,
|
|
||||||
ATTR_MAX_BYTE_RATE_DOWN: self._max_byte_rate_down,
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
|
||||||
def update(self):
|
|
||||||
"""Retrieve information from the FritzBox."""
|
|
||||||
try:
|
|
||||||
self._is_linked = self._fstatus.is_linked
|
|
||||||
self._is_connected = self._fstatus.is_connected
|
|
||||||
self._external_ip = self._fstatus.external_ip
|
|
||||||
self._uptime = self._fstatus.uptime
|
|
||||||
self._bytes_sent = self._fstatus.bytes_sent
|
|
||||||
self._bytes_received = self._fstatus.bytes_received
|
|
||||||
transmission_rate = self._fstatus.transmission_rate
|
|
||||||
self._transmission_rate_up = transmission_rate[0]
|
|
||||||
self._transmission_rate_down = transmission_rate[1]
|
|
||||||
self._max_byte_rate_up = self._fstatus.max_byte_rate[0]
|
|
||||||
self._max_byte_rate_down = self._fstatus.max_byte_rate[1]
|
|
||||||
self._state = STATE_ONLINE if self._is_connected else STATE_OFFLINE
|
|
||||||
except RequestException as err:
|
|
||||||
self._state = STATE_UNAVAILABLE
|
|
||||||
_LOGGER.warning("Could not reach FRITZ!Box: %s", err)
|
|
@ -637,7 +637,6 @@ freesms==0.2.0
|
|||||||
|
|
||||||
# homeassistant.components.fritz
|
# homeassistant.components.fritz
|
||||||
# homeassistant.components.fritzbox_callmonitor
|
# homeassistant.components.fritzbox_callmonitor
|
||||||
# homeassistant.components.fritzbox_netmonitor
|
|
||||||
fritzconnection==1.4.2
|
fritzconnection==1.4.2
|
||||||
|
|
||||||
# homeassistant.components.fritz
|
# homeassistant.components.fritz
|
||||||
|
@ -346,7 +346,6 @@ freebox-api==0.0.10
|
|||||||
|
|
||||||
# homeassistant.components.fritz
|
# homeassistant.components.fritz
|
||||||
# homeassistant.components.fritzbox_callmonitor
|
# homeassistant.components.fritzbox_callmonitor
|
||||||
# homeassistant.components.fritzbox_netmonitor
|
|
||||||
fritzconnection==1.4.2
|
fritzconnection==1.4.2
|
||||||
|
|
||||||
# homeassistant.components.fritz
|
# homeassistant.components.fritz
|
||||||
|
Loading…
x
Reference in New Issue
Block a user