mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 19:27:45 +00:00
Deduplicate multiprotocol addon helper (#90102)
* Deduplicate multiprotocol addon helper * Clarify
This commit is contained in:
parent
4c98495fe0
commit
1ea3312ed4
@ -26,6 +26,7 @@ from homeassistant.data_entry_flow import (
|
|||||||
FlowManager,
|
FlowManager,
|
||||||
FlowResult,
|
FlowResult,
|
||||||
)
|
)
|
||||||
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers.singleton import singleton
|
from homeassistant.helpers.singleton import singleton
|
||||||
|
|
||||||
from .const import LOGGER, SILABS_MULTIPROTOCOL_ADDON_SLUG
|
from .const import LOGGER, SILABS_MULTIPROTOCOL_ADDON_SLUG
|
||||||
@ -356,3 +357,53 @@ class OptionsFlowHandler(BaseMultiPanFlow, config_entries.OptionsFlow):
|
|||||||
if user_input is None:
|
if user_input is None:
|
||||||
return self.async_show_form(step_id="addon_installed_other_device")
|
return self.async_show_form(step_id="addon_installed_other_device")
|
||||||
return self.async_create_entry(title="", data={})
|
return self.async_create_entry(title="", data={})
|
||||||
|
|
||||||
|
|
||||||
|
async def check_multi_pan_addon(hass: HomeAssistant) -> None:
|
||||||
|
"""Check the multi-PAN addon state, and start it if installed but not started.
|
||||||
|
|
||||||
|
Does nothing if Hass.io is not loaded.
|
||||||
|
Raises on error or if the add-on is installed but not started.
|
||||||
|
"""
|
||||||
|
if not is_hassio(hass):
|
||||||
|
return
|
||||||
|
|
||||||
|
addon_manager: AddonManager = get_addon_manager(hass)
|
||||||
|
try:
|
||||||
|
addon_info: AddonInfo = await addon_manager.async_get_addon_info()
|
||||||
|
except AddonError as err:
|
||||||
|
_LOGGER.error(err)
|
||||||
|
raise HomeAssistantError from err
|
||||||
|
|
||||||
|
# Request the addon to start if it's not started
|
||||||
|
# addon_manager.async_start_addon returns as soon as the start request has been sent
|
||||||
|
# and does not wait for the addon to be started, so we raise below
|
||||||
|
if addon_info.state == AddonState.NOT_RUNNING:
|
||||||
|
await addon_manager.async_start_addon()
|
||||||
|
|
||||||
|
if addon_info.state not in (AddonState.NOT_INSTALLED, AddonState.RUNNING):
|
||||||
|
_LOGGER.debug("Multi pan addon installed and in state %s", addon_info.state)
|
||||||
|
raise HomeAssistantError
|
||||||
|
|
||||||
|
|
||||||
|
async def get_multi_pan_addon_info(
|
||||||
|
hass: HomeAssistant, device_path: str
|
||||||
|
) -> AddonInfo | None:
|
||||||
|
"""Return AddonInfo if the multi-PAN addon is using the given device.
|
||||||
|
|
||||||
|
Returns None if Hass.io is not loaded, the addon is not running or the addon is
|
||||||
|
connected to another device.
|
||||||
|
"""
|
||||||
|
if not is_hassio(hass):
|
||||||
|
return None
|
||||||
|
|
||||||
|
addon_manager: AddonManager = get_addon_manager(hass)
|
||||||
|
addon_info: AddonInfo = await addon_manager.async_get_addon_info()
|
||||||
|
|
||||||
|
if addon_info.state != AddonState.RUNNING:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if addon_info.options["device"] != device_path:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return addon_info
|
||||||
|
@ -1,75 +1,19 @@
|
|||||||
"""The Home Assistant SkyConnect integration."""
|
"""The Home Assistant SkyConnect integration."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from homeassistant.components import usb
|
from homeassistant.components import usb
|
||||||
from homeassistant.components.hassio import (
|
|
||||||
AddonError,
|
|
||||||
AddonInfo,
|
|
||||||
AddonManager,
|
|
||||||
AddonState,
|
|
||||||
is_hassio,
|
|
||||||
)
|
|
||||||
from homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon import (
|
from homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon import (
|
||||||
get_addon_manager,
|
check_multi_pan_addon,
|
||||||
|
get_multi_pan_addon_info,
|
||||||
get_zigbee_socket,
|
get_zigbee_socket,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .util import get_usb_service_info
|
from .util import get_usb_service_info
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
async def _wait_multi_pan_addon(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
|
||||||
"""Wait for multi-PAN info to be available."""
|
|
||||||
if not is_hassio(hass):
|
|
||||||
return
|
|
||||||
|
|
||||||
addon_manager: AddonManager = get_addon_manager(hass)
|
|
||||||
try:
|
|
||||||
addon_info: AddonInfo = await addon_manager.async_get_addon_info()
|
|
||||||
except AddonError as err:
|
|
||||||
_LOGGER.error(err)
|
|
||||||
raise ConfigEntryNotReady from err
|
|
||||||
|
|
||||||
# Start the addon if it's not started
|
|
||||||
if addon_info.state == AddonState.NOT_RUNNING:
|
|
||||||
await addon_manager.async_start_addon()
|
|
||||||
|
|
||||||
if addon_info.state not in (AddonState.NOT_INSTALLED, AddonState.RUNNING):
|
|
||||||
_LOGGER.debug(
|
|
||||||
"Multi pan addon in state %s, delaying yellow config entry setup",
|
|
||||||
addon_info.state,
|
|
||||||
)
|
|
||||||
raise ConfigEntryNotReady
|
|
||||||
|
|
||||||
|
|
||||||
async def _multi_pan_addon_info(
|
|
||||||
hass: HomeAssistant, entry: ConfigEntry
|
|
||||||
) -> AddonInfo | None:
|
|
||||||
"""Return AddonInfo if the multi-PAN addon is enabled for our SkyConnect."""
|
|
||||||
if not is_hassio(hass):
|
|
||||||
return None
|
|
||||||
|
|
||||||
addon_manager: AddonManager = get_addon_manager(hass)
|
|
||||||
addon_info: AddonInfo = await addon_manager.async_get_addon_info()
|
|
||||||
|
|
||||||
if addon_info.state != AddonState.RUNNING:
|
|
||||||
return None
|
|
||||||
|
|
||||||
usb_dev = entry.data["device"]
|
|
||||||
dev_path = await hass.async_add_executor_job(usb.get_serial_by_id, usb_dev)
|
|
||||||
|
|
||||||
if addon_info.options["device"] != dev_path:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return addon_info
|
|
||||||
|
|
||||||
|
|
||||||
async def _async_usb_scan_done(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
async def _async_usb_scan_done(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
||||||
"""Finish Home Assistant SkyConnect config entry setup."""
|
"""Finish Home Assistant SkyConnect config entry setup."""
|
||||||
@ -87,7 +31,9 @@ async def _async_usb_scan_done(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
|||||||
hass.async_create_task(hass.config_entries.async_remove(entry.entry_id))
|
hass.async_create_task(hass.config_entries.async_remove(entry.entry_id))
|
||||||
return
|
return
|
||||||
|
|
||||||
addon_info = await _multi_pan_addon_info(hass, entry)
|
usb_dev = entry.data["device"]
|
||||||
|
dev_path = await hass.async_add_executor_job(usb.get_serial_by_id, usb_dev)
|
||||||
|
addon_info = await get_multi_pan_addon_info(hass, dev_path)
|
||||||
|
|
||||||
if not addon_info:
|
if not addon_info:
|
||||||
usb_info = get_usb_service_info(entry)
|
usb_info = get_usb_service_info(entry)
|
||||||
@ -115,7 +61,10 @@ async def _async_usb_scan_done(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
|||||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
"""Set up a Home Assistant SkyConnect config entry."""
|
"""Set up a Home Assistant SkyConnect config entry."""
|
||||||
|
|
||||||
await _wait_multi_pan_addon(hass, entry)
|
try:
|
||||||
|
await check_multi_pan_addon(hass)
|
||||||
|
except HomeAssistantError as err:
|
||||||
|
raise ConfigEntryNotReady from err
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_usb_scan_done() -> None:
|
def async_usb_scan_done() -> None:
|
||||||
|
@ -1,58 +1,18 @@
|
|||||||
"""The Home Assistant Yellow integration."""
|
"""The Home Assistant Yellow integration."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
from homeassistant.components.hassio import get_os_info
|
||||||
|
|
||||||
from homeassistant.components.hassio import (
|
|
||||||
AddonError,
|
|
||||||
AddonInfo,
|
|
||||||
AddonManager,
|
|
||||||
AddonState,
|
|
||||||
get_os_info,
|
|
||||||
)
|
|
||||||
from homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon import (
|
from homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon import (
|
||||||
get_addon_manager,
|
check_multi_pan_addon,
|
||||||
|
get_multi_pan_addon_info,
|
||||||
get_zigbee_socket,
|
get_zigbee_socket,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
|
||||||
|
|
||||||
from .const import RADIO_DEVICE, ZHA_HW_DISCOVERY_DATA
|
from .const import RADIO_DEVICE, ZHA_HW_DISCOVERY_DATA
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
async def _multi_pan_addon_info(
|
|
||||||
hass: HomeAssistant, entry: ConfigEntry
|
|
||||||
) -> AddonInfo | None:
|
|
||||||
"""Return AddonInfo if the multi-PAN addon is enabled for the Yellow's radio."""
|
|
||||||
addon_manager: AddonManager = get_addon_manager(hass)
|
|
||||||
try:
|
|
||||||
addon_info: AddonInfo = await addon_manager.async_get_addon_info()
|
|
||||||
except AddonError as err:
|
|
||||||
_LOGGER.error(err)
|
|
||||||
raise ConfigEntryNotReady from err
|
|
||||||
|
|
||||||
# Start the addon if it's not started
|
|
||||||
if addon_info.state == AddonState.NOT_RUNNING:
|
|
||||||
await addon_manager.async_start_addon()
|
|
||||||
|
|
||||||
if addon_info.state not in (AddonState.NOT_INSTALLED, AddonState.RUNNING):
|
|
||||||
_LOGGER.debug(
|
|
||||||
"Multi pan addon in state %s, delaying yellow config entry setup",
|
|
||||||
addon_info.state,
|
|
||||||
)
|
|
||||||
raise ConfigEntryNotReady
|
|
||||||
|
|
||||||
if addon_info.state == AddonState.NOT_INSTALLED:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if addon_info.options["device"] != RADIO_DEVICE:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return addon_info
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
"""Set up a Home Assistant Yellow config entry."""
|
"""Set up a Home Assistant Yellow config entry."""
|
||||||
@ -66,7 +26,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
hass.async_create_task(hass.config_entries.async_remove(entry.entry_id))
|
hass.async_create_task(hass.config_entries.async_remove(entry.entry_id))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
addon_info = await _multi_pan_addon_info(hass, entry)
|
try:
|
||||||
|
await check_multi_pan_addon(hass)
|
||||||
|
except HomeAssistantError as err:
|
||||||
|
raise ConfigEntryNotReady from err
|
||||||
|
|
||||||
|
addon_info = await get_multi_pan_addon_info(hass, RADIO_DEVICE)
|
||||||
|
|
||||||
if not addon_info:
|
if not addon_info:
|
||||||
hw_discovery_data = ZHA_HW_DISCOVERY_DATA
|
hw_discovery_data = ZHA_HW_DISCOVERY_DATA
|
||||||
|
@ -172,7 +172,7 @@ async def test_setup_zha_multipan(
|
|||||||
) as mock_is_plugged_in, patch(
|
) as mock_is_plugged_in, patch(
|
||||||
"homeassistant.components.onboarding.async_is_onboarded", return_value=False
|
"homeassistant.components.onboarding.async_is_onboarded", return_value=False
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.homeassistant_sky_connect.is_hassio",
|
"homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon.is_hassio",
|
||||||
side_effect=Mock(return_value=True),
|
side_effect=Mock(return_value=True),
|
||||||
):
|
):
|
||||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
@ -226,7 +226,7 @@ async def test_setup_zha_multipan_other_device(
|
|||||||
) as mock_is_plugged_in, patch(
|
) as mock_is_plugged_in, patch(
|
||||||
"homeassistant.components.onboarding.async_is_onboarded", return_value=False
|
"homeassistant.components.onboarding.async_is_onboarded", return_value=False
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.homeassistant_sky_connect.is_hassio",
|
"homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon.is_hassio",
|
||||||
side_effect=Mock(return_value=True),
|
side_effect=Mock(return_value=True),
|
||||||
):
|
):
|
||||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
@ -304,7 +304,7 @@ async def test_setup_entry_addon_info_fails(
|
|||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.onboarding.async_is_onboarded", return_value=False
|
"homeassistant.components.onboarding.async_is_onboarded", return_value=False
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.homeassistant_sky_connect.is_hassio",
|
"homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon.is_hassio",
|
||||||
side_effect=Mock(return_value=True),
|
side_effect=Mock(return_value=True),
|
||||||
):
|
):
|
||||||
assert not await hass.config_entries.async_setup(config_entry.entry_id)
|
assert not await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
@ -333,7 +333,7 @@ async def test_setup_entry_addon_not_running(
|
|||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.onboarding.async_is_onboarded", return_value=False
|
"homeassistant.components.onboarding.async_is_onboarded", return_value=False
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.homeassistant_sky_connect.is_hassio",
|
"homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon.is_hassio",
|
||||||
side_effect=Mock(return_value=True),
|
side_effect=Mock(return_value=True),
|
||||||
):
|
):
|
||||||
assert not await hass.config_entries.async_setup(config_entry.entry_id)
|
assert not await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user