TigerJython4Kids | HomeTurtlegrafikRobotikDatenbanken |
DU LERNST HIER... |
wie du einen Webserver und sogar einen Accesspoint auf der Oxocard einrichten kannst, um über das WLAN mit einem Smartphone oder PC mit der Oxocard zu kommunizieren. In den Musterbeispielen lernst du auch, wie man ferngesteuerte Geräte programmiert. Du erhältst damit Einblick in die modernen Gebiete der Rechnerkommunikation und des "Internet der Dinge" (IOT, Internet of Things). Um die Einzelheiten zu verstehen, benötigst du einige Kenntnisse von HTTP, HTML (und wenig JavaScript), die du dir am besten mit einem Web-Tutorial aneignest. |
ZWEI VERBINDUNGSMÖGLICHKEITEN |
Damit zwei Rechner miteinander Informationen austauschen können, müssen sie über einen Datenkanal miteinander verbunden sein. Bei der Oxocard wird dabei das WLAN verwendet und als Verbindungsprotokoll TCP/IP eingesetzt. Die Verbindung erfolgt über ein spezielles Gerät, das man Accesspoint, Hotspot oder WLAN-Router nennt. (Kennst du diese Begriffe nicht, so orientiere dich im Internet. Du verwendest dieselben Verfahren wie mit deinem Smartphone.) Für die TCP/IP-Kommunikation mit der Oxocard gibt es zwei Szenarien: Verwendung eines vorhandenen Accesspoints Die Oxocard als Accesspoint |
MUSTERBEISPIELE |
Das Modul tcpcom einhält mehrere Klassen, um die Programmierung von Webapplikationen stark zu vereinfachen. Mit der Klasse Wlan kann man sich auf einem bestehenden Accesspoint einloggen oder einen eigenen Accesspoint starten. Die Klasse HTTPServer enthält einen einfachen Webserver. Erzeugt man mit HTTPServer(requestHandler = onRequest) ein Serverobjekt, so wird der Server auch gleich auf Port 80 gestartet. Dieser wartet auf auf diesem Port auf einen Client. Trifft ein HTTP-Request eines Clients ein, so wird die Callbackfunktion onRequest() aufgerufen, wo du festlegst, wie der Server reagieren soll und welchen HTTP-Response er dem Client zurück sendet. Als Client kannst du den Browser eines Smartphones oder eines beliebigen Computers verwenden. A. Vorhandenen Accesspoint verwendenIm ersten Beispiel realisierst du eine Fernsteuerung (Remote control). Dabei kannst du mit einem Webbrowser einen grünen Farbkreis ein- oder ausgeschalten. Stattdessen könnte es sich aber auch um irgend ein anderes Gerät handeln, dass du ein- oder ausschalten willst (Motor, Lampe, Raumheizung, usw.). Zuerst loggt sich die Oxocard mit Wlan.connect() auf einem Accesspoint mit einer SSID und einem (leeren) Passwort ein. (Diese Zeile musst du entsprechend den Angaben deines Accesspoints anpassen).
Nachfolgend wird der Webserver automatisch beim Erzeugen des HTTPservers gestartet. Er funktioniert eventgesteuert mit der Callbackfunktion onRequest(), die bei einem eingehenden GET-Request aufgerufen wird. Sie hat drei Parameter clientIP, filename, params. clientIP liefert die IP-Adresse des Clients, filename ist der Name der im GET-Request angeforderten Datei. params liefert die Parameter des GET-Requests als Tupel in der Form (key, value). In der Callbackfunktion wird hier lediglich eine Variable state auf den Wert "ON" oder "OFF" gesetzt, auf die in der Endlosschleife des Hauptprogramm getestet wird. Verändert sich ihr Wert, so wird der Farbkreis ein- oder ausgeschaltet (state muss daher als global bezeichnet werden). Für den HTTP-Response verwendest du den vordefinierten String html, wobei der aktuelle Wert des Zustands mit der Formatzeile Current light state: %s<br> eingebaut wird. Der return-Wert von onRequest() wird automatisch als HTTP-Response an den Client übertragen. Programm: from tcpcom import * # import before oxocard from oxocardext import * html = """<!DOCTYPE html> <html> <head> <title>Oxocard Light</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h2>Welcome to the Oxocard</h2> <b>Press to change light state:</b> <form method="get"> <input type="submit" style="font-size: 50px; height: 90px; width: 150px" name="light" value="ON" /> <input type="submit" style="font-size: 50px; height: 90px; width: 150px" name="light" value="OFF" /> </form> <br> Current light state: %s<br> </body> </html> """ def onRequest(clientIP, filename, params): global state if len(params) > 0: state = params[0][1] return html%(state) state = "OFF" oldState = "" dot(0, 0, BLUE) sleep(0.2) clear() Wlan.connect("ar", "aabbaabbaabb") print("Connected. IP:", Wlan.getMyIPAddress()) bigTextScroll(Wlan.getMyIPAddress()) HTTPServer(requestHandler = onRequest) clear() while True: if oldState != state: if state == "ON": fillCircle(3, 3, 3, GREEN) if state == "OFF": clear() oldState = state sleep(0.1) Nach dem Programmstart wird im Console-Fenster die IP-Adresse des Webservers angezeigt, die du im Browser auf dem Smartphone oder auf PC eingeben musst. (Etwas schöner wäre es, diese Adresse auf dem LED-Display der Oxocard als Scrolltext auszuschreiben). Das Tag <meta name="viewport"> bewirkt, dass die Textgrösse der Fenstergrösse des Webbrowsers angepasst wird. Damit wird die Webseite auf Smartphones vergrössert dargestellt.
B. Oxocard als Accesspoint
|
WEITERE ANWENDUNGEN |
Bei den folgenden Programmen kannst du selbst entscheiden, ob du einen vorhandenen Accesspoint oder den Accesspoint der Oxocard verwenden möchtest, musst aber den Programmcode entsprechend anpassen. Im folgenden Beispiel willst du ferngesteuert die Farbe der Schlange ändern. Im Hauptprogramm bewegst du die Schlange endlos auf einem Quadrat. Beim Klick auf die Schaltflächen "BLUE" bzw. "GREEN" sendet der Client einen GET-Request, wodurch die Callbackfunktion onRequest() aufgerufen wird. Hier legst du mit setTailColor() die Farbe des Schwanzes fest, sendest aber auch noch die so gesetzte Farbe im HTTP-Response an den Client zurück, der sie anzeigt.
Programm: from tcpcom import * from oxosnake import * html = """<!DOCTYPE html> <html> <head> <title>Oxocard Snake</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h1>Welcome to the Snake</h1> <b>Press to change the tail color</b> <form method="get"> <input type="submit" style="font-size: 35px; height: 90px; width: 150px" name="color" value="BLUE" /> <input type="submit" style="font-size: 35px; height: 90px; width: 150px" name="color" value="GREEN" /> </form> <br> Current color: %s<br> </body> </html> """ def onRequest(clientIP, filename, params): state = "GREEN" if len(params) > 0: state = params[0][1] if state == "BLUE": setTailColor(CYAN) if state == "GREEN": setTailColor(GREEN) return html%(state) makeSnake() if not Wlan.connect("ssid", "pasword"): print("Connection failed") else: print("Successfully connected to AP. IP:", Wlan.getMyIPAddress()) HTTPServer(requestHandler = onRequest) while True: forward(4) right(90)
Der HTML-Code ist etwas umfangreicher, da für die Anordnung der Schaltflächen eine Tabelle verwendet wird. Beim Klick auf einen Button bewirkt der an die Oxocard gesendete HTTP-Request wiederum den Aufruf der Callbackfunktion onRequest(). Der Wert von params[0][1] liefert den Namen des gedrückten Buttons (d.h. "north", "west", "south". "east" oder "stop") und dieser wird in der Variablen state gespeichert. Im Hautprogramm wird in einer endlosen while-Schleife (ausser im Fall von state = 'stop') forward() aufgerufen und und die Bewegungsrichtung entsprechend geändert. (Das sleep(0.1) verhindert, dass im Fall von state = 'stop' in der Schleife unnötig viel Rechenzeit vergeudet wird.) Programm: from tcpcom import * from oxosnake import * html = """<!DOCTYPE html> <html> <head> <title>Oxocard Snake</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h2>Welcome to the Snake</h2> <b>Press to change the tail color</b> <form method="get"> <table> <tr> <td> </td> <td><input type="submit" style="font-size:24px; height:50px; width:75px" name="btn" value="north"/></td> <td> </td> </tr> <tr> <td><input type="submit" style="font-size:24px; height:50px; width:75px" name="btn" value="west"/></td> <td><input type="submit" style="font-size:24px; height:50px; width:75px" name="btn" value="stop"/></td> <td><input type="submit" style="font-size:24px; height:50px; width:75px" name="btn" value="east"/></td> </tr> <tr> <td> </td> <td><input type="submit" style="font-size:24px; height:50px; width:75px" name="btn" value="south"/></td> <td> </td> </tr> </table> </form><br> Current state: %s<br> </body> </html> """ def onRequest(clientIP, filename, params): global state if len(params) > 0: state = params[0][1] return html%(state) makeSnake() state = "stop" Wlan.activateAP(ssid = "oxocard", password = "") HTTPServer(requestHandler = onRequest) while True: if state == 'north': setHeading(0) elif state == 'west': setHeading(-90) elif state == 'south': setHeading(180) elif state == 'east': setHeading(90) if state != 'stop': forward() sleep(0.1)
Temperatur messen und auf Smartphone oder PC anzeigen Oft müssen Messungen an weit entfernten Orten durchgeführt und die Werte in Echtzeit an eine Auswertestelle übertragen werden. Zur Demonstration dieses Szenarios wird mit dem Temperatursensor, der im Beschleunigungssensor der Oxocard eingebaut ist, die aktuelle Temperatur gemessen und über WLAN an ein Notebook oder Smartphone übertragen und dort im Browser angezeigt. Die Temperatur erhältst du durch Aufruf der Methode getTemperature() des Accel-Objekts. Sie entspricht aber der Temperatur im Innern des Accelerometer-Chips und steigt an, je länger die Oxocard in Betrieb ist. Um realistischere Werte für die Umgebungstemperatur zu erhalten, musst du die Oxocard aus dem Gehäuse nehmen.
Programm: from tcpcom import * from oxocard import * from oxoaccelerometer import * html = """<!DOCTYPE html> <html> <head> <title>Oxocard Temperature </title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h2>Welcome to the Oxocard</h2> <b>Press to refresh:</b> <form method="get"> <input type="submit" style="font-size: 25px; height: 50px; width:250px" name="temp" value="getTemperature"/> </form> <br> <h3>Current temperature: %d degC</h3> </body> </html> """ def onRequest(clientIP, filename, params): return html%(temp) Wlan.activateAP(ssid = "oxocard", password = "") HTTPServer(requestHandler = onRequest) acc = Accelerometer.create() while True: temp = acc.getTemperature() display(temp) sleep(1)
Der HTML-Code lässt sich beliebig erweitern und du kannst natürlich auch JavaScript und CSS verwenden. In diesem Beispiel willst du mit 3 Schiebereglern die Farbe eines Quadrats einstellen. Der JavaScript-Code sorgt für ein interaktives Verhalten der Schieberegler, so wie du es von einer PC-Applikation gewohnt bist: Während des "Ziehens" wird der aktuelle Wert ständig angezeigt und beim "Loslassen" wird der HTTP-Request (als Submit) automatisch an den Webserver auf der Oxocard gesendet. Programm: from tcpcom import * from oxocardext import * html = """<!DOCTYPE html> <html> <head> <title>Oxocard Color Controller</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <script> function showText(color, value) { switch(color) { case 0: document.forms[0].redtext.value = value; break; case 1: document.forms[0].greentext.value = value; break; case 2: document.forms[0].bluetext.value = value; break; } } function submitValues(color, value) { document.forms[0].submit(); } </script> </head> <body> <h3>Welcome To The Color Controller</h3> <b>Drag to change colors </b> <p> <form method="get"> Red:<br> <input type="range" min="0" max="100" value="%s" oninput="showText(0, value)" onchange="submitValues(0, value)"> <input size="5" name="redtext" value="%s"><br> Green:<br> <input type="range" min="0" max="100" value="%s" oninput="showText(1, value)" onchange="submitValues(1, value)"> <input size="5" name="greentext" value="%s"><br> Blue:<br> <input type="range" min="0" max="100" value="%s" oninput="showText(2, value)" onchange="submitValues(2, value)"> <input size="5" name="bluetext" value="%s"> </form></p> </body> </html> """ def onRequest(clientIP, filename, params): global r, g, b if len(params) > 0: r = int(params[0][1]) g = int(params[1][1]) b = int(params[2][1]) print(r, g, b) return html%(r, r, g, g, b, b) r = g = b = 100 oldR = oldG = oldB = 0 if not Wlan.connect("SSID", pw): print("Connection to AP failed") else: print("Successfully connected to AP. IP:", Wlan.getMyIPAddress()) HTTPServer(requestHandler = onRequest) while True: if r != oldR or g != oldG or b != oldB: fillRectangle(2, 2, 4, 4, (r, g, b)) oldR = r oldG = g oldB = b sleep(1) |
MERKE DIR... |
Die Oxocard kann sowohl als Accesspoint und als Webserver funktionieren. Der Webserver wartet auf einen HTTP-Request, der von einem Webbrowser eines Clients (PC, Smartphone, usw.) gesendet wird. Der Server verarbeitet den Request und und sendet einen HTTP-Response an den Client zurück. Mit dem Modul tcpcom wird das Eintreffen eines HTTP-Requests beim Server als Ereignis (Event) aufgefasst und automatisch eine Callbackfunktion aufgerufen. |
ZUM SELBST LÖSEN |
|
ZUSATZSTOFF: WEBCLIENT AUF DER OXOCARD |
Statt mit einem Handy auf einen Webserver zuzugreifen, der auf der Oxocard A läuft, kannst du auch eine zweite Oxocard B zur Steuerung von A verwenden. Dazu startest du auf B einen Webclient und sendest dem Server auf A die nötigen HTTP-GET-Requests. Im folgenden Beispiel läuft auf A das unveränderte Ein-/Ausschaltprogramm für den grünen Kreis und zwar in der Version, wo A ein Accesspoint ist. Das Programm auf B loggt sich zuerst auf diesem Accesspoint ein und sendet dann als HTTP-Client einen GET-Request mit dem Parameter light=OFF oder light=ON, je nachdem ob der Button L3 oder R3 geklickt wurde.
Programm (Oxocard A): from tcpcom import * from oxocardext import * def onRequest(clientIP, filename, params): global state if len(params) > 0: state = params[0][1] return state state = "ON" oldState = "" Wlan.activateAP(ssid = "oxocard", password = "") HTTPServer(requestHandler = onRequest) while True: if oldState != state: if state == "ON": fillCircle(3, 3, 3, GREEN) if state == "OFF": clear() oldState = state sleep(0.1)
Programm (Oxocard B): from tcpcom import * from oxobutton import * btnOff = Button(BUTTON_L3) btnOn = Button(BUTTON_R3) host = "192.168.4.1" port = 80 Wlan.connect("oxocard", "") client = HTTPClient() while True: if btnOff.wasPressed(): if (client.connect(host, port)): client.sendGetRequest("?light=OFF") client.closeConnection() if btnOn.wasPressed(): if (client.connect(host, port)): client.sendGetRequest("?light=ON") client.closeConnection()
/relay/1/on /relay/1/off /relay/2/off /relay/2/off Da die Oxocard als Accesspoint die Webadresse 192.168.4.1 hat, sind dann in einem Webbrowser die URLs zum Schalten der Relais: 192.168.4.1/relay/1/on 192.168.4.1/relay/1/off 192.168.4.1/relay/2/on 192.168.4.1/relay/2/off |
Du findest ein Tutorial über die Formatierung unter
https://www.python-course.eu/python3_formatted_output.php