cross-posted from: https://lemmy.world/post/6872403
What if your Klipper printer could keep track of which spool is loaded and how much filament is remaining?
- Do you wish your printer could keep track of the filament remaining on each spool automatically for you?
- Do you want it to automatically switch to the correct spool when you load one?
- Do you wish your printer would warn you when you have PLA loaded and try to print an ABS gcode?
Does that sound like something you need? Read on below:
Spoolman is the project for you!
It was created by Donkie (not myself) and it has official support in moonraker. Additionally the Fluidd, Mainsail and KlipperScreen UIs also integrate its functionality. Octoprint is not supported at the time of writing. Even without a compatible UI spools can be selected using macros or calls to the moonraker API.
Installation is fairly straight-forward, but some Klipper users may not be familiar with docker so it can seem rather intimidating.
I’ve written out a short guide to help you get started:
Setup
I don’t think the spoolman software is very resource-intensive, but I personally installed it on a separate system from my pi.
You will likely be fine to install it on the pi in most cases though.To begin, you need to install docker/docker-compose:
sudo apt update sudo apt -y install docker-compose
Then create a directory for spoolman:
mkdir ~/spoolman cd ~/spoolman
Create a docker-compose config:
nano ~/spoolman/docker-compose.yml
docker-compose.yml:
version: '3.3' services: spoolman: image: ghcr.io/donkie/spoolman:latest restart: unless-stopped volumes: - ./data:/home/ubuntu/.local/share/spoolman ports: - "7912:8000" environment: - TZ=America/New_York # Optional, defaults to UTC
You may want to change the timezone. A list is available here Then run:
sudo docker-compose up -d
You should now be able to access the interface at http://ipaddress:7912 (replace
ipaddress
with your pi/host’s ip address)Create your first Vendor, Filament, and then Spool in the UI there. When I tried to configure moonraker in the next step it failed without an initial spool existing in the database, so I wouldn’t skip this.
Configuration
Now we need to configure moonraker to use spoolman.
Pop open your
moonraker.conf
file and add the following:
# enables spool management [spoolman] server: http://ipaddress:7912 # URL to the Spoolman instance. This parameter must be provided. sync_rate: 5 # The interval, in seconds, between sync requests with the # Spoolman server. The default is 5. ``` Once again, we need to replace `ipaddress` with the ip address of the host system. If it is the same as the pi (the one running moonraker) you can also simply use `localhost` instead Restart moonraker and reload Fluidd/mainsail/etc and you should now see a `spoolman` section on the dashboard. You can also verify in your `moonraker.log` file, look for a line like this: ```2023-08-08 10:53:43,664 [server.py:load_component()] - Component (spoolman) loaded``` Remember, even without using a compatible UI, Klipper/moonraker will still track filament use against the last spool selected. We can also add commands that allow us to select the spool regardless of the UI: **printer.cfg**: ```ini [gcode_macro SET_ACTIVE_SPOOL] gcode: {% if params.ID %} {% set id = params.ID|int %} {action_call_remote_method( "spoolman_set_active_spool", spool_id=id )} {% else %} {action_respond_info("Parameter 'ID' is required")} {% endif %} [gcode_macro CLEAR_ACTIVE_SPOOL] gcode: {action_call_remote_method( "spoolman_set_active_spool", spool_id=None )}
These commands can be used like
SET_ACTIVE_SPOOL ID=5
andCLEAR_ACTIVE_SPOOL
to select (or clear) the spool. Spools are selected by spool-id, which you can see on the spoolman UI where you create new spools. These commands can even be used in your “Custom Filament Gcode” in the slicer to allow filament profiles to select spools automatically.Mainsail/Fluidd allow for integration with the klipper/crowsnest webcam to scan qrcodes from spools and automatically select the proper spool at the start of a print/etc. QRcodes can be printed from the spoolman web UI.
If you are not using mainsail/fluidd or you want it to function without the UI, I wrote a small script that will scan qrcodes from klipper cameras and command spoolman to select the spool it identifies.
This can be triggered from a macro which allows you to put it in your start gcode.
The code and instructions are below:
Scanning Spool QRcodes
This functionality requires you to install the
zbar-tools
package for scanning codes and the gcode_shell_command Klipper extension to allow klipper to trigger shell scripts.
# Install zbar-tools for reading qrcodes sudo apt install zbar-tools # Install gcode_shell_command to run scripts from klipper macros cd /home/pi/klipper/klippy/extras/ wget https://raw.githubusercontent.com/th33xitus/kiauh/master/resources/gcode_shell_command.py
Then we add some config to our klipper config file:
printer.cfg
[gcode_shell_command qrcode_qrscanner] ## NOTE: Change the path below if your klipper config is not in the default path ## command: sh /home/pi/printer_data/config/qrcodespoolman.sh verbose: True timeout: 2. [gcode_macro QRCode_Scan] gcode: RUN_SHELL_COMMAND CMD=qrcode_qrscanner
And create a shell script:
qrcodespoolman.sh (place in your config folder next to printer.cfg)
#!/bin/sh ########################################## WARNING: ############################################## ### This script assumes you are using a crowsnest webcam on the same host and the first camera ### ### Adjust the paths and addresses below as needed to work with your configuration ### ################################################################################################## ## Capture a snapshot from the camera and store it in a jpg file wget http://localhost/webcam/?action=snapshot -O /home/pi/printer_data/gcodes/qrcode.jpg ## Read any QRcodes from the image and strip just the spool-id from the data in the code SPOOLID=$(zbarimg -S*.enable /home/pi/printer_data/gcodes/qrcode.jpg | sed 's/[^0-9]*\([0-9]\+\).*/\1/') ## Return the spool-id in the console (this is mostly for debugging purposes) echo $SPOOLID ## Make an API call to spoolman selecting the spool that matches the spool-id curl -X POST -H "Content-Type: application/json" -d "{\"spool_id\": \"$SPOOLID\"}" http://localhost:7125/server/spoolman/spool_id
Please read through the comments in those snippets, particularly if your klipper config is not located in
/home/pi/printer_data/config
or your camera is not connected to the same machine. You may need to make adjustments to fit your machine.The paths and addresses used in the example should work for anyone using a pi with a single printer and the first/only camera configured in crowsnest.
If all goes well you should now be able to trigger this action with the following command:
QRCODE_SCAN
You can place that in your start gcode to have it triggered at the start of every print.
The command does the following:
- Triggers the qrcode script, which does the rest:
- Asks moonraker for a snapshot from the webcam
- Locates and scans any qrcode in the image
- Strips out any data in the qrcode except for the spool id
- Tells moonraker to tell spoolman to select that spool id
Updating Spoolman
To update your spoolman instance, assuming you have installed in
~/spoolman
, you can use the following command:
cd ~/spoolman;sudo docker-compose stop;sudo docker-compose pull;sudo docker-compose up -d
NOTE: Avoid using
docker-compose down
as it will wipe out the storage volumes, likely taking your spool database with it.You also may want to consider using watchtower to automatically keep docker containers updated, but that is outside the scope of this guide.
Bonus screenshots
Spoolman UI - Spools
Fluidd UI - Spool Widget
Fluidd UI - Spool Selection Dialog
Conclusion
I hope this little guide helps anyone interested in trying out spoolman, its a great tool that fulfills a function in Klipper that I’ve been looking for for a while, and it does so very well!
I just want to reiterate, this is not my project. I am just a Klipper fan who wanted to get the word out on what I think is a really great project that a lot of Klipper users may like.
That said, I hope my guide can help those users give it a try!
And if you have any trouble, or just questions/concerns, leave a comment below and I will do my best to help!
These scripts are incredibly usefuls for my QIDI with an older klipper/mainsail version not supporting Spoolman.
I was wondering if a similar API can be used to also send consumption data. Perhaps not in real-time but when the print ends (or stops)…any idea for these?
Oh hey I kinda helped get this started in a very round about way! Nice to see the fluid integration, maybe if I do the mainsail one, someone else will do it a better way lol. I’ve not been printing much lately but set spoolman up a while ago on the pi running my voron and it’s been great.
I switched over to Fluidd a while back, but at least according to the Spoolman repo Mainsail’s integration is working now as well
Thanks for sharing!
what do you mean by docker-compose down wiping volumes? Is’nt the whole idea of linking an internal folder to one on the host machine that the data will persist even if the docker instance is destroyed?
Ah shoot, disregard that.
I copied a lot of this from my Discord server and that little bit was actually caused by a permissions issue on my end. I just forgot to remove that line.
That said, I would recommend restarting the docker container after configuring your first spool, just to verify that your database doesn’t get lost on restart.
This is really neat! I was working on a project a few years ago to do something like this but then life happened. Glad to see others doing what I didn’t!
Thanks for sharing the guide. However, I noticed to short commings.
- The right volumen mapping is /home/pi/spoolman/data:/home/app/.local/share/spoolman
- You missed defining the service for autostart. E.g, for systemd it is:
[Unit] Description=Spool Management Documentation=https://github.com/Donkie/Spoolman After=network-online.target Before=moonraker.service Wants=udev.target [Install] Alias=spoolman WantedBy=multi-user.target [Service] Type=oneshot User=pi RemainAfterExit=yes WorkingDirectory=/home/pi/spoolman ExecStart=/usr/bin/env /usr/bin/docker-compose -f /home/pi/spoolman/docker-compose.yml up -d ExecStop=/usr/bin/env /usr/bin/docker-compose -f /home/pi/spoolman/docker-compose.yml stop
You then enable and start the service:
sudo systemctl enable spoolman sudo systemctl start spoolman
I think maybe he changed the volume mapping at some point because most of this I found through the GitHub page and I don’t think I ever changed that part myself.
FWIW it works for me as-is but there may be some fuckery because I started out in a much earlier version.
Great call on setting up a system service to start it though, probably would get annoying really quick without that if you frequently reboot.
In addition, Before being able to execute docker-compose you have to add your user to the docker group by executing
sudo usermod -aG docker pi
That’s definitely smarter than running as root with sudo like I do 😅