Drucker-Pi holt sich die Einrichtung, statt sie geschickt zu bekommen
Bisher richtete die App den Pi per SSH ein: Adresse, Benutzer und Passwort ins Webformular, Knopf druecken. Das verlangte ein SSH-Passwort in einem Browser, ein weiteres Paket (ssh2) und eine Verbindung vom Server zum Pi. Jetzt andersherum. Die App legt einen Link bereit und wartet. Auf dem Pi wird das Skript geholt und gestartet, dort wird der Drucker ausgewaehlt, und am Ende meldet sich der Pi von selbst an. Wer einen Drucker ansteckt, steht ohnehin am Pi - dort gehoert auch die Frage hin, welcher es sein soll. Die Auswahl zeigt Klartextnamen aus dem sysfs: "EPSON TM-T88IV" statt "lp0". Bei mehreren Druckern ist das der Unterschied zwischen Wissen und Raten. Das ausgelieferte Skript ist zusammengesetzt, nicht statisch: einrichten.sh ist eine Vorlage, in die setup.js Adresse, Code, print-server.py und die systemd-Unit einsetzt. Heraus kommt EINE Datei - auf dem Pi ist nichts nachzuladen, und eine halb geglueckte Uebertragung kann es nicht geben. Zwei Endpunkte muessen ohne Anmeldung auskommen, weil der Pi sich bei Authentik nicht anmelden kann. Der Einrichtungscode ist dort der einzige Schluessel: 32 Zeichen, gilt einmal und 30 Minuten, nur im Arbeitsspeicher, zeitkonstant verglichen, hinter einem eigenen Zaehler. Die Adresse des Pi wird der Verbindung entnommen und nicht dem Rumpf der Anmeldung - was der Pi ueber sich behauptet, koennte auch jemand anders behaupten. Die eigene Adresse leitet die App aus dem Host-Kopf ab und prueft sie streng, statt sie zu maskieren: der Wert landet in einem Shell-Skript. Geprueft am echten Pi (Debian 13, TM-T88IV): Link erzeugen, am Pi abholen, Drucker aus der Liste waehlen, Anmeldung, Uebernahme, Probedruck. Dazu die Abweise: verbrauchter Code, falscher Code, Abholung ohne Code, und dass die uebrige API weiterhin 401 liefert. Entfaellt: provision.js, install.sh, die Abhaengigkeit ssh2, das SSH-Formular. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8c5cdf16c4
commit
e68daee457
14 files changed
+834
-605
No files matched your search
+46
-31
@@ -14,54 +14,69 @@ Nur Python-Standardbibliothek, kein pip, kein CUPS, kein node.
|
||||
|
||||
## Installation — der übliche Weg
|
||||
|
||||
**Aus der Oberfläche:** ⚙️ Einstellungen → **🔧 Drucker einrichten**. Dort IP,
|
||||
Benutzer und Passwort des Pi eintragen und auf **🚀 Jetzt einrichten** klicken.
|
||||
|
||||
Die App macht dann per SSH genau das, was unten von Hand steht: Dateien
|
||||
übertragen, `install.sh` mit einem frisch erzeugten Token starten, aufräumen
|
||||
und nachsehen, ob der Dienst antwortet. Anschließend übernimmt sie den Drucker
|
||||
selbst — es ist **nichts** mehr in der `.env` einzutragen. Das Protokoll zeigt
|
||||
Schritt für Schritt, was passiert ist.
|
||||
|
||||
Der Pi braucht dafür nur: SSH, Python 3, systemd, einen Benutzer mit sudo — und
|
||||
den Drucker am USB-Anschluss. Ein frisch aufgesetztes Raspberry Pi OS erfüllt
|
||||
das ab Werk.
|
||||
|
||||
Die Zugangsdaten werden einmal benutzt und danach verworfen. Gespeichert wird
|
||||
allein das erzeugte Drucker-Token.
|
||||
|
||||
## Installation von Hand
|
||||
|
||||
Falls die App den Pi nicht erreicht (anderes Netz, kein sudo per Passwort):
|
||||
**In der Timer-App:** ⚙️ Einstellungen → **🔧 Drucker einrichten** →
|
||||
**🔗 Einrichtungslink erzeugen**. Die App zeigt einen Befehl an. Der wird auf
|
||||
dem Pi in ein Terminal getippt:
|
||||
|
||||
```bash
|
||||
# Dateien auf den Pi kopieren
|
||||
scp print-server.py bondrucker.service install.sh README.md pi@<PI-IP>:/tmp/bondrucker/
|
||||
|
||||
# Dort einrichten
|
||||
ssh pi@<PI-IP>
|
||||
cd /tmp/bondrucker && sudo bash install.sh
|
||||
curl -fsSL "<Link aus der Timer-App>" -o bondrucker.sh
|
||||
sudo bash bondrucker.sh
|
||||
```
|
||||
|
||||
`install.sh` legt an:
|
||||
Das Skript fragt, welcher Drucker verwendet werden soll, richtet alles ein und
|
||||
meldet den Pi anschließend selbst bei der Timer-App an. In der Oberfläche
|
||||
springt die Anzeige von „wartet auf den Pi" auf den fertigen Drucker um. In der
|
||||
`.env` ist **nichts** einzutragen.
|
||||
|
||||
Der Pi braucht dafür nur Python 3, systemd, `curl` und den Drucker am
|
||||
USB-Anschluss. Ein frisch aufgesetztes Raspberry Pi OS erfüllt das ab Werk.
|
||||
|
||||
### Warum der Pi sich meldet und nicht umgekehrt
|
||||
|
||||
Früher hat die App den Pi per SSH eingerichtet. Das verlangte ein SSH-Passwort
|
||||
in einem Webformular und eine Verbindung vom Server zum Pi. Beides ist jetzt
|
||||
weg: kein Passwort verlässt den Laden, und die Verbindung muss nur in eine
|
||||
Richtung funktionieren. Wer einen Drucker anschließt, steht ohnehin am Pi.
|
||||
|
||||
Der Link enthält einen Einrichtungscode. Er gilt **einmal** und **30 Minuten**,
|
||||
liegt nur im Arbeitsspeicher der App und ist nach einem Neustart der App
|
||||
ungültig. Wer den Code hat, kann den Drucker der App umbiegen — er gehört
|
||||
deshalb nicht in einen Chatverlauf.
|
||||
|
||||
## Was das Skript anlegt
|
||||
|
||||
| Was | Wo |
|
||||
|---|---|
|
||||
| Dienstbenutzer `bondrucker` (Gruppe `lp`) | — |
|
||||
| Programm | `/opt/bondrucker/print-server.py` |
|
||||
| Token | `/etc/bondrucker/env` (`0640`, root:bondrucker) |
|
||||
| Token und Gerät | `/etc/bondrucker/env` (`0640`, root:bondrucker) |
|
||||
| udev-Regel | `/etc/udev/rules.d/99-bondrucker.rules` |
|
||||
| Dienst | `bondrucker.service`, aktiviert und gestartet |
|
||||
|
||||
Am Ende gibt das Skript den Wert für das Token aus.
|
||||
|
||||
`install.sh` ist wiederholbar: ein erneuter Aufruf überschreibt Programm und
|
||||
Das Skript ist wiederholbar: ein erneuter Aufruf überschreibt Programm und
|
||||
Token und **startet den Dienst neu**. Ohne den Neustart liefe er mit dem alten
|
||||
Token weiter und würde jeden Druckauftrag mit HTTP 403 ablehnen.
|
||||
|
||||
Schalter für den Fall, dass nicht gefragt werden soll:
|
||||
|
||||
```bash
|
||||
sudo bash bondrucker.sh --device /dev/usb/lp1 --port 9100
|
||||
```
|
||||
|
||||
## Installation ohne die Timer-App
|
||||
|
||||
`einrichten.sh` im Quelltext ist eine Vorlage: die Stellen `@@APP_URL@@`,
|
||||
`@@SETUP_CODE@@`, `@@PRINT_SERVER@@` und `@@SERVICE@@` füllt die App beim
|
||||
Ausliefern. Direkt ausführbar ist sie deshalb nicht.
|
||||
|
||||
Ohne die App werden die Dateien von Hand abgelegt — `print-server.py` nach
|
||||
`/opt/bondrucker/`, `bondrucker.service` nach `/etc/systemd/system/`, dazu
|
||||
`/etc/bondrucker/env` mit `PRINT_TOKEN=` und `PRINT_DEVICE=`. Adresse, Port und
|
||||
Token kommen anschließend von Hand in die Einstellungen der Timer-App.
|
||||
|
||||
## Timer-Server konfigurieren
|
||||
|
||||
Nach der Einrichtung aus der Oberfläche: nichts zu tun.
|
||||
Nach der Einrichtung über den Link: nichts zu tun.
|
||||
|
||||
Nach der Einrichtung von Hand: in ⚙️ Einstellungen unter „Drucker einrichten"
|
||||
lassen sich Adresse, Port und Token auch direkt eintragen. Der Druckerzugang
|
||||
|
||||
@@ -15,7 +15,7 @@ Group=bondrucker
|
||||
SupplementaryGroups=lp
|
||||
|
||||
# Konfiguration. Das Token steht in /etc/bondrucker/env, damit es nicht in der
|
||||
# Versionsverwaltung landet - die Datei legt install.sh an.
|
||||
# Versionsverwaltung landet - die Datei legt einrichten.sh an.
|
||||
Environment=PRINT_DEVICE=/dev/usb/lp0
|
||||
Environment=PRINT_HOST=0.0.0.0
|
||||
Environment=PRINT_PORT=9100
|
||||
|
||||
Executable
+286
@@ -0,0 +1,286 @@
|
||||
#!/bin/bash
|
||||
# ---------------------------------------------------------------------------
|
||||
# Bondrucker-Bruecke einrichten - wird AUF DEM PI ausgefuehrt.
|
||||
#
|
||||
# Dieses Skript wird nicht von Hand gepflegt heruntergeladen, sondern von der
|
||||
# Timer-App ausgeliefert: sie setzt ihre eigene Adresse und einen einmaligen
|
||||
# Einrichtungscode ein und haengt den Druckdienst sowie die systemd-Unit
|
||||
# gleich mit an. Heraus kommt eine einzige Datei, die alles enthaelt.
|
||||
#
|
||||
# Aufruf auf dem Pi:
|
||||
# curl -fsSL "<Link aus der Timer-App>" -o bondrucker.sh
|
||||
# sudo bash bondrucker.sh
|
||||
#
|
||||
# Der Link steht in der Timer-App unter Einstellungen -> Drucker einrichten.
|
||||
#
|
||||
# Ohne Netz zur Timer-App laeuft das Skript trotzdem durch; es zeigt am Ende
|
||||
# Adresse und Token an, die dann von Hand in die Einstellungen gehoeren.
|
||||
#
|
||||
# Schalter:
|
||||
# --device /dev/usb/lp0 Drucker vorgeben, statt danach zu fragen
|
||||
# --port 9100 Lausch-Port der Bruecke
|
||||
# ---------------------------------------------------------------------------
|
||||
set -euo pipefail
|
||||
|
||||
# Diese beiden Werte ersetzt die Timer-App beim Ausliefern.
|
||||
APP_URL="@@APP_URL@@"
|
||||
SETUP_CODE="@@SETUP_CODE@@"
|
||||
|
||||
ZIEL=/opt/bondrucker
|
||||
GERAET=""
|
||||
PORT=9100
|
||||
|
||||
# --- Schalter --------------------------------------------------------------
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--device) GERAET="${2:-}"; shift 2 ;;
|
||||
--port) PORT="${2:-9100}"; shift 2 ;;
|
||||
-h|--help) sed -n '2,22p' "$0"; exit 0 ;;
|
||||
*) echo "Unbekannter Schalter: $1" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "Bitte mit sudo starten: sudo bash $0" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Hilfsmittel
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
titel() { printf '\n\033[1m%s\033[0m\n' "$1"; }
|
||||
punkt() { printf ' %s\n' "$1"; }
|
||||
warnung() { printf ' \033[33m%s\033[0m\n' "$1"; }
|
||||
fehler() { printf '\n\033[31m%s\033[0m\n' "$1" >&2; exit 1; }
|
||||
|
||||
# Fragt den Benutzer und gibt die Antwort auf stdout zurueck.
|
||||
#
|
||||
# Die Umleitung auf /dev/tty ist der Grund, warum auch
|
||||
# "curl ... | sudo bash" noch bedienbar bleibt: dort ist die Standardeingabe
|
||||
# die Pipe und nicht die Tastatur. Gibt es gar kein Terminal, wird die Vorgabe
|
||||
# genommen, statt in einer Endlosschleife zu haengen.
|
||||
frage() {
|
||||
local text="$1" vorgabe="${2:-}" antwort=""
|
||||
if [ -t 0 ]; then
|
||||
read -r -p "$text" antwort || true
|
||||
elif [ -e /dev/tty ]; then
|
||||
read -r -p "$text" antwort < /dev/tty || true
|
||||
fi
|
||||
printf '%s' "${antwort:-$vorgabe}"
|
||||
}
|
||||
|
||||
# Klartextname eines USB-Druckers aus dem sysfs, damit in der Auswahl nicht
|
||||
# nur "lp0" steht, sondern "EPSON TM-T88IV".
|
||||
usb_name() {
|
||||
local pfad
|
||||
pfad=$(readlink -f "/sys/class/usbmisc/$(basename "$1")/device" 2>/dev/null) || return 1
|
||||
while [ -n "$pfad" ] && [ "$pfad" != "/" ]; do
|
||||
if [ -r "$pfad/product" ]; then
|
||||
printf '%s %s' "$(cat "$pfad/manufacturer" 2>/dev/null || true)" "$(cat "$pfad/product")"
|
||||
return 0
|
||||
fi
|
||||
pfad=$(dirname "$pfad")
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 1. System pruefen
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
titel "1. System"
|
||||
|
||||
command -v python3 >/dev/null || fehler "python3 fehlt. Bitte nachinstallieren: apt install python3"
|
||||
command -v systemctl >/dev/null || fehler "systemd fehlt - dieses Skript richtet einen systemd-Dienst ein."
|
||||
|
||||
punkt "$(. /etc/os-release 2>/dev/null && echo "$PRETTY_NAME" || uname -s) ($(uname -m))"
|
||||
punkt "$(python3 --version)"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 2. Drucker auswaehlen
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
titel "2. Drucker"
|
||||
|
||||
if [ -z "$GERAET" ]; then
|
||||
GEFUNDEN=()
|
||||
for d in /dev/usb/lp* /dev/lp*; do
|
||||
[ -e "$d" ] && GEFUNDEN+=("$d")
|
||||
done
|
||||
|
||||
if [ "${#GEFUNDEN[@]}" -eq 0 ]; then
|
||||
warnung "Gerade haengt kein Drucker unter /dev/usb/lp* am Pi."
|
||||
warnung "Das ist kein Hindernis: der Dienst findet ihn, sobald er angesteckt wird."
|
||||
GERAET=$(frage " Geraetepfad [/dev/usb/lp0]: " "/dev/usb/lp0")
|
||||
else
|
||||
echo
|
||||
for i in "${!GEFUNDEN[@]}"; do
|
||||
printf ' %d) %-16s %s\n' "$((i + 1))" "${GEFUNDEN[$i]}" "$(usb_name "${GEFUNDEN[$i]}" || echo '')"
|
||||
done
|
||||
printf ' a) anderer Pfad\n\n'
|
||||
|
||||
WAHL=$(frage " Welcher Drucker? [1]: " "1")
|
||||
if [ "$WAHL" = "a" ] || [ "$WAHL" = "A" ]; then
|
||||
GERAET=$(frage " Geraetepfad: " "/dev/usb/lp0")
|
||||
elif [ "$WAHL" -ge 1 ] 2>/dev/null && [ "$WAHL" -le "${#GEFUNDEN[@]}" ]; then
|
||||
GERAET="${GEFUNDEN[$((WAHL - 1))]}"
|
||||
else
|
||||
fehler "Ungueltige Auswahl: $WAHL"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
punkt "gewaehlt: $GERAET"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 3. Dienstbenutzer
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
titel "3. Dienstbenutzer"
|
||||
|
||||
if ! id bondrucker >/dev/null 2>&1; then
|
||||
useradd --system --no-create-home --shell /usr/sbin/nologin --groups lp bondrucker
|
||||
punkt "Benutzer 'bondrucker' angelegt (Gruppe lp)."
|
||||
else
|
||||
usermod -aG lp bondrucker
|
||||
punkt "Benutzer 'bondrucker' war schon da."
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 4. Programmdateien
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
titel "4. Programmdateien"
|
||||
|
||||
install -d -m 755 "$ZIEL"
|
||||
|
||||
cat > "$ZIEL/print-server.py" <<'PRINT_SERVER_ENDE'
|
||||
@@PRINT_SERVER@@
|
||||
PRINT_SERVER_ENDE
|
||||
chmod 755 "$ZIEL/print-server.py"
|
||||
punkt "$ZIEL/print-server.py"
|
||||
|
||||
cat > /etc/systemd/system/bondrucker.service <<'SERVICE_ENDE'
|
||||
@@SERVICE@@
|
||||
SERVICE_ENDE
|
||||
chmod 644 /etc/systemd/system/bondrucker.service
|
||||
punkt "/etc/systemd/system/bondrucker.service"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 5. Konfiguration
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
titel "5. Konfiguration"
|
||||
|
||||
TOKEN="$(head -c 24 /dev/urandom | base64 | tr -d '/+=' | head -c 32)"
|
||||
|
||||
install -d -m 750 /etc/bondrucker
|
||||
{
|
||||
printf 'PRINT_TOKEN=%s\n' "$TOKEN"
|
||||
printf 'PRINT_DEVICE=%s\n' "$GERAET"
|
||||
printf 'PRINT_PORT=%s\n' "$PORT"
|
||||
} > /etc/bondrucker/env
|
||||
chmod 640 /etc/bondrucker/env
|
||||
chown root:bondrucker /etc/bondrucker/env
|
||||
punkt "/etc/bondrucker/env geschrieben, neues Token erzeugt."
|
||||
|
||||
# Ohne diese Regel gehoert /dev/usb/lp0 nach jedem Einstecken wieder root
|
||||
# allein - der Dienst laeuft aber nicht als root und koennte nicht drucken.
|
||||
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 >/dev/null 2>&1 || true
|
||||
udevadm trigger --subsystem-match=usbmisc >/dev/null 2>&1 || true
|
||||
punkt "udev-Regel gesetzt (Geraet ueberlebt das Aus- und Einstecken)."
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 6. Dienst starten
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
titel "6. Dienst"
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable bondrucker.service >/dev/null 2>&1
|
||||
# Bewusst "restart" und nicht "enable --now": bei einer erneuten Einrichtung
|
||||
# laeuft der Dienst schon, und "enable --now" wuerde ihn in Ruhe lassen. Er
|
||||
# liefe dann mit dem ALTEN Token weiter und wuerde jeden Bon ablehnen.
|
||||
systemctl restart bondrucker.service
|
||||
sleep 1
|
||||
|
||||
if ! systemctl is-active --quiet bondrucker.service; then
|
||||
systemctl --no-pager --lines=20 status bondrucker.service || true
|
||||
fehler "Der Dienst laeuft nicht. Die Ausgabe oben sagt, woran es liegt."
|
||||
fi
|
||||
punkt "bondrucker.service laeuft."
|
||||
|
||||
# Gegenprobe von innen: antwortet die Bruecke, und nimmt sie das neue Token?
|
||||
ANTWORT="$(curl -fsS -m 5 -H "X-Print-Token: $TOKEN" "http://127.0.0.1:$PORT/status" 2>/dev/null || true)"
|
||||
case "$ANTWORT" in
|
||||
*'"tokenAccepted": true'*|*'"tokenAccepted":true'*) punkt "Bruecke antwortet und nimmt das Token an." ;;
|
||||
"") warnung "Die Bruecke antwortet auf 127.0.0.1:$PORT noch nicht." ;;
|
||||
*) warnung "Die Bruecke antwortet, lehnt das Token aber ab: $ANTWORT" ;;
|
||||
esac
|
||||
|
||||
case "$ANTWORT" in
|
||||
*'"deviceExists": false'*|*'"deviceExists":false'*)
|
||||
warnung "Das Geraet $GERAET ist gerade nicht da - Kabel pruefen." ;;
|
||||
esac
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 7. Bei der Timer-App anmelden
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
IP="$(hostname -I 2>/dev/null | awk '{print $1}')"
|
||||
|
||||
titel "7. Timer-App"
|
||||
|
||||
angemeldet=0
|
||||
case "$APP_URL" in
|
||||
@@*|"")
|
||||
punkt "Kein Einrichtungscode enthalten - dieses Skript wurde nicht ueber"
|
||||
punkt "die Timer-App geladen. Anmeldung wird uebersprungen."
|
||||
;;
|
||||
*)
|
||||
if ! command -v curl >/dev/null; then
|
||||
warnung "curl fehlt - die Anmeldung muss von Hand erfolgen."
|
||||
else
|
||||
RUMPF="$(printf '{"code":"%s","port":%s,"token":"%s","device":"%s","hostHint":"%s"}' \
|
||||
"$SETUP_CODE" "$PORT" "$TOKEN" "$GERAET" "$IP")"
|
||||
if ERGEBNIS="$(curl -fsS -m 15 -X POST \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "$RUMPF" "$APP_URL/api/setup/register" 2>&1)"; then
|
||||
punkt "Bei $APP_URL angemeldet."
|
||||
punkt "Die Timer-App druckt ab jetzt auf diesen Pi."
|
||||
angemeldet=1
|
||||
else
|
||||
warnung "Anmeldung fehlgeschlagen: $ERGEBNIS"
|
||||
warnung "Meist ist der Code abgelaufen - in der Timer-App einen neuen erzeugen."
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Fertig
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
titel "Fertig"
|
||||
punkt "Drucker: $GERAET"
|
||||
punkt "Adresse: ${IP:-<IP des Pi>}"
|
||||
punkt "Port: $PORT"
|
||||
|
||||
if [ "$angemeldet" -eq 0 ]; then
|
||||
echo
|
||||
punkt "Von Hand eintragen in der Timer-App unter Einstellungen:"
|
||||
printf ' Adresse: %s\n Port: %s\n Token: %s\n' "${IP:-?}" "$PORT" "$TOKEN"
|
||||
fi
|
||||
|
||||
echo
|
||||
punkt "Zustand abfragen: curl -s http://${IP:-127.0.0.1}:$PORT/status"
|
||||
punkt "Protokoll: journalctl -u bondrucker -f"
|
||||
echo
|
||||
@@ -1,71 +0,0 @@
|
||||
#!/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 bondrucker.service
|
||||
# Bewusst "restart" statt "enable --now": bei einer erneuten Einrichtung laeuft
|
||||
# der Dienst schon, und "enable --now" wuerde ihn in Ruhe lassen. Er liefe dann
|
||||
# mit dem ALTEN Token weiter und wuerde jeden Druckauftrag ablehnen.
|
||||
systemctl restart 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)"
|
||||
Reference in new issue
Block a user