core/homeassistant/components/dlna_dmr/data.py

127 lines
4.9 KiB
Python
Raw Normal View History

Config-flow for DLNA-DMR integration (#55267) * Modernize dlna_dmr component: configflow, test, types * Support config-flow with ssdp discovery * Add unit tests * Enforce strict typing * Gracefully handle network devices (dis)appearing * Fix Aiohttp mock response headers type to match actual response class * Fixes from code review * Fixes from code review * Import device config in flow if unavailable at hass start * Support SSDP advertisements * Ignore bad BOOTID, fix ssdp:byebye handling * Only listen for events on interface connected to device * Release all listeners when entities are removed * Warn about deprecated dlna_dmr configuration * Use sublogger for dlna_dmr.config_flow for easier filtering * Tests for dlna_dmr.data module * Rewrite DMR tests for HA style * Fix DMR strings: "Digital Media *Renderer*" * Update DMR entity state and device info when changed * Replace deprecated async_upnp_client State with TransportState * supported_features are dynamic, based on current device state * Cleanup fully when subscription fails * Log warnings when device connection fails unexpectedly * Set PARALLEL_UPDATES to unlimited * Fix spelling * Fixes from code review * Simplify has & can checks to just can, which includes has * Treat transitioning state as playing (not idle) to reduce UI jerking * Test if device is usable * Handle ssdp:update messages properly * Fix _remove_ssdp_callbacks being shared by all DlnaDmrEntity instances * Fix tests for transitioning state * Mock DmrDevice.is_profile_device (added to support embedded devices) * Use ST & NT SSDP headers to find DMR devices, not deviceType The deviceType is extracted from the device's description XML, and will not be what we want when dealing with embedded devices. * Use UDN from SSDP headers, not device description, as unique_id The SSDP headers have the UDN of the embedded device that we're interested in, whereas the device description (`ATTR_UPNP_UDN`) field will always be for the root device. * Fix DMR string English localization * Test config flow with UDN from SSDP headers * Bump async-upnp-client==0.22.1, fix flake8 error * fix test for remapping * DMR HA Device connections based on root and embedded UDN * DmrDevice's UpnpDevice is now named profile_device * Use device type from SSDP headers, not device description * Mark dlna_dmr constants as Final * Use embedded device UDN and type for unique ID when connected via URL * More informative connection error messages * Also match SSDP messages on NT headers The NT header is to ssdp:alive messages what ST is to M-SEARCH responses. * Bump async-upnp-client==0.22.2 * fix merge * Bump async-upnp-client==0.22.3 Co-authored-by: Steven Looman <steven.looman@gmail.com> Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-27 20:47:01 +00:00
"""Data used by this integration."""
from __future__ import annotations
import asyncio
from collections import defaultdict
Improve dlna_dmr code quality (#56886) * Listen for config updates from DlnaDmrEntity.async_added_to_hass Use `Entity.async_on_remove` for dealing with callback cancellation, instead of re-inventing the wheel with `_remove_ssdp_callbacks`. * Use async_write_ha_state within async methods * Import YAML config from async_setup_platform * Import flow prompts user when device is uncontactable during migration When config flow is able to contact a device, or when it has information from SSDP, it will create config entries without error. If the device is uncontactable at this point then it will appear as unavailable in HA until it is turned on again. When import flow cannot migrate an entry because it needs to contact the device and can't, it will notify the user with a config flow form. * Don't del unused parameters, HA pylint doesn't care * Remove unused imports from tests * Abort config flow at earliest opportunity * Return async_abort instead of raising AbortFlow * Consolidate config entry test cleanup into a single function * fixup! Consolidate config entry test cleanup into a single function Revert "Consolidate config entry test cleanup into a single function" This reverts commit 8220da7263e346a37c3e1a219dc374c4a43c7df5. * Check resource acquisition/release in specific tests * fixup! Check resource acquisition/release in specific tests * Remove unused network dependency from manifest * _on_event runs in async context * Call async_write_ha_state directly (not via shedule_update) Co-authored-by: Martin Hjelmare <marhje52@gmail.com> Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-10-07 20:14:00 +00:00
from typing import NamedTuple, cast
Config-flow for DLNA-DMR integration (#55267) * Modernize dlna_dmr component: configflow, test, types * Support config-flow with ssdp discovery * Add unit tests * Enforce strict typing * Gracefully handle network devices (dis)appearing * Fix Aiohttp mock response headers type to match actual response class * Fixes from code review * Fixes from code review * Import device config in flow if unavailable at hass start * Support SSDP advertisements * Ignore bad BOOTID, fix ssdp:byebye handling * Only listen for events on interface connected to device * Release all listeners when entities are removed * Warn about deprecated dlna_dmr configuration * Use sublogger for dlna_dmr.config_flow for easier filtering * Tests for dlna_dmr.data module * Rewrite DMR tests for HA style * Fix DMR strings: "Digital Media *Renderer*" * Update DMR entity state and device info when changed * Replace deprecated async_upnp_client State with TransportState * supported_features are dynamic, based on current device state * Cleanup fully when subscription fails * Log warnings when device connection fails unexpectedly * Set PARALLEL_UPDATES to unlimited * Fix spelling * Fixes from code review * Simplify has & can checks to just can, which includes has * Treat transitioning state as playing (not idle) to reduce UI jerking * Test if device is usable * Handle ssdp:update messages properly * Fix _remove_ssdp_callbacks being shared by all DlnaDmrEntity instances * Fix tests for transitioning state * Mock DmrDevice.is_profile_device (added to support embedded devices) * Use ST & NT SSDP headers to find DMR devices, not deviceType The deviceType is extracted from the device's description XML, and will not be what we want when dealing with embedded devices. * Use UDN from SSDP headers, not device description, as unique_id The SSDP headers have the UDN of the embedded device that we're interested in, whereas the device description (`ATTR_UPNP_UDN`) field will always be for the root device. * Fix DMR string English localization * Test config flow with UDN from SSDP headers * Bump async-upnp-client==0.22.1, fix flake8 error * fix test for remapping * DMR HA Device connections based on root and embedded UDN * DmrDevice's UpnpDevice is now named profile_device * Use device type from SSDP headers, not device description * Mark dlna_dmr constants as Final * Use embedded device UDN and type for unique ID when connected via URL * More informative connection error messages * Also match SSDP messages on NT headers The NT header is to ssdp:alive messages what ST is to M-SEARCH responses. * Bump async-upnp-client==0.22.2 * fix merge * Bump async-upnp-client==0.22.3 Co-authored-by: Steven Looman <steven.looman@gmail.com> Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-27 20:47:01 +00:00
from async_upnp_client.aiohttp import AiohttpNotifyServer, AiohttpSessionRequester
from async_upnp_client.client import UpnpRequester
from async_upnp_client.client_factory import UpnpFactory
from async_upnp_client.event_handler import UpnpEventHandler
Config-flow for DLNA-DMR integration (#55267) * Modernize dlna_dmr component: configflow, test, types * Support config-flow with ssdp discovery * Add unit tests * Enforce strict typing * Gracefully handle network devices (dis)appearing * Fix Aiohttp mock response headers type to match actual response class * Fixes from code review * Fixes from code review * Import device config in flow if unavailable at hass start * Support SSDP advertisements * Ignore bad BOOTID, fix ssdp:byebye handling * Only listen for events on interface connected to device * Release all listeners when entities are removed * Warn about deprecated dlna_dmr configuration * Use sublogger for dlna_dmr.config_flow for easier filtering * Tests for dlna_dmr.data module * Rewrite DMR tests for HA style * Fix DMR strings: "Digital Media *Renderer*" * Update DMR entity state and device info when changed * Replace deprecated async_upnp_client State with TransportState * supported_features are dynamic, based on current device state * Cleanup fully when subscription fails * Log warnings when device connection fails unexpectedly * Set PARALLEL_UPDATES to unlimited * Fix spelling * Fixes from code review * Simplify has & can checks to just can, which includes has * Treat transitioning state as playing (not idle) to reduce UI jerking * Test if device is usable * Handle ssdp:update messages properly * Fix _remove_ssdp_callbacks being shared by all DlnaDmrEntity instances * Fix tests for transitioning state * Mock DmrDevice.is_profile_device (added to support embedded devices) * Use ST & NT SSDP headers to find DMR devices, not deviceType The deviceType is extracted from the device's description XML, and will not be what we want when dealing with embedded devices. * Use UDN from SSDP headers, not device description, as unique_id The SSDP headers have the UDN of the embedded device that we're interested in, whereas the device description (`ATTR_UPNP_UDN`) field will always be for the root device. * Fix DMR string English localization * Test config flow with UDN from SSDP headers * Bump async-upnp-client==0.22.1, fix flake8 error * fix test for remapping * DMR HA Device connections based on root and embedded UDN * DmrDevice's UpnpDevice is now named profile_device * Use device type from SSDP headers, not device description * Mark dlna_dmr constants as Final * Use embedded device UDN and type for unique ID when connected via URL * More informative connection error messages * Also match SSDP messages on NT headers The NT header is to ssdp:alive messages what ST is to M-SEARCH responses. * Bump async-upnp-client==0.22.2 * fix merge * Bump async-upnp-client==0.22.3 Co-authored-by: Steven Looman <steven.looman@gmail.com> Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-27 20:47:01 +00:00
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
from homeassistant.core import CALLBACK_TYPE, Event, HomeAssistant
from homeassistant.helpers import aiohttp_client
from .const import DOMAIN, LOGGER
class EventListenAddr(NamedTuple):
"""Unique identifier for an event listener."""
host: str | None # Specific local IP(v6) address for listening on
port: int # Listening port, 0 means use an ephemeral port
callback_url: str | None
class DlnaDmrData:
"""Storage class for domain global data."""
lock: asyncio.Lock
requester: UpnpRequester
upnp_factory: UpnpFactory
event_notifiers: dict[EventListenAddr, AiohttpNotifyServer]
event_notifier_refs: defaultdict[EventListenAddr, int]
stop_listener_remove: CALLBACK_TYPE | None = None
def __init__(self, hass: HomeAssistant) -> None:
"""Initialize global data."""
self.lock = asyncio.Lock()
session = aiohttp_client.async_get_clientsession(hass, verify_ssl=False)
self.requester = AiohttpSessionRequester(session, with_sleep=True)
Config-flow for DLNA-DMR integration (#55267) * Modernize dlna_dmr component: configflow, test, types * Support config-flow with ssdp discovery * Add unit tests * Enforce strict typing * Gracefully handle network devices (dis)appearing * Fix Aiohttp mock response headers type to match actual response class * Fixes from code review * Fixes from code review * Import device config in flow if unavailable at hass start * Support SSDP advertisements * Ignore bad BOOTID, fix ssdp:byebye handling * Only listen for events on interface connected to device * Release all listeners when entities are removed * Warn about deprecated dlna_dmr configuration * Use sublogger for dlna_dmr.config_flow for easier filtering * Tests for dlna_dmr.data module * Rewrite DMR tests for HA style * Fix DMR strings: "Digital Media *Renderer*" * Update DMR entity state and device info when changed * Replace deprecated async_upnp_client State with TransportState * supported_features are dynamic, based on current device state * Cleanup fully when subscription fails * Log warnings when device connection fails unexpectedly * Set PARALLEL_UPDATES to unlimited * Fix spelling * Fixes from code review * Simplify has & can checks to just can, which includes has * Treat transitioning state as playing (not idle) to reduce UI jerking * Test if device is usable * Handle ssdp:update messages properly * Fix _remove_ssdp_callbacks being shared by all DlnaDmrEntity instances * Fix tests for transitioning state * Mock DmrDevice.is_profile_device (added to support embedded devices) * Use ST & NT SSDP headers to find DMR devices, not deviceType The deviceType is extracted from the device's description XML, and will not be what we want when dealing with embedded devices. * Use UDN from SSDP headers, not device description, as unique_id The SSDP headers have the UDN of the embedded device that we're interested in, whereas the device description (`ATTR_UPNP_UDN`) field will always be for the root device. * Fix DMR string English localization * Test config flow with UDN from SSDP headers * Bump async-upnp-client==0.22.1, fix flake8 error * fix test for remapping * DMR HA Device connections based on root and embedded UDN * DmrDevice's UpnpDevice is now named profile_device * Use device type from SSDP headers, not device description * Mark dlna_dmr constants as Final * Use embedded device UDN and type for unique ID when connected via URL * More informative connection error messages * Also match SSDP messages on NT headers The NT header is to ssdp:alive messages what ST is to M-SEARCH responses. * Bump async-upnp-client==0.22.2 * fix merge * Bump async-upnp-client==0.22.3 Co-authored-by: Steven Looman <steven.looman@gmail.com> Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-27 20:47:01 +00:00
self.upnp_factory = UpnpFactory(self.requester, non_strict=True)
self.event_notifiers = {}
self.event_notifier_refs = defaultdict(int)
async def async_cleanup_event_notifiers(self, event: Event) -> None:
"""Clean up resources when Home Assistant is stopped."""
LOGGER.debug("Cleaning resources in DlnaDmrData")
async with self.lock:
tasks = (
server.async_stop_server() for server in self.event_notifiers.values()
)
Config-flow for DLNA-DMR integration (#55267) * Modernize dlna_dmr component: configflow, test, types * Support config-flow with ssdp discovery * Add unit tests * Enforce strict typing * Gracefully handle network devices (dis)appearing * Fix Aiohttp mock response headers type to match actual response class * Fixes from code review * Fixes from code review * Import device config in flow if unavailable at hass start * Support SSDP advertisements * Ignore bad BOOTID, fix ssdp:byebye handling * Only listen for events on interface connected to device * Release all listeners when entities are removed * Warn about deprecated dlna_dmr configuration * Use sublogger for dlna_dmr.config_flow for easier filtering * Tests for dlna_dmr.data module * Rewrite DMR tests for HA style * Fix DMR strings: "Digital Media *Renderer*" * Update DMR entity state and device info when changed * Replace deprecated async_upnp_client State with TransportState * supported_features are dynamic, based on current device state * Cleanup fully when subscription fails * Log warnings when device connection fails unexpectedly * Set PARALLEL_UPDATES to unlimited * Fix spelling * Fixes from code review * Simplify has & can checks to just can, which includes has * Treat transitioning state as playing (not idle) to reduce UI jerking * Test if device is usable * Handle ssdp:update messages properly * Fix _remove_ssdp_callbacks being shared by all DlnaDmrEntity instances * Fix tests for transitioning state * Mock DmrDevice.is_profile_device (added to support embedded devices) * Use ST & NT SSDP headers to find DMR devices, not deviceType The deviceType is extracted from the device's description XML, and will not be what we want when dealing with embedded devices. * Use UDN from SSDP headers, not device description, as unique_id The SSDP headers have the UDN of the embedded device that we're interested in, whereas the device description (`ATTR_UPNP_UDN`) field will always be for the root device. * Fix DMR string English localization * Test config flow with UDN from SSDP headers * Bump async-upnp-client==0.22.1, fix flake8 error * fix test for remapping * DMR HA Device connections based on root and embedded UDN * DmrDevice's UpnpDevice is now named profile_device * Use device type from SSDP headers, not device description * Mark dlna_dmr constants as Final * Use embedded device UDN and type for unique ID when connected via URL * More informative connection error messages * Also match SSDP messages on NT headers The NT header is to ssdp:alive messages what ST is to M-SEARCH responses. * Bump async-upnp-client==0.22.2 * fix merge * Bump async-upnp-client==0.22.3 Co-authored-by: Steven Looman <steven.looman@gmail.com> Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-27 20:47:01 +00:00
asyncio.gather(*tasks)
self.event_notifiers = {}
self.event_notifier_refs = defaultdict(int)
async def async_get_event_notifier(
self, listen_addr: EventListenAddr, hass: HomeAssistant
) -> UpnpEventHandler:
"""Return existing event notifier for the listen_addr, or create one.
Only one event notify server is kept for each listen_addr. Must call
async_release_event_notifier when done to cleanup resources.
"""
LOGGER.debug("Getting event handler for %s", listen_addr)
async with self.lock:
# Stop all servers when HA shuts down, to release resources on devices
if not self.stop_listener_remove:
self.stop_listener_remove = hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_STOP, self.async_cleanup_event_notifiers
)
# Always increment the reference counter, for existing or new event handlers
self.event_notifier_refs[listen_addr] += 1
# Return an existing event handler if we can
if listen_addr in self.event_notifiers:
return self.event_notifiers[listen_addr].event_handler
# Start event handler
source = (listen_addr.host or "0.0.0.0", listen_addr.port)
Config-flow for DLNA-DMR integration (#55267) * Modernize dlna_dmr component: configflow, test, types * Support config-flow with ssdp discovery * Add unit tests * Enforce strict typing * Gracefully handle network devices (dis)appearing * Fix Aiohttp mock response headers type to match actual response class * Fixes from code review * Fixes from code review * Import device config in flow if unavailable at hass start * Support SSDP advertisements * Ignore bad BOOTID, fix ssdp:byebye handling * Only listen for events on interface connected to device * Release all listeners when entities are removed * Warn about deprecated dlna_dmr configuration * Use sublogger for dlna_dmr.config_flow for easier filtering * Tests for dlna_dmr.data module * Rewrite DMR tests for HA style * Fix DMR strings: "Digital Media *Renderer*" * Update DMR entity state and device info when changed * Replace deprecated async_upnp_client State with TransportState * supported_features are dynamic, based on current device state * Cleanup fully when subscription fails * Log warnings when device connection fails unexpectedly * Set PARALLEL_UPDATES to unlimited * Fix spelling * Fixes from code review * Simplify has & can checks to just can, which includes has * Treat transitioning state as playing (not idle) to reduce UI jerking * Test if device is usable * Handle ssdp:update messages properly * Fix _remove_ssdp_callbacks being shared by all DlnaDmrEntity instances * Fix tests for transitioning state * Mock DmrDevice.is_profile_device (added to support embedded devices) * Use ST & NT SSDP headers to find DMR devices, not deviceType The deviceType is extracted from the device's description XML, and will not be what we want when dealing with embedded devices. * Use UDN from SSDP headers, not device description, as unique_id The SSDP headers have the UDN of the embedded device that we're interested in, whereas the device description (`ATTR_UPNP_UDN`) field will always be for the root device. * Fix DMR string English localization * Test config flow with UDN from SSDP headers * Bump async-upnp-client==0.22.1, fix flake8 error * fix test for remapping * DMR HA Device connections based on root and embedded UDN * DmrDevice's UpnpDevice is now named profile_device * Use device type from SSDP headers, not device description * Mark dlna_dmr constants as Final * Use embedded device UDN and type for unique ID when connected via URL * More informative connection error messages * Also match SSDP messages on NT headers The NT header is to ssdp:alive messages what ST is to M-SEARCH responses. * Bump async-upnp-client==0.22.2 * fix merge * Bump async-upnp-client==0.22.3 Co-authored-by: Steven Looman <steven.looman@gmail.com> Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-27 20:47:01 +00:00
server = AiohttpNotifyServer(
requester=self.requester,
source=source,
Config-flow for DLNA-DMR integration (#55267) * Modernize dlna_dmr component: configflow, test, types * Support config-flow with ssdp discovery * Add unit tests * Enforce strict typing * Gracefully handle network devices (dis)appearing * Fix Aiohttp mock response headers type to match actual response class * Fixes from code review * Fixes from code review * Import device config in flow if unavailable at hass start * Support SSDP advertisements * Ignore bad BOOTID, fix ssdp:byebye handling * Only listen for events on interface connected to device * Release all listeners when entities are removed * Warn about deprecated dlna_dmr configuration * Use sublogger for dlna_dmr.config_flow for easier filtering * Tests for dlna_dmr.data module * Rewrite DMR tests for HA style * Fix DMR strings: "Digital Media *Renderer*" * Update DMR entity state and device info when changed * Replace deprecated async_upnp_client State with TransportState * supported_features are dynamic, based on current device state * Cleanup fully when subscription fails * Log warnings when device connection fails unexpectedly * Set PARALLEL_UPDATES to unlimited * Fix spelling * Fixes from code review * Simplify has & can checks to just can, which includes has * Treat transitioning state as playing (not idle) to reduce UI jerking * Test if device is usable * Handle ssdp:update messages properly * Fix _remove_ssdp_callbacks being shared by all DlnaDmrEntity instances * Fix tests for transitioning state * Mock DmrDevice.is_profile_device (added to support embedded devices) * Use ST & NT SSDP headers to find DMR devices, not deviceType The deviceType is extracted from the device's description XML, and will not be what we want when dealing with embedded devices. * Use UDN from SSDP headers, not device description, as unique_id The SSDP headers have the UDN of the embedded device that we're interested in, whereas the device description (`ATTR_UPNP_UDN`) field will always be for the root device. * Fix DMR string English localization * Test config flow with UDN from SSDP headers * Bump async-upnp-client==0.22.1, fix flake8 error * fix test for remapping * DMR HA Device connections based on root and embedded UDN * DmrDevice's UpnpDevice is now named profile_device * Use device type from SSDP headers, not device description * Mark dlna_dmr constants as Final * Use embedded device UDN and type for unique ID when connected via URL * More informative connection error messages * Also match SSDP messages on NT headers The NT header is to ssdp:alive messages what ST is to M-SEARCH responses. * Bump async-upnp-client==0.22.2 * fix merge * Bump async-upnp-client==0.22.3 Co-authored-by: Steven Looman <steven.looman@gmail.com> Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-27 20:47:01 +00:00
callback_url=listen_addr.callback_url,
loop=hass.loop,
)
await server.async_start_server()
Config-flow for DLNA-DMR integration (#55267) * Modernize dlna_dmr component: configflow, test, types * Support config-flow with ssdp discovery * Add unit tests * Enforce strict typing * Gracefully handle network devices (dis)appearing * Fix Aiohttp mock response headers type to match actual response class * Fixes from code review * Fixes from code review * Import device config in flow if unavailable at hass start * Support SSDP advertisements * Ignore bad BOOTID, fix ssdp:byebye handling * Only listen for events on interface connected to device * Release all listeners when entities are removed * Warn about deprecated dlna_dmr configuration * Use sublogger for dlna_dmr.config_flow for easier filtering * Tests for dlna_dmr.data module * Rewrite DMR tests for HA style * Fix DMR strings: "Digital Media *Renderer*" * Update DMR entity state and device info when changed * Replace deprecated async_upnp_client State with TransportState * supported_features are dynamic, based on current device state * Cleanup fully when subscription fails * Log warnings when device connection fails unexpectedly * Set PARALLEL_UPDATES to unlimited * Fix spelling * Fixes from code review * Simplify has & can checks to just can, which includes has * Treat transitioning state as playing (not idle) to reduce UI jerking * Test if device is usable * Handle ssdp:update messages properly * Fix _remove_ssdp_callbacks being shared by all DlnaDmrEntity instances * Fix tests for transitioning state * Mock DmrDevice.is_profile_device (added to support embedded devices) * Use ST & NT SSDP headers to find DMR devices, not deviceType The deviceType is extracted from the device's description XML, and will not be what we want when dealing with embedded devices. * Use UDN from SSDP headers, not device description, as unique_id The SSDP headers have the UDN of the embedded device that we're interested in, whereas the device description (`ATTR_UPNP_UDN`) field will always be for the root device. * Fix DMR string English localization * Test config flow with UDN from SSDP headers * Bump async-upnp-client==0.22.1, fix flake8 error * fix test for remapping * DMR HA Device connections based on root and embedded UDN * DmrDevice's UpnpDevice is now named profile_device * Use device type from SSDP headers, not device description * Mark dlna_dmr constants as Final * Use embedded device UDN and type for unique ID when connected via URL * More informative connection error messages * Also match SSDP messages on NT headers The NT header is to ssdp:alive messages what ST is to M-SEARCH responses. * Bump async-upnp-client==0.22.2 * fix merge * Bump async-upnp-client==0.22.3 Co-authored-by: Steven Looman <steven.looman@gmail.com> Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-27 20:47:01 +00:00
LOGGER.debug("Started event handler at %s", server.callback_url)
self.event_notifiers[listen_addr] = server
return server.event_handler
async def async_release_event_notifier(self, listen_addr: EventListenAddr) -> None:
"""Indicate that the event notifier for listen_addr is not used anymore.
This is called once by each caller of async_get_event_notifier, and will
stop the listening server when all users are done.
"""
async with self.lock:
assert self.event_notifier_refs[listen_addr] > 0
self.event_notifier_refs[listen_addr] -= 1
# Shutdown the server when it has no more users
if self.event_notifier_refs[listen_addr] == 0:
server = self.event_notifiers.pop(listen_addr)
await server.async_stop_server()
Config-flow for DLNA-DMR integration (#55267) * Modernize dlna_dmr component: configflow, test, types * Support config-flow with ssdp discovery * Add unit tests * Enforce strict typing * Gracefully handle network devices (dis)appearing * Fix Aiohttp mock response headers type to match actual response class * Fixes from code review * Fixes from code review * Import device config in flow if unavailable at hass start * Support SSDP advertisements * Ignore bad BOOTID, fix ssdp:byebye handling * Only listen for events on interface connected to device * Release all listeners when entities are removed * Warn about deprecated dlna_dmr configuration * Use sublogger for dlna_dmr.config_flow for easier filtering * Tests for dlna_dmr.data module * Rewrite DMR tests for HA style * Fix DMR strings: "Digital Media *Renderer*" * Update DMR entity state and device info when changed * Replace deprecated async_upnp_client State with TransportState * supported_features are dynamic, based on current device state * Cleanup fully when subscription fails * Log warnings when device connection fails unexpectedly * Set PARALLEL_UPDATES to unlimited * Fix spelling * Fixes from code review * Simplify has & can checks to just can, which includes has * Treat transitioning state as playing (not idle) to reduce UI jerking * Test if device is usable * Handle ssdp:update messages properly * Fix _remove_ssdp_callbacks being shared by all DlnaDmrEntity instances * Fix tests for transitioning state * Mock DmrDevice.is_profile_device (added to support embedded devices) * Use ST & NT SSDP headers to find DMR devices, not deviceType The deviceType is extracted from the device's description XML, and will not be what we want when dealing with embedded devices. * Use UDN from SSDP headers, not device description, as unique_id The SSDP headers have the UDN of the embedded device that we're interested in, whereas the device description (`ATTR_UPNP_UDN`) field will always be for the root device. * Fix DMR string English localization * Test config flow with UDN from SSDP headers * Bump async-upnp-client==0.22.1, fix flake8 error * fix test for remapping * DMR HA Device connections based on root and embedded UDN * DmrDevice's UpnpDevice is now named profile_device * Use device type from SSDP headers, not device description * Mark dlna_dmr constants as Final * Use embedded device UDN and type for unique ID when connected via URL * More informative connection error messages * Also match SSDP messages on NT headers The NT header is to ssdp:alive messages what ST is to M-SEARCH responses. * Bump async-upnp-client==0.22.2 * fix merge * Bump async-upnp-client==0.22.3 Co-authored-by: Steven Looman <steven.looman@gmail.com> Co-authored-by: J. Nick Koston <nick@koston.org>
2021-09-27 20:47:01 +00:00
# Remove the cleanup listener when there's nothing left to cleanup
if not self.event_notifiers:
assert self.stop_listener_remove is not None
self.stop_listener_remove()
self.stop_listener_remove = None
def get_domain_data(hass: HomeAssistant) -> DlnaDmrData:
"""Obtain this integration's domain data, creating it if needed."""
if DOMAIN in hass.data:
return cast(DlnaDmrData, hass.data[DOMAIN])
data = DlnaDmrData(hass)
hass.data[DOMAIN] = data
return data