core/homeassistant/components/upnp/__init__.py

287 lines
9.1 KiB
Python
Raw Normal View History

"""Open ports in your router for Home Assistant and provide statistics."""
2021-08-13 16:13:25 +00:00
from __future__ import annotations
2020-08-13 10:11:58 +00:00
import asyncio
2021-08-13 16:13:25 +00:00
from collections.abc import Mapping
from dataclasses import dataclass
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
from datetime import timedelta
2021-08-13 16:13:25 +00:00
from typing import Any
2018-08-17 19:28:29 +00:00
from async_upnp_client.exceptions import UpnpCommunicationError, UpnpConnectionError
2018-08-17 19:28:29 +00:00
from homeassistant.components import ssdp
from homeassistant.components.binary_sensor import BinarySensorEntityDescription
from homeassistant.components.sensor import SensorEntityDescription
2018-08-29 19:19:04 +00:00
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import config_validation as cv, device_registry as dr
from homeassistant.helpers.entity import DeviceInfo
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
UpdateFailed,
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
)
2018-08-17 19:28:29 +00:00
2018-09-01 19:20:15 +00:00
from .const import (
CONFIG_ENTRY_HOST,
CONFIG_ENTRY_MAC_ADDRESS,
CONFIG_ENTRY_ORIGINAL_UDN,
CONFIG_ENTRY_ST,
CONFIG_ENTRY_UDN,
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
DEFAULT_SCAN_INTERVAL,
DOMAIN,
IDENTIFIER_HOST,
IDENTIFIER_SERIAL_NUMBER,
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
LOGGER,
2018-09-01 19:20:15 +00:00
)
from .device import Device, async_create_device
2018-08-17 19:28:29 +00:00
2019-07-31 19:25:30 +00:00
NOTIFICATION_ID = "upnp_notification"
NOTIFICATION_TITLE = "UPnP/IGD Setup"
PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR]
CONFIG_SCHEMA = cv.removed(DOMAIN, raise_if_present=False)
2018-08-17 19:28:29 +00:00
2018-08-29 19:19:04 +00:00
2021-05-27 13:56:20 +00:00
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up UPnP/IGD device from a config entry."""
LOGGER.debug("Setting up config entry: %s", entry.entry_id)
hass.data.setdefault(DOMAIN, {})
2021-05-27 13:56:20 +00:00
udn = entry.data[CONFIG_ENTRY_UDN]
st = entry.data[CONFIG_ENTRY_ST] # pylint: disable=invalid-name
2021-08-13 16:13:25 +00:00
usn = f"{udn}::{st}"
# Register device discovered-callback.
device_discovered_event = asyncio.Event()
discovery_info: ssdp.SsdpServiceInfo | None = None
2021-08-13 16:13:25 +00:00
async def device_discovered(
headers: ssdp.SsdpServiceInfo, change: ssdp.SsdpChange
) -> None:
if change == ssdp.SsdpChange.BYEBYE:
return
2021-08-13 16:13:25 +00:00
nonlocal discovery_info
LOGGER.debug("Device discovered: %s, at: %s", usn, headers.ssdp_location)
discovery_info = headers
2021-08-13 16:13:25 +00:00
device_discovered_event.set()
cancel_discovered_callback = await ssdp.async_register_callback(
2021-08-13 16:13:25 +00:00
hass,
device_discovered,
{
"usn": usn,
},
)
2020-08-13 10:11:58 +00:00
try:
2021-08-13 16:13:25 +00:00
await asyncio.wait_for(device_discovered_event.wait(), timeout=10)
except asyncio.TimeoutError as err:
raise ConfigEntryNotReady(f"Device not discovered: {usn}") from err
2021-08-13 16:13:25 +00:00
finally:
cancel_discovered_callback()
2020-08-13 10:11:58 +00:00
2021-08-13 16:13:25 +00:00
# Create device.
assert discovery_info is not None
assert discovery_info.ssdp_location is not None
location = discovery_info.ssdp_location
2021-10-06 04:31:11 +00:00
try:
device = await async_create_device(hass, location)
2021-10-06 04:31:11 +00:00
except UpnpConnectionError as err:
raise ConfigEntryNotReady(
f"Error connecting to device at location: {location}, err: {err}"
) from err
# Track the original UDN such that existing sensors do not change their unique_id.
if CONFIG_ENTRY_ORIGINAL_UDN not in entry.data:
hass.config_entries.async_update_entry(
2021-05-27 13:56:20 +00:00
entry=entry,
data={
**entry.data,
CONFIG_ENTRY_ORIGINAL_UDN: device.udn,
},
)
device.original_udn = entry.data[CONFIG_ENTRY_ORIGINAL_UDN]
# Store mac address for changed UDN matching.
device_mac_address = await device.async_get_mac_address()
if device_mac_address and not entry.data.get(CONFIG_ENTRY_MAC_ADDRESS):
hass.config_entries.async_update_entry(
2021-05-27 13:56:20 +00:00
entry=entry,
data={
**entry.data,
CONFIG_ENTRY_MAC_ADDRESS: device_mac_address,
CONFIG_ENTRY_HOST: device.host,
},
)
identifiers = {(DOMAIN, device.usn)}
if device.host:
identifiers.add((IDENTIFIER_HOST, device.host))
if device.serial_number:
identifiers.add((IDENTIFIER_SERIAL_NUMBER, device.serial_number))
connections = {(dr.CONNECTION_UPNP, device.udn)}
if device_mac_address:
connections.add((dr.CONNECTION_NETWORK_MAC, device_mac_address))
device_registry = dr.async_get(hass)
device_entry = device_registry.async_get_device(
identifiers=identifiers, connections=connections
)
if device_entry:
LOGGER.debug(
"Found device using connections: %s, device_entry: %s",
connections,
device_entry,
)
if not device_entry:
# No device found, create new device entry.
device_entry = device_registry.async_get_or_create(
config_entry_id=entry.entry_id,
connections=connections,
identifiers=identifiers,
name=device.name,
manufacturer=device.manufacturer,
model=device.model_name,
)
LOGGER.debug(
"Created device using UDN '%s', device_entry: %s", device.udn, device_entry
)
else:
# Update identifier.
device_entry = device_registry.async_update_device(
device_entry.id,
new_identifiers=identifiers,
)
assert device_entry
2022-04-12 21:10:54 +00:00
update_interval = timedelta(seconds=DEFAULT_SCAN_INTERVAL)
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
coordinator = UpnpDataUpdateCoordinator(
hass,
device=device,
device_entry=device_entry,
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
update_interval=update_interval,
)
# Try an initial refresh.
await coordinator.async_config_entry_first_refresh()
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
# Save coordinator.
hass.data[DOMAIN][entry.entry_id] = coordinator
# Setup platforms, creating sensors/binary_sensors.
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
2018-08-17 19:28:29 +00:00
return True
2018-08-29 19:19:04 +00:00
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a UPnP/IGD device from a config entry."""
LOGGER.debug("Unloading config entry: %s", entry.entry_id)
# Unload platforms.
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok:
del hass.data[DOMAIN][entry.entry_id]
return unload_ok
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
@dataclass
class UpnpBinarySensorEntityDescription(BinarySensorEntityDescription):
"""A class that describes UPnP entities."""
format: str = "s"
unique_id: str | None = None
@dataclass
class UpnpSensorEntityDescription(SensorEntityDescription):
"""A class that describes a sensor UPnP entities."""
format: str = "s"
unique_id: str | None = None
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
class UpnpDataUpdateCoordinator(DataUpdateCoordinator):
"""Define an object to update data from UPNP device."""
def __init__(
self,
hass: HomeAssistant,
device: Device,
device_entry: dr.DeviceEntry,
update_interval: timedelta,
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
) -> None:
"""Initialize."""
self.device = device
self.device_entry = device_entry
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
super().__init__(
hass,
LOGGER,
name=device.name,
update_interval=update_interval,
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
)
async def _async_update_data(self) -> Mapping[str, Any]:
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
"""Update data."""
try:
update_values = await asyncio.gather(
self.device.async_get_traffic_data(),
self.device.async_get_status(),
)
except UpnpCommunicationError as exception:
LOGGER.debug(
"Caught exception when updating device: %s, exception: %s",
self.device,
exception,
)
raise UpdateFailed(
f"Unable to communicate with IGD at: {self.device.device_url}"
) from exception
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
return {
**update_values[0],
**update_values[1],
}
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
class UpnpEntity(CoordinatorEntity[UpnpDataUpdateCoordinator]):
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
"""Base class for UPnP/IGD entities."""
entity_description: UpnpSensorEntityDescription | UpnpBinarySensorEntityDescription
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
def __init__(
self,
coordinator: UpnpDataUpdateCoordinator,
entity_description: UpnpSensorEntityDescription
| UpnpBinarySensorEntityDescription,
) -> None:
Add upnp binary sensor for connectivity status (#54489) * New binary sensor for connectivity * Add binary_sensor * New binary sensor for connectivity * Add binary_sensor * Handle values returned as None * Small text update for Uptime * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Updates based on review * Update homeassistant/components/upnp/binary_sensor.py Co-authored-by: Joakim Sørensen <hi@ludeeus.dev> * Further updates based on review * Set device_class as a class atribute * Create 1 combined data coordinator and UpnpEntity class * Updates on coordinator * Update comment * Fix in async_step_init for coordinator * Add async_get_status to mocked device and set times polled for each call seperately * Updated to get device through coordinator Check polling for each status call seperately * Use collections.abc instead of Typing for Mapping * Remove adding device to hass.data as coordinator is now saved * Removed setting _coordinator * Added myself as codeowner * Update type in __init__ * Removed attributes from binary sensor * Fix async_unload_entry * Add expected return value to is_on Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
2021-08-17 18:23:41 +00:00
"""Initialize the base entities."""
super().__init__(coordinator)
self._device = coordinator.device
self.entity_description = entity_description
self._attr_name = f"{coordinator.device.name} {entity_description.name}"
self._attr_unique_id = f"{coordinator.device.original_udn}_{entity_description.unique_id or entity_description.key}"
self._attr_device_info = DeviceInfo(
connections=coordinator.device_entry.connections,
name=coordinator.device_entry.name,
manufacturer=coordinator.device_entry.manufacturer,
model=coordinator.device_entry.model,
configuration_url=coordinator.device_entry.configuration_url,
)
@property
def available(self) -> bool:
"""Return if entity is available."""
return super().available and (
self.coordinator.data.get(self.entity_description.key) is not None
)