# ============================================================================= # Immich Album Watcher Blueprint for Home Assistant # ============================================================================= # This blueprint monitors Immich album changes and sends notifications when # assets (photos/videos) are added to specified albums. # Designed to be used in pair with `Immich Album Watcher` integration. # # Features: # - Filter by hub/instance name (for multi-hub setups) # - Monitor specific albums by name (whitelist) # - Filter by asset type (track images only, videos only, or both) # - Send notifications to multiple targets simultaneously # - Customizable notification messages with template variables # - Separate templates for image and video assets # - Optional: include people detected in photos # - Optional: include detailed asset list with per-item formatting # - Support for multiple change types (assets added, removed, changed) # - Optional: send photos/videos as Telegram media attachments # - Optional: periodic summary notifications with album list and share URLs # # Event Data from Immich: # - `hub_name`: Name of the Immich hub/instance that sent the event # - `album_id`: Album ID # - `album_name`: Album name # - `album_url`: Public URL to view the album (only if album has shared link) # - `change_type`: Type of change (assets_added, assets_removed, changed) # - `added_count`: Number of assets added # - `removed_count`: Number of assets removed # - `added_assets`: List of added assets (see Added Assets Fields below) # - `removed_assets`: List of removed asset IDs # - `people`: List of all people detected in the album # # Added Assets Fields (each item in `added_assets`): # - `id`: Unique asset ID # - `asset_type`: Type of asset (IMAGE or VIDEO) # - `asset_filename`: Original filename of the asset # - `asset_description`: User-provided description of the asset # - `asset_created`: Date/time when the asset was originally created # - `asset_owner`: Display name of the user who owns the asset # - `asset_owner_id`: Unique ID of the user who owns the asset # - `asset_url`: Public URL to view the asset (only if album has shared link) # - `asset_download_url`: Direct download URL for the asset (preferred for Telegram images) # - `asset_playback_url`: Playback/streaming URL for videos (preferred for Telegram videos) # - `people`: List of people detected in this specific asset # # Message Template Variables: # All message templates support these placeholder variables (use single braces): # - `{album_name}` - Name of the album # - `{album_url}` - Public URL to view the album (empty if no shared link) # - `{added_count}` - Number of assets added # - `{removed_count}` - Number of assets removed # - `{people}` - Comma-separated list of people detected # - `{assets}` - Formatted list of added assets (using asset item template) # - `{video_warning}` - Warning about video size limits (Telegram only, empty otherwise) # # Asset Item Template Variables (for image/video templates): # These variables can be used in the image and video asset templates. # Also used for Telegram media captions. # - `{filename}` - Original filename of the asset # - `{description}` - User-provided description of the asset # - `{type}` - Asset type (IMAGE or VIDEO) # - `{created}` - Creation date/time # - `{owner}` - Owner display name # - `{url}` - Public URL to view the asset (empty if no shared link) # - `{people}` - People detected in this asset # - `{album_name}` - Name of the album # # Telegram Media Attachments: # When enabled, photos/videos are sent as media attachments to Telegram # using Home Assistant's telegram_bot integration. # # Supports multiple recipients via two methods: # 1. Notify Entities: Select Telegram notify entities. Chat ID is extracted # from the friendly name. Format: "Name (123456789)" # 2. Raw Chat IDs: Enter chat IDs directly for groups/channels. # # Requirements: # - Telegram Bot integration must be configured in Home Assistant # - Immich album must have a shared link (to generate public asset URLs) # - If you have multiple Telegram bots, specify the config_entry_id # (find it in: Settings → Devices & Services → Telegram Bot → your bot → URL) # # Behavior: # - First sends a text notification message to each Telegram chat # - Then sends photos/videos as replies to that notification message # - Media is sent as individual messages (Home Assistant doesn't support # Telegram media groups / albums) # # Limitations: # - Only assets with valid public URLs will be sent # - Telegram has a 50 MB file size limit for media sent via URL # (large videos will fail with "Request Entity Too Large" error) # - Optional video warning can be shown when videos are present # - Media captions use the Image/Video Asset Templates # # Periodic Summary: # Sends a summary notification of tracked albums at regular intervals. # Configure Album Names and Album Share URL Entities (in matching order) to # include album links in the summary. URL entities can be sensors or input_text # helpers containing the share URL for each album. # # Summary Message Template Variables: # - `{albums}` - Formatted list of albums (using album item template) # - `{album_count}` - Number of tracked albums # # Album Item Template Variables: # - `{album_name}` - Name of the album # - `{album_url}` - Share URL for the album # # Author: Alexei Dolgolyov (dolgolyov.alexei@gmail.com) # ============================================================================= blueprint: name: "Custom: Immich Album Watcher" description: > Sends notifications to multiple targets when photos/videos are added to specified Immich albums. Monitors Immich album watcher events and filters by album name. domain: automation # =========================================================================== # INPUT CONFIGURATION # =========================================================================== input: # ------------------------------------------------------------------------- # Hub & Album Configuration # ------------------------------------------------------------------------- albums_group: name: "Hub & Albums" collapsed: false input: hub_names: name: Hub Names to Track description: > List of Immich hub/instance names to monitor. Only events from matching hubs will trigger notifications. Leave empty to track all hubs. default: [] selector: text: multiple: true album_names: name: Album Names to Track description: > List of album names to monitor for changes. Only albums matching these names will trigger notifications. Leave empty to track all albums. default: [] selector: text: multiple: true album_url_entities: name: Album Share URL Entities description: > List of sensor or input_text entities containing share URLs for each album (in the same order as Album Names). Used for periodic summary notifications. Each entity's state should contain the album's share URL. default: [] selector: entity: domain: - sensor - input_text multiple: true track_assets_added: name: Track Assets Added description: "Send notifications when assets are added to albums" default: true selector: boolean: track_assets_removed: name: Track Assets Removed description: "Send notifications when assets are removed from albums" default: false selector: boolean: track_images: name: Track Images description: "Include IMAGE assets in notifications" default: true selector: boolean: track_videos: name: Track Videos description: "Include VIDEO assets in notifications" default: true selector: boolean: # ------------------------------------------------------------------------- # Notification Configuration # ------------------------------------------------------------------------- notification_group: name: "Notification" collapsed: false input: notify_targets: name: Notification Targets description: "Notification service entities to send messages to (select one or more)" selector: entity: domain: notify multiple: true include_people: name: Include People in Notification description: "Include list of detected people in the notification message" default: true selector: boolean: include_asset_details: name: Include Asset Details description: "Include formatted list of added assets in the notification" default: false selector: boolean: max_assets_to_show: name: Maximum Assets to Show description: > Maximum number of assets to include in the notification. Set to 0 for unlimited. Useful to prevent very long notifications. default: 5 selector: number: min: 0 max: 50 mode: slider # ------------------------------------------------------------------------- # Message Templates # ------------------------------------------------------------------------- messages_group: name: "Messages" collapsed: true input: message_assets_added: name: "Assets Added Message" description: > Message sent when assets are added to an album. Variables: `{album_name}`, `{album_url}`, `{added_count}`, `{people}`, `{assets}`, `{video_warning}` default: "šŸ“· {added_count} new photo(s) added to album \"{album_name}\".{people}{assets}{video_warning}" selector: text: multiline: true message_assets_removed: name: "Assets Removed Message" description: > Message sent when assets are removed from an album. Variables: `{album_name}`, `{album_url}`, `{removed_count}` default: "šŸ—‘ļø {removed_count} photo(s) removed from album \"{album_name}\"." selector: text: multiline: true message_people_format: name: "People Format" description: > Format for the people list in notifications. Use `{people}` as the placeholder for the comma-separated list. Leave empty to just show people names without prefix. default: " People: {people}." selector: text: multiline: true message_asset_image: name: "Image Asset Template" description: > Template for IMAGE assets in the list. Also used for Telegram media captions. Variables: `{filename}`, `{description}`, `{type}`, `{created}`, `{owner}`, `{url}`, `{people}`, `{album_name}` default: "\n • šŸ–¼ļø {filename}" selector: text: multiline: true message_asset_video: name: "Video Asset Template" description: > Template for VIDEO assets in the list. Also used for Telegram media captions. Variables: `{filename}`, `{description}`, `{type}`, `{created}`, `{owner}`, `{url}`, `{people}`, `{album_name}` default: "\n • šŸŽ¬ {filename}" selector: text: multiline: true message_assets_format: name: "Assets List Format" description: > Format wrapper for the assets list. Use `{assets}` as placeholder for the formatted asset items. Use `{more_count}` for number of additional assets not shown. default: "\nAssets:{assets}" selector: text: multiline: true message_assets_more: name: "More Assets Message" description: > Message appended when there are more assets than the maximum shown. Use `{more_count}` for the number of additional assets. default: "\n • ...and {more_count} more" selector: text: multiline: true # ------------------------------------------------------------------------- # Telegram Media Attachments # ------------------------------------------------------------------------- telegram_group: name: "Telegram Media" description: "Send photos/videos as Telegram attachments (requires public asset URLs)" collapsed: true input: send_telegram_media: name: Send Media to Telegram description: > Send photos/videos as media attachments to Telegram. IMPORTANT: This requires assets to have public URLs, meaning the Immich album must have a shared link enabled. Note: Due to Home Assistant limitations, media is sent as individual messages rather than grouped albums. default: false selector: boolean: telegram_config_entry_id: name: Telegram Bot Config Entry ID description: > Required if you have multiple Telegram bots configured. Find this in Home Assistant: Settings → Devices & Services → Telegram Bot → Click on your bot → look at the URL, the ID is after /config_entry/ Example: "01JKXXXXXXXXXXXXXXXXXXX" Leave empty if you only have one Telegram bot. default: "" selector: text: telegram_notify_targets: name: Telegram Notify Targets description: > Select Telegram notify entities to send media to. The chat ID will be extracted from the entity's friendly name. Expected format: "Name (123456789)" where the number in parentheses is the chat ID. default: [] selector: entity: domain: notify multiple: true telegram_chat_ids: name: Additional Telegram Chat IDs description: > Additional raw chat IDs to send media to (one per line). Use this for chat IDs not associated with notify entities, or as a fallback if friendly name parsing doesn't work. Can be user IDs (positive) or group IDs (negative). default: [] selector: text: multiple: true max_media_to_send: name: Maximum Media to Send description: > Maximum number of photos/videos to send as attachments. Set to 0 for unlimited. Recommended to keep low to avoid spam. default: 5 selector: number: min: 0 max: 10 mode: slider telegram_media_delay: name: Delay Between Media (ms) description: > Delay in milliseconds between sending each media item. Helps avoid rate limiting and spaces out media messages. Set to 0 for no delay. default: 500 selector: number: min: 0 max: 5000 step: 100 unit_of_measurement: ms mode: slider telegram_video_warning: name: Video Warning Message description: > Warning message appended to notifications when videos are present. Telegram has a 50 MB file size limit for media sent via URL, so large videos may fail to send. Leave empty to disable warning. default: "\n\nāš ļø Note: Videos may not be sent due to Telegram's 50 MB file size limit." selector: text: multiline: true # ------------------------------------------------------------------------- # Periodic Summary # ------------------------------------------------------------------------- periodic_group: name: "Periodic Summary" description: "Send periodic notifications with a summary of tracked albums" collapsed: true input: enable_periodic_summary: name: Enable Periodic Summary description: > Send a summary notification of tracked albums at regular intervals. Requires Album Names and Album Share URLs to be configured. default: false selector: boolean: periodic_interval_hours: name: Summary Interval (Hours) description: "How often to send the summary notification (in hours)" default: 24 selector: number: min: 1 max: 168 unit_of_measurement: hours mode: slider periodic_summary_message: name: Summary Message Template description: > Message template for the periodic summary. Variables: `{albums}` (formatted list of albums), `{album_count}` (number of albums) default: "šŸ“‹ Tracked Albums Summary ({album_count} albums):{albums}" selector: text: multiline: true periodic_album_template: name: Album Item Template description: > Template for each album in the summary list. Variables: `{album_name}`, `{album_url}` default: "\n • {album_name}: {album_url}" selector: text: multiline: true # ------------------------------------------------------------------------- # Debug # ------------------------------------------------------------------------- debug: name: "Debug" collapsed: true input: enable_debug_notifications: name: Enable Debug Notifications description: > Send persistent notifications for debugging automation behavior. Shows event data and filtering decisions. default: false selector: boolean: # ============================================================================= # AUTOMATION MODE # ============================================================================= # Single mode to process one event at a time mode: single # ============================================================================= # TRIGGERS # ============================================================================= trigger: # Monitor Immich album watcher events - platform: event event_type: immich_album_watcher_assets_added id: "assets_added" - platform: event event_type: immich_album_watcher_assets_removed id: "assets_removed" - platform: event event_type: immich_album_watcher_changed id: "changed" # Periodic summary trigger (time pattern) # Note: Uses template to dynamically set interval, but HA requires static value # so we trigger every hour and check interval in conditions - platform: time_pattern hours: "/1" id: "periodic_summary" # ============================================================================= # VARIABLES # ============================================================================= variables: # --------------------------------------------------------------------------- # Input Variables # --------------------------------------------------------------------------- hub_names: !input hub_names album_names: !input album_names album_url_entities: !input album_url_entities notify_targets: !input notify_targets include_people: !input include_people include_asset_details: !input include_asset_details max_assets_to_show: !input max_assets_to_show track_assets_added: !input track_assets_added track_assets_removed: !input track_assets_removed track_images: !input track_images track_videos: !input track_videos enable_debug_notifications: !input enable_debug_notifications # Telegram Media Settings send_telegram_media: !input send_telegram_media telegram_config_entry_id: !input telegram_config_entry_id telegram_notify_targets: !input telegram_notify_targets telegram_chat_ids_raw: !input telegram_chat_ids max_media_to_send: !input max_media_to_send telegram_media_delay: !input telegram_media_delay telegram_video_warning_template: !input telegram_video_warning # Periodic Summary Settings enable_periodic_summary: !input enable_periodic_summary periodic_interval_hours: !input periodic_interval_hours periodic_summary_message_template: !input periodic_summary_message periodic_album_template: !input periodic_album_template # Parse chat IDs from notify entity friendly names (format: "Name (123456789)") # and combine with raw chat IDs telegram_chat_ids: > {% set ns = namespace(ids = []) %} {# Extract chat IDs from notify entity friendly names #} {% for entity_id in telegram_notify_targets %} {% set friendly_name = state_attr(entity_id, 'friendly_name') | default('') %} {# Match number in parentheses at the end: "Diana (350705409)" -> "350705409" #} {% set match = friendly_name | regex_findall('\\((-?\\d+)\\)\\s*$') %} {% if match | length > 0 %} {% set ns.ids = ns.ids + [match[0]] %} {% endif %} {% endfor %} {# Add raw chat IDs #} {% for chat_id in telegram_chat_ids_raw %} {% set clean_id = chat_id | trim %} {% if clean_id | length > 0 and clean_id not in ns.ids %} {% set ns.ids = ns.ids + [clean_id] %} {% endif %} {% endfor %} {{ ns.ids }} # --------------------------------------------------------------------------- # Message Templates # --------------------------------------------------------------------------- message_assets_added_template: !input message_assets_added message_assets_removed_template: !input message_assets_removed message_people_format_template: !input message_people_format message_asset_image_template: !input message_asset_image message_asset_video_template: !input message_asset_video message_assets_format_template: !input message_assets_format message_assets_more_template: !input message_assets_more # --------------------------------------------------------------------------- # Event Data # --------------------------------------------------------------------------- event_hub_name: "{{ trigger.event.data.hub_name | default('') }}" event_album_name: "{{ trigger.event.data.album_name | default('Unknown Album') }}" event_album_id: "{{ trigger.event.data.album_id | default('') }}" event_album_url: "{{ trigger.event.data.album_url | default('') }}" event_change_type: "{{ trigger.event.data.change_type | default(trigger.id) }}" event_added_count: "{{ trigger.event.data.added_count | default(0) | int }}" event_removed_count: "{{ trigger.event.data.removed_count | default(0) | int }}" event_people: "{{ trigger.event.data.people | default([]) }}" event_added_assets: "{{ trigger.event.data.added_assets | default([]) }}" # --------------------------------------------------------------------------- # Computed Values # --------------------------------------------------------------------------- # Check if this hub should be tracked (empty list = track all) is_hub_tracked: > {{ hub_names | length == 0 or event_hub_name in hub_names }} # Check if this album should be tracked (empty list = track all) is_album_tracked: > {{ album_names | length == 0 or event_album_name in album_names }} # Format people list for notification people_list: > {% if include_people and event_people | length > 0 %} {% set people_str = event_people | join(', ') %} {{ message_people_format_template | replace('{people}', people_str) }} {% else %} {{ '' }} {% endif %} # Filter assets based on track_images/track_videos settings filtered_assets: > {% set ns = namespace(assets = []) %} {% for asset in event_added_assets %} {% if (asset.asset_type == 'IMAGE' and track_images) or (asset.asset_type == 'VIDEO' and track_videos) %} {% set ns.assets = ns.assets + [asset] %} {% endif %} {% endfor %} {{ ns.assets }} # Count of filtered assets (for notifications) filtered_added_count: "{{ filtered_assets | length }}" # Format assets list for notification assets_list: > {% if include_asset_details and filtered_assets | length > 0 %} {% set ns = namespace(items = '') %} {% set max_items = max_assets_to_show if max_assets_to_show > 0 else filtered_assets | length %} {% set assets_to_show = filtered_assets[:max_items] %} {% for asset in assets_to_show %} {% set asset_template = message_asset_video_template if asset.asset_type == 'VIDEO' else message_asset_image_template %} {% set item = asset_template | replace('{filename}', asset.asset_filename | default('Unknown')) | replace('{description}', asset.asset_description | default('')) | replace('{type}', asset.asset_type | default('Unknown')) | replace('{created}', asset.asset_created | default('Unknown')) | replace('{owner}', asset.asset_owner | default('Unknown')) | replace('{url}', asset.asset_url | default('')) | replace('{people}', (asset.people | default([])) | join(', ')) | replace('{album_name}', event_album_name) %} {% set ns.items = ns.items ~ item %} {% endfor %} {% set more_count = filtered_assets | length - max_items %} {% if more_count > 0 %} {% set ns.items = ns.items ~ message_assets_more_template | replace('{more_count}', more_count | string) %} {% endif %} {{ message_assets_format_template | replace('{assets}', ns.items) }} {% else %} {{ '' }} {% endif %} # Check if filtered assets contain any videos (for Telegram warning) has_videos_in_assets: > {{ filtered_assets | selectattr('asset_type', 'equalto', 'VIDEO') | list | length > 0 }} # Video warning text (only populated when Telegram media is enabled and videos are present) video_warning_text: > {% if send_telegram_media and has_videos_in_assets and telegram_video_warning_template | length > 0 %} {{ telegram_video_warning_template }} {% else %} {{ '' }} {% endif %} # Filter assets that have valid URLs (for Telegram media) # URL preference: playback_url (videos) > download_url > asset_url (viewer) assets_with_urls: > {% set ns = namespace(assets = []) %} {% for asset in filtered_assets %} {% set playback_url = asset.asset_playback_url | default('') %} {% set download_url = asset.asset_download_url | default('') %} {% set view_url = asset.asset_url | default('') %} {% if playback_url | length > 0 or download_url | length > 0 or view_url | length > 0 %} {% set ns.assets = ns.assets + [asset] %} {% endif %} {% endfor %} {{ ns.assets }} # Determine if this event type should trigger a notification # For added assets, check filtered count (respects track_images/track_videos) should_notify: > {% if trigger.id == 'assets_added' and track_assets_added and filtered_added_count | int > 0 %} {{ true }} {% elif trigger.id == 'assets_removed' and track_assets_removed and event_removed_count > 0 %} {{ true }} {% elif trigger.id == 'changed' and (track_assets_added or track_assets_removed) %} {% if track_assets_added and filtered_added_count | int > 0 %} {{ true }} {% elif track_assets_removed and event_removed_count > 0 %} {{ true }} {% else %} {{ false }} {% endif %} {% else %} {{ false }} {% endif %} # --------------------------------------------------------------------------- # Periodic Summary Variables # --------------------------------------------------------------------------- # Check if periodic summary should run (every N hours based on interval) # Uses current hour modulo interval to determine if it's time to send should_send_periodic_summary: > {% if trigger.id == 'periodic_summary' and enable_periodic_summary %} {% set current_hour = now().hour %} {{ current_hour % (periodic_interval_hours | int) == 0 }} {% else %} {{ false }} {% endif %} # Format the albums list for periodic summary # Reads URLs from entity states (sensor or input_text) periodic_albums_list: > {% set ns = namespace(items = '') %} {% for i in range(album_names | length) %} {% set name = album_names[i] %} {% set url_entity = album_url_entities[i] | default('') if i < (album_url_entities | length) else '' %} {% set url = states(url_entity) | default('') if url_entity | length > 0 else '' %} {% set item = periodic_album_template | replace('{album_name}', name) | replace('{album_url}', url) %} {% set ns.items = ns.items ~ item %} {% endfor %} {{ ns.items }} # Complete periodic summary message periodic_summary_formatted: > {{ periodic_summary_message_template | replace('{albums}', periodic_albums_list) | replace('{album_count}', album_names | length | string) }} # ============================================================================= # CONDITIONS # ============================================================================= condition: # Allow through if: # 1. Periodic summary trigger and should send periodic summary # 2. Event trigger and passes all event-based checks - condition: template value_template: > {% if trigger.id == 'periodic_summary' %} {{ should_send_periodic_summary }} {% else %} {{ is_hub_tracked and is_album_tracked and should_notify }} {% endif %} # ============================================================================= # ACTIONS # ============================================================================= action: # --------------------------------------------------------------------------- # PERIODIC SUMMARY: Send summary of tracked albums (time-based trigger) # --------------------------------------------------------------------------- - choose: - conditions: - condition: template value_template: "{{ trigger.id == 'periodic_summary' }}" sequence: # Send periodic summary to notification targets - service: notify.send_message target: entity_id: "{{ notify_targets }}" data: message: "{{ periodic_summary_formatted }}" # Also send to Telegram if configured - choose: - conditions: - condition: template value_template: "{{ send_telegram_media and telegram_chat_ids | length > 0 }}" sequence: - repeat: for_each: "{{ telegram_chat_ids }}" sequence: - service: telegram_bot.send_message data: target: "{{ repeat.item }}" message: "{{ periodic_summary_formatted }}" config_entry_id: > {{ telegram_config_entry_id if telegram_config_entry_id | length > 0 else omit }} # Stop here for periodic summary - don't continue to event-based actions - stop: "Periodic summary sent" # --------------------------------------------------------------------------- # DEBUG: Log event data (enabled via Debug input section) # --------------------------------------------------------------------------- - choose: - conditions: - condition: template value_template: "{{ enable_debug_notifications }}" sequence: - service: persistent_notification.create data: title: "Immich Album Watcher Debug" message: > Trigger ID: {{ trigger.id }} Hub: {{ event_hub_name }} Album: {{ event_album_name }} Album ID: {{ event_album_id }} Album URL: {{ event_album_url }} Change Type: {{ event_change_type }} Added Count (raw): {{ event_added_count }} Added Count (filtered): {{ filtered_added_count }} Removed Count: {{ event_removed_count }} Added Assets: {{ event_added_assets | length }} People: {{ event_people | join(', ') }} Is Hub Tracked: {{ is_hub_tracked }} Is Album Tracked: {{ is_album_tracked }} Should Notify: {{ should_notify }} Track Images: {{ track_images }} Track Videos: {{ track_videos }} Include Asset Details: {{ include_asset_details }} # --------------------------------------------------------------------------- # Send Notification Based on Event Type # --------------------------------------------------------------------------- - choose: # --------------------------------------------------------------------- # CASE 1: Assets Added # --------------------------------------------------------------------- - conditions: - condition: template value_template: "{{ trigger.id == 'assets_added' and track_assets_added and filtered_added_count | int > 0 }}" sequence: - variables: message: > {% set tpl = message_assets_added_template %} {{ tpl | replace('{album_name}', event_album_name) | replace('{album_url}', event_album_url) | replace('{added_count}', filtered_added_count | string) | replace('{people}', people_list) | replace('{assets}', assets_list) | replace('{video_warning}', video_warning_text) }} - service: notify.send_message target: entity_id: "{{ notify_targets }}" data: message: "{{ message }}" # --------------------------------------------------------------------- # CASE 2: Assets Removed # --------------------------------------------------------------------- - conditions: - condition: template value_template: "{{ trigger.id == 'assets_removed' and track_assets_removed and event_removed_count > 0 }}" sequence: - variables: message: > {% set tpl = message_assets_removed_template %} {{ tpl | replace('{album_name}', event_album_name) | replace('{album_url}', event_album_url) | replace('{removed_count}', event_removed_count | string) }} - service: notify.send_message target: entity_id: "{{ notify_targets }}" data: message: "{{ message }}" # --------------------------------------------------------------------- # CASE 3: Changed (handles both added and removed in one event) # --------------------------------------------------------------------- - conditions: - condition: template value_template: "{{ trigger.id == 'changed' }}" sequence: # Send added notification if applicable - choose: - conditions: - condition: template value_template: "{{ track_assets_added and filtered_added_count | int > 0 }}" sequence: - variables: message: > {% set tpl = message_assets_added_template %} {{ tpl | replace('{album_name}', event_album_name) | replace('{album_url}', event_album_url) | replace('{added_count}', filtered_added_count | string) | replace('{people}', people_list) | replace('{assets}', assets_list) | replace('{video_warning}', video_warning_text) }} - service: notify.send_message target: entity_id: "{{ notify_targets }}" data: message: "{{ message }}" # Send removed notification if applicable - choose: - conditions: - condition: template value_template: "{{ track_assets_removed and event_removed_count > 0 }}" sequence: - variables: message: > {% set tpl = message_assets_removed_template %} {{ tpl | replace('{album_name}', event_album_name) | replace('{album_url}', event_album_url) | replace('{removed_count}', event_removed_count | string) }} - service: notify.send_message target: entity_id: "{{ notify_targets }}" data: message: "{{ message }}" # --------------------------------------------------------------------------- # Send Media to Telegram (if enabled) # --------------------------------------------------------------------------- # Sends photos/videos as individual Telegram messages using telegram_bot integration. # Note: Media is sent individually (HA doesn't support Telegram media groups). - choose: - conditions: - condition: template value_template: > {{ send_telegram_media and telegram_chat_ids | length > 0 and assets_with_urls | length > 0 and (trigger.id == 'assets_added' or (trigger.id == 'changed' and filtered_added_count | int > 0)) }} sequence: - variables: # Calculate how many media items to send media_limit: > {% if max_media_to_send > 0 %} {{ max_media_to_send }} {% else %} {{ assets_with_urls | length }} {% endif %} media_to_send: "{{ assets_with_urls[:media_limit | int] }}" # Debug logging for Telegram media - choose: - conditions: - condition: template value_template: "{{ enable_debug_notifications }}" sequence: - service: persistent_notification.create data: title: "Immich Album Watcher - Telegram Media Debug" message: > **Telegram Configuration:** - Config Entry ID: {{ telegram_config_entry_id if telegram_config_entry_id | length > 0 else '(not set)' }} - Chat IDs: {{ telegram_chat_ids | join(', ') }} **Media to Send ({{ media_to_send | length }} items):** {% for asset in media_to_send %} {% set playback_url = asset.asset_playback_url | default('') %} {% set download_url = asset.asset_download_url | default('') %} {% set view_url = asset.asset_url | default('') %} {% if asset.asset_type == 'VIDEO' %} {% set used_url = playback_url if playback_url | length > 0 else (download_url if download_url | length > 0 else view_url) %} {% else %} {% set used_url = download_url if download_url | length > 0 else view_url %} {% endif %} - {{ asset.asset_type }}: {{ asset.asset_filename | default('unknown') }} Playback URL: {{ playback_url if playback_url | length > 0 else '(not available)' }} Download URL: {{ download_url if download_url | length > 0 else '(not available)' }} View URL: {{ view_url if view_url | length > 0 else '(not available)' }} **Using: {{ used_url if used_url | length > 0 else '(no URL!)' }}** {% endfor %} **Tip:** For videos, playback URLs (asset_playback_url) are preferred. For images, download URLs (asset_download_url) are preferred. View URLs may return 404. # Build the notification message for Telegram # Uses {video_warning} placeholder which is populated when videos are present - variables: telegram_message: > {% set tpl = message_assets_added_template %} {{ tpl | replace('{album_name}', event_album_name) | replace('{album_url}', event_album_url) | replace('{added_count}', filtered_added_count | string) | replace('{people}', people_list) | replace('{assets}', assets_list) | replace('{video_warning}', video_warning_text) }} # Loop through each chat ID - repeat: for_each: "{{ telegram_chat_ids }}" sequence: - variables: current_chat_id: "{{ repeat.item }}" # First send the text notification message to this chat - service: telegram_bot.send_message response_variable: telegram_response data: target: "{{ current_chat_id }}" message: "{{ telegram_message }}" config_entry_id: > {{ telegram_config_entry_id if telegram_config_entry_id | length > 0 else omit }} # Extract message ID for replies from response.chats[0].message_id - variables: reply_to_message_id: "{{ telegram_response.chats[0].message_id | default(0) | int }}" # Send each media item to this chat as reply to the notification - repeat: count: "{{ media_to_send | length }}" sequence: # Delay before each media item (acts as delay after notification for first item) - choose: - conditions: - condition: template value_template: "{{ telegram_media_delay > 0 }}" sequence: - delay: milliseconds: "{{ telegram_media_delay }}" - variables: current_asset: "{{ media_to_send[repeat.index - 1] }}" asset_type: "{{ current_asset.asset_type | default('IMAGE') }}" # URL preference: playback_url (videos) > download_url > asset_url asset_url: > {% set playback_url = current_asset.asset_playback_url | default('') %} {% set download_url = current_asset.asset_download_url | default('') %} {% set view_url = current_asset.asset_url | default('') %} {% if asset_type == 'VIDEO' and playback_url | length > 0 %} {{ playback_url }} {% elif download_url | length > 0 %} {{ download_url }} {% else %} {{ view_url }} {% endif %} # Use image/video asset templates for captions caption: > {% set tpl = message_asset_video_template if asset_type == 'VIDEO' else message_asset_image_template %} {{ tpl | replace('{filename}', current_asset.asset_filename | default('')) | replace('{description}', current_asset.asset_description | default('')) | replace('{type}', current_asset.asset_type | default('')) | replace('{created}', current_asset.asset_created | default('')) | replace('{owner}', current_asset.asset_owner | default('')) | replace('{url}', current_asset.asset_url | default('')) | replace('{people}', (current_asset.people | default([])) | join(', ')) | replace('{album_name}', event_album_name) }} # Send photo or video based on asset type - choose: # Send as photo for IMAGE assets - conditions: - condition: template value_template: "{{ asset_type == 'IMAGE' }}" sequence: - service: telegram_bot.send_photo # Continue on error so one failed photo doesn't stop other media continue_on_error: true data: target: "{{ current_chat_id }}" url: "{{ asset_url }}" caption: "{{ caption }}" reply_to_message_id: > {{ reply_to_message_id if reply_to_message_id > 0 else omit }} config_entry_id: > {{ telegram_config_entry_id if telegram_config_entry_id | length > 0 else omit }} # Send as video for VIDEO assets - conditions: - condition: template value_template: "{{ asset_type == 'VIDEO' }}" sequence: - service: telegram_bot.send_video # Continue on error so one large video doesn't stop other media # Note: Telegram has 50 MB limit for videos sent via URL continue_on_error: true data: target: "{{ current_chat_id }}" url: "{{ asset_url }}" caption: "{{ caption }}" reply_to_message_id: > {{ reply_to_message_id if reply_to_message_id > 0 else omit }} config_entry_id: > {{ telegram_config_entry_id if telegram_config_entry_id | length > 0 else omit }}