Make hassio coordinator refresh data (#69272)

pull/69253/head
Joakim Sørensen 2022-04-04 17:34:06 +02:00 committed by GitHub
parent bfa364741b
commit cfdfa3eab2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 101 additions and 46 deletions

View File

@ -42,7 +42,7 @@ from homeassistant.helpers.device_registry import (
)
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.typing import ConfigType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.loader import bind_hass
from homeassistant.util.dt import utcnow
@ -609,21 +609,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: # noqa:
DOMAIN, service, async_service_handler, schema=settings.schema
)
async def update_addon_stats(slug):
"""Update single addon stats."""
stats = await hassio.get_addon_stats(slug)
return (slug, stats)
async def update_addon_changelog(slug):
"""Return the changelog for an add-on."""
changelog = await hassio.get_addon_changelog(slug)
return (slug, changelog)
async def update_addon_info(slug):
"""Return the info for an add-on."""
info = await hassio.get_addon_info(slug)
return (slug, info)
async def update_info_data(now):
"""Update last available supervisor information."""
@ -644,28 +629,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: # noqa:
hassio.get_os_info(),
)
addons = [
addon
for addon in hass.data[DATA_SUPERVISOR_INFO].get("addons", [])
if addon[ATTR_STATE] == ATTR_STARTED
]
stats_data = await asyncio.gather(
*[update_addon_stats(addon[ATTR_SLUG]) for addon in addons]
)
hass.data[DATA_ADDONS_STATS] = dict(stats_data)
hass.data[DATA_ADDONS_CHANGELOGS] = dict(
await asyncio.gather(
*[update_addon_changelog(addon[ATTR_SLUG]) for addon in addons]
)
)
hass.data[DATA_ADDONS_INFO] = dict(
await asyncio.gather(
*[update_addon_info(addon[ATTR_SLUG]) for addon in addons]
)
)
if ADDONS_COORDINATOR in hass.data:
await hass.data[ADDONS_COORDINATOR].async_refresh()
except HassioAPIError as err:
_LOGGER.warning("Can't read Supervisor data: %s", err)
@ -855,7 +818,7 @@ class HassioDataUpdateCoordinator(DataUpdateCoordinator):
hass,
_LOGGER,
name=DOMAIN,
update_method=self._async_update_data,
update_interval=HASSIO_UPDATE_INTERVAL,
)
self.hassio: HassIO = hass.data[DOMAIN]
self.data = {}
@ -865,6 +828,11 @@ class HassioDataUpdateCoordinator(DataUpdateCoordinator):
async def _async_update_data(self) -> dict[str, Any]:
"""Update data via library."""
try:
await self.force_data_refresh()
except HassioAPIError as err:
raise UpdateFailed(f"Error on Supervisor API: {err}") from err
new_data = {}
supervisor_info = get_supervisor_info(self.hass)
addons_info = get_addons_info(self.hass)
@ -940,3 +908,53 @@ class HassioDataUpdateCoordinator(DataUpdateCoordinator):
"""Force update of the supervisor info."""
self.hass.data[DATA_SUPERVISOR_INFO] = await self.hassio.get_supervisor_info()
await self.async_refresh()
async def force_data_refresh(self) -> None:
"""Force update of the addon info."""
await self.hassio.refresh_updates()
(
self.hass.data[DATA_INFO],
self.hass.data[DATA_CORE_INFO],
self.hass.data[DATA_SUPERVISOR_INFO],
self.hass.data[DATA_OS_INFO],
) = await asyncio.gather(
self.hassio.get_info(),
self.hassio.get_core_info(),
self.hassio.get_supervisor_info(),
self.hassio.get_os_info(),
)
addons = [
addon
for addon in self.hass.data[DATA_SUPERVISOR_INFO].get("addons", [])
if addon[ATTR_STATE] == ATTR_STARTED
]
stats_data = await asyncio.gather(
*[self._update_addon_stats(addon[ATTR_SLUG]) for addon in addons]
)
self.hass.data[DATA_ADDONS_STATS] = dict(stats_data)
self.hass.data[DATA_ADDONS_CHANGELOGS] = dict(
await asyncio.gather(
*[self._update_addon_changelog(addon[ATTR_SLUG]) for addon in addons]
)
)
self.hass.data[DATA_ADDONS_INFO] = dict(
await asyncio.gather(
*[self._update_addon_info(addon[ATTR_SLUG]) for addon in addons]
)
)
async def _update_addon_stats(self, slug):
"""Update single addon stats."""
stats = await self.hassio.get_addon_stats(slug)
return (slug, stats)
async def _update_addon_changelog(self, slug):
"""Return the changelog for an add-on."""
changelog = await self.hassio.get_addon_changelog(slug)
return (slug, changelog)
async def _update_addon_info(self, slug):
"""Return the info for an add-on."""
info = await self.hassio.get_addon_info(slug)
return (slug, info)

View File

@ -168,6 +168,14 @@ class HassIO:
"""
return self.send_command("/homeassistant/stop")
@_api_bool
def refresh_updates(self):
"""Refresh available updates.
This method return a coroutine.
"""
return self.send_command("/refresh_updates", timeout=None)
@api_data
def retrieve_discovery_messages(self):
"""Return all discovery data from Hass.io API.

View File

