# Multi-Sensor Alarm & Notification Blueprint # Monitors sensors and triggers notifications and alarm actions when activated. # See README.md for detailed documentation. blueprint: name: "Custom: Multi-Sensor Alarm & Notification" description: > Triggers notifications and alarm actions when any of the configured binary sensors change to "on". Supports per-sensor notification texts, optional alarm switch, melody and volume selectors. domain: automation input: # ------------------------------------------------------------------------- # Sensor Configuration # ------------------------------------------------------------------------- devices: name: "Devices" collapsed: false input: binary_sensors: name: Binary Sensors description: List of binary sensors or input booleans to monitor for alarm triggers selector: entity: domain: - binary_sensor - input_boolean multiple: true binary_sensors_debounce_duration: name: Sensor Debounce Duration description: > Minimum time a sensor must stay ON before triggering an alarm. Helps prevent false alarms from brief or spurious sensor activations. default: 5 selector: number: min: 0 max: 30 unit_of_measurement: seconds # ------------------------------------------------------------------------- # Notification Configuration # ------------------------------------------------------------------------- notification: name: "Notification" collapsed: false input: notify_target: name: Notification Target (optional) description: > Notify entity to send notifications (e.g., notify.mobile_app_phone). Leave empty to disable notifications. default: selector: entity: domain: notify notify_texts: name: Notification Messages description: > Custom message for each sensor (one per line, in same order as sensor list). If a sensor doesn't have a corresponding message, a default will be used. default: [] selector: text: multiple: true # ------------------------------------------------------------------------- # Alarm Device Configuration # ------------------------------------------------------------------------- alarm_group: name: "Alarm" collapsed: false input: alarm_switch: name: Alarm Switch (optional) description: Switch entity to control the alarm device. Leave empty to disable alarm control. default: [] selector: entity: domain: switch multiple: false melody_select: name: Melody Selector (optional) description: Select entity for choosing alarm melody/ringtone default: [] selector: entity: domain: - input_select - select multiple: false melody_id: name: Melody Value description: The melody/ringtone option to select when alarm triggers default: "" selector: text: volume_select: name: Volume Selector (optional) description: Select entity for choosing alarm volume level default: [] selector: entity: domain: - input_select - select multiple: false volume_id: name: Volume Value description: The volume level option to select when alarm triggers default: "" selector: text: # ------------------------------------------------------------------------- # Debug Configuration # ------------------------------------------------------------------------- debug_group: name: "Debug" collapsed: true input: debug_enabled: name: Enable Debug Logging description: > When enabled, creates persistent notifications at each stage of execution: trigger received, notification attempt, notification result, alarm control. Use to troubleshoot why notifications aren't reaching the target. default: false selector: boolean: # Restart mode ensures rapid sensor changes are handled cleanly mode: restart # ============================================================================= # Triggers # ============================================================================= trigger: # Sensor turned ON and stayed on for the debounce duration - platform: state entity_id: !input binary_sensors to: "on" for: seconds: !input binary_sensors_debounce_duration id: "sensor_on" # Sensor turned OFF (for turning off alarm when all clear) - platform: state entity_id: !input binary_sensors to: "off" id: "sensor_off" # ============================================================================= # Variables # ============================================================================= variables: # Input references binary_sensors: !input binary_sensors notify_target: !input notify_target notify_texts: !input notify_texts alarm_switch: !input alarm_switch melody_select: !input melody_select melody_id: !input melody_id volume_select: !input volume_select volume_id: !input volume_id is_debug: !input debug_enabled # Computed state values enabled_sensors: "{{ binary_sensors | select('is_state', 'on') | list }}" is_any_sensor_on: "{{ (binary_sensors | select('is_state', 'on') | list | length) > 0 }}" # Whether a usable notify target is configured has_notify_target: "{{ notify_target is not none and (notify_target | string | trim) not in ['', '[]', 'None'] }}" # Whether alarm control is configured has_alarm_switch: "{{ alarm_switch is not none and (alarm_switch | string | trim) not in ['', '[]', 'None'] }}" # Small delay between setting melody/volume to ensure device processes each command delay_between_commands_ms: 100 # Version stamp so debug output can confirm which blueprint revision is live. # Bump this whenever debug/flow logic changes. blueprint_version: "2.6.4 (notify.send_message + entity_id)" # ============================================================================= # Actions # ============================================================================= action: # --------------------------------------------------------------------------- # Debug Stage 1: Trigger Received # --------------------------------------------------------------------------- - choose: - conditions: - condition: template value_template: "{{ is_debug }}" sequence: - service: persistent_notification.create data: notification_id: "alarm_debug_trigger" title: "Alarm Debug [1/4]: Trigger Received" message: > Blueprint version: {{ blueprint_version }} Trigger ID: {{ trigger.id }} Entity: {{ trigger.entity_id }} From: {{ trigger.from_state.state if trigger.from_state is not none else 'n/a' }} → To: {{ trigger.to_state.state if trigger.to_state is not none else 'n/a' }} All monitored sensors: {{ binary_sensors }} Currently active (on): {{ enabled_sensors }} Any sensor on: {{ is_any_sensor_on }} Notify target: {{ notify_target }} Has notify target: {{ has_notify_target }} Alarm switch: {{ alarm_switch }} Has alarm switch: {{ has_alarm_switch }} - service: system_log.write data: level: info logger: blueprint.alarm_notification message: >- Trigger '{{ trigger.id }}' from {{ trigger.entity_id }}; active={{ enabled_sensors }}; notify_target={{ notify_target }}; has_notify_target={{ has_notify_target }} # --------------------------------------------------------------------------- # Debug Stage 1.5: What the notification-branch conditions evaluate to # --------------------------------------------------------------------------- - choose: - conditions: - condition: template value_template: "{{ is_debug }}" sequence: - service: persistent_notification.create data: notification_id: "alarm_debug_pre_notify" title: "Alarm Debug [1.5/4]: Evaluating notify conditions" message: > trigger.id = {{ trigger.id }} trigger.id == 'sensor_on': {{ trigger.id == 'sensor_on' }} has_notify_target: {{ has_notify_target }} Combined (should be True to enter notify branch): {{ trigger.id == 'sensor_on' and has_notify_target }} # --------------------------------------------------------------------------- # Send Notification (only on sensor_on, when target configured) # --------------------------------------------------------------------------- - choose: - conditions: # Single template condition avoids any quirks with condition: trigger # inside a choose block. - condition: template value_template: "{{ trigger.id == 'sensor_on' and has_notify_target }}" sequence: - variables: # The sensor that fired this trigger sensor: "{{ trigger.entity_id }}" # Namespace-loop avoids Jinja sandbox restrictions on list.index() sensor_index: >- {%- set ns = namespace(idx=-1) -%} {%- for s in binary_sensors -%} {%- if s == sensor -%}{%- set ns.idx = loop.index0 -%}{%- endif -%} {%- endfor -%} {{ ns.idx }} # Resolve message (strip whitespace to keep notifications clean) message: >- {%- set messages = notify_texts | list -%} {%- set idx = sensor_index | int(-1) -%} {%- if idx >= 0 and idx < messages | length -%} {{ messages[idx] }} {%- else -%} Alarm: {{ state_attr(sensor, 'friendly_name') or sensor }} triggered {%- endif -%} # Debug Stage 2: Variables computed, about to send - choose: - conditions: - condition: template value_template: "{{ is_debug }}" sequence: - service: persistent_notification.create data: notification_id: "alarm_debug_notify_attempt" title: "Alarm Debug [2/4]: Sending Notification" message: > Target: {{ notify_target }} Sensor: {{ sensor }} Sensor index (raw): "{{ sensor_index }}" Messages defined: {{ notify_texts | length }} Resolved message: "{{ message }}" # Debug Stage 2.25: About to invoke service - choose: - conditions: - condition: template value_template: "{{ is_debug }}" sequence: - service: persistent_notification.create data: notification_id: "alarm_debug_pre_service" title: "Alarm Debug [2.25/4]: Before notify.send_message" message: > Blueprint version: {{ blueprint_version }} About to call: action notify.send_message with target.entity_id: {{ notify_target }} and data.message: "{{ message }}" # Send via notify.send_message targeting the notify entity. # This matches the canonical HA pattern used by working automations. # continue_on_error ensures the alarm-control stage still runs # if the notify integration is misconfigured. - action: notify.send_message metadata: {} target: entity_id: "{{ notify_target }}" data: message: "{{ message }}" continue_on_error: true # Debug Stage 2.75: Service call returned (success or caught error) - choose: - conditions: - condition: template value_template: "{{ is_debug }}" sequence: - service: persistent_notification.create data: notification_id: "alarm_debug_post_service" title: "Alarm Debug [2.75/4]: After notify.send_message" message: > notify.send_message to {{ notify_target }} returned (either success or continue_on_error caught it). If this notification is missing but [2.25/4] is present, the call raised an error that continue_on_error did NOT catch. Check the HA log and verify {{ notify_target }} is a notify entity (Developer Tools → States should list it). # Debug Stage 3: Notification result - choose: - conditions: - condition: template value_template: "{{ is_debug }}" sequence: - service: persistent_notification.create data: notification_id: "alarm_debug_notify_result" title: "Alarm Debug [3/4]: Notification Sent" message: > notify.send_message dispatched to {{ notify_target }} with message: "{{ message }}". If nothing arrived on the device, check: 1) HA log for errors from the notify integration 2) That the underlying integration (Telegram bot, mobile app, etc.) is online 3) Test from Developer Tools → Actions: notify.send_message with target {{ notify_target }} - service: system_log.write data: level: info logger: blueprint.alarm_notification message: >- Notification attempted to {{ notify_target }}; sensor={{ sensor }}; message='{{ message }}' # --------------------------------------------------------------------------- # Debug Stage 3.5: Unconditional checkpoint so we can tell whether the # notification branch silently aborted the script above. If this appears # but [2/4] or [3/4] don't, the variables block or notify.send_message # errored silently. # --------------------------------------------------------------------------- - choose: - conditions: - condition: template value_template: "{{ is_debug }}" sequence: - service: persistent_notification.create data: notification_id: "alarm_debug_after_notify" title: "Alarm Debug [3.5/4]: After notify branch" message: > Execution reached this point. trigger.id = {{ trigger.id }}. If [2/4] and [3/4] did NOT appear above, the notify branch either did not enter (check [1.5/4]), or errored silently in the variables / notify.send_message step. Check Home Assistant log for Jinja or service errors. # --------------------------------------------------------------------------- # Alarm Device Control # --------------------------------------------------------------------------- - choose: - conditions: - condition: template value_template: "{{ has_alarm_switch }}" sequence: # Set melody (if configured) - choose: - conditions: - condition: template value_template: "{{ melody_select is not none and (melody_select | string | trim) not in ['', '[]', 'None'] and (melody_id | string | length) > 0 }}" sequence: - service: select.select_option target: entity_id: "{{ melody_select }}" data: option: "{{ melody_id }}" continue_on_error: true - delay: milliseconds: "{{ delay_between_commands_ms }}" # Set volume (if configured) - choose: - conditions: - condition: template value_template: "{{ volume_select is not none and (volume_select | string | trim) not in ['', '[]', 'None'] and (volume_id | string | length) > 0 }}" sequence: - service: select.select_option target: entity_id: "{{ volume_select }}" data: option: "{{ volume_id }}" continue_on_error: true - delay: milliseconds: "{{ delay_between_commands_ms }}" # Turn alarm ON or OFF based on sensor state - choose: # Any sensor active -> turn alarm ON - conditions: - condition: template value_template: "{{ is_any_sensor_on }}" sequence: - service: switch.turn_on target: entity_id: "{{ alarm_switch }}" continue_on_error: true # All sensors clear -> turn alarm OFF default: - service: switch.turn_off target: entity_id: "{{ alarm_switch }}" continue_on_error: true # Debug Stage 4: Alarm control done - choose: - conditions: - condition: template value_template: "{{ is_debug }}" sequence: - service: persistent_notification.create data: notification_id: "alarm_debug_alarm_control" title: "Alarm Debug [4/4]: Alarm Control Done" message: > Alarm switch: {{ alarm_switch }} Action: {{ 'turn_on' if is_any_sensor_on else 'turn_off' }} Melody: {{ melody_id }} → {{ melody_select }} Volume: {{ volume_id }} → {{ volume_select }}