Guide ·
Building the NFC reader for the printer
An ESP32 with an NFC reader recognises which sample tile sits at the printer and reports it to the server. With parts list, wiring, ESPHome and holders to print.
The Snapmaker U1 reads the NFC tags of its spools itself. Other printers cannot, and there you would have to tap “In Drucker einlegen” (load into printer) in the app after every spool change. The NFC reader does that for you: a holder with one slot per printer slot hangs on the printer. You put the sample tile of the type you are loading into it, an ESP32 reads it and tells the server which tile sits in which slot. The server puts a spool of that type into the slot and books the next print's usage onto it.
This guide is the third part after the server and the apps. The sample tiles must already be assigned to a type in the app.
Which variant for which printer
| Printer | Build | ESPHome file |
|---|---|---|
| one slot, e.g. Prusa MK4S, Mini or Bambu P1S with external spool | ESP32-C3 with display and one PN532, one pocket | fach-1x-pn532.yaml |
| Prusa Core One with MMU3 | ESP32 DevKit and five RC522, one reader per pocket | fach-5x-rc522.yaml |
| many slots, e.g. Anycubic Kobra X with ACE | ESP32-C3 with display and one PN532 in tap mode: tap the tile, choose the slot with a button | tippen-pn532.yaml |
So far the variant with one pocket has been tried on a Prusa MK4S. The MMU3 variant with five readers and tap mode are fully built and compile without errors, but have not yet run on a printer. So it is best to start with a printer with one slot.
What you need
For a printer with one slot or for tap mode:
- an ESP32-C3 board with a built-in 0.42" OLED (often sold as HW-675, 20.7 × 25 mm)
- a PN532 NFC module (the red board with two small switches for I²C and SPI)
- four wires, such as female Dupont wires
- a USB-C cable for flashing and a USB power supply for continuous use
For the MMU3 with five pockets:
- an ESP32 DevKit with 38 pins (ESP32-WROOM-32)
- five RC522 modules
- wires for the shared SPI bus, most conveniently on a piece of perfboard
- a micro USB cable and a USB power supply
For the holders:
- neodymium disc magnets 12 mm in diameter and a good 2.6 mm high; they hold the holder on the printer's frame
- filament without metal or carbon fibre, so PLA or PETG for example; fibres with metal or carbon can dampen the radio field
You also need a computer with Python 3, a soldering iron and your sample tiles with NTAG tags.
1. Wiring
PN532 on the ESP32-C3. First set the two switches on the PN532 to I²C: switch 1 ON, switch 2 OFF. The reader shares the I²C bus with the C3's display, so four wires are enough:
| PN532 | VCC | GND | SDA | SCL |
|---|---|---|---|---|
| ESP32-C3 | 3V3 | GND | GPIO5 | GPIO6 |
On the C3 you solder the four wires on directly, without a pin header, so it fits into the holder later. On the PN532 you plug them onto the four-pin header.
Five RC522 on the ESP32 DevKit. All readers are connected in parallel to power and to the three data lines of the SPI bus. Only the SDA line (used here as chip select) goes to each reader separately. RST goes to 3.3 V, IRQ stays free.
| RC522 | 3.3V | GND | SCK | MOSI | MISO | RST |
|---|---|---|---|---|---|---|
| ESP32 DevKit (all readers) | 3V3 | GND | GPIO18 | GPIO23 | GPIO19 | 3V3 |
| Slot | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| SDA to | GPIO26 | GPIO17 | GPIO16 | GPIO4 | GPIO13 |
Never connect the readers to 5 V. Both PN532 and RC522 run on 3.3 V here.
2. Install ESPHome
The readers run on ESPHome. Install it once in a Python environment of its own and fetch the repository with the ready-made configurations:
python3 -m venv ~/esphome
~/esphome/bin/pip install esphome
git clone https://github.com/Marcel-B/fil-o-mat.git
cd fil-o-mat/reader
After that the command is ~/esphome/bin/esphome. If you want to call it simply as esphome, add an alias once:
echo 'alias esphome=~/esphome/bin/esphome' >> ~/.zshrc && source ~/.zshrc
The ESP32-C3 needs no driver. If your computer does not recognise the DevKit, it is usually missing Silicon Labs' CP210x driver.
3. Enter credentials and printer
Copy the example file and enter your Wi-Fi and the server's address:
cp secrets.example.yaml secrets.yaml
wifi_ssid: "MyWiFi"
wifi_password: "…"
filomat_url: "http://192.168.1.50:8080"
filomat_api_key: ""
ota_password: ""
For filomat_url use the address in your home network with http, not the Tailscale address: the ESP32 does not join
the tailnet. If an API key is set on the server, it goes into filomat_api_key. The file secrets.yaml stays on your
computer and is not added to the repository.
Now you need the printer's ID. Open http://192.168.1.50:8080/api/printers in your browser. Each printer has
"id": "…" next to its name. With an API key it works in the terminal:
curl -H "X-Api-Key: …" http://192.168.1.50:8080/api/printers
Create a small file of its own for each printer that includes the shared configuration, here mk4s.yaml:
substitutions:
name: filomat-mk4s
friendly_name: fil-O-mat MK4S
printer_id: "ID from /api/printers"
packages:
fach: !include fach-1x-pn532.yaml
For the MMU3 you include fach-5x-rc522.yaml, for tap mode tippen-pn532.yaml. Because your file only contains the
three values, later improvements arrive by themselves with git pull.
4. Flash and check
Connect the ESP32 by USB and run:
esphome run mk4s.yaml
The first run downloads the tools and takes five to ten minutes. If ESPHome asks for the port, choose the USB entry,
such as /dev/cu.usbmodem… for the C3 or /dev/cu.usbserial… for the DevKit. If none appears, hold down the BOOT
button while plugging in the cable. Later, once the ESP32 is on your Wi-Fi, updates work without a cable: then choose
the “Over The Air” entry.
After uploading, the log keeps running. It shows you whether everything is right:
Connectedwith an IP address: the ESP32 is on your Wi-Fi.- In the I²C scan,
Found device at address 0x24(PN532) and0x3C(display). - Hold a tile to the reader. A line with
Backend: HTTP 200and"state":"known"follows.
Backend: HTTP 200 {"slots":[{"slot":0,"tag":"0423BC53CB2A81","state":"known","label":"eSun PLA #1",…}]}
The display shows “Eingelegt” (loaded) with the type and the spool number, and in the app the spool is now in the printer. With the MMU3 you hold a tile to each reader in turn. It must appear in the right slot in the log; if it shows up elsewhere, two SDA lines are swapped.
You can look at the log again at any time:
esphome logs mk4s.yaml
5. Print the holders
The holders have a pocket for the sample tile at the front and a compartment for the reader behind it. Magnets in the base hold them on the printer's frame. They sit below the reader and so outside its antenna, because right behind it they would disturb reception. They are printed standing, base on the bed; you need no supports.
An important measure is the distance between tile and reader. The PN532 reads a tile only from about one centimetre away and reliably from a good two centimetres. The holder for the PN532 therefore keeps a distance of 25 mm and is 41 mm deep as a result. The ESP32-C3 sits right in the block in between: it slides in from the left, the display looks out at the top, the USB-C socket on the left. Below it there is room for the wires, and a slot leads them back to the reader.
| Part | For | Size (W × D × H) | Files |
|---|---|---|---|
| PN532 reader holder with snap catch: two catches hold the C3 | one slot, tap mode | 45 × 41 × 57 mm | 3MF, STL |
| PN532 reader holder with plug: a second part with a USB hole closes the opening | one slot, tap mode | 45 × 41 × 57 mm, plug beside it | 3MF, STL |
| RC522 reader holder, five pockets | MMU3 | 209 × 17 × 73 mm | 3MF, STL |
| Case for the ESP32 DevKit, box with lid | MMU3 | 72 × 63 × 28 mm | 3MF, STL |
| Tag holder without reader, one pocket | just keeping tiles, e.g. at the U1 | 43 × 11 × 46 mm | 3MF, STL |
| Tag holder without reader, five pockets | MMU3 without reader | 209 × 11 × 46 mm | 3MF, STL |
| Fit test for the magnets: five slots, tighter from left to right | before the first holder | 85 × 4 × 18 mm | 3MF, STL |
You open the 3MF files directly in your slicer; for the holder with plug and the DevKit case both parts already lie side by side. The STL files contain the same parts.
The holders with a built-in C3 and the RC522 holder are new and not yet proven in continuous use. Print the fit test first and check with a reader whether the range reaches through the printed holder.
This is how you assemble the PN532 holder:
- Press the magnets into their slots from below.
- Slide the PN532 into the rear compartment from above, components facing back, the smooth side towards the tile. The pin header sticks out at the top.
- Slide the C3 with its soldered wires into the block from the left until the catches engage or the plug sits, and lead the wires through the slot to the pin header.
- Put the holder on the frame and insert a tile into the pocket.
6. Adapt the holders to your parts
All parts are generated by small Python scripts. Every measure is a parameter in them that you can change when calling
the script. You need the packages manifold3d and numpy:
python3 -m venv ~/halter
~/halter/bin/pip install manifold3d numpy
~/halter/bin/python leserhalter.py # PN532 with snap catch
~/halter/bin/python leserhalter.py lock=stopfen # PN532 with plug
~/halter/bin/python leserhalter.py reader=rc522 count=5 # five RC522 for the MMU3
~/halter/bin/python leserhalter.py sep=20 # less distance between tile and reader
| Script | Generates |
|---|---|
| leserhalter.py | reader holder with PN532 or RC522, optionally with built-in C3 |
| esp_gehaeuse.py | case for the DevKit (board=devkit) or a single rail for the C3 (board=c3) |
| taghalter_coreone.py | tag holder without reader, count=5 for five pockets |
| magnet_passungstest.py | fit test for the magnets |
The parameters are explained at the top of each script, such as mag_d and mag_h for other magnets or slot_w and
slot_h for larger sample tiles. The result is a 3MF file in the current folder each time.
7. How you work with it
- One pocket per slot: load the spool, put the tile into the pocket, done. The display shows the type with the spool number. Pulling the tile out changes nothing in the stock. The spool stays loaded until another tile comes or you move it in the app.
- Tap mode: hold the tile to the reader, the display shows the type. With the BOOT button you choose the slot, each press one further (on the Kobra X 1–4 in the printer, 5–8 in the ACE). Four seconds after the last press the spool goes into that slot. Without a button press the reader gives up after 15 seconds.
- Unknown tile: the display shows “Unbekannt” (unknown), and with ntfy set up a notification arrives on your phone. Assign the tile to a type in the app and insert it again.
When something does not work
| What you see | Cause | What helps |
|---|---|---|
command not found: esphome |
ESPHome is not on the path | call ~/esphome/bin/esphome or add the alias |
| ESP32 does not appear when flashing | not in flash mode, or a charge-only cable | hold BOOT while plugging in, try another cable |
no 0x24 in the I²C scan |
PN532 switches not set to I²C, or SDA and SCL swapped | switch 1 ON, 2 OFF; swap the wires on GPIO5 and GPIO6 |
| tile is not recognised | too close to the reader, or a magnet in front of the antenna | increase the distance, keep magnets outside the antenna |
| display “nicht erreichbar” (unreachable) | wrong address, or the Tailscale address entered | home network address in secrets.yaml, then flash again |
| display “Fehler 404” (error 404) | server too old, or wrong printer_id |
update the server, check the ID under /api/printers |
| display “Fehler 401” (error 401) | API key missing or wrong | filomat_api_key in secrets.yaml |
| one MMU3 slot flickers in the log | neighbouring RC522 interfere with each other | more distance between the readers |
The address and all other values are written into the firmware when it is built. So after every change to
secrets.yaml or your printer file, flash again with esphome run. More details on the wiring and on how the server
behaves are in the reader's README (in German).