mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Add firmware update entity to IronOS integration (#123031)
This commit is contained in:
parent
1eaaa5c6d3
commit
3e8f3cfb49
@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
import logging
|
import logging
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from aiogithubapi import GitHubAPI
|
||||||
from pynecil import Pynecil
|
from pynecil import Pynecil
|
||||||
|
|
||||||
from homeassistant.components import bluetooth
|
from homeassistant.components import bluetooth
|
||||||
@ -12,13 +14,23 @@ from homeassistant.config_entries import ConfigEntry
|
|||||||
from homeassistant.const import CONF_NAME, Platform
|
from homeassistant.const import CONF_NAME, Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .coordinator import IronOSCoordinator
|
from .coordinator import IronOSFirmwareUpdateCoordinator, IronOSLiveDataCoordinator
|
||||||
|
|
||||||
PLATFORMS: list[Platform] = [Platform.NUMBER, Platform.SENSOR]
|
PLATFORMS: list[Platform] = [Platform.NUMBER, Platform.SENSOR, Platform.UPDATE]
|
||||||
|
|
||||||
type IronOSConfigEntry = ConfigEntry[IronOSCoordinator]
|
|
||||||
|
@dataclass
|
||||||
|
class IronOSCoordinators:
|
||||||
|
"""IronOS data class holding coordinators."""
|
||||||
|
|
||||||
|
live_data: IronOSLiveDataCoordinator
|
||||||
|
firmware: IronOSFirmwareUpdateCoordinator
|
||||||
|
|
||||||
|
|
||||||
|
type IronOSConfigEntry = ConfigEntry[IronOSCoordinators]
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -39,10 +51,19 @@ async def async_setup_entry(hass: HomeAssistant, entry: IronOSConfigEntry) -> bo
|
|||||||
|
|
||||||
device = Pynecil(ble_device)
|
device = Pynecil(ble_device)
|
||||||
|
|
||||||
coordinator = IronOSCoordinator(hass, device)
|
coordinator = IronOSLiveDataCoordinator(hass, device)
|
||||||
await coordinator.async_config_entry_first_refresh()
|
await coordinator.async_config_entry_first_refresh()
|
||||||
|
|
||||||
entry.runtime_data = coordinator
|
session = async_get_clientsession(hass)
|
||||||
|
github = GitHubAPI(session=session)
|
||||||
|
|
||||||
|
firmware_update_coordinator = IronOSFirmwareUpdateCoordinator(hass, device, github)
|
||||||
|
await firmware_update_coordinator.async_config_entry_first_refresh()
|
||||||
|
|
||||||
|
entry.runtime_data = IronOSCoordinators(
|
||||||
|
live_data=coordinator,
|
||||||
|
firmware=firmware_update_coordinator,
|
||||||
|
)
|
||||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -4,7 +4,9 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import logging
|
import logging
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from aiogithubapi import GitHubAPI, GitHubException, GitHubReleaseModel
|
||||||
from pynecil import CommunicationError, DeviceInfoResponse, LiveDataResponse, Pynecil
|
from pynecil import CommunicationError, DeviceInfoResponse, LiveDataResponse, Pynecil
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
@ -16,24 +18,43 @@ from .const import DOMAIN
|
|||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
SCAN_INTERVAL = timedelta(seconds=5)
|
SCAN_INTERVAL = timedelta(seconds=5)
|
||||||
|
SCAN_INTERVAL_GITHUB = timedelta(hours=3)
|
||||||
|
|
||||||
|
|
||||||
class IronOSCoordinator(DataUpdateCoordinator[LiveDataResponse]):
|
class IronOSBaseCoordinator[_DataT](DataUpdateCoordinator[_DataT]):
|
||||||
"""IronOS coordinator."""
|
"""IronOS base coordinator."""
|
||||||
|
|
||||||
device_info: DeviceInfoResponse
|
device_info: DeviceInfoResponse
|
||||||
config_entry: ConfigEntry
|
config_entry: ConfigEntry
|
||||||
|
|
||||||
def __init__(self, hass: HomeAssistant, device: Pynecil) -> None:
|
def __init__(
|
||||||
|
self,
|
||||||
|
hass: HomeAssistant,
|
||||||
|
device: Pynecil,
|
||||||
|
update_interval: timedelta,
|
||||||
|
) -> None:
|
||||||
"""Initialize IronOS coordinator."""
|
"""Initialize IronOS coordinator."""
|
||||||
super().__init__(
|
super().__init__(
|
||||||
hass,
|
hass,
|
||||||
_LOGGER,
|
_LOGGER,
|
||||||
name=DOMAIN,
|
name=DOMAIN,
|
||||||
update_interval=SCAN_INTERVAL,
|
update_interval=update_interval,
|
||||||
)
|
)
|
||||||
self.device = device
|
self.device = device
|
||||||
|
|
||||||
|
async def _async_setup(self) -> None:
|
||||||
|
"""Set up the coordinator."""
|
||||||
|
|
||||||
|
self.device_info = await self.device.get_device_info()
|
||||||
|
|
||||||
|
|
||||||
|
class IronOSLiveDataCoordinator(IronOSBaseCoordinator):
|
||||||
|
"""IronOS live data coordinator."""
|
||||||
|
|
||||||
|
def __init__(self, hass: HomeAssistant, device: Pynecil) -> None:
|
||||||
|
"""Initialize IronOS coordinator."""
|
||||||
|
super().__init__(hass, device=device, update_interval=SCAN_INTERVAL)
|
||||||
|
|
||||||
async def _async_update_data(self) -> LiveDataResponse:
|
async def _async_update_data(self) -> LiveDataResponse:
|
||||||
"""Fetch data from Device."""
|
"""Fetch data from Device."""
|
||||||
|
|
||||||
@ -43,11 +64,27 @@ class IronOSCoordinator(DataUpdateCoordinator[LiveDataResponse]):
|
|||||||
except CommunicationError as e:
|
except CommunicationError as e:
|
||||||
raise UpdateFailed("Cannot connect to device") from e
|
raise UpdateFailed("Cannot connect to device") from e
|
||||||
|
|
||||||
async def _async_setup(self) -> None:
|
|
||||||
"""Set up the coordinator."""
|
class IronOSFirmwareUpdateCoordinator(IronOSBaseCoordinator):
|
||||||
|
"""IronOS coordinator for retrieving update information from github."""
|
||||||
|
|
||||||
|
def __init__(self, hass: HomeAssistant, device: Pynecil, github: GitHubAPI) -> None:
|
||||||
|
"""Initialize IronOS coordinator."""
|
||||||
|
super().__init__(hass, device=device, update_interval=SCAN_INTERVAL_GITHUB)
|
||||||
|
self.github = github
|
||||||
|
|
||||||
|
async def _async_update_data(self) -> GitHubReleaseModel:
|
||||||
|
"""Fetch data from Github."""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.device_info = await self.device.get_device_info()
|
release = await self.github.repos.releases.latest("Ralim/IronOS")
|
||||||
|
|
||||||
except CommunicationError as e:
|
except GitHubException as e:
|
||||||
raise UpdateFailed("Cannot connect to device") from e
|
raise UpdateFailed(
|
||||||
|
"Failed to retrieve latest release data from Github"
|
||||||
|
) from e
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
assert release.data
|
||||||
|
|
||||||
|
return release.data
|
||||||
|
@ -9,17 +9,17 @@ from homeassistant.helpers.entity import EntityDescription
|
|||||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
|
||||||
from .const import MANUFACTURER, MODEL
|
from .const import MANUFACTURER, MODEL
|
||||||
from .coordinator import IronOSCoordinator
|
from .coordinator import IronOSBaseCoordinator
|
||||||
|
|
||||||
|
|
||||||
class IronOSBaseEntity(CoordinatorEntity[IronOSCoordinator]):
|
class IronOSBaseEntity(CoordinatorEntity[IronOSBaseCoordinator]):
|
||||||
"""Base IronOS entity."""
|
"""Base IronOS entity."""
|
||||||
|
|
||||||
_attr_has_entity_name = True
|
_attr_has_entity_name = True
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
coordinator: IronOSCoordinator,
|
coordinator: IronOSBaseCoordinator,
|
||||||
entity_description: EntityDescription,
|
entity_description: EntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the sensor."""
|
"""Initialize the sensor."""
|
||||||
|
@ -12,6 +12,6 @@
|
|||||||
"dependencies": ["bluetooth_adapters"],
|
"dependencies": ["bluetooth_adapters"],
|
||||||
"documentation": "https://www.home-assistant.io/integrations/iron_os",
|
"documentation": "https://www.home-assistant.io/integrations/iron_os",
|
||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
"loggers": ["pynecil"],
|
"loggers": ["pynecil", "aiogithubapi"],
|
||||||
"requirements": ["pynecil==0.2.0"]
|
"requirements": ["pynecil==0.2.0", "aiogithubapi==24.6.0"]
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ async def async_setup_entry(
|
|||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up number entities from a config entry."""
|
"""Set up number entities from a config entry."""
|
||||||
coordinator = entry.runtime_data
|
coordinator = entry.runtime_data.live_data
|
||||||
|
|
||||||
async_add_entities(
|
async_add_entities(
|
||||||
IronOSNumberEntity(coordinator, description)
|
IronOSNumberEntity(coordinator, description)
|
||||||
|
@ -180,7 +180,7 @@ async def async_setup_entry(
|
|||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up sensors from a config entry."""
|
"""Set up sensors from a config entry."""
|
||||||
coordinator = entry.runtime_data
|
coordinator = entry.runtime_data.live_data
|
||||||
|
|
||||||
async_add_entities(
|
async_add_entities(
|
||||||
IronOSSensorEntity(coordinator, description)
|
IronOSSensorEntity(coordinator, description)
|
||||||
|
76
homeassistant/components/iron_os/update.py
Normal file
76
homeassistant/components/iron_os/update.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
"""Update platform for IronOS integration."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from homeassistant.components.update import (
|
||||||
|
UpdateDeviceClass,
|
||||||
|
UpdateEntity,
|
||||||
|
UpdateEntityDescription,
|
||||||
|
UpdateEntityFeature,
|
||||||
|
)
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
|
from . import IronOSConfigEntry
|
||||||
|
from .coordinator import IronOSBaseCoordinator
|
||||||
|
from .entity import IronOSBaseEntity
|
||||||
|
|
||||||
|
UPDATE_DESCRIPTION = UpdateEntityDescription(
|
||||||
|
key="firmware",
|
||||||
|
device_class=UpdateDeviceClass.FIRMWARE,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry: IronOSConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up IronOS update platform."""
|
||||||
|
|
||||||
|
coordinator = entry.runtime_data.firmware
|
||||||
|
|
||||||
|
async_add_entities([IronOSUpdate(coordinator, UPDATE_DESCRIPTION)])
|
||||||
|
|
||||||
|
|
||||||
|
class IronOSUpdate(IronOSBaseEntity, UpdateEntity):
|
||||||
|
"""Representation of an IronOS update entity."""
|
||||||
|
|
||||||
|
_attr_supported_features = UpdateEntityFeature.RELEASE_NOTES
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: IronOSBaseCoordinator,
|
||||||
|
entity_description: UpdateEntityDescription,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the sensor."""
|
||||||
|
super().__init__(coordinator, entity_description)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def installed_version(self) -> str | None:
|
||||||
|
"""IronOS version on the device."""
|
||||||
|
|
||||||
|
return self.coordinator.device_info.build
|
||||||
|
|
||||||
|
@property
|
||||||
|
def title(self) -> str | None:
|
||||||
|
"""Title of the IronOS release."""
|
||||||
|
|
||||||
|
return f"IronOS {self.coordinator.data.name}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def release_url(self) -> str | None:
|
||||||
|
"""URL to the full release notes of the latest IronOS version available."""
|
||||||
|
|
||||||
|
return self.coordinator.data.html_url
|
||||||
|
|
||||||
|
@property
|
||||||
|
def latest_version(self) -> str | None:
|
||||||
|
"""Latest IronOS version available for install."""
|
||||||
|
|
||||||
|
return self.coordinator.data.tag_name
|
||||||
|
|
||||||
|
async def async_release_notes(self) -> str | None:
|
||||||
|
"""Return the release notes."""
|
||||||
|
|
||||||
|
return self.coordinator.data.body
|
@ -249,6 +249,7 @@ aioflo==2021.11.0
|
|||||||
aioftp==0.21.3
|
aioftp==0.21.3
|
||||||
|
|
||||||
# homeassistant.components.github
|
# homeassistant.components.github
|
||||||
|
# homeassistant.components.iron_os
|
||||||
aiogithubapi==24.6.0
|
aiogithubapi==24.6.0
|
||||||
|
|
||||||
# homeassistant.components.guardian
|
# homeassistant.components.guardian
|
||||||
|
@ -234,6 +234,7 @@ aioesphomeapi==27.0.0
|
|||||||
aioflo==2021.11.0
|
aioflo==2021.11.0
|
||||||
|
|
||||||
# homeassistant.components.github
|
# homeassistant.components.github
|
||||||
|
# homeassistant.components.iron_os
|
||||||
aiogithubapi==24.6.0
|
aiogithubapi==24.6.0
|
||||||
|
|
||||||
# homeassistant.components.guardian
|
# homeassistant.components.guardian
|
||||||
|
@ -107,6 +107,29 @@ def mock_ble_device() -> Generator[MagicMock]:
|
|||||||
yield ble_device
|
yield ble_device
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def mock_githubapi() -> Generator[AsyncMock]:
|
||||||
|
"""Mock aiogithubapi."""
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.iron_os.GitHubAPI",
|
||||||
|
autospec=True,
|
||||||
|
) as mock_client:
|
||||||
|
client = mock_client.return_value
|
||||||
|
client.repos.releases.latest = AsyncMock()
|
||||||
|
|
||||||
|
client.repos.releases.latest.return_value.data.html_url = (
|
||||||
|
"https://github.com/Ralim/IronOS/releases/tag/v2.22"
|
||||||
|
)
|
||||||
|
client.repos.releases.latest.return_value.data.name = (
|
||||||
|
"V2.22 | TS101 & S60 Added | PinecilV2 improved"
|
||||||
|
)
|
||||||
|
client.repos.releases.latest.return_value.data.tag_name = "v2.22"
|
||||||
|
client.repos.releases.latest.return_value.data.body = "**RELEASE_NOTES**"
|
||||||
|
|
||||||
|
yield client
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_pynecil() -> Generator[AsyncMock]:
|
def mock_pynecil() -> Generator[AsyncMock]:
|
||||||
"""Mock Pynecil library."""
|
"""Mock Pynecil library."""
|
||||||
|
62
tests/components/iron_os/snapshots/test_update.ambr
Normal file
62
tests/components/iron_os/snapshots/test_update.ambr
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# serializer version: 1
|
||||||
|
# name: test_update.2
|
||||||
|
'**RELEASE_NOTES**'
|
||||||
|
# ---
|
||||||
|
# name: test_update[update.pinecil_firmware-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': None,
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'update',
|
||||||
|
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||||
|
'entity_id': 'update.pinecil_firmware',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <UpdateDeviceClass.FIRMWARE: 'firmware'>,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Firmware',
|
||||||
|
'platform': 'iron_os',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': <UpdateEntityFeature: 16>,
|
||||||
|
'translation_key': None,
|
||||||
|
'unique_id': 'c0:ff:ee:c0:ff:ee_firmware',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_update[update.pinecil_firmware-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'auto_update': False,
|
||||||
|
'device_class': 'firmware',
|
||||||
|
'entity_picture': 'https://brands.home-assistant.io/_/iron_os/icon.png',
|
||||||
|
'friendly_name': 'Pinecil Firmware',
|
||||||
|
'in_progress': False,
|
||||||
|
'installed_version': 'v2.22',
|
||||||
|
'latest_version': 'v2.22',
|
||||||
|
'release_summary': None,
|
||||||
|
'release_url': 'https://github.com/Ralim/IronOS/releases/tag/v2.22',
|
||||||
|
'skipped_version': None,
|
||||||
|
'supported_features': <UpdateEntityFeature: 16>,
|
||||||
|
'title': 'IronOS V2.22 | TS101 & S60 Added | PinecilV2 improved',
|
||||||
|
'update_percentage': None,
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'update.pinecil_firmware',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'off',
|
||||||
|
})
|
||||||
|
# ---
|
73
tests/components/iron_os/test_update.py
Normal file
73
tests/components/iron_os/test_update.py
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
"""Tests for IronOS update platform."""
|
||||||
|
|
||||||
|
from collections.abc import AsyncGenerator
|
||||||
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
|
from aiogithubapi import GitHubException
|
||||||
|
import pytest
|
||||||
|
from syrupy.assertion import SnapshotAssertion
|
||||||
|
|
||||||
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
|
from homeassistant.const import Platform
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry, snapshot_platform
|
||||||
|
from tests.typing import WebSocketGenerator
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
async def update_only() -> AsyncGenerator[None]:
|
||||||
|
"""Enable only the update platform."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.iron_os.PLATFORMS",
|
||||||
|
[Platform.UPDATE],
|
||||||
|
):
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("mock_pynecil", "ble_device", "mock_githubapi")
|
||||||
|
async def test_update(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: MockConfigEntry,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
hass_ws_client: WebSocketGenerator,
|
||||||
|
) -> None:
|
||||||
|
"""Test the IronOS update platform."""
|
||||||
|
ws_client = await hass_ws_client(hass)
|
||||||
|
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert config_entry.state is ConfigEntryState.LOADED
|
||||||
|
|
||||||
|
await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id)
|
||||||
|
|
||||||
|
await ws_client.send_json(
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"type": "update/release_notes",
|
||||||
|
"entity_id": "update.pinecil_firmware",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
result = await ws_client.receive_json()
|
||||||
|
assert result["result"] == snapshot
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("ble_device", "mock_pynecil")
|
||||||
|
async def test_config_entry_not_ready(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: MockConfigEntry,
|
||||||
|
mock_githubapi: AsyncMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test config entry not ready."""
|
||||||
|
|
||||||
|
mock_githubapi.repos.releases.latest.side_effect = GitHubException
|
||||||
|
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert config_entry.state is ConfigEntryState.SETUP_RETRY
|
Loading…
x
Reference in New Issue
Block a user