Last active
April 18, 2026 15:05
-
-
Save alexdetsch/42d4c07d906eceed5d088231bb87dd7d to your computer and use it in GitHub Desktop.
Homeassistant Blueprint Device Progress Notification
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| blueprint: | |
| name: "Device Progress Notification" | |
| description: > | |
| Displays a persistent Android notification with progress bar, percentage, | |
| remaining time, and estimated completion time for any device that reports | |
| operation state and progress. Supports both remaining-time countdown | |
| (e.g. Bambu Lab) and end-time timestamp (e.g. HomeConnect) as time source. | |
| Create one automation per device. (v1.4.0) | |
| source_url: https://gist.github.com/alexdetsch/42d4c07d906eceed5d088231bb87dd7d | |
| domain: automation | |
| input: | |
| device_name: | |
| name: Device Name | |
| description: "Display name for the notification (e.g. 'Washing Machine', '3D Printer')" | |
| default: "Device" | |
| selector: | |
| text: | |
| operation_state_entity: | |
| name: Operation State Entity | |
| description: "Entity reporting the device's operational status (e.g. sensor.washer_operation_state, sensor.bambu_print_status)" | |
| selector: | |
| entity: | |
| domain: sensor | |
| running_state_value: | |
| name: Running State Value | |
| description: > | |
| The state value that indicates the device is actively running. | |
| HomeConnect: "Run" · Bambu Lab: "running" · Others: check your integration. | |
| default: "Run" | |
| selector: | |
| text: | |
| progress_entity: | |
| name: Progress Entity | |
| description: "Entity reporting program progress as a percentage (0–100)" | |
| selector: | |
| entity: | |
| domain: sensor | |
| time_source: | |
| name: Time Source | |
| description: > | |
| How the device reports timing information. | |
| "Remaining time": a countdown value (e.g. Bambu Lab). | |
| "End time": a timestamp when the program finishes (e.g. HomeConnect). | |
| default: "remaining" | |
| selector: | |
| select: | |
| options: | |
| - label: "Remaining time" | |
| value: "remaining" | |
| - label: "End time (timestamp)" | |
| value: "end_time" | |
| remaining_time_entity: | |
| name: Remaining Time Entity | |
| description: "Entity reporting the remaining program duration (only used when time source is 'Remaining time')" | |
| default: sensor.none | |
| selector: | |
| entity: | |
| domain: sensor | |
| remaining_time_unit: | |
| name: Remaining Time Unit | |
| description: "Unit of the remaining time entity (only used when time source is 'Remaining time')" | |
| default: "seconds" | |
| selector: | |
| select: | |
| options: | |
| - label: "Seconds" | |
| value: "seconds" | |
| - label: "Minutes" | |
| value: "minutes" | |
| - label: "Hours" | |
| value: "hours" | |
| end_time_entity: | |
| name: End Time Entity | |
| description: "Entity reporting the program's finish time as a timestamp (only used when time source is 'End time')" | |
| default: sensor.none | |
| selector: | |
| entity: | |
| domain: sensor | |
| notify_service: | |
| name: Notification Service | |
| description: > | |
| The mobile_app notify service for your Android device | |
| (e.g. notify.mobile_app_pixel_8) | |
| default: notify.mobile_app_smartphone | |
| selector: | |
| text: | |
| notification_channel: | |
| name: Notification Channel | |
| description: "Android notification channel (controls priority and sound behavior)" | |
| default: "device_progress" | |
| selector: | |
| text: | |
| icon_running: | |
| name: Icon (running) | |
| description: "MDI icon shown while the device is running" | |
| default: "mdi:progress-clock" | |
| selector: | |
| icon: | |
| icon_finished: | |
| name: Icon (finished) | |
| description: "MDI icon shown when the program completes" | |
| default: "mdi:check-circle" | |
| selector: | |
| icon: | |
| variables: | |
| device_name: !input device_name | |
| progress_entity: !input progress_entity | |
| time_source: !input time_source | |
| remaining_time_entity: !input remaining_time_entity | |
| remaining_time_unit: !input remaining_time_unit | |
| end_time_entity: !input end_time_entity | |
| notify_service: !input notify_service | |
| notification_channel: !input notification_channel | |
| running_state_value: !input running_state_value | |
| icon_running: !input icon_running | |
| icon_finished: !input icon_finished | |
| notification_tag: >- | |
| device_progress_{{ states[progress_entity].object_id | default('device') }} | |
| remaining_sec: >- | |
| {% if time_source == 'end_time' %} | |
| {% set end_ts = states(end_time_entity) %} | |
| {% if end_ts not in ['unknown', 'unavailable', ''] %} | |
| {{ [((as_timestamp(end_ts) - as_timestamp(now())) | int), 0] | max }} | |
| {% else %} | |
| 0 | |
| {% endif %} | |
| {% else %} | |
| {% set raw = states(remaining_time_entity) | float(0) %} | |
| {% if remaining_time_unit == 'hours' %} | |
| {{ (raw * 3600) | int }} | |
| {% elif remaining_time_unit == 'minutes' %} | |
| {{ (raw * 60) | int }} | |
| {% else %} | |
| {{ raw | int }} | |
| {% endif %} | |
| {% endif %} | |
| trigger: | |
| - id: "started" | |
| platform: state | |
| entity_id: !input operation_state_entity | |
| to: !input running_state_value | |
| - id: "update" | |
| platform: time_pattern | |
| minutes: "/1" | |
| - id: "finished" | |
| platform: state | |
| entity_id: !input operation_state_entity | |
| from: !input running_state_value | |
| condition: [] | |
| action: | |
| - choose: | |
| # ── Device finished ── | |
| - conditions: | |
| - condition: trigger | |
| id: "finished" | |
| sequence: | |
| - action: "{{ notify_service }}" | |
| data: | |
| title: "{{ device_name }} – Done! ✅" | |
| message: "The program has finished." | |
| data: | |
| tag: "{{ notification_tag }}" | |
| channel: "{{ notification_channel }}" | |
| importance: high | |
| persistent: false | |
| timeout: 300 | |
| notification_icon: "{{ icon_finished }}" | |
| color: "#4CAF50" | |
| # ── Periodic update (only while running) ── | |
| - conditions: | |
| - condition: trigger | |
| id: "update" | |
| - condition: state | |
| entity_id: !input operation_state_entity | |
| state: !input running_state_value | |
| sequence: | |
| - action: "{{ notify_service }}" | |
| data: | |
| title: >- | |
| {{ device_name }} – {{ states(progress_entity) | int(0) }}% | |
| message: >- | |
| {% set rsec = remaining_sec | int(0) %} | |
| {% set hours = (rsec // 3600) %} | |
| {% set minutes = ((rsec % 3600) // 60) %} | |
| {% if time_source == 'end_time' %} | |
| {% set end_time = as_timestamp(states(end_time_entity)) | timestamp_custom('%H:%M') %} | |
| {% else %} | |
| {% set end_time = (now() + timedelta(seconds=rsec)).strftime('%H:%M') %} | |
| {% endif %} | |
| {% if hours > 0 %} | |
| Remaining: {{ hours }}h {{ minutes }}min · Done ~{{ end_time }} | |
| {% else %} | |
| Remaining: {{ minutes }} min · Done ~{{ end_time }} | |
| {% endif %} | |
| data: | |
| tag: "{{ notification_tag }}" | |
| channel: "{{ notification_channel }}" | |
| importance: low | |
| persistent: true | |
| sticky: true | |
| ongoing: true | |
| notification_icon: "{{ icon_running }}" | |
| color: "#2196F3" | |
| alert_once: true | |
| progress: "{{ states(progress_entity) | int(0) }}" | |
| progress_max: 100 | |
| # ── Device started ── | |
| - conditions: | |
| - condition: trigger | |
| id: "started" | |
| sequence: | |
| - action: "{{ notify_service }}" | |
| data: | |
| title: >- | |
| {{ device_name }} – Started | |
| message: >- | |
| {% set rsec = remaining_sec | int(0) %} | |
| {% set hours = (rsec // 3600) %} | |
| {% set minutes = ((rsec % 3600) // 60) %} | |
| {% if time_source == 'end_time' %} | |
| {% set end_time = as_timestamp(states(end_time_entity)) | timestamp_custom('%H:%M') %} | |
| {% else %} | |
| {% set end_time = (now() + timedelta(seconds=rsec)).strftime('%H:%M') %} | |
| {% endif %} | |
| {% if hours > 0 %} | |
| Estimated duration: {{ hours }}h {{ minutes }}min · Done ~{{ end_time }} | |
| {% else %} | |
| Estimated duration: {{ minutes }} min · Done ~{{ end_time }} | |
| {% endif %} | |
| data: | |
| tag: "{{ notification_tag }}" | |
| channel: "{{ notification_channel }}" | |
| importance: default | |
| persistent: true | |
| sticky: true | |
| ongoing: true | |
| notification_icon: "{{ icon_running }}" | |
| color: "#2196F3" | |
| progress: 0 | |
| progress_max: 100 | |
| mode: restart | |
| max_exceeded: silent |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment