Make hassio coordinator refresh data (#69272)
parent
bfa364741b
commit
cfdfa3eab2
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in New Issue