4
\$\begingroup\$

I am trying to build a websocket server to run on the Raspberry Pi. The websocket server has to push periodic realtime update to a browser. Here is a sample code that I am planning to use. The example code here sends the current time instead of sensor data.

Most of the code is built form an example. However, what I need feedback on is

  • The way stpoll is coded (sensor status poll)
  • The global variable that passes the message to terminate the thread. I don't like it. Is there a better way to terminate a task that runs forever?
  • The way the time (sensor data) is broadcasted to all connected clients. (another global variable)

I had to code this without much documentation.

# -*- coding: utf-8 -*-
import argparse
import random
import os
import time
import threading
import signal
import sys
import cherrypy
from ws4py.server.cherrypyserver import WebSocketPlugin, WebSocketTool
from ws4py.websocket import WebSocket
from ws4py.messaging import TextMessage
class ChatWebSocketHandler(WebSocket):
 def received_message(self, m):
 cherrypy.engine.publish('websocket-broadcast', m)
 def closed(self, code, reason="A client left the room without a proper explanation."):
 cherrypy.engine.publish('websocket-broadcast', TextMessage(reason))
class Root(object):
 def __init__(self, host, port, ssl=False):
 self.host = host
 self.port = port
 self.scheme = 'wss' if ssl else 'ws'
 @cherrypy.expose
 def index(self):
 return """<html>
 <head>
 <script type='application/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js'></script>
 <script type='application/javascript'>
 $(document).ready(function() {
 websocket = '%(scheme)s://%(host)s:%(port)s/ws';
 if (window.WebSocket) {
 ws = new WebSocket(websocket);
 }
 else if (window.MozWebSocket) {
 ws = MozWebSocket(websocket);
 }
 else {
 console.log('WebSocket Not Supported');
 return;
 }
 window.onbeforeunload = function(e) {
 $('#chat').val($('#chat').val() + 'Bye bye...\\n');
 ws.close(1000, '%(username)s left the room');
 if(!e) e = window.event;
 e.stopPropagation();
 e.preventDefault();
 };
 ws.onmessage = function (evt) {
 $('#chat').val($('#chat').val() + evt.data + '\\n');
 };
 ws.onopen = function() {
 ws.send("%(username)s entered the room");
 };
 ws.onclose = function(evt) {
 $('#chat').val($('#chat').val() + 'Connection closed by server: ' + evt.code + ' \"' + evt.reason + '\"\\n');
 };
 $('#send').click(function() {
 console.log($('#message').val());
 ws.send('%(username)s: ' + $('#message').val());
 $('#message').val("");
 return false;
 });
 });
 </script>
 </head>
 <body>
 <form action='#' id='chatform' method='get'>
 <textarea id='chat' cols='35' rows='10'></textarea>
 <br />
 <label for='message'>%(username)s: </label><input type='text' id='message' />
 <input id='send' type='submit' value='Send' />
 </form>
 </body>
 </html>
 """ % {'username': "User%d" % random.randint(0, 100), 'host': self.host, 'port': self.port, 'scheme': self.scheme}
 @cherrypy.expose
 def ws(self):
 cherrypy.log("Handler created: %s" % repr(cherrypy.request.ws_handler))
def stpoll(arg):
 global pollStatus
 while pollStatus:
 tm=time.localtime();
 print tm.tm_sec
 if 'WebSocket' in globals():
 print "WS !"
 cherrypy.engine.publish('websocket-broadcast', '%s ' %tm)
 time.sleep(2)
 print "exitting therad"
def signal_handler(signal, frame):
 global pollStatus
 pollStatus=False
 cherrypy.engine.stop()
 cherrypy.engine.exit()
 print('You pressed Ctrl+C!')
if __name__ == '__main__':
 import logging
 from ws4py import configure_logger
 configure_logger(level=logging.DEBUG)
 signal.signal(signal.SIGINT, signal_handler)
 pollStatus=True 
 thread = threading.Thread(target = stpoll, args = (10, ))
 thread.daemon = True
 thread.start()
 parser = argparse.ArgumentParser(description='Echo CherryPy Server')
 parser.add_argument('--host', default='127.0.0.1')
 parser.add_argument('-p', '--port', default=9000, type=int)
 parser.add_argument('--ssl', action='store_true')
 args = parser.parse_args()
 cherrypy.config.update({'server.socket_host': args.host,
 'server.socket_port': args.port,
 'tools.staticdir.root': os.path.abspath(os.path.join(os.path.dirname(__file__), 'static'))})
 if args.ssl:
 cherrypy.config.update({'server.ssl_certificate': './server.crt',
 'server.ssl_private_key': './server.key'})
 WebSocketPlugin(cherrypy.engine).subscribe()
 cherrypy.tools.websocket = WebSocketTool()
 cherrypy.quickstart(Root(args.host, args.port, args.ssl), '', config={
 '/ws': {
 'tools.websocket.on': True,
 'tools.websocket.handler_cls': ChatWebSocketHandler
 },
 '/js': {
 'tools.staticdir.on': True,
 'tools.staticdir.dir': 'js'
 }
 }
 )
 thread.join()
Quill
12k5 gold badges41 silver badges93 bronze badges
asked Jan 31, 2015 at 6:40
\$\endgroup\$
2

1 Answer 1

2
\$\begingroup\$

Your code is nice, but it could use a few changes:

  • % {}: rather than using that formatting method, you should use the string.format() method, involving {0} {1} instead of % as it is recommended by PEP8, Python's official style guide.
  • print "exitting therad": both exiting and thread are spelt incorrectly
  • global pollStatus: you shouldn't be naming your variables like camelCase, rather snake_case instead, as also expressed by PEP8
  • tm=time.localtime(): you should have whitespace between your binary operators, and also you shouldn't abbreviate your variables like tm: local_time would be much better.

Other than that, your code looks nice, well done!

answered Jul 9, 2015 at 13:49
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.