Add timer reload service. (#30015)

pull/30057/head
Alexei Chetroi 2019-12-18 15:15:11 -05:00 committed by Paulus Schoutsen
parent 0adb88156d
commit 41bef4b919
2 changed files with 140 additions and 17 deletions

View File

@ -4,11 +4,12 @@ import logging
import voluptuous as vol
from homeassistant.const import CONF_ICON, CONF_NAME
from homeassistant.const import CONF_ICON, CONF_NAME, SERVICE_RELOAD
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.helpers.restore_state import RestoreEntity
import homeassistant.helpers.service
import homeassistant.util.dt as dt_util
_LOGGER = logging.getLogger(__name__)
@ -54,26 +55,31 @@ CONFIG_SCHEMA = vol.Schema(
extra=vol.ALLOW_EXTRA,
)
RELOAD_SERVICE_SCHEMA = vol.Schema({})
async def async_setup(hass, config):
"""Set up a timer."""
component = EntityComponent(_LOGGER, DOMAIN, hass)
entities = []
entities = await _async_process_config(hass, config)
for object_id, cfg in config[DOMAIN].items():
if not cfg:
cfg = {}
name = cfg.get(CONF_NAME)
icon = cfg.get(CONF_ICON)
duration = cfg.get(CONF_DURATION)
entities.append(Timer(hass, object_id, name, icon, duration))
if not entities:
return False
async def reload_service_handler(service_call):
"""Remove all input booleans and load new ones from config."""
conf = await component.async_prepare_reload()
if conf is None:
return
new_entities = await _async_process_config(hass, conf)
if new_entities:
await component.async_add_entities(new_entities)
homeassistant.helpers.service.async_register_admin_service(
hass,
DOMAIN,
SERVICE_RELOAD,
reload_service_handler,
schema=RELOAD_SERVICE_SCHEMA,
)
component.async_register_entity_service(
SERVICE_START,
{
@ -87,10 +93,28 @@ async def async_setup(hass, config):
component.async_register_entity_service(SERVICE_CANCEL, {}, "async_cancel")
component.async_register_entity_service(SERVICE_FINISH, {}, "async_finish")
await component.async_add_entities(entities)
if entities:
await component.async_add_entities(entities)
return True
async def _async_process_config(hass, config):
"""Process config and create list of entities."""
entities = []
for object_id, cfg in config[DOMAIN].items():
if not cfg:
cfg = {}
name = cfg.get(CONF_NAME)
icon = cfg.get(CONF_ICON)
duration = cfg.get(CONF_DURATION)
entities.append(Timer(hass, object_id, name, icon, duration))
return entities
class Timer(RestoreEntity):
"""Representation of a timer."""

View File

@ -3,6 +3,9 @@
import asyncio
from datetime import timedelta
import logging
from unittest.mock import patch
import pytest
from homeassistant.components.timer import (
ATTR_DURATION,
@ -23,8 +26,14 @@ from homeassistant.components.timer import (
STATUS_IDLE,
STATUS_PAUSED,
)
from homeassistant.const import ATTR_FRIENDLY_NAME, ATTR_ICON, CONF_ENTITY_ID
from homeassistant.core import CoreState
from homeassistant.const import (
ATTR_FRIENDLY_NAME,
ATTR_ICON,
CONF_ENTITY_ID,
SERVICE_RELOAD,
)
from homeassistant.core import Context, CoreState
from homeassistant.exceptions import Unauthorized
from homeassistant.setup import async_setup_component
from homeassistant.util.dt import utcnow
@ -195,3 +204,93 @@ def test_no_initial_state_and_no_restore_state(hass):
state = hass.states.get("timer.test1")
assert state
assert state.state == STATUS_IDLE
async def test_config_reload(hass, hass_admin_user, hass_read_only_user):
"""Test reload service."""
count_start = len(hass.states.async_entity_ids())
_LOGGER.debug("ENTITIES @ start: %s", hass.states.async_entity_ids())
config = {
DOMAIN: {
"test_1": {},
"test_2": {
CONF_NAME: "Hello World",
CONF_ICON: "mdi:work",
CONF_DURATION: 10,
},
}
}
assert await async_setup_component(hass, "timer", config)
await hass.async_block_till_done()
assert count_start + 2 == len(hass.states.async_entity_ids())
await hass.async_block_till_done()
state_1 = hass.states.get("timer.test_1")
state_2 = hass.states.get("timer.test_2")
state_3 = hass.states.get("timer.test_3")
assert state_1 is not None
assert state_2 is not None
assert state_3 is None
assert STATUS_IDLE == state_1.state
assert ATTR_ICON not in state_1.attributes
assert ATTR_FRIENDLY_NAME not in state_1.attributes
assert STATUS_IDLE == state_2.state
assert "Hello World" == state_2.attributes.get(ATTR_FRIENDLY_NAME)
assert "mdi:work" == state_2.attributes.get(ATTR_ICON)
assert "0:00:10" == state_2.attributes.get(ATTR_DURATION)
with patch(
"homeassistant.config.load_yaml_config_file",
autospec=True,
return_value={
DOMAIN: {
"test_2": {
CONF_NAME: "Hello World reloaded",
CONF_ICON: "mdi:work-reloaded",
CONF_DURATION: 20,
},
"test_3": {},
}
},
):
with patch("homeassistant.config.find_config_file", return_value=""):
with pytest.raises(Unauthorized):
await hass.services.async_call(
DOMAIN,
SERVICE_RELOAD,
blocking=True,
context=Context(user_id=hass_read_only_user.id),
)
await hass.services.async_call(
DOMAIN,
SERVICE_RELOAD,
blocking=True,
context=Context(user_id=hass_admin_user.id),
)
await hass.async_block_till_done()
assert count_start + 2 == len(hass.states.async_entity_ids())
state_1 = hass.states.get("timer.test_1")
state_2 = hass.states.get("timer.test_2")
state_3 = hass.states.get("timer.test_3")
assert state_1 is None
assert state_2 is not None
assert state_3 is not None
assert STATUS_IDLE == state_2.state
assert "Hello World reloaded" == state_2.attributes.get(ATTR_FRIENDLY_NAME)
assert "mdi:work-reloaded" == state_2.attributes.get(ATTR_ICON)
assert "0:00:20" == state_2.attributes.get(ATTR_DURATION)
assert STATUS_IDLE == state_3.state
assert ATTR_ICON not in state_3.attributes
assert ATTR_FRIENDLY_NAME not in state_3.attributes