Paramiko Output abfangen

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Itech
User
Beiträge: 20
Registriert: Freitag 6. Juli 2018, 15:44

Moin Moin

Umgebung
Es befinden sich zwei Raspberry Pi 4 mit jeweils einer Kamera in meinem Netzwerk. Auf den beiden Pi's befindet sich ein Python Script, um Fotos über die Kameras aufzunehmen. Außerdem gibt es ein Windows Rechner im gleichen Netzwerk wie die Pi's, der sich per SSH verbindet.

Was ist mein Ziel
Ziel ist es, sich mit dem Windows Rechner per SSH gleichzeitig auf die Pi's zu verbinden und das Script für die Fotos zu starten. Beide Pi's sollen simultan Fotos erstellen.
Es soll auf dem Windows Rechner alle Print Befehle übertragen werden und es soll auch möglich sein einen Input auf dem Win Rechner zu geben. Im Endeffekt möchte ich die Scripte auf den Pi's Remote benutzen.

Mein Problem
Die SSH Verbindung zu den beiden Pi's funktioniert und das Script auf den Pi's wird auch richtig gestartet.
Die Scripte auf den Pi's warten aber auf einen User Input (User Input = Benennung der Fotos). Der Print Befehl für den Input bekomme ich aber nicht zurückgegeben, sodass die Scripte nicht weiterlaufen können und ich suche nach einer Möglichkeit Input Befehle per SSH zu übertragen.

Script auf dem Win Rechner 1 Variante

Code: Alles auswählen

import paramiko

 
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
        ssh.connect('IP', username='pi', password='raspberry')
except paramiko.SSHException:
        print ("Connection Failed")
        quit()
 
stdin,stdout,stderr = ssh.exec_command("python3 camera.py", get_pty=True)
 
for line in stdout.readlines():
        print (line.strip())
 

###############################


ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
        ssh.connect('10.0.0.98', username='pi', password='raspberry')
except paramiko.SSHException:
        print ("Connection Failed")
        quit()
 
stdin,stdout,stderr = ssh.exec_command("python3 camera.py", get_pty=True)
 
for line in stdout.readlines():
        print (line.strip())

        
ssh.close()
Script auf dem Win Rechner 2 Variante

Code: Alles auswählen

import paramiko
import xlrd
import time

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

Host = '10.0.0.126'
Port = '22'
User = 'pi'
Pass = 'raspberry'

def details(Host, Port, User, Pass):
      time.sleep(2)

      ssh.connect(Host, Port, User, Pass)
      print('connected to ip ', Host)

      stdin = ssh.exec_command("python3 camera.py")
      remote_conn = ssh.invoke_shell()
      print("Interactive SSH session established")

      time.sleep(5)
      output = remote_conn.recv(10000)
      print(output)

      output = remote_conn.recv(1000)
      remote_conn.send("")
      remote_conn.send("")

details(Host, Port, User, Pass)
Script auf den beiden Pi's

Code: Alles auswählen

from picamera import PiCamera
import time
from time import sleep
import random
import string




camera = PiCamera()

id = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(13))


#print("Bitte den zu scannenden Produktnamen eingeben:")
produktname = input("Bitte den zu scannenden Produktnamen eingeben:   ")

print("Bitte, wenn vorhanden, eine EAN Nummer eingeben:   ")
#print("EAN:")
ean = input("EAN:")

gewicht = input("Wie viel wiegt der Artikel:   ")

i = 0

start = input("Maschine starten mit Enter  ")

while i < 100:
    variable = "/home/pi/pictures/" + produktname + "-" + id + "-" + ean + "-" + gewicht + "g" + ".jpg"
    camera.capture(variable)
    i += 1
    print(i)


    print("Ein Foto wurde aufgenommen.")
    wait = input("Den nächsten Durchgang mit Enter starten ")
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dann übergib die Parameter als Kommandozeilen-Argumente, statt die mit Input abzufragen, und schon muss nix und niemand auf etwas warten.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Du mußt doch nur nach stdin schreiben. Keine Notwendigkeit pty zu benutzen. Besser wären natürlich Kommandozeilenparameter.
time und sleep werden gar nicht verwendet. Warum wird das Bild immer wieder überschrieben? Was ist der Sinn gerade 100 Bilder zu machen, wenn man zum Schluß eh nur eins hat?
Und wie weiß der Nutzer den Namen der Datei, wenn sie eine zufällige ID enthält?
Itech
User
Beiträge: 20
Registriert: Freitag 6. Juli 2018, 15:44

