Raspberry Pi websockets with Python & Tornado

I started to look into websockets for RaspberryPi. My Pi is overclocked at 900Mhz and it’s stable but even so it became apparent that loading it with too many HTTP requests for various things (streaming data into EmonCMS works over HTTP) can get slow. So here’s a simple working Hello-World websockets example in Python, using the popular Tornado websocket library. It’s a very simple echo program, but I think proves the point that websockets are much faster than HTTP requests since they are a direct link between the server and the browser.

RaspberryPi_websockets_example_python_tornadoFirst you’ll need to install Tornado using pip (python’s package manager):

sudo pip install Tornado

Then upload this script to the /home/pi directory:

import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web

class WSHandler(tornado.websocket.WebSocketHandler):
  def open(self):
    print 'New connection was opened'
    self.write_message("Welcome to my websocket!")

  def on_message(self, message):
    print 'Incoming message:', message
    self.write_message("You said: " + message)

  def on_close(self):
    print 'Connection was closed...'

application = tornado.web.Application([
  (r'/ws', WSHandler),
])

if __name__ == "__main__":
  http_server = tornado.httpserver.HTTPServer(application)
  http_server.listen(8888)
  tornado.ioloop.IOLoop.instance().start()

Upload this php page to the /var/www directory, and edit the “raspberrypi” hostname where your websocket lives if you need to (line 33):

<!doctype html>
<html>
  <head>
    <title>WebSockets with Python & Tornado</title>
    <meta charset="utf-8" />
    <style type="text/css">
      body {
        text-align: center;
        min-width: 500px;
      }
    </style>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <script>
      $(function(){
        var ws;
        var logger = function(msg){
          var now = new Date();
          var sec = now.getSeconds();
          var min = now.getMinutes();
          var hr = now.getHours();
          $("#log").html($("#log").html() + "<br/>" + hr + ":" + min + ":" + sec + " ___ " +  msg);
          //$("#log").animate({ scrollTop: $('#log')[0].scrollHeight}, 100);
          $('#log').scrollTop($('#log')[0].scrollHeight);
        }

        var sender = function() {
          var msg = $("#msg").val();
          if (msg.length > 0)
            ws.send(msg);
          $("#msg").val(msg);
        }

        ws = new WebSocket("ws://raspberrypi:8888/ws");
        ws.onmessage = function(evt) {

          logger(evt.data);
        };
        ws.onclose = function(evt) { 
          $("#log").text("Connection was closed..."); 
          $("#thebutton #msg").prop('disabled', true);
        };
        ws.onopen = function(evt) { $("#log").text("Opening socket..."); };

        $("#msg").keypress(function(event) {
          if (event.which == 13) {
             sender();
           }
        });

        $("#thebutton").click(function(){
          sender();
        });
      });
    </script>
  </head>

  <body>
    <h1>WebSockets with Python & Tornado</h1>
    <div id="log" style="overflow:scroll;width:500px; height:200px;background-color:#ffeeaa; margin:auto; text-align:left">Messages go here</div>

    <div style="margin:10px">
      <input type="text" id="msg" style="background:#fff;width:200px"/>
      <input type="button" id="thebutton" value="Send" />
    </div>

    <a href="http://lowpowerlab.com/blog/2013/01/17/raspberrypi-websockets-with-python-tornado/">www.LowPowerLab.com</a>
  </body>
</html>

Then start your socket server (the & will put the python thread in the background):

pi@raspberrypi ~ $ sudo python pysocket.py &
[1] 2554

If you later need to kill/stop this script, do this (note the thread ID above – 2554):

pi@raspberrypi ~ $ sudo kill 2554

Then go ahead and point your browser to: http://raspberrypi/pysocket.php.
The socket server should greet you. If you close the browser or stop the python script, or shutdown the Pi, the connection will be closed. You may open another browser and point it to the same address, your socket will just spawn a new connection and will now talk to two socket clients independently!
Needless to say this won’t work properly in IE, it doesn’t seem to support this version of the websockets protocol. I’ve fired IE long ago and only open it when I want to laugh or cry about how bad a browser it is.

This is a starting point which hopefully will expand into a more versatile platform for the Pi which can accept websockets as a replacement/addition to HTTP requests. Next up is trying to interface this puppy to the GPIO, particularly the serial port.

Enjoy your pysocket, and let me know if you do something interesting with it!

In case you care, here’s an interesting comparison of different websocket frameworks: http://en.wikipedia.org/wiki/Comparison_of_WebSocket_implementations

4 thoughts on “Raspberry Pi websockets with Python & Tornado

  1. what should we name the fist script file to be saved in /home/pi/???.py

    Thx
    R

    • That’s like your “Desktop” on windows or home directory. But you can save it wherever you want…

  2. Would be nice if you tell us how to name the php script, where we must change the scripts to use other script-names and if you could make some more comments.

    I’d like to use your code but all i got was something like:
    “Can only ‘upgrade’ to ‘WebSocket'”

Comments are closed.