Reputation: 147
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
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:
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.
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.
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.
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.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:
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