9

I'm investigating the possibility of using a Flask application as an interface to an embedded system. I've used flask before (I've written some very basic flask sites to poll external systems in response to a page load to populate a chart for example) but I'm not sure how I would go about pushing data into the Flask application and on to the user's browser(s).

I was planning on pushing data from a C++ application running on the embedded device into the flask application (also running on the embedded device) using ZeroMQ.

From what I've read, something like flask-socketIO would be a possibility to get things from Flask to the user's browser.

The one thing that's not clear to me is whether it's possible / how you would go about receiving data from ZeroMQ and pushing that out to the browser?

7
  • Might be a duplicate of another SO post if using a background thread is the right approach? Commented Jan 3, 2017 at 13:08
  • I've done it with websockets and gevent, and it worked pretty good. Can check out my example here: github.com/reptillicus/zmq/blob/master/exmaples/diffusion/… Commented Jan 3, 2017 at 13:40
  • Mainly just frustrating issues with the client side vs server side versions changing slightly and breaking everything. I gave up on it Commented Jan 3, 2017 at 14:25
  • Also, almost everything supports standard web sockets now, so no need for socketio really Commented Jan 3, 2017 at 14:35
  • @reptilicus - I gave your suggestion a shot but the wsgi server appears to be throwing errors when it loads a request (see edits above). Commented Jan 3, 2017 at 15:25

1 Answer 1

14

In case anyone else wants to do the same, this is the simplest example I could boil things down to based on the example by reptilicus...

Instructions

  1. Set the code below laid out in the structure mentioned below.
  2. Install the Python modules listed below
  3. Run the server
  4. Run the data source
  5. Open a web browser and navigate to http://localhost:25000/

If everything worked you should see a very basic page along these lines:

enter image description here

Python / Modules

These were the versions my test implementation used. Others may work too.

  • Python v3.5.2
  • Pyzmq v15.2.0
  • gevent v1.2.0
  • karellen-geventws v1.0.1 (required over gevent-websocket for Python 3 support)
  • Flask v0.10.1
  • Flask-Sockets v0.2.1

You also need a copy of Reconnecting Websocket, available here.

Code layout

\ZmqFlaskForwarder
    \static
        \js
            application.js
            reconnecting-websocket.min.js
    \templates
        index.html
    data_source.py
    server.py

Server App (server.py)

import zmq.green as zmq
import json
import gevent
from flask_sockets import Sockets
from flask import Flask, render_template
import logging
from gevent import monkey

monkey.patch_all()

app = Flask(__name__)
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

sockets = Sockets(app)
context = zmq.Context()

ZMQ_LISTENING_PORT = 12000

@app.route('/')
def index():
    logger.info('Rendering index page')
    return render_template('index.html')

@sockets.route('/zeromq')
def send_data(ws):
    logger.info('Got a websocket connection, sending up data from zmq')
    socket = context.socket(zmq.SUB)
    socket.connect('tcp://localhost:{PORT}'.format(PORT=ZMQ_LISTENING_PORT))
    socket.setsockopt_string(zmq.SUBSCRIBE, "")
    poller = zmq.Poller()
    poller.register(socket, zmq.POLLIN)
    gevent.sleep()
    received = 0
    while True:
        received += 1
        # socks = dict(poller.poll())
        # if socket in socks and socks[socket] == zmq.POLLIN:
        data = socket.recv_json()
        logger.info(str(received)+str(data))
        ws.send(json.dumps(data))
        gevent.sleep()

if __name__ == '__main__':
    logger.info('Launching web server')
    from gevent import pywsgi
    from geventwebsocket.handler import WebSocketHandler
    server = pywsgi.WSGIServer(('', 25000), app, handler_class=WebSocketHandler)
    logger.info('Starting serving')
    server.serve_forever()

Data Source (data_source.py)

import zmq
import random
import sys
import time
import json

port = "12000"

context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind("tcp://*:%s" % port)
while True:
    first_data_element = random.randrange(2,20)
    second_data_element = random.randrange(0,360)
    message = json.dumps({'First Data':first_data_element, 'Second Data':second_data_element})
    print(message)
    socket.send_string(message)
    time.sleep(0.5)

Client JavaScript (application.js)

ws = new ReconnectingWebSocket("ws://"  + location.host + '/zeromq')

ws.onmessage = function(message) {
  payload = JSON.parse(message.data);
  $('#latest_data').html('<h2> Data: ' + message.data + '</h2>');
};

Template (index.html)

<!DOCTYPE html>
<html>
  <head>
    <title>Python Websockets ZeroMQ demo</title>
  </head>
  <body>
    <div class="container">
      <h2> Simple ZeroMQ data streaming via web sockets! </h2>
      <div id="latest_data"></div>
    </div>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
    <script type="text/javascript" src="static/js/reconnecting-websocket.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.6/d3.min.js"></script>
    <script type="text/javascript" src="static/js/application.js"></script>
  </body>
</html>
Sign up to request clarification or add additional context in comments.

1 Comment

This is something I looked for a while already. Thanks. On one PC it is perfect, the other - when I close a page, it shows an error geventwebsocket.exceptions.WebSocketError: Socket is dead ..dist-packages/geventwebsocket/websocket.py BUT the other PC is prefect. Thnx

Your Answer

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.