Create an issue when Bluetooth is active on old HAOS (#78430)
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>pull/78671/head^2
parent
caba202efa
commit
12856dea05
homeassistant/components/bluetooth
tests/components/bluetooth
|
@ -8,14 +8,24 @@ import platform
|
|||
from typing import TYPE_CHECKING, cast
|
||||
|
||||
import async_timeout
|
||||
from awesomeversion import AwesomeVersion
|
||||
|
||||
from homeassistant.components import usb
|
||||
from homeassistant.config_entries import SOURCE_INTEGRATION_DISCOVERY, ConfigEntry
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.config_entries import (
|
||||
SOURCE_IGNORE,
|
||||
SOURCE_INTEGRATION_DISCOVERY,
|
||||
ConfigEntry,
|
||||
)
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STARTED, EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback as hass_callback
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers import device_registry as dr, discovery_flow
|
||||
from homeassistant.helpers.debounce import Debouncer
|
||||
from homeassistant.helpers.issue_registry import (
|
||||
IssueSeverity,
|
||||
async_create_issue,
|
||||
async_delete_issue,
|
||||
)
|
||||
from homeassistant.loader import async_get_bluetooth
|
||||
|
||||
from . import models
|
||||
|
@ -71,6 +81,8 @@ __all__ = [
|
|||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
RECOMMENDED_MIN_HAOS_VERSION = AwesomeVersion("9.0.dev0")
|
||||
|
||||
|
||||
def _get_manager(hass: HomeAssistant) -> BluetoothManager:
|
||||
"""Get the bluetooth manager."""
|
||||
|
@ -223,6 +235,43 @@ async def async_get_adapter_from_address(
|
|||
return await _get_manager(hass).async_get_adapter_from_address(address)
|
||||
|
||||
|
||||
@hass_callback
|
||||
def _async_haos_is_new_enough(hass: HomeAssistant) -> bool:
|
||||
"""Check if the version of Home Assistant Operating System is new enough."""
|
||||
# Only warn if a USB adapter is plugged in
|
||||
if not any(
|
||||
entry
|
||||
for entry in hass.config_entries.async_entries(DOMAIN)
|
||||
if entry.source != SOURCE_IGNORE
|
||||
):
|
||||
return True
|
||||
if (
|
||||
not hass.components.hassio.is_hassio()
|
||||
or not (os_info := hass.components.hassio.get_os_info())
|
||||
or not (haos_version := os_info.get("version"))
|
||||
or AwesomeVersion(haos_version) >= RECOMMENDED_MIN_HAOS_VERSION
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@hass_callback
|
||||
def _async_check_haos(hass: HomeAssistant) -> None:
|
||||
"""Create or delete an the haos_outdated issue."""
|
||||
if _async_haos_is_new_enough(hass):
|
||||
async_delete_issue(hass, DOMAIN, "haos_outdated")
|
||||
return
|
||||
async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
"haos_outdated",
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.WARNING,
|
||||
learn_more_url="/config/updates",
|
||||
translation_key="haos_outdated",
|
||||
)
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Set up the bluetooth integration."""
|
||||
integration_matcher = IntegrationMatcher(await async_get_bluetooth(hass))
|
||||
|
@ -261,6 +310,13 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||
EVENT_HOMEASSISTANT_STOP, hass_callback(lambda event: cancel())
|
||||
)
|
||||
|
||||
# Wait to check until after start to make sure
|
||||
# that the system info is available.
|
||||
hass.bus.async_listen_once(
|
||||
EVENT_HOMEASSISTANT_STARTED,
|
||||
hass_callback(lambda event: _async_check_haos(hass)),
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"name": "Bluetooth",
|
||||
"documentation": "https://www.home-assistant.io/integrations/bluetooth",
|
||||
"dependencies": ["usb"],
|
||||
"after_dependencies": ["hassio"],
|
||||
"quality_scale": "internal",
|
||||
"requirements": [
|
||||
"bleak==0.17.0",
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
{
|
||||
"issues": {
|
||||
"haos_outdated": {
|
||||
"title": "Update to Home Assistant Operating System 9.0 or later",
|
||||
"description": "To improve Bluetooth reliability and performance, we highly recommend you update to version 9.0 or later of the Home Assistant Operating System."
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"flow_title": "{name}",
|
||||
"step": {
|
||||
|
|
|
@ -9,9 +9,6 @@
|
|||
"bluetooth_confirm": {
|
||||
"description": "Do you want to setup {name}?"
|
||||
},
|
||||
"enable_bluetooth": {
|
||||
"description": "Do you want to setup Bluetooth?"
|
||||
},
|
||||
"multiple_adapters": {
|
||||
"data": {
|
||||
"adapter": "Adapter"
|
||||
|
@ -29,14 +26,18 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
"haos_outdated": {
|
||||
"description": "To improve Bluetooth reliability and performance, we highly recommend you update to version 9.0 or later of the Home Assistant Operating System.",
|
||||
"title": "Update to Home Assistant Operating System 9.0 or later"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"data": {
|
||||
"adapter": "The Bluetooth Adapter to use for scanning",
|
||||
"passive": "Passive scanning"
|
||||
},
|
||||
"description": "Passive listening requires BlueZ 5.63 or later with experimental features enabled."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,44 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
|||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(name="operating_system_85")
|
||||
def mock_operating_system_85():
|
||||
"""Mock running Home Assistant Operating system 8.5."""
|
||||
with patch("homeassistant.components.hassio.is_hassio", return_value=True), patch(
|
||||
"homeassistant.components.hassio.get_os_info",
|
||||
return_value={
|
||||
"version": "8.5",
|
||||
"version_latest": "10.0.dev20220912",
|
||||
"update_available": False,
|
||||
"board": "odroid-n2",
|
||||
"boot": "B",
|
||||
"data_disk": "/dev/mmcblk1p4",
|
||||
},
|
||||
), patch("homeassistant.components.hassio.get_info", return_value={}), patch(
|
||||
"homeassistant.components.hassio.get_host_info", return_value={}
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture(name="operating_system_90")
|
||||
def mock_operating_system_90():
|
||||
"""Mock running Home Assistant Operating system 9.0."""
|
||||
with patch("homeassistant.components.hassio.is_hassio", return_value=True), patch(
|
||||
"homeassistant.components.hassio.get_os_info",
|
||||
return_value={
|
||||
"version": "9.0.dev20220912",
|
||||
"version_latest": "10.0.dev20220912",
|
||||
"update_available": False,
|
||||
"board": "odroid-n2",
|
||||
"boot": "B",
|
||||
"data_disk": "/dev/mmcblk1p4",
|
||||
},
|
||||
), patch("homeassistant.components.hassio.get_info", return_value={}), patch(
|
||||
"homeassistant.components.hassio.get_host_info", return_value={}
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture(name="bluez_dbus_mock")
|
||||
def bluez_dbus_mock():
|
||||
"""Fixture that mocks out the bluez dbus calls."""
|
||||
|
@ -39,6 +77,23 @@ def windows_adapter():
|
|||
yield
|
||||
|
||||
|
||||
@pytest.fixture(name="no_adapters")
|
||||
def no_adapter_fixture(bluez_dbus_mock):
|
||||
"""Fixture that mocks no adapters on Linux."""
|
||||
with patch(
|
||||
"homeassistant.components.bluetooth.platform.system", return_value="Linux"
|
||||
), patch(
|
||||
"homeassistant.components.bluetooth.scanner.platform.system",
|
||||
return_value="Linux",
|
||||
), patch(
|
||||
"homeassistant.components.bluetooth.util.platform.system", return_value="Linux"
|
||||
), patch(
|
||||
"bluetooth_adapters.get_bluetooth_adapter_details",
|
||||
return_value={},
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture(name="one_adapter")
|
||||
def one_adapter_fixture(bluez_dbus_mock):
|
||||
"""Fixture that mocks one adapter on Linux."""
|
||||
|
|
|
@ -37,6 +37,7 @@ from homeassistant.components.bluetooth.match import (
|
|||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STARTED, EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.issue_registry import async_get as async_get_issue_registry
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
|
@ -2680,3 +2681,51 @@ async def test_discover_new_usb_adapters(hass, mock_bleak_scanner_start, one_ada
|
|||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.config_entries.flow.async_progress(DOMAIN)) == 1
|
||||
|
||||
|
||||
async def test_issue_outdated_haos(
|
||||
hass, mock_bleak_scanner_start, one_adapter, operating_system_85
|
||||
):
|
||||
"""Test we create an issue on outdated haos."""
|
||||
entry = MockConfigEntry(
|
||||
domain=bluetooth.DOMAIN, data={}, unique_id="00:00:00:00:00:01"
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
assert await async_setup_component(hass, bluetooth.DOMAIN, {})
|
||||
await hass.async_block_till_done()
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
await hass.async_block_till_done()
|
||||
registry = async_get_issue_registry(hass)
|
||||
issue = registry.async_get_issue(DOMAIN, "haos_outdated")
|
||||
assert issue is not None
|
||||
|
||||
|
||||
async def test_issue_outdated_haos_no_adapters(
|
||||
hass, mock_bleak_scanner_start, no_adapters, operating_system_85
|
||||
):
|
||||
"""Test we do not create an issue on outdated haos if there are no adapters."""
|
||||
assert await async_setup_component(hass, bluetooth.DOMAIN, {})
|
||||
await hass.async_block_till_done()
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
registry = async_get_issue_registry(hass)
|
||||
issue = registry.async_get_issue(DOMAIN, "haos_outdated")
|
||||
assert issue is None
|
||||
|
||||
|
||||
async def test_haos_9_or_later(
|
||||
hass, mock_bleak_scanner_start, one_adapter, operating_system_90
|
||||
):
|
||||
"""Test we do not create issues for haos 9.x or later."""
|
||||
entry = MockConfigEntry(
|
||||
domain=bluetooth.DOMAIN, data={}, unique_id="00:00:00:00:00:01"
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
assert await async_setup_component(hass, bluetooth.DOMAIN, {})
|
||||
await hass.async_block_till_done()
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
await hass.async_block_till_done()
|
||||
registry = async_get_issue_registry(hass)
|
||||
issue = registry.async_get_issue(DOMAIN, "haos_outdated")
|
||||
assert issue is None
|
||||
|
|
Loading…
Reference in New Issue