Gérer une ferme d’impression, c’est gérer des consommables à grande échelle. Le filament arrive par kilogramme, est chargé sur les machines, consommé par des dizaines de travaux, et finit par s’épuiser — souvent en plein milieu d’une impression si l’on n’y prend pas garde. Le même stock remplit deux rôles simultanément : il alimente les imprimantes en tant que consommable de production, et figure dans le catalogue WooCommerce en tant que produit disponible à la revente. Une bobine chargée sur une machine est une bobine qui n’est plus disponible pour un client. Pour une exploitation commerciale, la différence entre savoir exactement ce que l’on a et devoir deviner, c’est la différence entre établir un devis précis et absorber le coût d’un travail raté — ou vendre en trop un stock déjà sur un plateau d’impression.
Ce billet décrit le système bout en bout que nous avons construit chez 3D ETPLUS pour suivre le filament depuis la facture d’achat jusqu’à la buse de l’imprimante et aux niveaux de stock WooCommerce, en combinant des outils open source, du matériel bon marché, des ponts logiciels personnalisés, et — pour l’import initial en masse — un modèle de langage qui lisait les factures et rédigeait ses propres appels API.
Le système comporte cinq couches, chacune résolvant un problème distinct :
- Spoolman comme base de données d’inventaire centrale, étendue pour comprendre plusieurs formats de tags NFC
- Des lecteurs NFC sur chaque imprimante qui relient les bobines physiques à l’inventaire logiciel dès leur chargement
- Un fork de Moonraker qui suit la consommation de filament par extrudeur pour les machines multi-outils sans nécessiter de modifications des macros
- Un pont Snapmaker qui intègre une imprimante IDEX à firmware propriétaire dans le même écosystème que nos machines Klipper
- Un script de synchronisation qui traduit les données de consommation de Spoolman en niveaux de stock WooCommerce en temps réel sur le site de production
La Fondation : Spoolman avec Support NFC
Spoolman est un service web auto-hébergé pour le suivi des bobines de filament. Par défaut, il s’intègre à Klipper/Moonraker et OctoPrint, fournit une API REST et permet de signaler la consommation de filament pendant les impressions. Le projet upstream est solide — nous l’utilisons comme colonne vertébrale du système — mais il ne sait pas lire les tags NFC que les fabricants intègrent de plus en plus dans leurs emballages.
Notre fork de Spoolman ajoute l’identification des bobines par NFC à la fois au niveau du navigateur et du serveur, avec la prise en charge de trois formats de tags couvrant la majeure partie du marché :
TigerTag (ISO 14443A / NTAG213) est un format binaire utilisé par le filament Bambu Lab et un nombre croissant de fabricants tiers. Le tag stocke un identifiant produit ; les spécifications réelles du filament se trouvent dans la base de données externe de TigerTag, que le fork interroge au moment du scan pour récupérer le type de matériau, la couleur, le diamètre et la densité. Un TigerTag non reconnu déclenche la création automatique d’une bobine à partir de la recherche en base — scanner une nouvelle bobine la fait apparaître dans Spoolman sans aucune saisie manuelle.
OpenPrintTag (ISO 15693 / NFC-V) est le standard ouvert NDEF/CBOR de Prusa. Les tags portent des UUIDs par bobine et intègrent les données de filament directement sur la puce, les rendant autonomes sans nécessiter de recherche externe.
Qidi (ISO 14443A / MIFARE Classic 1K) couvre le filament des imprimantes Qidi. Le format de tag encode le type de matériau et les données de couleur dans la disposition de secteurs propriétaire de Qidi.
Le fork expose deux interfaces de scan. Le chemin basé sur le navigateur utilise l’API Web NFC — supportée sur Chrome pour Android — permettant à quiconque dispose d’un téléphone compatible de tapoter une bobine pour la faire apparaître dans Spoolman. Le chemin côté serveur utilise un lecteur NFC USB connecté à l’hôte Spoolman, permettant le scan depuis une station fixe. Les deux chemins partagent la même logique d’identification et de création automatique.
Amorcer 300 kg d’Inventaire avec un LLM
Avant que le scan NFC ne soit utile, nous avions besoin de l’inventaire existant dans Spoolman. Nous avions reçu une unique commande groupée d’un seul fabricant — environ 300 kg de filament, une seule marque, déclinée en plusieurs matériaux et couleurs — et ce stock n’existait que sous forme de lignes sur une facture d’achat, sans aucune base de données structurée.
Saisir tout cela manuellement aurait pris des heures et aurait été source d’erreurs. À la place, nous avons fourni les PDFs de factures à Claude en décrivant ce dont nous avions besoin : pour chaque ligne, identifier la marque de filament, le matériau, la couleur, le diamètre et la quantité ; rechercher la fiche technique du fabricant pour compléter la densité et d’autres spécifications techniques ; puis générer les appels API REST Spoolman appropriés pour créer les entrées de bobines.
Le processus a mieux fonctionné qu’espéré. Le LLM a correctement analysé les lignes de facture, trouvé les fiches techniques sur les sites des fabricants et produit des requêtes curl POST valides ciblant notre instance Spoolman. Quelques entrées ont nécessité des corrections mineures — une valeur de densité différant entre la fiche technique et une mesure communautaire, un nom de couleur légèrement différent — mais la majeure partie de l’inventaire a été importée en une seule session.
La leçon pratique : un LLM combiné à une API REST structurée constitue un pipeline ETL capable pour des documents semi-structurés. La facture est la source, la fiche technique est l’enrichissement, l’API est la cible, et le LLM gère la transformation. Aucun script personnalisé requis, aucun format intermédiaire à maintenir.
NFC sur l’Imprimante : klipper-nfc-daemon
Faire entrer une bobine dans Spoolman n’est que la moitié du problème. L’autre moitié consiste à indiquer à l’imprimante — et à Spoolman — quelle bobine est réellement chargée. Sans ce lien, Klipper et Moonraker n’ont aucun moyen de savoir quel poids de bobine décrémenter lorsque du filament est consommé.
klipper-nfc-daemon fonctionne comme un service sur l’hôte Klipper et gère ce lien automatiquement. Nos machines Klipper tournent sur la carte contrôleur Recore d’Intelligent Agent, une carte ARM conçue spécifiquement qui remplace la combinaison Raspberry Pi + MCU par une seule unité. Le matériel NFC est un lecteur PN532 connecté via un câble USB-UART.
Quand une bobine est chargée, l’opérateur la tapote contre le lecteur. Le daemon lit le tag, interroge le point de terminaison NFC de Spoolman pour trouver l’enregistrement de bobine correspondant, et lie cette bobine à l’outil actif dans Spoolman. À partir de là, chaque millimètre d’extrusion signalé par Klipper est attribué à la bonne bobine.
Pour les imprimantes avec plusieurs extrudeurs — une machine IDEX, un changeur d’outil, un système multi-matériaux — le daemon présente une boîte de dialogue demandant dans quel outil la bobine scannée est chargée. L’opérateur sélectionne l’outil et le daemon complète le lien pour cet extrudeur spécifique. Cette interaction est minimale : tapoter la bobine, choisir l’outil si demandé, terminé.
Une remarque sur le matériel : le PN532 via USB-UART ne gère que les tags de Type A (NTAG213/215). OpenPrintTag utilise NFC-V (Type V / ISO 15693), qui nécessite un chipset de lecteur différent. Pour une flotte qui mélange filaments TigerTag et OpenPrintTag, le chemin de scan côté serveur dans le fork Spoolman gère NFC-V via un téléphone, tandis que le PN532 gère TigerTag à l’imprimante.
L’économie des coûts favorise largement le NTAG213. Les puces NTAG213 vierges coûtent environ 0,02 $ l’unité pour des commandes de 100 unités, ce qui les rend essentiellement gratuites à l’échelle d’une flotte. Les tags NFC-V sont nettement plus chers. Surtout, les tags NTAG213 sont réinscriptibles — le même tag physique peut être effacé et réassigné à une nouvelle bobine quand l’ancienne est vide, ce qui signifie que le pool de tags s’amortit sur toute la durée de vie de la flotte plutôt qu’à raison d’un tag par bobine.
Suivi du Filament Multi-Outils : Le Fork Moonraker
Le Moonraker upstream gère bien l’intégration Spoolman pour les machines à extrudeur unique. Pour les imprimantes IDEX et multi-outils, l’implémentation upstream ne suit qu’une seule bobine active — reflétant une hypothèse de conception originale selon laquelle il n’y a qu’un seul filament actif à tout moment.
Notre fork Moonraker étend l’intégration Spoolman pour suivre une bobine par outil, sans nécessiter de modifications des macros d’imprimante. L’approche est purement au niveau de l’API.
Les changements clés :
Stockage des bobines par outil. Plutôt qu’une seule clé de base de données spoolman.spool_id, le fork stocke spoolman.spool_id.0, spoolman.spool_id.1, et ainsi de suite — une clé par outil. Les configurations à extrudeur unique existantes migrent automatiquement au premier démarrage.
Points de terminaison API conscients des outils. Le point de terminaison HTTP GET/POST /server/spoolman/spool_id et les gestionnaires WebSocket RPC correspondants acceptent un paramètre optionnel tool. Cela correspond à la forme d’API attendue par le panneau Spoolman multi-extrudeur de Mainsail.
Champ de réponse tool_spool_map. Mainsail utilise ce champ pour passer du mode d’affichage à bobine unique au mode d’affichage par outil. Sans lui, Mainsail revient au comportement à bobine unique quelle que soit la configuration du backend. L’ajouter n’a nécessité qu’un champ de réponse ; le changement de comportement de l’UI a été immédiat.
Ce fork est la PR upstream que nous avons soumise — les commits sont propres, la couverture de tests est là, et les changements sont minimaux. En attendant qu’elle soit intégrée, utiliser notre fork signifie que la fonctionnalité est disponible sans attendre.
Intégration du Snapmaker J1S dans l’Écosystème
Tout ce qui est sur le plateau ne tourne pas sous Klipper. Notre Snapmaker J1S est une imprimante IDEX avec un matériel capable — double extrusion indépendante, un volume de construction correct, une mécanique fiable — mais elle tourne sur le firmware propriétaire de Snapmaker et parle un protocole binaire appelé SACP. Du point de vue de notre workflow basé sur Mainsail, c’était une île.
snapmaker-moonraker est le pont que nous avons construit pour la connecter. Le pont fonctionne aux côtés d’une instance Klipper/Moonraker et traduit entre l’API Moonraker qu’attendent Mainsail, PrusaSlicer et Spoolman, et le protocole binaire SACP que parle réellement le J1S.
L’intégration est suffisamment profonde pour que le J1S soit maintenant indiscernable d’une machine Klipper au niveau des outils :
- Les fichiers sont téléchargés depuis PrusaSlicer directement vers Mainsail, qui les transfère via le pont à l’imprimante
- Un post-processeur GCode réécrit les numéros d’outils, génère l’en-tête de métadonnées Snapmaker V1 requis par l’écran tactile, extrait les données de miniatures du slicer et les convertit au format que l’IHM du J1S affiche
- Le contrôle d’impression (démarrer, pause, reprendre, annuler) passe par des commandes SACP natives, maintenant l’IHM de l’écran tactile synchronisée
- Le rapport et le contrôle de température, le contrôle du ventilateur et la progression de l’impression sont tous exposés via l’API Moonraker et visibles dans Mainsail
- L’intégration Spoolman suit la consommation de filament par extrudeur, en utilisant le même mécanisme de bobine par outil que nos autres machines multi-extrudeurs
- Les modes IDEX Copie et Miroir fonctionnent : PrusaSlicer signale le mode via M605, le post-processeur l’intègre dans l’en-tête Snapmaker V1, et le pont envoie la commande SACP correspondante avant le démarrage de l’impression
Le pont est livré avec 12 profils d’imprimante PrusaSlicer couvrant les trois modes IDEX sur huit préréglages de qualité.
Le principe de conception tout au long a été de pousser toute l’adaptation dans le pont et de laisser l’écosystème environnant inchangé. Mainsail ne sait pas qu’il parle à un Snapmaker. Spoolman ne sait pas qu’il suit une machine propriétaire. PrusaSlicer utilise la même configuration dual-extrudeur qu’il utilise pour n’importe quelle autre imprimante IDEX. Le pont absorbe la complexité pour que rien d’autre n’ait à le faire.
Un compte rendu technique détaillé du développement du pont est disponible dans notre article précédent.
Boucler la Boucle : De Spoolman à WooCommerce
Le dernier élément connecte le système d’inventaire à la boutique. Le même stock de filament qui alimente les imprimantes est également listé à la revente — ce qui signifie que chaque travail d’impression est un événement potentiel de niveau de stock. Maintenir des quantités listées précises est important dans les deux sens : la survente crée des commandes en attente pour du stock déjà dans une buse, et la sous-vente représente du chiffre d’affaires manqué sur du matériel assis sur une étagère.
La source de vérité pour l’inventaire de filament est Spoolman. Au fur et à mesure que les bobines sont utilisées dans la flotte — consommées par des travaux d’impression suivis via Klipper, le pont Snapmaker, ou enregistrées manuellement — Spoolman reflète le poids restant mis à jour sur chaque bobine.
Un cron job tournant sur le serveur de staging gère la réconciliation :
-
Interroger Spoolman pour tous les enregistrements de bobines. Identifier les bobines qui ont été utilisées — soit par la présence d’un horodatage
last_used, soit par un poids restant inférieur au poids original de la bobine. -
Calculer le stock disponible par produit filament (marque, matériau, couleur, diamètre), en agrégeant le poids restant sur toutes les bobines correspondantes.
-
Interroger la boutique WooCommerce de staging pour vérifier que ses niveaux de stock actuels correspondent aux données Spoolman. Cela détecte toute dérive entre les deux systèmes avant de pousser vers la production.
-
Pousser en production. Une fois l’inventaire de staging réconcilié, le script met à jour les niveaux de stock de la boutique WooCommerce de production via l’API REST.
L’état final : quand un travail d’impression se termine et que Spoolman enregistre le filament consommé, cette consommation circule via le cron job jusqu’aux niveaux de stock de produits visibles par les clients sur le site. La latence est d’un cycle de cron — généralement moins d’une heure.
Le Système dans son Ensemble
Chaque pièce a été construite pour résoudre un problème spécifique, mais elles composent quelque chose de plus grand que leurs parties :
Une nouvelle bobine arrive. La PDF de facture va au LLM, qui crée l’entrée Spoolman. La bobine reçoit un tag NFC si elle n’en a pas déjà un.
La bobine est chargée sur une imprimante. L’opérateur la tapote contre le lecteur PN532. Le daemon lie la bobine physique à l’outil correct dans Spoolman. S’il s’agit d’une machine multi-extrudeur, il sélectionne quel outil. Toute l’interaction prend cinq secondes.
Un travail tourne. Klipper (ou le pont Snapmaker) signale l’extrusion en temps réel. Moonraker débite la bonne bobine. S’il s’agit d’un travail dual-extrudeur, les deux bobines sont suivies indépendamment.
Le travail se termine. Spoolman a des poids restants mis à jour. Dans l’heure, le cron job récupère le changement, vérifie contre le staging, et met à jour le stock produit WooCommerce.
Pas de tableurs. Pas de comptages de stock manuels. Pas de réconciliation en fin de journée. L’état de l’inventaire est continu et précis parce que chaque événement de consommation est capturé au moment où il se produit.
Ce Qui Est Ouvert, Ce Qui Ne L’Est Pas
Les quatre composants logiciels sont open source :
- goeland86/spoolman — Fork Spoolman avec support NFC TigerTag, OpenPrintTag et Qidi
- goeland86/klipper-nfc-daemon — Daemon NFC vers Spoolman pour les imprimantes Klipper
- goeland86/moonraker — Fork Moonraker avec suivi Spoolman par outil
- goeland86/snapmaker-moonraker — Pont Snapmaker J1S vers Moonraker
Le script de synchronisation WooCommerce est spécifique à notre configuration de boutique et n’est pas actuellement publié, mais l’approche — API REST Spoolman en entrée, API REST WooCommerce en sortie, avec une étape de vérification sur le staging — est simple à reproduire.
Le coût matériel pour l’intégration d’une seule imprimante est inférieur à 10 $ pour le lecteur PN532 et le câble USB-UART. La pile logicielle tourne sur la même carte Recore qui fait tourner Klipper, donc aucune capacité de calcul supplémentaire à provisionner.
Cela a été construit avec l’aide substantielle de Claude (Anthropic). Le LLM a été impliqué à chaque couche : écriture des implémentations initiales de protocoles, débogage de l’analyse binaire, génération des appels curl d’import de bobines à partir de PDFs de factures, et rédaction des articles qui le décrivent. La déclaration d’IA dans le dépôt snapmaker-moonraker s’applique à l’ensemble de cet écosystème.
