async def async_start(self) -> None: """Start the scanner.""" self.description_manager = DescriptionManager(self.hass) self.flow_dispatcher = FlowDispatcher(self.hass) for source_ip in await self._async_build_source_set(): self._ssdp_listeners.append( SSDPListener(async_callback=self._async_process_entry, source_ip=source_ip)) try: IPv4Address(source_ip) except ValueError: continue # Some sonos devices only seem to respond if we send to the broadcast # address. This matches pysonos' behavior # https://github.com/amelchio/pysonos/blob/d4329b4abb657d106394ae69357805269708c996/pysonos/discovery.py#L120 self._ssdp_listeners.append( SSDPListener( async_callback=self._async_process_entry, source_ip=source_ip, target_ip=IPV4_BROADCAST, )) self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self.async_stop) self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, self.flow_dispatcher.async_start) await asyncio.gather( *[listener.async_start() for listener in self._ssdp_listeners]) self._cancel_scan = async_track_time_interval(self.hass, self.async_scan, SCAN_INTERVAL)
def _patched_ssdp_listener(info, *args, **kwargs): listener = SSDPListener(*args, **kwargs) async def _async_callback(*_): await listener.async_callback(info) listener.async_start = _async_callback return listener
def _generate_failing_ssdp_listener(*args, **kwargs): create_args.append([args, kwargs]) listener = SSDPListener(*args, **kwargs) async def _async_callback(*_): if kwargs["source_ip"] == IPv6Address("2001:db8::"): raise OSError pass listener.async_start = _async_callback listener.async_search = _callback return listener
def _generate_fake_ssdp_listener(*args, **kwargs): listener = SSDPListener(*args, **kwargs) async def _async_callback(*_): pass @callback def _callback(*_): hass.async_create_task(listener.async_callback(mock_ssdp_response)) listener.async_start = _async_callback listener.async_search = _callback return listener
def _generate_fake_ssdp_listener(*args, **kwargs): create_args.append([args, kwargs]) listener = SSDPListener(*args, **kwargs) async def _async_callback(*_): pass @callback def _callback(*_): pass listener.async_start = _async_callback listener.async_search = _callback return listener
def _patched_ssdp_listener(info, *args, **kwargs): listener = SSDPListener(*args, **kwargs) async def _async_callback(*_): await listener.async_callback(info) @callback def _async_search(*_): # Prevent an actual scan. pass listener.async_start = _async_callback listener.async_search = _async_search return listener
def _generate_fake_ssdp_listener(*args, **kwargs): listener = SSDPListener(*args, **kwargs) async def _async_callback(*_): pass @callback def _callback(*args): nonlocal search_args search_args.append(args) pass listener.async_start = _async_callback listener.async_search = _callback return listener
async def async_start(self) -> None: """Start the scanner.""" self.description_manager = DescriptionManager(self.hass) self.flow_dispatcher = FlowDispatcher(self.hass) for source_ip in await self._async_build_source_set(): self._ssdp_listeners.append( SSDPListener( async_connect_callback=self.async_scan, async_callback=self._async_process_entry, source_ip=source_ip, ) ) self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self.async_stop) self.hass.bus.async_listen_once( EVENT_HOMEASSISTANT_STARTED, self.flow_dispatcher.async_start ) results = await asyncio.gather( *(listener.async_start() for listener in self._ssdp_listeners), return_exceptions=True, ) failed_listeners = [] for idx, result in enumerate(results): if isinstance(result, Exception): _LOGGER.warning( "Failed to setup listener for %s: %s", self._ssdp_listeners[idx].source_ip, result, ) failed_listeners.append(self._ssdp_listeners[idx]) for listener in failed_listeners: self._ssdp_listeners.remove(listener) self._cancel_scan = async_track_time_interval( self.hass, self.async_scan, SCAN_INTERVAL )
def _patched_ssdp_listener(info, *args, **kwargs): listener = SSDPListener(*args, **kwargs) async def _async_callback(*_): if kwargs["source_ip"] == IPv4Address(FAIL_TO_BIND_IP): raise OSError await listener.async_connect_callback() @callback def _async_search(*_): if info: asyncio.create_task(listener.async_callback(info)) listener.async_start = _async_callback listener.async_search = _async_search return listener
async def async_setup(self): """Set up the scanner.""" if self._connected_events: await asyncio.gather(*(event.wait() for event in self._connected_events)) return for idx, source_ip in enumerate(await self._async_build_source_set()): self._connected_events.append(asyncio.Event()) def _wrap_async_connected_idx(idx): """Create a function to capture the idx cell variable.""" async def _async_connected(): self._connected_events[idx].set() return _async_connected self._listeners.append( SSDPListener( async_callback=self._async_process_entry, service_type=SSDP_ST, target=SSDP_TARGET, source_ip=source_ip, async_connect_callback=_wrap_async_connected_idx(idx), )) results = await asyncio.gather( *(listener.async_start() for listener in self._listeners), return_exceptions=True, ) failed_listeners = [] for idx, result in enumerate(results): if not isinstance(result, Exception): continue _LOGGER.warning( "Failed to setup listener for %s: %s", self._listeners[idx].source_ip, result, ) failed_listeners.append(self._listeners[idx]) self._connected_events[idx].set() for listener in failed_listeners: self._listeners.remove(listener) await asyncio.gather(*(event.wait() for event in self._connected_events)) self.async_scan()
async def async_start(self) -> None: """Start the scanner.""" self.description_manager = DescriptionManager(self.hass) self.flow_dispatcher = FlowDispatcher(self.hass) for source_ip in await self._async_build_source_set(): self._ssdp_listeners.append( SSDPListener(async_callback=self._async_process_entry, source_ip=source_ip)) self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self.async_stop) self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, self.flow_dispatcher.async_start) await asyncio.gather( *[listener.async_start() for listener in self._ssdp_listeners]) self._cancel_scan = async_track_time_interval(self.hass, self.async_scan, SCAN_INTERVAL)