Add hub support

This commit is contained in:
2026-01-30 02:57:45 +03:00
parent 60573374a4
commit 82f293d0df
11 changed files with 50 additions and 16 deletions

View File

@@ -12,6 +12,7 @@ from .const import (
CONF_ALBUM_ID,
CONF_ALBUM_NAME,
CONF_API_KEY,
CONF_HUB_NAME,
CONF_IMMICH_URL,
CONF_SCAN_INTERVAL,
DEFAULT_SCAN_INTERVAL,
@@ -27,6 +28,7 @@ _LOGGER = logging.getLogger(__name__)
class ImmichHubData:
"""Data for the Immich hub."""
name: str
url: str
api_key: str
scan_interval: int
@@ -48,12 +50,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: ImmichConfigEntry) -> bo
"""Set up Immich Album Watcher hub from a config entry."""
hass.data.setdefault(DOMAIN, {})
hub_name = entry.data.get(CONF_HUB_NAME, "Immich")
url = entry.data[CONF_IMMICH_URL]
api_key = entry.data[CONF_API_KEY]
scan_interval = entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
# Store hub data
entry.runtime_data = ImmichHubData(
name=hub_name,
url=url,
api_key=api_key,
scan_interval=scan_interval,
@@ -104,6 +108,7 @@ async def _async_setup_subentry_coordinator(
album_id=album_id,
album_name=album_name,
scan_interval=hub_data.scan_interval,
hub_name=hub_data.name,
)
# Fetch initial data

View File

@@ -15,12 +15,14 @@ from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util import slugify
from .const import (
ATTR_ALBUM_ID,
ATTR_ALBUM_NAME,
CONF_ALBUM_ID,
CONF_ALBUM_NAME,
CONF_HUB_NAME,
DOMAIN,
NEW_ASSETS_RESET_DELAY,
)
@@ -71,7 +73,9 @@ class ImmichAlbumNewAssetsSensor(
self._subentry = subentry
self._album_id = subentry.data[CONF_ALBUM_ID]
self._album_name = subentry.data.get(CONF_ALBUM_NAME, "Unknown Album")
self._attr_unique_id = f"{subentry.subentry_id}_new_assets"
self._hub_name = entry.data.get(CONF_HUB_NAME, "Immich")
unique_id_prefix = slugify(f"{self._hub_name}_album_{self._album_name}")
self._attr_unique_id = f"{unique_id_prefix}_new_assets"
@property
def _album_data(self) -> AlbumData | None:

View File

@@ -15,8 +15,9 @@ from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util import slugify
from .const import CONF_ALBUM_ID, CONF_ALBUM_NAME, DOMAIN
from .const import CONF_ALBUM_ID, CONF_ALBUM_NAME, CONF_HUB_NAME, DOMAIN
from .coordinator import AlbumData, ImmichAlbumWatcherCoordinator
_LOGGER = logging.getLogger(__name__)
@@ -66,7 +67,9 @@ class ImmichAlbumThumbnailCamera(
self._subentry = subentry
self._album_id = subentry.data[CONF_ALBUM_ID]
self._album_name = subentry.data.get(CONF_ALBUM_NAME, "Unknown Album")
self._attr_unique_id = f"{subentry.subentry_id}_thumbnail"
self._hub_name = entry.data.get(CONF_HUB_NAME, "Immich")
unique_id_prefix = slugify(f"{self._hub_name}_album_{self._album_name}")
self._attr_unique_id = f"{unique_id_prefix}_thumbnail"
self._cached_image: bytes | None = None
self._last_thumbnail_id: str | None = None

View File

@@ -23,6 +23,7 @@ from .const import (
CONF_ALBUM_ID,
CONF_ALBUM_NAME,
CONF_API_KEY,
CONF_HUB_NAME,
CONF_IMMICH_URL,
CONF_SCAN_INTERVAL,
DEFAULT_SCAN_INTERVAL,
@@ -92,6 +93,7 @@ class ImmichAlbumWatcherConfigFlow(ConfigFlow, domain=DOMAIN):
errors: dict[str, str] = {}
if user_input is not None:
hub_name = user_input[CONF_HUB_NAME].strip()
self._url = user_input[CONF_IMMICH_URL].rstrip("/")
self._api_key = user_input[CONF_API_KEY]
@@ -105,8 +107,9 @@ class ImmichAlbumWatcherConfigFlow(ConfigFlow, domain=DOMAIN):
self._abort_if_unique_id_configured()
return self.async_create_entry(
title="Immich Album Watcher",
title=hub_name,
data={
CONF_HUB_NAME: hub_name,
CONF_IMMICH_URL: self._url,
CONF_API_KEY: self._api_key,
},
@@ -129,6 +132,7 @@ class ImmichAlbumWatcherConfigFlow(ConfigFlow, domain=DOMAIN):
step_id="user",
data_schema=vol.Schema(
{
vol.Required(CONF_HUB_NAME, default="Immich"): str,
vol.Required(CONF_IMMICH_URL): str,
vol.Required(CONF_API_KEY): str,
}

View File

@@ -6,6 +6,7 @@ from typing import Final
DOMAIN: Final = "immich_album_watcher"
# Configuration keys
CONF_HUB_NAME: Final = "hub_name"
CONF_IMMICH_URL: Final = "immich_url"
CONF_API_KEY: Final = "api_key"
CONF_ALBUMS: Final = "albums"
@@ -26,6 +27,7 @@ EVENT_ASSETS_ADDED: Final = f"{DOMAIN}_assets_added"
EVENT_ASSETS_REMOVED: Final = f"{DOMAIN}_assets_removed"
# Attributes
ATTR_HUB_NAME: Final = "hub_name"
ATTR_ALBUM_ID: Final = "album_id"
ATTR_ALBUM_NAME: Final = "album_name"
ATTR_ALBUM_URL: Final = "album_url"

View File

@@ -29,6 +29,7 @@ from .const import (
ATTR_ASSET_TYPE,
ATTR_ASSET_URL,
ATTR_CHANGE_TYPE,
ATTR_HUB_NAME,
ATTR_PEOPLE,
ATTR_REMOVED_ASSETS,
ATTR_REMOVED_COUNT,
@@ -217,6 +218,7 @@ class ImmichAlbumWatcherCoordinator(DataUpdateCoordinator[AlbumData | None]):
album_id: str,
album_name: str,
scan_interval: int,
hub_name: str = "Immich",
) -> None:
"""Initialize the coordinator."""
super().__init__(
@@ -229,6 +231,7 @@ class ImmichAlbumWatcherCoordinator(DataUpdateCoordinator[AlbumData | None]):
self._api_key = api_key
self._album_id = album_id
self._album_name = album_name
self._hub_name = hub_name
self._previous_state: AlbumData | None = None
self._session: aiohttp.ClientSession | None = None
self._people_cache: dict[str, str] = {} # person_id -> name
@@ -542,6 +545,7 @@ class ImmichAlbumWatcherCoordinator(DataUpdateCoordinator[AlbumData | None]):
added_assets_detail.append(asset_detail)
event_data = {
ATTR_HUB_NAME: self._hub_name,
ATTR_ALBUM_ID: change.album_id,
ATTR_ALBUM_NAME: change.album_name,
ATTR_CHANGE_TYPE: change.change_type,

View File

@@ -8,6 +8,5 @@
"iot_class": "cloud_polling",
"issue_tracker": "https://github.com/your-repo/immich-album-watcher/issues",
"requirements": [],
"single_config_entry": true,
"version": "1.1.0"
"version": "1.2.0"
}

View File

@@ -20,6 +20,7 @@ from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util import slugify
from .const import (
ATTR_ALBUM_ID,
@@ -36,6 +37,7 @@ from .const import (
ATTR_VIDEO_COUNT,
CONF_ALBUM_ID,
CONF_ALBUM_NAME,
CONF_HUB_NAME,
DOMAIN,
SERVICE_GET_RECENT_ASSETS,
SERVICE_REFRESH,
@@ -112,6 +114,9 @@ class ImmichAlbumBaseSensor(CoordinatorEntity[ImmichAlbumWatcherCoordinator], Se
self._subentry = subentry
self._album_id = subentry.data[CONF_ALBUM_ID]
self._album_name = subentry.data.get(CONF_ALBUM_NAME, "Unknown Album")
self._hub_name = entry.data.get(CONF_HUB_NAME, "Immich")
# Generate unique_id prefix: {hub_name}_album_{album_name}
self._unique_id_prefix = slugify(f"{self._hub_name}_album_{self._album_name}")
@property
def _album_data(self) -> AlbumData | None:
@@ -171,7 +176,7 @@ class ImmichAlbumAssetCountSensor(ImmichAlbumBaseSensor):
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, entry, subentry)
self._attr_unique_id = f"{subentry.subentry_id}_asset_count"
self._attr_unique_id = f"{self._unique_id_prefix}_asset_count"
@property
def native_value(self) -> int | None:
@@ -222,7 +227,7 @@ class ImmichAlbumPhotoCountSensor(ImmichAlbumBaseSensor):
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, entry, subentry)
self._attr_unique_id = f"{subentry.subentry_id}_photo_count"
self._attr_unique_id = f"{self._unique_id_prefix}_photo_count"
@property
def native_value(self) -> int | None:
@@ -247,7 +252,7 @@ class ImmichAlbumVideoCountSensor(ImmichAlbumBaseSensor):
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, entry, subentry)
self._attr_unique_id = f"{subentry.subentry_id}_video_count"
self._attr_unique_id = f"{self._unique_id_prefix}_video_count"
@property
def native_value(self) -> int | None:
@@ -272,7 +277,7 @@ class ImmichAlbumLastUpdatedSensor(ImmichAlbumBaseSensor):
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, entry, subentry)
self._attr_unique_id = f"{subentry.subentry_id}_last_updated"
self._attr_unique_id = f"{self._unique_id_prefix}_last_updated"
@property
def native_value(self) -> datetime | None:
@@ -302,7 +307,7 @@ class ImmichAlbumCreatedSensor(ImmichAlbumBaseSensor):
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, entry, subentry)
self._attr_unique_id = f"{subentry.subentry_id}_created"
self._attr_unique_id = f"{self._unique_id_prefix}_created"
@property
def native_value(self) -> datetime | None:
@@ -332,7 +337,7 @@ class ImmichAlbumPeopleSensor(ImmichAlbumBaseSensor):
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, entry, subentry)
self._attr_unique_id = f"{subentry.subentry_id}_people_count"
self._attr_unique_id = f"{self._unique_id_prefix}_people_count"
@property
def native_value(self) -> int | None:
@@ -366,7 +371,7 @@ class ImmichAlbumPublicUrlSensor(ImmichAlbumBaseSensor):
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, entry, subentry)
self._attr_unique_id = f"{subentry.subentry_id}_public_url"
self._attr_unique_id = f"{self._unique_id_prefix}_public_url"
@property
def native_value(self) -> str | None:
@@ -411,7 +416,7 @@ class ImmichAlbumProtectedUrlSensor(ImmichAlbumBaseSensor):
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, entry, subentry)
self._attr_unique_id = f"{subentry.subentry_id}_protected_url"
self._attr_unique_id = f"{self._unique_id_prefix}_protected_url"
@property
def native_value(self) -> str | None:
@@ -451,7 +456,7 @@ class ImmichAlbumProtectedPasswordSensor(ImmichAlbumBaseSensor):
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, entry, subentry)
self._attr_unique_id = f"{subentry.subentry_id}_protected_password"
self._attr_unique_id = f"{self._unique_id_prefix}_protected_password"
@property
def native_value(self) -> str | None:

View File

@@ -11,12 +11,14 @@ from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.util import slugify
from .const import (
ATTR_ALBUM_ID,
ATTR_ALBUM_PROTECTED_URL,
CONF_ALBUM_ID,
CONF_ALBUM_NAME,
CONF_HUB_NAME,
DOMAIN,
)
from .coordinator import AlbumData, ImmichAlbumWatcherCoordinator
@@ -68,7 +70,9 @@ class ImmichAlbumProtectedPasswordText(
self._subentry = subentry
self._album_id = subentry.data[CONF_ALBUM_ID]
self._album_name = subentry.data.get(CONF_ALBUM_NAME, "Unknown Album")
self._attr_unique_id = f"{subentry.subentry_id}_protected_password_edit"
self._hub_name = entry.data.get(CONF_HUB_NAME, "Immich")
unique_id_prefix = slugify(f"{self._hub_name}_album_{self._album_name}")
self._attr_unique_id = f"{unique_id_prefix}_protected_password_edit"
@property
def _album_data(self) -> AlbumData | None:

View File

@@ -51,10 +51,12 @@
"title": "Connect to Immich",
"description": "Enter your Immich server details. You can get an API key from Immich → User Settings → API Keys.",
"data": {
"hub_name": "Hub Name",
"immich_url": "Immich URL",
"api_key": "API Key"
},
"data_description": {
"hub_name": "A name for this Immich server (used in entity IDs)",
"immich_url": "The URL of your Immich server (e.g., http://192.168.1.100:2283)",
"api_key": "Your Immich API key"
}

View File

@@ -51,10 +51,12 @@
"title": "Подключение к Immich",
"description": "Введите данные вашего сервера Immich. API-ключ можно получить в Immich → Настройки пользователя → API-ключи.",
"data": {
"hub_name": "Название хаба",
"immich_url": "URL Immich",
"api_key": "API-ключ"
},
"data_description": {
"hub_name": "Название для этого сервера Immich (используется в ID сущностей)",
"immich_url": "URL вашего сервера Immich (например, http://192.168.1.100:2283)",
"api_key": "Ваш API-ключ Immich"
}