mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 04:07:08 +00:00
Add update entity to immich integration (#147273)
* add update entity * remove unneccessary entity description * rename update entity to version * simplify test * define static attribute outside of the constructor * move min version check into coordinator
This commit is contained in:
parent
d4e7667ea0
commit
41e53297c2
@ -20,7 +20,7 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
|||||||
|
|
||||||
from .coordinator import ImmichConfigEntry, ImmichDataUpdateCoordinator
|
from .coordinator import ImmichConfigEntry, ImmichDataUpdateCoordinator
|
||||||
|
|
||||||
PLATFORMS: list[Platform] = [Platform.SENSOR]
|
PLATFORMS: list[Platform] = [Platform.SENSOR, Platform.UPDATE]
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: ImmichConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: ImmichConfigEntry) -> bool:
|
||||||
|
@ -13,7 +13,9 @@ from aioimmich.server.models import (
|
|||||||
ImmichServerAbout,
|
ImmichServerAbout,
|
||||||
ImmichServerStatistics,
|
ImmichServerStatistics,
|
||||||
ImmichServerStorage,
|
ImmichServerStorage,
|
||||||
|
ImmichServerVersionCheck,
|
||||||
)
|
)
|
||||||
|
from awesomeversion import AwesomeVersion
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_SSL
|
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_SSL
|
||||||
@ -33,6 +35,7 @@ class ImmichData:
|
|||||||
server_about: ImmichServerAbout
|
server_about: ImmichServerAbout
|
||||||
server_storage: ImmichServerStorage
|
server_storage: ImmichServerStorage
|
||||||
server_usage: ImmichServerStatistics | None
|
server_usage: ImmichServerStatistics | None
|
||||||
|
server_version_check: ImmichServerVersionCheck | None
|
||||||
|
|
||||||
|
|
||||||
type ImmichConfigEntry = ConfigEntry[ImmichDataUpdateCoordinator]
|
type ImmichConfigEntry = ConfigEntry[ImmichDataUpdateCoordinator]
|
||||||
@ -71,9 +74,16 @@ class ImmichDataUpdateCoordinator(DataUpdateCoordinator[ImmichData]):
|
|||||||
if self.is_admin
|
if self.is_admin
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
|
server_version_check = (
|
||||||
|
await self.api.server.async_get_version_check()
|
||||||
|
if AwesomeVersion(server_about.version) >= AwesomeVersion("v1.134.0")
|
||||||
|
else None
|
||||||
|
)
|
||||||
except ImmichUnauthorizedError as err:
|
except ImmichUnauthorizedError as err:
|
||||||
raise ConfigEntryAuthFailed from err
|
raise ConfigEntryAuthFailed from err
|
||||||
except CONNECT_ERRORS as err:
|
except CONNECT_ERRORS as err:
|
||||||
raise UpdateFailed from err
|
raise UpdateFailed from err
|
||||||
|
|
||||||
return ImmichData(server_about, server_storage, server_usage)
|
return ImmichData(
|
||||||
|
server_about, server_storage, server_usage, server_version_check
|
||||||
|
)
|
||||||
|
@ -68,6 +68,11 @@
|
|||||||
"usage_by_videos": {
|
"usage_by_videos": {
|
||||||
"name": "Disk used by videos"
|
"name": "Disk used by videos"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"update": {
|
||||||
|
"update": {
|
||||||
|
"name": "Version"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
57
homeassistant/components/immich/update.py
Normal file
57
homeassistant/components/immich/update.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
"""Update platform for the Immich integration."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from homeassistant.components.update import UpdateEntity
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||||
|
|
||||||
|
from .coordinator import ImmichConfigEntry, ImmichDataUpdateCoordinator
|
||||||
|
from .entity import ImmichEntity
|
||||||
|
|
||||||
|
# Coordinator is used to centralize the data updates
|
||||||
|
PARALLEL_UPDATES = 0
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry: ImmichConfigEntry,
|
||||||
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Add immich server update entity."""
|
||||||
|
coordinator = entry.runtime_data
|
||||||
|
|
||||||
|
if coordinator.data.server_version_check is not None:
|
||||||
|
async_add_entities([ImmichUpdateEntity(coordinator)])
|
||||||
|
|
||||||
|
|
||||||
|
class ImmichUpdateEntity(ImmichEntity, UpdateEntity):
|
||||||
|
"""Define Immich update entity."""
|
||||||
|
|
||||||
|
_attr_translation_key = "update"
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: ImmichDataUpdateCoordinator,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize."""
|
||||||
|
super().__init__(coordinator)
|
||||||
|
self._attr_unique_id = f"{coordinator.config_entry.unique_id}_update"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def installed_version(self) -> str:
|
||||||
|
"""Current installed immich server version."""
|
||||||
|
return self.coordinator.data.server_about.version
|
||||||
|
|
||||||
|
@property
|
||||||
|
def latest_version(self) -> str:
|
||||||
|
"""Available new immich server version."""
|
||||||
|
assert self.coordinator.data.server_version_check
|
||||||
|
return self.coordinator.data.server_version_check.release_version
|
||||||
|
|
||||||
|
@property
|
||||||
|
def release_url(self) -> str | None:
|
||||||
|
"""URL to the full release notes of the new immich server version."""
|
||||||
|
return (
|
||||||
|
f"https://github.com/immich-app/immich/releases/tag/{self.latest_version}"
|
||||||
|
)
|
@ -8,6 +8,7 @@ from aioimmich.server.models import (
|
|||||||
ImmichServerAbout,
|
ImmichServerAbout,
|
||||||
ImmichServerStatistics,
|
ImmichServerStatistics,
|
||||||
ImmichServerStorage,
|
ImmichServerStorage,
|
||||||
|
ImmichServerVersionCheck,
|
||||||
)
|
)
|
||||||
from aioimmich.users.models import ImmichUserObject
|
from aioimmich.users.models import ImmichUserObject
|
||||||
import pytest
|
import pytest
|
||||||
@ -79,21 +80,21 @@ def mock_immich_server() -> AsyncMock:
|
|||||||
mock = AsyncMock(spec=ImmichServer)
|
mock = AsyncMock(spec=ImmichServer)
|
||||||
mock.async_get_about_info.return_value = ImmichServerAbout.from_dict(
|
mock.async_get_about_info.return_value = ImmichServerAbout.from_dict(
|
||||||
{
|
{
|
||||||
"version": "v1.132.3",
|
"version": "v1.134.0",
|
||||||
"versionUrl": "https://github.com/immich-app/immich/releases/tag/v1.132.3",
|
"versionUrl": "https://github.com/immich-app/immich/releases/tag/v1.134.0",
|
||||||
"licensed": False,
|
"licensed": False,
|
||||||
"build": "14709928600",
|
"build": "15281783550",
|
||||||
"buildUrl": "https://github.com/immich-app/immich/actions/runs/14709928600",
|
"buildUrl": "https://github.com/immich-app/immich/actions/runs/15281783550",
|
||||||
"buildImage": "v1.132.3",
|
"buildImage": "v1.134.0",
|
||||||
"buildImageUrl": "https://github.com/immich-app/immich/pkgs/container/immich-server",
|
"buildImageUrl": "https://github.com/immich-app/immich/pkgs/container/immich-server",
|
||||||
"repository": "immich-app/immich",
|
"repository": "immich-app/immich",
|
||||||
"repositoryUrl": "https://github.com/immich-app/immich",
|
"repositoryUrl": "https://github.com/immich-app/immich",
|
||||||
"sourceRef": "v1.132.3",
|
"sourceRef": "v1.134.0",
|
||||||
"sourceCommit": "02994883fe3f3972323bb6759d0170a4062f5236",
|
"sourceCommit": "58ae77ec9204a2e43a8cb2f1fd27482af40d0891",
|
||||||
"sourceUrl": "https://github.com/immich-app/immich/commit/02994883fe3f3972323bb6759d0170a4062f5236",
|
"sourceUrl": "https://github.com/immich-app/immich/commit/58ae77ec9204a2e43a8cb2f1fd27482af40d0891",
|
||||||
"nodejs": "v22.14.0",
|
"nodejs": "v22.14.0",
|
||||||
"exiftool": "13.00",
|
"exiftool": "13.00",
|
||||||
"ffmpeg": "7.0.2-7",
|
"ffmpeg": "7.0.2-9",
|
||||||
"libvips": "8.16.1",
|
"libvips": "8.16.1",
|
||||||
"imagemagick": "7.1.1-47",
|
"imagemagick": "7.1.1-47",
|
||||||
}
|
}
|
||||||
@ -130,6 +131,12 @@ def mock_immich_server() -> AsyncMock:
|
|||||||
],
|
],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
mock.async_get_version_check.return_value = ImmichServerVersionCheck.from_dict(
|
||||||
|
{
|
||||||
|
"checkedAt": "2025-06-21T16:35:10.352Z",
|
||||||
|
"releaseVersion": "v1.135.3",
|
||||||
|
}
|
||||||
|
)
|
||||||
return mock
|
return mock
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,23 +3,23 @@
|
|||||||
dict({
|
dict({
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'server_about': dict({
|
'server_about': dict({
|
||||||
'build': '14709928600',
|
'build': '15281783550',
|
||||||
'build_image': 'v1.132.3',
|
'build_image': 'v1.134.0',
|
||||||
'build_image_url': 'https://github.com/immich-app/immich/pkgs/container/immich-server',
|
'build_image_url': 'https://github.com/immich-app/immich/pkgs/container/immich-server',
|
||||||
'build_url': 'https://github.com/immich-app/immich/actions/runs/14709928600',
|
'build_url': 'https://github.com/immich-app/immich/actions/runs/15281783550',
|
||||||
'exiftool': '13.00',
|
'exiftool': '13.00',
|
||||||
'ffmpeg': '7.0.2-7',
|
'ffmpeg': '7.0.2-9',
|
||||||
'imagemagick': '7.1.1-47',
|
'imagemagick': '7.1.1-47',
|
||||||
'libvips': '8.16.1',
|
'libvips': '8.16.1',
|
||||||
'licensed': False,
|
'licensed': False,
|
||||||
'nodejs': 'v22.14.0',
|
'nodejs': 'v22.14.0',
|
||||||
'repository': 'immich-app/immich',
|
'repository': 'immich-app/immich',
|
||||||
'repository_url': 'https://github.com/immich-app/immich',
|
'repository_url': 'https://github.com/immich-app/immich',
|
||||||
'source_commit': '02994883fe3f3972323bb6759d0170a4062f5236',
|
'source_commit': '58ae77ec9204a2e43a8cb2f1fd27482af40d0891',
|
||||||
'source_ref': 'v1.132.3',
|
'source_ref': 'v1.134.0',
|
||||||
'source_url': 'https://github.com/immich-app/immich/commit/02994883fe3f3972323bb6759d0170a4062f5236',
|
'source_url': 'https://github.com/immich-app/immich/commit/58ae77ec9204a2e43a8cb2f1fd27482af40d0891',
|
||||||
'version': 'v1.132.3',
|
'version': 'v1.134.0',
|
||||||
'version_url': 'https://github.com/immich-app/immich/releases/tag/v1.132.3',
|
'version_url': 'https://github.com/immich-app/immich/releases/tag/v1.134.0',
|
||||||
}),
|
}),
|
||||||
'server_storage': dict({
|
'server_storage': dict({
|
||||||
'disk_available': '136.3 GiB',
|
'disk_available': '136.3 GiB',
|
||||||
@ -49,6 +49,10 @@
|
|||||||
'usage_videos': 65234281361,
|
'usage_videos': 65234281361,
|
||||||
'videos': 1836,
|
'videos': 1836,
|
||||||
}),
|
}),
|
||||||
|
'server_version_check': dict({
|
||||||
|
'checked_at': '2025-06-21T16:35:10.352000+00:00',
|
||||||
|
'release_version': 'v1.135.3',
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
'entry': dict({
|
'entry': dict({
|
||||||
'data': dict({
|
'data': dict({
|
||||||
|
61
tests/components/immich/snapshots/test_update.ambr
Normal file
61
tests/components/immich/snapshots/test_update.ambr
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# serializer version: 1
|
||||||
|
# name: test_update[update.someone_version-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': None,
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'config_subentry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'update',
|
||||||
|
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||||
|
'entity_id': 'update.someone_version',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Version',
|
||||||
|
'platform': 'immich',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'suggested_object_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'update',
|
||||||
|
'unique_id': 'e7ef5713-9dab-4bd4-b899-715b0ca4379e_update',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_update[update.someone_version-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'auto_update': False,
|
||||||
|
'display_precision': 0,
|
||||||
|
'entity_picture': 'https://brands.home-assistant.io/_/immich/icon.png',
|
||||||
|
'friendly_name': 'Someone Version',
|
||||||
|
'in_progress': False,
|
||||||
|
'installed_version': 'v1.134.0',
|
||||||
|
'latest_version': 'v1.135.3',
|
||||||
|
'release_summary': None,
|
||||||
|
'release_url': 'https://github.com/immich-app/immich/releases/tag/v1.135.3',
|
||||||
|
'skipped_version': None,
|
||||||
|
'supported_features': <UpdateEntityFeature: 0>,
|
||||||
|
'title': None,
|
||||||
|
'update_percentage': None,
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'update.someone_version',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'on',
|
||||||
|
})
|
||||||
|
# ---
|
45
tests/components/immich/test_update.py
Normal file
45
tests/components/immich/test_update.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
"""Test the Immich update platform."""
|
||||||
|
|
||||||
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
|
from syrupy.assertion import SnapshotAssertion
|
||||||
|
|
||||||
|
from homeassistant.const import Platform
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
|
||||||
|
from . import setup_integration
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry, snapshot_platform
|
||||||
|
|
||||||
|
|
||||||
|
async def test_update(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
mock_immich: Mock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Test the Immich update platform."""
|
||||||
|
|
||||||
|
with patch("homeassistant.components.immich.PLATFORMS", [Platform.UPDATE]):
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_update_min_version(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
mock_immich: Mock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Test the Immich update platform with min version not installed."""
|
||||||
|
|
||||||
|
mock_immich.server.async_get_about_info.return_value.version = "v1.132.3"
|
||||||
|
|
||||||
|
with patch("homeassistant.components.immich.PLATFORMS", [Platform.UPDATE]):
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
assert not hass.states.async_all()
|
Loading…
x
Reference in New Issue
Block a user