Hallo in meinem Python Scribt möchte ich über die Abfrage zweier GPIO Pins welche als eingänge fundieren ein weiteres Python Programm (GUI Fenster) öffnen. Dies funktioniert soweit gut. Nur werden nicht beim Betätigen aller Eingängealle Programme geöffnet sondern immer nur das erste. das Programm hängt in der jeweiligen Schleife fest, bis das GUI Fenster geschlossen wird. Woran kann das liegen?
#!/usr/bin/python3
#coding: utf8
import RPi.GPIO as GPIO
import tkinter as tk
import subprocess
from tkinter import *
from subprocess import *
import os
import sys
import tkinter
InputList= [35,37] #Liste benötigte Pins
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(InputList, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
GPIO.add_event_detect(35, GPIO.RISING)
def ausgabe1():
#print("1")
os.system('python3 faltec7.py')
def ausgabe2():
#print("2")
os.system('python3 faltec8.py')
while (True):
if (GPIO.input(37) == GPIO.HIGH):
ausgabe1()
print("hello7")
if(GPIO.input(35) == GPIO.HIGH): #continue
ausgabe2()
print("Hello8")
GPIO.cleanup()
Probleme mit Schleifen und GUI Fenster
Bitte in Zukunft Code-Tags verwenden, damit man die in Python relevanten Einrückungen erkennen kann. Dazu im vollstaendigen Editor den </>-Knopf druecken, nachdem man den Quelltext markiert hat.
Und dieses Thema ist ein Murmeltierthema - sprich: es kommt jeden Tag. Bitte arbeite dich durch das tkinter Unterforum und lies mal ein paar andere Beitraege, die zu diesem Thema geschrieben werden. Es wird nicht lange dauern, versprochen.
Und dieses Thema ist ein Murmeltierthema - sprich: es kommt jeden Tag. Bitte arbeite dich durch das tkinter Unterforum und lies mal ein paar andere Beitraege, die zu diesem Thema geschrieben werden. Es wird nicht lange dauern, versprochen.
- __blackjack__
- User
- Beiträge: 14051
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@magic.pete: Das liegt daran das `os.system()` ein blockierender Aufruf ist, das heisst der kehrt erst zurück wenn das Programm was da gestartet wurde, auch wieder beendet wurde.
Davon abgesehen sollte man `os.system()` nicht verwenden. Dessen Dokumentation verweist auf das `subprocess`-Modul. Von dem Du ja auch alles per * importierst, aber dann nichts verwendest. Da sind sowieso ein ganzer Haufen unbenutzter und teilsweise unsinniger Importe. Per * sollte man eher nichts davon importieren weil einem das im Falle von `tkinter` beispielsweise hunderte von Namen ins Modul holt von denen in der Regel nur ein ganz kleiner Bruchteil verwendet wird. In diesem Fall sogar genau gar nichts. Und man importiert da nicht nur die Namen die im `tkinter`-Modul definiert werden sondern auch die Namen die das `tkinter`-Modul seinerseits von woanders importiert. Und es wird dann auch das `tkinter`-Modul noch mal unter dem `tk` und unter dem Namen `tkinter` importiert. Obwohl das Programm keine einzige Zeile GUI-Code enthält. Warum‽
Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst und nicht zwischen Funktionsdefinitionen auf Modulebene verteilt.
Um Bedingungen gehören keine unnötigen Klammern.
Warnungen sind nicht dazu da sie zu unterdrücken sondern damit man weiss das man irgend wo etwas falsch macht und die Ursache für die Warnung beheben kann. In diesem Fall sollte man *sicherstellen*, dass `GPIO.cleanup()` in jedem Fall aufgerufen wird, also auch wenn das Programm vom Benutzer per Strg+C oder durch eine Ausnahme abgebrochen wird.
Konstanten werden per Konvention KOMPLETT_GROSS geschrieben und Grunddatentypen haben nichts in Namen verloren. So etwas ändert sich im Laufe der Programmentwicklung gerne mal und dann hat man entweder falsche, irreführende Namen oder muss die überall anpassen.
Ich würde auch den beiden Pin-Nummern Namen geben statt im Programm diese ”magischen” Zahlen stehen zu haben.
Der `add_event_detect()` macht so keinen Sinn weil der keinen Effekt hat solange man da nicht auch eine Rückruffunktion angibt.
Den ``# continue``-Kommentar verstehe ich nicht. Kommentare die Kommentare brauchen damit man sie versteht sind keine guten Kommentare.
Ich würde da wenigstens ein ganz kleines bisschen Wartezeit in die ``while``-Schleife einbauen damit der Prozessor nicht 100% Rechenzeit auf die Abfrage der Pins verbrät.
Das ganze mal aufgeräumt:
Hat natürlich das gleiche Laufzeitverhalten weil auch `subprocess.run()` blockiert bis das externe Programm abgelaufen ist.
Letztlich ist das alles etwas komplexer wenn man auf Pin-Aktivität ein externes Programm starten möchte, das aber nur *einmal* und nebenläufig. Man wird `subprocess.Popen()` verwenden müssen und dann entweder in einer „busy loop“ (mit ein bisschen Wartezeit) prüfen müssen ob der Prozess beendet ist, oder mit Threads arbeiten müssen die auf das Ende eines externen Prozesses warten und das an den Hauptthread zurückmelden, zum Beispiel über eine `queue.queue`. `add_event_detect()` macht hier wahrscheinlich auch mehr Sinn als selbst in einer Schleife die Pins abzufragen.
Davon abgesehen sollte man `os.system()` nicht verwenden. Dessen Dokumentation verweist auf das `subprocess`-Modul. Von dem Du ja auch alles per * importierst, aber dann nichts verwendest. Da sind sowieso ein ganzer Haufen unbenutzter und teilsweise unsinniger Importe. Per * sollte man eher nichts davon importieren weil einem das im Falle von `tkinter` beispielsweise hunderte von Namen ins Modul holt von denen in der Regel nur ein ganz kleiner Bruchteil verwendet wird. In diesem Fall sogar genau gar nichts. Und man importiert da nicht nur die Namen die im `tkinter`-Modul definiert werden sondern auch die Namen die das `tkinter`-Modul seinerseits von woanders importiert. Und es wird dann auch das `tkinter`-Modul noch mal unter dem `tk` und unter dem Namen `tkinter` importiert. Obwohl das Programm keine einzige Zeile GUI-Code enthält. Warum‽
Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst und nicht zwischen Funktionsdefinitionen auf Modulebene verteilt.
Um Bedingungen gehören keine unnötigen Klammern.
Warnungen sind nicht dazu da sie zu unterdrücken sondern damit man weiss das man irgend wo etwas falsch macht und die Ursache für die Warnung beheben kann. In diesem Fall sollte man *sicherstellen*, dass `GPIO.cleanup()` in jedem Fall aufgerufen wird, also auch wenn das Programm vom Benutzer per Strg+C oder durch eine Ausnahme abgebrochen wird.
Konstanten werden per Konvention KOMPLETT_GROSS geschrieben und Grunddatentypen haben nichts in Namen verloren. So etwas ändert sich im Laufe der Programmentwicklung gerne mal und dann hat man entweder falsche, irreführende Namen oder muss die überall anpassen.
Ich würde auch den beiden Pin-Nummern Namen geben statt im Programm diese ”magischen” Zahlen stehen zu haben.
Der `add_event_detect()` macht so keinen Sinn weil der keinen Effekt hat solange man da nicht auch eine Rückruffunktion angibt.
Den ``# continue``-Kommentar verstehe ich nicht. Kommentare die Kommentare brauchen damit man sie versteht sind keine guten Kommentare.
Ich würde da wenigstens ein ganz kleines bisschen Wartezeit in die ``while``-Schleife einbauen damit der Prozessor nicht 100% Rechenzeit auf die Abfrage der Pins verbrät.
Das ganze mal aufgeräumt:
Code: Alles auswählen
#!/usr/bin/env python3
import subprocess
import RPi.GPIO as GPIO
BUTTON_A_PIN = 35
BUTTON_B_PIN = 37
PYTHON_EXECUTABLE_NAME = "python3"
def ausgabe_a():
subprocess.run([PYTHON_EXECUTABLE_NAME, "faltec7.py"], check=True)
def ausgabe_b():
subprocess.run([PYTHON_EXECUTABLE_NAME, "faltec8.py"], check=True)
def main():
try:
GPIO.setmode(GPIO.BOARD)
GPIO.setup(
[BUTTON_A_PIN, BUTTON_B_PIN], GPIO.IN, pull_up_down=GPIO.PUD_DOWN
)
while True:
if GPIO.input(BUTTON_B_PIN):
ausgabe_a()
print("hello7")
if GPIO.input(BUTTON_A_PIN):
ausgabe_b()
print("Hello8")
finally:
GPIO.cleanup()
if __name__ == "__main__":
main()
Letztlich ist das alles etwas komplexer wenn man auf Pin-Aktivität ein externes Programm starten möchte, das aber nur *einmal* und nebenläufig. Man wird `subprocess.Popen()` verwenden müssen und dann entweder in einer „busy loop“ (mit ein bisschen Wartezeit) prüfen müssen ob der Prozess beendet ist, oder mit Threads arbeiten müssen die auf das Ende eines externen Prozesses warten und das an den Hauptthread zurückmelden, zum Beispiel über eine `queue.queue`. `add_event_detect()` macht hier wahrscheinlich auch mehr Sinn als selbst in einer Schleife die Pins abzufragen.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
-
- User
- Beiträge: 5
- Registriert: Mittwoch 8. Januar 2020, 11:50
Das ging ja schnell. Vielen Lieben Dank. Ich habe die Änderung übernommen.Leider tritt der Fehler genau noch so auf.
- __blackjack__
- User
- Beiträge: 14051
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
Sagte ich ja, ich habe ja semantisch nicht wirklich etwas geändert. Da ist halt die Frage wie sich das am Ende genau verhalten soll.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Ja, __blackjack__s Skript funktioniert noch so, wie Deines, nur besser. Du mußt die Prozesse so starten, dass sie nicht auf das Ende warten. Dann mußt Du aber selbst prüfen, wann der Prozess fertig ist, außerdem mußt Du sicherstellen, dass nur ein Prozess nur einmal gestartet werden kann.
-
- User
- Beiträge: 5
- Registriert: Mittwoch 8. Januar 2020, 11:50
Der Prozess ist ein GUI -Fenster welches dem Benutzer anzeigt, dass ein Taster betätigt wurde. Dieses Fenster wird aktiv über einen Button vom Benutzer beendet.
Es sollen aber je nach dem welche Taster betätigt werden mehrere Informationsfenster zur gleichen Zeit auf gehen können. So nach der Art Notfallklingel im Krankenhaus.
wie soll ich das Fenster starten ohne das dieses auf das Ende wartet?
#!/usr/bin/env python3
#coding: utf8
import RPi.GPIO as GPIO
import os
from tkinter import *
fenster1 = Tk()
fenster1.title("Materialbedarf-Faltec 7")
fenster1.geometry("500x300+1050+50")
fenster1.config(background = "#0099ff")
label=Label(master=fenster1,text="Faltec 7",relief="solid",width=50,font=("arial",20,"bold"))
label.place(x = 80, y = 50, width=300, height=60)
label.config(background = "red")
button = Button(master=fenster1, text="Recet",command = fenster1.destroy) #Erzeugung des Button 1
button.place(x = 400, y = 50, width=80, height=60)
button.config(background = "white")
button.config(font=('Arial', 15))
if __name__ == "__main__":
fenster1.mainloop()
Es sollen aber je nach dem welche Taster betätigt werden mehrere Informationsfenster zur gleichen Zeit auf gehen können. So nach der Art Notfallklingel im Krankenhaus.
wie soll ich das Fenster starten ohne das dieses auf das Ende wartet?
#!/usr/bin/env python3
#coding: utf8
import RPi.GPIO as GPIO
import os
from tkinter import *
fenster1 = Tk()
fenster1.title("Materialbedarf-Faltec 7")
fenster1.geometry("500x300+1050+50")
fenster1.config(background = "#0099ff")
label=Label(master=fenster1,text="Faltec 7",relief="solid",width=50,font=("arial",20,"bold"))
label.place(x = 80, y = 50, width=300, height=60)
label.config(background = "red")
button = Button(master=fenster1, text="Recet",command = fenster1.destroy) #Erzeugung des Button 1
button.place(x = 400, y = 50, width=80, height=60)
button.config(background = "white")
button.config(font=('Arial', 15))
if __name__ == "__main__":
fenster1.mainloop()
-
- User
- Beiträge: 5
- Registriert: Mittwoch 8. Januar 2020, 11:50
das Programm ist nur der Übersichtlichkeit separat. Ich hatte es auch schon mit eingebunden. Das Problem bestand fort.
Das Thema subprocess bekomme ich nicht zum laufen. Keine Ahnung.
Das Thema subprocess bekomme ich nicht zum laufen. Keine Ahnung.
Was heißt denn "mit eingebunden".
Es ist zumindest sehr ungewöhnlich ein anderes Python-Script als externen Prozess aus einem Python-Script heraus zu starten. In der Regel ist dann das Problem, dass noch nicht verstanden wurde, dass es Module gibt und wie diese angesprochen werden.
Und wenn dann die Datenanamen der Scripte durchnummeriert sind, ist das auch kein gutes Zeichen.
Vielleicht solltest du etwas weiter ausholen, was dein Problem angeht.
Es ist zumindest sehr ungewöhnlich ein anderes Python-Script als externen Prozess aus einem Python-Script heraus zu starten. In der Regel ist dann das Problem, dass noch nicht verstanden wurde, dass es Module gibt und wie diese angesprochen werden.
Und wenn dann die Datenanamen der Scripte durchnummeriert sind, ist das auch kein gutes Zeichen.
Vielleicht solltest du etwas weiter ausholen, was dein Problem angeht.
-
- User
- Beiträge: 5
- Registriert: Mittwoch 8. Januar 2020, 11:50
ganz einfach gesagt, Such ich nach einer Möglichkeit , wobei ich über die Eingänge eine Information auf den Bildschirm schalten kann. Jeder Eingang soll ein Taster sein welchem genau eine INformation oder Nachricht zugeordnet ist. Nachdem die Nachrichten gelesen wurden, sollten Sie per Button wieder geschlossen werden. Dazu wollte ich das Tkinter Fenster nutzen. Nun kann es sein das mehrere Taster hintereinander betätigt werden, dies Fenster sollen auch alle erscheinen. Dies funktioniert aktuell nicht. Erst wenn eines geschlossen wird kann ein neues aktiviert werden.
- __blackjack__
- User
- Beiträge: 14051
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@magic.pete: Der Grund dafür wurde ja schon genannt: `subprocess.run()` kehrt erst zum Aufrufer zurück wenn das externe Programm beendet ist. Um asynchron Programme zu starten gibt es `subprocess.Popen()`. Da musst Du dann selber dafür sorgen, dass das Programmende erkannt wird und entsprechend darauf reagiert wird.
Nur um Fenster anzuzeigen braucht man aber keine externen Programme starten die dann auch in Python geschrieben sind. Das würde man sinnvollerweise in *einem* Programm machen.
Wie man es letztendlich löst, es bleibt am Ende nebenläufige Programmierung bei der eine GUI involviert ist, also auch mit den entsprechenden Problemen. Egal ob man das auf mehrere Programme verteilt oder nicht.
In einem Programm würde man ein Hauptfenster erstellen und das gleich wieder mit `withdraw()` verschwinden lassen, weil es nur *ein* Hauptfenster geben darf. Weitere Fenster erstellt man mit `tkinter.Toplevel`.
Diese ganzen Grössen und Positionsangaben sind eher keine gute Idee. So etwas überlasst man besser der Fensterverwaltung im Falle von Fenstern und einem Layoutmanager im Falle von Elementen innerhalb von Fenstern.
Nur um Fenster anzuzeigen braucht man aber keine externen Programme starten die dann auch in Python geschrieben sind. Das würde man sinnvollerweise in *einem* Programm machen.
Wie man es letztendlich löst, es bleibt am Ende nebenläufige Programmierung bei der eine GUI involviert ist, also auch mit den entsprechenden Problemen. Egal ob man das auf mehrere Programme verteilt oder nicht.
In einem Programm würde man ein Hauptfenster erstellen und das gleich wieder mit `withdraw()` verschwinden lassen, weil es nur *ein* Hauptfenster geben darf. Weitere Fenster erstellt man mit `tkinter.Toplevel`.
Diese ganzen Grössen und Positionsangaben sind eher keine gute Idee. So etwas überlasst man besser der Fensterverwaltung im Falle von Fenstern und einem Layoutmanager im Falle von Elementen innerhalb von Fenstern.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Ich habe es schon gesagt, und ich sag's auch gerne nochmal: das ansteuern von GPIOs in Kombination mit tkinter wird hier permanent diskutiert. Hast du dir mal Beispiele angesehen, wie andere hier das machen bzw was denen geraten wird, wie sie soetwas umsetzen? Und nein - mehrere Prozesse sind dafuer NICHT die Antwort.
@magic.pete: warum werden die Fenster per Taster geöffnet aber per Knopf wieder geschlossen? Wie hast Du Dir das vorgestellt, wenn mehrere Fenster auf dem Bildschirm sind, dass die sich nicht überlappen (denn sonst kann man sie ja nicht lesen)?
Grundaufbau:
Jedes Informations-Fenster wird als Tkinter-TopLevel modeliert (das jeweils in einem eigenen Modul stehen kann). Das Tk-Hauptfenster ist von Anfang sichtbar oder unsichtbar da und der mainloop läuft. Die Taster werden über add_event_detect gesteuert und füllen darin eine Queue, die per after im Hauptfenster abfragt, ob und welches Info-Fenster geöffnet werden soll.
Grundaufbau:
Jedes Informations-Fenster wird als Tkinter-TopLevel modeliert (das jeweils in einem eigenen Modul stehen kann). Das Tk-Hauptfenster ist von Anfang sichtbar oder unsichtbar da und der mainloop läuft. Die Taster werden über add_event_detect gesteuert und füllen darin eine Queue, die per after im Hauptfenster abfragt, ob und welches Info-Fenster geöffnet werden soll.