Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I stream data through a flask application?

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?

like image 291
Jon Cage Avatar asked Jan 03 '17 12:01

Jon Cage


People also ask

How do you send data through a URL in flask?

If you're looking to use variables sent like /arg1/arg2/arg3 use: @app. route('/create/<arg1>/<arg2>/<arg3>', methods=['POST']) def clone(arg1, arg2, arg3): ...


1 Answers

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>
like image 185
Jon Cage Avatar answered Oct 19 '22 19:10

Jon Cage