Über Taster (GPIO) ein Javascript ausführen

  • Hallo in die Runde.

    Ich sitze seit einigen Wochen an einem kleinen Projekt bei dem ich diverse Informationen und Aktionen auf einer Website anzeigen lassen will. Ich habe bereits mit Hilfe der sehr ausführlichen Anleitung von meigrafd und der Hilfe von anderen Forenmitgliedern ( hyle , _Blackjack_ , vielen dank nochmals!) die meisten Probleme lösen können.

    Nun bleibt nur noch eine (hoffentlich) letzte Hürde: Ich möchte mit einem Tastendruck am Raspberry (GPIO) ein Javascript auf der Website starten bzw. anhalten ...etc. Ich nutze Bottle, JSON und Python. Variableninhalte aus Python an die Website zu schicken und diese darstellen zu lassen funktioniert einwandfrei. Auch umgekehrt (z.B. die Daten per Button anzufordern) geht alles. Aber ich bekomme das Testscript (eine Stoppuhr aus dem Netz, siehe Script) nicht gestartet. Habe versucht das mit einem addEvent (change) zu lösen, aber es scheint, als wird weder die Änderung des Variableninhaltes registriert, noch der Befehl ( start() ) an Java übergeben. Zumindest beim letzteren bin ich mir sicher, dass ich etwas ziemlich falsch mache.


    Hier das HTML Script. Die Variable "PiRAM" ist noch aus dem Beispielprojekt und wird alle 2 Sekunden aktualisiert. Diese dient mir hier erstmal als Platzhalter für den später geplanten Taster bzw. dessen Rückmeldung über AJAX vom Raspberry.

    Beim Klick auf einen der Taster im Bereich "Buttonbehälter" startet, stoppt oder pausiert die Stoppuhr. Ich möchte diese aber bei Änderung des Variableninhaltes von PiRAM starten (oder später auch stoppen usw.) . Wie geschrieben soll dies später einmal über einen Tastendruck am Pi erfolgen.

    Ich lasse den addEventListener mit dem Event "change" auf die Variable "PiRAM" schauen. Wenn diese sich ändert, soll die Funktion "start()" ausgeführt werden (zumindest ist das der Plan).


    Ich habe hier im Forum zig ähnliche Einträge/Problemstellungen gefunden, aber keines bezogen auf Python => AJAX => Java.

    Kann mir da jemand weiterhelfen?


    Die Control.js



    Python Code (mit Testvariablen)

    Edited once, last by homiys: Script war unvollständig (March 22, 2024 at 6:05 PM).

  • Hallo,

    als grundsätzlich bekommt die Webseite _nicht_ mit, wenn auf dem Server irgendwas passiert, jedenfalls nicht mit dem vorhanden Setup.

    Es gibt (mindestens) drei Möglichkeiten, das zu ändern:

    * Du pollst permanent via JavaScript, ob sich auf dem Server was ändern und reagierst auf der Webseite drauf. Wenn du eine Stoppuhr starten willst musst du aber schon ziemlich oft pollen (wie alle 0,5 Sekunden oder so), um die Latenz klein zu halten. Was eher unschön ist.
    * Du nutzt Websockets für bidirektionale zwischen Server und Webseite. JavaScript kann das, Bottle OOTB nicht. Keine Ahnung, ob's da eine brauchbare / gepflegte Erweiterung gibt. Ein anderes Microframework, was das kann, ist microdot. Für Flask gibt's ziemlich sicher auch was passend.
    * Du nutzt SSE - Server Side Events. IMHO nicht so gängig, funktioniert aber. Bottle kann das OOTB nicht. Keine Ahnung, ob's da eine brauchbare / gepflegte Erweiterung gibt. Ein anderes Microframework, was das kann, ist microdot. Für Flask gibt's ziemlich sicher auch was passend.

    Gruß, noisefloor

  • Kannst du vielleicht die anderen Dateien (control.js, stoppuhr.js und die Python-Datei) auch mit posten? Mit AJAX wird in deiner Datei gar nichts gemacht.


    Ich würde zum senden von Nachrichten ja WebSockets bzw. socket.io verwenden, aber ich denke mal, dass es in dem Bottle Framework einen anderen (besseren) Weg dafür gibt

    Hallo bennetr , danke für deine Antwort. Ich hatte das nicht gepostet, da ich eigentlich davon ausgehe, dass das ein rein HTML/ Java internes Problem ist. Möchte niemanden mit "überflüssigen" Code - Mengen nerven.

    Habe die anderen Programme aber nun hinzugefügt.

    Edited once, last by homiys (March 22, 2024 at 6:12 PM).

  • Hallo noisefloor , auch dir danke ich, für deine Antwort.

    Nun, ich polle die Kommunikation über AJAX im Augenblick testweise alle 100ms. Da das ganze lokal läuft, ist das sogar stabil. Allerdings ist das nicht das Ziel (und natürlich auch nicht ratsam). Wenn ich es hin bekomme, die Javascriptfunktion über diese externe Information zu starten, kann ich die Übertragung ja auch auf Event und nicht auf Zeit machen.

    Aber natürlich bin ich auch für alle anderen Vorschläge offen. Kenne mich allerdings so gar nicht mit Flask aus.

  • homiys Naja, wenn du dich fragst, wie du Frontend und Backend miteinander verbinden kannst, solltest du schon beides mitschicken. Jetzt, wo du die anderen Dateien mitgeschickt hast, wird schon vieles klarer.

    Um es zusammenzufassen, du benutzt Bottle als Backend und hast da verschiedene Endpoints, z.B. /data/. Außerdem stellt Bottle eine fast statische HTML-Seite bereit. Diese pollt die Information vom Backend. Die Templates werden gar nicht benutzt.

    Wie noisefloor schon gesagt hat, ist Polling nicht so toll, da ist es besser WebSockets zu benutzen. Ich finde socket.io ganz toll, weil das noch ein paar Mechanismen zur Fehlerverhinderung mitbringt. Für JavaScript wäre das https://socket.io/docs/v4/ (client), für Python https://github.com/miguelgrinberg/python-socketio. Ich hätte da auch ein funktionierendes Beispiel, das ich dir schicken könnte

  • Ich habe mir meinen Code mal genauer angeguckt, und ich glaube, wenn du dir die Dokumentation anguckst, bist du besser dran :D Ich habe aber mal das Setup auf dem Server für dich, da habe ich auch einige Probleme gehabt.

    Du brauchst die Python-Packages flask und socketio

    Ich hoffe, das hilft dir weiter. Wenn du noch Fragen hast, meld dich gerne

  • Hallo bennetr .

    Hm, das hilft mir nicht so richtig weiter. Vermutlich (oder bestimmt) weil ich es nicht verstehe. Was ist die Aufgabe deines Codes? Wird dadurch eine Website bereitgestellt? Falls ja, wie lautet die IP Adresse? Oder läuft die "app.py" parallel zu meiner "web_bottle.py" (muss also darin aufgerufen werden)? In dem Code wird "Stoppuhr.main" aufgerufen... Ich Checks nicht, sorry.

  • Das Script von bennetr deckt nur den Serverteil ab. Dazu musst du noch den WebSocket-Code im Browser schreiben.

    Und beachte den Kommentar auf Zeile 36!

    flask kann auch die HTML-Seite ausliefern falls du das willst.

    Hallo Tell. Auch dir meinen Dank. Ja, so etwas hatte ich befürchtet.

    Ich bin da, glaube ich, nicht bewandert genug drin. Eigentlich wollte ich nur für einen guten Freund eine Stoppuhr Anwendung bauen, die per Tastendruck am Pi gestartet werden kann (bekomme ich hin) dann erscheint auf der Website "START!" (bekomme ich auch hin) und letztendlich soll deren Ergebnis dann nach stoppen der Zeit auf der Website (soll später über Beamer angezeigt werden) angezeigt werden (bekomme ich ebenfalls hin). Man sieht also den "Start" und das Ergebnis. Das ist allerdings nicht besonders "sexy". Schöner wäre, wenn man auch die laufende Zeit sehen würde, und da scheitere ich.

    Permanentes Updaten der Laufzeit zwischen Pi und Client ist nicht sinnvoll bzw, in Python schwer umsetzbar. Also möchte ich die eine Java Stoppuhr parallel laufen lassen, die eben bei Erhalt der "Start - Information" lös läuft und bei drücken der Stopptaste am Pi angehalten, bzw. gelöscht wird (würde ich dann auf 0 setzen, damit keine Unterschiede zwischen der Stoppuhrzeit und der gemessenen Zeit am Pi dargestellt werden).

    Eigentlich eine simple Aufgabe an der ich nun schon Wochen dran sitze und gefühlt hunderte Turorials gesehen/gelesen habe :(

  • homiysPermanentes aktualisieren zwischen Pi und Client ist nicht in Python schwer umsetzbar, sondern generell. Webseiten funktionieren halt in der Regel so, dass der Client anfragen stellt und der Server antwortet. Ein dauerhafter Datenstrom und/oder Kommunikation in beide Richtungen ist bei dem Konzept traditionell nicht vorgesehen. So etwas macht man heute mit Websockets. Die sind in Python auch möglich und nicht schwerer als in anderen Programmiersprachen.

    Was hier auch noch reinspielt ist das der Knopf am Server einen Zustand beim Server ändert, es aber nicht nur einen Client geben muss. Davon kann es mehr geben. Oder auch gar keinen, denn man kann den Knopf ja auch drücken wenn die entsprechende Webseite in keinem Client offen ist. So simpel ist die Aufgabe gar nicht. Die mag simpel aussehen wenn man die ganzen technischen Gegebenheiten und Einschränkungen von Server und Browser nicht kennt.

    "He who laughs last thinks slowest"

  • Du wirst immer einen Unterschied zwischen der Zeit in Python und in JS haben, auch wenn er nur gering und möglicherweise nicht sichtbar ist. Irgendwo kommt der Stopp-Befehl ja zuerst an und muss dann zur jeweils anderen Seite geschickt werden.

    Eine Webanwendung mit JavaScript-Frontend und Python-Backend dafür ungeeignet ist. Am besten wäre eine grafische Oberfläche direkt in Python, dann gäbe es nur ein Timer, der kontrolliert werden muss und du kannst dir das aufwendige Synchronisieren sparen. Wenn du aber ein getrenntes Frontend benötigst, z.B. weil du die Stoppuhr auch vom Handy aus steuern willst, ist es auf jeden Fall besser, WebSockets zu nehmen statt Polling.

    Der Code, den du oben gepostet hast, hat eine komplett andere Aufgabe, nämlich das Darstellen von Messwerten. Den weiter zu einer Stoppuhr umzubauen, macht alles nur unübersichtlich (außerdem gibt es keinen Grund, jQuery zu benutzen und was bitte ist diese isset-Funktion?).

  • Ich kenne mich leider wenig mit dem ganzen aus. Ich suchte von Anfang an nach einer Möglichkeit, die oben beschriebene Aufgabe zu lösen. Dabei habe ich mich u.a. der Vorlage hier im Forum bedient. Diese enthält diese "isset" Funktion. Ich weiß tatsächlich nicht, was die macht.

    Eine grafische Oberfläche in Python? Wusste nicht, dass das geht... Ich möchte halt niemanden bitten, für mich einen wie auch immer gearteten Code zu schreiben,. Genauso wenig, wie ich jemandes Zeit stehlen möchte. Aber mittlerweile wäre ich für alles sehr dankbar.

    Grundsätzlich ist mir der Lösungsweg bzw. die Art auch relativ egal. Wenn alles in Python möglich ist, umso besser. Allerdings, wie geschrieben, weiß ich nicht wie.

  • Natürlich geht das. Schau dir mal tkinter an, das ist sogar in Python eingebaut. Es gibt da ein offizielles Tutorial (https://tkdocs.com/tutorial/intro.html), wenn du schon Python kannst, sollte das kein Problem sein.

    Vielen Dank! Das werde ich mir mal anschauen. Das grundsätzliche Problem konnte ich allerdings nun mit Hilfe aus einem Javaforum lösen:

    So, eingebetet in dem Scriptaufruf funktioniert es.

    HTML: index.html
    document.getElementById("PiRAM").addEventListener("DOMSubtreeModified", () => start());


    Natürlich werde ich mir aber TK auch anschauen, ich finde die Idee einer "eigenen App" ganz charmant.

    Auch nochmals vielen Dank an _Blackjack_!!

Participate now!

Don’t have an account yet? Register yourself now and be a part of our community!