mirror of
https://github.com/home-assistant/core.git
synced 2025-04-19 14:57:52 +00:00
Add async_set_updated_data method to PassiveBluetoothProcessorCoordinator (#142879)
This commit is contained in:
parent
8ab59bee47
commit
8b88272bc0
@ -374,6 +374,27 @@ class PassiveBluetoothProcessorCoordinator[_DataT](BasePassiveBluetoothCoordinat
|
||||
self.logger.exception("Unexpected error updating %s data", self.name)
|
||||
return
|
||||
|
||||
self._process_update(update, was_available)
|
||||
|
||||
@callback
|
||||
def async_set_updated_data(self, update: _DataT) -> None:
|
||||
"""Manually update the processor with new data.
|
||||
|
||||
If the data comes in via a different method, like a
|
||||
notification, this method can be used to update the
|
||||
processor with the new data.
|
||||
|
||||
This is useful for devices that retrieve
|
||||
some of their data via notifications.
|
||||
"""
|
||||
was_available = self._available
|
||||
self._available = True
|
||||
self._process_update(update, was_available)
|
||||
|
||||
def _process_update(
|
||||
self, update: _DataT, was_available: bool | None = None
|
||||
) -> None:
|
||||
"""Process the update from the bluetooth device."""
|
||||
if not self.last_update_success:
|
||||
self.last_update_success = True
|
||||
self.logger.info("Coordinator %s recovered", self.name)
|
||||
|
@ -273,6 +273,111 @@ async def test_basic_usage(hass: HomeAssistant) -> None:
|
||||
cancel_coordinator()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_bleak_scanner_start", "mock_bluetooth_adapters")
|
||||
async def test_async_set_updated_data_usage(hass: HomeAssistant) -> None:
|
||||
"""Test async_set_updated_data of the PassiveBluetoothProcessorCoordinator."""
|
||||
await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
|
||||
|
||||
@callback
|
||||
def _mock_update_method(
|
||||
service_info: BluetoothServiceInfo,
|
||||
) -> dict[str, str]:
|
||||
return {"test": "data"}
|
||||
|
||||
@callback
|
||||
def _async_generate_mock_data(
|
||||
data: dict[str, str],
|
||||
) -> PassiveBluetoothDataUpdate:
|
||||
"""Generate mock data."""
|
||||
assert data == {"test": "data"}
|
||||
return GENERIC_PASSIVE_BLUETOOTH_DATA_UPDATE
|
||||
|
||||
coordinator = PassiveBluetoothProcessorCoordinator(
|
||||
hass,
|
||||
_LOGGER,
|
||||
"aa:bb:cc:dd:ee:ff",
|
||||
BluetoothScanningMode.ACTIVE,
|
||||
_mock_update_method,
|
||||
)
|
||||
assert coordinator.available is False # no data yet
|
||||
|
||||
processor = PassiveBluetoothDataProcessor(_async_generate_mock_data)
|
||||
|
||||
unregister_processor = coordinator.async_register_processor(processor)
|
||||
cancel_coordinator = coordinator.async_start()
|
||||
|
||||
entity_key = PassiveBluetoothEntityKey("temperature", None)
|
||||
entity_key_events = []
|
||||
all_events = []
|
||||
mock_entity = MagicMock()
|
||||
mock_add_entities = MagicMock()
|
||||
|
||||
def _async_entity_key_listener(data: PassiveBluetoothDataUpdate | None) -> None:
|
||||
"""Mock entity key listener."""
|
||||
entity_key_events.append(data)
|
||||
|
||||
cancel_async_add_entity_key_listener = processor.async_add_entity_key_listener(
|
||||
_async_entity_key_listener,
|
||||
entity_key,
|
||||
)
|
||||
|
||||
def _all_listener(data: PassiveBluetoothDataUpdate | None) -> None:
|
||||
"""Mock an all listener."""
|
||||
all_events.append(data)
|
||||
|
||||
cancel_listener = processor.async_add_listener(
|
||||
_all_listener,
|
||||
)
|
||||
|
||||
cancel_async_add_entities_listener = processor.async_add_entities_listener(
|
||||
mock_entity,
|
||||
mock_add_entities,
|
||||
)
|
||||
|
||||
assert coordinator.available is False
|
||||
coordinator.async_set_updated_data({"test": "data"})
|
||||
assert coordinator.available is True
|
||||
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
|
||||
# Each listener should receive the same data
|
||||
# since both match, and an additional all_events
|
||||
# for the async_set_updated_data call
|
||||
assert len(entity_key_events) == 1
|
||||
assert len(all_events) == 2
|
||||
|
||||
# There should be 4 calls to create entities
|
||||
assert len(mock_entity.mock_calls) == 2
|
||||
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
||||
|
||||
# Only the all listener should receive the new data
|
||||
# since temperature is not in the new data, and an additional all_events
|
||||
# for the async_set_updated_data call
|
||||
assert len(entity_key_events) == 1
|
||||
assert len(all_events) == 3
|
||||
|
||||
# On the second, the entities should already be created
|
||||
# so the mock should not be called again
|
||||
assert len(mock_entity.mock_calls) == 2
|
||||
|
||||
cancel_async_add_entity_key_listener()
|
||||
cancel_listener()
|
||||
cancel_async_add_entities_listener()
|
||||
|
||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||
|
||||
# Each listener should not trigger any more now
|
||||
# that they were cancelled
|
||||
assert len(entity_key_events) == 1
|
||||
assert len(all_events) == 3
|
||||
assert len(mock_entity.mock_calls) == 2
|
||||
assert coordinator.available is True
|
||||
|
||||
unregister_processor()
|
||||
cancel_coordinator()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_bleak_scanner_start", "mock_bluetooth_adapters")
|
||||
async def test_entity_key_is_dispatched_on_entity_key_change(
|
||||
hass: HomeAssistant,
|
||||
|
Loading…
x
Reference in New Issue
Block a user