Permalink
Browse files

Start of WebServer that runs on Pi and serves up mobile UI for intera…

…cting with devices.
  • Loading branch information...
Joe Walnes
Joe Walnes committed May 24, 2012
0 parents commit 5a15ab764ffaf9b3a0ee2709cf6ed3f7a77b91c5
@@ -0,0 +1,3 @@
+virtual-env
+*.pyc
+*.swp
@@ -0,0 +1 @@
+Experiments with the Raspberry Pi
@@ -0,0 +1,16 @@
+Simple example of:
+
+* ...a mobile web-app that contains a slider bar...
+* ...that communicates to a Python program via WebSockets...
+* ...that adjusts an LED bar-graph.
+
+Setup
+-----
+
+ pip install -r requirements.txt
+
+Run
+---
+
+ ./slider.py
+
@@ -0,0 +1 @@
+tornado>=2.2.1
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+from webserver import *
+
+class SharedValueHandler(WebSocketHandler):
+
+ def __init__(self, value=None):
+ self.value = value
+ self.connections = set()
+
+ def on_open(self, connection):
+ connection.send(self.value)
+ self.connections.add(connection)
+
+ def on_close(self, connection):
+ self.connections.remove(connection)
+
+ def on_message(self, connection, message):
+ print 'New value: %s' % message
+ self.value = message
+ for other_connection in self.connections:
+ other_connection.send(message)
+
+def main():
+ webserver = TornadoWebServer(port=8888, debug=True)
+ webserver.static_files('/static/', './static')
+ webserver.websocket('/slider-value', SharedValueHandler(0))
+ print 'Listening on %s' % webserver.url
+ webserver.run()
+
+if __name__ == '__main__':
+ main()
+
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<title>Slider</title>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<link rel="stylesheet" href="/static/lib/jquery.mobile-1.1.0.min.css">
+<script src="/static/lib/jquery-1.7.1.min.js"></script>
+<script src="/static/lib/jquery.mobile-1.1.0.min.js"></script>
+
+<script>
+ $(function() {
+
+ var websocket = new WebSocket('ws://' + document.location.host + '/slider-value');
+ websocket.onopen = function() {
+ console.log('connected');
+ };
+ websocket.onclose = function() {
+ console.log('disconnected');
+ };
+ websocket.onmessage = function(event) {
+ $('#slider1').val(event.data).data('updating', true).slider('refresh').data('updating', false);
+ };
+ $('#slider1').change(function(event) {
+ if (!$(event.target).data('updating')) {
+ websocket.send($(event.target).val());
+ }
+ });
+ });
+</script>
+
+<div data-role="page">
+
+ <div data-role="header">
+ <h1>Slider Demo</h1>
+ </div>
+
+ <div data-role="content">
+ <p>Adjust LED bar graph, by flicking slider</p>
+ <p>
+ <input type="range" id="slider1" value="31" min="0" max="63" data-highlight="true">
+ </p>
+ </div>
+
+</div>

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -0,0 +1,100 @@
+class WebServer(object):
+
+ def static_files(self, path, directory_on_disk, default_filename='index.html'):
+ pass
+
+ def websocket(self, path, handler):
+ pass
+
+ def run(self):
+ pass
+
+
+class WebSocketHandler(object):
+
+ def on_open(self, connection):
+ pass
+
+ def on_close(self, connection):
+ pass
+
+ def on_message(self, connection, message):
+ pass
+
+
+class WebSocketConnection(object):
+
+ def send(self, message):
+ pass
+
+ def close(self):
+ pass
+
+
+## Tornado backed implementation
+
+from socket import gethostname
+from tornado import websocket
+from tornado.ioloop import IOLoop
+from tornado.web import Application
+
+class TornadoWebServer(WebServer):
+
+ def __init__(self,
+ port,
+ debug = False,
+ ioloop = IOLoop.instance()):
+ self.handlers = []
+ self.application = None
+ self.ioloop = ioloop
+ self.port = port
+ self.url = 'http://%s:%d/' % (gethostname(), self.port)
+ self.settings = dict(
+ debug = debug # Auto reload app when Python code changes on disk, stack traces on error pages
+ )
+
+ def static_files(self, path, directory_on_disk, default_filename='index.html'):
+ self.settings['static_url_prefix'] = path
+ self.settings['static_path'] = directory_on_disk
+ self.settings['static_handler_args'] = dict(default_filename = default_filename)
+
+ def websocket(self, path, handler):
+ self.handlers.append((path, TornadoWebSocketAdapter, dict(handler=handler)))
+
+ def run(self, **kwargs):
+ self.application = Application(self.handlers, **self.settings)
+ self.application.listen(self.port)
+ self.ioloop.start()
+
+
+class TornadoWebSocketAdapter(websocket.WebSocketHandler):
+
+ def __init__(self, application, request, handler, **kwargs):
+ websocket.WebSocketHandler.__init__(self, application, request, **kwargs)
+ self.handler = handler
+ self.connection = TornadoWebSocketConnection(self)
+
+ def open(self):
+ self.handler.on_open(self.connection)
+
+ def on_message(self, message):
+ self.handler.on_message(self.connection, str(message))
+
+ def on_close(self):
+ self.handler.on_close(self.connection)
+
+
+class TornadoWebSocketConnection(WebSocketConnection):
+
+ def __init__(self, tornado_handler):
+ self.tornado_handler = tornado_handler
+
+ def send(self, message):
+ self.tornado_handler.write_message(str(message))
+
+ def close(self):
+ self.close()
+
+ def __str__(self):
+ return 'WebSocketConnection' # TODO: id, url, remote source, open time
+

0 comments on commit 5a15ab7

Please sign in to comment.