Bon fuer die Kasse auf einem USB-Bondrucker ausgeben

Der Kunde soll mit einem Zettel zur Kasse gehen koennen, auf dem steht, was
er zahlen muss. Drei Wege fuehren jetzt zu einem Bon: der Knopf "Bon" auf der
Timer-Karte druckt den Zwischenstand und laesst den Timer weiterlaufen,
"Beenden" druckt den Endbeleg, und in der Historie laesst sich jeder Beleg
nachdrucken.

Der Drucker haengt per USB an einem Raspberry Pi und ist damit vom
Timer-Server aus nicht direkt erreichbar. Auf dem Pi laeuft deshalb eine
kleine Bruecke (deploy/bondrucker/, nur Python-Standardbibliothek), die
fertige ESC/POS-Daten per HTTP annimmt. Das Bon-Layout bleibt bewusst hier
im Repo, damit Aenderungen daran nicht auf dem Pi angefasst werden muessen.

Beim Beenden wird erst gespeichert und dann gedruckt. Eine leere Papierrolle
ist damit ein Papierproblem und kein Datenproblem - der Vorgang steht in der
Historie, die Oberflaeche sagt ausdruecklich, dass der Bon nicht gedruckt
wurde, und nennt den Grund.

Ohne PRINTER_HOST in der .env ist die Druckfunktion aus und die App verhaelt
sich unveraendert.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kerim (portable/claudecode)
2026-09-04 20:37:12 +02:00
co-authored by Claude Opus 5
parent 5e83999950
commit 70756f3762
13 changed files with 1424 additions and 27 deletions
+67
View File
@@ -0,0 +1,67 @@
#!/bin/bash
# ---------------------------------------------------------------------------
# Bondrucker-Bruecke auf dem Raspberry Pi einrichten.
#
# Aufruf auf dem Pi: sudo bash install.sh [TOKEN]
# Ohne TOKEN wird eins erzeugt und am Ende ausgegeben - dieser Wert gehoert
# anschliessend in die .env des Timer-Servers (PRINTER_TOKEN).
# ---------------------------------------------------------------------------
set -euo pipefail
QUELLE="$(cd "$(dirname "$0")" && pwd)"
ZIEL=/opt/bondrucker
TOKEN="${1:-}"
if [ "$(id -u)" -ne 0 ]; then
echo "Bitte mit sudo starten." >&2
exit 1
fi
echo "--- Dienstbenutzer"
if ! id bondrucker >/dev/null 2>&1; then
useradd --system --no-create-home --shell /usr/sbin/nologin --groups lp bondrucker
echo " Benutzer 'bondrucker' angelegt (Gruppe lp)."
else
usermod -aG lp bondrucker
echo " Benutzer 'bondrucker' war schon da."
fi
echo "--- Programmdateien nach $ZIEL"
install -d -m 755 "$ZIEL"
install -m 755 "$QUELLE/print-server.py" "$ZIEL/print-server.py"
[ -f "$QUELLE/README.md" ] && install -m 644 "$QUELLE/README.md" "$ZIEL/README.md"
echo "--- Konfiguration"
install -d -m 750 /etc/bondrucker
if [ -f /etc/bondrucker/env ] && [ -z "$TOKEN" ]; then
echo " /etc/bondrucker/env besteht bereits - Token bleibt unveraendert."
else
[ -n "$TOKEN" ] || TOKEN="$(head -c 24 /dev/urandom | base64 | tr -d '/+=' | head -c 32)"
printf 'PRINT_TOKEN=%s\n' "$TOKEN" > /etc/bondrucker/env
chmod 640 /etc/bondrucker/env
chown root:bondrucker /etc/bondrucker/env
echo " Token geschrieben."
fi
echo "--- udev-Regel (Geraet ueberlebt das Aus- und Einstecken)"
cat > /etc/udev/rules.d/99-bondrucker.rules <<'RULE'
# USB-Bondrucker: Gruppe lp und Schreibrecht, damit der Dienst 'bondrucker'
# ohne root drucken kann. Gilt fuer alle usblp-Geraete.
SUBSYSTEM=="usbmisc", KERNEL=="lp[0-9]*", GROUP="lp", MODE="0660"
SUBSYSTEM=="usb", ATTR{bInterfaceClass}=="07", GROUP="lp", MODE="0660"
RULE
udevadm control --reload-rules || true
udevadm trigger --subsystem-match=usbmisc || true
echo "--- systemd"
install -m 644 "$QUELLE/bondrucker.service" /etc/systemd/system/bondrucker.service
systemctl daemon-reload
systemctl enable --now bondrucker.service
sleep 1
systemctl --no-pager --lines=5 status bondrucker.service || true
echo
echo "--- Fertig"
echo "Status abfragen: curl -s http://$(hostname -I | awk '{print $1}'):9100/status"
echo "Token fuer die .env des Timer-Servers:"
echo " PRINTER_TOKEN=$(sed -n 's/^PRINT_TOKEN=//p' /etc/bondrucker/env)"