Compare commits

..

6 Commits

Author SHA1 Message Date
13132323ea Add debug logging and quiet hours support to Immich Album Watcher Telegram notifications
- Add debug persistent notifications after all 13 send_telegram_notification calls
  (periodic summary, scheduled per-album/combined, memory per-album/combined,
  album renamed/deleted, assets added text/media) logging chat ID, caption,
  assets count, reply-to ID, and service response when debug mode is enabled
- Replace removed ignore_quiet_hours parameter with new quiet_hours_start and
  quiet_hours_end time inputs (defaults: 23:00-07:00) on all Telegram service calls
- Update README with quiet hours documentation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 00:42:26 +03:00
a6ac4f4257 Add debug logging input and skip redundant on/off commands in Climate Device Controller
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 13:42:02 +03:00
584c970044 Make power_sensor optional in Climate Device Controller
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 13:27:48 +03:00
4c03bc849e Several minor updates to the existing blueprints 2026-02-28 22:10:11 +03:00
eefc8993e3 Add min_brightness setting to Light Color Mapper
Adds a minimum brightness floor (default: 5) that prevents lights from
becoming too dim. Applied to both sensor brightness and default color paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 00:51:03 +03:00
9d19dfa8d3 Fix multiple mode:restart state machine bugs in Motion Light
- Fix brightness threshold falsely resetting state to NONE during light
  transition ramp-up (brightness temporarily below threshold != light off)
- Fix false manual override from Zigbee attribute-only updates (on→on)
  by requiring meaningful state change (on→off or off→on)
- Fix disable guard to also accept ENABLING state (not just ENABLED)
- Move state updates before service calls to survive mode:restart cancellation
- Add ENABLING sub-case handler for motion-cleared-during-enable scenario
- Add CASE 1 default handler for restart recovery disable path
- Add comprehensive debug logging at automation entry and CASE 1 entry
- Change default timeout_delay to 0 and grace_period to 2s
- Remove unused is_debug/is_base_debug variables

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 01:57:45 +03:00
7 changed files with 824 additions and 144 deletions

View File

@@ -237,8 +237,11 @@ blueprint:
collapsed: false
input:
power_sensor:
name: Power Sensor
description: "Sensor reporting device power consumption (W)"
name: Power Sensor (optional)
description: >
Sensor reporting device power consumption (W).
Leave empty to disable power monitoring.
default:
selector:
entity:
domain: sensor
@@ -277,6 +280,22 @@ blueprint:
entity:
domain: input_boolean
# -------------------------------------------------------------------------
# Debug
# -------------------------------------------------------------------------
debug_group:
name: "Debug"
collapsed: true
input:
enable_debug_notifications:
name: Enable Debug Notifications
description: >
Send persistent notifications for debugging automation behavior.
Shows current state of all variables and filtering decisions.
default: false
selector:
boolean:
# =============================================================================
# AUTOMATION MODE
# =============================================================================
@@ -321,13 +340,6 @@ trigger:
- platform: state
entity_id: !input env_sensors
# Power sensor dropped below threshold (potential malfunction)
- platform: numeric_state
entity_id: !input power_sensor
below: !input power_threshold
for:
seconds: !input power_decay_duration
# =============================================================================
# CONDITIONS
# =============================================================================
@@ -349,6 +361,11 @@ action:
force_on_entity: !input force_on_entity
hysteresis_window: !input hysteresis_window
# -----------------------------------------------------------------------
# Device State
# -----------------------------------------------------------------------
is_device_on: "{{ states(device_entity) not in ['off', 'unavailable', 'unknown'] }}"
# -----------------------------------------------------------------------
# Force ON Check
# -----------------------------------------------------------------------
@@ -406,13 +423,13 @@ action:
# -----------------------------------------------------------------------
# Power Monitoring
# -----------------------------------------------------------------------
power_threshold: !input power_threshold
power_sensor: !input power_sensor
power_threshold: !input power_threshold
power_problematic_indicator_entity: !input power_problematic_indicator_entity
power_decay_duration: !input power_decay_duration
power: "{{ states(power_sensor) | float(0) }}"
power: "{{ states(power_sensor) | float(0) if power_sensor is not none else 0 }}"
# Device is problematic if it's consuming power but below threshold
is_power_not_ok: "{{ (power > 0 and power < power_threshold) if power_threshold != 0 else false }}"
is_power_not_ok: "{{ (power > 0 and power < power_threshold) if power_sensor is not none and power_threshold != 0 else false }}"
# -----------------------------------------------------------------------
# Window/Door State
@@ -472,7 +489,7 @@ action:
# -----------------------------------------------------------------------
# Debug Flag
# -----------------------------------------------------------------------
is_debug: false
is_debug: !input enable_debug_notifications
# ---------------------------------------------------------------------------
# DEBUG: Log current state
@@ -482,18 +499,29 @@ action:
sequence:
- service: persistent_notification.create
data:
title: "Climate Controller (debug)"
title: "Climate Device Controller Debug"
message: >
is_force_on = {{ is_force_on }},
room_closed = {{ room_closed }},
house_closed = {{ house_closed }},
is_value_below_threshold = {{ is_value_below_threshold }},
is_value_below_turn_on_threshold = {{ is_value_below_turn_on_threshold }},
is_value_at_or_above_target = {{ is_value_at_or_above_target }},
target_value = {{ target_value }},
turn_on_threshold = {{ turn_on_threshold }},
schedule_active = {{ schedule_active }},
control_switch = {{ states(control_switch) }}
**Device State:**
- Device: {{ states(device_entity) }} (on: {{ is_device_on }})
- Control Switch: {{ states(control_switch) }}
- Force ON: {{ is_force_on }}
- Schedule Active: {{ schedule_active }}
**Environment:**
- Target Value: {{ target_value }}
- Turn-On Threshold: {{ turn_on_threshold }} (hysteresis: {{ hysteresis_window }})
- Below Emergency Threshold: {{ is_value_below_threshold }}
- Below Turn-On Threshold: {{ is_value_below_turn_on_threshold }}
- At/Above Target: {{ is_value_at_or_above_target }}
**Doors & Windows:**
- House Closed: {{ house_closed }}
- Room Closed: {{ room_closed }}
**Power Monitoring:**
- Power Sensor: {{ power_sensor | default('not configured') }}
- Power: {{ power }} W
- Power OK: {{ not is_power_not_ok }}
# ---------------------------------------------------------------------------
# POWER MONITORING: Flag device if malfunctioning
@@ -503,7 +531,7 @@ action:
- choose:
- conditions:
- condition: template
value_template: "{{ states(device_entity) not in ['off', 'unavailable', 'unknown'] and power_problematic_indicator_entity is not none }}"
value_template: "{{ power_sensor is not none and states(device_entity) not in ['off', 'unavailable', 'unknown'] and power_problematic_indicator_entity is not none }}"
sequence:
- variables:
# Check if enough time has passed since last power reading
@@ -562,7 +590,11 @@ action:
- conditions:
- condition: template
value_template: "{{ is_force_on }}"
sequence: !input turn_on_action
sequence:
- if:
- condition: template
value_template: "{{ not is_device_on }}"
then: !input turn_on_action
# -----------------------------------------------------------------------
# PRIORITY 2: Emergency Override (Safety)
@@ -571,7 +603,11 @@ action:
- conditions:
- condition: template
value_template: "{{ is_value_below_threshold }}"
sequence: !input turn_on_action
sequence:
- if:
- condition: template
value_template: "{{ not is_device_on }}"
then: !input turn_on_action
# -----------------------------------------------------------------------
# PRIORITY 3: Control Switch Off
@@ -580,7 +616,11 @@ action:
- conditions:
- condition: template
value_template: "{{ is_state(control_switch, 'off') }}"
sequence: !input turn_off_action
sequence:
- if:
- condition: template
value_template: "{{ is_device_on }}"
then: !input turn_off_action
# -----------------------------------------------------------------------
# PRIORITY 4: Environment Not Ready
@@ -589,7 +629,11 @@ action:
- conditions:
- condition: template
value_template: "{{ not (house_closed or room_closed) or not schedule_active }}"
sequence: !input turn_off_action
sequence:
- if:
- condition: template
value_template: "{{ is_device_on }}"
then: !input turn_off_action
# -----------------------------------------------------------------------
# PRIORITY 5: Target Reached
@@ -598,7 +642,11 @@ action:
- conditions:
- condition: template
value_template: "{{ is_value_at_or_above_target }}"
sequence: !input turn_off_action
sequence:
- if:
- condition: template
value_template: "{{ is_device_on }}"
then: !input turn_off_action
# -----------------------------------------------------------------------
# PRIORITY 6: Below Turn-On Threshold
@@ -607,7 +655,11 @@ action:
- conditions:
- condition: template
value_template: "{{ is_value_below_turn_on_threshold }}"
sequence: !input turn_on_action
sequence:
- if:
- condition: template
value_template: "{{ not is_device_on }}"
then: !input turn_on_action
# -------------------------------------------------------------------------
# DEFAULT: Maintain Current State (Hysteresis Zone)

