• Für viele klingt es ungreifbar und für mich wird es auch ein Experiment, aber ich möchte meinen Briefkasten digitalisieren. Dabei möchte ich einen Raspberry Pi als Server verwenden, um den Scanner smart zu machen. Smart heißt in diesem Sinne:

    • Die Bedienung das Scanners soll auch trotz Modifikation einfach vonstatten gehen
    • zudem soll die smarte Bedienung einfach und Intuitiv sein
    • wenn mehrere Dokumente nacheinander gescannt wurden, sollen diese zu einer mehrseitigen PDF zusammengefasst werden
    • ich möchte meine Nextcloud mit ins Boot holen, um die Dokumente nach dem Scan auf der Cloud verfügbar zu haben

    Also wenn alles gut läuft, haben wir nicht nur einen smarten Scanner der ohne zusätzliche Software von Drittanbietern auskommt, sondern auch eine Headless-Bedienung mit der Anbindung zur eigenen Cloud - die sich von nun an auch als digitaler Briefkasten bezeichnen kann.

    nextcloud_briefkasten

    Scanner Inbetriebnahme

    Zuerst muss der Scanner mit dem Raspberry Pi verbunden und identifiziert werden. Also ab mit dem Scanner an den Raspberry Pi und nachsehen, ob das Gerät an irgendeiner Stelle erkannt wird. Ich habe ein frisches System und werde einen EPSON Scanner hinzufügen, damit ihr die Schritte so übernehmen könnt. Ob es ein EPSON-Scanner ist oder ein Scanner einer anderen Marke macht hierbei nicht den Unterschied zwischen win und fail.

    Mein EPSON Stylus SX235W hat eigentlich schon von Haus aus WLAN und könnte die gewünschten Funktionen evtl. (nicht geprüft) auch ohne DIY Setup umsetzen, aber sehr wahrscheinlich bin ich dann wieder auf zusätzliche Apps und meinen Computer angewiesen. Trotz Wlan ist der Scanner also nicht mehr der neuste, und genau da kommt unser eigenes Setup ins Spiel.

    Bevor wir mit der Installation von Software beginnen, sollte die Paketliste und die darin enthaltenen Pakete geupdated werden.

    sudo apt update -y && sudo apt upgrade -y
    

    Danach wird SANE installiert. SANE (Scanner Access Now Easy) ist ein Kommandozeilen-Interface, das dazu dient, Scanner wie etwa Multifunktionsgeräte oder Flachbettscanner an einem Computer zu bedienen und zu steuern.

    sudo apt install sane sane-utils
    

    Die Pakete die heruntergeladen werden sind ziemlich groß. Bestätigt die Installation mit der gewünschten Eingabe des Systems.

    Nach dieser Operation werden 445 MB Plattenplatz zusätzlich benutzt.
    Möchten Sie fortfahren? [J/n]
    

    Mit dem Installieren von sane und sane-utils kam auch das Paket scanimage hinzu. Über dieses Toll kann der Scanner absofort angesprochen werden.

    Ich prüfe dazu erstmal alle verfügbaren Scanner am Raspberry Pi mit folgendem Befehl:

    sudo scanimage --list-devices
    
    user@server:~ $ sudo scanimage --list-devices
    Created directory: /var/lib/snmp/cert_indexes
    
    No scanners were identified. If you were expecting something different,
    check that the scanner is plugged in, turned on and detected by the
    sane-find-scanner tool (if appropriate). Please read the documentation
    which came with this software (README, FAQ, manpages).
    

    Jetzt schalte den Scanner ein und schaue nach, ob er ordnungsgemäß erkannt wird.

    user@server:~ $ sudo scanimage --list-devices
    device `epson2:libusb:001:004' is a Epson PID 0885 flatbed scanner
    

    Wenn das der einzige Scanner ist, der angeschlossen werden soll, könnt ihr mithilfe des folgenden Befehls direkt ein Dokument scannen.

    sudo scanimage --format=jpeg --resolution=300 -p > output.jpg

    Es wird ein Bild mit dem Namen output.jpg erzeug. Ich bin bereits per FTP mit dem Server verbunden und sehe das Bild in dem Verzeichnis, in dem ich den Befehl aufgerufen habe.

    Um das Dokument in Farbe zu scannen, kann der --mode color hinzugefügt werden.

    sudo scanimage --format=jpeg --resolution=300 --mode color -p > output.jpg

    Mit diesen beiden Befehlen können jetzt Dokumente und Bilder eingescannt werden.

    Konvertieren der Bilder zu einer PDF-Datei

    Um die einzeln eingescannten Dokumenten-JPGs nun als PDF zusammenzufassen kann ich euch das Tool imagemagick empfehlen. Mit imagemagick könnt ihr unter anderem ganz einfach Bilder zu PDF konvertieren lassen. Dabei werden einzelne Dateien unterstützt:

    convert ouptput.jpg -quality 100 output.pdf
    

    Um mehrere Dateien gleichzeitig zu einer PDF zusammenzufassen empfiehlt es sich, einen kleinen Namespace anzulegen. Als Beispiel haben wir drei Dateien:

    • scan_10.jpg
    • scan_11.jpg
    • scan_12.jpg

    Alle drei Bilder lassen sich der Nummerierung nach zu einer PDF zusammenfassen:

    convert scan_*.jpeg -quality 100 collectedPDF.pdf
    

    Das Sternchen steht dabei für einen Platzhalter und das Kommandozeilen Tool sucht sich automatisch die Bilder in der Passenden Reihenfolge.

    Tipp: Fangt bei 10 zu zählen an, nicht bei 1. Falls ihr weniger als 10 Dokumente hat spielt es keine Rolle. Solltet ihr aber Dokument 11 oder 12 haben, so kann es passieren, dass die Reihenfolge durcheinanderrutscht.

    Die eigene Scanner API mit Node.JS

    Scannen mithilfe von Befehlen ist schön und recht. Das bietet uns aber leider noch keine Möglichkeit, den Scanner von einem anderen Gerät aus zu bedienen. Um den Scanner automatisiert bedienen zu können, aber ich mir eine kleine Node.JS API programmiert.

    Diese API lässt es über den Endpoint 192.168.0.1:4444/scan zu, einen Scanvorgang zu starten. Über einen weiteren Endpoint der API 192.168.0.1/collect lassen sich die einzelnen Scan-JPGs als PDF zusammenfassen.

    Beim Aufruf der API führt meine Node.JS Anwendung zum einen die oben genannten Befehle aus.

    sudo scanimage --format=jpeg --resolution=300 --mode color -p > output.jpg
    convert scan_*.jpeg -quality 100 collectedPDF.pdf
    

    Zum anderen wurde auch die komplette Logik in Node.JS implementiert, da man so einfach mehr Möglichkeiten hat.

    Auf den Programmcode von Node.JS möchte ich nicht detailliert eingehen, aber im Endeffekt beschränkt er sich auf einen einfachen Node.JS -Express-Webserver der die Endpoints bereitstellt. Dazu werden lediglich folgende Pakete und Variablen global benötigt.

    Variablen und Module

    const express = require('express');
    const execSh = require("exec-sh");
    var fs = require('fs');
    
    // Einstellungen
    var newSession = true;
    var scanSite = 10;
    

    API zum Scannen

    app.get('/scan', async (req, res) => {
        if (!fs.existsSync("scans")){
            fs.mkdirSync("scans");
        }
        scanSite = scanSite + 1;
        if(newSession){
            scanSite = 10;
            newSession = false;
        }
        var singleFileName = "scan_" + scanSite;
        // Direkt die Antwort senden, damit der Kurzbefehl nicht so lange braucht
        res.status(200).send({
            code: 200,
            status: "unknown",
            filename: singleFileName
        });
        execSh("echo 'Versuche Terminal zu öffnen ...'", { cwd: "/home" }, (err) => {
            if (err) {
                console.log("Kein Zugriff auf das Terminal möglich", err.code);
                return;
            }
            // Hier wird der Terminal Befehl zum Scannen abgesetzt
            const child = execSh(["sudo bash ./bash/scan.sh 300 " + singleFileName], true, (err, stdout, stderr) => {
                if (err) {
                    console.log("error: ", err);
                    return;
                }               
            });
        });
    });
    

    API zum Zusammenfassen der Scans

    app.get('/collect', (req, res) => {
        // Filename = Datum
        var filename = getdate();
        // Damit der Kurzbefehl nicht so lange braucht,
        // wird direkt eine Antwort vom Server geschickt
        res.status(200).send({
            code: 200,
            status: "unknown",
            filename: filename
        });
        // Hier werden Shell Befehle abgesetzt 
        execSh("echo 'Versuche Terminal zu öffnen ...'", { cwd: "/home" }, (err) => {
            if (err) {
                console.log("Kein Zugriff auf das Terminal möglich", err.code);
                return;
            }
            // Hier werden die Scans konvertiert und zusammengefasst
            const child = execSh(["sudo convert ./scans/scan_*.jpg -compress jpeg " + filename + ".pdf"], true, (err, stdout, stderr) => {
                if (err) {
                    console.log("Anforderung: Collect Scans. \n Keine Dateien im Ordner `scans` vorhanden.");
                    return;
                }      
                // Hier wird die neue zusammengefasste Datei in das Verzeichnis "inbox" verschoben
                var oldPath = filename + ".pdf";
                var newPath = "inbox/" + filename + ".pdf";
                fs.rename(oldPath, newPath, function (err) {
                    if (err) throw err
                    console.log('Datei wurde verschoben.')
                    fs.rmSync("scans", { 
                        recursive: true, 
                        force: true 
                    });
                    // Damit mein Programm weiß, dass der Namespace wieder zurückgesetzt wird
                    // Wichtig für den Namespace scan_10, scan_11, scan_12, ...
                    newSession = true;
                })       
            });
        });
    });
    

    Scannen am Smartphone

    Um die Bedienung noch einfacher zu machen, habe ich meine Node.JS-API via Homebridge in Apple Home eingebunden und kann so den Scanner per Sprachbefehl bedienen. Das ist aber eher “für den Fall der Fälle”. Also wenn man sein Handy nicht griffbereit hat. Denn in der Regel kann ich den Scanner mit zwei Kurzbefehlen, ebenfalls auf iOS bedienen. Diese Kurzbefehle callen die API und diese führt dann entsprechende Aktionen aus.

    Über den Kurzbefehl “Scan hochladen” wird vorher noch gefragt, ob ich dem Dokument einen Namen geben will. Wenn das der Fall ist. Wird auf den Endpoint192.168.0.1/collect/:name zurückgegriffen, über den ich einen Namen vergeben kann. Wird kein Name vergeben, wird der aktuelle Zeitstempel als Name für den Scan verwendet.

    Deine eigene Scanner API

    In meinem Fall ist es ein Node.JS Backend, dass die Anfragen verwaltet, auswertet und dann lediglich die Befehle zum Scannen und Zusammenfassen absetzt. Aber im Prinzip kann es alles sein. Ihr könnt eine eigene Logik definieren und dann die Aktionen zum Scannen und Zusammenfassen mit eurem eigenen Programm in Verbindung bringen. PHP, Ruby, C++ oder Java. Am Ende des Tages sind es zwei Befehle, die euren Scanner smart machen.

    sudo scanimage --format=jpeg --resolution=300 --mode color -p > output.jpg
    convert scan_*.jpeg -quality 100 collectedPDF.pdf
    

    Nextcloud Einbindung

    Es klingt total spannend und spektakulär, dass die Scans in der Nextcloud laden. Aber tatsächlich ist es ein FTP-Server, der die Dateien auf der Nextcloud verfügbar macht.

    fs.rename(alteDatei, neueDatei, function (err) {
        if (err) throw err
        console.log('Datei wurde verschoben.')
        // Ordner für einzelene Scans löschen
        fs.rmSync("scans", { 
            recursive: true, 
            force: true 
        });
        newSession = true;
    })     
    

    Dieser kleine Code-Block in meinem Node.JS Programm verschiebt die Datei nach erfolgreicher Konvertierung in ein anderes Verzeichnis und macht Platz für die neuen Scans. Das Verzeichnis in das die Scans verschoben werden, ist via External Storage FTP in Nextcloud eingebunden. Das macht alle Dateien im Ordner inbox auf der Nextcloud verfügbar. Dort aber im Namen von 01_Breifkasten.

    nextcloud_external_storage

Ähnliche Themen

  • 1
  • 2
  • 52
  • 10
  • 16