Martin
Martin

Reputation: 147

Update variables in a web page without reloading it in a simple way

Colleagues,

I am receiving serial info in the raspberry pi and need to send it to a browser. I am using python to capture the data and flask as a web framework . The main isue that I facing is how to refresh automatically, like every second, the web page . Actually refresh the variables only . Was browsing several post and everyone seems to point to AJAX /JSON /JQUERY , but for my simple app, seems to much . Is there any simple way to do what I need?

python app

from flask import Flask,render_template

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html', ent_direc ="120")

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')

ent_direc in this case(fixed to 120 for testing, but is received through pyserial) is the variable that I am passing to my html page , where I have java script ( + html canvas) to display a gauge .

index.html - just a few lines

<!DOCTYPE html>
<html>
<body>

<canvas id="canvas" width="400" height="400" style="background-color:#ffffff"></canvas>

<script>
 var canvas = document.getElementById("canvas");
 var ctx = canvas.getContext("2d");
 var radius = canvas.height / 2;
 var ent_direc;
 ctx.translate(radius, radius);
 radius = radius * 0.90;
 drawClock();




function drawClock() {
    drawFace(ctx, radius);
    drawNumbers(ctx, radius);
    drawTime(ctx, radius);
    drawMajorticks(ctx,radius);
    drawMinorticks(ctx,radius);
}

Update :

I have been working on this , but need more help. It seems my server side app (app.py) is not "hiting" the web page index.html. I am saying this because when I do a page refresh, i do see my variable in the web page, just text. All my canvas is not shown. Actually deleted index.html and same result . This is the app.py, that basically receive two variables from serial and return those. My file structure is : webapp/ app.py templates/ index.html static/ jquery-1.11.3.min.js

code

app = Flask(__name__)

@app.route('/',methods=['GET'])
def index():


    while 1:

            global velocidad_total
            global direccion_total
            global i
            c=ser.readline()
            #aux2= str(c, 'utf-8') not needed for python 2
            aux2=str(c)
            aux = aux2.split(" ")
            direccion.append(int(aux[0]))
            velocidad.append(int(aux[1]))       
            ent_direc=aux[0]
            print (aux[0]," ",aux[1])
            return jsonify(ent_direc = ent_direc)

     if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')

on index.html

<!DOCTYPE html>
<html>
<body>

<canvas id="canvas" width="400" height="400" style="background-color:#ffffff"></canvas>
<script>
 var canvas = document.getElementById("canvas");
 var ctx = canvas.getContext("2d");
 var radius = canvas.height / 2;
 var ent_direc={{ent_direc}};   <===THIS IS THE VARIABLE I NEED TO UPDATE
 ctx.translate(radius, radius);
 radius = radius * 0.90;
 drawClock();

setInterval(update_values(), 1000);

function drawClock()
{
    drawFace(ctx, radius);
    drawNumbers(ctx, radius);
    drawTime(ctx, radius);  <== THAT IS USED HERE
    drawMajorticks(ctx,radius);
    drawMinorticks(ctx,radius);
}

This is the new function that I am adding to update the variable

function update_values() {
            $SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
            $.getJSON($SCRIPT_ROOT+"/",
                function(data) {
                   $(data.ent_direc)

                });
        }

And at the end of my file I added

</script>
<script type=text/javascript src="{{
  url_for('static', filename='jquery-1.11.3.min.js') }}"></script>

</body>
</html>

Finally I will need to add a function like setInterval () or similar to execute the update_values() function every second .

Any help really appreciated .Regards, martin

Upvotes: 1

Views: 6984

Answers (1)

jwg
jwg

Reputation: 5847

AJAX / JSON / JQUERY is by no means too much for your application, and are (the three words all relate to different concepts and tools) on the contrary a clean and minimal solution to exactly your problem.

First, let's consider some ways you could get the information to refresh in your page. There might be other way, these are just the ones which are obvious to me:

  1. You could refresh the whole page. This is very simple to code and you should be able to find a couple of lines of Javascript almost immediately on Google. However, it is slow and inefficient. If you want to update every second, it's probably almost impossible to do it this way, since you page will be constantly loading and re-rendering.

  2. You could send a message from the backend to the frontend for each update. This is quite a popular technology nowadays. For you it is almost certainly the overkill solution. You would need a Socket.io (or similar WebSockets library) module for Javascript and a matching module for Flask. You would have constraints on which webservers you can use for Flask. Proxying and so on would become much harder. All this might make sense if you want messages from the server to arrive at unpredictable times and to update immediately (for example a chat application, where each time someone types something the other clients see it immediately). If you want regular updates or updates as and when each client requests them, there is no advantage to this method.

  3. Let's call this, for the sake of argument AJAX. The browser Javascript, at various times, whether based on timing or client actions, makes a request to the backend for some piece of data. The backend sends back that information, not as a webpage, but as a text file in one of various formats (usually JSON), which the front-end Javascript can parse and use to update the page.

