Manual updates (#17278)
parent
cf249e3e5e
commit
e903f7ffda
|
@ -12,6 +12,8 @@ import itertools as it
|
|||
import logging
|
||||
from typing import Awaitable
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
import homeassistant.core as ha
|
||||
import homeassistant.config as conf_util
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
@ -21,11 +23,16 @@ from homeassistant.const import (
|
|||
ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE,
|
||||
SERVICE_HOMEASSISTANT_STOP, SERVICE_HOMEASSISTANT_RESTART,
|
||||
RESTART_EXIT_CODE)
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SERVICE_RELOAD_CORE_CONFIG = 'reload_core_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):
|
||||
|
@ -133,12 +140,20 @@ async def async_setup(hass: ha.HomeAssistant, config: dict) -> Awaitable[bool]:
|
|||
if call.service == SERVICE_HOMEASSISTANT_RESTART:
|
||||
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(
|
||||
ha.DOMAIN, SERVICE_HOMEASSISTANT_STOP, async_handle_core_service)
|
||||
hass.services.async_register(
|
||||
ha.DOMAIN, SERVICE_HOMEASSISTANT_RESTART, async_handle_core_service)
|
||||
hass.services.async_register(
|
||||
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):
|
||||
"""Service handler for reloading core config."""
|
||||
|
|
|
@ -346,7 +346,7 @@ class Entity:
|
|||
if hasattr(self, 'async_update'):
|
||||
await self.async_update()
|
||||
elif hasattr(self, 'update'):
|
||||
await self.hass.async_add_job(self.update)
|
||||
await self.hass.async_add_executor_job(self.update)
|
||||
finally:
|
||||
self._update_staged = False
|
||||
if warning:
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import asyncio
|
||||
from datetime import timedelta
|
||||
from itertools import chain
|
||||
import logging
|
||||
|
||||
from homeassistant import config as conf_util
|
||||
from homeassistant.setup import async_prepare_setup_platform
|
||||
|
@ -11,10 +12,33 @@ from homeassistant.core import callback
|
|||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_per_platform, discovery
|
||||
from homeassistant.helpers.service import extract_entity_ids
|
||||
from homeassistant.loader import bind_hass
|
||||
from homeassistant.util import slugify
|
||||
from .entity_platform import EntityPlatform
|
||||
|
||||
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:
|
||||
|
@ -45,6 +69,8 @@ class EntityComponent:
|
|||
self.async_add_entities = self._platforms[domain].async_add_entities
|
||||
self.add_entities = self._platforms[domain].add_entities
|
||||
|
||||
hass.data.setdefault(DATA_INSTANCES, {})[domain] = self
|
||||
|
||||
@property
|
||||
def entities(self):
|
||||
"""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)
|
||||
assert mock_call.call_args_list[1][0] == (
|
||||
'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):
|
||||
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