Spoolman Updater – Automate Filament Tracking

:loudspeaker: Spoolman Updater – Automate Filament Tracking

Hi everyone! :wave:

I’ve built Spoolman Updater, an API that integrates Spoolman with Home Assistant, making it easy to track filament usage automatically. If you’re using a Bambu Lab AMS or any other setup that tracks filament consumption, this tool will help keep your spool database up-to-date.

:dart: Features:

:white_check_mark: Automatic filament tracking – updates spool usage when a print finishes or an AMS tray switches
:white_check_mark: Home Assistant integration via REST commands
:white_check_mark: Works with Bambu Lab AMS (requires ha-bambulab integration)
:white_check_mark: Requires Spoolman (GitHub) to manage filament spools
:white_check_mark: Lightweight Docker-based API
:white_check_mark: Fetch spools by brand and color for easy tracking

:wrench: Requirements

  • Spoolman installed and running
  • ha-bambulab installed in Home Assistant
  • Home Assistant REST commands enabled

:rocket: How It Works

:one: Deploy Spoolman

Before using Spoolman Updater, you need to install and run Spoolman:
Spoolman Installation Guide

:two: Deploy the API with Docker

docker run -d -p 8088:8080 \
  -e APPLICATION__HOMEASSISTANT__URL=http://homeassistant.local \
  -e APPLICATION__HOMEASSISTANT__TOKEN=your-token \
  -e APPLICATION__SPOOLMAN__URL=http://spoolman.local \
  --name spoolman-updater marcokreeft/spoolman-updater

:three: Add this REST command to configuration.yaml

rest_command:
  update_spool:
    url: "http://<your-server>:8088/Spools/spool"
    method: POST
    headers:
      Content-Type: "application/json"
    payload: >
      {
        "name": "{{ name }}",
        "material": "{{ material }}",
        "tagUid": "{{ tag_uid }}",
        "usedWeight": {{ used_weight }},
        "color": "{{ color }}"
      }

:four: Create an automation to trigger updates

alias: Update Spool When Print Finishes or Tray Switches
trigger:
  - platform: state
    entity_id: sensor.x1c_print_status
    to: "idle"
  - platform: state
    entity_id: sensor.x1c_active_tray_index
condition:
  - condition: template
    value_template: "{{ states('sensor.x1c_active_tray_index') | int > 0 }}"
action:
  - variables:
      tray_number: "{{ trigger.to_state.state if trigger.entity_id == 'sensor.x1c_active_tray_index' else states('sensor.x1c_active_tray_index') }}"
      tray_sensor: "sensor.x1c_ams_tray_{{ tray_number }}"
      tray_weight: "{{ state_attr('sensor.x1c_print_weight', 'AMS 1 Tray ' ~ tray_number) | float(0) }}"
      tag_uid: "{{ state_attr(tray_sensor, 'tag_uid') }}"
      material: "{{ state_attr(tray_sensor, 'type') }}"
      name: "{{ state_attr(tray_sensor, 'name') }}"
      color: "{{ state_attr(tray_sensor, 'color') }}"
  - service: rest_command.update_spool
    data:
      name: "{{ name }}"
      material: "{{ material }}"
      tag_uid: "{{ tag_uid }}"
      used_weight: "{{ tray_weight }}"
      color: "{{ color }}"

:link: More Info

:blue_book: GitHub Repository: Spoolman Updater
:whale: Docker Hub: marcokreeft/spoolman-updater
:link: Spoolman (Required!): GitHub
:link: Home Assistant BambuLab Integration: ha-bambulab

Would love to hear your feedback and see how you’re using it! Let me know if you have any questions or improvements. :blush:

This post was definitely not generated by ChatGPT.

Oh and it’s not tested through and through so please don’t yell at me if it breaks

2 Likes

Hey, that looks awesome!
I get the error message
Error in describing action: e.services[t] is undefined
on the action - any chance you have an idea?


Nevermind - Restarting Home Assist fixes it!

But one more question

The Active Tray number is not working for me

    {{ trigger.to_state.state if trigger.entity_id ==
    'sensor.p1s_01p00c482000314_aktiver_slotindex' else
    states('sensor.p1s_01p00c482000314_aktiver_slotindex') }}
(german variables)

The active slotindex is unknow after finishing a print
2 Likes

Do you have an AMS?

I’m using a AMS on my P1S and the issue is that on every spool change the whole weight is being used in the used_weight attribute. When i have a print wit a lot of spool changes the print had used far more weight than actually used as every time the whole print weight is used.

To change this i’ve used a utility_meter to track the weight on after every change and reset it to 0 when a new spool is used.

Automation:

