A daemon that runs on a Klipper host to automatically select the active Spoolman spool by scanning NFC tags. Supports both TigerTag (NTAG213) and OpenPrintTag (NFC-V / ICODE SLIX2) formats.
- The daemon polls a configured NFC reader for tags
- When a tag is detected, it reads the raw tag memory and sends it to Spoolman's
/api/v1/nfc/lookupendpoint - Spoolman auto-detects the tag format, decodes it, and matches it to a spool
- If a match is found, the daemon:
- Sets the active spool in Moonraker
- Pushes filament metadata to Klipper via
SAVE_VARIABLE(for use in macros) - Updates a Mainsail preheat preset with the filament's temperatures
Tag format is auto-detected by Spoolman:
- TigerTag (ISO 14443A / NTAG213): matched by
id_productfield against filamentexternal_id - OpenPrintTag (ISO 15693 / NFC-V): matched by
instance_uuidderived from the tag's hardware UID
The daemon includes debouncing so the same tag won't re-trigger within a configurable window.
| Reader | Interface | TigerTag | OpenPrintTag | Dependencies |
|---|---|---|---|---|
| PN532 | UART | Yes | No | pyserial |
| PN5180 | SPI + GPIO | Yes | Yes | spidev, gpiod or RPi.GPIO |
| ACR1552U | USB | Yes | Yes | pyscard, pcscd |
- A Klipper host (Raspberry Pi, BeagleBone, etc.) running Moonraker
- One of the supported NFC readers (see above)
- Spoolman with NFC endpoints enabled (
SPOOLMAN_TIGERTAG_ENABLED=TRUE,SPOOLMAN_NFC_ENABLED=TRUE) — see Integration ecosystem below for the fork that provides these - Python 3.9+
This daemon is part of a broader 3D-printing tooling stack maintained at github.com/goeland86. For tested end-to-end behavior, pair it with these components:
| Component | Source | Required? | Why this fork / repo |
|---|---|---|---|
| Spoolman | goeland86/Spoolman branch pr/nfc-support |
Required | Adds the /api/v1/nfc/lookup endpoint and the SPOOLMAN_TIGERTAG_ENABLED / SPOOLMAN_NFC_ENABLED env vars the daemon depends on. Not yet merged into upstream Donkie/Spoolman. |
| Moonraker host | upstream Klipper + Moonraker, or goeland86/snapmaker_moonraker |
Required (one of the two) | The daemon speaks Moonraker JSON-RPC and pushes Klipper macros (SAVE_VARIABLE, RESPOND TYPE=command MSG="action:prompt_*"). On a Snapmaker J1S the snapmaker_moonraker bridge natively intercepts these so the daemon works without real Klipper. |
| Web UI | Mainsail, Fluidd, or KlipperScreen | Recommended | UI-agnostic — the daemon only uses the standard notify_gcode_response prompt protocol every current Klipper-compatible frontend renders. Upstream versions are fine. |
Single-tool mode (mode = single) works against any of the above with no
extra config. Multi-tool mode requires either real Klipper with
[respond] + [save_variables] configured (see Multi-tool mode below)
or the snapmaker_moonraker bridge.
Clone this repo onto your Klipper host and run the installer:
git clone <repo-url>
cd klipper-nfc
./install.shThe installer will:
- Create a Python venv at
~/nfc-spoolman-envwith base dependencies (pyserial,requests) - Copy the daemon and readers to your home directory
- Copy the example config to
~/printer_data/config/nfc_spoolman.cfg(if it doesn't already exist) - Install and enable a systemd service (
nfc-spoolman) - Add the service to
moonraker.asvcso it appears in Mainsail/Fluidd
For PN5180 or ACR1552U readers, install additional dependencies:
# PN5180 (SPI)
~/nfc-spoolman-env/bin/pip install spidev gpiod
# ACR1552U (USB/PC/SC)
sudo apt install pcscd libpcsclite-dev
~/nfc-spoolman-env/bin/pip install pyscardTo receive update notifications in Mainsail or Fluidd (same badge system as Klipper and Moonraker), add this block to your moonraker.conf:
[update_manager nfc-spoolman]
type: git_repo
path: ~/klipper-nfc-daemon
origin: https://github.com/goeland86/klipper-nfc-daemon.git
primary_branch: main
virtualenv: ~/nfc-spoolman-env
requirements: requirements.txt
managed_services: nfc-spoolmanReplace ~/klipper-nfc-daemon with the actual path where you cloned this repo if different. Moonraker will:
- Poll GitHub for new commits
- Show an update badge in the UI when updates are available
- Run
git pull+ reinstall Python deps + restart thenfc-spoolmanservice when you click Update
Restart Moonraker after adding the block.
Edit ~/printer_data/config/nfc_spoolman.cfg:
[nfc]
# Reader type: pn532, pn5180, acr1552u
reader = pn532
# PN532 (UART)
pn532_device = /dev/ttyUSB0
pn532_baudrate = 115200
# PN5180 (SPI) — uncomment if using
# pn5180_spi_bus = 0
# pn5180_spi_cs = 0
# pn5180_busy_pin = 25
# pn5180_reset_pin = 24
# ACR1552U (USB) — uncomment if using
# acr1552u_reader_name = ACS ACR1552U
# Common
poll_interval = 0.5
debounce_time = 5.0
# Auto-create spool when scanning an unrecognized OpenPrintTag
auto_create = false
# Update a Mainsail preheat preset with filament temps on spool detect
mainsail_preset = true
# Push filament metadata to Klipper SAVE_VARIABLE (see below)
klipper_variables = true
[spoolman]
url = http://localhost:7912
[moonraker]
url = http://localhost:7125# Start the service
sudo systemctl start nfc-spoolman
# Check status
sudo systemctl status nfc-spoolman
# Follow logs
journalctl -u nfc-spoolman -f
# Restart after config changes
sudo systemctl restart nfc-spoolmanLogs are also written to ~/printer_data/logs/nfc_spoolman.log.
For printers with multiple tools, set mode = multi_tool in the config. Instead of silently setting the global spool, the daemon will show a KlipperScreen prompt each time a spool is scanned, letting you assign it to a specific tool.
-
Add
[respond]to yourprinter.cfg(required for the prompt dialog):[respond] -
Include the NFC macros in your
printer.cfg:[include nfc_macros.cfg]Copy
nfc_macros.cfgfrom this repo to~/printer_data/config/. -
Set the mode in
nfc_spoolman.cfg:[nfc] mode = multi_tool
-
Restart the daemon:
sudo systemctl restart nfc-spoolman
- You scan a spool on the NFC reader
- The daemon looks up the spool in Spoolman
- A KlipperScreen dialog appears: "Assign Spool: PolyTerra PLA Red" with buttons [T0] [T1] [T2] ...
- You tap a tool button on the touchscreen
- The spool is assigned to that tool in Moonraker's Spoolman integration
- Per-tool filament metadata is saved to Klipper variables (if
[save_variables]is configured)
The daemon auto-discovers available tools at startup by querying Moonraker — it checks for a toolchanger object (klipper_toolchanger plugin) first, then falls back to counting extruder objects.
When [save_variables] is configured, NFC_ASSIGN_TOOL saves per-tool variables with a nfc_tN_ prefix:
| Variable | Example (T0) | Example (T2) |
|---|---|---|
nfc_t0_spool_id |
42 |
nfc_t2_spool_id = 87 |
nfc_t0_material |
"PLA" |
nfc_t2_material = "ASA" |
nfc_t0_extruder_temp |
210 |
nfc_t2_extruder_temp = 260 |
nfc_t0_bed_temp |
60 |
nfc_t2_bed_temp = 100 |
nfc_t0_vendor |
"PolyTerra" |
nfc_t2_vendor = "eSun" |
Use them in macros:
[gcode_macro PRINT_START]
gcode:
{% set svv = printer.save_variables.variables %}
; Get temps for the first tool being used
{% set extruder = svv.nfc_t0_extruder_temp|default(200)|int %}
{% set bed = svv.nfc_t0_bed_temp|default(60)|int %}
M140 S{bed}
M109 S{extruder}
M190 S{bed}NFC_STATUS— print current per-tool spool assignments to the consoleNFC_CANCEL— dismiss the prompt without assigning_NFC_STATE— show the pending (just-scanned) spool info
When enabled, the daemon pushes filament metadata to Klipper via SAVE_VARIABLE commands. This requires a [save_variables] section in your printer.cfg:
[save_variables]
filename: ~/printer_data/config/saved_variables.cfgThe following variables are set on each NFC scan:
| Variable | Type | Example |
|---|---|---|
nfc_spool_id |
int | 42 |
nfc_material |
string | "PLA" |
nfc_extruder_temp |
int | 210 |
nfc_bed_temp |
int | 60 |
nfc_vendor |
string | "Rosa3D" |
nfc_filament_name |
string | "PLA Starter" |
nfc_color_hex |
string | "ff9724" |
nfc_diameter |
float | 1.75 |
Use them in your PRINT_START macro:
[gcode_macro PRINT_START]
gcode:
{% set svv = printer.save_variables.variables %}
{% set extruder = svv.nfc_extruder_temp|default(200)|int %}
{% set bed = svv.nfc_bed_temp|default(60)|int %}
M140 S{bed} ; start bed heating
M109 S{extruder} ; wait for extruder
M190 S{bed} ; wait for bedWhen enabled, the daemon creates/updates a preheat preset named "NFC: Vendor Material Name" in Mainsail. This appears in the temperature panel as a one-click preheat button. The preset is always updated in-place (same ID) so you won't get duplicate entries.
Set the PN532 to UART mode (DIP switches / solder jumpers). Connect via a USB-UART adapter (e.g. PL2303, FTDI) or directly to GPIO UART pins.
The daemon handles the PN532 HSU wakeup automatically — every command is preceded by the 16-byte 0x55 wakeup preamble, so the chip is reliably awakened even after it has dropped back to low-power between transactions. No external bridge MCU is required.
Connect to SPI0 (or your chosen bus) plus two GPIO pins for BUSY and RESET. The PN5180 needs 5V for the RF antenna and 3.3V for logic.
Plug in the USB reader. Ensure pcscd is running (sudo systemctl start pcscd).
Verify any reader works at the OS level:
# For PN532 with libnfc
sudo apt install libnfc-bin
nfc-list
# For ACR1552U with pcsc-tools
sudo apt install pcsc-tools
pcsc_scan