-
-
Notifications
You must be signed in to change notification settings - Fork 35.8k
Improve scan interval for Airthings Corentium Home 2 #155694
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from 15 commits
e024fa7
3564eb7
7133275
4afac76
cc6e552
9573a82
c0f2bb3
011c0a7
2bac611
8fa4fac
bd76df9
2d70980
f115848
bdd741c
04b786e
64c041a
3b1a873
46ea184
7db8444
d59ac29
af07f3d
c0627d6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,5 +7,6 @@ | |
| VOLUME_PICOCURIE = "pCi/L" | ||
|
|
||
| DEFAULT_SCAN_INTERVAL = 300 | ||
| RADON_SCAN_INTERVAL = 1800 | ||
|
|
||
| MAX_RETRIES_AFTER_STARTUP = 5 | ||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,7 +5,11 @@ | |||||||||
| from datetime import timedelta | ||||||||||
| import logging | ||||||||||
|
|
||||||||||
| from airthings_ble import AirthingsBluetoothDeviceData, AirthingsDevice | ||||||||||
| from airthings_ble import ( | ||||||||||
| AirthingsBluetoothDeviceData, | ||||||||||
| AirthingsDevice, | ||||||||||
| AirthingsDeviceType, | ||||||||||
| ) | ||||||||||
| from bleak.backends.device import BLEDevice | ||||||||||
| from bleak_retry_connector import close_stale_connections_by_address | ||||||||||
|
|
||||||||||
|
|
@@ -16,7 +20,7 @@ | |||||||||
| from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed | ||||||||||
| from homeassistant.util.unit_system import METRIC_SYSTEM | ||||||||||
|
|
||||||||||
| from .const import DEFAULT_SCAN_INTERVAL, DOMAIN | ||||||||||
| from .const import DEFAULT_SCAN_INTERVAL, DOMAIN, RADON_SCAN_INTERVAL | ||||||||||
|
|
||||||||||
| _LOGGER = logging.getLogger(__name__) | ||||||||||
|
|
||||||||||
|
|
@@ -34,12 +38,19 @@ def __init__(self, hass: HomeAssistant, entry: AirthingsBLEConfigEntry) -> None: | |||||||||
| self.airthings = AirthingsBluetoothDeviceData( | ||||||||||
| _LOGGER, hass.config.units is METRIC_SYSTEM | ||||||||||
| ) | ||||||||||
|
|
||||||||||
| device_model = entry.data.get("device_model") | ||||||||||
| if device_model == AirthingsDeviceType.CORENTIUM_HOME_2.value: | ||||||||||
| interval = RADON_SCAN_INTERVAL | ||||||||||
| else: | ||||||||||
| interval = DEFAULT_SCAN_INTERVAL | ||||||||||
|
|
||||||||||
| super().__init__( | ||||||||||
| hass, | ||||||||||
| _LOGGER, | ||||||||||
| config_entry=entry, | ||||||||||
| name=DOMAIN, | ||||||||||
| update_interval=timedelta(seconds=DEFAULT_SCAN_INTERVAL), | ||||||||||
| update_interval=timedelta(seconds=interval), | ||||||||||
| ) | ||||||||||
|
|
||||||||||
| async def _async_setup(self) -> None: | ||||||||||
|
|
@@ -58,11 +69,26 @@ async def _async_setup(self) -> None: | |||||||||
| ) | ||||||||||
| self.ble_device = ble_device | ||||||||||
|
|
||||||||||
| if "device_model" not in self.config_entry.data: | ||||||||||
|
||||||||||
| try: | ||||||||||
| _LOGGER.debug("Fetching device info for migration") | ||||||||||
|
||||||||||
| try: | |
| _LOGGER.debug("Fetching device info for migration") | |
| _LOGGER.debug("Fetching device info for migration") | |
| try: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be more specific here, ideally we should also update the one in async_update_data but that is outside of the scope
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted. Will try to handle this (+ the other one) in a separate PR.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UpdateFailed
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,160 @@ | ||
| """Test the Airthings BLE coordinator.""" | ||
|
|
||
| from datetime import timedelta | ||
| from unittest.mock import patch | ||
|
|
||
| import pytest | ||
|
|
||
| from homeassistant.components.airthings_ble.const import ( | ||
| DEFAULT_SCAN_INTERVAL, | ||
| DOMAIN, | ||
| RADON_SCAN_INTERVAL, | ||
| ) | ||
| from homeassistant.components.airthings_ble.coordinator import ( | ||
| AirthingsBLEDataUpdateCoordinator, | ||
| ) | ||
| from homeassistant.core import HomeAssistant | ||
|
|
||
| from . import CORENTIUM_HOME_2_DEVICE_INFO, WAVE_DEVICE_INFO, WAVE_ENHANCE_DEVICE_INFO | ||
|
|
||
| from tests.common import MockConfigEntry | ||
| from tests.components.bluetooth import generate_ble_device | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| ("device_info", "expected_interval"), | ||
| [ | ||
| (CORENTIUM_HOME_2_DEVICE_INFO, RADON_SCAN_INTERVAL), | ||
| (WAVE_DEVICE_INFO, DEFAULT_SCAN_INTERVAL), | ||
| (WAVE_ENHANCE_DEVICE_INFO, DEFAULT_SCAN_INTERVAL), | ||
| ], | ||
| ) | ||
| async def test_scan_interval_adjustment( | ||
| hass: HomeAssistant, | ||
| device_info, | ||
| expected_interval: int, | ||
| ) -> None: | ||
| """Test that scan interval is adjusted based on device type.""" | ||
| coordinator = AirthingsBLEDataUpdateCoordinator( | ||
| hass=hass, | ||
| entry=MockConfigEntry( | ||
| domain=DOMAIN, | ||
| unique_id="cc:cc:cc:cc:cc:cc", | ||
| data={"device_model": device_info.model.value}, | ||
| ), | ||
| ) | ||
| coordinator.ble_device = generate_ble_device("cc:cc:cc:cc:cc:cc", device_info.name) | ||
|
|
||
| assert coordinator.update_interval == timedelta(seconds=expected_interval) | ||
|
|
||
|
|
||
| async def test_migration_existing_entry_radon_device( | ||
| hass: HomeAssistant, | ||
| ) -> None: | ||
| """Test migration of existing config entry without device_model for radon device.""" | ||
| entry = MockConfigEntry( | ||
| domain=DOMAIN, | ||
| unique_id="cc:cc:cc:cc:cc:cc", | ||
| data={}, | ||
| ) | ||
| entry.add_to_hass(hass) | ||
|
|
||
| coordinator = AirthingsBLEDataUpdateCoordinator( | ||
| hass=hass, | ||
| entry=entry, | ||
| ) | ||
|
|
||
| assert coordinator.update_interval == timedelta(seconds=DEFAULT_SCAN_INTERVAL) | ||
| assert "device_model" not in entry.data | ||
|
|
||
| with ( | ||
| patch( | ||
| "homeassistant.components.airthings_ble.coordinator.AirthingsBluetoothDeviceData.update_device", | ||
| return_value=CORENTIUM_HOME_2_DEVICE_INFO, | ||
| ), | ||
| patch( | ||
| "homeassistant.components.bluetooth.async_ble_device_from_address", | ||
| return_value=generate_ble_device( | ||
| "cc:cc:cc:cc:cc:cc", CORENTIUM_HOME_2_DEVICE_INFO.name | ||
| ), | ||
| ), | ||
| ): | ||
| await coordinator._async_setup() | ||
|
|
||
| assert "device_model" in entry.data | ||
| assert entry.data["device_model"] == CORENTIUM_HOME_2_DEVICE_INFO.model.value | ||
| assert coordinator.update_interval == timedelta(seconds=RADON_SCAN_INTERVAL) | ||
|
|
||
|
|
||
| async def test_migration_existing_entry_non_radon_device( | ||
| hass: HomeAssistant, | ||
| ) -> None: | ||
| """Test migration of existing config entry without device_model for non-radon device.""" | ||
| entry = MockConfigEntry( | ||
| domain=DOMAIN, | ||
| unique_id="cc:cc:cc:cc:cc:cc", | ||
| data={}, | ||
| ) | ||
| entry.add_to_hass(hass) | ||
|
|
||
| coordinator = AirthingsBLEDataUpdateCoordinator( | ||
| hass=hass, | ||
| entry=entry, | ||
| ) | ||
|
|
||
| assert coordinator.update_interval == timedelta(seconds=DEFAULT_SCAN_INTERVAL) | ||
| assert "device_model" not in entry.data | ||
|
|
||
| with ( | ||
| patch( | ||
| "homeassistant.components.airthings_ble.coordinator.AirthingsBluetoothDeviceData.update_device", | ||
| return_value=WAVE_DEVICE_INFO, | ||
| ), | ||
| patch( | ||
| "homeassistant.components.bluetooth.async_ble_device_from_address", | ||
| return_value=generate_ble_device( | ||
| "cc:cc:cc:cc:cc:cc", WAVE_DEVICE_INFO.name | ||
| ), | ||
| ), | ||
| ): | ||
| await coordinator._async_setup() | ||
|
|
||
| assert "device_model" in entry.data | ||
| assert entry.data["device_model"] == WAVE_DEVICE_INFO.model.value | ||
| assert coordinator.update_interval == timedelta(seconds=DEFAULT_SCAN_INTERVAL) | ||
|
|
||
|
|
||
| async def test_no_migration_when_device_model_exists( | ||
| hass: HomeAssistant, | ||
| ) -> None: | ||
| """Test that migration does not run when device_model already exists.""" | ||
| entry = MockConfigEntry( | ||
| domain=DOMAIN, | ||
| unique_id="cc:cc:cc:cc:cc:cc", | ||
| data={"device_model": WAVE_DEVICE_INFO.model.value}, | ||
| ) | ||
| entry.add_to_hass(hass) | ||
|
|
||
| coordinator = AirthingsBLEDataUpdateCoordinator( | ||
| hass=hass, | ||
| entry=entry, | ||
| ) | ||
|
|
||
| assert coordinator.update_interval == timedelta(seconds=DEFAULT_SCAN_INTERVAL) | ||
|
|
||
| with ( | ||
| patch( | ||
| "homeassistant.components.airthings_ble.coordinator.AirthingsBluetoothDeviceData.update_device", | ||
| ) as mock_update, | ||
| patch( | ||
| "homeassistant.components.bluetooth.async_ble_device_from_address", | ||
| return_value=generate_ble_device( | ||
| "cc:cc:cc:cc:cc:cc", WAVE_DEVICE_INFO.name | ||
| ), | ||
| ), | ||
| ): | ||
| await coordinator._async_setup() | ||
|
|
||
| # Migration should not have been called | ||
| mock_update.assert_not_called() | ||
| assert entry.data["device_model"] == WAVE_DEVICE_INFO.model.value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would assume these changes also have an effect to the test_config_flow.py