From b38fcf310006a3fe06ee967cd707344b631e2da9 Mon Sep 17 00:00:00 2001 From: mib1185 Date: Sun, 22 Jun 2025 09:43:12 +0000 Subject: [PATCH] add upload_file action --- homeassistant/components/immich/__init__.py | 13 +++ homeassistant/components/immich/icons.json | 5 + homeassistant/components/immich/manifest.json | 2 +- homeassistant/components/immich/services.py | 107 ++++++++++++++++++ homeassistant/components/immich/services.yaml | 15 +++ homeassistant/components/immich/strings.json | 37 ++++++ requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 8 files changed, 180 insertions(+), 3 deletions(-) create mode 100644 homeassistant/components/immich/services.py create mode 100644 homeassistant/components/immich/services.yaml diff --git a/homeassistant/components/immich/__init__.py b/homeassistant/components/immich/__init__.py index 18782ec6fd3..fe5155003d5 100644 --- a/homeassistant/components/immich/__init__.py +++ b/homeassistant/components/immich/__init__.py @@ -16,13 +16,25 @@ from homeassistant.const import ( ) from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady +from homeassistant.helpers import config_validation as cv from homeassistant.helpers.aiohttp_client import async_get_clientsession +from homeassistant.helpers.typing import ConfigType +from .const import DOMAIN from .coordinator import ImmichConfigEntry, ImmichDataUpdateCoordinator +from .services import async_setup_services + +CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN) PLATFORMS: list[Platform] = [Platform.SENSOR] +async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: + """Set up immich integration.""" + await async_setup_services(hass) + return True + + async def async_setup_entry(hass: HomeAssistant, entry: ImmichConfigEntry) -> bool: """Set up Immich from a config entry.""" @@ -33,6 +45,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ImmichConfigEntry) -> bo entry.data[CONF_HOST], entry.data[CONF_PORT], entry.data[CONF_SSL], + "home-assistant", ) try: diff --git a/homeassistant/components/immich/icons.json b/homeassistant/components/immich/icons.json index 15bac6370a6..aefce3ed615 100644 --- a/homeassistant/components/immich/icons.json +++ b/homeassistant/components/immich/icons.json @@ -11,5 +11,10 @@ "default": "mdi:file-video" } } + }, + "services": { + "upload_file": { + "service": "mdi:upload" + } } } diff --git a/homeassistant/components/immich/manifest.json b/homeassistant/components/immich/manifest.json index 36c993e9c8f..80dcd87cd88 100644 --- a/homeassistant/components/immich/manifest.json +++ b/homeassistant/components/immich/manifest.json @@ -8,5 +8,5 @@ "iot_class": "local_polling", "loggers": ["aioimmich"], "quality_scale": "silver", - "requirements": ["aioimmich==0.9.1"] + "requirements": ["aioimmich==0.10.1"] } diff --git a/homeassistant/components/immich/services.py b/homeassistant/components/immich/services.py new file mode 100644 index 00000000000..b856c621678 --- /dev/null +++ b/homeassistant/components/immich/services.py @@ -0,0 +1,107 @@ +"""Services for the Immich integration.""" + +import logging +import os.path + +from aioimmich.exceptions import ImmichError +import voluptuous as vol + +from homeassistant.config_entries import ConfigEntryState +from homeassistant.core import HomeAssistant, ServiceCall +from homeassistant.exceptions import ServiceValidationError + +from .const import DOMAIN +from .coordinator import ImmichDataUpdateCoordinator + +_LOGGER = logging.getLogger(__name__) + +SERVICE_UPLOAD_FILE = "upload_file" +SERVICE_SCHEMA_UPLOAD_FILE = vol.Schema( + { + vol.Required("config_entry_id"): str, + vol.Required("file"): str, + vol.Optional("album_id"): str, + } +) + + +async def _async_upload_file(service_call: ServiceCall) -> None: + """Call immich upload file service.""" + _LOGGER.debug( + "Executing service %s with arguments %s", + service_call.service, + service_call.data, + ) + hass = service_call.hass + target_entry = hass.config_entries.async_get_entry( + service_call.data["config_entry_id"] + ) + target_file = service_call.data["file"] + + if not target_entry: + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="config_entry_not_found", + translation_placeholders={"service": service_call.service}, + ) + + if target_entry.state is not ConfigEntryState.LOADED: + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="config_entry_not_loaded", + translation_placeholders={"service": service_call.service}, + ) + + if not os.path.isfile(target_file): + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="file_not_found", + translation_placeholders={ + "service": service_call.service, + "file": target_file, + }, + ) + + coordinator: ImmichDataUpdateCoordinator = target_entry.runtime_data + + if target_album := service_call.data.get("album_id"): + try: + await coordinator.api.albums.async_get_album_info(target_album, True) + except ImmichError as ex: + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="album_not_found", + translation_placeholders={ + "service": service_call.service, + "album_id": target_album, + "error": str(ex), + }, + ) from ex + + try: + upload_result = await coordinator.api.assets.async_upload_asset(target_file) + if target_album: + await coordinator.api.albums.async_add_assets_to_album( + target_album, [upload_result.asset_id] + ) + except ImmichError as ex: + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="upload_failed", + translation_placeholders={ + "service": service_call.service, + "file": target_file, + "error": str(ex), + }, + ) from ex + + +async def async_setup_services(hass: HomeAssistant) -> None: + """Set up services for immich integration.""" + + hass.services.async_register( + DOMAIN, + SERVICE_UPLOAD_FILE, + _async_upload_file, + SERVICE_SCHEMA_UPLOAD_FILE, + ) diff --git a/homeassistant/components/immich/services.yaml b/homeassistant/components/immich/services.yaml new file mode 100644 index 00000000000..f77a8621a79 --- /dev/null +++ b/homeassistant/components/immich/services.yaml @@ -0,0 +1,15 @@ +upload_file: + fields: + config_entry_id: + required: true + selector: + config_entry: + integration: immich + file: + required: true + selector: + text: + album_id: + required: false + selector: + text: diff --git a/homeassistant/components/immich/strings.json b/homeassistant/components/immich/strings.json index 875eb79f50b..f08b5db32d6 100644 --- a/homeassistant/components/immich/strings.json +++ b/homeassistant/components/immich/strings.json @@ -69,5 +69,42 @@ "name": "Disk used by videos" } } + }, + "services": { + "upload_file": { + "name": "Upload file", + "description": "Upload a file to your Immich instance.", + "fields": { + "config_entry_id": { + "name": "Immich instance", + "description": "Select the Immich instance where to upload the file." + }, + "file": { + "name": "File", + "description": "The path to the file to be uploaded." + }, + "album_id": { + "name": "Album id", + "description": "The album where to put the file in after upload." + } + } + } + }, + "exceptions": { + "config_entry_not_found": { + "message": "Failed to perform action \"{service}\". Config entry not found" + }, + "config_entry_not_loaded": { + "message": "Failed to perform action \"{service}\". Config entry not loaded." + }, + "file_not_found": { + "message": "Failed to perform action \"{service}\". File `{file}` not found." + }, + "album_not_found": { + "message": "Failed to perform action \"{service}\". Album with id `{album_id}` not found ({error})." + }, + "upload_failed": { + "message": "Failed to perform action \"{service}\". Upload of file `{file}` failed ({error})." + } } } diff --git a/requirements_all.txt b/requirements_all.txt index 4abc26d14f2..447ec1f1df8 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -280,7 +280,7 @@ aiohue==4.7.4 aioimaplib==2.0.1 # homeassistant.components.immich -aioimmich==0.9.1 +aioimmich==0.10.1 # homeassistant.components.apache_kafka aiokafka==0.10.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index d18c44e2e2a..588651b976a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -265,7 +265,7 @@ aiohue==4.7.4 aioimaplib==2.0.1 # homeassistant.components.immich -aioimmich==0.9.1 +aioimmich==0.10.1 # homeassistant.components.apache_kafka aiokafka==0.10.0