[Blueprint] Bambu Lab 3D Printer – Cost Notification (Telegram, Bambu HACS)

Hi everyone! :raising_hands:
I’ve published a blueprint (it’s my first!) that calculates filament, electricity, and depreciation per-print costs a my Bambu Lab printer and sends a Telegram message (official integration) with a full breakdown and the cover image from the Bambu HACS integration. Filament length is optional.

EDIT : the import link is now working

:backhand_index_pointing_right: One-click import:
Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

What it does

  • Tracks kWh used for the print (from your smart plug’s cumulative kWh)
  • Uses Bambu HACS sensors for status, start/end time, (optional) cover image, usage hours, weight, (optional) length
  • Computes:
    • Filament cost (weight × price/kg)
    • Electricity cost (kWh × price/kWh)
    • Depreciation cost = purchase_cost / lifetime_hours × hours_printed
  • Sends a Telegram photo + caption (fallback to text-only)
  • Optional “Do Not Disturb” for pause notifications
  • Optional cumulative stats helpers

You’ll need

  • Bambu Lab HACS integration configured
  • A smart plug (or similar) exposing a cumulative kWh sensor
  • Telegram Bot (official integration) and your chat_id
  • A few helpers in HA:
    • input_number.3d_print_kwh_start (stores starting kWh per print)
    • (Optional totals) input_number helpers for cumulative filament weight, cumulative filament cost, cumulative electrical cost, cumulative total cost, and last print kWh used

Blueprint inputs (high level)

  • HA URL (base, no trailing slash)
  • Printer sensors: print status, start time, end time, usage hours
  • Image entity (optional): cover image from the Bambu integration
  • Weight (g), length (optional) (mm/m)
  • Energy (kWh) sensor, Start kWh helper
  • Costs: filament €/kg, electricity €/kWh, printer purchase cost, lifetime hours
  • Telegram chat ID(s) (comma-separated)
  • (Optional) sleeping toggle & cumulative helper entities
  • Disable Image and Currency Symbol

Installation

More info on GitHub README

  1. Create input helpers

  2. Import the blueprint

Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

  1. Create a new automation from this blueprint and fill the inputs (see below).

Creating the helpers

In Home Assistant, go to Settings → Devices & Services → Helpers → Create Helper → Number:

  • input_number.3d_print_kwh_start (no unit required)
  • Optionally: input_number.3d_cumulative_filament_weight (g), input_number.3d_cumulative_filament_cost, input_number.3d_cumulative_electrical_cost, input_number.3d_cumulative_total_cost, input_number.3d_last_print_kwh_used

img

Image from Colton Onushko’s post

Inputs & What They Do

Input Required Notes
Home Assistant URL (ha_url) :white_check_mark: Base URL (no trailing slash). Used to prefix image URLs in Telegram. Example: http://homeassistant.local:8123 or your external URL.
Printer Status Sensor :white_check_mark: sensor.<printer>_print_status from the Bambu HACS integration. Triggers prepare/finish/pause.
Print Cover Image The image entity exposed by the Bambu integration, if available. Leave empty to send text-only.
Start Time / End Time Sensors :white_check_mark: sensor.<printer>_start_time and sensor.<printer>_end_time from the Bambu integration. Used to compute duration.
Print Weight Sensor :white_check_mark: Grams (integration sensor or input_number). Used for filament cost (Typically from the Bambu integration)
Print Length Sensor Sensor/helper for filament length (mm or m). Leave empty if you don’t have it.
Total Usage Hours Sensor sensor.<printer>_total_usage_hours (or similar) from the integration, for all-time usage stats.
Energy Consumption Sensor :white_check_mark: Your smart plug’s cumulative kWh sensor for the printer.
Start kWh Helper :white_check_mark: input_number to store the start kWh reading. Create one (e.g. input_number.3d_print_kwh_start).
Filament Price per KG :white_check_mark: e.g. 25.99 for €25.99/kg (your currency).
Electricity Cost per kWh :white_check_mark: e.g. 0.385 for €0.385/kWh.
Printer Purchase Cost :white_check_mark: e.g. 1000.
Printer Lifetime (hours) :white_check_mark: e.g. 6000.
Telegram Chat ID(s) :white_check_mark: One or more chat IDs (comma-separated) . See below to find your chat ID(s). e.g. -1001234567890, 12345678
Sleep Mode Toggle input_boolean to suppress pause alerts (DND).
Cumulative Stats helpers (Filament Weight, Filament Cost, Electrical Cost, Total Cost, Last Print kWh) Create input_number helpers if you want totals updated after each print: cumulative_filament_weight (g), cumulative_filament_cost, cumulative_electrical_cost, cumulative_total_cost, and (optionally) last_print_kwh_used.
Disable Image Sending If true, always send text (no image).
Currency Symbol :white_check_mark: Defaults to $. Use , £, etc. Only symbol (no spaces). Used for display only

