mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 04:37:06 +00:00
Do not warn for weak referenced entities (#43848)
This commit is contained in:
parent
648f9e100d
commit
f3bb243b1d
@ -21,7 +21,7 @@ from homeassistant.const import (
|
|||||||
import homeassistant.core as ha
|
import homeassistant.core as ha
|
||||||
from homeassistant.exceptions import HomeAssistantError, Unauthorized, UnknownUser
|
from homeassistant.exceptions import HomeAssistantError, Unauthorized, UnknownUser
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.helpers import config_validation as cv
|
||||||
from homeassistant.helpers.service import async_extract_entity_ids
|
from homeassistant.helpers.service import async_extract_referenced_entity_ids
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
DOMAIN = ha.DOMAIN
|
DOMAIN = ha.DOMAIN
|
||||||
@ -37,39 +37,37 @@ async def async_setup(hass: ha.HomeAssistant, config: dict) -> bool:
|
|||||||
|
|
||||||
async def async_handle_turn_service(service):
|
async def async_handle_turn_service(service):
|
||||||
"""Handle calls to homeassistant.turn_on/off."""
|
"""Handle calls to homeassistant.turn_on/off."""
|
||||||
entity_ids = await async_extract_entity_ids(hass, service)
|
referenced = await async_extract_referenced_entity_ids(hass, service)
|
||||||
|
all_referenced = referenced.referenced | referenced.indirectly_referenced
|
||||||
|
|
||||||
# Generic turn on/off method requires entity id
|
# Generic turn on/off method requires entity id
|
||||||
if not entity_ids:
|
if not all_referenced:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"homeassistant/%s cannot be called without entity_id", service.service
|
"homeassistant.%s cannot be called without a target", service.service
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Group entity_ids by domain. groupby requires sorted data.
|
# Group entity_ids by domain. groupby requires sorted data.
|
||||||
by_domain = it.groupby(
|
by_domain = it.groupby(
|
||||||
sorted(entity_ids), lambda item: ha.split_entity_id(item)[0]
|
sorted(all_referenced), lambda item: ha.split_entity_id(item)[0]
|
||||||
)
|
)
|
||||||
|
|
||||||
tasks = []
|
tasks = []
|
||||||
|
unsupported_entities = set()
|
||||||
|
|
||||||
for domain, ent_ids in by_domain:
|
for domain, ent_ids in by_domain:
|
||||||
# This leads to endless loop.
|
# This leads to endless loop.
|
||||||
if domain == DOMAIN:
|
if domain == DOMAIN:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"Called service homeassistant.%s with invalid entity IDs %s",
|
"Called service homeassistant.%s with invalid entities %s",
|
||||||
service.service,
|
service.service,
|
||||||
", ".join(ent_ids),
|
", ".join(ent_ids),
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# We want to block for all calls and only return when all calls
|
if not hass.services.has_service(domain, service.service):
|
||||||
# have been processed. If a service does not exist it causes a 10
|
unsupported_entities.update(set(ent_ids) & referenced.referenced)
|
||||||
# second delay while we're blocking waiting for a response.
|
continue
|
||||||
# But services can be registered on other HA instances that are
|
|
||||||
# listening to the bus too. So as an in between solution, we'll
|
|
||||||
# block only if the service is defined in the current HA instance.
|
|
||||||
blocking = hass.services.has_service(domain, service.service)
|
|
||||||
|
|
||||||
# Create a new dict for this call
|
# Create a new dict for this call
|
||||||
data = dict(service.data)
|
data = dict(service.data)
|
||||||
@ -79,10 +77,21 @@ async def async_setup(hass: ha.HomeAssistant, config: dict) -> bool:
|
|||||||
|
|
||||||
tasks.append(
|
tasks.append(
|
||||||
hass.services.async_call(
|
hass.services.async_call(
|
||||||
domain, service.service, data, blocking, context=service.context
|
domain,
|
||||||
|
service.service,
|
||||||
|
data,
|
||||||
|
blocking=True,
|
||||||
|
context=service.context,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if unsupported_entities:
|
||||||
|
_LOGGER.warning(
|
||||||
|
"The service homeassistant.%s does not support entities %s",
|
||||||
|
service.service,
|
||||||
|
", ".join(sorted(unsupported_entities)),
|
||||||
|
)
|
||||||
|
|
||||||
if tasks:
|
if tasks:
|
||||||
await asyncio.gather(*tasks)
|
await asyncio.gather(*tasks)
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ class TestComponentsCore(unittest.TestCase):
|
|||||||
assert not mock_stop.called
|
assert not mock_stop.called
|
||||||
|
|
||||||
|
|
||||||
async def test_turn_on_to_not_block_for_domains_without_service(hass):
|
async def test_turn_on_skips_domains_without_service(hass, caplog):
|
||||||
"""Test if turn_on is blocking domain with no service."""
|
"""Test if turn_on is blocking domain with no service."""
|
||||||
await async_setup_component(hass, "homeassistant", {})
|
await async_setup_component(hass, "homeassistant", {})
|
||||||
async_mock_service(hass, "light", SERVICE_TURN_ON)
|
async_mock_service(hass, "light", SERVICE_TURN_ON)
|
||||||
@ -261,7 +261,7 @@ async def test_turn_on_to_not_block_for_domains_without_service(hass):
|
|||||||
service_call = ha.ServiceCall(
|
service_call = ha.ServiceCall(
|
||||||
"homeassistant",
|
"homeassistant",
|
||||||
"turn_on",
|
"turn_on",
|
||||||
{"entity_id": ["light.test", "sensor.bla", "light.bla"]},
|
{"entity_id": ["light.test", "sensor.bla", "binary_sensor.blub", "light.bla"]},
|
||||||
)
|
)
|
||||||
service = hass.services._services["homeassistant"]["turn_on"]
|
service = hass.services._services["homeassistant"]["turn_on"]
|
||||||
|
|
||||||
@ -271,18 +271,19 @@ async def test_turn_on_to_not_block_for_domains_without_service(hass):
|
|||||||
) as mock_call:
|
) as mock_call:
|
||||||
await service.job.target(service_call)
|
await service.job.target(service_call)
|
||||||
|
|
||||||
assert mock_call.call_count == 2
|
assert mock_call.call_count == 1
|
||||||
assert mock_call.call_args_list[0][0] == (
|
assert mock_call.call_args_list[0][0] == (
|
||||||
"light",
|
"light",
|
||||||
"turn_on",
|
"turn_on",
|
||||||
{"entity_id": ["light.bla", "light.test"]},
|
{"entity_id": ["light.bla", "light.test"]},
|
||||||
True,
|
|
||||||
)
|
)
|
||||||
assert mock_call.call_args_list[1][0] == (
|
assert mock_call.call_args_list[0][1] == {
|
||||||
"sensor",
|
"blocking": True,
|
||||||
"turn_on",
|
"context": service_call.context,
|
||||||
{"entity_id": ["sensor.bla"]},
|
}
|
||||||
False,
|
assert (
|
||||||
|
"The service homeassistant.turn_on does not support entities binary_sensor.blub, sensor.bla"
|
||||||
|
in caplog.text
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -381,6 +382,6 @@ async def test_not_allowing_recursion(hass, caplog):
|
|||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
f"Called service homeassistant.{service} with invalid entity IDs homeassistant.light"
|
f"Called service homeassistant.{service} with invalid entities homeassistant.light"
|
||||||
in caplog.text
|
in caplog.text
|
||||||
), service
|
), service
|
||||||
|
Loading…
x
Reference in New Issue
Block a user