From 0489ae53c44e06f9eaf2a1d376dcc6cd64a1c1a7 Mon Sep 17 00:00:00 2001 From: Colin O'Dell Date: Fri, 3 Mar 2017 16:11:40 -0500 Subject: [PATCH] Don't initialize components which have already been discovered (#6381) * Don't initialize components which have already been discovered (fixes #5588) * Don't log that we've found a service unless we know it's not a duplicate * Encode discovery data hash with JSON This also solves the issue of trying to hash non-hashable objects like dicts * Add test for duplicate device discovery --- homeassistant/components/discovery.py | 12 ++++++++++-- tests/components/test_discovery.py | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/discovery.py b/homeassistant/components/discovery.py index ac68cfaf367..421ba321c8d 100644 --- a/homeassistant/components/discovery.py +++ b/homeassistant/components/discovery.py @@ -7,6 +7,7 @@ Knows which components handle certain types, will make sure they are loaded before the EVENT_PLATFORM_DISCOVERED is fired. """ import asyncio +import json from datetime import timedelta import logging @@ -66,6 +67,7 @@ def async_setup(hass, config): logger = logging.getLogger(__name__) netdisco = NetworkDiscovery() + already_discovered = set() # Disable zeroconf logging, it spams logging.getLogger('zeroconf').setLevel(logging.CRITICAL) @@ -80,14 +82,20 @@ def async_setup(hass, config): logger.info("Ignoring service: %s %s", service, info) return - logger.info("Found new service: %s %s", service, info) - comp_plat = SERVICE_HANDLERS.get(service) # We do not know how to handle this service. if not comp_plat: return + discovery_hash = json.dumps([service, info], sort_keys=True) + if discovery_hash in already_discovered: + return + + already_discovered.add(discovery_hash) + + logger.info("Found new service: %s %s", service, info) + component, platform = comp_plat if platform is None: diff --git a/tests/components/test_discovery.py b/tests/components/test_discovery.py index bc2be3ed463..abffc3b17cd 100644 --- a/tests/components/test_discovery.py +++ b/tests/components/test_discovery.py @@ -126,3 +126,30 @@ def test_ignore_service(hass): assert not mock_discover.called assert not mock_platform.called + + +@asyncio.coroutine +def test_discover_duplicates(hass): + """Test load a component.""" + result = yield from async_setup_component(hass, 'discovery', BASE_CONFIG) + assert result + + def discover(netdisco): + """Fake discovery.""" + return [(SERVICE_NO_PLATFORM, SERVICE_INFO), + (SERVICE_NO_PLATFORM, SERVICE_INFO)] + + with patch.object(discovery, '_discover', discover), \ + patch('homeassistant.components.discovery.async_discover', + return_value=mock_coro()) as mock_discover, \ + patch('homeassistant.components.discovery.async_load_platform', + return_value=mock_coro()) as mock_platform: + hass.bus.async_fire(EVENT_HOMEASSISTANT_START) + yield from hass.async_block_till_done() + + assert mock_discover.called + assert mock_discover.call_count == 1 + assert not mock_platform.called + mock_discover.assert_called_with( + hass, SERVICE_NO_PLATFORM, SERVICE_INFO, + SERVICE_NO_PLATFORM_COMPONENT, BASE_CONFIG)