Sirius3 hat geschrieben: Mittwoch 18. März 2020, 09:38 Du mußt doch nur nach stdin schreiben. Keine Notwendigkeit pty zu benutzen. Besser wären natürlich Kommandozeilenparameter.
time und sleep werden gar nicht verwendet. Warum wird das Bild immer wieder überschrieben? Was ist der Sinn gerade 100 Bilder zu machen, wenn man zum Schluß eh nur eins hat?
Und wie weiß der Nutzer den Namen der Datei, wenn sie eine zufällige ID enthält?
Die Bilder überschreiben sich eigentlich nicht. Nach den lokalen Tests waren 100 Bilder vorhanden. Neben der ID ist das Bild auch mit den Inputs benannt.
(ID-Produktname-...) Die Bilder werden danach auch noch weiterverarbeitet, deswegen diese Benennung.
Liefert er die Kommandozeilenparameter dann auch wieder zurück oder wo besteht dort der Unterschied?
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Was meinst Du mit "zurückliefern"? Du schickst sie doch, da müssen sie doch nicht zurückkommen.
Der Dateiname enthält kein i, also sind die alle gleich.
Itech
User
Beiträge: 20
Registriert: Freitag 6. Juli 2018, 15:44

Nach jedem gemachten Foto wartet das Script auf eine Eingabe zb. Enter, damit es das nächste Foto macht. Ich habe die Befürchtung das man die damit nicht abfangen kann.
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wie schon erwaehnt, entferne diese ganzen unnoetigen Inputs. Lass das Skript *ein* Foto machen, und in dem Moment kannst du es vom Host aus 1, 13, 29 oder 100 mal triggern.
Benutzeravatar
__blackjack__
User
Beiträge: 13103
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Itech: Die Namen von eingebauten Funktionen sollte man nach Möglichkeit nicht überschreiben. Es gibt eine Funktion die `id()` heisst.

Der Zeichenvorrat für die einzelnen ID-Zeichen wird 13 mal aus den gleichen drei Teilen zusammengesetzt. Das sollte man aus dem Generatorausdruck heraus ziehen.

`start` und `wait` werden Werte zugewiesen die nie irgendwo verwendet werden. Dann kann man die Namen auch weglassen.

Die ``while``-Schleife wäre einfacher und deutlicher eine ``for``-Schleife, denn es ist am Schleifenanfang klar wie oft die durchlaufen wird und ein Leser muss nicht erst schauen unter welchen Bedigungen sich `i` wie ändert.

`variable` ist kein guter Name für einen Dateinamen.

Zeichenketten und Werte stückelt man nicht mit ``+`` zusammen. Das ist eher BASIC als Python. In Python gibt es dafür Zeichenkettenformatierung mit der `format()`-Methode und ab Python 3.6 f-Zeichenkettenliterale.

Pfadteile setzt man nicht mit ``+`` zusammen. Dafür gibt es das `pathlib`-Modul.

Die `input()`-Aufrufe die auf eine Eingabe warten um mit dem nächsten Schritt fort zu fahren sind unlogisch verteilt. Statt das einmal vor der Schleife und dann immer am Schleifenende zu machen, sollte man das einmal, in der Schleife vor der Aufnahme stehen haben. So wie es jetzt ist, startet man mit dem letzten mal gar keinen neuen Durchgang wie der ausgegebene Text behauptet, sondern braucht noch eine 101. Eingabe um das Programm zu beenden.

Die Kamera sollte am Ende auch sauber wieder freigegeben werden. Dazu bietet sich die ``with``-Anweisung an.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import random
import string
from pathlib import Path

from picamera import PiCamera

PICTURE_PATH = Path("/home/pi/pictures")
ID_ALPHABET = string.ascii_uppercase + string.ascii_lowercase + string.digits


