From 6848c3f903a8aeda21e56038b965dbfe1cc94306 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Mon, 9 Feb 2026 12:50:23 +0300 Subject: [PATCH] BREAKING: Replace hour/interval inputs with flexible time lists in `Immich Album Watcher` Replace interval-based scheduling with explicit time lists for more flexibility: - Periodic Summary: Replace interval_hours + start_hour with notification_times - Scheduled Assets: Replace interval_hours + start_hour with notification_times - Memory Mode: Replace start_hour with notification_times Changes: - Remove `periodic_interval_hours` and `periodic_start_hour` inputs - Remove `scheduled_assets_interval_hours` and `scheduled_assets_start_hour` inputs - Replace `memory_mode_start_hour` with `memory_mode_notification_times` - Add three new time text inputs accepting comma-separated HH:MM format - Replace hourly time_pattern trigger with three template triggers - Update trigger logic to match current time against configured times - Update documentation to reflect new time-based scheduling Users can now specify any times (e.g., "09:00, 14:30, 21:00") instead of calculating intervals. Times must use 24-hour format with leading zeros. Co-Authored-By: Claude Sonnet 4.5 --- Common/Immich Album Watcher/README.md | 8 +- Common/Immich Album Watcher/blueprint.yaml | 181 +++++++++------------ manifest.json | 2 +- 3 files changed, 84 insertions(+), 107 deletions(-) diff --git a/Common/Immich Album Watcher/README.md b/Common/Immich Album Watcher/README.md index 1acdd3e..a755a87 100644 --- a/Common/Immich Album Watcher/README.md +++ b/Common/Immich Album Watcher/README.md @@ -156,7 +156,7 @@ Select input_text entities containing Telegram chat IDs. Can be user IDs (positi ## 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). +Sends a summary notification of tracked albums at configured times. Album names and share URLs are automatically read from the Album ID Entity's `album_name` and `share_url` attributes (if available). You can configure multiple notification times (e.g., "12:00, 18:00") using comma-separated 24-hour format with leading zeros. When Telegram media is enabled, an optional image can be attached to the summary message. By default, the official Immich logo is used. Set the **Summary Image URL** to empty to send text-only notifications. @@ -189,7 +189,7 @@ To target a specific automation, set its Automation ID in config and include it ## Scheduled Assets -Sends scheduled notifications with existing assets from tracked albums. Uses the `immich_album_watcher.get_assets` service to fetch assets. +Sends scheduled notifications with existing assets from tracked albums at configured times. Uses the `immich_album_watcher.get_assets` service to fetch assets. You can configure multiple notification times (e.g., "09:00, 21:00") using comma-separated 24-hour format with leading zeros. ### Album Modes @@ -244,14 +244,14 @@ Send scheduled notifications with photos taken on today's date in previous years | Option | Description | |--------|-------------| | `enable_memory_mode` | Enable/disable memory notifications | -| `start_hour` | Hour of day for the daily notification (0-23) | +| `notification_times` | Comma-separated times in 24-hour format (e.g., "09:00, 18:00") | | `album_mode` | per_album, combined, or random | | `limit` | Maximum number of assets to fetch (1-100) | | `favorite_only` | Only fetch favorite assets | | `asset_type` | Filter by type (all, photo, video) | | `min_rating` | Minimum rating filter (1-5, 0 = no filter) | -Memory notifications are sent once per day at the configured start hour. +Memory notifications are sent at the configured times. Times must use 24-hour format with leading zeros (e.g., "09:00" not "9:00"). ### Memory Mode Message Template Variables diff --git a/Common/Immich Album Watcher/blueprint.yaml b/Common/Immich Album Watcher/blueprint.yaml index 483f182..e232a6e 100644 --- a/Common/Immich Album Watcher/blueprint.yaml +++ b/Common/Immich Album Watcher/blueprint.yaml @@ -489,30 +489,14 @@ blueprint: 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_start_hour: - name: Summary Start Hour + periodic_notification_times: + name: Summary Notification Times description: > - Hour of day (0-23) when the first summary should be sent. - Subsequent summaries are sent at this hour plus the interval. - Example: Start hour 12 with 24h interval = daily at 12:00. - default: 12 + Comma-separated list of times to send periodic summaries in + 24-hour format with leading zeros (e.g., "12:00, 18:00"). + default: "12:00" selector: - number: - min: 0 - max: 23 - unit_of_measurement: hour - mode: slider + text: periodic_summary_message: name: Summary Message Template @@ -560,29 +544,14 @@ blueprint: selector: boolean: - scheduled_assets_interval_hours: - name: Interval (Hours) - description: "How often to send scheduled asset notifications (in hours)" - default: 24 - selector: - number: - min: 1 - max: 168 - unit_of_measurement: hours - mode: slider - - scheduled_assets_start_hour: - name: Start Hour + scheduled_assets_notification_times: + name: Notification Times description: > - Hour of day (0-23) when the first notification should be sent. - Example: Start hour 9 with 24h interval = daily at 09:00. - default: 9 + Comma-separated list of times to send scheduled asset notifications + in 24-hour format with leading zeros (e.g., "09:00, 21:00"). + default: "09:00" selector: - number: - min: 0 - max: 23 - unit_of_measurement: hour - mode: slider + text: scheduled_assets_album_mode: name: Album Mode @@ -723,18 +692,14 @@ blueprint: selector: boolean: - memory_mode_start_hour: - name: Start Hour + memory_mode_notification_times: + name: Notification Times description: > - Hour of day (0-23) when the daily memory notification should be sent. - Memory notifications are sent once per day at this hour. - default: 9 + Comma-separated list of times to send memory notifications in + 24-hour format with leading zeros (e.g., "09:00, 18:00"). + default: "09:00" selector: - number: - min: 0 - max: 23 - unit_of_measurement: hour - mode: slider + text: memory_mode_album_mode: name: Album Mode @@ -844,6 +809,14 @@ blueprint: mode: queued max: 10 +# ============================================================================= +# TRIGGER VARIABLES (available in trigger templates) +# ============================================================================= +trigger_variables: + input_periodic_times: !input periodic_notification_times + input_scheduled_times: !input scheduled_assets_notification_times + input_memory_times: !input memory_mode_notification_times + # ============================================================================= # TRIGGERS # ============================================================================= @@ -869,12 +842,21 @@ trigger: event_type: immich_album_watcher_album_deleted id: "album_deleted" - # Hourly timer trigger for periodic summary and scheduled assets - # 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: "hourly_timer" + # Time-based triggers for periodic summary, scheduled assets, and memory mode + - platform: template + value_template: > + {{ now().strftime('%H:%M') in (input_periodic_times.split(',') | map('trim') | list) }} + id: "periodic_summary_timer" + + - platform: template + value_template: > + {{ now().strftime('%H:%M') in (input_scheduled_times.split(',') | map('trim') | list) }} + id: "scheduled_assets_timer" + + - platform: template + value_template: > + {{ now().strftime('%H:%M') in (input_memory_times.split(',') | map('trim') | list) }} + id: "memory_mode_timer" # Manual trigger for testing periodic summary # Fire this event from Developer Tools > Events to test periodic summary immediately @@ -947,16 +929,12 @@ variables: # Periodic Summary Settings enable_periodic_summary: !input enable_periodic_summary - periodic_interval_hours: !input periodic_interval_hours - periodic_start_hour: !input periodic_start_hour periodic_summary_message_template: !input periodic_summary_message periodic_album_template: !input periodic_album_template periodic_summary_image_url: !input periodic_summary_image_url # Scheduled Assets Settings enable_scheduled_assets: !input enable_scheduled_assets - scheduled_assets_interval_hours: !input scheduled_assets_interval_hours - scheduled_assets_start_hour: !input scheduled_assets_start_hour scheduled_assets_album_mode: !input scheduled_assets_album_mode scheduled_assets_limit: !input scheduled_assets_limit scheduled_assets_favorite_only: !input scheduled_assets_favorite_only @@ -970,7 +948,6 @@ variables: # Memory Mode Settings enable_memory_mode: !input enable_memory_mode - memory_mode_start_hour: !input memory_mode_start_hour memory_mode_album_mode: !input memory_mode_album_mode memory_mode_limit: !input memory_mode_limit memory_mode_favorite_only: !input memory_mode_favorite_only @@ -1270,15 +1247,14 @@ variables: # --------------------------------------------------------------------------- # Periodic Summary Variables # --------------------------------------------------------------------------- - # Check if periodic summary should run (every N hours starting from start_hour) - # Formula: (current_hour - start_hour) % interval == 0 - # Example: start_hour=12, interval=24 → sends at 12:00 daily - # Example: start_hour=9, interval=12 → sends at 09:00 and 21:00 + # Check if periodic summary should run (at configured times) # Manual test event (immich_album_watcher_test_periodic_summary) bypasses time check # If event data contains automation_id, only matching automations respond should_send_periodic_summary: > - {% if trigger.id in ['hourly_timer', 'periodic_summary'] and enable_periodic_summary %} - {% if trigger.platform == 'event' and trigger.event.event_type == 'immich_album_watcher_test_periodic_summary' %} + {% if enable_periodic_summary %} + {% if trigger.id == 'periodic_summary_timer' %} + {{ true }} + {% elif trigger.platform == 'event' and trigger.event.event_type == 'immich_album_watcher_test_periodic_summary' %} {% set event_automation_id = trigger.event.data.automation_id | default('') %} {% if event_automation_id | length > 0 %} {{ automation_id == event_automation_id }} @@ -1286,10 +1262,7 @@ variables: {{ true }} {% endif %} {% else %} - {% set current_hour = now().hour %} - {% set start = periodic_start_hour | int %} - {% set interval = periodic_interval_hours | int %} - {{ (current_hour - start) % interval == 0 }} + {{ false }} {% endif %} {% else %} {{ false }} @@ -1329,22 +1302,23 @@ variables: # --------------------------------------------------------------------------- # Scheduled Assets Variables # --------------------------------------------------------------------------- - # Check if scheduled assets should run (every N hours starting from start_hour) + # Check if scheduled assets should run (at configured times) # Manual test event (immich_album_watcher_test_scheduled_assets) bypasses time check # If event data contains automation_id, only matching automations respond should_send_scheduled_assets: > - {% if trigger.id == 'scheduled_assets' and enable_scheduled_assets %} - {% set event_automation_id = trigger.event.data.automation_id | default('') %} - {% if event_automation_id | length > 0 %} - {{ automation_id == event_automation_id }} - {% else %} + {% if enable_scheduled_assets %} + {% if trigger.id == 'scheduled_assets_timer' %} {{ true }} + {% elif trigger.platform == 'event' and trigger.event.event_type == 'immich_album_watcher_test_scheduled_assets' %} + {% set event_automation_id = trigger.event.data.automation_id | default('') %} + {% if event_automation_id | length > 0 %} + {{ automation_id == event_automation_id }} + {% else %} + {{ true }} + {% endif %} + {% else %} + {{ false }} {% endif %} - {% elif trigger.id == 'hourly_timer' and enable_scheduled_assets %} - {% set current_hour = now().hour %} - {% set start = scheduled_assets_start_hour | int %} - {% set interval = scheduled_assets_interval_hours | int %} - {{ (current_hour - start) % interval == 0 }} {% else %} {{ false }} {% endif %} @@ -1360,21 +1334,23 @@ variables: # --------------------------------------------------------------------------- # Memory Mode Variables # --------------------------------------------------------------------------- - # Check if memory mode should run (every N hours starting from start_hour) + # Check if memory mode should run (at configured times) # Manual test event (immich_album_watcher_test_memory_mode) bypasses time check # If event data contains automation_id, only matching automations respond should_send_memory_mode: > - {% if trigger.id == 'memory_mode' and enable_memory_mode %} - {% set event_automation_id = trigger.event.data.automation_id | default('') %} - {% if event_automation_id | length > 0 %} - {{ automation_id == event_automation_id }} - {% else %} + {% if enable_memory_mode %} + {% if trigger.id == 'memory_mode_timer' %} {{ true }} + {% elif trigger.platform == 'event' and trigger.event.event_type == 'immich_album_watcher_test_memory_mode' %} + {% set event_automation_id = trigger.event.data.automation_id | default('') %} + {% if event_automation_id | length > 0 %} + {{ automation_id == event_automation_id }} + {% else %} + {{ true }} + {% endif %} + {% else %} + {{ false }} {% endif %} - {% elif trigger.id == 'hourly_timer' and enable_memory_mode %} - {% set current_hour = now().hour %} - {% set start = memory_mode_start_hour | int %} - {{ current_hour == start }} {% else %} {{ false }} {% endif %} @@ -1392,17 +1368,18 @@ variables: # ============================================================================= condition: # Allow through if: - # 1. Hourly timer or periodic summary trigger and should send periodic summary, scheduled assets, or memory mode - # 2. Scheduled assets trigger (manual test) - # 3. Memory mode trigger (manual test) - # 4. Event trigger and passes all event-based checks + # 1. Time-based triggers (periodic_summary_timer, scheduled_assets_timer, memory_mode_timer) + # 2. Manual test event triggers (periodic_summary, scheduled_assets, memory_mode) + # 3. Event trigger and passes all event-based checks - condition: template value_template: > - {% if trigger.id == 'scheduled_assets' %} + {% if trigger.id == 'periodic_summary_timer' %} + {{ should_send_periodic_summary }} + {% elif trigger.id == 'scheduled_assets_timer' %} {{ should_send_scheduled_assets }} - {% elif trigger.id == 'memory_mode' %} + {% elif trigger.id == 'memory_mode_timer' %} {{ should_send_memory_mode }} - {% elif trigger.id in ['hourly_timer', 'periodic_summary'] %} + {% elif trigger.platform == 'event' and trigger.event.event_type in ['immich_album_watcher_test_periodic_summary', 'immich_album_watcher_test_scheduled_assets', 'immich_album_watcher_test_memory_mode'] %} {{ should_send_periodic_summary or should_send_scheduled_assets or should_send_memory_mode }} {% else %} {{ is_hub_tracked and is_album_tracked and should_notify }} diff --git a/manifest.json b/manifest.json index a0197e8..4928ba5 100644 --- a/manifest.json +++ b/manifest.json @@ -1,3 +1,3 @@ { - "version": "1.35.0" + "version": "2.0.0" }