Infostandsystem - Auslesen von NFC-Tags (PN532)

L I V E Stammtisch ab 20:30 Uhr im Chat
  • `if data is not None:` kannst du einfacher als `if data` schreiben. `is not None` ist eine doppelte Verneinung und damit das gleiche.

    Das ist einfach Falsch! if data is not None: liefert auch 'True' wenn data = 0. if data: liefert in diesem Fall aber 'False'.

    Deswegen sollte man so etwas immer im Kontext sehen, vor allem, wenn '0' ein gültiges Datum ist.

  • Das ist einfach Falsch! if data is not None: liefert auch 'True' wenn data = 0. if data: liefert in diesem Fall aber 'False'.

    Deswegen sollte man so etwas immer im Kontext sehen, vor allem, wenn '0' ein gültiges Datum ist.

    Gleiches Spiel mit leeren Strings, Listen etc. Manchmal ist None der "schlechte" Wert und ein leerer String, Liste etc. sind "ok". Kommt immer drauf an ;)

  • Hallo!

    Ich habe mich nun mit dieser klassenorientieren Entwicklung beschäftigt und da mal mal Anfänge geschaffen. Nun bekomme ich folgende Error nicht weg:

    Das ist der Quellcode dazu:

    LG und vielen Dank für die Hilfe

    Steffen

  • Ich habe mich nun mit dieser klassenorientieren Entwicklung beschäftigt und da mal mal Anfänge geschaffen. Nun bekomme ich folgende Error nicht weg:

    Du hast ja auch keine globale Funktion changeinterface - aber eine Medthode in der selben Klasse. Python kann aber nicht hellsehen, also musst du auf die Methode über self zugreifen (Instanz der Klasse).

    Siehe Python OOP-Grundlagen hier: https://docs.python.org/3/tutorial/classes.html

  • Du hast ja auch keine globale Funktion changeinterface - aber eine Medthode in der selben Klasse. Python kann aber nicht hellsehen, also musst du auf die Methode über self zugreifen (Instanz der Klasse).

    Siehe Python OOP-Grundlagen hier: https://docs.python.org/3/tutorial/classes.html

    Ich habe jetzt alle Variablen auch in die Klasse verlegt da es bei einer möglichen späteren Erweiterung um eine LED-Lichtsteuerungsklasse so übersichtlicher bleibt. Nach den Ausgaben zu urteilen läuft das Script auch ganz gut bis es zur Auswertung der Daten kommt... nun erhalte ich folgenden Fehler:

    Ich weiß echt nicht woran es liegen kann weil genau die Befehle in einem anderen Script (hier Script 2) nicht diesen Fehler auslösen:


  • Linus

    Ich habe das Programm jetzt komplett neu geschrieben und dabei etwas abgespeckt. Dabei sind auch alle bestehenden Fehler verschwunden...

    Leider bekomme ich jetzt aber diesen Fehler:

    Zitat

    File "SensorUI.py", line 58, in sensorabfrage

    self.changewindow(part=obj)

    TypeError: changewindow() got multiple values for keyword argument 'part'

    Kannst du (oder auch jemand anderes) mir erklären wo hier das Problem liegt?:wallbash::helpnew:

    Der neue Code:

    Um mich für diese bisher schon gigantische Hilfe von euch zu revongieren, habe ich mir etwas überlegt. Allen Leuten, die mir in diesem Thread aktiv geholfen haben ( Linus , Hofei , noisefloor ) möchte ich anbieten (falls ihr keinen eigenen 3D-Drucker habt) Teile für euer nächstes Projekt auszudrucken, falls ihr das gebrauchen könnt. Dafür könnt ihr mir einfach eine DM schicken.:angel:

    Vielen Dank für die ganze nette Hilfe bisher!:bravo2::danke_ATDE:

    LG

    Steffen

  • Kannst du (oder auch jemand anderes) mir erklären wo hier das Problem liegt? :wallbash:

    Infostandsystem - Auslesen von NFC-Tags (PN532)

    da fehlt ein self ;)

    -> def changewindow(self, part):

    Mit welchen Editor programmierst du? Ich würde dir PyCharm ans Herz legen!

    Vielen Dank für dein Angebot, eventuell komme ich mal darauf zurück ;) und du noch im Forum bist

    Aber generell biete ich meine Hilfe ohne jegliche Bezahlung an, das ganze basiert auf Freiwilligkeit.

    Viel mehr ist geholfen, wenn du dich einfach hier im Forum aktiv beteiligst und selbst Fragen beantwortest von Hilfesuchenden.

  • Ich würde dir PyCharm ans Herz legen!

    Ich würde dir VSCode ans Herz legen! PyCharm ist für große Projekte in Ordnung (aber auch kein muss), für kleine finde ich es völlig übertrieben. Als IntelliJ-basierende IDE braucht es relativ viele Ressourcen und ist träge.

    Aber generell biete ich meine Hilfe ohne jegliche Bezahlung an, das ganze basiert auf Freiwilligkeit.

    Dem schließe ich mich an. Außerdem darf ich mich selbst Besitzer eines Anet A8 nennen ;)

  • Noch mehr Kritik hilfreiche Tipps:

    • Konsistente Einrückungen sind wichtig. Nicht nur das, konsistenter Code allgemein ist wichtig. So solltest du IMMER 4 Leerzeichen pro Ebene einrücken - nicht mehr, nicht weniger, keine Tabs, nichts mischen.
      Verwende am besten einen Code-Formatter (Black erfreut sich wachsender Beliebtheit und wurde sogar in die GitHub-Organisation der PSF übertragen: https://github.com/psf/black). So spart man sich mühsame Handarbeit und muss sich nicht über Formatierung Gedanken machen.
    • Alle Variablennamen von Konstanten GROSS_MIT_UNTERSTRICH schreiben
    • Das Hauptprogramm in einer Funktion kapseln und mit if __name__ == "__main__": main() ausführen. Dieses weit verbreitete Konstrukt ist hier sehr ausführlich erklärt: https://code.visualstudio.com/docs/python/linting https://stackoverflow.com/a/419185/5952681
      Im globalen Namensraum sollten sich nur Funktionen/Klassendefinitionen, Konstanten und Imports befinden
    • Imports sortieren - ist nicht zwingend notwendig, aber übersichtlicher. Viele (inkl. mir) verwenden folgendes:

      Also zuerst die Module aus der Standardbibliothek, dann externe (i.d.R. mit pip installierte) Module, dann die eigenen zum Projekt gehörenden.

    • Warum enthalten einige deiner Methoden ein return True? Das hat keinen Mehrwert, erst Recht wenn du mit dem Rückgabewert nichts tust. Selbst für sensorabfrage solltest du es nicht brauchen, siehe Doku: https://developer.gnome.org/pygobject/stab…ib--timeout-add
    • teil = part bringt... nichts. Nenne den Parameter gleich teil oder verwende part im Code.
    • Strings werden nicht mit + zusammengesetzt, niemalsnie. Nimm str.format (https://docs.python.org/3/library/stdtypes.html#str.format) oder noch viel besser f-Strings (https://docs.python.org/3/reference/le….html#f-strings, ab Python 3.6, auf dem neuen Raspbian Buster ist 3.7). Beides ist deutlich mächtiger (siehe Doku) und erhöht die Lesbarkeit des Codes.
    • Andererseits ist ein sowas eher schlecht: '{0}'.format(int(data[2:8].decode("utf-8"), 16)). Das ist besser und kürzer als str(int(data[2:8].decode("utf-8"), 16)) geschrieben - du willst ja keinen String formatieren, sondern eine Nummer in einen String konvertieren. Wobei das hier auch nicht optimal ist, verwende einfach Integer als Keys im Dictionary karten. Und if action is not None: kannst du dir sparen, da das Ergebnis von str.format immer ein String sein wird.
    • Bleibe mit der Sprache konsistent. Entweder allen eigenen Code Deutsch, oder viel besser, alles auf Englisch. Alles andere wird einfach nur unlesbar.
    • Folge dem "Don't repeat yourself"-Prinzip (DRY). Der Code im Konstruktor und changewindow gehört in eine gemeinsam verwendbare Funktion/Methode ausgelagert um Wiederholungen zu vermeiden.
    • Vermeide global, das ist in 99.9% falsch. Du hast doch eine Klasse und kannst Instanz-Attribute verwenden!
    • Denk' dir was besseres aus, als None und "none" zu mischen. Es ist spät und ich hab' schon den ganzen Tag auf Code gestarrt, ich werde jetzt nicht versuchen, das zu entziffern :lol:
    • Verwende sinnvolle Kommentare. Keine Sorge, ich habe auch ewig gebraucht, bis ich das halbwegs drauf hatte - aber #Auswertung der Daten oder # Timer starten haben wirklich keinen Mehrwert - das ist doch mehr als offensichtlich. Lieber sollten kompliziertere Codestellen erklärende Kommentare haben, und da muss man dann auch nicht sparsam sein. Dazu gibt's jede Menge Lesestoff im Internet, z.B. https://www.freecodecamp.org/news/code-comm…y-be9cc65fbf83/

    Vieles davon ist Teil von PEP 8, dem in der Python-Community anerkannten Styleguide: https://www.python.org/dev/peps/pep-0008/. Das solltest du beachten, dabei kann dir teilweise ein Formatter, teilweise ein Linter helfen. (z.B. https://code.visualstudio.com/docs/python/linting)

    Zu guter Letzt - laut deinem Profil bist du 17 Jahre alt - aus Erfahrung weiß ich, dass sich nicht viele leider immer weniger Schüler*innen/junge Menschen für "Computerzeugs" interessieren, bei der derzeitigen Situation bezüglich Informatik-Unterricht in den deutschen Schulen ja auch kein Wunder. Weiter so! :bravo2:

  • Das ist mir auch klar! :angel:

    Dafür vielen Dank! Wenn ich das Gefühl habe helfen zu können, werde ich das natürlich auch tun, denn so funktioniert ein Forum ja... da ich die Möglichkeit habe wollte ich jedoch trotzdem so etwas Projektbezogenes anbieten.

    LG :baeh2:

  • Noch mehr Kritik hilfreiche Tipps:

    • Konsistente Einrückungen sind wichtig. Nicht nur das, konsistenter Code allgemein ist wichtig. So solltest du IMMER 4 Leerzeichen pro Ebene einrücken - nicht mehr, nicht weniger, keine Tabs, nichts mischen.
      Verwende am besten einen Code-Formatter (Black erfreut sich wachsender Beliebtheit und wurde sogar in die GitHub-Organisation der PSF übertragen: https://github.com/psf/black). So spart man sich mühsame Handarbeit und muss sich nicht über Formatierung Gedanken machen.
    • Alle Variablennamen von Konstanten GROSS_MIT_UNTERSTRICH schreiben
    • Das Hauptprogramm in einer Funktion kapseln und mit if __name__ == "__main__": main() ausführen. Dieses weit verbreitete Konstrukt ist hier sehr ausführlich erklärt: https://code.visualstudio.com/docs/python/linting
      Im globalen Namensraum sollten sich nur Funktionen/Klassendefinitionen, Konstanten und Imports befinden
    • Imports sortieren - ist nicht zwingend notwendig, aber übersichtlicher. Viele (inkl. mir) verwenden folgendes:

      Also zuerst die Module aus der Standardbibliothek, dann externe (i.d.R. mit pip installierte) Module, dann die eigenen zum Projekt gehörenden.

    • Warum enthalten einige deiner Methoden ein return True? Das hat keinen Mehrwert, erst Recht wenn du mit dem Rückgabewert nichts tust. Selbst für sensorabfrage solltest du es nicht brauchen, siehe Doku: https://developer.gnome.org/pygobject/stab…ib--timeout-add
    • teil = part bringt... nichts. Nenne den Parameter gleich teil oder verwende part im Code.
    • Strings werden nicht mit + zusammengesetzt, niemalsnie. Nimm str.format (https://docs.python.org/3/library/stdtypes.html#str.format) oder noch viel besser f-Strings (https://docs.python.org/3/reference/le….html#f-strings, ab Python 3.6, auf dem neuen Raspbian Buster ist 3.7). Beides ist deutlich mächtiger (siehe Doku) und erhöht die Lesbarkeit des Codes.
    • Andererseits ist ein sowas eher schlecht: '{0}'.format(int(data[2:8].decode("utf-8"), 16)). Das ist besser und kürzer als str(int(data[2:8].decode("utf-8"), 16)) geschrieben - du willst ja keinen String formatieren, sondern eine Nummer in einen String konvertieren. Wobei das hier auch nicht optimal ist, verwende einfach Integer als Keys im Dictionary karten. Und if action is not None: kannst du dir sparen, da das Ergebnis von str.format immer ein String sein wird.
    • Bleibe mit der Sprache konsistent. Entweder allen eigenen Code Deutsch, oder viel besser, alles auf Englisch. Alles andere wird einfach nur unlesbar.
    • Folge dem "Don't repeat yourself"-Prinzip (DRY). Der Code im Konstruktor und changewindow gehört in eine gemeinsam verwendbare Funktion/Methode ausgelagert um Wiederholungen zu vermeiden.
    • Vermeide global, das ist in 99.9% falsch. Du hast doch eine Klasse und kannst Instanz-Attribute verwenden!
    • Denk' dir was besseres aus, als None und "none" zu mischen. Es ist spät und ich hab' schon den ganzen Tag auf Code gestarrt, ich werde jetzt nicht versuchen, das zu entziffern :lol:
    • Verwende sinnvolle Kommentare. Keine Sorge, ich habe auch ewig gebraucht, bis ich das halbwegs drauf hatte - aber #Auswertung der Daten oder # Timer starten haben wirklich keinen Mehrwert - das ist doch mehr als offensichtlich. Lieber sollten kompliziertere Codestellen erklärende Kommentare haben, und da muss man dann auch nicht sparsam sein. Dazu gibt's jede Menge Lesestoff im Internet, z.B. https://www.freecodecamp.org/news/code-comm…y-be9cc65fbf83/

    Vieles davon ist Teil von PEP 8, dem in der Python-Community anerkannten Styleguide: https://www.python.org/dev/peps/pep-0008/. Das solltest du beachten, dabei kann dir teilweise ein Formatter, teilweise ein Linter helfen. (z.B. https://code.visualstudio.com/docs/python/linting)

    Zu guter Letzt - laut deinem Profil bist du 17 Jahre alt - aus Erfahrung weiß ich, dass sich nicht viele leider immer weniger Schüler*innen/junge Menschen für "Computerzeugs" interessieren, bei der derzeitigen Situation bezüglich Informatik-Unterricht in den deutschen Schulen ja auch kein Wunder. Weiter so! :bravo2:

    :danke_ATDE::danke_ATDE::danke_ATDE::danke_ATDE::danke_ATDE::danke_ATDE::danke_ATDE:

    Vielen Dank für diese detaillierte konstruktive Kritik zu meinem Code, genau das ist das, was einem so unglaublich weiterhilft, wenn man noch in der Lernphase ist. Denn wie du auch schon erwähnt hast ist es mit dem erlernen einer Programmiersprache in der Schule aktuell alles andere als einfach... ich habe selber drei Jahre Informatik belegt und über RobotKarol; Scratch und dem MIT-AppInventor sind wir nicht hinaus gekommen...

    Ich habe die Antwort grade erst gesehen als ich eigentlich schon wegen einem weiteren Error fragen wollte, doch nun werde ich ersteinmal versuchen meinen Code durch deine ganzen Tipps zu verschlanken und die Syntax zu verbessern.

    Vielen Dank!

    LG

    Steffen

  • Moin Moin!

    Der Code ist nun überarbeitet, aber ich konnte jedoch manche Probleme noch nicht ganz lösen und es gibt auch einen neuen Fehler den ich versucht habe zu lösen... leider hat der Versuch das Problem nur noch verschlimmert.:conf::no_sad:

    Das Ist die neue Fehlermeldung:

    Zitat von Fehlermeldung

    Traceback (most recent call last):

    File "SensorUI.py", line 49, in sensorabfrage

    uid = pn532.read_passive_target()

    NameError: global name 'pn532' is not defined

    Mein Ansatz war die Teile von der "main" Funktion , die den NFC Sensor inkludieren mit in die "Sensorabfrage" Funktion zu verschieben. Das hat nicht geklappt.:helpnew:

    Außerdem konnte ich bisher das Problem mit den globalen Variablen lösen, daher bestehen diese weiterhin... ich finde bei Tutorials eigentlich immer nur die Möglichkeit mit global. :daumendreh2:

    Außerdem bestehen auch weiterhin kleine Teile wo Sprachen durchmisst sind, um dieses Finetuning mit Variablenumbennenung werde ich mich kümmern, wenn ich die erste Version des funktionierenden Codes habe.

    Bei der Erstellung des Strings bin ich auf die bessere Art zur Verknüpfung mehrerer Springs/Variablen umgestiegen, die Änderung auf Integer sehe ich noch skeptisch, weil ich ja auch den String "Hauptmenü" benutze.

    Bei der "sensorabfrage()" Funktion habe ich das return true beibehalten, weil dies dort laut einiger Beispielprojekte sein sollte.

    Hier der aktuelle Code:


    Mit freundlichen Grüßen

    Steffen

    :danke_ATDE:

  • Zeile 8: import Adafruit_PN532 as PN532

    und

    Zeile 49: uid = pn532.read_passive_target()

    Zeile 55: data = pn532.mifare_classic_read_block(4)


    schreib PN532 doch auch in Zeile 8 klein, so import Adafruit_PN532 as pn532

    Edit: das war daneben getippt, siehe Linus Beitrag #36

    Einmal editiert, zuletzt von kle (27. September 2019 um 18:45)

  • Zeile 8: import Adafruit_PN532 as PN532

    und

    Zeile 49: uid = pn532.read_passive_target()

    Zeile 55: data = pn532.mifare_classic_read_block(4)

    schreib PN532 doch auch in Zeile 8 klein, so import Adafruit_PN532 as pn532

    Nö. Das ist falsch, bei einem handelt es sich um die Klasse (PN532), beim anderen um die Instanz (pn532) - das kann man nicht einfach austauschen. Die korrekte Lösung ist, die Instanz von PN532 entweder in der MainWindow-Klasse zu erstellen oder als Argument zu übergeben.

  • Zeile 8: import Adafruit_PN532 as PN532

    und

    Zeile 49: uid = pn532.read_passive_target()

    Zeile 55: data = pn532.mifare_classic_read_block(4)

    schreib PN532 doch auch in Zeile 8 klein, so import Adafruit_PN532 as pn532

    Das sollte eigentlich kein Problem sein, denn ich denke das kleingeschriebene pn532 bezieht sich auf das zuvor definierte

    pn532 = PN532.PN532(cs=CS, sclk=SCLK, mosi=MOSI, miso=MISO) in der Main Funktion. Hier wiederum wird sich auf das PN532 aus Zeile 8 bezogen.

    LG

  • Nö. Das ist falsch, bei einem handelt es sich um die Klasse (PN532), beim anderen um die Instanz (pn532) - das kann man nicht einfach austauschen. Die korrekte Lösung ist, die Instanz von PN532 entweder in der MainWindow-Klasse zu erstellen oder als Argument zu übergeben.

    Wie kann ich die denn als Argument übergeben? Einfach in der Klasse ein Parameter wie zum Beispiel "sensor" hinzufügen?

    Also wäre das so korrekt?:

    class MainWindow(Gtk.Window, sensor):

    und dann

    Gtk.main(sensor= pn532):denker::denker:

    LG

  • Nein. Das wäre Vererbung - du musst einen Parameter zu __init__ hinzufügen. Hier ist es von Anfang an erklärt: https://realpython.com/python3-object-oriented-programming/


    Deutsche Lektüre gibt es sicherlich auch, aber erfahrungsgemäß mit einigen „schwarzen Schafen“.

    Habe es jetzt folgendermaßen gemacht.

    Code: Main Funktion
    def main():
        pn532 = PN532.PN532(cs=CS, sclk=SCLK, mosi=MOSI, miso=MISO)
        pn532.begin()
        pn532.SAM_configuration()
    
        win = MainWindow(sensor=pn532)
        win.startsensortimer()
        Gtk.main()

    und dann bei Init:

    Python: Init
    def __init__(self, sensor):
            global letzter_tag
            pn532 = sensor
            letzter_tag = "hauptmenue"
            self.changewindow(part="hauptmenue")


    Leider bekomme ich immer noch den gleichen Fehler...

    :conf:

Jetzt mitmachen!

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