automation:
  - alias: BAMBU LAB - Update Spool When Print Finishes or Tray Switches
    id: 8caacd91-1328-4ecf-9120-bb5bc32e0475
    triggers:
      - trigger: state
        entity_id: sensor.bambu_lab_p1s_actieve_tray_index
    conditions:
      - condition: template
        value_template: "{{ trigger.from_state.state not in ['unknown', 'unavailable'] }}"
      - condition: template
        value_template: "{{ trigger.from_state.state | int > 0 }}"
    actions:
      - variables:
          tray_number: "{{ trigger.from_state.state if trigger.entity_id == 'sensor.bambu_lab_p1s_actieve_tray_index' else states('sensor.bambu_lab_p1s_actieve_tray_index') }}"
          tray_sensor: "sensor.bambu_lab_p1s_ams1_tray_{{ tray_number }}"
          tray_weight: "{{ states('sensor.bambulab_filament_usage_meter') | float(0) | round(2) }}"
          tag_uid: "{{ state_attr(tray_sensor, 'tag_uid') }}"
          material: "{{ state_attr(tray_sensor, 'type') }}"
          name: "{{ state_attr(tray_sensor, 'name') }}"
          color: "{{ state_attr(tray_sensor, 'color') }}"
      - action: rest_command.bambulab_update_spool
        data:
          name: "{{ name }}"
          material: "{{ material }}"
          tag_uid: "{{ tag_uid }}"
          used_weight: "{{ tray_weight }}"
          color: "{{ color }}"
      - action: utility_meter.calibrate
        data:
          value: "0"
        target:
          entity_id: sensor.bambulab_filament_usage_meter

Utility Meter:

utility_meter:
  bambulab_filament_usage_meter:
    unique_id: 148d1e2d-87b2-4883-a923-a36a2c9fa0ac
    source: sensor.bambulab_filament_usage
    cycle: weekly

I’m missing the sensor.bambulab_filament_usage is that correct?

You’re right, i indeed forgot to add the config:

sensor:
  - platform: template
    sensors:
      bambulab_filament_usage:
        unique_id: b954300e-d3a2-44ab-948f-39c30b2f0c00
        friendly_name: "Bambu Lab Filament Usage"
        value_template: "{{ states('sensor.bambu_lab_p1s_gewicht_van_print') | float(0) / 100 * states('sensor.bambu_lab_p1s_printvoortgang') | float(0) }}"
        availability_template: "{% if is_state('sensor.bambu_lab_p1s_gewicht_van_print', 'unknown') or is_state('sensor.bambu_lab_p1s_gewicht_van_print', 'unavailable') %} false {% else %} true {%- endif %}"

That’s a really great feature you’re developing!

I am using the Spoolman Updater API, as described in the documentation. I understand that the API receives data such as name, material, tagUid, usedWeight, and color to update spool information.

Based on the integration examples with Bambu Lab AMS, the tagUid seems to play a role … However, for users who do not use Bambu Lab filament and thus might not have a tagUid, what fields are primarily used for matching? Is the spool name the key identifier, or are other fields like material also considered important for associating the update with the correct spool in Spoolman?

Brand name, material and color are used for matching. Should be uniquely enough

Hi,I would love to use your updater but I can’t get it to run on my raspi, probably because it has an ARM chip and your image is built for amd64.
Could you add an ARM Image so the spoolman updater becomes available on raspi, too? I would really appreciate it :slight_smile:

OK got it to work, but now it seems that everytime the automation fires, a New spool gets created. Including Filament and vendor. I dont have spools with an taguid, ist that a Problem?

  domain: rest_command
  service: update_spool
  service_data:
    filament_name: Bambu PLA Silk
    filament_material: PLA
    filament_tag_uid: '0000000000000000'
    filament_used_weight: 2.9
    filament_color: '#C6C4D2FF'
  target: {}
running_script: false

This is how my automation calls the API. As you can see I also dont have tag_uids :slight_smile: As long as the color, name and material are unique it should get the same spool every time

Ahh ok, then i got my error: I got SUNLU PLA+ and this is also represented in the Filament in the AMS. A “+” doesn’t go so well URL-wise, always problematic with encodings. So the call to the spoolman API doesn’t really translates the actual name of the filament but always creates a new one.
I changed 2 lines in your code to accomodate this issue and could file a pull request if you like :slight_smile:
Now it works and I only have to work out how to use the utility meter :smiley:

Thanks @marcokreeft87 for your work!

I will definitely try your Spoolman Updater in the next days, after my holidays :smiley: , but I have already a question :slight_smile:

How does it work in case in Spoolman there are two different Spools that have the same color, material and name, if there is no id linked to the spool?

For me is the case where I have in spoolman a spool already used and a spare spool brand new of the same color, material and name.

thanks

Yeah that wont work. You will have to put the spools in 1 by 1 in that case

@marcokreeft87 Trying to work this out as I can’t see any reference here to sensor.bambulab_filament_usage ???

Also left scratching my head as using

rest_command:
  update_spool:
    url: "http://10.0.1.102:8088/Spools/spool"
    method: POST
    headers:
      Content-Type: "application/json"
    payload: >
      {
        "name": "{{ name }}",
        "material": "{{ material }}",
        "tagUid": "{{ tag_uid }}",
        "usedWeight": {{ used_weight }},
        "color": "{{ color }}"
      }

and HA configuration warning says: “Setup of package ‘spoolman’ failed: integration ‘rest_command’ has duplicate key ‘url’”

About the filament usage, you really have to read the other posts in here bro…

The duplicate key is a weird one. It isnt duplicate haha. Don’t know man, maybe somewere else is also defined?

Noticed a small error in the description above -
"docker run -d -p 8088:8088 "

Should be
"docker run -d -p 8088:8080 "

It appears to be correct on the Github page.

Thnx great catch!