Why length is optional? Cost uses weight × price/kg. Length (m/ft) is nice for reporting but not essential.

Example message

🎉 3D PRINT COMPLETED
⏱️ Duration: 2 hours, 48 minutes
⚖️ Weight: 92.0 g – Cost: €2.39
🔌 Power: 0.31 kWh – Cost: €0.12
🛠️ Depreciation: €0.41
💰 Total Cost: €2.92

(“Filament Length” line appears only if you supply a length sensor.)

Notes

  • If the photo can’t be sent, the blueprint automatically sends the text-only message.
  • If you don’t have a length sensor, just leave it empty.
  • If you prefer only text, enable Disable Image.

Credit

This blueprint is heavily inspired by Colton Onushko’s automation. Big thanks to him !
I replaced Discord with Telegram and rely exclusively on the Bambu HACS integration instead of OrcaSlicer and Colton’s python script.

Happy printing! Feedback, questions or PRs are welcome. :raising_hands:

Hello soflane,

Looks awesome, but your link is not working…

I am guessing because it is very long, 2 sub folders in and one of the folders is long with spaces instead of '-'s likely.
My suggestion is move it and test it until you find something that works…
I tried both of your ‘my links’.

Sorry!!! As I said it’s the first time I post a blueprint :sweat_smile:
The link is now working.
Enjoy!

1 Like

was a cool idea :slight_smile:

1 Like

Doesnt seem to work on my Instance. I have several issues:

1.I get Error while executing automation See log:
automation.auto_bambu_cost_notification: Failed to load URL: 404

i tried my publicly accessible https://Adress and then i tried
http://internalip.adress.of.ha:8123 and still get the issue and i wont get smarter when i watch the traces.

and second issue: It wants me to create a helper but i think this helper doesnt make sense, wouldnt a text helper make more sence since

Now i can have 0 to 100 - but that wont help, wont a input text make generally make more sense?!

downloading opening the trace, it seems to not properly push the image and therefore screw something up. Im on HAOS - do i need to create folders so that the image gets saved? where does it get saved anyway or whitelist a folder for this token image?

Okay in the meantime I debugged a bit and found the issue on this
First of all ignore Topics 2 and 3 since they are self-inflicted issues and can be narrowed down to my own incompetence.

I focused on question 1 since this is clearly a bug in the Blueprint.
So back to topic:

I found out that sending without a picture works totally fine

So i was trying to find out why the picture push didnt work and why the message does not get sent at all.

