Files
haos-blueprints/Common/Immich Album Watcher.yaml
alexei.dolgolyov f30ed433fd
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 3s
That album ids entities which also provide with required attributes. Change default datetime format.
2026-01-30 16:12:33 +03:00

1093 lines
48 KiB
YAML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================================
# 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.
# Album names and share URLs are automatically read from the Album ID Entity's
# `album_name` and `share_url` attributes (if available).
#
# 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_id_entities:
name: Album ID Entities
description: >
List of sensor or input_text entities containing album IDs to monitor.
Only albums matching these IDs will trigger notifications.
Leave empty to track all albums.
Album IDs are stable and won't change if albums get renamed.
Album names and share URLs are automatically read from the entity's
`album_name` and `share_url` attributes for periodic summary notifications.
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
date_format:
name: "Date Format"
description: >
Format for displaying asset creation dates.
Uses Python strftime format codes (e.g., %Y-%m-%d %H:%M).
Note: Month names (%b, %B) use system locale (typically English).
Use numeric format (%m) for locale-independent dates.
default: "%d.%m.%Y, %H:%M"
selector:
text:
# -------------------------------------------------------------------------
# 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_id}`, `{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_id_entities: !input album_id_entities
# Read album IDs from entity states
album_ids: >
{% set ns = namespace(ids = []) %}
{% for entity_id in album_id_entities %}
{% set value = states(entity_id) | default('') | trim %}
{% if value | length > 0 and value not in ['unknown', 'unavailable'] %}
{% set ns.ids = ns.ids + [value] %}
{% endif %}
{% endfor %}
{{ ns.ids }}
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
date_format: !input date_format
# ---------------------------------------------------------------------------
# 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_ids | length == 0 or event_album_id in album_ids }}
# 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 raw_date = asset.asset_created | default('') %}
{% set dt = raw_date | as_datetime(none) if raw_date | length > 0 else none %}
{% set formatted_date = dt.strftime(date_format) if dt else '' %}
{% 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}', formatted_date)
| 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 album name and share URL from album ID entity's attributes
periodic_albums_list: >
{% set ns = namespace(items = '') %}
{% for i in range(album_id_entities | length) %}
{% set entity_id = album_id_entities[i] %}
{% set id = states(entity_id) | default('') %}
{% if id | length > 0 and id not in ['unknown', 'unavailable'] %}
{% set name_attr = state_attr(entity_id, 'album_name') %}
{% set name = name_attr if name_attr not in [none, '', 'unknown', 'unavailable'] else id %}
{% set url_attr = state_attr(entity_id, 'share_url') %}
{% set url = url_attr if url_attr not in [none, 'unknown', 'unavailable'] else '' %}
{% set item = periodic_album_template
| replace('{album_name}', name)
| replace('{album_id}', id)
| replace('{album_url}', url) %}
{% set ns.items = ns.items ~ item %}
{% endif %}
{% endfor %}
{{ ns.items }}
# Complete periodic summary message
periodic_summary_formatted: >
{{ periodic_summary_message_template
| replace('{albums}', periodic_albums_list)
| replace('{album_count}', album_ids | 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 %}
{% set raw_date = current_asset.asset_created | default('') %}
{% set dt = raw_date | as_datetime(none) if raw_date | length > 0 else none %}
{% set formatted_date = dt.strftime(date_format) if dt else '' %}
{{ tpl | replace('{filename}', current_asset.asset_filename | default(''))
| replace('{description}', current_asset.asset_description | default(''))
| replace('{type}', current_asset.asset_type | default(''))
| replace('{created}', formatted_date)
| 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 }}