Manual updates (#17278)
parent
cf249e3e5e
commit
e903f7ffda
|
@ -12,6 +12,8 @@ import itertools as it
|
||||||
import logging
|
import logging
|
||||||
from typing import Awaitable
|
from typing import Awaitable
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
import homeassistant.core as ha
|
import homeassistant.core as ha
|
||||||
import homeassistant.config as conf_util
|
import homeassistant.config as conf_util
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
@ -21,11 +23,16 @@ from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE,
|
ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE,
|
||||||
SERVICE_HOMEASSISTANT_STOP, SERVICE_HOMEASSISTANT_RESTART,
|
SERVICE_HOMEASSISTANT_STOP, SERVICE_HOMEASSISTANT_RESTART,
|
||||||
RESTART_EXIT_CODE)
|
RESTART_EXIT_CODE)
|
||||||
|
from homeassistant.helpers import config_validation as cv
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
SERVICE_RELOAD_CORE_CONFIG = 'reload_core_config'
|
SERVICE_RELOAD_CORE_CONFIG = 'reload_core_config'
|
||||||
SERVICE_CHECK_CONFIG = 'check_config'
|
SERVICE_CHECK_CONFIG = 'check_config'
|
||||||
|
SERVICE_UPDATE_ENTITY = 'update_entity'
|
||||||
|
SCHEMA_UPDATE_ENTITY = vol.Schema({
|
||||||
|
ATTR_ENTITY_ID: cv.entity_id
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
def is_on(hass, entity_id=None):
|
def is_on(hass, entity_id=None):
|
||||||
|
@ -133,12 +140,20 @@ async def async_setup(hass: ha.HomeAssistant, config: dict) -> Awaitable[bool]:
|
||||||
if call.service == SERVICE_HOMEASSISTANT_RESTART:
|
if call.service == SERVICE_HOMEASSISTANT_RESTART:
|
||||||
hass.async_create_task(hass.async_stop(RESTART_EXIT_CODE))
|
hass.async_create_task(hass.async_stop(RESTART_EXIT_CODE))
|
||||||
|
|
||||||
|
async def async_handle_update_service(call):
|
||||||
|
"""Service handler for updating an entity."""
|
||||||
|
await hass.helpers.entity_component.async_update_entity(
|
||||||
|
call.data[ATTR_ENTITY_ID])
|
||||||
|
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
ha.DOMAIN, SERVICE_HOMEASSISTANT_STOP, async_handle_core_service)
|
ha.DOMAIN, SERVICE_HOMEASSISTANT_STOP, async_handle_core_service)
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
ha.DOMAIN, SERVICE_HOMEASSISTANT_RESTART, async_handle_core_service)
|
ha.DOMAIN, SERVICE_HOMEASSISTANT_RESTART, async_handle_core_service)
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
ha.DOMAIN, SERVICE_CHECK_CONFIG, async_handle_core_service)
|
ha.DOMAIN, SERVICE_CHECK_CONFIG, async_handle_core_service)
|
||||||
|
hass.services.async_register(
|
||||||
|
ha.DOMAIN, SERVICE_UPDATE_ENTITY, async_handle_update_service,
|
||||||
|
schema=SCHEMA_UPDATE_ENTITY)
|
||||||
|
|
||||||
async def async_handle_reload_config(call):
|
async def async_handle_reload_config(call):
|
||||||
"""Service handler for reloading core config."""
|
"""Service handler for reloading core config."""
|
||||||
|
|
|
@ -346,7 +346,7 @@ class Entity:
|
||||||
if hasattr(self, 'async_update'):
|
if hasattr(self, 'async_update'):
|
||||||
await self.async_update()
|
await self.async_update()
|
||||||
elif hasattr(self, 'update'):
|
elif hasattr(self, 'update'):
|
||||||
await self.hass.async_add_job(self.update)
|
await self.hass.async_add_executor_job(self.update)
|
||||||
finally:
|
finally:
|
||||||
self._update_staged = False
|
self._update_staged = False
|
||||||
if warning:
|
if warning:
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
import logging
|
||||||
|
|
||||||
from homeassistant import config as conf_util
|
from homeassistant import config as conf_util
|
||||||
from homeassistant.setup import async_prepare_setup_platform
|
from homeassistant.setup import async_prepare_setup_platform
|
||||||
|
@ -11,10 +12,33 @@ from homeassistant.core import callback
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers import config_per_platform, discovery
|
from homeassistant.helpers import config_per_platform, discovery
|
||||||
from homeassistant.helpers.service import extract_entity_ids
|
from homeassistant.helpers.service import extract_entity_ids
|
||||||
|
from homeassistant.loader import bind_hass
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
from .entity_platform import EntityPlatform
|
from .entity_platform import EntityPlatform
|
||||||
|
|
||||||
DEFAULT_SCAN_INTERVAL = timedelta(seconds=15)
|
DEFAULT_SCAN_INTERVAL = timedelta(seconds=15)
|
||||||
|
DATA_INSTANCES = 'entity_components'
|
||||||
|
|
||||||
|
|
||||||
|
@bind_hass
|
||||||
|
async def async_update_entity(hass, entity_id):
|
||||||
|
"""Trigger an update for an entity."""
|
||||||
|
domain = entity_id.split('.', 1)[0]
|
||||||
|
entity_comp = hass.data.get(DATA_INSTANCES, {}).get(domain)
|
||||||
|
|
||||||
|
if entity_comp is None:
|
||||||
|
logging.getLogger(__name__).warning(
|
||||||
|
'Forced update failed. Component for %s not loaded.', entity_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
entity = entity_comp.get_entity(entity_id)
|
||||||
|
|
||||||
|
if entity is None:
|
||||||
|
logging.getLogger(__name__).warning(
|
||||||
|
'Forced update failed. Entity %s not found.', entity_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
await entity.async_update_ha_state(True)
|
||||||
|
|
||||||
|
|
||||||
class EntityComponent:
|
class EntityComponent:
|
||||||
|
@ -45,6 +69,8 @@ class EntityComponent:
|
||||||
self.async_add_entities = self._platforms[domain].async_add_entities
|
self.async_add_entities = self._platforms[domain].async_add_entities
|
||||||
self.add_entities = self._platforms[domain].add_entities
|
self.add_entities = self._platforms[domain].add_entities
|
||||||
|
|
||||||
|
hass.data.setdefault(DATA_INSTANCES, {})[domain] = self
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def entities(self):
|
def entities(self):
|
||||||
"""Return an iterable that returns all entities."""
|
"""Return an iterable that returns all entities."""
|
||||||
|
|
|
@ -355,3 +355,17 @@ async def test_turn_on_to_not_block_for_domains_without_service(hass):
|
||||||
'light', 'turn_on', {'entity_id': ['light.bla', 'light.test']}, True)
|
'light', 'turn_on', {'entity_id': ['light.bla', 'light.test']}, True)
|
||||||
assert mock_call.call_args_list[1][0] == (
|
assert mock_call.call_args_list[1][0] == (
|
||||||
'sensor', 'turn_on', {'entity_id': ['sensor.bla']}, False)
|
'sensor', 'turn_on', {'entity_id': ['sensor.bla']}, False)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_entity_update(hass):
|
||||||
|
"""Test being able to call entity update."""
|
||||||
|
await comps.async_setup(hass, {})
|
||||||
|
|
||||||
|
with patch('homeassistant.helpers.entity_component.async_update_entity',
|
||||||
|
return_value=mock_coro()) as mock_update:
|
||||||
|
await hass.services.async_call('homeassistant', 'update_entity', {
|
||||||
|
'entity_id': 'light.kitchen'
|
||||||
|
}, blocking=True)
|
||||||
|
|
||||||
|
assert len(mock_update.mock_calls) == 1
|
||||||
|
assert mock_update.mock_calls[0][1][1] == 'light.kitchen'
|
||||||
|
|
|
@ -415,3 +415,19 @@ async def test_unload_entry_fails_if_never_loaded(hass):
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
await component.async_unload_entry(entry)
|
await component.async_unload_entry(entry)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_update_entity(hass):
|
||||||
|
"""Test that we can update an entity with the helper."""
|
||||||
|
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||||
|
entity = MockEntity()
|
||||||
|
entity.async_update_ha_state = Mock(return_value=mock_coro())
|
||||||
|
await component.async_add_entities([entity])
|
||||||
|
|
||||||
|
# Called as part of async_add_entities
|
||||||
|
assert len(entity.async_update_ha_state.mock_calls) == 1
|
||||||
|
|
||||||
|
await hass.helpers.entity_component.async_update_entity(entity.entity_id)
|
||||||
|
|
||||||
|
assert len(entity.async_update_ha_state.mock_calls) == 2
|
||||||
|
assert entity.async_update_ha_state.mock_calls[-1][1][0] is True
|
||||||
|
|
Loading…
Reference in New Issue