Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions PR_BODY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
## Summary

Your RFID filament detection implementation is excellent - thank you for the solid NDEF/OpenSpool support!

This PR extends it with optional Spoolman integration by:
- Extracting the `spool_id` field from OpenSpool JSON payloads
- Calling an optional `ON_NFC_SPOOL_READ` macro when `spool_id` is present

This allows users with [Spoolman](https://github.com/Donkie/Spoolman) to get automatic spool tracking when loading filament.

## Changes

- **filament_protocol_ndef.py**: Extract optional `spool_id` field from OpenSpool JSON into `info['SPOOL_ID']`
- **02-add-ndef-protocol.patch**: Call `ON_NFC_SPOOL_READ CHANNEL=<n> SPOOL_ID=<id>` macro when spool_id is present
- **docs/rfid_support.md**: Add Spoolman Integration section with field reference and example macro
- **examples/nfc_spoolman.cfg**: Ready-to-use macro file users can copy to their config

## Tag Format

Users add `spool_id` to their existing OpenSpool tags:

```json
{
"protocol": "openspool",
"version": "1.0",
"brand": "Elegoo",
"type": "PLA",
"color_hex": "#FF5733",
"spool_id": 42
}
```

## Backward Compatibility

- Tags without `spool_id` work exactly as before
- The macro call only fires when `spool_id` is present
- No configuration required unless user wants Spoolman integration

## Example Macro

Users create `extended/klipper/nfc_spoolman.cfg`:

```cfg
[gcode_macro ON_NFC_SPOOL_READ]
gcode:
{% set channel = params.CHANNEL|int %}
{% set spool_id = params.SPOOL_ID|int %}
{% set tool = "T" ~ channel %}
SET_GCODE_VARIABLE MACRO={tool} VARIABLE=spool_id VALUE={spool_id}
RESPOND PREFIX="NFC" MSG="Spool {spool_id} assigned to {tool}"
```

## Testing

- Tested with NTAG215 tags containing OpenSpool JSON with spool_id field
- Verified backward compatibility with tags without spool_id
- Verified macro is called with correct channel and spool_id parameters
73 changes: 73 additions & 0 deletions docs/rfid_support.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ Using the non-standard OpenSpool `subtype` field it is possible to specify a mat
- `additional_color_hexes` - Additional colors for multicolor spools (up to 4)
- `weight` - Spool weight in grams
- `diameter` - Filament diameter in mm (e.g., 1.75)
- `spool_id` - Spoolman spool ID for automatic spool tracking (see [Spoolman Integration](#spoolman-integration))

### Snapmaker Orca Naming Convention

Expand Down Expand Up @@ -135,3 +136,75 @@ Use the **NFC Tools** app (iOS/Android) to inspect tags:
**NTAG tags only work on extended firmware:**
- Basic and original firmware only support Mifare Classic 1K with Snapmaker proprietary format
- Extended firmware adds NTAG215/216 support

## Spoolman Integration

[Spoolman](https://github.com/Donkie/Spoolman) is a self-hosted filament inventory management system. When combined with NFC tags, you can automatically track which spool is loaded in each extruder.

### How It Works

1. Include `spool_id` in your OpenSpool NFC tag payload
2. When the tag is read, the firmware calls the `ON_NFC_SPOOL_READ` macro
3. Your macro updates Spoolman with the active spool

### Tag Format

Add the `spool_id` field to your OpenSpool payload:

```json
{
"protocol": "openspool",
"version": "1.0",
"brand": "Elegoo",
"type": "PLA",
"color_hex": "#FF5733",
"min_temp": 200,
"max_temp": 220,
"spool_id": 42
}
```

The `spool_id` should match the spool ID in your Spoolman database.

### Example Macro

Create `extended/klipper/nfc_spoolman.cfg`:

```cfg
# NFC Tag → Spoolman Integration
# Automatically called when an NFC tag with spool_id is read
# Parameters: CHANNEL (0-3 = T0-T3), SPOOL_ID (integer)

[gcode_macro ON_NFC_SPOOL_READ]
description: Called when NFC tag with spool_id is read
gcode:
{% set channel = params.CHANNEL|int %}
{% set spool_id = params.SPOOL_ID|int %}
{% set tool = "T" ~ channel %}

# Update tool's spool assignment
SET_GCODE_VARIABLE MACRO={tool} VARIABLE=spool_id VALUE={spool_id}

# Optional: Trigger deferred spool save
UPDATE_DELAYED_GCODE ID=SAVE_SELECTED_SPOOLS DURATION=1

RESPOND PREFIX="NFC" MSG="Spool {spool_id} assigned to {tool}"
```

### Generating Tags from Spoolman

If you have Spoolman running, you can generate the tag payload directly:

```bash
SPOOL_ID=42 # Your spool ID
curl -s "http://spoolman:7912/api/v1/spool/$SPOOL_ID" | jq '{
protocol: "openspool",
version: "1.0",
type: .filament.material,
brand: .filament.vendor.name,
color_hex: ("#" + .filament.color_hex),
spool_id: .id
}'
```

Write this JSON to an NTAG215 tag using any NFC app that supports NDEF with MIME type `application/json`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# NFC Tag -> Spoolman Integration
# Copy this file to extended/klipper/ to enable automatic spool tracking
#
# When an NFC tag with a spool_id field is read, this macro is called
# with the channel (0-3 = T0-T3) and the spool_id from the tag.
#
# Tag format example:
# {"protocol":"openspool","version":"1.0","type":"PLA","brand":"Elegoo","color_hex":"#FF5733","spool_id":42}
#
# Customize this macro to integrate with your Spoolman setup.

[gcode_macro ON_NFC_SPOOL_READ]
description: Called automatically when NFC tag with spool_id is read
gcode:
{% set channel = params.CHANNEL|int %}
{% set spool_id = params.SPOOL_ID|int %}
{% set tool = "T" ~ channel %}

# Update tool's spool assignment (requires tool macros with spool_id variable)
SET_GCODE_VARIABLE MACRO={tool} VARIABLE=spool_id VALUE={spool_id}

# Optional: Trigger deferred spool save to Moonraker/Spoolman
# UPDATE_DELAYED_GCODE ID=SAVE_SELECTED_SPOOLS DURATION=1

RESPOND PREFIX="NFC" MSG="Spool {spool_id} assigned to {tool}"
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ diff -uNr rootfs.original/home/lava/klipper/klippy/extras/filament_detect.py roo
+from . import filament_protocol_ndef
from . import fm175xx_reader
from . import filament_feed
@@ -124,6 +125,14 @@

@@ -124,6 +125,22 @@
filament_info = info
else:
logging.error("channel[%d] m1 parse err: %d", channel, error)
Expand All @@ -18,6 +18,15 @@ diff -uNr rootfs.original/home/lava/klipper/klippy/extras/filament_detect.py roo
+ if (error == filament_protocol.FILAMENT_PROTO_OK):
+ logging.info("channel[%d] NDEF parse ok....", channel)
+ filament_info = info
+ # Call macro if spool_id present in NFC tag (for Spoolman integration)
+ spool_id = info.get('SPOOL_ID')
+ if spool_id is not None:
+ try:
+ gcode = self.printer.lookup_object('gcode')
+ gcode.run_script_from_command(
+ f"ON_NFC_SPOOL_READ CHANNEL={channel} SPOOL_ID={spool_id}")
+ except Exception as e:
+ logging.warning(f"Failed to run ON_NFC_SPOOL_READ: {e}")
+ else:
+ logging.error("channel[%d] NDEF parse err....", channel)
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,9 @@ def openspool_parse_payload(payload):
info['OFFICIAL'] = True
info['CARD_UID'] = []

# Extract spool_id for Spoolman integration (optional field)
info['SPOOL_ID'] = data.get('spool_id', None)

return filament_protocol.FILAMENT_PROTO_OK, info

except json.JSONDecodeError as e:
Expand Down
Loading