mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Make Bluetooth active coordinator debouncers run tasks in the background (#113129)
This commit is contained in:
parent
4c2a54746d
commit
c948392ebc
@ -99,6 +99,7 @@ class ActiveBluetoothDataUpdateCoordinator(
|
|||||||
cooldown=POLL_DEFAULT_COOLDOWN,
|
cooldown=POLL_DEFAULT_COOLDOWN,
|
||||||
immediate=POLL_DEFAULT_IMMEDIATE,
|
immediate=POLL_DEFAULT_IMMEDIATE,
|
||||||
function=self._async_poll,
|
function=self._async_poll,
|
||||||
|
background=True,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
poll_debouncer.function = self._async_poll
|
poll_debouncer.function = self._async_poll
|
||||||
|
@ -92,6 +92,7 @@ class ActiveBluetoothProcessorCoordinator(
|
|||||||
cooldown=POLL_DEFAULT_COOLDOWN,
|
cooldown=POLL_DEFAULT_COOLDOWN,
|
||||||
immediate=POLL_DEFAULT_IMMEDIATE,
|
immediate=POLL_DEFAULT_IMMEDIATE,
|
||||||
function=self._async_poll,
|
function=self._async_poll,
|
||||||
|
background=True,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
poll_debouncer.function = self._async_poll
|
poll_debouncer.function = self._async_poll
|
||||||
|
@ -129,7 +129,7 @@ async def test_basic_usage(
|
|||||||
cancel = coordinator.async_start()
|
cancel = coordinator.async_start()
|
||||||
|
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
||||||
assert coordinator.data == {"fake": "data"}
|
assert coordinator.data == {"fake": "data"}
|
||||||
|
|
||||||
@ -175,13 +175,13 @@ async def test_bleak_error_during_polling(
|
|||||||
cancel = coordinator.async_start()
|
cancel = coordinator.async_start()
|
||||||
|
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
||||||
assert coordinator.data is None
|
assert coordinator.data is None
|
||||||
assert coordinator.last_poll_successful is False
|
assert coordinator.last_poll_successful is False
|
||||||
|
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO_2.rssi}
|
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO_2.rssi}
|
||||||
assert coordinator.data == {"fake": "data"}
|
assert coordinator.data == {"fake": "data"}
|
||||||
assert coordinator.last_poll_successful is True
|
assert coordinator.last_poll_successful is True
|
||||||
@ -228,13 +228,13 @@ async def test_generic_exception_during_polling(
|
|||||||
cancel = coordinator.async_start()
|
cancel = coordinator.async_start()
|
||||||
|
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
||||||
assert coordinator.data is None
|
assert coordinator.data is None
|
||||||
assert coordinator.last_poll_successful is False
|
assert coordinator.last_poll_successful is False
|
||||||
|
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO_2.rssi}
|
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO_2.rssi}
|
||||||
assert coordinator.data == {"fake": "data"}
|
assert coordinator.data == {"fake": "data"}
|
||||||
assert coordinator.last_poll_successful is True
|
assert coordinator.last_poll_successful is True
|
||||||
@ -280,7 +280,7 @@ async def test_polling_debounce(
|
|||||||
|
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
||||||
# We should only get one poll because of the debounce
|
# We should only get one poll because of the debounce
|
||||||
assert coordinator.data == {"poll_count": 1}
|
assert coordinator.data == {"poll_count": 1}
|
||||||
@ -316,7 +316,9 @@ async def test_polling_debounce_with_custom_debouncer(
|
|||||||
mode=BluetoothScanningMode.ACTIVE,
|
mode=BluetoothScanningMode.ACTIVE,
|
||||||
needs_poll_method=_needs_poll,
|
needs_poll_method=_needs_poll,
|
||||||
poll_method=_poll_method,
|
poll_method=_poll_method,
|
||||||
poll_debouncer=Debouncer(hass, _LOGGER, cooldown=0.1, immediate=True),
|
poll_debouncer=Debouncer(
|
||||||
|
hass, _LOGGER, cooldown=0.1, immediate=True, background=True
|
||||||
|
),
|
||||||
)
|
)
|
||||||
assert coordinator.available is False # no data yet
|
assert coordinator.available is False # no data yet
|
||||||
|
|
||||||
@ -327,7 +329,7 @@ async def test_polling_debounce_with_custom_debouncer(
|
|||||||
|
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
||||||
# We should only get one poll because of the debounce
|
# We should only get one poll because of the debounce
|
||||||
assert coordinator.data == {"poll_count": 1}
|
assert coordinator.data == {"poll_count": 1}
|
||||||
@ -371,25 +373,25 @@ async def test_polling_rejecting_the_first_time(
|
|||||||
cancel = coordinator.async_start()
|
cancel = coordinator.async_start()
|
||||||
|
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
||||||
# First poll is rejected, so no data yet
|
# First poll is rejected, so no data yet
|
||||||
assert coordinator.data is None
|
assert coordinator.data is None
|
||||||
|
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
||||||
# Data is the same so no poll check
|
# Data is the same so no poll check
|
||||||
assert coordinator.data is None
|
assert coordinator.data is None
|
||||||
|
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO_2.rssi}
|
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO_2.rssi}
|
||||||
# Data is different so poll is done
|
# Data is different so poll is done
|
||||||
assert coordinator.data == {"fake": "data"}
|
assert coordinator.data == {"fake": "data"}
|
||||||
|
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
||||||
# Data is different again so poll is done
|
# Data is different again so poll is done
|
||||||
assert coordinator.data == {"fake": "data"}
|
assert coordinator.data == {"fake": "data"}
|
||||||
@ -434,19 +436,19 @@ async def test_no_polling_after_stop_event(
|
|||||||
assert needs_poll_calls == 0
|
assert needs_poll_calls == 0
|
||||||
|
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
assert coordinator.passive_data == {"rssi": GENERIC_BLUETOOTH_SERVICE_INFO.rssi}
|
||||||
assert coordinator.data == {"fake": "data"}
|
assert coordinator.data == {"fake": "data"}
|
||||||
|
|
||||||
assert needs_poll_calls == 1
|
assert needs_poll_calls == 1
|
||||||
|
|
||||||
hass.set_state(CoreState.stopping)
|
hass.set_state(CoreState.stopping)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert needs_poll_calls == 1
|
assert needs_poll_calls == 1
|
||||||
|
|
||||||
# Should not generate a poll now
|
# Should not generate a poll now
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert needs_poll_calls == 1
|
assert needs_poll_calls == 1
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
|
@ -84,7 +84,7 @@ async def test_basic_usage(
|
|||||||
cancel = coordinator.async_start()
|
cancel = coordinator.async_start()
|
||||||
|
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
|
|
||||||
assert coordinator.available is True
|
assert coordinator.available is True
|
||||||
|
|
||||||
@ -127,10 +127,7 @@ async def test_poll_can_be_skipped(
|
|||||||
needs_poll_method=_poll_needed,
|
needs_poll_method=_poll_needed,
|
||||||
poll_method=_poll,
|
poll_method=_poll,
|
||||||
poll_debouncer=Debouncer(
|
poll_debouncer=Debouncer(
|
||||||
hass,
|
hass, _LOGGER, cooldown=0, immediate=True, background=True
|
||||||
_LOGGER,
|
|
||||||
cooldown=0,
|
|
||||||
immediate=True,
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
assert coordinator.available is False # no data yet
|
assert coordinator.available is False # no data yet
|
||||||
@ -142,19 +139,19 @@ async def test_poll_can_be_skipped(
|
|||||||
cancel = coordinator.async_start()
|
cancel = coordinator.async_start()
|
||||||
|
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert async_handle_update.mock_calls[-1] == call({"testdata": True})
|
assert async_handle_update.mock_calls[-1] == call({"testdata": True})
|
||||||
|
|
||||||
flag = False
|
flag = False
|
||||||
|
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert async_handle_update.mock_calls[-1] == call({"testdata": None}, True)
|
assert async_handle_update.mock_calls[-1] == call({"testdata": None}, True)
|
||||||
|
|
||||||
flag = True
|
flag = True
|
||||||
|
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert async_handle_update.mock_calls[-1] == call({"testdata": True})
|
assert async_handle_update.mock_calls[-1] == call({"testdata": True})
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
@ -208,7 +205,7 @@ async def test_bleak_error_and_recover(
|
|||||||
|
|
||||||
# First poll fails
|
# First poll fails
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert async_handle_update.mock_calls[-1] == call({"testdata": None}, False)
|
assert async_handle_update.mock_calls[-1] == call({"testdata": None}, False)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
@ -219,7 +216,7 @@ async def test_bleak_error_and_recover(
|
|||||||
# Second poll works
|
# Second poll works
|
||||||
flag = False
|
flag = False
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert async_handle_update.mock_calls[-1] == call({"testdata": False})
|
assert async_handle_update.mock_calls[-1] == call({"testdata": False})
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
@ -272,13 +269,13 @@ async def test_poll_failure_and_recover(
|
|||||||
|
|
||||||
# First poll fails
|
# First poll fails
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert async_handle_update.mock_calls[-1] == call({"testdata": None}, False)
|
assert async_handle_update.mock_calls[-1] == call({"testdata": None}, False)
|
||||||
|
|
||||||
# Second poll works
|
# Second poll works
|
||||||
flag = False
|
flag = False
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert async_handle_update.mock_calls[-1] == call({"testdata": False})
|
assert async_handle_update.mock_calls[-1] == call({"testdata": False})
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
@ -329,7 +326,7 @@ async def test_second_poll_needed(
|
|||||||
# Second poll gets stuck behind first poll
|
# Second poll gets stuck behind first poll
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
||||||
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert async_handle_update.mock_calls[1] == call({"testdata": 1})
|
assert async_handle_update.mock_calls[1] == call({"testdata": 1})
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
@ -381,7 +378,7 @@ async def test_rate_limit(
|
|||||||
# Third poll gets stuck behind first poll doesn't get queued
|
# Third poll gets stuck behind first poll doesn't get queued
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||||
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert async_handle_update.mock_calls[-1] == call({"testdata": 1})
|
assert async_handle_update.mock_calls[-1] == call({"testdata": 1})
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
@ -425,7 +422,7 @@ async def test_no_polling_after_stop_event(
|
|||||||
cancel = coordinator.async_start()
|
cancel = coordinator.async_start()
|
||||||
|
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert needs_poll_calls == 1
|
assert needs_poll_calls == 1
|
||||||
|
|
||||||
assert coordinator.available is True
|
assert coordinator.available is True
|
||||||
@ -438,12 +435,12 @@ async def test_no_polling_after_stop_event(
|
|||||||
assert async_handle_update.mock_calls[1] == call({"testdata": 1})
|
assert async_handle_update.mock_calls[1] == call({"testdata": 1})
|
||||||
|
|
||||||
hass.set_state(CoreState.stopping)
|
hass.set_state(CoreState.stopping)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert needs_poll_calls == 1
|
assert needs_poll_calls == 1
|
||||||
|
|
||||||
# Should not generate a poll now that CoreState is stopping
|
# Should not generate a poll now that CoreState is stopping
|
||||||
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
inject_bluetooth_service_info(hass, GENERIC_BLUETOOTH_SERVICE_INFO_2)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
assert needs_poll_calls == 1
|
assert needs_poll_calls == 1
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user