Under Construction
Diese Anleitung befindet sich noch im Aufbau, daher ist die Struktur etwas durcheinander.
Fragen, Anregungen usw bitte im Diskussions-Thread stellen!
Einleitung:
Alles GPIO relevante lässt sich am einfachsten und umfangreichsten über Python behandeln. Aber auch ohne GPIO sind die Möglichkeiten über Python umfassender als über PHP & Co.
Wer vor hat sein Python Projekt auch übers Web zu steuern oder Informationen abrufen zu können, hat mehrere Möglichkeiten.
Dabei gilt es aber 2 Sachlagen zu unterscheiden:
1) Ein permanent laufendes Python Script
2) Ein Python Script was nur ein mal bei Bedarf ausgeführt wird und direkt die Informationen ausgibt.
Die 2. Möglichkeit kann wie gehabt mithilfe von PHP und exec(); umgesetzt werden (siehe dazu => hier <=); man kann aber auch eine FIFO Datei o.ä. nutzen. Auf diese Möglichkeit will ich hier aber nicht weiter eingehen - mein Anliegen in dieser Anleitung zielt auf die 1.Möglichkeit ab. Aber auch hier gibt es mehrere Möglichkeiten, wie immer
- Eine Kombination aus WebSocket in JavaScript und Python.
- Eine Übermittlung der Daten über spezielle URL's
Bei der 2.Variante verzichtet man vollständig auf einen Webserver wie apache2, nginx, lighttpd usw.
Bei der 1.Variante kann man ebenfalls auf einen Webserver wie apache2 verzichten, kann aber auch weiterhin apache2 usw nutzen.
Primär möchte ich hier im speziellen mit Python und einem sog. Web-Framework arbeiten. Die bekanntesten wären: bottle, tornado, Flask, Django, Falcon, Pyramid... Weitere findet ihr zum Beispiel > hier < oder > hier <.
Ich gehe hier erst mal nur auf bottle und tornado ein.
Anfangs hab ich viel tornado genutzt, mittlerweile nutze ich aber bottle - hatte bei meinem RoPi Projekt einige Probleme mit tornado die ich mit bottle aber nicht mehr hatte... Ich glaub es hing damit zusammen das tornado Klassen benötigt bottle aber nicht unbedingt...
Letztlich sollte es für euch aber kaum einen Unterschied ausmachen - es gibt immer irgendwelche Pro / Contras.
Ein Vorteil, nicht nur sein Python Script zum auslesen eines Sensors o.ä. zu verwenden, sondern auch das Web-Interface mit Python umzusetzen besteht darin, dass man Python-Variablen/Werte direkt in den HTML Code einbetten kann...
Ähnlich wie mit PHP wird dem Client nur Ausgaben angezeigt also HTML. Dh wenn eine sog. "route" (Erklärung weiter unten) angesprochen wird kann man bestimmte Stellen im HTML Code (template) durch Werte von Python-Variablen ersetzen bevor diese dem Client angezeigt werden.
Das funktioniert aber nur ein mal beim laden der Seite (des templates). Wer dann nicht jedes mal die komplette Seite neu laden möchte greift stattdessen auf AJAX zurück. Auch das ist mit diesen Web-Frameworks kein Problem, JavaScript bzw jQuery wird ebenfalls unterstützt. JavaScript läuft übrigens nur beim Client. AJAX stellt nämlich auch nur Anfragen an den Server der dann darauf antwortet.
Ein weiterer Vorteil besteht auch darin direkt GPIO's behandeln zu können, diese im vollen Umfang und direkt zu schalten sowie auszulesen da bekanntlich die meisten Module ala RPi.GPIO oder pigpio für Python existieren.
Aber auch die andere Hardware des Raspberry's lassen sich über Python besser ansprechen als über PHP...
Auch hat WebSocket den Vorteil das für den Zeitraum wie der Client die Seite offen hat, permanent eine Verbindung zwischen Client und Server besteht - wofür das HTTP Protokoll nicht gedacht und in der Lage ist. AJAX ist daher langsamer und auch belastender als der Weg über WebSocket.
Und last but not least bedeutet solch eine Umsetzung über Python auch eine verbesserte Realtime Anwendung, da weitaus weniger Verzögerungen verursacht werden als ein Umweg über exec(); usw.
Um gezielte Daten zwischen "Webserver" und "Client" auszutauschen verwendet man also am besten WebSocket.
Man kann aber auch bestimmte "route"n anlegen um allgemeine Informationen abzurufen - route'n sind quasi URL's, so wäre " / " die Haupt-Route und zum Beispiel " /data/ " eine weitere die man zum abrufen der allgemeinen Informationen verwenden kann und " /cmd/ " könnte eine Route sein um Befehle abzusetzen... Bei letzterem könnte der Aufruf zum Beispiel so aussehen: /cmd/forward ... Der Befehl wäre dann also: forward
Diesen Teil kann man übrigens auch mithilfe des Modules BaseHTTPServer (python2) bzw http.server (python3) realisieren, damit habe ich es nämlich in meinem RPi Info Windows Gadget umgesetzt.
Zur Übergabe der Daten sollte man JSON verwenden, da sich so mehrere Informationen mit nur einer Abfrage übermitteln und standardisiert verarbeiten lassen. Auch darauf möchte ich hier eingehen da ich das mittlerweile für mein RoPi Projekt nutzen (anfangs nutzte ich WebSockets aber habe dann im laufe der Entwicklung eine bessere Vorgehensweise entdeckt). HTML5 Spiele nutzen ebenfalls diese Vorgehensweise.
Auf der folgenden Seite findet ihr dazu eine detaillierte Beschreibung: https://www.fullstackpython.com/websockets.html
Den HTML Code kann man entweder direkt in das Python Script, in die jeweilige Route-Funktion, einbetten - oder separate html Dateien verwenden. Letzteres ist die zu bevorzugende Möglichkeit. Dabei werden die Dateien in einem sog. template Verzeichnis abgelegt, Bilddateien oder auch die JavaScript Dateien wiederum legt man in einem sog. "static" Verzeichnis ab... Die Verzeichnisse kann man aber selbstverständlich auch einstellen.
..das sollte als Einführung erst mal reichen
Anmerkung:
Leider verschluckt das Forum manche Leerzeichen in den Code-Blöcken, weshalb ich die wichtigsten Teile zusätzlich auf codepad.org verlinkt habe. Wenn ihr also Probleme habt dann probiert es bitte mit den codepad.org Links.
Vorab: Ich achte nicht unbedingt auf absolute Korrektheit, PEP lass ich ebenfalls außen vor. Wer es professioneller als hier beschrieben umsetzen möchte möge sich bitte selber genauer zu dem Thema einlesen Ich befinde mich hier selbst noch in der Lernphase.
Ich versuche hier nur die Oberflächlichen Details anzukratzen um es nicht allzu kompliziert werden zu lassen - es gibt aber unzählige Möglichkeiten...
[an=index][/an]
Aufgrund dessen was ich hier alles zeigen möchte unterteile ich die Anleitung in 3 Abschnitte:
- [al=chapter1]Ein Webserver in Python, mit einsetzen von Variablen beim laden der Seite.[/al]
- [al=chapter2]Ein Webserver in Python, mit WebSocket, der sowohl Poll als auch Push beherrscht.[/al]
- [al=chapter2_auto]Automatisierung[/al]
- [al=chapter3]Ein Webserver in Python, mit unterschiedlichen "route"s für reines Polling, ohne WebSocket.[/al]
Poll bedeutet das der Client Daten vom Server abfragt.
Push bedeutet das der Server die Daten sendet, ohne expliziter Anforderung des Clients. Der Client also nicht extra eine Aufforderung zum senden der Daten an den Server schicken muss.
Auch wenn ihr eigentlich nur den 2. oder 3. Abschnitt umsetzen wollt solltet ihr auch den 1. beachten bzw lesen!
Eine Erklärung wie ihr selber eine Erweiterung einbauen könnt findet ihr => in diesem Thread <=
Ein weiteres Projekt was ich mittlerweile ebenfalls auf der hier vorgestellten Basis umgesetzt habe: Python: Sensor Werte mit HighCharts visualisieren
=> bottle - the right way to use <=
Under Construction
Spoiler anzeigen
Für WebSocket gibt es alternativ auch noch die Python Module websocket-server oder ws4py mit denen ich auch schon Erfahrung gemacht habe.
Nun aber erst mal zu einem simplen Grundgerüst für WebSocket:
bottle
from __future__ import print_function
import sys
import os.path
import json
from bottle import route, run, request, abort, Bottle ,static_file
app = Bottle()
@app.route('/websocket')
def handle_websocket():
wsock = request.environ.get('wsgi.websocket')
if not wsock:
abort(400, 'Expected WebSocket request.')
while True:
try:
message = wsock.receive()
wsock.send("Your message was: %r" % message)
sleep(3)
wsock.send("Your message was: %r" % message)
except WebSocketError:
break
@app.route('/<filename:path>')
def send_html(filename):
return static_file(filename, root='./static', mimetype='text/html')
from gevent.pywsgi import WSGIServer
from geventwebsocket import WebSocketHandler, WebSocketError
host = "127.0.0.1"
port = 8080
server = WSGIServer((host, port), app,
handler_class=WebSocketHandler)
print "access @ http://%s:%s/websocket.html" % (host,port)
server.serve_forever()
[/php]
[b]bottle[/b] => http://codepad.org/erftmgrS
[code=php]
# http://bottlepy.org/docs/dev/tutorial.html
from __future__ import print_function
import sys
import os.path
import json
import bottle
from random import randrange
bottle.debug(True) #sollte spaeter ausgeschaltet werden!
bottle.TEMPLATE_PATH.insert(0, os.path.join(os.path.dirname(__file__), 'templates'))
@bottle.route('/')
def MainHandler():
values = {
'test': randrange(1, 1000),
}
return bottle.template('index.html', values)
@bottle.route('/data/')
def TelemetryHandler():
print("Telemetry Request.")
bottle.response.content_type = 'application/json'
data = {}
data["MotorSpeed"] = randrange(10, 250)
data["distance"] = randrange(5, 500)
return json.dumps(data)
@bottle.route('/cmd/<command>')
def CommandHandler(command):
print("Command Request: {}".format(command))
@bottle.route('/static/<filename>')
def send_static(filename):
if filename.endswith(".css"):
bottle.response.content_type = 'text/css'
elif filename.endswith(".js"):
bottle.response.content_type = 'text/javascript'
elif filename.endswith(".png"):
bottle.response.content_type = 'image/png'
return bottle.static_file(filename, root=os.path.join(os.path.dirname(__file__), 'static'))
@bottle.error(404)
def error404(error):
return 'Error 404: Nothing here, sorry.'
try:
bottle.run(host='0.0.0.0', port=8080, quiet=True)
except (KeyboardInterrupt, SystemExit):
print('\nQuit\n')
[/php]
[b]tornado[/b] => http://codepad.org/BXh94y4X
[code=php]
from __future__ import print_function
import tornado.escape
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
import logging
import os.path
import json
from random import randrange
class Application(tornado.web.Application):
def __init__(self):
handlers = [
(r"/", MainHandler),
(r"/data/(.*)", TelemetryHandler),
(r"/cmd/(.*)", CommandHandler),
(r"/static/(.*)", StaticHandler),
]
settings = dict(
template_path=os.path.join(os.path.dirname(__file__), "templates"),
static_path=os.path.join(os.path.dirname(__file__), "static"),
debug=True,
autoescape=None
)
tornado.web.Application.__init__(self, handlers, **settings)
# Configure logging
tornado.options.log_file_max_size = (1024**2)*10
logging.getLogger().setLevel(logging.INFO)
tornado.log.enable_pretty_logging()
class MainHandler(tornado.web.RequestHandler):
#called every time someone sends a GET HTTP request
@tornado.web.asynchronous
def get(self):
self.render(
"index.html",
test = randrange(1, 1000),
)
class TelemetryHandler(tornado.web.RequestHandler):
def get(self, request):
print("Telemetry Request")
data = {}
data["MotorSpeed"] = randrange(10, 250)
data["distance"] = randrange(5, 500)
output = json.dumps(data)
print(output)
self.write(output)
class CommandHandler(tornado.web.RequestHandler):
def get(self, request):
print("Command Request: {}".format(request))
output = json.dumps({ "ID": "command", "value": randrange(1001, 9000) }) #Turns json dict into a str
print(output)
self.write(output)
# deliver static files to page
class StaticHandler(tornado.web.RequestHandler):
def get(self, filename):
with open("static/" + filename, "r") as fh:
self.file = fh.read()
# write to page
if filename.endswith(".css"):
self.set_header("Content-Type", "text/css")
elif filename.endswith(".js"):
self.set_header("Content-Type", "text/javascript")
self.write(self.script)
try:
http_server = tornado.httpserver.HTTPServer(Application())
http_server.listen(8080)
tornado.ioloop.IOLoop.instance().start()
except (KeyboardInterrupt, SystemExit):
print("\nQuit\n")
[/php]
[b]templates/index.html[/b]
[code=php]
<!DOCTYPE html>
<html>
<head>
</head>
<body>
Test: {{ test }}
</body>
</html>
[/php]
Beide Python Scripts beinhalten noch keinen WebSocket!
Im derzeitigen Zustand der beiden obigen Scripts spielt es noch keine Rolle ob man sie mit python2 oder python3 ausführt. Beachtet aber das python3 nicht vollständig kompatibel zu python2 ist und einige Sachen anders gehandhabt werden, insbesondere Types.
[b]Wichtig:[/b] Die Python Script Datei darf [u]nicht[/u] wie das Module heißen! Ihr dürft die Datei also [u]nicht[/u] bottle.py oder tornado.py nennen!
Ich verwende hier daher: web_bottle.py und web_tornado.py
Desweiteren an dieser Stelle noch ein Hinweis:
Man benötigt eigentlich nur [u]entweder[/u] WebSocket [u]oder[/u] "/cmd/" und "/data/". Ich habe oben aber erst mal nur letzteres eingefügt, im späteren Verlauf dieser Anleitung zeige ich dann speziell den Code für WebSocket.
Das Script könnt ihr als normaler Benutzer ausführen - solange der Port über 1024 liegt (niedriger darf nur root verwenden).
Wichtig ist die Struktur:
Im selben Verzeichnis wo das Python Script liegt müssen 2 Verzeichnisse erstellt werden: [b]templates[/b] & [b]static[/b]
Die [b]index.html[/b] gehört ins [b]templates/[/b] Verzeichnis. Ins [b]static/[/b] Verzeichnis kommt später die jquery.min.js Datei (und ggf noch *.css oder Bilddateien etc.)
Ihr habt nun also zum Beispiel im Verzeichnis [b]/home/pi/[/b] das Script [b]web_bottle.py[/b] und ein Verzeichnis [b]/home/pi/templates/[/b] sowie die Datei [b]/home/pi/templates/index.html[/b]
Führt nun das Python Script aus und surft die IP eures Pi's mit Zusatz des Ports [b]8080[/b] an - zum Beispiel http://192.168.0.10:8080
Jedes mal wenn ihr die Seite aufruft (ladet) ändert sich der "Test: xxxx" Text, also beim ersten Aufruf steht da zB. "Test: 970", drückt ihr dann F5 (reload) steht da "Test: 160" usw. Was da passiert wurde zuvor im Script festgelegt und die Variable "test" in den HTML Code gesetzt. Das kann man für Statische Informationen verwenden wie zum Beispiel Variablen für JavaScript die man nicht unbedingt fest (hardcoded) in den HTML Code einbauen möchte, sondern bequemer nur das Python Script anpassen brauch... Wie zum Beispiel eine Debug-Ausgabe von JavaScript die ihr nur bei Bedarf einschaltet.
Ein Aufruf von http://192.168.0.10:8080/cmd/bla gibt euch auf der Konsole eine Zeile "Command Request: bla" aus aber weiter passiert erst mal nichts da das noch nicht eingebaut ist.
Ein Aufruf von http://192.168.0.10:8080/data/ wiederum gibt euch eine JSON Zeile aus: {"distance": 16, "MotorSpeed": 26} Aber mehr passiert hier auch noch nicht da das ebenfalls noch nicht eingebaut ist ;)
Somit funktioniert schon mal das Grundgerüst auf das ihr weiter aufbauen könnt :angel:
Als nächstes bauen wir den WebSocket Teil ein um einzelne Elemente der Webseite dynamisch aktualisieren zu können, oder auch um zB über Buttons auf der Webseite Befehle ans Pythonscript zu schicken - ohne das jedes mal die ganze Seite neu läd.
Zunächst laden wir jQuery ins Verzeichnis static:
[code]wget -O/home/pi/static/jquery.min.js https://code.jquery.com/jquery-1.12.3.min.js
Alles anzeigen
Als nächstes legen wir uns eine eigene JavaScript Datei an in der wir unsere Funktionen usw einfügen: nano /home/pi/static/control.js
Und fügen dort folgendes ein:
control.js => http://codepad.org/z7cxw2GX
[code=php]
if (typeof(String.prototype.strip) === "undefined") {
String.prototype.strip = function() {
return String(this).replace(/^\s+|\s+$/g, '');
};
}
function isset(strVariableName) {
try {
eval( strVariableName );
} catch( err ) {
if ( err instanceof ReferenceError )
return false;
}
return true;
}
function sleep(millis, callback) {
setTimeout(function() { callback(); } , millis);
}
//source of: http://www.html5tutorial.info/html5-range.php
function printValue(sliderID, textbox) {
var x = document.getElementById(textbox);
var y = document.getElementById(sliderID);
x.value = y.value;
}
function mylog(message) {
if (isset(DEBUG) && DEBUG == 1) {
console.log(message);
var logthingy;
logthingy = document.getElementById("Log");
if( logthingy.innerHTML.length > 5000 )
logthingy.innerHTML = logthingy.innerHTML.slice(logthingy.innerHTML.length-5000);
logthingy.innerHTML = logthingy.innerHTML+"<br/>"+message;
logthingy.scrollTop = logthingy.scrollHeight*2;
}
}
//----------------------------------------------------------------
/*
var telemetryTimer;
$(document).ready(function() {
// start Main Timers
telemetryTimer = setTimeout(get_telemetry, 1000);
});
*/
function Send(command) {
$.ajax({
type: "GET",
url: "/cmd/" + command,
async: true,
dataType: "JSON",
success: function(obj) {
console.log("JSON Data: " + obj.ID + ":" + obj.value);
document.getElementById(obj.ID).innerHTML = obj.value;
},
});
}
function get_telemetry() {
$.getJSON("/data/")
.fail(function() {
console.log("Error processing get_telemetry");
clearTimeout(telemetryTimer);
})
.done(function(data) {
$.each(data, function(id,val) {
if (document.getElementById(id) !== null) {
console.log("JSON Data: " + id + ":" + val);
if (id == "LoadAVGnum") {
document.getElementById(id).innerHTML = val + "%";
} else if (id == "LoadAVGperc") {
document.getElementById(id).value = val;
} else if (id == "RAMnum") {
document.getElementById(id).innerHTML = val + "MB";
} else if (id == "RAMperc") {
document.getElementById(id).value = val;
} else {
document.getElementById(id).innerHTML = val;
}
}
})
telemetryTimer = setTimeout(get_telemetry, 2000);
});
}
function parseResponse(requestlist) {
//mylog("Parsing: "+requestlist)
for (var i=0; i<requestlist.length; i++) {
var requestsplit = requestlist[i].strip().split(':')
requestsplit[requestsplit.length] = "dummy";
command = requestsplit[0];
val = requestsplit[1];
val2 = requestsplit[2];
if (command == "LoadAVGnum") {
document.getElementById("LoadAVGnum").innerHTML = val + "%";
} else if (command == "LoadAVGperc") {
document.getElementById("LoadAVGperc").value = val;
} else if (command == "RAMnum") {
document.getElementById("RAMnum").innerHTML = val + "MB";
} else if (command == "RAMperc") {
document.getElementById("RAMperc").value = val;
}
}
}
[/php]
Auch hier ist bis jetzt noch kein WebSocket enthalten!
In dieser JS Datei sind erst mal alle Voraussetzungen gegeben um " /data/ " und " /cmd/ " zu nutzen.
Nach dem horizontalen Stich ist oben ein Teil noch auskommentiert, welcher bewirkt das nach laden der Seite nach 1000ms (1sec) die Funktion "get_telemetry()" ausgeführt und /data/ angesprochen wird. Das wird von dieser Funktion dann alle 2000ms wiederholt und vom Pythonscript zurückgegebene JSON Daten entsprechend verarbeitet.. Die Sachen ganz oben sind hilfreiche Funktionen, wie zum Beispiel "isset".
Nun aber erst mal zum WebSocket Teil... Das können wir ebenfalls in die Datei control.js einfügen, es kann aber auch eine separate Datei sein, muss dann nur in der index.html zusätzlich geladen werden. Letzteres verwende ich hier und die Datei muss natürlich auch wieder ins static Verzeichnis.
websocket.js => http://codepad.org/XidIvxoD
[code=php]
var ws;
var ws_status = "closed";
function set_ws_status(status) {
ws_status = status;
if (document.getElementById("connectionStatus") !== null) {
document.getElementById("connectionStatus").innerHTML = status;
}
}
function WebSocket_Close() {
ws.close();
}
function WebSocket_Open() {
ws = new WebSocket("ws://"+location.host+":7070");
//mylog(ws);
ws.onerror = function(evt) {
mylog('Error detected: '+evt.data);
}
ws.onopen = function() {
mylog('Connection opened!');
set_ws_status("opened");
}
ws.onclose = function(evt) {
if (isset(evt.reason)) {
mylog('Connection closed:'+evt.reason);
} else {
mylog('Connection closed!');
}
set_ws_status("closed");
}
ws.onmessage = function(evt) {
var message = evt.data;
mylog('Received message: >>>'+message+'<<<');
parseResponse(message.split("\n"));
}
}
function WebSocket_Send(data) {
if (ws_status == "opened") {
ws.send(data);
mylog('Sent message: >>>'+data+'<<<');
}
}
[/php]
Natürlich müssen wir ins Python Script auch noch Unterstützung für WebSocket einbauen. Ich poste jetzt aber nur die zusätzlichen Zeilen sodass man das auch standalone verwenden könnte - Wie die Scripts vollständig aussehen folgt später in dieser Anleitung.
bottle
[code=php]
from __future__ import print_function
[/php]
tornado
[code=php]
from __future__ import print_function
import tornado.web
import tornado.websocket
import tornado.ioloop
WebSocketPort = 7070
DEBUG = True
def printD(message):
if DEBUG:
print(message)
def getUptime():
with open('/proc/uptime', 'r') as f:
uptime_seconds = float(f.readline().split()[0])
uptime = str(timedelta(seconds = uptime_seconds))
return uptime
def getPiRAM():
with open('/proc/meminfo', 'r') as mem:
tmp = 0
for i in mem:
sline = i.split()
if str(sline[0]) == 'MemTotal:':
total = int(sline[1])
elif str(sline[0]) in ('MemFree:', 'Buffers:', 'Cached:'):
tmp += int(sline[1])
free = tmp
used = int(total) - int(free)
usedPerc = (used * 100) / total
return usedPerc
def getPiTemperature():
with open("/sys/class/thermal/thermal_zone0/temp", 'r') as f:
content = f.read().splitlines()
return float(content[0]) / 1000.0
### Parse request from webif
#required format-> command:value
def WebRequestHandler(requestlist):
returnlist = ""
for request in requestlist:
request = request.strip()
requestsplit = request.split(':')
requestsplit.append("dummy")
command = requestsplit[0]
value = requestsplit[1]
if value == "dummy":
value = "0"
if command == "localping":
returnlist += "\n localping:ok"
elif command == "LoadAVRnum":
returnlist += "\n LoadAVRnum:"+open("/proc/loadavg").readline().split(" ")[:3][0]
elif command == "Uptime":
returnlist += "\n Uptime:"+str(getUptime()).split(".")[0]
elif command == "RAMperc":
returnlist += "\n RAMperc:"+str(getPiRAM())
#returnlist += "\n RAMperc:"+str(psutil.phymem_usage().percent)
elif command == "PiTEMP":
returnlist += "\n PiTEMP:"+str(getPiTemperature())
elif command == "System.Power":
if value == "off":
subprocess.Popen(["shutdown","-h","now"])
return "System.Power:ok"
elif value == "reboot":
subprocess.Popen(["shutdown","-r","now"])
return "System.Power:ok"
return returnlist
### WebSocket server tornado <-> WebInterface
class WebSocketHandler(tornado.websocket.WebSocketHandler):
connections = []
# the client connected
def open(self):
printD("New client connected")
self.write_message("You are connected")
self.connections.append(self)
# the client sent the message
def on_message(self, message):
printD("Message from WebIf: >>>"+message+"<<<")
requestlist = message.splitlines()
self.write_message(WebRequestHandler(requestlist))
# client disconnected
def on_close(self):
printD("Client disconnected")
self.connections.remove(self)
# start a new WebSocket Application
# use "/" as the root, and the WebSocketHandler as our handler
application = tornado.web.Application([
(r"/", WebSocketHandler),
])
try:
# start the tornado webserver on port WebSocketPort
application.listen(WebSocketPort)
tornado.ioloop.IOLoop.instance().start()
except Exception, e1:
print("Error...: " + str(e1))
except KeyboardInterrupt:
print("Schliesse Programm..")
[/php]
Jetzt müssen wir auch noch die index.html anpassen bzw erweitern und bauen auch gleich einen Button zum testen ein:
index.html
[code=php]
<!DOCTYPE html>
<html>
<head>
<script src="/static/jquery.min.js" type="text/javascript"></script>
<script src="/static/control.js" type="text/javascript"></script>
<script src="/static/websocket.js" type="text/javascript"></script>
</head>
<body>
Test: {{ test }}
<br/>
<input type="button" value="CPU Temperatur" onClick="WebSocket_Send('PiTEMP')" />
<br/>
<span id="PiTEMP"></span> °C
</body>
</html>
[/php]