View File

@@ -275,9 +275,14 @@ variables:
# CONDITIONS
# =============================================================================
condition:
# Only process events from the configured vacuum entity
# Only process events from the configured vacuum entity.
# The Dreame Vacuum integration uses generate_entity_id() for the entity_id
# in event data, which may append a numeric suffix (e.g., _2) since the
# actual vacuum entity already occupies the base entity_id.
- condition: template
value_template: "{{ event_entity_id == vacuum_entity }}"
value_template: >
{{ event_entity_id == vacuum_entity
or event_entity_id.startswith(vacuum_entity ~ '_') }}
# =============================================================================
# ACTIONS

View File

@@ -4,8 +4,7 @@ This blueprint monitors Immich album changes and sends notifications when assets
## Features
- Filter by hub/instance name (for multi-hub setups)
- Monitor specific albums by name (whitelist)
- Monitor specific albums by ID (whitelist)
- Filter by asset type (track images only, videos only, or both)
- Filter by favorites only (only notify about favorite assets)
- Sort assets by date, rating, name, or keep original order
@@ -147,6 +146,7 @@ Select input_text entities containing Telegram chat IDs. Can be user IDs (positi
- Large media lists are automatically split into multiple groups (2-10 items per group)
- Optional chat action indicator (typing, uploading photo/video) while processing
- Optional maximum asset size filter to skip large files
- Respects integration quiet hours — notifications are queued and sent when quiet hours end (configurable bypass per blueprint instance)
### Limitations
@@ -159,6 +159,8 @@ Select input_text entities containing Telegram chat IDs. Can be user IDs (positi
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.
Use **Summary Interval** to control how often summaries are sent (default: every day). Set it to `7` for weekly, `14` for bi-weekly, etc. The **Summary Start Date** anchors the interval — summaries are sent on that date and every N days after. For example, setting the start date to a Monday with an interval of 7 sends summaries every Monday.
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.
### Summary Message Template Variables

View File

@@ -19,20 +19,9 @@ blueprint:
# Hub & Album Configuration
# -------------------------------------------------------------------------
albums_group:
name: "Hub & Albums"
name: "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: >
@@ -472,6 +461,23 @@ blueprint:
- label: "Uploading Document..."
value: "upload_document"
telegram_quiet_hours_start:
name: Quiet Hours Start
description: >
Start time for quiet hours. During quiet hours, Telegram notifications
are queued and sent when quiet hours end.
default: "23:00"
selector:
time:
telegram_quiet_hours_end:
name: Quiet Hours End
description: >
End time for quiet hours. Queued notifications are sent after this time.
default: "07:00"
selector:
time:
# -------------------------------------------------------------------------
# Periodic Summary
# -------------------------------------------------------------------------
@@ -489,6 +495,28 @@ blueprint:
selector:
boolean:
periodic_summary_interval:
name: Summary Interval (Days)
description: >
Number of days between periodic summaries.
Set to 1 for daily, 7 for weekly, etc.
default: 1
selector:
number:
min: 1
max: 365
step: 1
mode: box
periodic_summary_start_date:
name: Summary Start Date
description: >
The date from which to start counting the summary interval.
Summaries are sent on this date and every N days after.
default: "2025-01-01"
selector:
date:
periodic_notification_times:
name: Summary Notification Times
description: >
@@ -886,7 +914,7 @@ variables:
# ---------------------------------------------------------------------------
# Input Variables
# ---------------------------------------------------------------------------
hub_names: !input hub_names
album_id_entities: !input album_id_entities
automation_id: !input automation_id
@@ -926,9 +954,13 @@ variables:
telegram_disable_url_preview: !input telegram_disable_url_preview
telegram_chat_action: !input telegram_chat_action
telegram_max_asset_size: !input telegram_max_asset_size
telegram_quiet_hours_start: !input telegram_quiet_hours_start
telegram_quiet_hours_end: !input telegram_quiet_hours_end
# Periodic Summary Settings
enable_periodic_summary: !input enable_periodic_summary
periodic_summary_interval: !input periodic_summary_interval
periodic_summary_start_date: !input periodic_summary_start_date
periodic_summary_message_template: !input periodic_summary_message
periodic_album_template: !input periodic_album_template
periodic_summary_image_url: !input periodic_summary_image_url
@@ -1033,10 +1065,6 @@ variables:
# ---------------------------------------------------------------------------
# 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 }}
@@ -1249,13 +1277,15 @@ variables:
# ---------------------------------------------------------------------------
# Periodic Summary Variables
# ---------------------------------------------------------------------------
# Check if periodic summary should run (at configured times)
# Manual test event (immich_album_watcher_test_periodic_summary) bypasses time check
# Check if periodic summary should run (at configured times and interval)
# Manual test event (immich_album_watcher_test_periodic_summary) bypasses interval check
# If event data contains automation_id, only matching automations respond
should_send_periodic_summary: >
{% if enable_periodic_summary %}
{% if trigger.id == 'periodic_summary_timer' %}
{{ true }}
{% set start = periodic_summary_start_date | as_datetime %}
{% set days_elapsed = (now().date() - start.date()).days %}
{{ days_elapsed >= 0 and days_elapsed % periodic_summary_interval == 0 }}
{% 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 %}
@@ -1384,7 +1414,7 @@ condition:
{% 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 }}
{{ is_album_tracked and should_notify }}
{% endif %}
# =============================================================================
@@ -1426,6 +1456,25 @@ action:
assets: "{{ [{'url': periodic_summary_image_url, 'type': 'photo'}] if periodic_summary_image_url | length > 0 else [] }}"
disable_web_page_preview: "{{ telegram_disable_url_preview }}"
chat_action: "{{ telegram_chat_action }}"
quiet_hours_start: "{{ telegram_quiet_hours_start }}"
quiet_hours_end: "{{ telegram_quiet_hours_end }}"
# Debug: Log text send result
- choose:
- conditions:
- condition: template
value_template: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Immich Album Watcher - Telegram Send Debug"
message: >
**Periodic Summary - Send:**
- Chat ID: {{ repeat.item }}
- Caption: {{ periodic_summary_formatted[:200] }}...
- Has Image: {{ 'Yes' if periodic_summary_image_url | length > 0 else 'No' }}
- Response: {{ telegram_periodic_response }}
# Delay between periodic summary and scheduled assets if both trigger at the same hour
- if:
@@ -1670,6 +1719,24 @@ action:
caption: "{{ scheduled_message }}"
disable_web_page_preview: "{{ telegram_disable_url_preview }}"
chat_action: "{{ telegram_chat_action }}"
quiet_hours_start: "{{ telegram_quiet_hours_start }}"
quiet_hours_end: "{{ telegram_quiet_hours_end }}"
# Debug: Log text send result
- choose:
- conditions:
- condition: template
value_template: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Immich Album Watcher - Telegram Send Debug"
message: >
**Scheduled Per-Album - Text Send:**
- Chat ID: {{ repeat.item }}
- Caption: {{ scheduled_message[:200] }}...
- Response: {{ telegram_scheduled_text_response }}
# Extract message ID for reply
- variables:
@@ -1699,6 +1766,25 @@ action:
max_asset_data_size: "{{ telegram_max_asset_size | int * 1048576 }}"
wait_for_response: false
chat_action: "{{ telegram_chat_action }}"
quiet_hours_start: "{{ telegram_quiet_hours_start }}"
quiet_hours_end: "{{ telegram_quiet_hours_end }}"
# Debug: Log media send result
- choose:
- conditions:
- condition: template
value_template: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Immich Album Watcher - Telegram Send Debug"
message: >
**Scheduled Per-Album - Media Send:**
- Chat ID: {{ repeat.item }}
- Assets: {{ scheduled_media_urls | length }}
- Reply To: {{ scheduled_reply_to_id }}
- Response: {{ telegram_scheduled_media_response }}
# Combined Mode: Fetch from all albums and combine into one notification
# Distributes the limit evenly across albums (e.g., limit=10 with 2 albums = 5 each)
@@ -1930,6 +2016,24 @@ action:
caption: "{{ combined_message }}"
disable_web_page_preview: "{{ telegram_disable_url_preview }}"
chat_action: "{{ telegram_chat_action }}"
quiet_hours_start: "{{ telegram_quiet_hours_start }}"
quiet_hours_end: "{{ telegram_quiet_hours_end }}"
# Debug: Log text send result
- choose:
- conditions:
- condition: template
value_template: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Immich Album Watcher - Telegram Send Debug"
message: >
**Scheduled Combined - Text Send:**
- Chat ID: {{ repeat.item }}
- Caption: {{ combined_message[:200] }}...
- Response: {{ telegram_combined_text_response }}
- variables:
combined_reply_to_id: "{{ telegram_combined_text_response[album_id_entities[0]].message_id | default(0) | int }}"
@@ -1957,6 +2061,25 @@ action:
max_asset_data_size: "{{ telegram_max_asset_size | int * 1048576 }}"
wait_for_response: false
chat_action: "{{ telegram_chat_action }}"
quiet_hours_start: "{{ telegram_quiet_hours_start }}"
quiet_hours_end: "{{ telegram_quiet_hours_end }}"
# Debug: Log media send result
- choose:
- conditions:
- condition: template
value_template: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Immich Album Watcher - Telegram Send Debug"
message: >
**Scheduled Combined - Media Send:**
- Chat ID: {{ repeat.item }}
- Assets: {{ combined_media_urls | length }}
- Reply To: {{ combined_reply_to_id }}
- Response: {{ telegram_combined_media_response }}
# Delay before memory mode if another scheduled notification was sent at the same hour
- if:
@@ -2196,6 +2319,24 @@ action:
caption: "{{ memory_message }}"
disable_web_page_preview: "{{ telegram_disable_url_preview }}"
chat_action: "{{ telegram_chat_action }}"
quiet_hours_start: "{{ telegram_quiet_hours_start }}"
quiet_hours_end: "{{ telegram_quiet_hours_end }}"
# Debug: Log text send result
- choose:
- conditions:
- condition: template
value_template: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Immich Album Watcher - Telegram Send Debug"
message: >
**Memory Per-Album - Text Send:**
- Chat ID: {{ repeat.item }}
- Caption: {{ memory_message[:200] }}...
- Response: {{ telegram_memory_text_response }}
# Extract message ID for reply
- variables:
@@ -2225,6 +2366,25 @@ action:
max_asset_data_size: "{{ telegram_max_asset_size | int * 1048576 }}"
wait_for_response: false
chat_action: "{{ telegram_chat_action }}"
quiet_hours_start: "{{ telegram_quiet_hours_start }}"
quiet_hours_end: "{{ telegram_quiet_hours_end }}"
# Debug: Log media send result
- choose:
- conditions:
- condition: template
value_template: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Immich Album Watcher - Telegram Send Debug"
message: >
**Memory Per-Album - Media Send:**
- Chat ID: {{ repeat.item }}
- Assets: {{ memory_media_urls | length }}
- Reply To: {{ memory_reply_to_id }}
- Response: {{ telegram_memory_media_response }}
# Combined Mode: Fetch from all albums and combine into one notification
- conditions:
@@ -2446,6 +2606,24 @@ action:
caption: "{{ memory_comb_message }}"
disable_web_page_preview: "{{ telegram_disable_url_preview }}"
chat_action: "{{ telegram_chat_action }}"
quiet_hours_start: "{{ telegram_quiet_hours_start }}"
quiet_hours_end: "{{ telegram_quiet_hours_end }}"
# Debug: Log text send result
- choose:
- conditions:
- condition: template
value_template: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Immich Album Watcher - Telegram Send Debug"
message: >
**Memory Combined - Text Send:**
- Chat ID: {{ repeat.item }}
- Caption: {{ memory_comb_message[:200] }}...
- Response: {{ telegram_memory_comb_text_response }}
- variables:
memory_comb_reply_to_id: "{{ telegram_memory_comb_text_response[album_id_entities[0]].message_id | default(0) | int }}"
@@ -2473,6 +2651,25 @@ action:
max_asset_data_size: "{{ telegram_max_asset_size | int * 1048576 }}"
wait_for_response: false
chat_action: "{{ telegram_chat_action }}"
quiet_hours_start: "{{ telegram_quiet_hours_start }}"
quiet_hours_end: "{{ telegram_quiet_hours_end }}"
# Debug: Log media send result
- choose:
- conditions:
- condition: template
value_template: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Immich Album Watcher - Telegram Send Debug"
message: >
**Memory Combined - Media Send:**
- Chat ID: {{ repeat.item }}
- Assets: {{ memory_comb_media_urls | length }}
- Reply To: {{ memory_comb_reply_to_id }}
- Response: {{ telegram_memory_comb_media_response }}
# Stop here if this was a scheduled trigger - don't continue to event-based actions
- choose:
@@ -2512,7 +2709,6 @@ action:
- {{ event_people | join(', ') if event_people | length > 0 else '(none)' }}
**Filtering:**
- Is Hub Tracked: {{ is_hub_tracked }}
- Is Album Tracked: {{ is_album_tracked }}
- Should Notify: {{ should_notify }}
- Track Images: {{ track_images }}
@@ -2676,6 +2872,24 @@ action:
caption: "{{ message }}"
disable_web_page_preview: "{{ telegram_disable_url_preview }}"
chat_action: "{{ telegram_chat_action }}"
quiet_hours_start: "{{ telegram_quiet_hours_start }}"
quiet_hours_end: "{{ telegram_quiet_hours_end }}"
# Debug: Log text send result
- choose:
- conditions:
- condition: template
value_template: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Immich Album Watcher - Telegram Send Debug"
message: >
**Album Renamed - Text Send:**
- Chat ID: {{ repeat.item }}
- Caption: {{ message[:200] }}...
- Response: {{ telegram_renamed_response }}
# ---------------------------------------------------------------------
# CASE 5: Album Deleted
@@ -2713,6 +2927,24 @@ action:
caption: "{{ message }}"
disable_web_page_preview: "{{ telegram_disable_url_preview }}"
chat_action: "{{ telegram_chat_action }}"
quiet_hours_start: "{{ telegram_quiet_hours_start }}"
quiet_hours_end: "{{ telegram_quiet_hours_end }}"
# Debug: Log text send result
- choose:
- conditions:
- condition: template
value_template: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Immich Album Watcher - Telegram Send Debug"
message: >
**Album Deleted - Text Send:**
- Chat ID: {{ repeat.item }}
- Caption: {{ message[:200] }}...
- Response: {{ telegram_deleted_response }}
# ---------------------------------------------------------------------------
# Send Media to Telegram (if enabled)
@@ -2839,6 +3071,24 @@ action:
caption: "{{ telegram_message }}"
disable_web_page_preview: "{{ telegram_disable_url_preview }}"
chat_action: "{{ telegram_chat_action }}"
quiet_hours_start: "{{ telegram_quiet_hours_start }}"
quiet_hours_end: "{{ telegram_quiet_hours_end }}"
# Debug: Log text send result
- choose:
- conditions:
- condition: template
value_template: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Immich Album Watcher - Telegram Send Debug"
message: >
**Assets Added - Text Send:**
- Chat ID: {{ current_chat_id }}
- Caption: {{ telegram_message[:200] }}...
- Response: {{ telegram_text_response }}
# Extract message ID for replies
- variables:
@@ -2881,3 +3131,23 @@ action:
max_asset_data_size: "{{ telegram_max_asset_size | int * 1048576 }}"
wait_for_response: false
chat_action: "{{ telegram_chat_action }}"
quiet_hours_start: "{{ telegram_quiet_hours_start }}"
quiet_hours_end: "{{ telegram_quiet_hours_end }}"
# Debug: Log media send result
- choose:
- conditions:
- condition: template
value_template: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Immich Album Watcher - Telegram Send Debug"
message: >
**Assets Added - Media Send:**
- Chat ID: {{ current_chat_id }}
- Assets: {{ media_urls | length }}
- Reply To: {{ reply_to_message_id }}
- Max Group Size: {{ max_media_per_group }}
- Response: {{ telegram_media_response }}

View File

@@ -101,6 +101,19 @@ blueprint:
max: 255
mode: slider
min_brightness:
name: Minimum Brightness
description: >
Minimum brightness for all lights (1255). If the sensor or
override brightness is below this value, this minimum is used
instead. Prevents lights from becoming too dim to see.
default: 5
selector:
number:
min: 1
max: 255
mode: slider
none_action:
name: When Sensor is Unavailable
description: "Action to take when a sensor state is None, unknown, or unavailable."
@@ -189,6 +202,7 @@ variables:
lights: !input lights
max_fps: !input max_fps
brightness_override: !input brightness_override
min_brightness: !input min_brightness
none_action: !input none_action
default_color: !input default_color
enable_debug_notifications: !input enable_debug_notifications
@@ -222,6 +236,7 @@ action:
**Pairs:** {{ pair_count }}
**FPS:** {{ max_fps }}
**Brightness Override:** {{ brightness_override }}
**Min Brightness:** {{ min_brightness }}
**Sensor States:**
{% for i in range(pair_count | int) %}
@@ -286,7 +301,7 @@ action:
entity_id: "{{ current_light }}"
data:
rgb_color: "{{ default_color }}"
brightness: "{{ brightness_override | int if brightness_override | int > 0 else 255 }}"
brightness: "{{ [brightness_override | int if brightness_override | int > 0 else 255, min_brightness | int] | max }}"
# keep_last — do nothing
@@ -295,7 +310,7 @@ action:
- variables:
sensor_rgb: "{{ state_attr(current_sensor, 'rgb_color') | default([255, 255, 255]) }}"
sensor_brightness: "{{ state_attr(current_sensor, 'brightness') | default(255) }}"
target_brightness: "{{ brightness_override | int if brightness_override | int > 0 else sensor_brightness | int }}"
target_brightness: "{{ [brightness_override | int if brightness_override | int > 0 else sensor_brightness | int, min_brightness | int] | max }}"
- service: light.turn_on
target:

View File

@@ -141,7 +141,7 @@ blueprint:
description: >
Delay before turning off the light after all motion sensors
clear. Set to 0 for immediate turn off.
default: 120
default: 0
selector:
number:
min: 0
@@ -393,7 +393,7 @@ blueprint:
Some devices (especially Zigbee) report delayed state updates
that can be mistaken for manual control. Increase this value
if you see false manual overrides in the debug log.
default: 10
default: 2
selector:
number:
min: 0
@@ -527,12 +527,6 @@ condition: !input user_condition
# =============================================================================
variables:
# ---------------------------------------------------------------------------
# Debug Flags
# ---------------------------------------------------------------------------
is_debug: false # Detailed debug for specific actions
is_base_debug: false # Basic debug info at start
# ---------------------------------------------------------------------------
# State Machine Constants
# ---------------------------------------------------------------------------
@@ -826,7 +820,7 @@ variables:
# Should we disable the light? (Motion cleared OR condition switch turned off)
must_be_disabled_preview: >
{{ ((not all_of_condition_switches_on) or motion_all_off) | bool }}
must_be_disabled_guard: "{{ state_is_enabled }}"
must_be_disabled_guard: "{{ state_is_enabled or state_is_enabling }}"
must_be_disabled: >
{{ must_be_disabled_preview and must_be_disabled_guard }}
@@ -836,22 +830,61 @@ variables:
action:
# ---------------------------------------------------------------------------
# DEBUG: Log basic info (enable by setting is_base_debug: true)
# DEBUG: Log entry state on every trigger (helps trace mode: restart issues)
# ---------------------------------------------------------------------------
- choose:
- conditions:
- condition: template
value_template: "{{ is_base_debug }}"
- conditions: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Debug Info - Motion Light"
title: "Motion Light Debug - ENTRY"
message: >
must_be_enabled_preview: {{ must_be_enabled_preview }},
must_be_disabled_preview: {{ must_be_disabled_preview }},
must_be_disabled: {{ must_be_disabled }},
must_be_disabled_guard: {{ must_be_disabled_guard }},
trigger_id: {{ trigger.id }}
=== Automation Triggered ===
Time: {{ now().strftime('%H:%M:%S.%f')[:12] }}
Trigger ID: {{ trigger_id }}
Trigger Entity: {{ trigger.entity_id | default('N/A') }}
Trigger From: {{ trigger.from_state.state | default('N/A') }}
Trigger To: {{ trigger.to_state.state | default('N/A') }}
=== State Machine ===
State: {{ motion_light_state }} (NONE=0, ENABLED=1, ENABLING=2, MANUAL=3)
state_is_none: {{ state_is_none }}
state_is_enabling: {{ state_is_enabling }}
state_is_enabled: {{ state_is_enabled }}
state_is_manual: {{ state_is_manual }}
=== Decision Variables ===
motion_on: {{ motion_on }} ({{ count_of_enabled_sensor }} sensors)
all_of_condition_switches_on: {{ all_of_condition_switches_on }}
luminance_ok: {{ luminance_ok }}
time_condition_ok: {{ time_condition_ok }}
any_device_on: {{ any_device_on }}
=== Enable/Disable Logic ===
must_be_enabled_preview: {{ must_be_enabled_preview }}
must_be_enabled_guard: {{ must_be_enabled_guard }}
must_be_enabled: {{ must_be_enabled }}
must_be_disabled_preview: {{ must_be_disabled_preview }}
must_be_disabled_guard: {{ must_be_disabled_guard }}
must_be_disabled: {{ must_be_disabled }}
=== Which CASE will match ===
CASE 1 (state changed): {{ trigger_id == 'light_state_changed' or trigger_id == 'switch_state_changed' }}
CASE 2 (enable): {{ must_be_enabled }}
CASE 3 (disable): {{ must_be_disabled }}
=== Grace Period ===
{%- set last_ts = automation_state.get(state_motion_light_last_action_timestamp, none) -%}
{%- set grace = (transition_duration | float(0)) + (manual_override_grace_period | float(2)) -%}
last_action_ts: {{ last_ts | default('not set') }}
grace_period: {{ grace }}s
{%- if last_ts is not none -%}
{%- set parsed = last_ts | as_datetime -%}
{%- if parsed is not none %}
time_since_action: {{ (now() - parsed).total_seconds() | round(2) }}s
grace_expired: {{ (now() - parsed).total_seconds() > grace }}
{%- endif -%}
{%- endif %}
# ===========================================================================
# MAIN STATE MACHINE
@@ -867,6 +900,26 @@ action:
- condition: template
value_template: "{{ trigger_id == 'light_state_changed' or trigger_id == 'switch_state_changed' }}"
sequence:
# Debug: log which CASE 1 sub-case will fire
- choose:
- conditions: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Motion Light Debug - CASE 1"
message: >
CASE 1: light/switch state changed
Time: {{ now().strftime('%H:%M:%S.%f')[:12] }}
Trigger: {{ trigger_id }}
Entity: {{ trigger.entity_id | default('N/A') }}
From: {{ trigger.from_state.state | default('N/A') }} → To: {{ trigger.to_state.state | default('N/A') }}
Meaningful change: {{ trigger.from_state.state != trigger.to_state.state }}
Light brightness: {{ state_attr(reference_light, 'brightness') | default('N/A') }}
State: {{ motion_light_state }}
state_is_enabling: {{ state_is_enabling }}
state_is_enabled: {{ state_is_enabled }}
must_be_disabled_preview: {{ must_be_disabled_preview }}
- choose:
# ----- Sub-case: Light/Switch turned OFF -----
@@ -874,12 +927,13 @@ action:
- conditions:
- condition: template
value_template: >
{# BUG FIX: Changed from 'res = false' to 'res = true' for AND logic #}
{# Check actual on/off state only — do NOT use brightness_threshold here.
Brightness threshold is for the enable guard (any_device_on), not for
detecting whether the light was actually turned off. During transitions,
brightness may temporarily be below threshold while the light is still on. #}
{% set res = true %}
{% if light_entity is not none %}
{% set brightness = state_attr(light_entity, 'brightness') | int(0) %}
{% set light_off = is_state(light_entity, 'off') or brightness < brightness_threshold %}
{% set res = res and light_off %}
{% set res = res and is_state(light_entity, 'off') %}
{% endif %}
{% if switch_entity is not none %}
{% set res = res and is_state(switch_entity, 'off') %}
@@ -897,12 +951,206 @@ action:
{% set new_automation_state = (automation_state | combine({ state_motion_light_state: automation_state_none })) %}
{{ automation_state_global | combine({ automation_state_key: new_automation_state }) | tojson }}
# Re-evaluate: if an external source turned off the light while
# the automation was actively controlling it, wait briefly and
# re-enable if conditions are still met.
# Safety: state_is_enabled/state_is_enabling reflect the state at
# run start (before reset). When CASE 3 turns off the light, it
# sets state to NONE first, so on restart state_is_none=true and
# this block is skipped — preventing unwanted re-enable.
- choose:
- conditions:
- condition: template
value_template: "{{ state_is_enabled or state_is_enabling }}"
sequence:
# Wait for the off-transition to finish
- delay:
seconds: "{{ transition_duration }}"
# Fresh condition check (evaluates current entity states)
- condition: template
value_template: >
{% set e = sensors if sensors is iterable else [sensors] %}
{% set motion_active = e | select('is_state', 'on') | list | length > 0 %}
{% set cond_ok = true %}
{% set cs = condition_switches if condition_switches is iterable else [condition_switches] %}
{% if cs | length > 0 %}
{% set cond_ok = (cs | select('is_state', 'on') | list | length) == (cs | length) %}
{% endif %}
{{ motion_active and cond_ok }}
# Re-read state from input_text (may have changed during delay)
- variables:
re_eval_state_global: >
{% set text = states(automation_state_entity) | string %}
{% if text in ['unknown','unavailable','none',''] %}
{{ dict() }}
{% else %}
{{ text | from_json }}
{% endif %}
re_eval_state: "{{ re_eval_state_global.get(automation_state_key, dict()) }}"
re_eval_motion_light_state: "{{ re_eval_state.get(state_motion_light_state, automation_state_none) }}"
# Only proceed if state is still NONE (no other run claimed it)
- condition: template
value_template: "{{ (re_eval_motion_light_state | string) == automation_state_none }}"
# --- Re-enable path (mirrors CASE 2) ---
# Set state to ENABLING before turning on
- service: input_text.set_value
target:
entity_id: "{{ automation_state_entity }}"
data:
value: >
{% set new_automation_state = (re_eval_state | combine({
state_motion_light_state: automation_state_enabling,
state_motion_light_last_action_timestamp: now(),
state_motion_light_last_brightness: 0
})) %}
{{ re_eval_state_global | combine({ automation_state_key: new_automation_state }) | tojson }}
# Scene or light activation
- choose:
- conditions:
- condition: template
value_template: "{{ use_scene_instead and effective_scene is not none }}"
sequence:
- service: scene.turn_on
target:
entity_id: "{{ effective_scene }}"
data:
transition: "{{ transition_duration }}"
default:
# Turn ON lights
- choose:
- conditions:
- condition: template
value_template: "{{ resolved_all_lights | length > 0 }}"
sequence:
- service: light.turn_on
target:
entity_id: "{{ resolved_all_lights }}"
data: >
{% set d = effective_light_data if effective_light_data else {} %}
{% if transition_duration > 0 %}
{% set d = d | combine({'transition': transition_duration}) %}
{% endif %}
{{ d }}
# Turn ON switches
- choose:
- conditions:
- condition: template
value_template: "{{ resolved_all_switches | length > 0 }}"
sequence:
- service: switch.turn_on
target:
entity_id: "{{ resolved_all_switches }}"
# Execute enable callback
- choose:
- conditions:
- condition: template
value_template: "{{ enable_action != [] }}"
sequence: !input enable_action
# Debug notification
- choose:
- conditions: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Motion Light Debug"
message: >
Action: RE-ENABLE (external turn-off recovery)
Time: {{ now().strftime('%H:%M:%S') }}
Lights: {{ resolved_all_lights }}
Switches: {{ resolved_all_switches }}
Scene: {{ effective_scene if use_scene_instead else 'N/A' }}
# ----- Sub-case: Automation just turned on the light -----
# Transition from ENABLING to ENABLED
# Transition from ENABLING to ENABLED, or disable immediately
# if motion already cleared during the ENABLING phase
- conditions:
- condition: template
value_template: "{{ state_is_enabling }}"
sequence:
- choose:
# If disable conditions are already met (motion cleared
# while light was still in ENABLING state), skip ENABLED
# and go straight to disable
- conditions:
- condition: template
value_template: "{{ must_be_disabled_preview }}"
sequence:
# Reset state to NONE
- service: input_text.set_value
target:
entity_id: "{{ automation_state_entity }}"
data:
value: >
{% set new_automation_state = (automation_state | combine({ state_motion_light_state: automation_state_none })) %}
{{ automation_state_global | combine({ automation_state_key: new_automation_state }) | tojson }}
# Turn OFF or restore lights
- choose:
- conditions:
- condition: template
value_template: "{{ resolved_all_lights | length > 0 }}"
sequence:
- variables:
last_brightness: "{{ automation_state.get(state_motion_light_last_brightness, 0) | int }}"
- choose:
- conditions:
- condition: template
value_template: "{{ last_brightness > 0 }}"
sequence:
- service: light.turn_on
target:
entity_id: "{{ resolved_all_lights }}"
data:
brightness: "{{ last_brightness }}"
transition: "{{ transition_duration }}"
default:
- service: light.turn_off
target:
entity_id: "{{ resolved_all_lights }}"
data:
transition: "{{ transition_duration }}"
# Turn OFF switches
- choose:
- conditions:
- condition: template
value_template: "{{ resolved_all_switches | length > 0 }}"
sequence:
- service: switch.turn_off
target:
entity_id: "{{ resolved_all_switches }}"
# Execute disable callback
- choose:
- conditions:
- condition: template
value_template: "{{ disable_action != [] }}"
sequence: !input disable_action
# Debug notification
- choose:
- conditions: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Motion Light Debug"
message: >
Action: DISABLE (enabling interrupted)
Time: {{ now().strftime('%H:%M:%S') }}
Trigger: {{ trigger_id }}
# Normal case: motion still active, transition to ENABLED
default:
- service: input_text.set_value
target:
entity_id: "{{ automation_state_entity }}"
@@ -913,20 +1161,27 @@ action:
# ----- Sub-case: User manually changed the light -----
# Transition from ENABLED to MANUAL (user took control)
# Only triggers on meaningful state changes (on→off or off→on),
# NOT on attribute-only updates (on→on) which Zigbee devices
# commonly send as the light settles after a transition.
# Grace period: ignore state changes shortly after the automation
# turns on the light to avoid false manual override detection.
# Some devices (especially Zigbee) report delayed state updates.
- conditions:
- condition: template
value_template: >
{% set meaningful_change = trigger.from_state.state != trigger.to_state.state %}
{% if not meaningful_change %}
{{ false }}
{% else %}
{% set last_ts = automation_state.get(state_motion_light_last_action_timestamp, none) %}
{% set grace = (transition_duration | float(0)) + (manual_override_grace_period | float(10)) %}
{% set grace = (transition_duration | float(0)) + (manual_override_grace_period | float(2)) %}
{% if state_is_enabled and last_ts is not none %}
{% set parsed = last_ts | as_datetime %}
{{ parsed is none or (now() - parsed).total_seconds() > grace }}
{% else %}
{{ state_is_enabled }}
{% endif %}
{% endif %}
sequence:
# BUG FIX: Fixed YAML structure - was 'data: >' instead of 'data:' with 'value: >'
- service: input_text.set_value
@@ -961,6 +1216,81 @@ action:
New State: MANUAL
Trigger: {{ trigger_id }}
# ----- Default: No sub-case matched -----
# This handles the case where a light_state_changed trigger fires
# during the grace period (e.g., Zigbee delayed state reports) while
# the disable path was already in progress but got cancelled by
# mode: restart. If disable conditions are met, turn off directly.
default:
- choose:
- conditions:
- condition: template
value_template: "{{ (state_is_enabled or state_is_enabling) and must_be_disabled_preview }}"
sequence:
# Reset state to NONE first (before turn-off triggers another restart)
- service: input_text.set_value
target:
entity_id: "{{ automation_state_entity }}"
data:
value: >
{% set new_automation_state = (automation_state | combine({ state_motion_light_state: automation_state_none })) %}
{{ automation_state_global | combine({ automation_state_key: new_automation_state }) | tojson }}
# Turn OFF or restore lights
- choose:
- conditions:
- condition: template
value_template: "{{ resolved_all_lights | length > 0 }}"
sequence:
- variables:
last_brightness: "{{ automation_state.get(state_motion_light_last_brightness, 0) | int }}"
- choose:
- conditions:
- condition: template
value_template: "{{ last_brightness > 0 }}"
sequence:
- service: light.turn_on
target:
entity_id: "{{ resolved_all_lights }}"
data:
brightness: "{{ last_brightness }}"
transition: "{{ transition_duration }}"
default:
- service: light.turn_off
target:
entity_id: "{{ resolved_all_lights }}"
data:
transition: "{{ transition_duration }}"
# Turn OFF switches
- choose:
- conditions:
- condition: template
value_template: "{{ resolved_all_switches | length > 0 }}"
sequence:
- service: switch.turn_off
target:
entity_id: "{{ resolved_all_switches }}"
# Execute disable callback
- choose:
- conditions:
- condition: template
value_template: "{{ disable_action != [] }}"
sequence: !input disable_action
# Debug notification
- choose:
- conditions: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Motion Light Debug"
message: >
Action: DISABLE (restart recovery)
Time: {{ now().strftime('%H:%M:%S') }}
Trigger: {{ trigger_id }}
# -----------------------------------------------------------------------
# CASE 2: Enable Path (Motion Detected, Should Turn On)
# -----------------------------------------------------------------------
@@ -988,6 +1318,21 @@ action:
{{ state_attr(reference_light, 'brightness') | int(0) }}
{% endif %}
# Update state to ENABLING BEFORE turning on the light.
# This must happen first because mode: restart may cancel
# subsequent steps if the light state change fires immediately.
- service: input_text.set_value
target:
entity_id: "{{ automation_state_entity }}"
data:
value: >
{% set new_automation_state = (automation_state | combine({
state_motion_light_state: automation_state_enabling,
state_motion_light_last_action_timestamp: date_time_now,
state_motion_light_last_brightness: last_brightness
})) %}
{{ automation_state_global | combine({ automation_state_key: new_automation_state }) | tojson }}
# Scene activation path
- choose:
- conditions:
@@ -1028,19 +1373,6 @@ action:
target:
entity_id: "{{ resolved_all_switches }}"
# Update state to ENABLING (waiting for light state change confirmation)
- service: input_text.set_value
target:
entity_id: "{{ automation_state_entity }}"
data:
value: >
{% set new_automation_state = (automation_state | combine({
state_motion_light_state: automation_state_enabling,
state_motion_light_last_action_timestamp: date_time_now,
state_motion_light_last_brightness: last_brightness
})) %}
{{ automation_state_global | combine({ automation_state_key: new_automation_state }) | tojson }}
# Execute enable callback action
- choose:
- conditions:
@@ -1114,15 +1446,49 @@ action:
- delay:
seconds: "{{ dim_duration }}"
# Read last_brightness before resetting state
- variables:
last_brightness: "{{ automation_state.get(state_motion_light_last_brightness, 0) | int }}"
# Update state to NONE BEFORE turning off the light.
# This must happen first because mode: restart may cancel
# subsequent steps if the light state change fires during
# turn_off transition, which could falsely trigger manual override.
- service: input_text.set_value
target:
entity_id: "{{ automation_state_entity }}"
data:
value: >
{% set new_automation_state = (automation_state | combine({ state_motion_light_state: automation_state_none })) %}
{{ automation_state_global | combine({ automation_state_key: new_automation_state }) | tojson }}
# Execute disable callback action (before turn-off to avoid restart cancellation)
- choose:
- conditions:
- condition: template
value_template: "{{ disable_action != [] }}"
sequence: !input disable_action
# Debug notification (before turn-off to avoid restart cancellation)
- choose:
- conditions: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Motion Light Debug"
message: >
Action: DISABLE
Time: {{ now().strftime('%H:%M:%S') }}
Timeout: {{ timeout }}s
Min On Duration: {{ min_on_duration }}s
Dim Before Off: {{ enable_dim_before_off }}
# Turn OFF or restore the lights
- choose:
- conditions:
- condition: template
value_template: "{{ resolved_all_lights | length > 0 }}"
sequence:
- variables:
last_brightness: "{{ automation_state.get(state_motion_light_last_brightness, 0) | int }}"
- choose:
# Restore previous brightness if it was set
- conditions:
@@ -1153,33 +1519,3 @@ action:
- service: switch.turn_off
target:
entity_id: "{{ resolved_all_switches }}"
# Update state to NONE (ready for next motion event)
- service: input_text.set_value
target:
entity_id: "{{ automation_state_entity }}"
data:
value: >
{% set new_automation_state = (automation_state | combine({ state_motion_light_state: automation_state_none })) %}
{{ automation_state_global | combine({ automation_state_key: new_automation_state }) | tojson }}
# Execute disable callback action
- choose:
- conditions:
- condition: template
value_template: "{{ disable_action != [] }}"
sequence: !input disable_action
# Debug notification
- choose:
- conditions: "{{ enable_debug_notifications }}"
sequence:
- service: persistent_notification.create
data:
title: "Motion Light Debug"
message: >
Action: DISABLE
Time: {{ now().strftime('%H:%M:%S') }}
Timeout: {{ timeout }}s
Min On Duration: {{ min_on_duration }}s
Dim Before Off: {{ enable_dim_before_off }}

View File

@@ -1,3 +1,3 @@
{
"version": "2.2.3"
"version": "2.5.2"
}