Python Forum
Output ZMQ-content to browser
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Output ZMQ-content to browser
#1
I have this code in Python. (Add i'm not a great python-expert ;) )
With this I can output the content of the ZeroMQ-stream to a file. Only writing to a file every 10 seconds does not seem to be really useful and costs a lot of performance.

Now I would like to show the content in a web-page. I am not an extreme python expert, but I have learned that I can set up a web server with PyBottle.

How can I integrate PyBottle in my code, so it can output the latest message of the stream? I thought about the code of PyBottle in the **while**-loop.

But do not I ( unnecessarily ) create a new web-server instance?

How can I handle this?

Or does anyone else have a good idea how to export the content of recent data from the stream to a browser?

Sample of PyBottle:
    from bottle import route, run, template
    
    @route( '/hello/<name>' )
    def index( name ):
        return template( '<b>Hello {{name}}</b>!', name = name )
    
    run( host = 'localhost', port = 8080 )
And my Python script, so far:
    #!/usr/bin/env python2

    from gzip       import GzipFile
    from cStringIO  import StringIO
    from subprocess import call
    pass;           import zmq
    
    context = zmq.Context()
    
    subscriber = context.socket( zmq.XSUB )
    subscriber.connect( "tcp://pubsub.*******.nl:7664" )
    subscriber.send( chr( 0x01 )             # { 0x01: ZMQ_XSUB.subscribe,
                   + "/RIG/VehiclePositions" #   0x00: ZMQ_XSUB.unsubscribe
                     )                       #   }
    while   True:

            multipart =  subscriber.recv_multipart()
            address   =  multipart[0]
            contents  = ''.join(multipart[1:])
            contents  =  GzipFile( '', 'r', 0, StringIO( contents ) ).read()
            filename  = "tmp/treinpos.txt"
            file      =  open( filename, "w" )
            file.write( contents )
            file.close()
    
    subscriber.close()
    context.term()
Reply
#2
Anyone an idea how i can output the content to the browser?
Reply
#3
I guess you mean Bottle and not PyBottle.
Quote:But do not I ( unnecessarily ) create a new web-server instance?
Yes it's not good and unnecessarily to create a web-server instance for every update.
There are soultion for this and i would recommend Flask,
that has better support for stuff like this like Flask-SocketIO and jQuery + socket.io on the client side.
Also mention Celery that work well with Flask.

The topic of running background live update/stream tasks is complex.
If new to Python and web-develoment dos not help Wink

Can show a solution that call a Python function on server side every 10-sec.
This is using Ajax to no reload browser,and done with jQuery on client side.
To help keep it clean $.ajaxSetup({ cache: false });
Will prevent all future AJAX requests from being cached.
setTimeout( will execute a script only one time) is better setInterval().

app.py:
from flask import Flask, render_template, jsonify, request
import random

app = Flask(__name__)

@app.route("/")
def test_job():
    return render_template('index.html')

@app.route('/stuff', methods=['GET'])
def stuff():
    '''Here stuff to be send to browser'''
    val_random = random.random()   
    return jsonify(val_random=val_random)

if __name__ == "__main__":
    app.run(debug=True)
index.html:
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/style.css') }}" />
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <title>Show updated random number</title>
</head>
<body>
  <div class="table">
    <p id="rand_value">Value</p>
    <button>Push to start random update</button>
  </div>
</body>

<script> 
  $.ajaxSetup({ cache: false });
  $(document).ready(function () {
    $("button").click(function update_values() {
      $.getJSON('/stuff', function (dat) {
        $("#rand_value").text(dat['val_random']);
      });
      var interval = setTimeout(update_values, 10000);
    });
  });
</script>

</html>
Reply
#4
Thank you for your extensive response. I will look at it from the weekend.
I am talking about the latest update in the stream, which must be shown in the browser.

How you can have this refreshed real-time by users, that is indeed with AJAX.
I was familiar with that point.
Reply
#5
I do not understand at all?

This is what i must do first in my code, and of course make sure that flask is installed and running.
app = Flask(__name__)
And so I have to put this code in the while loop?

@app.route("/")
def index():
    return content
Is this right?
Reply
#6
(Nov-24-2017, 02:26 PM)AarClay Wrote: And so I have to put this code in the while loop?
Is this right?
No i think you are confused Confused
There no while loop,the build web-server of Flask is what should be running. 
Here is the full setup,also added Bootstrap to make button and random numbers text look better.
pip install Flask
Folder setup:
rand_numbers\
  |-- app.py
  templates\
    |-- index.html
app.py:
from flask import Flask, render_template, jsonify, request
import random
 
app = Flask(__name__)
 
@app.route("/")
def test_job():
    return render_template('index.html')
 
@app.route('/stuff', methods=['GET'])
def stuff():
    '''Here stuff to be send to browser'''
    val_random = random.random()   
    return jsonify(val_random=val_random)
 
if __name__ == "__main__":
    app.run(debug=True)
index.html:
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/style4.css') }}" />
  <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" >
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <title>Show updated random number</title>
</head>

<body style="background-color: rgb(186, 209, 231)">
  <div class="text-center" role="group" aria-label="...">
    <h1 class="text-success" id='numbers'>000000</h1>
    <a id='b1' class="btn btn-primary"><span class="glyphicon glyphicon-random"></span> Random numbers</a>
  </div>
</body>

<script> 
  $.ajaxSetup({ cache: false });
  $(document).ready(function () {
    $("#b1").click(function update_values() {
      $.getJSON('/stuff', function (dat) {
        $("#numbers").text(dat['val_random']);
      });
      var interval = setTimeout(update_values, 10000);
    });
  });
</script>
</html>
No shall start web-server bye running python app.py in rand_numbers folder(always to this from command line).
This will give you a address http://127.0.0.1:5000/.
This address do you copy and paste into browser,and push button to start random update every 10-sec.
Reply
#7
But, i want to output the last message from the ZeroMQ stream. Not a random number....
Read my first post ;)
How can i integrate this, on the way that i describe?
Reply
#8
(Nov-26-2017, 12:01 AM)AarClay Wrote: Read my first post ;)
ow can i integrate this, on the way that i describe?
They point is not at all that i shall write everything for for you Dodgy
Look at jsonify(),it can handle both python list and dict which will be JSON serialization automatic over the connection.
So when i do jsonify(val_random=val_random) it will send this Response JSON object in browser {"val_random: 0.55719943207732"}.
You have to look at your contents,and think of how it can be transferred based on this info.
Reply
#9
The content is also a JSON-string. I will try something.... Thanks :)
Reply
#10
Smile thanks for the post snippsat. I used your example (with data changes) to use flask on my Raspberry Pi 2 with a Sense Hat to have a dynamic webpage which automatically updates Humidity, Temp, Barometric Pressure, and other data. It worked marvelously!!
snippsat likes this post
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  JupyterLab Dictionary Content Output Format Ourkid123uk 0 1,301 Sep-04-2020, 02:18 PM
Last Post: Ourkid123uk

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020