def main():
    id_ = "".join(random.choice(ID_ALPHABET) for _ in range(13))
    produktname = input("Bitte den zu scannenden Produktnamen eingeben: ")
    print("Bitte, wenn vorhanden, eine EAN Nummer eingeben: ")
    ean = input("EAN: ")
    gewicht = input("Wie viel wiegt der Artikel: ")

    filename = PICTURE_PATH / "{}-{}-{}-{}g.jpg".format(
        produktname, id_, ean, gewicht
    )
    with PiCamera() as camera:
        for i in range(100):
            input("Ein Photo mit Enter schiessen ")
            camera.capture(str(filename))
            print(i + 1)


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Itech
User
Beiträge: 20
Registriert: Freitag 6. Juli 2018, 15:44

__blackjack__ hat geschrieben: Mittwoch 18. März 2020, 11:50 @Itech: Die Namen von eingebauten Funktionen sollte man nach Möglichkeit nicht überschreiben. Es gibt eine Funktion die `id()` heisst.

Der Zeichenvorrat für die einzelnen ID-Zeichen wird 13 mal aus den gleichen drei Teilen zusammengesetzt. Das sollte man aus dem Generatorausdruck heraus ziehen.

`start` und `wait` werden Werte zugewiesen die nie irgendwo verwendet werden. Dann kann man die Namen auch weglassen.

Die ``while``-Schleife wäre einfacher und deutlicher eine ``for``-Schleife, denn es ist am Schleifenanfang klar wie oft die durchlaufen wird und ein Leser muss nicht erst schauen unter welchen Bedigungen sich `i` wie ändert.

`variable` ist kein guter Name für einen Dateinamen.

Zeichenketten und Werte stückelt man nicht mit ``+`` zusammen. Das ist eher BASIC als Python. In Python gibt es dafür Zeichenkettenformatierung mit der `format()`-Methode und ab Python 3.6 f-Zeichenkettenliterale.

Pfadteile setzt man nicht mit ``+`` zusammen. Dafür gibt es das `pathlib`-Modul.

Die `input()`-Aufrufe die auf eine Eingabe warten um mit dem nächsten Schritt fort zu fahren sind unlogisch verteilt. Statt das einmal vor der Schleife und dann immer am Schleifenende zu machen, sollte man das einmal, in der Schleife vor der Aufnahme stehen haben. So wie es jetzt ist, startet man mit dem letzten mal gar keinen neuen Durchgang wie der ausgegebene Text behauptet, sondern braucht noch eine 101. Eingabe um das Programm zu beenden.

Die Kamera sollte am Ende auch sauber wieder freigegeben werden. Dazu bietet sich die ``with``-Anweisung an.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import random
import string
from pathlib import Path

from picamera import PiCamera

PICTURE_PATH = Path("/home/pi/pictures")
ID_ALPHABET = string.ascii_uppercase + string.ascii_lowercase + string.digits


def main():
    id_ = "".join(random.choice(ID_ALPHABET) for _ in range(13))
    produktname = input("Bitte den zu scannenden Produktnamen eingeben: ")
    print("Bitte, wenn vorhanden, eine EAN Nummer eingeben: ")
    ean = input("EAN: ")
    gewicht = input("Wie viel wiegt der Artikel: ")

    filename = PICTURE_PATH / "{}-{}-{}-{}g.jpg".format(
        produktname, id_, ean, gewicht
    )
    with PiCamera() as camera:
        for i in range(100):
            input("Ein Photo mit Enter schiessen ")
            camera.capture(str(filename))
            print(i + 1)


if __name__ == "__main__":
    main()
Vielen Dank das ist deutlich besser geschrieben. Nur das Bild überschreibt sich , sodass am ende nur ein Bild vorhanden ist.
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Und darum muss der Bildname basierend auf der Variable i sein. Wie schon mehrfach erwaehnt. Und bitte keinen full-quote des Beitrages der eh direkt davor steht.
Itech
User
Beiträge: 20
Registriert: Freitag 6. Juli 2018, 15:44

Wie baue ich den i in den filename mit ein? Sry bin nicht wirklich fit in Programmieren
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

So wie Du alle anderen Variablen auch eingebaut hast: Format-String mit einem zusätzlichen Argument.
Antworten