@ -127,6 +127,7 @@ def mock_all(aioclient_mock, request):
aioclient_mock.get(
"http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}}
)
aioclient_mock.post("http://127.0.0.1/refresh_updates", json={"result": "ok"})
@pytest.mark.parametrize(

View File

@ -9,6 +9,7 @@ from homeassistant.auth.const import GROUP_ID_ADMIN
from homeassistant.components import frontend
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
from homeassistant.components.hassio import ADDONS_COORDINATOR, DOMAIN, STORAGE_KEY
from homeassistant.components.hassio.handler import HassioAPIError
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.helpers.device_registry import async_get
from homeassistant.setup import async_setup_component
@ -151,6 +152,7 @@ def mock_all(aioclient_mock, request):
aioclient_mock.get(
"http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}}
)
aioclient_mock.post("http://127.0.0.1/refresh_updates", json={"result": "ok"})
async def test_setup_api_ping(hass, aioclient_mock):
@ -159,7 +161,7 @@ async def test_setup_api_ping(hass, aioclient_mock):
result = await async_setup_component(hass, "hassio", {})
assert result
assert aioclient_mock.call_count == 10
assert aioclient_mock.call_count == 15
assert hass.components.hassio.get_core_info()["version_latest"] == "1.0.0"
assert hass.components.hassio.is_hassio()
@ -198,7 +200,7 @@ async def test_setup_api_push_api_data(hass, aioclient_mock):
)
assert result
assert aioclient_mock.call_count == 10
assert aioclient_mock.call_count == 15
assert not aioclient_mock.mock_calls[1][2]["ssl"]
assert aioclient_mock.mock_calls[1][2]["port"] == 9999
assert aioclient_mock.mock_calls[1][2]["watchdog"]
@ -214,7 +216,7 @@ async def test_setup_api_push_api_data_server_host(hass, aioclient_mock):
)
assert result
assert aioclient_mock.call_count == 10
assert aioclient_mock.call_count == 15
assert not aioclient_mock.mock_calls[1][2]["ssl"]
assert aioclient_mock.mock_calls[1][2]["port"] == 9999
assert not aioclient_mock.mock_calls[1][2]["watchdog"]
@ -226,7 +228,7 @@ async def test_setup_api_push_api_data_default(hass, aioclient_mock, hass_storag
result = await async_setup_component(hass, "hassio", {"http": {}, "hassio": {}})
assert result
assert aioclient_mock.call_count == 10
assert aioclient_mock.call_count == 15
assert not aioclient_mock.mock_calls[1][2]["ssl"]
assert aioclient_mock.mock_calls[1][2]["port"] == 8123
refresh_token = aioclient_mock.mock_calls[1][2]["refresh_token"]
@ -293,7 +295,7 @@ async def test_setup_api_existing_hassio_user(hass, aioclient_mock, hass_storage
result = await async_setup_component(hass, "hassio", {"http": {}, "hassio": {}})
assert result
assert aioclient_mock.call_count == 10
assert aioclient_mock.call_count == 15
assert not aioclient_mock.mock_calls[1][2]["ssl"]
assert aioclient_mock.mock_calls[1][2]["port"] == 8123
assert aioclient_mock.mock_calls[1][2]["refresh_token"] == token.token
@ -307,7 +309,7 @@ async def test_setup_core_push_timezone(hass, aioclient_mock):
result = await async_setup_component(hass, "hassio", {"hassio": {}})
assert result
assert aioclient_mock.call_count == 10
assert aioclient_mock.call_count == 15
assert aioclient_mock.mock_calls[2][2]["timezone"] == "testzone"
with patch("homeassistant.util.dt.set_default_time_zone"):
@ -324,7 +326,7 @@ async def test_setup_hassio_no_additional_data(hass, aioclient_mock):
result = await async_setup_component(hass, "hassio", {"hassio": {}})
assert result
assert aioclient_mock.call_count == 10
assert aioclient_mock.call_count == 15
assert aioclient_mock.mock_calls[-1][3]["X-Hassio-Key"] == "123456"
@ -630,3 +632,27 @@ async def test_device_registry_calls(hass):
async_fire_time_changed(hass, dt_util.now() + timedelta(hours=3))
await hass.async_block_till_done()
assert len(dev_reg.devices) == 5
async def test_coordinator_updates(hass, caplog):
"""Test coordinator."""
with patch.dict(os.environ, MOCK_ENVIRON), patch(
"homeassistant.components.hassio.HassIO.refresh_updates"
) as refresh_updates_mock:
config_entry = MockConfigEntry(domain=DOMAIN, data={}, unique_id=DOMAIN)
config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert refresh_updates_mock.call_count == 1
with patch(
"homeassistant.components.hassio.HassIO.refresh_updates",
side_effect=HassioAPIError("Unknown"),
) as refresh_updates_mock:
async_fire_time_changed(hass, dt_util.now() + timedelta(minutes=5))
await hass.async_block_till_done()
assert refresh_updates_mock.call_count == 1
assert (
"Error fetching hassio data: Error on Supervisor API: Unknown"
in caplog.text
)

View File

@ -120,6 +120,7 @@ def mock_all(aioclient_mock, request):
aioclient_mock.get(
"http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}}
)
aioclient_mock.post("http://127.0.0.1/refresh_updates", json={"result": "ok"})
@pytest.mark.parametrize(

View File

@ -133,6 +133,7 @@ def mock_all(aioclient_mock, request):
aioclient_mock.get(
"http://127.0.0.1/ingress/panels", json={"result": "ok", "data": {"panels": {}}}
)
aioclient_mock.post("http://127.0.0.1/refresh_updates", json={"result": "ok"})
@pytest.mark.parametrize(