Etikettendruck mit Python-Feldskripten automatisieren
Das Etikett stimmt fast immer. Das Datum ist veraltet, die Seriennummer hat ihre führenden Nullen verloren, und die Prüfziffer fehlt, bevor der Barcode gescannt werden kann. Also öffnet jemand die Etikettenvorlage im Designer, bearbeitet drei Felder, drückt auf Drucken – und macht am nächsten Morgen genau dasselbe.
Diese Bearbeitung gehört nicht in eine Vorlage. Sie gehört in Code, der im Moment des Druckens ausgeführt wird. Mit RSJ LPSNG können Sie einen Python-Skriptblock direkt an ein Etikettenfeld anhängen, sodass die Transformation innerhalb der Vorlage stattfindet – kein Vorverarbeitungsschritt, kein Ritual „erst die CSV korrigieren" zwischen Ihrem ERP und dem Drucker.
In diesem Artikel geht es um Automatisierung auf Feldebene: Was ein Feldskript ist, wie Sie es einmal einrichten, wie Sie es über die Web-Service-API steuern und wie Sie verhindern, dass es Ihre Produktionslinie stillschweigend lahmlegt.
Zwei angrenzende Themen werden an anderer Stelle behandelt: Inhalte, die sich pro Auftrag ändern, finden Sie unter Building Order-Specific Labeling on Top of a Label Printing API, und datengesteuerte Etiketten aus Tabellenkalkulationen unter How to Create Labels from Excel Data Files and Lookup Tables. Hier bleiben wir beim Feld.
Warum den Etikettendruck mit Python-Feldskripten automatisieren?
Feldskripte laufen innerhalb der Etikettenvorlage. Der Python-Block wird an ein Feld angehängt und erhält Zugriff auf den aktuellen Wert dieses Feldes, den er ändern kann, bevor das Etikett gerendert wird. Diese eine Designentscheidung verändert die Pipeline:
- Keine externe Vorverarbeitung. Sie brauchen kein Skript, das Ihre Eingabedaten vor dem Absenden umschreibt. Die Daten gehen so hinein, wie sie sind; das Etikett korrigiert, was korrigiert werden muss.
- Konsistenz über alle Clients hinweg. Das Skript reist mit dem Etikett. Ob der Auftrag aus der Web-UI, der Web-Service-API oder dem LPSNG Player kommt – dasselbe Feld erhält dieselbe Behandlung.
- Die Logik ist überprüfbar. Sie liegt neben dem Feld, das sie betrifft, nicht in einem Cron-Job auf dem Laptop von irgendjemandem.
Die Aufgaben, die das rechtfertigen, sind langweilig und repetitiv:
| Aufgabe | Manueller Ansatz | Feldskript |
|---|---|---|
| Druckzeitstempel | Heutiges Datum ins Feld eintippen | Wert zur Renderzeit formatieren |
| Seriennummern | Von Hand auffüllen, eine vergessen, neu drucken | Auf feste Breite normalisieren |
| Prüfziffern | In einer Tabellenkalkulation berechnen | Aus dem Feldwert berechnen |
| Abgeleitete Labels | Wert aus einem anderen Feld kopieren | Auf das Quellfeld verweisen |
Nichts davon ist schwierig. Das ist der Punkt – es ist zu klein, um einen eigenen Service zu rechtfertigen, und zu häufig, um es weiterhin von Hand zu machen.
Einmalige Einrichtung: Etikett und Skript vorbereiten
Die Einrichtung ist ein einmaliger Vorgang pro Feld. Sie benötigen das Label Studio, keine lokale Python-Umgebung.
- Öffnen Sie das Etikett, das Sie automatisieren möchten, im LPSNG Label Studio und wählen Sie das Feld aus. Wählen Sie ein Feld, das einem Text- oder Barcode-Element zugeordnet ist.
- Hängen Sie einen Python-Skriptblock über die Feldskript-API an dieses Feld an. Das Skript wird von der Plattform zusammen mit dem Etikett gespeichert und verwaltet – auf dem Druckclient muss kein Interpreter installiert werden.
- Nutzen Sie den Skriptkontext. Der Block sieht den aktuellen Wert des Feldes und gibt vor dem Drucken einen geänderten zurück. Die genauen Kontextvariablen sind in der Python-API-Referenz definiert – lesen Sie sie einmal, und kopieren Sie dann das Muster.
- Speichern Sie das Etikett. Von nun an führt jeder Auftrag, der dieses Etikett rendert, das Skript aus.
Ein minimaler Block, der eine Seriennummer normalisiert:
# Field: serial
# Runs before rendering. Input: the value passed in the print job.
raw = str(value).strip()
if raw.isdigit():
value = f"SN-{int(raw):06d}"
else:
value = raw.upper()
Und einer, der die Druckzeit stempelt, statt den Daten zu vertrauen:
# Field: printed_at
from datetime import datetime
value = datetime.now().strftime("%Y-%m-%d %H:%M")
Der Vorteil, dies in einer verwalteten Plattform statt im eigenen Code zu tun, besteht darin, dass das Skript Teil des Etiketts ist: Es wird mit ihm versioniert, über Aufträge hinweg wiederverwendet und kann nicht mit der Vorlage aus dem Takt geraten.
Wiederverwendung ist der eigentliche Gewinn. Sobald ein Skript korrekt ist, hängen Sie denselben Block an jedes Feld an, das dieselbe Transformation benötigt – über Etiketten und Drucker hinweg. Zehn Etikettenvorlagen, die alle Seriennummern auf dieselbe Weise drucken, sind zehn Vorlagen, die alle auf dieselbe Weise fehlschlagen – und eine Stelle, an der man es beheben kann.
Die automatisierte Pipeline aufbauen: von den Daten zum Druck
Mit dem angehängten Skript lautet die Pipeline: authentifizieren, einen Druckauftrag absenden, das Etikett die Arbeit machen lassen.
Einmal authentifizieren
Die Web-Service-Schnittstelle von LPSNG verwendet OAuth2 mit einem vereinfachten Registrierungsprotokoll, das ein externes System über eine einzige URL verbindet. Führen Sie die Registrierung einmal durch, speichern Sie das Token in Ihrem Secret Store und halten Sie es aus Ihrem Repository heraus:
export LPSNG_BASE_URL="https://lpsng.rsj.de" # host of your edition
export LPSNG_TOKEN="<token from the OAuth2 registration>"
Einen Auftrag absenden
Die Web-Service-API nimmt Druckaufträge entgegen, rendert einzelne Etiketten als PDF oder PNG und unterstützt den direkten Druck. Die genauen Endpunktpfade und das Payload-Schema stammen aus der Dokumentation der Web-Service-Schnittstelle – das folgende Snippet zeigt die Form des Aufrufs, nicht einen Ersatz für die Referenz:
import os
import requests
BASE = os.environ["LPSNG_BASE_URL"]
TOKEN = os.environ["LPSNG_TOKEN"]
job = {
# Payload keys are illustrative — use the schema from the
# web service interface documentation.
"label": "shipping-label",
"printer": "warehouse-zebra-01",
"data": {
"order_id": "A-10442",
"serial": "42", # the field script turns this into SN-000042
"printed_at": "", # left empty on purpose
},
}
resp = requests.post(
f"{BASE}/<print-endpoint-from-the-docs>",
headers={"Authorization": f"Bearer {TOKEN}"},
json=job,
timeout=30,
)
resp.raise_for_status()
print(resp.json()) # the response gives you the reference to poll
Beachten Sie, was der Aufrufer nicht tut: Er formatiert die Seriennummer nicht und füllt printed_at nicht aus. Das ist jetzt Aufgabe des Etiketts.
Der interessante Fall: einen Wert berechnen
Die Transformation, die sich am schnellsten bezahlt macht, ist eine Prüfziffer, denn eine falsche bedeutet, dass ein Scanner das Etikett an der Packstation ablehnt. Das Skript berechnet sie aus dem Wert, den der Auftrag übergeben hat:
# Field: ean
# Compute the mod-10 check digit for a 12-digit payload.
digits = [int(c) for c in str(value) if c.isdigit()]
if len(digits) == 12:
checksum = (10 - (sum(digits[::2]) + 3 * sum(digits[1::2])) % 10) % 10
value = "".join(map(str, digits)) + str(checksum)
else:
# Defensive: don't render an invalid barcode silently.
value = "INVALID"
Da das Skript den Feldwert vor dem Rendern des Barcodes ändert, spiegelt der Barcodeinhalt das berechnete Ergebnis wider. Sie benötigen keinen separaten Barcode-Generierungsschritt.
Der beschwerliche Weg, zum Vergleich
Die Alternative besteht darin, diese Werte vorgelagert zu berechnen: ein Präprozessor, der Ihre Auftragsdaten liest, jedes Feld umschreibt und erst dann die API aufruft. Das funktioniert – bis Präprozessor und Etikettenvorlage nicht mehr übereinstimmen (einer füllt auf sechs Stellen auf, der andere auf acht) und es niemand bemerkt, bis eine Palette mit unlesbaren Seriennummern versandt wird. Die Logik in der Vorlage zu belassen bedeutet, dass es pro Feld genau eine Definition von „korrekt" gibt.
Wenn Sie dieselbe Etikettenlogik irgendwo ohne Browser ausführen müssen, ist der LPSNG Player eine eigenständige Kommandozeilen-Druck-Engine, die ein Paket plus Daten entgegennimmt und PDF, PNG, JSON, einen direkten Druck oder ein ESL-Update erzeugt. Dasselbe Etikett, dieselben Skripte, anderer Ausführungskontext.
Überwachung und Fehlerbehandlung beim automatisierten Drucken
Eine automatisierte Pipeline, die stillschweigend fehlschlägt, ist schlimmer als eine manuelle, weil niemand auf das Etikett schaut.
Beobachten Sie die Warteschlange. Die Web-UI hat eine Auftragswarteschlange, und über die Web-Service-API können Sie den Auftragsstatus prüfen. Fragen Sie die Referenz, die Sie bei der Übermittlung zurückbekommen haben, mit Backoff ab und schlagen Sie Alarm, wenn ein Auftrag zu lange im selben Zustand verharrt:
import time
def wait_for_job(session, base, job_ref, timeout=120, interval=5):
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
status = session.get(
f"{base}/<job-status-endpoint-from-the-docs>/{job_ref}",
timeout=15,
).json()
if status.get("state") in ("done", "failed"):
return status
time.sleep(interval)
raise TimeoutError(f"job {job_ref} did not finish in {timeout}s")
Die veröffentlichte Schnittstelle dokumentiert Auftragsübermittlung, Einzeletikett-Rendering, direkten Druck und Status – sie beschreibt keine Webhooks, daher ist Polling das Muster, auf dem Sie aufbauen sollten. Wenn Sie Push-Benachrichtigungen benötigen, behandeln Sie das als Lücke, die Sie auf Ihrer Seite lösen müssen.
Scheitern Sie defensiv innerhalb des Skripts. Entscheiden Sie, was ein fehlerhafter Eingabewert tun soll, bevor es passiert. Ein Skript, das INVALID in ein Barcodefeld rendert, erweist Ihnen einen größeren Dienst als eines, das eine Exception auslöst und den gesamten Auftrag mitreißt – oder eines, das eine Exception auslöst, verschluckt wird und den unformatierten Wert druckt. Prüfen Sie in der Dokumentation zur Feldskript-API, wie die Plattform einen fehlschlagenden Block meldet, und schreiben Sie Ihre Skripte so, dass der Fehlermodus der von Ihnen gewählte ist.
Probelauf mit gerendertem Output. Die Web-Service-API kann ein einzelnes Etikett als PDF oder PNG rendern. Rendern Sie, bevor Sie drucken. Es ist der günstigste Smoke-Test, den Sie haben: Füttern Sie das Skript mit einer bekannten Eingabe, schauen Sie sich die Ausgabe an und richten Sie erst dann die Pipeline auf den Drucker.
Best Practices für Python-Feldskripte
- Eine Transformation pro Skript. Ein Block, der ein Datum formatiert und einen Kundennamen nachschlägt und eine Summe neu berechnet, ist ein Block, den niemand um 2 Uhr nachts debuggen wird.
- Seien Sie idempotent. Nachdrucke kommen vor – ein hängengebliebenes Etikett, ein zurückgewiesener Karton, ein Bediener, der zweimal auf Drucken drückt. Wenn
SN-000042erneut durch das Skript läuft, sollteSN-000042herauskommen, nichtSN-SN-000042. Prüfen Sie, ob der Wert bereits die erwartete Form hat, bevor Sie ihn transformieren. - Versionieren Sie die Skripte außerhalb von LPSNG. Halten Sie die Etikettendefinitionen und ihre Skriptblöcke in Git, mit einer kurzen Notiz, warum jedes existiert. Die Plattform speichert und führt sie aus; sie ersetzt kein Code-Review.
- Daten niemals fest codieren. Keine festen Kundennummern, keine festen Datumsangaben, keine druckerspezifische Verzweigungslogik. Alles sollte aus dem Feldwert oder aus Daten stammen, die im Druckauftrag übergeben werden.
- Halten Sie es leichtgewichtig. Vermeiden Sie lang laufende Operationen. Feldskripte laufen im Druckpfad, und ein langsames Skript bedeutet ein langsames Etikett.
- Testen Sie mit echten Kuriositäten. Leere Strings, führende Nullen, bereits formatierte Werte, viel zu lange Werte. Genau dort brechen Feldskripte.
FAQ
Können Python-Feldskripte auf externe APIs oder Datenbanken zugreifen?
Die Feldskript-API ist dafür ausgelegt, Feldwerte innerhalb des Etikettenkontexts abzurufen und zu ändern. Für externe Daten würden Sie diese typischerweise in den Druckauftragsdaten übergeben. Prüfen Sie die LPSNG-Dokumentation auf etwaige Einschränkungen bei externen Aufrufen.
Welche Python-Version und welche Bibliotheken stehen in Feldskripten zur Verfügung?
Die genaue Python-Umgebung ist in der LPSNG-Dokumentation zur Feldskript-API angegeben. Es wird empfohlen, Funktionen der Standardbibliothek zu verwenden und Skripte leichtgewichtig zu halten.
Wie funktionieren Feldskripte mit Barcodes?
Skripte können den Feldwert ändern, bevor der Barcode gerendert wird, sodass Sie Prüfziffern berechnen, Daten formatieren oder Transformationen anwenden können, die den Barcodeinhalt beeinflussen.
Gibt es ein Limit für die Ausführungszeit von Skripten?
Feldskripte sollten effizient sein. Obwohl in den bereitgestellten Informationen keine konkreten Limits genannt sind, ist es Best Practice, lang laufende Operationen zu vermeiden. Entnehmen Sie etwaige Einschränkungen der LPSNG-Dokumentation.
Fazit
Das Muster ist einfach, und deshalb funktioniert es: Hängen Sie die Transformation einmal an das Feld an, authentifizieren Sie sich einmal, senden Sie für immer Aufträge ab. Die manuelle Bearbeitung verschwindet, und die Definition eines korrekten Etiketts lebt an genau einer Stelle – der Vorlage – statt bei der Person, die heute Morgen zufällig am Drucker stand.
Fangen Sie mit einem Feld an. Nehmen Sie das, das Ihr Team am häufigsten bearbeitet, schreiben Sie zehn Zeilen Python, rendern Sie ein PDF und vergleichen Sie es mit einem bekannt guten Etikett. Dann machen Sie das nächste.
Next Generation Label Printing System ist die verwaltete Plattform, die diese Skripte ausführt – das Label Studio, die OAuth2-Web-Service-Schnittstelle, die Auftragswarteschlange und den Player – ohne eine lokale Python-Umgebung, die gepflegt werden muss. Das Gesamtbild sehen Sie unter lpsng.rsj.de.
Verwandte Beiträge
- Zebra Label Software Alternative: A Browser-Based Approach
- Building Order-Specific Labeling on Top of a Label Printing API
- How to Create Labels from Excel Data Files and Lookup Tables
