Schlagwort: remote USB

  • Scanner-Server mit USB-Scanner über Netzwerk

    Problem

    Viele haben einen Scanner, der nur über USB direkt an einem PC betrieben werden kann. Wenn dieser Scanner aber z.B. ein spezieller Dokumentenscanner ist und/oder von mehreren Personen benutzt werden soll (z.B. ein „Abteilungsscanner“ auf dem Flur), dann ist das entweder unmöglich, oder ein extra „Scan-PC“ muss neben dem Scanner stehen, der auch immer laufen muss — oder für jeden Scan extra eingeschaltet werden muss. Diesen „Scan-PC“ kann man aber sehr kostengünstig und so geschickt aufsetzen, dass daraus eine wahrlich geniale Lösung wird:

    Lösungskonzept

       

        • kleine Linux-Kiste (alter Raspberry Pi) neben dem Scanner, an der der Scanner direkt per USB hängt. Natürlich muss die Box im Netz hängen.

        • per udev-Regel wird das Einschalten des Scanners erkannt und ein Dienst gestartet.

             

              • dieser Dienst startet den USB-IP-Hostdienst und stellt den Scanner somit als USB-Gerät im Netz zur Verfügung

              • ausserdem logt sich der Dienst per SSH im Verarbeitungsserver ein und startet dort ebenfalls einen Dienst

          • Dieser Dienst hängt mit USB-IP den remote Scanner als lokales USB-Gerät

               

                • Auf diesem Verarbeitungsserver kann dann die kompliziertere Image-Verarbeitung (OCR, etc.) stattfinden.

          Somit steht der Scanner automatisch wenige Sekunden nach dem Einschalten auf der remote Box als „pseudo“ lokales Gerät zur Verfügung.

          Vorteile dieses Ansatzes

          Der PC, der die Scans verarbeitet muss durchaus einige Ressourcen in Bezug auf CPU und Memory haben, weil die graphische Aufbereitung der Scans (entrauschen), sowie OCR doch relativ Ressourcen-hungrig sind. Dazu kommt, dass im Fall eines Dokumentenscanners eigentlich alle Scan-Parameter vorher festgelegt werden können. Der Scanner sollte eigentlich auf Knopfdruck starten und die Scans idealerweise irgendwo im Netzwerk ablegen. Mit diesem Ansatz kann die eigentliche Verarbeitung des Scans irgendwo im Netz (z.B. auf einer ausreichend dimensionierten VM) stattfinden. Vor Ort muss der Linux-Rechner eigentlich nur das USB-Gerät über das Netz weiterreichen. Dafür reicht auch ein uralt-Raspi.

          Natürlich gibt es Dokumentenscanner, die das alles out-of-the-box können, aber die sind im Vergleich sehr teuer — sehr viel teurer, als ein einfacher, aber zuverlässiger Dokumentenscanner plus ein alter Raspberry Pi. Daher entstand die Idee.

          Raspi konfigurieren

             

              • usbip installieren + kernel-module ‚usbip-host‘ laden

              • ssh-connection zu Client-Computer vorbereiten (ssh-copy-id)

            Jetzt müssen mehrere Dienste konfiguriert werden. Zunächst die udev-Regel, die den USB-IP Dienst zur Weiterleitung des Geräts startet, sobald der Scanner „sichtbar“ wird. Das passiert z.B. beim Einschalten des Scanners (oder Aufwachen aus dem Standby).

            /etc/udev/rules.d/90-usbip.rules

            SUBSYSTEM=="usb", 
            ATTR{idVendor}=="04c5", 
            ATTR{idProduct}=="1626", 
            ENV{DEVTYPE}=="usb_device", 
            TAG+="systemd", 
            ENV{SYSTEMD_WANTS}+="usbip@%k.service"

            Die Vendor- und ProductID müssen natürlich angepasst werden. Einfach mit lsusb nachschauen, wenn der Scanner per USB verbunden ist.

            Jetzt kommt der Dienst, der von der udev-Regel gestartet werden soll. Der Trick hier ist, dass per SSH der nötige Dienst zum remote einbinden des USB-Geräts auf dem Verarbeitungsserver automatisch gestartet wird, sobald der Scanner eingeschaltet wird.

            WICHTIG: In der zweiten ExecStart-Anweisung und der ersten ExecStop-Anweisung muss natürlich „root@verarbeitungsserver“ und „usbip@raspi“ geändert werden auf die tatsächlichen ssh-Benutzer und Hostnamen.

            /lib/systemd/system/usbip@.service

            [Unit]
            Description=USB-IP Binding %i
            After=network-online.target usbipd.service
            Wants=network-online.target usbipd.service
            PartOf=usbipd.service
            StopWhenUnneeded=yes
            [Service]
            Type=simple
            RemainAfterExit=yes
            # binding a device itself
            ExecStart=/bin/sh -c "/usr/sbin/usbip bind -b %i"
            # and attching the device on remote computer
            ExecStartPost=ssh root@verarbeitungsserver "/bin/systemctl start usbip@raspi:%i"
            # expecting errors of unbinding actually "already disconnected device"
            ExecStop=ssh root@verarbeitungsserver "/bin/systemctl stop usbip@raspi:%i"
            ExecStop=-/bin/sh -c "/usr/sbin/usbip unbind -b %i"
            ExecStop=/bin/systemctl reset-failed
            [Install]
            WantedBy=multi-user.target

            Dieser Dienst stellt sicher, dass der USB-IP Service immer läuft:

            /lib/systemd/system/usbipd.service

            [Unit]
            Description=USB-IP Host Daemon
            After=network-online.target
            Wants=network-online.target
            [Service]
            Type=simple
            Restart=always
            ExecStart=/bin/sh -c "/usr/sbin/usbipd"
            [Install]
            WantedBy=multi-user.target

            Und aktivieren und starten:

            udevadm control --reload-rules
            systemctl daemon-reload
            systemctl restart systemd-udevd
            systemctl enable usbipd && sudo systemctl start usbipd

            Verarbeitungsserver konfigurieren

               

                • usbip installieren und Kernel-module laden

                • ssh-connection zu Server konfigurieren

              Als erstes brauchen wir das Gegenstück für den Dienst, der auf dem Raspi aktiviert wird, wenn der Scanner eingeschaltet wird. Der Raspi startet dann diesen Dienst auf dem Verarbeitungsserver remote per SSH. Er dient dazu, den im Netz angebotenen USB-IP-Scanner lokal wieder als USB-Gerät zur Verfügung zu stellen.

              /etc/systemd/system/usbip@.service

              [Unit]
              Description=USB-IP [At/De]taching %i
              After=network-online.target
              Wants=network-online.target
              [Service]
              Type=simple
              Restart=on-failure
              RestartSec=1
              RemainAfterExit=yes
              ExecStart=/bin/sh -c "/usr/sbin/usbip attach -r $(echo %i | sed 's/:/ -b /1')"
              #Expected error of unbinding actually "already disconnected device"
              ExecStop=-/bin/sh -c "/usr/sbin/usbip detach --port `/usr/sbin/usbip port | grep -B2 $(echo %i | awk -F':' '{print $2}') | grep 'Port' | cut -b 6-7`"
              [Install]
              WantedBy=multi-user.target

              Dazu muss natürlich der USB-IP Dienst immer laufen.

              /etc/systemd/system/usbipd.service

              [Unit]
              Description=USB-IP Client Daemon
              After=network-online.target
              Wants=network-online.target
              [Service]
              Type=simple
              Restart=always
              RemainAfterExit=yes
              # creating a tmp-file if any USB port is available
              ExecStart=/bin/sh -c "/usr/sbin/usbip list -r raspi | grep '/' > /tmp/usbip-exportable-list"
              # cleaning garbage after yourself
              ExecStop=-rm /tmp/usbip-exportable-list
              # sometime had happened too
              ExecStop=systemctl reset-failed
              [Install]
              WantedBy=multi-user.target

              Und noch ein kleiner Dienst für den Fehlerfall (siehe Kommentare im Code):

              /etc/systemd/system/usbipd-restart.service

              [Unit]
              Description=USB-IP Deamon Remote Restarting (runs by client)
              After=network-online.target usbipd.service
              Wants=network-online.target usbipd.service
              [Service]
              Type=simple
              EnvironmentFile=/etc/usbip.conf
              # Is any USB port already available? - This is the case if we bekome online after the server.
              # If so - restart usbipd.service remotely to be attached.
              # If not (file is empty) - nothing to do, USB will be attached
              # later on while being inserted into the host.
              ConditionFileNotEmpty=/tmp/usbip-exportable-list
              ExecStart=-ssh root@raspi "systemctl restart usbipd"
              # Clean up usbipd's garbage
              ExecStartPost=-rm /tmp/usbip-exportable-list
              ExecStartPost=systemctl reset-failed
              [Install]
              WantedBy=multi-user.target

              systemctl daemon-reload
              systemctl enable usbipd && sudo systemctl start usbipd

              Damit steht der Scanner dynamisch über ein Ethernet Netzwerk als USB-Gerät auf dem Verarbeitungsserver zur Verfügung. 

              Jetzt kann auf dem Verarbeitungsserver die Scannersoftware eingerichtet werden, so als ob der Scanner am lokalen USB-Port hängen würde, also z.B. ein Treiber/Software/Dienst, der den Scan-Button auslesen kann (falls es das für den eingesetzten Scanner gibt). Auch das Anstossen des eigentlichen Scans, sowie die weitere Verarbeitung müssen über eine zum Scanner passende Scansoftware konfiguriert werden. Tut man das auf einem Server (z.B. eine VM) im Netz und richtet den Prozess mitsamt fester Scanparameter so ein, dass die fertigen Dokumente auf ein Netzlaufwerk gestellt werden, hat man eine maximal flexible Lösung, wo der Scanner im Prinzip überall stehen kann, solange eine Netzwerkdose in der Nähe ist.

              Der Prozess für den Benutzer ist einfach: Der Raspi läuft bei mir immer (ich habe noch keine Lösung gefunden, um ihn durch das Einschalten eines angesteckten USB-Gerätes zu starten). D.h. Scanner einschalten, warten bis er „da ist“ (wenige Sekunden), in der Zwischenzeit die Dokumente einlegen und auf den Scan-Knopf drücken. Der dadurch angestoßene Prozess über die remote Services, die den eigentlichen Scan auslösen dauert bei mir unter 1 Sekunde. Fast augenblicklich fängt der Scanner an zu arbeiten.

            This website stores cookies on your computer. These cookies are used to provide a more personalized experience and to track your whereabouts around our website in compliance with the European General Data Protection Regulation. If you decide to to opt-out of any future tracking, a cookie will be setup in your browser to remember this choice for one year.

            Accept or Deny