for some reason it uses a wrongly formatted URL (thats why I get error 404) with two slashes, even though my _ha_url variable is totally fine and explicitly defined in the trace log:

      "changed_variables": {
        "_ha_url": "http://192.168.1.211:8123",

image

BUT it seems to add two slashes “//” to it instead of one in the trace log.

After that I changed the url to http://192.168.1.211:8123/" for the lulz (despite what the blueprint tells me) and voila: triple slashes.

image

It seems to be that the blueprint is flawed in line 446
url: '{{ _ha_url }}/{{ cover_image_url }}'
since the cover_image_url already has a “/” in the beginning
I went into the dir of the code (\config\blueprints\automation\soflane) of it, made a copy and removed the excess slash so the var gets glued together correctly to:
url: '{{ _ha_url }}{{ cover_image_url }}'
then i copied the yaml into \config\blueprints\automation and now it works as a quick fix…

and it works now.

I just created a pull-request for removing that excess character

1 Like

Hey there — thanks a lot for digging in and for the PR! :raised_hands:

Sorry for the late reply — I’ve been quite busy lately and wanted to take the time to check why it didn’t cause an error on my setup.

You were absolutely right: the URL was being built as {{ _ha_url }}/{{ cover_image_url }} while cover_image_url already starts with /, so some setups ended up with a // and a 404. On my side, it “worked” because my reverse proxy (Traefik) automatically normalized the double slash — which is why I didn’t catch it earlier. I’ve just merged your PR! :tada:

A few extra notes for anyone following along:

  • No local file saving needed: The image comes from the Bambu integration as a URL path (served by HA). Nothing is written to disk for this blueprint, and you don’t need to create folders or whitelist anything.
  • About the helper type (“Start kWh”): It must be an input_number, not a text helper — the blueprint performs arithmetic with it. The default 0–100 range you see is just Home Assistant’s default when creating a number helper. Feel free to set a wide range and small step, depending on your smart plug’s precision. For example:
    • Min: 0
    • Max: 100000
    • Step: 0.001
    • Mode: Box

If anyone still encounters URL edge cases (some proxies can be… creative :sweat_smile:), you can add a more robust version like this:

# Replace:
url: '{{ _ha_url }}{{ cover_image_url }}'

# With:
url: >-
  {{ _ha_url.rstrip('/') ~ '/' ~ (cover_image_url | string).lstrip('/') }}

That ensures the URL is properly joined regardless of extra slashes.
With the merged fix, most setups won’t need it — but I’m leaving it here as a “sticky note” for reference.

Again, huge thanks for reporting, testing, and sending the PR — really appreciate the help! :pray:

1 Like

Hello, I’ve managed to configure everything except for sending the message via Telegram, which isn’t working. I’m entering my ID (numbers) but the message isn’t being sent. When I test it using the developer tools, it works.

Do you have any logs to share ?

Sorry, It was me who made a mistake. With the / :grimacing:
I downloaded it again from GitHub and everything is fine, thank you!

Nice - the cumulative trackers are just what I was looking for :slight_smile:

Hello, I added a bot to HA for Alarmo. I created discussion groups for ease of use. However, it no longer works with blueprints. I correctly specified the group ID with the hyphen (-) in front. Here’s what I see in the automation logs.

did you ever figure this out? im running into the same log message.

Hey, not the author at all but do you have a target set. It looks like it’s one of the inputs, it needs a target that is a telegram bot.

The issue is there because it has the "old" telegram send message scheme which now breaks the whole script from what I see.
It worked flawlessly but after an update it broke this blueprint/automation
The whole Blueprint needs an overhaul.

@yannouche4260 @Lx4lights512

I have created a quick fix for the new format.
I tried to change as little as possible in the blueprint since I am not super experienced with blueprints but I wanted to make sure it works as longterm as possible for the upcoming 2026.9.0 update.

Basically what I did:

  • removed chat.id var, since the whole splitting etc is no longer needed basically
  • adjusted to using notify entities AND you can also specify multiple targets
  • refactored cosmetics with AI
data:
  entity_id:
    - notify.telegram_bot_1234567890_1234567890 

instead of the old

data:
  target: 
    - 1234567890

This is the current yaml....i will soon try to fork and request a merge

blueprint:
  name: "Bambu Lab 3D Printer Cost Notification fix"
  description: >
    Calculate filament, electricity, and depreciation costs for each Bambu Lab 3D print,
    and send a Telegram notification (official Telegram Bot integration) with the details
    and print image when the job completes. Filament length is optional.
  domain: automation
  input:
    ha_url:
      name: Home Assistant URL
      description: "Base URL of your Home Assistant instance (without trailing slash)"
      selector:
        text:
      default: "http://homeassistant.local:8123"
    printer_status_sensor:
      name: Printer Status Sensor
      description: "sensor.<printer>_print_status (HACS Bambu Lab integration)"
      selector:
        entity:
          integration: bambu_lab
          domain: sensor
    printer_cover_image:
      name: Print Cover Image
      description: "Image entity from Bambu integration (optional). Leave blank to send only text."
      default: ~
      selector:
        entity:
          integration: bambu_lab
          domain: image

    printer_start_time_sensor:
      name: Printer Start Time Sensor
      description: "sensor.<printer>_start_time (HACS Bambu Lab integration)"
      selector:
        entity:
          integration: bambu_lab
          domain: sensor
    printer_end_time_sensor:
      name: Printer End Time Sensor
      description: "sensor.<printer>_end_time (HACS Bambu Lab integration)"
      selector:
        entity:
          integration: bambu_lab
          domain: sensor

    print_weight_sensor:
      name: Print Weight Sensor/Helper
      description: "Weight in grams (integration sensor or input_number)."
      selector:
        entity:
          filter:
            - domain: sensor
            - domain: input_number

    print_length_sensor:
      name: Print Length Sensor/Helper (optional)
      description: "Length in mm or m (integration sensor or input_number). Leave empty if not available."
      default: ~
      selector:
        entity:
          multiple: false
          filter:
            - domain: sensor
            - domain: input_number

    total_usage_sensor:
      name: Total Usage Hours Sensor
      description: "Sensor for the printer's total usage hours (from Bambu integration, e.g. sensor.<printer>_total_usage_hours). Used for all-time stats."
      selector:
        entity:
          integration: bambu_lab
          domain: sensor
    energy_usage_sensor:
      name: Energy Consumption Sensor
      description: "Sensor that tracks cumulative energy (kWh) used by the printer (from a smart plug)."
      selector:
        entity:
          domain: sensor
          device_class: energy
    start_energy_helper:
      name: "Helper – Start kWh"
      description: "Input Number helper to store the printer's energy meter reading at the start of each print."
      selector:
        entity:
          domain: input_number
    filament_price_per_kg:
      name: Filament Price per KG
      description: "Cost of filament per kilogram (in your currency). This will be used to calculate filament cost from the print's weight."
      selector:
        number:
          min: 0.0
          max: 1000.0
          unit_of_measurement: "/kg"
          step: 0.01
      default: 25.99
    energy_cost_per_kwh:
      name: Electricity Cost per kWh
      description: "Your electricity cost per kilowatt-hour."
      selector:
        number:
          min: 0.0
          max: 10.0
          unit_of_measurement: "/kWh"
          step: 0.001
      default: 0.4
    printer_purchase_cost:
      name: Printer Purchase Cost
      description: "What you paid for the 3D printer (for depreciation calculation)."
      selector:
        number:
          min: 0.0
          max: 10000.0
          step: 0.01
      default: 1000.0
    printer_lifetime_hours:
      name: Estimated Printer Lifetime (hours)
      description: "Estimated total usage hours for the printer's life (for depreciation). e.g. 2000 hours."
      selector:
        number:
          min: 1
          max: 100000
          step: 1
      default: 6000

    # --- Telegram (official integration) ---
    telegram_chat_ids:
      name: Telegram Notify Target(s)
      description: "The notify service name for Telegram (e.g., notify.telegram_bot_botid_yourid)."
      selector:
        entity:
          multiple: true
          filter:
            - domain: notify


    # Optional inputs for DND & cumulative stats
    sleep_mode_boolean:
      name: "Sleeping Mode Toggle (optional)"
      description: "An input_boolean that indicates 'do not disturb' mode (to suppress pause notifications at night). Leave blank if not used."
      selector:
        entity:
          domain: input_boolean
      default: ~

    cumulative_filament_weight:
      name: "Cumulative Filament Weight (optional)"
      description: "Input Number helper tracking total filament used (grams). (Optional: updated after each print.)"
      selector:
        entity:
          domain: input_number
      default: ~
    cumulative_filament_cost:
      name: "Cumulative Filament Cost (optional)"
      description: "Input Number helper tracking total filament cost. (Optional: updated after each print.)"
      selector:
        entity:
          domain: input_number
      default: ~
    cumulative_electrical_cost:
      name: "Cumulative Electrical Cost (optional)"
      description: "Input Number helper tracking total electrical cost. (Optional: updated after each print.)"
      selector:
        entity:
          domain: input_number
      default: ~
    cumulative_total_cost:
      name: "Cumulative Total Cost (optional)"
      description: "Input Number helper tracking total cost (filament+electric) of all prints. (Optional: updated after each print.)"
      selector:
        entity:
          domain: input_number
      default: ~
    last_print_kwh_used:
      name: "Last Print kWh Used (optional)"
      description: "Input Number helper to record energy (kWh) used by the last print. (Optional: updated after each print.)"
      selector:
        entity:
          domain: input_number
      default: ~
    disable_image_boolean:
      name: "Disable Image Sending"
      description: "If ON, only a text message is sent (no image)."
      selector:
        boolean:
      default: false
    currency_symbol:
      name: "Currency Symbol"
      description: "Symbol used for cost lines (e.g. $, €, £)."
      selector:
        text:
      default: "$"
  source_url: "https://coltography.ca/usage-cost-notifications-with-home-assistant-and-bambu-lab-3d-printers/"
variables:
  _ha_url: !input ha_url
  _printer_status_sensor: !input printer_status_sensor
  _printer_cover_image: !input printer_cover_image
  _printer_start_time_sensor: !input printer_start_time_sensor
  _printer_end_time_sensor: !input printer_end_time_sensor
  _print_weight_sensor: !input print_weight_sensor
  _print_length_sensor: !input print_length_sensor
  _total_usage_sensor: !input total_usage_sensor
  _energy_usage_sensor: !input energy_usage_sensor
  _start_energy_helper: !input start_energy_helper
  _filament_price_per_kg: !input filament_price_per_kg
  _energy_cost_per_kwh: !input energy_cost_per_kwh
  _printer_purchase_cost: !input printer_purchase_cost
  _printer_lifetime_hours: !input printer_lifetime_hours
  _telegram_chat_ids: !input telegram_chat_ids
  _sleep_mode_boolean: !input sleep_mode_boolean
  _cumulative_filament_weight: !input cumulative_filament_weight
  _cumulative_filament_cost: !input cumulative_filament_cost
  _cumulative_electrical_cost: !input cumulative_electrical_cost
  _cumulative_total_cost: !input cumulative_total_cost
  _last_print_kwh_used: !input last_print_kwh_used
  _disable_image_boolean: !input disable_image_boolean
  _currency_symbol: !input currency_symbol

trigger:
  - platform: state
    entity_id: !input printer_status_sensor
    to: "prepare"
    id: prepare

  - platform: state
    entity_id: !input printer_status_sensor
    to: "finish"
    id: finish

  - platform: state
    entity_id: !input printer_status_sensor
    to: "pause"
    id: paused

condition: []

action:
  # ======== PREPARE ========
  - alias: Record energy reading at print start
    if:
      - condition: trigger
        id: prepare
    then:
      - service: input_number.set_value
        data:
          entity_id: "{{ _start_energy_helper }}"
          value: "{{ states(_energy_usage_sensor) | float(0) }}"

  # ======== FINISH ========
  - alias: Handle print completed - calculate costs and send Telegram message
    if:
      - condition: trigger
        id: finish
    then:
      - delay: "00:00:02"

  # (Ancien debug retiré)

      - variables:
          end_power: "{{ (states(_energy_usage_sensor) if _energy_usage_sensor is not none else 0) | float(0) }}"
          start_power: "{{ (states(_start_energy_helper) if _start_energy_helper is not none else 0) | float(0) }}"
          weight_g: "{{ (states(_print_weight_sensor) if _print_weight_sensor is not none else 0) | float(0) }}"
          length_raw: >-
            {% if _print_length_sensor is not none %}
              {{ states(_print_length_sensor) | float(0) }}
            {% else %}
              {{ None }}
            {% endif %}
          total_usage_hrs: "{{ (states(_total_usage_sensor) if _total_usage_sensor is not none else 0) | float(0) }}"
          total_kwh: "{{ ((end_power | float(0)) - (start_power | float(0))) | float(0) }}"
          filament_cost: "{{ ((weight_g | float(0)) * (_filament_price_per_kg | float(0)) / 1000) | round(2) }}"
          electrical_cost: "{{ ((total_kwh | float(0)) * (_energy_cost_per_kwh | float(0))) | round(2) }}"
          # start_time: "{{ states('sensor.' ~ ( _printer_status_sensor ).split('.')[1].replace('_etat_de_l_impression','_heure_de_debut')) | as_datetime }}"
          # end_time:   "{{ states('sensor.' ~ ( _printer_status_sensor ).split('.')[1].replace('_etat_de_l_impression','_heure_de_fin'))   | as_datetime }}"

          start_ts: "{{ (as_timestamp(states(_printer_start_time_sensor)) | float(0)) if _printer_start_time_sensor is not none else 0 }}"
          end_ts:   "{{ (as_timestamp(states(_printer_end_time_sensor)) | float(0)) if _printer_end_time_sensor is not none else 0 }}"
          duration_seconds: >
            {% if (start_ts | float(0)) > 0 and (end_ts | float(0)) > 0 %}
              {{ ((end_ts | float(0)) - (start_ts | float(0))) | float(0) }}
            {% else %} 0 {% endif %}
          duration_str: >
            {% set secs = duration_seconds | float(0) %}
            {% set days = (secs // 86400) | int %}
            {% set hrs  = ((secs % 86400) // 3600) | int %}
            {% set mins = ((secs % 3600) // 60) | int %}
            {% set parts = [] %}
            {% if days > 0 %}{% set parts = parts + [days ~ ' day' ~ (days>1 and 's' or '')] %}{% endif %}
            {% if hrs  > 0 %}{% set parts = parts + [hrs  ~ ' hour' ~ (hrs >1 and 's' or '')] %}{% endif %}
            {% set parts = parts + [mins ~ ' minute' ~ (mins>1 and 's' or '')] %}
            {{ parts | join(', ') }}

          depreciation_cost: >
            {% set hours = duration_seconds / 3600 %}
            {% if ( _printer_lifetime_hours | float(0) ) > 0 %}
              {{ ( _printer_purchase_cost | float(0) * (hours / ( _printer_lifetime_hours | float(1) )) ) | round(2) }}
            {% else %} 0 {% endif %}
      # Update helper values (cumulative stats and last print energy), if provided

      - alias: Update statistics helpers
        sequence:
          # Update kWh used for this print (if a helper is provided)
          - choose:
              - conditions:
                  - condition: template
                    value_template: "{{ _last_print_kwh_used is defined and _last_print_kwh_used is not none }}"
                sequence:
                  - service: input_number.set_value
                    data:
                      entity_id: "{{ _last_print_kwh_used }}"
                      value: "{{ total_kwh | float(0) }}"
          # Update cumulative filament length (in meters) if provided
          - choose:
              - conditions:
                  - condition: template
                    value_template: "{{ _cumulative_filament_weight is not none }}"
                sequence:
                  - service: input_number.set_value
                    data:
                      entity_id: "{{ _cumulative_filament_weight }}"
                      value: "{{ (states(_cumulative_filament_weight) | float(0)) + (weight_g | float(0)) }}"
          - choose:
              - conditions:
                  - condition: template
                    value_template: "{{ _cumulative_filament_cost is not none }}"
                sequence:
                  - service: input_number.set_value
                    data:
                      entity_id: "{{ _cumulative_filament_cost }}"
                      value: "{{ (states(_cumulative_filament_cost) | float(0)) + (filament_cost | float(0)) }}"
          - choose:
              - conditions:
                  - condition: template
                    value_template: "{{ _cumulative_electrical_cost is not none }}"
                sequence:
                  - service: input_number.set_value
                    data:
                      entity_id: "{{ _cumulative_electrical_cost }}"
                      value: "{{ (states(_cumulative_electrical_cost) | float(0)) + (electrical_cost | float(0)) }}"
          - choose:
              - conditions:
                  - condition: template
                    value_template: "{{ _cumulative_total_cost is not none }}"
                sequence:
                  - service: input_number.set_value
                    data:
                      entity_id: "{{ _cumulative_total_cost }}"
                      value: "{{ (states(_cumulative_total_cost) | float(0)) + ((filament_cost | float(0)) + (electrical_cost | float(0)) + (depreciation_cost | float(0))) }}"

      # Define variables for message content (including all-time stats if available)
      - variables:
          # Optional length formatting
          length_m: >
            {% if length_raw is not none %}
              {% set val = length_raw | float(0) %}
              {{ ( val / (val > 50 and 1000 or 1) ) | round(2) }}
            {% else %} {{ None }} {% endif %}
          length_ft: >
            {% if length_raw is not none %}
              {{ (( length_m | float(0) ) * 3.28084 ) | round(2) }}
            {% else %} {{ None }} {% endif %}
          total_cost: "{{ ( filament_cost | float(0) + electrical_cost | float(0) + depreciation_cost | float(0) ) | round(2) }}"
          # All-time cumulative values (post-update)
          cumulative_cost: "{{ (states(_cumulative_total_cost) | float(0)) if _cumulative_total_cost is not none else 0 }}"
          total_filament_g: "{{ (states(_cumulative_filament_weight) | float(0)) if _cumulative_filament_weight is not none else 0 }}"
          total_filament_lbs: "{{ (total_filament_g / 453.5924) | round(2) }}"
          # Build message with optional length line
          msg_body: |-
            {% macro md(v) -%}
            {{ (v|string)
              .replace('\\','\\\\')
              .replace('_','\\_')
              .replace('*','\\*')
              .replace('[','\\[')
              .replace(']','\\]')
              .replace('(','\\(')
              .replace(')','\\)')
              .replace('~','\\~')
              .replace('`','\\`')
              .replace('>','\\>')
              .replace('#','\\#')
              .replace('+','\\+')
              .replace('-','\\-')
              .replace('=','\\=')
              .replace('|','\\|')
              .replace('{','\\{')
              .replace('}','\\}')
              .replace('.','\\.')
              .replace('!','\\!')
            }}
            {%- endmacro %}
            {% set cs = md(_currency_symbol) %}
            🎉 **3D PRINT COMPLETED**
            ⏱️ *Duration:* {{ md(duration_str) }}
            ⚖️ *Weight:* {{ md(weight_g | round(1)) }} g \- Cost: __{{ cs }}{{ md(filament_cost) }}__
            {% if length_m is not none %}🧵 *Filament Length:* {{ md(length_m) }} m / {{ md(length_ft) }} ft
            {% endif %}🔌 *Power:* {{ md(total_kwh | round(3)) }} kWh \- Cost: __{{ cs }}{{ md(electrical_cost) }}__
            🛠️ *Depreciation:* __{{ cs }}{{ md(depreciation_cost) }}__
            💰 *Total Cost:* *__{{ cs }}{{ md(total_cost) }}__*
            {% if _cumulative_total_cost is not none %}🕒 *All Time Usage:* {{ md(total_usage_hrs | round(1)) }} h
            📊 *All Time Cost:* __{{ cs }}{{ md('%0.2f'|format(cumulative_cost)) }}__
            🧵 *All Time Filament:* {{ md(total_filament_g | round(0)) }} g / {{ md(total_filament_lbs) }} lbs
            {% endif %}
          # Integration cover image: use attribute or fallback entity (guarded)
          cover_image_url: >-
            {% if _printer_cover_image is not none %}
              {{ state_attr(_printer_cover_image, 'cover_image')
                 or state_attr(_printer_cover_image, 'entity_picture') }}
            {% else %}
              {{ None }}
            {% endif %}

      # Send single photo with caption (official Telegram Bot)
      - repeat:
          for_each: >
            {{ _telegram_chat_ids | select('string') | map('trim') | reject('equalto','') | list }}
          sequence:
            - variables:
                _image_disabled: >-
                  {{ _disable_image_boolean | default(false) }}
                _has_image: >-
                  {{ (cover_image_url is defined and cover_image_url is not none and (cover_image_url|string)|length > 10 and not (cover_image_url|string)|lower in ['none','null','unavailable','unknown']) and (not _image_disabled) }}
            - choose:
                - conditions: "{{ _has_image }}"
                  sequence:
                    - service: telegram_bot.send_photo
                      data:
                        entity_id: "{{ repeat.item | string }}"
                        url: "{{ _ha_url }}{{ cover_image_url }}"
                        caption: "{{ msg_body }}"
                        parse_mode: markdownv2
              default:
                - service: telegram_bot.send_message
                  data:
                    entity_id: "{{ repeat.item | string }}"
                    message: "{{ msg_body }}"
                    parse_mode: markdownv2
            - service: system_log.write
              data:
                level: info
                message: >
                  [Bambu Print Notify] Sent to chat {{ repeat.item }} has_image={{ _has_image }} image_disabled={{ _image_disabled }} cover_image_url="{{ cover_image_url }}"

  # ========== Paused: Print Paused ==========
  - alias: Notify on print paused
    if:
      - condition: trigger
        id: paused
      - condition: or
        conditions:
          # Only send pause alert if no sleep mode enabled or the sleep toggle is off
          - condition: template
            value_template: "{{ _sleep_mode_boolean == None or _sleep_mode_boolean == '' }}"
          - condition: template
            value_template: "{{ _sleep_mode_boolean is not none and (states(_sleep_mode_boolean) == 'off') }}"
    then:
      - repeat:
          for_each: "{{ _telegram_chat_ids }}"
          sequence:
            - service: telegram_bot.send_message
              data:
                entity_id: "{{ repeat.item | string }}"
                message: "⏸️ 3D Printer has paused the print job."
                parse_mode: markdownv2

I created a Pull, it just needs to be merged by @soflane

2 Likes