Erste einfache GUI mit DHT22-Werten & Remote 433mhz

  • Hallo,

    tkinter kennt drei Layout-Manager: pack, grid und place. place möchten man in der Regel nicht verwenden, weil absolute Positonierung die Skalierung und Erweiterung des Fensters unflexibel machen.

    Aber, Tipp: Layout ist nice-to-have, du solltest an den anderen Punkten arbeiten und vernünftig Python lernen. Ein gut aussehende GUI ist genau nichts wert, wenn die Programmlogik dahiner suboptimal ist.

    Was zu Beispiel bei dir auch noch zu verbessern ist (hatte ich gestern nicht erwähnt): relais1_an / _aus und relais2_an / _aus sind fast identischer = redundanter Code -> das geht besser. Schreibe die Methode so um, dass sie als Argument einen GPIO-Pin (bzw. eine Instanz von OutputDevice) erwartet und diesen dann an oder aus schaltet.

    Gruß, noisefloor

  • Erste einfache GUI mit DHT22-Werten & Remote 433mhz? Schau mal ob du hier fündig wirst!

  • Also das mit File-close habe ich gelöst =>

    Code
    self.f = open("werte.txt")
    temp = self.f.readline()
    self.displayline['text'] = temp
    self.after(180000, self.update_display)
    self.f = close()

    Ja mit Layout halte ich mich erstmal nicht auf. Verstehe nicht so genau was du damit meinst, dass ich die Methode umschreiben soll. Nur dass sich die Namen ähnlich sind. Da muss ich mich noch in Ruhe rein denken.

    Ich hätte noch ein Problem was ich nicht verstehe. Ich habe der Datei sämtliche Berechtigungen hinzugefügt. Dann habe ich folgendes eingefügt:

    Python
    #!/usr/bin/python3

    Gestern konnte ich die Datei noch über anklicken direkt ausführen (also fast direkt -> Kommt noch ein Fenster mit Ausführen, Öffnen...). Heute kann ich die nicht Ausführen, ohne dass ich die über Thonny abspiele.

    Was stimmt da nicht?

  • Hallo,

    ich sag's mal direkt: die fünfte Zeile Code ist gruslig und zeigt dass du keine blassen Schimmer hast, was du da treibst. Klingt hart, aber so isses. Programmieren ist nun mal nicht raten.

    Man führt in der init-Methode nicht wild irgendwelche Code aus - wie ich oben schon sagte, das packt man strukturiert in Funktionen. Außerdem schließt du die Datei nicht, sondern bindest das Attribut `f` nur an den Rückgabewert der Funktion `close()` - was eigentlich in einer Fehlermeldung resultieren sollte, weil `close()` zu diesem Zeitpunkt eigentlich nicht existieren dürfte.

    Ernst gemeinter Tipp: vergiß' dein Projekt für ein paar Tage und nimm' dir die Zeit, dass offizielle Python-Tutorial durch zuarbeiten. Danach kann du / man zwar sicherlich nicht perfekt Programmieren, aber das Grundverständnis für Python sollte da sein, so dass zumindest das "ich rate mal Code" weitestgehend eliminiert sein sollte.

    Gruß, noisefloor

  • Hallo Igel85,

    Ich kann mich noisefloor nur anschließen. Es wird Zeit, dass du nochmal (ordentlich) zurückruderst und ein paar Grundlagen lernst.

    In #20 gab ich dir folgenden Link: https://docs.python.org/3.7/tutorial/i…d-writing-files

    Wenn du den verlinkten Abschnitt wirklich gelesen hast, so ist es mir schleierhaft wieso du a) immer noch so ein Wirrwar hast und b) auf eine Seite von tutorialspoint zurückgreifen musst.

    Jetzt noch mal im Schnelldurchgang: Lesen von Dateien in Python.

    Grundsätzlich erzeugst du zunächst ein Dateiobjekt mit open("/pfad/zur/datei.txt", "r"). Dieses hat die Methode read. Damit die Datei nicht unnötig lang blockiert wird, rufst du so bald wie möglich (nach dem Lesen) die Methode close des Dateiobjekts auf (mehr Infos in der verlinkten Doku).

    Konkret:

    Python
    f = open("/path/to/file.txt", "r")
    content = f.read()
    f.close()
    # Do something with `content`

    Der 2. Parameter von open ("r") ist zwar standardmäßig "r" und in diesem Fall somit optional, laut "Zen of Python" ist explizit aber besser als implizit.

    Nun gibt es eine tolle Sache namens Kontextmanager. Diese führen in der Regel "Aufräumarbeiten" aus, im Falle eines Dateiobjekts bedeutet das: die close-Methode wird automatisch aufgerufen.

    Konkret, analog zu obigem Code:

    Python
    with open("/path/to/file.txt", "r") as f:
        content = f.read()
    # Do something with `content`

    Das ist der empfohlene Weg.

    Wie bereits mehrfach erwähnt, macht es keinen Sinn, dein Dateiobjekt als Instanzvariable zu speichern (self.f = ...)!

    Desweiteren... noisefloor gibt eigentlich immer super konstruktives Feedback zu Python-Code aller Art, wie auch in deinem Fall. Wenn du davon etwas nicht verstehst, frage nochmal nach, es einfach zu ignorieren finde ich persönlich unhöflich.

    In #13 schrieb er bereits:

    Es ist unnötig, `f` als Klassenattribut zu deklarieren, weil du `f` im ganzen Code nur genau 1x brauchst.

    In #25 (!) hast du da immer noch self.f stehen...

  • Hallo zusammen,

    ich habe zusätzlich ein keypad angeschlossen und würde es gerne mit einbinden.

    Bei einem Tastendruck soll eine Funktion angesteuert werden.

    z.B. Taste 1 = Relais1_An (self)

    ... Usw.

    Bei einer nicht definierten Taste soll nichts passieren.

    Die Funktionen sind ja bereits im GUI Code definiert. Beim Tastendruck soll nur ausgeführt werden.

    Für das keypad benutzte ich folgenden Code:

  • Ich habe noch einen Code für die Steuerung des Keypads. Hier wird Aktuell nur die Eingabe ausgelesen und in der Shell wiedergegeben:

    Ist es möglich das Keypad per import mit einzubinden und dann mittels if Eingabe = 1: relais1_an.self ... So in der Art?

  • Hallo,

    davon ausgehend, dass dein Keypad sich wie eine "normale" Tastatur verhält und nicht irgendwas exotisches ist: tkinter braucht so Code nicht, weil es Methoden gibt, mit denen du Events an einen Tastendruck binden kannst: http://effbot.org/tkinterbook/tk…nd-bindings.htm.

    Und der 2. Code ist auch alles, aber nicht gut bzw. pythonisch.

    Und nochmal für dich: Programmieren ist nicht raten und Programmieren ist nicht Copy&Paste gepaart mit der Hoffnung, dass es läuft.

    Gruß, noisefloor

  • Habe leider zum Thema Keypad in Kombi mit tkinter u. events direkt so nichts gefunden. Überall wird nur der von mir gepostete Code verwendet. Ich dachte, ich könnte den als Basis benutzen und dann auf die Funktionen verweisen. Anscheinend nicht so einfach. Da ich kein Profi bin und bis dahin es noch ein wenig dauern wird, benutze ich eben für die Anfänge das Forum.

  • Hallo,

    du hast einfach zu kompliziert gedacht. Wie gesagt, tkinter kann direkt auf Tastendrücke reagieren und die kannst an einen Tastendruck einen Callback (wie das Schalten eines GPIO-Pins) binden. Das Prinzip ist in dem Link in meinem vorherigen Post erklärt.

    Wenn du nicht weiter kommst -> zeigt _deinen_ Code, beschreibe, was nicht läuft und dann schauen wir mal weiter :)

    Gruß, noisefloor

  • Das was ist nicht verstehe ist, wie ich das Keypad ansprechen soll. Dieses hängt ja an bestimmten GPIO.

    In meinem Fall:

    1. matrix = [["1","2","3", "A"],
    2. ["4","5","6", "B"],
    3. ["7","8","9", "C"],
    4. ["*", "0", "#", "D"]]
    5. spalte = [12, 16, 20, 21]
    6. zeile = [18, 23, 24, 25]

    Nun wird gemessen an welchem GPIO Strom fließt um zu ermitteln welche Taste gedrückt wurde.

    Mir ist nur ein Rätsel, wie ich in Tkinter das obige Keypad ansteuern soll.

  • Hallo,

    ach so... Ist das Keypad über die GPIO-Pins angeschlossen? Ich war davon ausgegangen, dass du ein USB Keypad hast...

    Die Integration in eine GUI ist _nicht_ ganz trivial, weil beide Codes auf Polling setzen und damit den Mainloop der GUI blockieren würden. Du müsstest also das Keypad bzw. die Funtkion, die die Tasten abfragt, periodisch über die `after()` Methode abfragen, die tkinter standardmäßig kennt.

    Das funktioniert aber wiederum nur vernünfitg, wenn du dein GUI als Klasse ausführst, was wieder bedingt, dass du Klassen und Methoden und Objektorierierung von Python grundlegend verstandn hast.

    Zeig' doch nochmal deinen aktuallen GUI-Code und dann noch, was du mit dem Keypad vor hast.

    Gruß, noisefloor

  • Hallo,

    also zunächst was ich mit dem Keypad vorhabe. Das Keypad soll auf Tastendruck die Funktionen ausführen, die es bereits auch in der GUI gibt. Dort werden diese ja per Button ausgeführt.

    Ich würde gerne mit den Keypad-Tasten auf die vorhandenen Funktionen verweisen, da hier dann auch gleich die Anzeige in der Status_Lbl und am LCD mit geändert wird.

    Folgende commands sollen beim Tastendruck ausgeführt werden:

    1 = ['command'] = self.led_on

    2 = ['command'] = self.relais1_an

    3 = ['command'] = self.relais2_an

    4 = ['command'] = self.relais1und2_an

    A = ['command'] = self.relais1und2_aus

    B = ['command'] = self.abort

    Sollten andere Tasten gedrückt werden, so soll nichts geschehen und eine erneute Eingabe sollte nach 1-2 Sek. wieder möglich sein.

    Das Keypad ist über 8 GPIO angeschlossen:spalte = [12, 16, 20, 21], zeile = [18, 23, 24, 25] # BCM-Nr.Aktuellen GUI-Code poste ich Heute Abend :)

  • Hier der aktuelle GUI-Code:

  • Also ich habe noch die Tage recherchiert. Und leider konnte ich zu diesem Thema absolut nichts passendes finden. Bin mir nicht sicher ob das dann so einfach möglich ist :/.... Der einzige Ansatz der mir noch vorschweben würde wäre die Methode value / source von gpio zero. Allerdings gibt es zu diesem Thema in Verbindung mit einem gpio matrix keypad auch keine Beispiele.... Bin mir jetzt nicht mehr sicher ob das so eine gute Investition war :D

  • Hallo,

    zu `after` Methode von tkinter findest du mit Sicherheit hunderte von Treffern...

    Ungetestet:

    Gruß, noisefloor

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!