From 90842fcb846be0d989d44a5883885c9d3f73dc3e Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 25 Aug 2020 17:25:15 -0500 Subject: [PATCH] Support reloading the universal platform (#39248) --- homeassistant/components/template/__init__.py | 51 ++------------ .../template/alarm_control_panel.py | 8 +-- .../components/template/binary_sensor.py | 8 +-- homeassistant/components/template/const.py | 12 ++++ homeassistant/components/template/cover.py | 8 +-- homeassistant/components/template/fan.py | 8 +-- homeassistant/components/template/light.py | 8 +-- homeassistant/components/template/lock.py | 8 +-- homeassistant/components/template/sensor.py | 8 +-- homeassistant/components/template/switch.py | 8 +-- homeassistant/components/template/vacuum.py | 8 +-- .../components/universal/media_player.py | 25 ++++++- .../components/universal/services.yaml | 2 + homeassistant/helpers/reload.py | 70 +++++++++++++++++++ .../components/universal/test_media_player.py | 64 +++++++++++++++++ .../helpers/reload_configuration.yaml | 14 ++++ tests/fixtures/universal/configuration.yaml | 9 +++ tests/helpers/test_reload.py | 63 +++++++++++++++++ 18 files changed, 300 insertions(+), 82 deletions(-) create mode 100644 homeassistant/helpers/reload.py create mode 100644 tests/fixtures/helpers/reload_configuration.yaml create mode 100644 tests/fixtures/universal/configuration.yaml create mode 100644 tests/helpers/test_reload.py diff --git a/homeassistant/components/template/__init__.py b/homeassistant/components/template/__init__.py index f7f40cb92f7..a0f3a6a4a65 100644 --- a/homeassistant/components/template/__init__.py +++ b/homeassistant/components/template/__init__.py @@ -2,65 +2,26 @@ import logging -from homeassistant import config as conf_util from homeassistant.const import SERVICE_RELOAD -from homeassistant.exceptions import HomeAssistantError -from homeassistant.helpers import config_per_platform, entity_platform -from homeassistant.loader import async_get_integration +from homeassistant.helpers.reload import async_reload_integration_platforms -from .const import DOMAIN, EVENT_TEMPLATE_RELOADED, PLATFORM_STORAGE_KEY +from .const import DOMAIN, EVENT_TEMPLATE_RELOADED, PLATFORMS _LOGGER = logging.getLogger(__name__) -async def _async_setup_reload_service(hass): +async def async_setup_reload_service(hass): + """Create the reload service for the template domain.""" + if hass.services.has_service(DOMAIN, SERVICE_RELOAD): return async def _reload_config(call): """Reload the template platform config.""" - try: - unprocessed_conf = await conf_util.async_hass_config_yaml(hass) - except HomeAssistantError as err: - _LOGGER.error(err) - return - - for platform in hass.data[PLATFORM_STORAGE_KEY]: - - integration = await async_get_integration(hass, platform.domain) - - conf = await conf_util.async_process_component_config( - hass, unprocessed_conf, integration - ) - - if not conf: - continue - - await platform.async_reset() - - # Extract only the config for template, ignore the rest. - for p_type, p_config in config_per_platform(conf, platform.domain): - if p_type != DOMAIN: - continue - - entities = await platform.platform.async_create_entities(hass, p_config) - - await platform.async_add_entities(entities) - + await async_reload_integration_platforms(hass, DOMAIN, PLATFORMS) hass.bus.async_fire(EVENT_TEMPLATE_RELOADED, context=call.context) hass.helpers.service.async_register_admin_service( DOMAIN, SERVICE_RELOAD, _reload_config ) - - -async def async_setup_platform_reloadable(hass): - """Template platform with reloadability.""" - - await _async_setup_reload_service(hass) - - platform = entity_platform.current_platform.get() - - if platform not in hass.data.setdefault(PLATFORM_STORAGE_KEY, []): - hass.data[PLATFORM_STORAGE_KEY].append(platform) diff --git a/homeassistant/components/template/alarm_control_panel.py b/homeassistant/components/template/alarm_control_panel.py index ac71ec74397..292c359d334 100644 --- a/homeassistant/components/template/alarm_control_panel.py +++ b/homeassistant/components/template/alarm_control_panel.py @@ -33,7 +33,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import async_generate_entity_id from homeassistant.helpers.script import Script -from . import async_setup_platform_reloadable +from . import async_setup_reload_service from .template_entity import TemplateEntity _LOGGER = logging.getLogger(__name__) @@ -76,7 +76,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( ) -async def async_create_entities(hass, config): +async def _async_create_entities(hass, config): """Create Template Alarm Control Panels.""" alarm_control_panels = [] @@ -112,8 +112,8 @@ async def async_create_entities(hass, config): async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Template Alarm Control Panels.""" - await async_setup_platform_reloadable(hass) - async_add_entities(await async_create_entities(hass, config)) + await async_setup_reload_service(hass) + async_add_entities(await _async_create_entities(hass, config)) class AlarmControlPanelTemplate(TemplateEntity, AlarmControlPanelEntity): diff --git a/homeassistant/components/template/binary_sensor.py b/homeassistant/components/template/binary_sensor.py index 863bf2ab1c9..5ea04d67207 100644 --- a/homeassistant/components/template/binary_sensor.py +++ b/homeassistant/components/template/binary_sensor.py @@ -26,7 +26,7 @@ from homeassistant.helpers.entity import async_generate_entity_id from homeassistant.helpers.event import async_call_later from homeassistant.helpers.template import result_as_boolean -from . import async_setup_platform_reloadable +from . import async_setup_reload_service from .const import CONF_AVAILABILITY_TEMPLATE from .template_entity import TemplateEntity @@ -57,7 +57,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( ) -async def async_create_entities(hass, config): +async def _async_create_entities(hass, config): """Create the template binary sensors.""" sensors = [] @@ -97,8 +97,8 @@ async def async_create_entities(hass, config): async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the template binary sensors.""" - await async_setup_platform_reloadable(hass) - async_add_entities(await async_create_entities(hass, config)) + await async_setup_reload_service(hass) + async_add_entities(await _async_create_entities(hass, config)) class BinarySensorTemplate(TemplateEntity, BinarySensorEntity): diff --git a/homeassistant/components/template/const.py b/homeassistant/components/template/const.py index 6d46978b86f..cf1ec8bc1c3 100644 --- a/homeassistant/components/template/const.py +++ b/homeassistant/components/template/const.py @@ -7,3 +7,15 @@ DOMAIN = "template" PLATFORM_STORAGE_KEY = "template_platforms" EVENT_TEMPLATE_RELOADED = "event_template_reloaded" + +PLATFORMS = [ + "alarm_control_panel", + "binary_sensor", + "cover", + "fan", + "light", + "lock", + "sensor", + "switch", + "vacuum", +] diff --git a/homeassistant/components/template/cover.py b/homeassistant/components/template/cover.py index 688b116628c..828d7790ebf 100644 --- a/homeassistant/components/template/cover.py +++ b/homeassistant/components/template/cover.py @@ -37,7 +37,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import async_generate_entity_id from homeassistant.helpers.script import Script -from . import async_setup_platform_reloadable +from . import async_setup_reload_service from .const import CONF_AVAILABILITY_TEMPLATE from .template_entity import TemplateEntity @@ -100,7 +100,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( ) -async def async_create_entities(hass, config): +async def _async_create_entities(hass, config): """Create the Template cover.""" covers = [] @@ -152,8 +152,8 @@ async def async_create_entities(hass, config): async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Template cover.""" - await async_setup_platform_reloadable(hass) - async_add_entities(await async_create_entities(hass, config)) + await async_setup_reload_service(hass) + async_add_entities(await _async_create_entities(hass, config)) class CoverTemplate(TemplateEntity, CoverEntity): diff --git a/homeassistant/components/template/fan.py b/homeassistant/components/template/fan.py index 747d8b522a5..b7136787948 100644 --- a/homeassistant/components/template/fan.py +++ b/homeassistant/components/template/fan.py @@ -34,7 +34,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import async_generate_entity_id from homeassistant.helpers.script import Script -from . import async_setup_platform_reloadable +from . import async_setup_reload_service from .const import CONF_AVAILABILITY_TEMPLATE from .template_entity import TemplateEntity @@ -81,7 +81,7 @@ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend( ) -async def async_create_entities(hass, config): +async def _async_create_entities(hass, config): """Create the Template Fans.""" fans = [] @@ -129,8 +129,8 @@ async def async_create_entities(hass, config): async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the template fans.""" - await async_setup_platform_reloadable(hass) - async_add_entities(await async_create_entities(hass, config)) + await async_setup_reload_service(hass) + async_add_entities(await _async_create_entities(hass, config)) class TemplateFan(TemplateEntity, FanEntity): diff --git a/homeassistant/components/template/light.py b/homeassistant/components/template/light.py index c066a5d66d0..8fa2ae5f632 100644 --- a/homeassistant/components/template/light.py +++ b/homeassistant/components/template/light.py @@ -33,7 +33,7 @@ from homeassistant.helpers.config_validation import PLATFORM_SCHEMA from homeassistant.helpers.entity import async_generate_entity_id from homeassistant.helpers.script import Script -from . import async_setup_platform_reloadable +from . import async_setup_reload_service from .const import CONF_AVAILABILITY_TEMPLATE from .template_entity import TemplateEntity @@ -78,7 +78,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( ) -async def async_create_entities(hass, config): +async def _async_create_entities(hass, config): """Create the Template Lights.""" lights = [] @@ -135,8 +135,8 @@ async def async_create_entities(hass, config): async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the template lights.""" - await async_setup_platform_reloadable(hass) - async_add_entities(await async_create_entities(hass, config)) + await async_setup_reload_service(hass) + async_add_entities(await _async_create_entities(hass, config)) class LightTemplate(TemplateEntity, LightEntity): diff --git a/homeassistant/components/template/lock.py b/homeassistant/components/template/lock.py index 3e91e7b05c0..74197e6eb6d 100644 --- a/homeassistant/components/template/lock.py +++ b/homeassistant/components/template/lock.py @@ -17,7 +17,7 @@ from homeassistant.exceptions import TemplateError import homeassistant.helpers.config_validation as cv from homeassistant.helpers.script import Script -from . import async_setup_platform_reloadable +from . import async_setup_reload_service from .const import CONF_AVAILABILITY_TEMPLATE from .template_entity import TemplateEntity @@ -42,7 +42,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( ) -async def async_create_entities(hass, config): +async def _async_create_entities(hass, config): """Create the Template lock.""" device = config.get(CONF_NAME) value_template = config.get(CONF_VALUE_TEMPLATE) @@ -65,8 +65,8 @@ async def async_create_entities(hass, config): async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the template lock.""" - await async_setup_platform_reloadable(hass) - async_add_entities(await async_create_entities(hass, config)) + await async_setup_reload_service(hass) + async_add_entities(await _async_create_entities(hass, config)) class TemplateLock(TemplateEntity, LockEntity): diff --git a/homeassistant/components/template/sensor.py b/homeassistant/components/template/sensor.py index da99ac40ed2..f6844364928 100644 --- a/homeassistant/components/template/sensor.py +++ b/homeassistant/components/template/sensor.py @@ -26,7 +26,7 @@ from homeassistant.exceptions import TemplateError import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity, async_generate_entity_id -from . import async_setup_platform_reloadable +from . import async_setup_reload_service from .const import CONF_AVAILABILITY_TEMPLATE from .template_entity import TemplateEntity @@ -57,7 +57,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( ) -async def async_create_entities(hass, config): +async def _async_create_entities(hass, config): """Create the template sensors.""" sensors = [] @@ -97,8 +97,8 @@ async def async_create_entities(hass, config): async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the template sensors.""" - await async_setup_platform_reloadable(hass) - async_add_entities(await async_create_entities(hass, config)) + await async_setup_reload_service(hass) + async_add_entities(await _async_create_entities(hass, config)) class SensorTemplate(TemplateEntity, Entity): diff --git a/homeassistant/components/template/switch.py b/homeassistant/components/template/switch.py index 995f12584e6..7ef540144d8 100644 --- a/homeassistant/components/template/switch.py +++ b/homeassistant/components/template/switch.py @@ -26,7 +26,7 @@ from homeassistant.helpers.entity import async_generate_entity_id from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.script import Script -from . import async_setup_platform_reloadable +from . import async_setup_reload_service from .const import CONF_AVAILABILITY_TEMPLATE from .template_entity import TemplateEntity @@ -55,7 +55,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( ) -async def async_create_entities(hass, config): +async def _async_create_entities(hass, config): """Create the Template switches.""" switches = [] @@ -90,8 +90,8 @@ async def async_create_entities(hass, config): async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the template switches.""" - await async_setup_platform_reloadable(hass) - async_add_entities(await async_create_entities(hass, config)) + await async_setup_reload_service(hass) + async_add_entities(await _async_create_entities(hass, config)) class SwitchTemplate(TemplateEntity, SwitchEntity, RestoreEntity): diff --git a/homeassistant/components/template/vacuum.py b/homeassistant/components/template/vacuum.py index 3fd2c0f6ad1..b6b6669f7b9 100644 --- a/homeassistant/components/template/vacuum.py +++ b/homeassistant/components/template/vacuum.py @@ -43,7 +43,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import async_generate_entity_id from homeassistant.helpers.script import Script -from . import async_setup_platform_reloadable +from . import async_setup_reload_service from .const import CONF_AVAILABILITY_TEMPLATE from .template_entity import TemplateEntity @@ -93,7 +93,7 @@ PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend( ) -async def async_create_entities(hass, config): +async def _async_create_entities(hass, config): """Create the Template Vacuums.""" vacuums = [] @@ -145,8 +145,8 @@ async def async_create_entities(hass, config): async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the template vacuums.""" - await async_setup_platform_reloadable(hass) - async_add_entities(await async_create_entities(hass, config)) + await async_setup_reload_service(hass) + async_add_entities(await _async_create_entities(hass, config)) class TemplateVacuum(TemplateEntity, StateVacuumEntity): diff --git a/homeassistant/components/universal/media_player.py b/homeassistant/components/universal/media_player.py index bff5ad1542b..aaf4464452b 100644 --- a/homeassistant/components/universal/media_player.py +++ b/homeassistant/components/universal/media_player.py @@ -56,6 +56,7 @@ from homeassistant.const import ( SERVICE_MEDIA_PREVIOUS_TRACK, SERVICE_MEDIA_SEEK, SERVICE_MEDIA_STOP, + SERVICE_RELOAD, SERVICE_SHUFFLE_SET, SERVICE_TURN_OFF, SERVICE_TURN_ON, @@ -71,6 +72,7 @@ from homeassistant.const import ( from homeassistant.core import EVENT_HOMEASSISTANT_START, callback from homeassistant.exceptions import TemplateError from homeassistant.helpers import config_validation as cv +from homeassistant.helpers.reload import async_reload_integration_platforms from homeassistant.helpers.service import async_call_from_config _LOGGER = logging.getLogger(__name__) @@ -102,9 +104,31 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( extra=vol.REMOVE_EXTRA, ) +EVENT_UNIVERSAL_RELOADED = "event_universal_reloaded" + + +async def async_setup_reload_service(hass): + """Create the reload service for the universal domain.""" + + if hass.services.has_service("universal", SERVICE_RELOAD): + return + + async def _reload_config(call): + """Reload the template universal config.""" + + await async_reload_integration_platforms(hass, "universal", ["media_player"]) + hass.bus.async_fire(EVENT_UNIVERSAL_RELOADED, context=call.context) + + hass.helpers.service.async_register_admin_service( + "universal", SERVICE_RELOAD, _reload_config + ) + async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the universal media players.""" + + await async_setup_reload_service(hass) + player = UniversalMediaPlayer( hass, config.get(CONF_NAME), @@ -157,7 +181,6 @@ class UniversalMediaPlayer(MediaPlayerEntity): result = self.hass.helpers.event.async_track_template_result( self._state_template, _async_on_template_update ) - self.hass.bus.async_listen_once( EVENT_HOMEASSISTANT_START, callback(lambda _: result.async_refresh()) ) diff --git a/homeassistant/components/universal/services.yaml b/homeassistant/components/universal/services.yaml index e69de29bb2d..ed8f550275e 100644 --- a/homeassistant/components/universal/services.yaml +++ b/homeassistant/components/universal/services.yaml @@ -0,0 +1,2 @@ +reload: + description: Reload all universal entities. diff --git a/homeassistant/helpers/reload.py b/homeassistant/helpers/reload.py new file mode 100644 index 00000000000..3922f3710e2 --- /dev/null +++ b/homeassistant/helpers/reload.py @@ -0,0 +1,70 @@ +"""Class to reload platforms.""" + +import logging +from typing import Optional + +from homeassistant import config as conf_util +from homeassistant.core import callback +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers import config_per_platform +from homeassistant.helpers.entity_platform import DATA_ENTITY_PLATFORM, EntityPlatform +from homeassistant.helpers.typing import HomeAssistantType +from homeassistant.loader import async_get_integration + +_LOGGER = logging.getLogger(__name__) + + +async def async_reload_integration_platforms( + hass: HomeAssistantType, integration_name: str, integration_platforms: str +) -> None: + """Reload an integration's platforms. + + The platform must support being re-setup. + + This functionality is only intended to be used for integrations that process + Home Assistant data and make this available to other integrations. + + Examples are template, stats, derivative, utility meter. + """ + try: + unprocessed_conf = await conf_util.async_hass_config_yaml(hass) + except HomeAssistantError as err: + _LOGGER.error(err) + return + + for integration_platform in integration_platforms: + platform = async_get_platform(hass, integration_name, integration_platform) + + if not platform: + continue + + integration = await async_get_integration(hass, integration_platform) + + conf = await conf_util.async_process_component_config( + hass, unprocessed_conf, integration + ) + + if not conf: + continue + + await platform.async_reset() + + # Extract only the config for template, ignore the rest. + for p_type, p_config in config_per_platform(conf, integration_platform): + if p_type != integration_name: + continue + + await platform.async_setup(p_config) # type: ignore + + +@callback +def async_get_platform( + hass: HomeAssistantType, integration_name: str, integration_platform_name: str +) -> Optional[EntityPlatform]: + """Find an existing platform.""" + for integration_platform in hass.data[DATA_ENTITY_PLATFORM][integration_name]: + if integration_platform.domain == integration_platform_name: + platform: EntityPlatform = integration_platform + return platform + + return None diff --git a/tests/components/universal/test_media_player.py b/tests/components/universal/test_media_player.py index af2132e8f69..8f274fcc9c9 100644 --- a/tests/components/universal/test_media_player.py +++ b/tests/components/universal/test_media_player.py @@ -1,10 +1,13 @@ """The tests for the Universal Media player platform.""" import asyncio from copy import copy +from os import path import unittest +from asynctest.mock import patch from voluptuous.error import MultipleInvalid +from homeassistant import config as hass_config import homeassistant.components.input_number as input_number import homeassistant.components.input_select as input_select import homeassistant.components.media_player as media_player @@ -812,3 +815,64 @@ async def test_master_state_with_template(hass): await hass.async_block_till_done() hass.states.get("media_player.tv").state == STATE_OFF + + +async def test_reload(hass): + """Test the state_template option.""" + hass.states.async_set("input_boolean.test", STATE_OFF) + hass.states.async_set("media_player.mock1", STATE_OFF) + + templ = ( + '{% if states.input_boolean.test.state == "off" %}on' + "{% else %}{{ states.media_player.mock1.state }}{% endif %}" + ) + + await async_setup_component( + hass, + "media_player", + { + "media_player": { + "platform": "universal", + "name": "tv", + "state_template": templ, + } + }, + ) + + await hass.async_block_till_done() + assert len(hass.states.async_all()) == 3 + await hass.async_start() + + await hass.async_block_till_done() + hass.states.get("media_player.tv").state == STATE_ON + + hass.states.async_set("input_boolean.test", STATE_ON) + await hass.async_block_till_done() + + hass.states.get("media_player.tv").state == STATE_OFF + + hass.states.async_set("media_player.master_bedroom_2", STATE_OFF) + hass.states.async_set( + "remote.alexander_master_bedroom", + STATE_ON, + {"activity_list": ["act1", "act2"], "current_activity": "act2"}, + ) + + yaml_path = path.join( + _get_fixtures_base_path(), "fixtures", "universal/configuration.yaml", + ) + with patch.object(hass_config, "YAML_CONFIG_FILE", yaml_path): + await hass.services.async_call( + "universal", universal.SERVICE_RELOAD, {}, blocking=True, + ) + await hass.async_block_till_done() + + assert len(hass.states.async_all()) == 5 + + assert hass.states.get("media_player.tv") is None + assert hass.states.get("media_player.master_bed_tv").state == "on" + assert hass.states.get("media_player.master_bed_tv").attributes["source"] == "act2" + + +def _get_fixtures_base_path(): + return path.dirname(path.dirname(path.dirname(__file__))) diff --git a/tests/fixtures/helpers/reload_configuration.yaml b/tests/fixtures/helpers/reload_configuration.yaml new file mode 100644 index 00000000000..f7c628bec5a --- /dev/null +++ b/tests/fixtures/helpers/reload_configuration.yaml @@ -0,0 +1,14 @@ +test_domain: + - platform: test_platform + sensors: + combined_sensor_energy_usage: + friendly_name: Combined Sense Energy Usage + unit_of_measurement: kW + value_template: '{{ ((states(''sensor.energy_usage'') | float) + (states(''sensor.energy_usage_2'') + | float)) / 1000 }}' + watching_tv_in_master_bedroom: + friendly_name: Watching TV in Master Bedroom + value_template: '{% if state_attr("remote.alexander_master_bedroom","current_activity") + == "Watch TV" or state_attr("remote.alexander_master_bedroom","current_activity") + == "Watch Apple TV" %}on{% else %}off{% endif %}' + diff --git a/tests/fixtures/universal/configuration.yaml b/tests/fixtures/universal/configuration.yaml new file mode 100644 index 00000000000..c3e445615f1 --- /dev/null +++ b/tests/fixtures/universal/configuration.yaml @@ -0,0 +1,9 @@ +media_player: + - platform: universal + name: Master Bed TV + children: + - media_player.master_bedroom_2 + attributes: + state: remote.alexander_master_bedroom + source_list: remote.alexander_master_bedroom|activity_list + source: remote.alexander_master_bedroom|current_activity diff --git a/tests/helpers/test_reload.py b/tests/helpers/test_reload.py new file mode 100644 index 00000000000..d9067b4b35f --- /dev/null +++ b/tests/helpers/test_reload.py @@ -0,0 +1,63 @@ +"""Tests for the reload helper.""" +import logging +from os import path + +from homeassistant import config +from homeassistant.helpers.entity_component import EntityComponent +from homeassistant.helpers.reload import ( + async_get_platform, + async_reload_integration_platforms, +) + +from tests.async_mock import Mock, patch +from tests.common import ( + MockModule, + MockPlatform, + mock_entity_platform, + mock_integration, +) + +_LOGGER = logging.getLogger(__name__) +DOMAIN = "test_domain" +PLATFORM = "test_platform" + + +async def test_reload_platform(hass): + """Test the polling of only updated entities.""" + component_setup = Mock(return_value=True) + + setup_called = [] + + async def setup_platform(*args): + setup_called.append(args) + + mock_integration(hass, MockModule(DOMAIN, setup=component_setup)) + mock_integration(hass, MockModule(PLATFORM, dependencies=[DOMAIN])) + + mock_platform = MockPlatform(async_setup_platform=setup_platform) + mock_entity_platform(hass, f"{DOMAIN}.{PLATFORM}", mock_platform) + + component = EntityComponent(_LOGGER, DOMAIN, hass) + + await component.async_setup({DOMAIN: {"platform": PLATFORM, "sensors": None}}) + await hass.async_block_till_done() + assert component_setup.called + + assert f"{DOMAIN}.{PLATFORM}" in hass.config.components + assert len(setup_called) == 1 + + platform = async_get_platform(hass, PLATFORM, DOMAIN) + assert platform.platform_name == PLATFORM + assert platform.domain == DOMAIN + + yaml_path = path.join( + _get_fixtures_base_path(), "fixtures", "helpers/reload_configuration.yaml", + ) + with patch.object(config, "YAML_CONFIG_FILE", yaml_path): + await async_reload_integration_platforms(hass, PLATFORM, [DOMAIN]) + + assert len(setup_called) == 2 + + +def _get_fixtures_base_path(): + return path.dirname(path.dirname(__file__))