Add an event filter to the alexa state report state change listener (#115076)

Co-authored-by: jbouwh <jan@jbsoft.nl>
pull/114546/head
J. Nick Koston 2024-04-07 03:14:18 -10:00 committed by GitHub
parent f617000920
commit 5630b3611d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 56 additions and 37 deletions

View File

@ -13,10 +13,16 @@ from uuid import uuid4
import aiohttp
from homeassistant.components import event
from homeassistant.const import MATCH_ALL, STATE_ON
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, State, callback
from homeassistant.const import EVENT_STATE_CHANGED, STATE_ON
from homeassistant.core import (
CALLBACK_TYPE,
Event,
EventStateChangedData,
HomeAssistant,
State,
callback,
)
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.event import async_track_state_change
from homeassistant.helpers.significant_change import create_checker
import homeassistant.util.dt as dt_util
from homeassistant.util.json import JsonObjectType, json_loads_object
@ -265,28 +271,35 @@ async def async_enable_proactive_mode(
checker = await create_checker(hass, DOMAIN, extra_significant_check)
async def async_entity_state_listener(
changed_entity: str,
old_state: State | None,
new_state: State | None,
) -> None:
@callback
def _async_entity_state_filter(data: EventStateChangedData) -> bool:
if not hass.is_running:
return
return False
if not new_state:
return
if not (new_state := data["new_state"]):
return False
if new_state.domain not in ENTITY_ADAPTERS:
return
return False
changed_entity = data["entity_id"]
if not smart_home_config.should_expose(changed_entity):
_LOGGER.debug("Not exposing %s because filtered by config", changed_entity)
return
return False
return True
async def _async_entity_state_listener(
event_: Event[EventStateChangedData],
) -> None:
data = event_.data
new_state = data["new_state"]
if TYPE_CHECKING:
assert new_state is not None
alexa_changed_entity: AlexaEntity = ENTITY_ADAPTERS[new_state.domain](
hass, smart_home_config, new_state
)
# Determine how entity should be reported on
should_report = False
should_doorbell = False
@ -303,6 +316,7 @@ async def async_enable_proactive_mode(
return
if should_doorbell:
old_state = data["old_state"]
if (
new_state.domain == event.DOMAIN
or new_state.state == STATE_ON
@ -324,7 +338,12 @@ async def async_enable_proactive_mode(
hass, smart_home_config, alexa_changed_entity, alexa_properties
)
return async_track_state_change(hass, MATCH_ALL, async_entity_state_listener)
return hass.bus.async_listen(
EVENT_STATE_CHANGED,
_async_entity_state_listener,
event_filter=_async_entity_state_filter,
run_immediately=True,
)
async def async_send_changereport_message(

View File

@ -185,14 +185,14 @@ async def test_report_state_unsets_authorized_on_error(
config = get_default_config(hass)
await state_report.async_enable_proactive_mode(hass, config)
config._store.set_authorized.assert_not_called()
hass.states.async_set(
"binary_sensor.test_contact",
"off",
{"friendly_name": "Test Contact Sensor", "device_class": "door"},
)
config._store.set_authorized.assert_not_called()
# To trigger event listener
await hass.async_block_till_done()
config._store.set_authorized.assert_called_once_with(False)
@ -215,15 +215,15 @@ async def test_report_state_unsets_authorized_on_access_token_error(
await state_report.async_enable_proactive_mode(hass, config)
hass.states.async_set(
"binary_sensor.test_contact",
"off",
{"friendly_name": "Test Contact Sensor", "device_class": "door"},
)
config._store.set_authorized.assert_not_called()
with patch.object(config, "async_get_access_token", AsyncMock(side_effect=exc)):
hass.states.async_set(
"binary_sensor.test_contact",
"off",
{"friendly_name": "Test Contact Sensor", "device_class": "door"},
)
# To trigger event listener
await hass.async_block_till_done()
config._store.set_authorized.assert_called_once_with(False)
@ -731,39 +731,39 @@ async def test_proactive_mode_filter_states(
assert len(aioclient_mock.mock_calls) == 0
# hass not running should not report
current_state = hass.state
hass.set_state(core.CoreState.stopping)
await hass.async_block_till_done()
await hass.async_block_till_done()
hass.states.async_set(
"binary_sensor.test_contact",
"off",
{"friendly_name": "Test Contact Sensor", "device_class": "door"},
)
current_state = hass.state
hass.set_state(core.CoreState.stopping)
await hass.async_block_till_done()
await hass.async_block_till_done()
hass.set_state(current_state)
assert len(aioclient_mock.mock_calls) == 0
# unsupported entity should not report
hass.states.async_set(
"binary_sensor.test_contact",
"on",
{"friendly_name": "Test Contact Sensor", "device_class": "door"},
)
with patch.dict(
"homeassistant.components.alexa.state_report.ENTITY_ADAPTERS", {}, clear=True
):
hass.states.async_set(
"binary_sensor.test_contact",
"on",
{"friendly_name": "Test Contact Sensor", "device_class": "door"},
)
await hass.async_block_till_done()
await hass.async_block_till_done()
assert len(aioclient_mock.mock_calls) == 0
# Not exposed by config should not report
hass.states.async_set(
"binary_sensor.test_contact",
"off",
{"friendly_name": "Test Contact Sensor", "device_class": "door"},
)
with patch.object(config, "should_expose", return_value=False):
hass.states.async_set(
"binary_sensor.test_contact",
"off",
{"friendly_name": "Test Contact Sensor", "device_class": "door"},
)
await hass.async_block_till_done()
await hass.async_block_till_done()
assert len(aioclient_mock.mock_calls) == 0