.titleBar { margin-bottom: 5px!important; }

[HowTo] Erweiterter USB-Printserver, insbesondere Drucker ein und aus schalten

Dieses Thema im Forum "Freetz" wurde erstellt von RalfFriedl, 14 Dez. 2011.

  1. RalfFriedl

    RalfFriedl IPPF-Urgestein

    Registriert seit:
    22 Apr. 2007
    Beiträge:
    12,343
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    #1 RalfFriedl, 14 Dez. 2011
    Zuletzt bearbeitet: 9 März 2012
    Im [THREAD=232493]Thread über steuerbare Steckdosenleisten[/THREAD] kam die Idee auf, [POST=1783099]einen Drucker einzuschalten, wenn ein Druckjob an die Box kommt[/POST].

    Hier erstmal ein einfacher Ansatz dazu.
    Im Prinzip muss so ein Printserver nicht viel tun. Auf eingehende Verbindungen warten, diese annehmen und die Daten an den Drucker weiter geben.
    Das kann man so machen:
    Code:
    #include <stdio.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netinet/tcp.h>
    
    
    int
    main (int argc, char **argv)
    {
      int opt;
      u_short port = 9100;
      char const *device = "/dev/usblp0";
      char const *logfile = "/dev/stdout";
      int fd_listen;
      int ret;
      int int_val;
      struct sockaddr_in sin;
    
      while ((opt = getopt (argc, argv, "d:p:c:h")) != EOF)
        switch (opt) {
        case 'd':
          device = optarg;
          break;
        case 'p':
          port = atoi (optarg);
          break;
        case 'c':
          logfile = optarg;
          break;
        }
      fd_listen = socket (PF_INET, SOCK_STREAM, 0);
      int_val = 1;
      ret = setsockopt (fd_listen, SOL_SOCKET, SO_REUSEADDR, &int_val, sizeof (int_val));
      sin.sin_family = AF_INET;
      sin.sin_port = htons (port);
      sin.sin_addr.s_addr = INADDR_ANY;
      ret = bind (fd_listen, (struct sockaddr *)&sin, sizeof (sin));
      ret = listen (fd_listen, 1);
      ret = fork ();
      if (ret < 0) {
        perror ("fork");
        exit (1);
      }
      if (ret > 0)
        exit (0);
      setsid ();
      for (;;) {
        int fd_accept, fd_printer;
        char buf[0x1000];
    
        fd_accept = accept (fd_listen, NULL, NULL);
        ret = system ("printserv-job start");
        fd_printer = open (device, O_WRONLY);
        while ((ret = read (fd_accept, buf, sizeof (buf))) > 0) {
          write (fd_printer, buf, ret);
        }
        close (fd_printer);
        close (fd_accept);
        ret = system ("printserv-job end");
      }
    }
    
    Bei AVM gibt es dafür gleich 4 Prozesse, ich weiß nicht, warum die das so kompliziert gemacht haben. Die Optionen sind mit Absicht kompatibel zu denen von AVM gewählt. Man könnte/sollte noch an einigen Stellen auf Fehler prüfen, außerdem geht das Programm nicht von selbst in den Hintergrund, aber das Programm sollte so funktionieren. Ich habe aber keinen USB-Drucker an der Box, um das zu testen.
    Vor und nach jedem Druckauftrag wird printserv-job aufgerufen, einmal mit start und einmal mit end als Parameter. Bei Start könnte man den Drucker einschalten und 30 Sekunden warten, oder wie lang auch immer der Drucker braucht. Bei End kann man festhalten, dass der Druckauftrag zu Ende ist, und dafür sorgen, dass der Drucker irgendwann ausgeschaltet wird, wenn keine neuen Aufträge kommen.

    Bei AVM wird auch noch eine Datei /var/log/printer_status erstellt. Wenn jemand herausfindet, was dort zu verschiedenen Gelegenheiten drin steht, kann man das auch ergänzen.
     
  2. caldir65

    caldir65 Neuer User

    Registriert seit:
    26 Juni 2008
    Beiträge:
    112
    Zustimmungen:
    0
    Punkte für Erfolge:
    16
    Ort:
    Melle
    Moin Ralf,

    klasse, wie schnell Du ein erstes Proggi zum Umsetzen gestrickt hast. Ich bin jetzt kein Fachmann, aber soweit ich das jetzt verstehe, hast Du den Port und Vorlauf- sowie Nachlaufzeit fest in das Programm codiert? Wie wäre es, quasi per Aufrufparameter oder per cfg diese Dinge zu übergeben, da
    • der Port abhängig davon ist, wieviele Drucker angeschlossen sind (oder sich auch aus anderen Gründen evtl. wieder mal verschieben könnte im Trunk, auch wenn es von AVM kommt ...
    • jeder Drucker durchaus seine eigene Vorlaufzeit benötigt, und sie somit individuell optimiert werden kann
    • jeder, der einen Drucker auf diese Art steuern möchte, vlt. individuell festlegen möchte, wie lange nach dem Ende sein Drucker eingeschaltet bleibt
    • möglicherweise die Aufrufparameter zur sispmctl geändert werden sollen, da ja mehrere Schaltleisten angeschlossen sein können sowie der Drucker zudem auch an unterschiedlichen Steckdosen je Leiste sitzen kann

    Auf jeden Fall erstmal ein großes Danke für Deine schnellen Bemühungen!

    Gruß, Christoph
     
  3. RalfFriedl

    RalfFriedl IPPF-Urgestein

    Registriert seit:
    22 Apr. 2007
    Beiträge:
    12,343
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Der Port wird über den Parameter -p gewählt, wie beim AVM Programm.
    Der Drucker wird über den Parameter -d gewählt, wie beim AVM Programm.
    Die Logdatei wird über den Parameter -c gewählt, wie beim AVM Programm, obwohl dies im jetzigen Programm nicht verwendet wird.
    Wie schon geschrieben, ist es Absicht, dass die Optionen identisch gewählt sind.
    Unabhängig davon werden für alle Optionen Vorgaben gesetzt, die in den meisten Fällen sinnvoll sind.

    Wenn man noch einbauen würde, dass das Programm selbst in den Hintergrund geht, könnte man es direkt als Ersatz für das AVM Programm verwenden. Die Datei /var/log/printer_status könnte man auch noch entsprechend aktualisieren, wenn jemand mit einem USB-Drucker an der Box mal schaut, was in der Datei drinsteht, wenn der Drucker ausgeschaltet ist, eingeschaltet bzw. gerade am Drucken, ohne Papier usw.

    Vorlauf- sowie Nachlaufzeit ist weder fest noch unfest im Programm. Das Programm ruft vor und nach einem Druck "printserv-job" auf. Damit das etwas bringt, muss man ein Programm/Skript mit dem Namen erstellen, in dem man die beabsichtigten Aktionen ausführt.
     
  4. stan23

    stan23 Neuer User

    Registriert seit:
    4 Sep. 2010
    Beiträge:
    63
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Beruf:
    Specialist Mobile Power Management
    Ort:
    Beilngries
    Könnte man dafür die libdaemon benutzen?
     
  5. RalfFriedl

    RalfFriedl IPPF-Urgestein

    Registriert seit:
    22 Apr. 2007
    Beiträge:
    12,343
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Die könnte man verwenden.
    Man kann es aber auch von Hand machen:
    Code:
        ret = fork ();
        if (ret < 0) {
          perror ("fork");
          exit (1);
        }
        if (ret > 0)
          exit (0);
        setsid ();
    
     
  6. caldir65

    caldir65 Neuer User

    Registriert seit:
    26 Juni 2008
    Beiträge:
    112
    Zustimmungen:
    0
    Punkte für Erfolge:
    16
    Ort:
    Melle
    Hallo Ralf,

    also wenn ich das jetzt richtig verstanden habe, müßte Dein Printserver der von AVM ergänzt werden und als permanenter Dienst eingebunden werden, damit via z.B. /var/log/printer_status (sofern dort vernünftige Stati abgelegt werden ...) überprüfen kann, ob tatsächlich ein Drucker vorhanden bzw. eingeschaltet ist. Sofern nicht, schaltet Dein PS den Drucker via Leiste ein, um danach den Druckjob an den eigentlichen PS (oder ggf. auch den Drucker) zu übergeben.

    Wenn ich den AVM-Mechanismus richtig verstehe, wird doch bei denen der PS vom Hotplug gestartet, sobald an USB ein Drucker angeschlossen wird. Könnte man da nicht mit der /var/log/printer_id (wird, soweit ich weiß, angelegt, wenn ein Drucker vorhanden, mit der Druckerbezeichnung, wie sie auch im Webfrontend gezeigt wird)? Da könnte dann auch überwacht werden, wenn jemand mehrere Drucker angeschlossen hat und steuern will, ob der richtige bereits an ist ...

    Voraussetzung ist allerdings ein USB-Drucker - ob es mit einer bidirektionalen USB2LPT-Verbindung geht, kann ich im Moment nicht testen, mein Adapter geht nur in eine Richtung :( (da gibt es auch keine Stati in printer_status außer 0, und in der printer_id steht die Bezeichnung des Adapters ...)

    Gruß, Christoph
     
  7. RalfFriedl

    RalfFriedl IPPF-Urgestein

    Registriert seit:
    22 Apr. 2007
    Beiträge:
    12,343
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Dieses Programm ist nicht als Ergänzung, sondern als Ersatz für das Programm von AVM gedacht. Insbesondere mit dem fork aus #5 geht das Programm auch selbst in den Hintergrund. Ein gleichzeitiger Betrieb mit dem AVM Programm ist weder notwendig noch möglich. Es wäre jedoch auch denkbar, ein Programm zu erstellen, das zusätzlich zum AVM Programm läuft und die Daten an dieses Programm weiter gibt.

    Bekannte Unterschiede zum AVM Programm:
    Das Programm aktualisiert nicht die Datei /var/log/printer_status. Hauptsächlich weil ich nicht weiß, was man da rein schreiben kann und was es bringt. Bei mir steht in der Datei "4" drin.
    Das Programm öffnet nicht zusätzlich den Port 9101. Auch hier weiß ich nicht, worauf der reagiert und wofür der gut ist.
    Kann jemand, der einen USB Drucker angeschlossen hat, mal herausfinden, was auf dem Port 9101 passiert?

    Die Datei /var/log/printer_id kommt von /usr/share/ctlmgr/libctlusb.so und nicht von printserv.
     
  8. stan23

    stan23 Neuer User

    Registriert seit:
    4 Sep. 2010
    Beiträge:
    63
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Beruf:
    Specialist Mobile Power Management
    Ort:
    Beilngries
    Hi,
    ich habe inzwischen auch so eine steuerbare Steckdosenleiste von Gembird und bin an der printserver-Lösung interessiert.

    Der Inhalt von /var/log/printer_status äußert sich bei mir folgendermaßen im AVM WebIF unter Heimnetz -> USB-Geräte:
    Code:
    printer_status  Anzeige im AVM WebIF
    0               Status: Bereit
    1               Status: Beim Drucken
    2               Status: Bitte Papier einlegen
    3               Status: Allgemeiner Fehler
    4 und höher     Status nicht verfügbar
    Wenn ich /var/log/printer_status ändere, wird sie innerhalb weniger Sekunden wieder überschrieben.
     
  9. stan23

    stan23 Neuer User

    Registriert seit:
    4 Sep. 2010
    Beiträge:
    63
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Beruf:
    Specialist Mobile Power Management
    Ort:
    Beilngries
    Hi Ralf,

    ich habe dein Programm mal getestet (ohne fork) und folgendes festgestellt:
    Code:
        fd_printer = open (device, O_WRONLY);
        ret = system ("printserv-job start");
    sollte in umgekehrter Reihenfolge aufgerufen werden, denn man kann den Drucker erst öffnen wenn er eingeschaltet ist :)

    Und der Drucker schaltet immer nach einen Job (und Wartezeit) ab, auch wenn schon der nächste Job ansteht. Man müsste also in printserv oder printserv-jobs prüfen ob ein neuer Druckjob ansteht und das Abschalten nach der Wartezeit verwerfen.


    Hier mein printserv-job
    Code:
    #! /bin/sh
    # switch printer on/off 
    # using SIS-PM power strip
    
    # device number
    SIS_DEVICE=0
    # plug number
    SIS_PLUG=1
    # waiting time after switching on (let printer boot)
    WAIT_START=30
    # waiting time before switching off (wait for another job)
    WAIT_END=30
    
    
    case $1 in
    start)
    	echo "[printserv-job] Switching on plug $SIS_PLUG on device $SIS_DEVICE..."
    	sispmctl -d $SIS_DEVICE -o $SIS_PLUG
    	echo "[printserv-job] done"
    	echo "[printserv-job] Waiting $WAIT_START seconds..."
    	sleep $WAIT_START
    	;;
    end|stop)
    	echo "[printserv-job] Waiting $WAIT_END seconds..."
    	sleep $WAIT_END
    	echo "[printserv-job] Switching off plug $SIS_PLUG on device $SIS_DEVICE..."
    	sispmctl -d $SIS_DEVICE -f $SIS_PLUG
    	echo "[printserv-job] done"
    	;;
    *)
    	echo "[printserv-job] start or end expected"
    	;;
    esac
    
     
  10. RalfFriedl

    RalfFriedl IPPF-Urgestein

    Registriert seit:
    22 Apr. 2007
    Beiträge:
    12,343
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Den Drucker zuerst einzuschalten ist sicher eine gute Idee.

    Das Skript sollte etwas flexibler sein, wenn man mehrere Druckjobs nacheinander drucken will. Insbesondere sollte es nicht warten und dann den Drucker grundsätzlich ausschalten, denn in der Wartezeit ist der Printerserver nicht ansprechbar.

    Code:
    #! /bin/sh
    # switch printer on/off 
    # using SIS-PM power strip
    
    # device number
    SIS_DEVICE=0
    # plug number
    SIS_PLUG=1
    # waiting time after switching on (let printer boot)
    WAIT_START=30
    # waiting time before switching off (wait for another job)
    WAIT_END=30
    
    FILE_START=/tmp/printserv_start
    FILE_END=/tmp/printserv_end
    FILE_TMP=/tmp/printserv_tmp
    
    case $1 in
    start)
    	touch $FILE_START
    	while ! ln $FILE_START $FILE_TMP 2> /dev/null; do
    		sleep 1
    	done
    	# Wenn Drucker noch nicht an ...
    	if test ! -e $FILE_END; then
    		echo "[printserv-job] Switching on plug $SIS_PLUG on device $SIS_DEVICE..."
    		sispmctl -d $SIS_DEVICE -o $SIS_PLUG
    		echo "[printserv-job] done"
    		echo "[printserv-job] Waiting $WAIT_START seconds..."
    		sleep $WAIT_START
    	fi
    	rm $FILE_TMP
    	;;
    end|stop)
    	touch $FILE_END
    	(
    	echo "[printserv-job] Waiting $WAIT_END seconds..."
    	sleep $WAIT_END
    	if ln $FILE_START $FILE_TMP 2> /dev/null && test $FILE_START -ot $FILE_END; then
    		echo "[printserv-job] Switching off plug $SIS_PLUG on device $SIS_DEVICE..."
    		sispmctl -d $SIS_DEVICE -f $SIS_PLUG
    		echo "[printserv-job] done"
    		# Wartezeit, damit der Drucker nicht sofort wieder eingeschaltet wird.
    		sleep 1
    		rm -f $FILE_END $FILE_TMP
    	fi
    	) &
    	;;
    *)
    	echo "[printserv-job] start or end expected"
    	;;
    esac
    
    Damit wird nach Beenden des Jobs im Hintergrund 30 Sekunden gewartet, das Skript wird jedoch beendet und der Printserver ist bereit für den nächsten Job. Die Zeit, zu der der Job beendet wurde, wird in FILE_END festgehalten.

    Falls in den nächsten 30 Sekunden ein neuer Job gestartet wird, wird dessen Zeit in FILE_START festgehalten. Da dies nach dem Beenden des ersten Jobs ist, ist in dem Test FILE_START neuer als FILE_END, und der Drucker wird nicht ausgeschaltet.

    Umgekehrt wird beim Start auf die Existenz von FILE_END getestet. Diese Datei wird gelöscht, wenn der Drucker ausgeschaltet wird. Wenn die Datei noch existiert, muss der Drucker nicht eingeschaltet werden.

    Die Datei FILE_TMP wird als Semaphore verwendet. Wenn die Datei existiert, wird der Drucker nicht ausgeschaltet, weil dann gerade ein neuer Druckauftrag gestartet wurde. Wenn andererseits die Datei existiert, wenn ein Druckauftrag gestartet werden soll, dann wird gerade der Drucker ausgeschaltet. In diesem Fall wird solange gewartet, bis die Datei nicht mehr existiert. Die Verzögerung nach dem Ausschalten dient dazu, dass der Drucker etwas Pause zwischen aus und einschalten hat. Manchen Geräten bekommt eine zu kurze Pause nicht, evtl. muss man die Zeit verlängern.
     
  11. stan23

    stan23 Neuer User

    Registriert seit:
    4 Sep. 2010
    Beiträge:
    63
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Beruf:
    Specialist Mobile Power Management
    Ort:
    Beilngries
    Danke Ralf, das sieht gut aus.
    Ich teste es mal diese Woche und melde mich dann wieder.
     
  12. caldir65

    caldir65 Neuer User

    Registriert seit:
    26 Juni 2008
    Beiträge:
    112
    Zustimmungen:
    0
    Punkte für Erfolge:
    16
    Ort:
    Melle
    Hey,

    klasse, die Arbeiten von Euch smilie_op_010.gif
    Jetzt müsste nur noch eine Möglichkeit angebunden werden, die Parameter z.B. per Config-File zu beeinflussen, ohne gleich den Quellcode neu übersetzen zu müssen ;)

    Leider kann ich nicht coden, so daß das meine Möglichkeiten weit überschreitet ...

    Gruß, Christoph
     
  13. RalfFriedl

    RalfFriedl IPPF-Urgestein

    Registriert seit:
    22 Apr. 2007
    Beiträge:
    12,343
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Vielleicht kannst Du aber wenigstens die Parameter nennen, die Deiner Meinung nach aus dem Quellcode in ein Config-File sollen?
     
  14. caldir65

    caldir65 Neuer User

    Registriert seit:
    26 Juni 2008
    Beiträge:
    112
    Zustimmungen:
    0
    Punkte für Erfolge:
    16
    Ort:
    Melle
    Hey,

    oh, sorry, klar, hier kommen sie:

    Code:
    # device number
    SIS_DEVICE=0
    # plug number
    SIS_PLUG=1
    # waiting time after switching on (let printer boot)
    WAIT_START=30
    # waiting time before switching off (wait for another job)
    WAIT_END=30
    Somit müßte nicht jedes Mal der Quellcode beackert werden, wenn jemand andere Vorstellungen hat, oder das Gerät anderes Vorgehen verlangt.

    Ein Laserdrucker zum Bsp. bzw. seine Fixiereinheit hat es nicht gerne, zu oft ein- und wieder ausgeschaltet zu werden - da sollte dann evtl. auch ein längerer Zeitraum des Wartens auf weitere Druckjobs einstellbar sein.
    Zudem hängt es ja auch stark vom jeweiligen Drucker ab, wie lange nach dem Einschalten noch gewartet werden sollte.

    auf welchem Port der Steckdose liegt der Drucker?

    Welches Device (Steckdosenleiste) muß nicht unbedingt - ich nehme mal an, daß nicht viele einen Drucker via SISPM und Fritzbox steuern wollen und auch noch mehrere SISPM angeschlossen haben ;)

    Letztlich macht es das ganze hinterher auch einfacher, wenn z.B. mal wieder ein neuer Drucker angeschlossen werden soll, weil der Alte wieder einmal seinen Dienst verweigert, da abgeraucht :D

    Gruß, Christoph
     
  15. RalfFriedl

    RalfFriedl IPPF-Urgestein

    Registriert seit:
    22 Apr. 2007
    Beiträge:
    12,343
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Und inwieweit ist es einfacher, eine Konfigurationsdatei zu ändern als die Zeilen direkt in der Datei zu ändern?
     
  16. olistudent

    olistudent IPPF-Urgestein

    Registriert seit:
    19 Okt. 2004
    Beiträge:
    14,761
    Zustimmungen:
    5
    Punkte für Erfolge:
    38
    Beruf:
    Softwareentwickler
    Ort:
    Kaiserslautern
    Ich hab kein gcc auf der Box, so dass ich sowas direkt ändern könnte. :mrgreen:
     
  17. RalfFriedl

    RalfFriedl IPPF-Urgestein

    Registriert seit:
    22 Apr. 2007
    Beiträge:
    12,343
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Und ich dachte, Du hättest mal den GCC für die Box erstellt.

    Aber der Ausschnitt ist aus einem Shell-Skript. Das C-Programm oben ist so aufgebaut, dass es nur ein Skript aufruft, dieses ist dann für die weiteren Aktionen zuständig.
     
  18. caldir65

    caldir65 Neuer User

    Registriert seit:
    26 Juni 2008
    Beiträge:
    112
    Zustimmungen:
    0
    Punkte für Erfolge:
    16
    Ort:
    Melle
    Ich dachte da an User, die sich nicht auf Shellebene mit Telnet auf der Box bewegen ... Abgesehen davon, wenn man nach einem z.B. Jahr einen neuen Drucker bekommt, findet man solche Einstellungen in der Freetz-Oberfläche mit sicherheit schneller wieder als in den Tiefen der Box ;) Und dann kann man bestimmt mittels Webfrontend auch direkt diese Parameter in der Datei beackern, oder?

    Gruß, Christoph
     
  19. RalfFriedl

    RalfFriedl IPPF-Urgestein

    Registriert seit:
    22 Apr. 2007
    Beiträge:
    12,343
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Auch, vorhin hat noch ein Config-File gereicht, jetzt soll es gleich ein Webfrontend sein?

    Das Skript ist sowieso nur ein Beispiel dafür, was man mit den Start und Stop Aktionen anstellen kann.
     
  20. caldir65

    caldir65 Neuer User

    Registriert seit:
    26 Juni 2008
    Beiträge:
    112
    Zustimmungen:
    0
    Punkte für Erfolge:
    16
    Ort:
    Melle
    Hey,

    ich denke dabei ja nur an solche Nutzer, die halt nicht soo tief in allem drin stecken ;)

    Gruß, Christoph