Nach langer Suche im Internet bin ich auf Websockets gestoßen. Das müsste doch für eine bidirektionale Schnittstelle zu einem Pythonprogramm genau das Richtige sein, oder ?
Hallo,
ich möchte gerne meinen Roboter mit Raspberry-Gehirn unter anderem über eine Webseite steuern können.
Auf dem Raspberry läuft ein lighttpd Webserver und ein Pythonscript (Steuerung der Motoren usw.).
Die Webseite soll bei Tastendruck auf Buttons die jeweiligen Informationen ohne die Seite neu laden zu müssen an das Pythonscript weiterleiten. Aber es sollte auch möglich sein Informationen wie Sensorwerte and die Webseite zu senden (auch ohne laden der Seite).
Das Pythonscript soll als Schleife laufen ,da es auch noch andere Schnittstellen verarbeitet.
Wie kann ich die Kommunikation realisieren?
Da die Webseite sich aktualisieren soll, ohne die Seite neu zu laden, muss ich da wohl etwas Javascript anwenden?
Doch wie kann ich vom Javascript aus Informationen mit einem unabhängig laufendem Pythonprogramm austauschen?
Meine Suche im Netz hat mir schon einige Stichworte wie ajax und cgi gebracht, doch weiß ich nicht so ganz, wie man die Kommunikation damit umsetzen kann.
Denn bei Cgi und ajax habe ich nur Beispiele gefunden, wie diese Pythonscripte starten können. Nicht aber das, was ich gerne haben möchte.
Würde mich freuen, wenn mir einer helfen könnte...
Der Einsteiger
Nach langer Suche im Internet bin ich auf Websockets gestoßen. Das müsste doch für eine bidirektionale Schnittstelle zu einem Pythonprogramm genau das Richtige sein, oder ?
Ja das ist so richtig, aber dann wäre es keine Webseteuerung (über Browser) mehr ... leider entzieht sich HTML und PHP (das wäre in deinem Fall wohl die Lösung vermute ich) meinem Fähigkeitsgebiet
Es gibt 10 Sorten von Menschen: Die einen können binär zählen, die anderen
nicht.
Es gibt PHP GPIO da kann man direkt mit den GPIOs kommunizieren. Dann kann man sich den Weg über Python sparen.
cYa pig
Ein häufiger Weg den man bei sowas beschreitet, ist in deinem Python (oder egal welche Sprache) Programm, einen Webserver aufzumachen. Das ist in Python ca. 3 Zeilen Code. Dieser Webserver bindet sich z.B. auf Port 80 auf deiner lokalen IP Adresse. Diese kannst du dann mit deinem Browser aufmachen. Dein Browser kommuniziert mit dem Webserver über GET bzw. POST requests. Diese Request kannst du in deinem Programm selber parsen und je nach Request eine andere Aktion ausführen.
Hört sich zwar bisschen kompliziert am Anfang an, ist aber wirklich einfach, wenn man es mal ausprobiert hat. Siehe https://docs.python.org/3/library/http.server.html
Und noch etwas Beispielcode. Jedoch ungetestet. Habe den aus einem bestehenden Projekt ausgebaut...
Code:import sys, time from http.server import BaseHTTPRequestHandler, HTTPServer from urllib.parse import urlparse, parse_qs class testHTTPServer_RequestHandler(BaseHTTPRequestHandler): # GET def do_GET(self): (host,port) = self.client_address testHTTPServer_RequestHandler.clients[host] = time.time() parsed = parse_qs(urlparse(self.path).query).get('text',[''])[0]; message = "Thanks for your message!" # Send response status code self.send_response(200) # Send headers self.send_header('Content-type','text/html') self.end_headers() # Send message back to client # # Write content as utf-8 data self.wfile.write(bytes(message, "utf8")) return def main(): print("starting server") server_address = ('127.0.0.1', 8080) httpd = HTTPServer(server_address, testHTTPServer_RequestHandler) httpd.timeout = 1 while True: time.sleep(0.001) httpd.handle_request() httpd.close() sys.exit(app.exec_()) main()
Danke für die Antworten
Zu Ceos: warum ist es denn dann keine Websteuerung über Browser mehr? Wenn ich im Browser die Webseite des Pis eingebe und dann das Javascript( welches die Tcp Verbindung mit dem Server beginnt) mit einem Button starte, dann steuere ich den Roboter doch über den Browser, oder funktioniert das so nicht? Browser(TCP/Javascript) <=> Server(TCP/Python)
Zum Thema HTML, PHP und auch GPIO:
So wollte ich das auch erst lösen. Doch habe ich herausgefunden, dass PHP nur serverseitig ausgeführt wird. Und das schafft gleich mehrere Probleme, die ich für meine Websteuerung nicht haben möchte.
1. Muss bei jeder Interaktion (Button click) die Webseite komplett neu geladen werden. Das habe ich früher schon mal ausprobiert. Wenn man nur einen festen Aufbau wie eine Lampe hat ist das nicht so schlimm, da diese eh nicht häufig Steuerimpulse bekommt... Da der Robi aber im WLAN ist und recht zügig Befehle empfangen muss funktioniert das nicht so toll wenn ständig die Seite neu geladen wird...
2. Ist keine gute bidirektionale Verbindung möglich, da bei z.B. Button click man nur per PHP entweder ein Pythonscript starten könnte, was dann die Ausgabe von Steuerimpulsen erlaubt, oder man direkt per PHP wie piggituX gesagt hat die GPIOs ansteuern könnte.
3. Möchte ich nicht die GPIOs normal nutzen, sodern möchte z.B. über I2C Motoren steuern oder Kommunikation mit anderen Dingen durchführen. Dies klappt aber nur, wenn das Script in einer Schleife laufen kann und nicht für jeden Vorgang neu gestartet werden muss...
4. Über PHP lassen sich von einem Pythonscript keine Informationen an die Webseite schicken... (jedenfalls wenn die Bedingung 3. erfüllt sein soll)
Das was shedepe beschreibt, hört sich doch schon mal gut an. Werde ich auf jeden Fall drüber nachdenken. Momentan habe ich das nämlich noch nicht durchblickt... Einen Nachteil sehe ich dabei aber. Es würde nicht mehr so einfach sein mehrere Webseiten mit unterschiedlichen Dingen zu basteln. Die Webseiten brauchen ja auch noch CSS und so...
Ich möchte erst mal noch ein bisschen probieren, ob ich die TCP Lösung hinbekomme, wenn nicht, dann komme ich auf diesen Ansatz zurück.
Der Tcp Ansatz müsste mir doch eigentlich noch einen Vorteil bringen...Theoretisch kann man doch auch die Serverseite mit dem Python Code auf einen anderen PC auslagern??
Probiere gerade die Lösung aus: http://stackoverflow.com/questions/1...-communication
Ich verwende gerade die Lösung Html5 socket von Antwort 1 aus dem Link für mein Javascript im Browser und für das Pythonscript(auf meinem PC, nicht auf PI!!):
Wenn ich das Javascript von Microsoft Edge aus ausführe passiert nichts, wenn ich die Seite aber von Chrome aus verwende gibt mir mein Pythonscript das aus:Code:import socketserver class ChatRequestHandler(socketserver.BaseRequestHandler): def handle(self): addr = self.client_address[0] print("[{}] Verbindung hergestellt".format(addr)) while True: s = self.request.recv(1024) if s: print("[{}] {}".format(addr, s.decode())) else: print("[{}] Verbindung geschlossen".format(addr)) break server = socketserver.TCPServer(("", 50000), ChatRequestHandler) server.serve_forever()
Leider schaffe ich es noch nicht Nachrichten zu senden oder zu empfangen...
Wenigstens verbindet sich da was. Darauf lässt sich ja aufbauen...
Ich verstehe nur noch nicht, wie das mit dem Handshake dings weiter unten im Link funktioniert??
wait what? custom websockets mit javascript im browser? okay man lernt nie aus XD
Es gibt 10 Sorten von Menschen: Die einen können binär zählen, die anderen
nicht.
hab ne ganz interessante Webseite dazu gefunden: http://enterprisewebbook.com/ch8_websockets.html
Ich muss also, bevor ich die Kommunikation beginnen kann erst mal einen Schlüssel bearbeiten und dann zurückschicken...
Mein Programm um das zu testen sieht momentan so aus:
Leider bekomme ich nicht den gleichen Accept Schlüssel zum zurückschicken raus wie im Beispiel auf der Seite...Code:import hashlib import base64 MAGIC = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" HSHAKE_RESP = "HTTP/1.1 101 Switching Protocols\r\n" + \ "Upgrade: websocket\r\n" + \ "Connection: Upgrade\r\n" + \ "Sec-WebSocket-Accept: %s\r\n" + \ "\r\n" data = "GET HTTP/1.1\r\n" + \ "Upgrade: websocket\r\n" + \ "Connection: Upgrade\r\n" + \ "Host: echo.websocket.org\r\n" + \ "Origin: http://www.websocket.org\r\n" + \ "Sec-WebSocket-Key: i9ri`AfOgSsKwUlmLjIkGA==\r\n" + \ "Sec-WebSocket-Version: 13\r\n" + \ "Sec-WebSocket-Protocol: chat\r\n" print("HSHAKE_RESP: ", HSHAKE_RESP) print("data: ", data) headers = {} lines = data.splitlines() for l in lines: parts = l.split(": ", 1) if len(parts) == 2: headers[parts[0]] = parts[1] headers['code'] = lines[len(lines) - 1] key = headers['Sec-WebSocket-Key'] print("key: ", key) combi = key + MAGIC; combi_b = combi.encode('UTF-8') print("combi: ", combi) #print("combi_b: ", combi_b) resp_data = HSHAKE_RESP % ((base64.b64encode(hashlib.sha1(combi_b).digest()),)) print("resp_data: ", resp_data)
Die schicken den Key: i9ri`AfOgSsKwUlmLjIkGA== an das Serverscript und bekommen dann, wenn sie es mit dem "special globally unique identifier (GUID) string 258EAFA5-E914-47DA-95CA-C5AB0DC85B11" bearbeitet haben das raus: Qz9Mp4/YtIjPccdpbvFEm17G8bs=
Ich bekomme aber das raus: ti16O6oiN0nzWbVtqq9omKeAd/Y=
warum ? Kann mir einer helfen ? Ich habe ja schließlich nichts groß verändert, sondern den Code fast von da ganz unten übernommen : http://stackoverflow.com/questions/1...ing-to-python#
Du kannst einen Webserver davor schalten, und nur gewissen krams weiterleiten.Das was shedepe beschreibt, hört sich doch schon mal gut an. Werde ich auf jeden Fall drüber nachdenken. Momentan habe ich das nämlich noch nicht durchblickt... Einen Nachteil sehe ich dabei aber. Es würde nicht mehr so einfach sein mehrere Webseiten mit unterschiedlichen Dingen zu basteln. Die Webseiten brauchen ja auch noch CSS und so...
Ich möchte erst mal noch ein bisschen probieren, ob ich die TCP Lösung hinbekomme, wenn nicht, dann komme ich auf diesen Ansatz zurück.
Btw:
Meine Erfahrung mit Webseiten die Roboter steuern war in der Vergangenheit meistens von solcher Natur, dass der Roboter irgendwann an einer Wand geklebt ist, weil man einen verdammt hohen Delay haben kann.
Ich glaube, dass ich die Tage dann doch mal deine Lösung ausprobieren werde...
Ich saß heute bestimmt den halben Tag daran, herauszufinden, warum auf einmal mein Javascript nicht mehr ging, obwohl ich nichts daran seit gestern gemacht hatte. Dann bin ich mal auf die Idee gekommen die Broserdaten(Cache) zu löschen und auf einmal ging es wieder... kein Plan warum ?? Dachte schon, dass mir der Raspberry einen Aprilscherz spielen wollte
Jetzt bekomme ich schon mal wenigstens die Verbindung so hin, dass die Verbindung Clientseitig wieder angenommen wird (connection.onopen...)
Nur das mit den Nachrichten klappt noch nicht, weil ich gerade gemerkt habe, dass nicht direkt die Daten mit xyz.encode verschickt werden, sondern die Daten in Frames transportiert werden...
Wenn man z.B. das Wort "Pingen" mit connection.send mit dem Javascript verschickt zeigt mir Python das an: b'\x81\x860og\x80\x1f\x06\t\xe7*\x01' Wie ich das decodieren soll weiß ich noch nicht wirklich...
Zu der Sache mit dem Delay: Ich möchte es ja wenigstens mal probieren Die meiste Zeit soll der Robi eh autonom unterwegs sein...
Lesezeichen