3.5" Display - Monitoring View....wie krieg ich die Daten auf das Display

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Moin

    ich hab von Anwendungsentwicklung nur bedingt einen Plan, hab aber eine Idee und null Plan wie ich dahin komme. Schubst mich mal bitte in die richtige Richtung.

    Ich hab einen Pi der sammelt Daten, Messwerte usw. Schreibt diese in eine Datenbank und diese Daten sende ich in meine Cloud, hab damit alle Messwerte online verfügbar.

    Jetzt würde ich diese Werte gern auf einem 3.5 Display in Echtzeit direkt am Pi angeschlossen anzeigen lassen, wie in einer "App" mehr oder weniger. Das muss einfach nur rudimentär aussehen wie ein gekacheltes Bild und in jeder Kachel steht ein Echtzeit-Messwert drin den ich aus der Datenbank geholt hab. Eigentlich nicht dramatisch.

    Grafana kommt nicht in Frage... ich moechte kein Framework installieren was Ressourcen frisst. Dafür müsste man einen weiteren Pi zur Verfügung stellen der nur "Grafana" macht.

    Ich such was schlankes, einfach eine Anwendung die sich Vollbild oeffnet auf dem Display und mir 6 Werte auf dem Display darstellt. Das kann so schwer eigentlich nicht sein, ich habs nur noch nie gemacht.

    In der Cloud lade ich die Daten hoch ohne DB oder API connection. Ich erstelle lokal per imagemagick grafische Kacheln in denen die Messwerte drin abgebildet werden, so wie hier:

    http://knipsfisch.de/aq/tempT_status.gif ...(forum lässt mich keine 3rd party image links einstellen)

    Das ist eine dieser Kacheln, die aktualisiert sich in meiner Cloud jede Minute...das ist also nur "fast" real-time, reicht mir aber um unterwegs informiert zu sein. Bei dem letzen Build hab ich einen lokalen Webserver verwendet auf dem Pi, eine statische HTML Seite angelegt mit den Kacheln drin und per Browser konnte ich diese praktisch in Vollbild die Werte sehen, das Browserfenster hat sich alle 60sek. aktualisiert.

    Momentan läuft kein Webserver auf dem Pi, ich will auch keinen. :| Der muss so ressourcenschonend wie moeglich laufen.

    Wie code ich mir eine einfache Application zusammen die mir einfach in Vollbild ein Messwerte darstellt und sich auch selbst aktualisiert?

    Mit welchem Framework kann ich sowas einfach bauen?

    Ich bin recht gut im Umgang mit den Pi's als "Sensorenphalance", aber das übliche Coden wie man eine einfache Anwendung erstellt ist mir bislang entgangen. Wird Zeit das ich mich da rein fummele.

  • 3.5" Display - Monitoring View....wie krieg ich die Daten auf das Display? Schau mal ob du hier fündig wirst!

  • Wenn du live Daten aus deiner Datenbank möchtest, wirst du um Websockets oder MQTT nicht herumkommen.

    Andererseits lassen sich die meisten Sensoren sehr gut mit Python auslesen.

    In Kombination mit PyGame könnte man recht einfach eine Oberfläche basteln die sich in einem Zyklischen abstand die Daten von den Sensoren selbst holt.

    So würdest du dir API traffic und die zusätzliche Schnittstelle sparen.

    Damit hast du zwar keine single source of truth mehr, sollte hier aber kein Problem sein, da eine rein anzeigende Oberfläche ja keine Hintergrund Prozesse steuert.

  • Jetzt würde ich diese Werte gern auf einem 3.5 Display in Echtzeit direkt am Pi angeschlossen anzeigen lassen, wie in einer "App" mehr oder weniger. Das muss einfach nur rudimentär aussehen wie ein gekacheltes Bild und in jeder Kachel steht ein Echtzeit-Messwert drin den ich aus der Datenbank geholt hab. Eigentlich nicht dramatisch.

    Da der PI die Messwerte erfasst, kann er sie auch abspeichern.

    An dem Punkt, wo du die Daten an deine Cloud übergibst, speicherst du auch die Messwerte z.B. in /tmp/display.json als json.

    Die Software für die Anzeige kann dann die Messwerte aus der Datei auslesen.

  • Moin

    ich hab die Werte alle in einer RRD DB erfasst, ist also kein Problem Daten bereit zu stellen. Tkinter schau ich mir mal an, das sah auf den ersten Blick so aus als würde es meine Anforderungen erfüllen, ich muss mich nur dahinter klemmen und mal anfangen zu basteln. Brauchte nur mal kurz Input von Erleuchteten. Danke :)

  • Moin

    nochmal danke für die Anregungen. Ich hab mich Sonntag mal mit tkinter auseinandergesetzt. Cooles Tool! Nach 3 Stunden hatte ich erste sichtbare und vor allem funktionierende Ergebnisse. Nur passt hier mein Namenszusatz mit VNNA recht gut. Ich bin kein Coder, Python ist nicht unbedingt mein Lieblingsframwork und ich hab dort keine Ahnung von Klassen usw. aber das sieht man in dem Code weiter unten das ich dort Diletant bin.

    Als erstes hab ich mir eine Oberfläche für meine Schrittmotorsteuerung gebastelt die am AQ einen Vliesfilter von der Rolle zieht.


    Danach hab ich versucht meinen AQ Monitor als GUI zu erstellen so das ich aktuelle Werte ablesen kann und dort stoße ich auf ein Problem.

    Die ersten drei Werte oben sind Grafiken die ich mit Imagemagick erstelle. Diese aktualisieren sich alle 5 Sekunden und werden neu geladen.

    Jetzt gibt es einen Punkt in diesem Konstrukt wo ich scheitere...... wird die Grafik aktualisiert, während imagemagick gerade eine neue Kachel erstellt, spuckt das Python skript einen Fehler aus das die Datei nicht gelesen werden kann. Die Update Routine für diese Grafik ist dann unterbrochen und aktualisiert nicht mehr. Hier mal der Ausschnitt:

    Die Ausgabe im Terminal ist:

    Daran sehe ich das die Grafik neu geladen wurde, alles soweit gut. Funktioniert. Wie bereits erwähnt kommt es jetzt zu diesem Aussetzer wenn der Grafik-refresh genau dann stattfindet, wenn eine neue Grafik generiert wird und die Datei "noch" nicht gelesen werden kann.

    Hier ist Bild2 betroffen, konnte nicht gelesen werden und der Update Task stoppt. Nur noch 1 und 3 laufen weiter. :(

    Das Konstrukt soll so bleiben, also es sollen Grafiken geladen und aktualisiert werden, ich moechte keine Werte aus der DB lesen und in tkinter darstellen...

    Wie umgeh ich jetzt den Aussetzer? Irgendeine Idee?

    Mein Code koennte sicher noch zusammengefasst werden, die Profis werden sicher die Augen verdrehen, aber denkt dran, ich hab von nichts ne ahnung.

  • Ich kapiere immer noch nicht warum es unbedingt Bilder sein muessen...

    Weil die da sind und ihre Funktion haben. Die Grafiken zeigen mit ihren Hintergrundfarbe den Status an. Grün heißt "alles gut", orange heißt "nah am Grenzwert" und roter Hintergrund bedeutet alle Fische sind jetzt tot.

    Das koennte ich als Funktion sicher in Python alles so nachbauen (Original werde die Grafiken in einem Bash Skript erstellt) und mit einbauen, aber das ist mir noch zu hoch jetzt. Daher würd ich gern auf die vorhandenen Grafiken zurückgreifen, ich will das Rad jetzt nicht neu erfinden müssen.

    Wenn es nur ganz kompliziert geht dann werd ich doch die Zeit investieren und mir try..... mal anschauen.

  • Mögliche Ursache:

    Prozess schreibt gerade die Datei und der andere Prozess greift auf die Datei zu, obwohl sie noch gar nicht durch den anderen Prozess geschlossen ist.

    Ein try... except würde nur den Fehler umgehen und das Bild kann dann einfach nicht angezeigt werden.

    Was definitiv besser funktionieren würde, ist das Überschreiben durch Umbenennen.

    Erst das Bild in eine temporäre Datei schreiben und danach in das Umbenennen, was gelesen werden soll.


    Python
    from pathlib import Path
    
    
    msg_file = Path("hello.txt")
    msg_file.write_text("xxx")
    tmp_msg_file = Path("tmp_hello.txt")
    tmp_msg_file.write_text("Hello World\n")
    tmp_msg_file.rename(msg_file)
    print(msg_file.read_text())
  • Was definitiv besser funktionieren würde, ist das Überschreiben durch Umbenennen.

    Erst das Bild in eine temporäre Datei schreiben und danach in das Umbenennen, was gelesen werden soll.


    Python
    from pathlib import Path
    
    
    msg_file = Path("hello.txt")
    msg_file.write_text("xxx")
    tmp_msg_file = Path("tmp_hello.txt")
    tmp_msg_file.write_text("Hello World\n")
    tmp_msg_file.rename(msg_file)
    print(msg_file.read_text())

    Die Idee ist gut, das versuch ich mal.

    Was mir noch eingefallen ist, das ich während die Grafik erstellt eine Variable solange auf 1 setze bis der Schreibvorgang abgeschlossen ist. Erst dann darf tkinter updaten wenn die Variable wieder auf 0 ist ...oder so ähnlich :|

  • 4zap Anmerkungen zum Quelltext: Eingerückt wird in Python per Konvention vier Leerzeichen pro Ebene.

    Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

    Dem Code nach ist das `tkinter`-Modul unter *zwei* Namen erreichbar. Das sollte nicht sein. Entweder nur `tkinter` oder nur `tk`. Wonach entscheidet man sonst wann man welchen Weg wählt?

    Man gibt bei GUIs weder die Fenstergrösse vor, noch platziert man Elemente mit `place()`. Die Fenstergrösse ergibt sich automatisch aus dem Inhalt.

    Man nummeriert keine Namen. Dann will man entweder bessere Namen, oder gar keine Einzelnamen und Werte, sondern eine Datenstruktur. Oft eine Liste.

    Extem verwirrend ist hier auch, dass es `label`, `label1`, `label2`, und `label3` gibt, aber `label1` aus der Reihe fällt, während `label` ohne Nummer und `label2` und `label3` für die Bilder stehen. Wie gesagt entweder bessere Namen, denn der Leser will ja gar nicht wissen das wievielte Label das ist, sondern was das was darauf angezeigt wird, *bedeutet*. Oder man steckt die drei Bilder-Labels in eine Liste.

    Falls man mit einem Wert später gar nichts mehr macht, braucht man den auch überhaupt nicht an einen Namen binden. Das erste Label beispielsweise, zumindest soweit wir hier den Quelltext kennen.

    Wenn es für eine Zeichenkette mit besonderer Bedeutung als Argument eine Konstante im `tkinter`-Modul gibt, sollte man diese Konstante verwenden. Also beispielsweise `tk.TOP` statt "top".

    Code und Daten sollten nicht wiederholt werden. Den Pfad zu den Bildern sollte man nur einmal im Code stehen haben und auch die Namen der Bilder. Auch die drei `update()`-Funktionen, die ja grundsätzlich das gleiche machen, nur mit leicht anderen Parametern, sollte es so nicht geben. Da schreibt man *eine* parametrisierte Funktion für.

    Auch das laden der Bilder sollte nicht zweimal im Code stehen und die 5000 für das Update-Intervall steht da auch viel zu oft. Wenn man die `update()`-Funktion(en) in der Hauptfunktion nicht per `after()` aufrufen lässt, sondern sie dort *direkt* aufruft, dann kann man sich das laden der Bilder in der Hauptfunktion sparen.

    ``global`` hat in einem sauberen Programm nichts zu suchen. Eine Funktion oder Methode bekommt alles was sie ausser Konstanten benötigt, als Argument(e) übergeben. Man kann `after()` Argumente für den Aufruf übergeben. In jeder nicht-trivialen GUI kommt man aber sehr schnell an den Punkt, wo man um objektorientierte Programmierung nicht herum kommt. Also selbst Klassen schreiben.

    Ungetestet:

    “Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”

Jetzt mitmachen!

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