Now let's explain the terminology.

  • AJAX means (originally) 'Asyncronous JavaScript And XML'. Asynchronous means that the Javascript code makes requests, and updates the page when it gets the message back, rather than pausing and waiting. This is conceptually very important to how modern web apps work, but you don't need to worry too much about it. Javascript is Javascript, and XML was originally the format used for the information that the server got back. XML was more popular then, and the functionality for making individual data requests used a Javascript function called XMLHttpRequest. AJAX is often used loosely to mean any page which does live updating of information, such as your webmail, and all the related technologies.
  • JSON is a text based format for storing data including simple types such as integers and strings, and complex types such as arrays and objects. It stands for JavaScript Object Notation, and is based on the way you would declare variables in Javascript code. JSON has become much more popular than XML for sending data back and forth between browser and server, because it fits closely with data types in Javascript, and other languages such as Python. It is also easier to read, can be more compact and is less ambiguous regarding how it should be parsed into in-memory objects.
  • JQUERY is a very very widespread Javascript library. It's core strength is that it makes it much easier and more intuitive to update HTML pages in-place. Things like finding a given instance of a particular tag and changing its value based on the value of another instance of a different tag, are much more elegantly and simply expressed in JQuery than in plain old Javascript, where you will have lots of lines of opaque code with things like 'getElementsByTagName'. JQuery also has capabilities to manage things like sending a request for a data update to the server, and updating based on the response when it comes back. You don't have to use JQuery to do AJAX. But it will be a lot easier to do so, than to try and write all the code yourself to do the same thing. You might also want to look at other JS libraries such as BackBoneJS, which is designed to do exactly what you are interested in, and to make it very easy. You might be worried about adding complexity and steepening the learning curve by including this technology. But the well-known JS frameworks make JS MUCH more straightforward to use, and are very widely supported with good documentation. Professional web devs and designers invariably use these toolkits, not in order to be cool, but to make themselves much more productive.

Now, for you to change your web app to do live updates, you will have to make some changes. But in most cases you will find that these changes have a positive effect on your architecture, separately from the new functionality.

On the backend, you are going to want to take the variables which need to be updated, and add them to a different Flask endpoint. This will be a bit different from the ones that you are used to, in that it won't return a rendered template. Rather, you are going to just return a piece of text, possibly using jsonify() to create JSON from a Python dict or array.

This will actually make it easier to separate the concerns of your application. When you want to test the logic behind the data, you can just look at the JSON response from that endpoint. And when you want to test the template and the HTML, you can do that independently of the data.

Still on the Flask side, you might want to look at plugins such as Flask-Restless. These take data from your database (if you are using one in your app), and create endpoints which return JSON. This means you don't have to hard-code yourself which fields get returned for which database tables.

Another important thing is that you can make lots of different Flask endpoints, for different pieces of data, which all come together to make your page. This is the microservice approach. If you do this well, you make it much easier to understand your app when coding the frontend, and much easier to test, deploy and maintain your backend code (since you can now have handle backend code for different services separately).

On the frontend, you probably want to set things up so that:

  1. Your pages loads, without any data. This might just be simple HTML without need for Javascript, or it might involve JS, for things like logins or status bars.
  2. When the page has loaded, some JS code does a request to the 'data' Flask endpoint(s), and processes the responses. The info in the page now reflect
  3. Now, each time you want to update, you just do 2. again. So there is now no difference between the initial data load, and the updates.

I am not the right person to recommend a JS framework. There are lots and many of them have funny names such as AngularJS and BackBoneJS. I think Angular might be too much too soon, and BackBone might be just right to allow you to build something simple quickly. Some of these remove some of the need for JQuery, and some are complementary, or can be used either with or without. Perhaps you could post another question.

However, I can assure you that Flask is absolutely ideal for this kind of design, and there are loads of add-ons which should help you a lot.

Look into the 'Model-View-Controller' concept and related things such as 'Model-View-Presenter'. This is the 'philosophy' behind what you want to do. Find out as much as you can about JQuery and other JS libraries, and look up JSON, and REST APIs. Lots of people are doing things like this with Python and Flask/Django/Pyramid etc., (which might be why there are so many backend frameworks too) so you should be able to find good examples and docs, including complete working apps.

Upvotes: 9

Related Questions