Reputation: 33
Im trying to get a sensor value from Flask to auto update in a javascript gauge. The sensor input is named "a1" in Flask python. I got it to work in a regular html code like this:
<div id="main">
<h4>Sensor 1: <span class="bold white">{{a1}}</span> bar </h4>
and to auto update it every second with this:
$(document).ready(function(){
setInterval(function(){
$("#main").load(window.location.href + " #main" );
}, 1000);
});
and the value even shows up in the js gauge:
<div id="PT1" class="gauge-container pt">
<span class="label">Pressure Transmitter 1</span>
<span class="label2">0 - 400 bar</span>
</div>
JS:
var PT1 = Gauge(
document.getElementById("PT1"), {
max: 400,
dialStartAngle: 135,
dialEndAngle: 45,
label: function(value) {
return Math.round(value * 100) / 100;
}
}
);
(function loop() {
var value1 = {{a1}}
PT1.setValueAnimated(value1, 1);
setTimeout(loop, 1000);
})();
My problem is that the gauge value dont auto update, it only shows the correct value when I refresh the page, and stays unchanged until I refresh again. (while the html code keeps updating every second)
Is this possible to solve?
Thanks
Vincent
Upvotes: 1
Views: 1567
Reputation: 33
Here's my final working example code.
Python:
from flask import Flask,render_template, jsonify
from random import random
app = Flask(__name__)
@app.route('/read_sensor')
def read_sensor():
data = {'a1': (random()*150)}
return jsonify(data)
@app.route('/')
def index():
return render_template("index.html")
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80, debug=True)
HTML
<body>
<div id="PT1" class="gauge-container">
<span class="label">DEFAULT</span>
</div>
</div>
<script type='text/javascript'>
var PT1 = new Gauge(
document.getElementById("PT1"), {
max: 400,
dialStartAngle: 135,
dialEndAngle: 45,
label: function(value) {
return Math.round(value * 100) / 100;
}
}
);
function callme(){
//This promise will resolve when the network call succeeds
//Feel free to make a REST fetch using promises and assign it to networkPromise
var networkPromise = fetch('/read_sensor')
.then(response => response.json())
.then(data => {
console.log(data);
PT1.setValueAnimated(data['a1'], 1);
});;
//This promise will resolve when 2 seconds have passed
var timeOutPromise = new Promise(function(resolve, reject) {
// 2 Second delay
setTimeout(resolve, 2000, 'Timeout Done');
});
Promise.all(
[networkPromise, timeOutPromise]).then(function(values) {
console.log("Atleast 2 secs + TTL (Network/server)");
//Repeat
callme();
});
}
callme();
</script>
</body>
Thanks!
Upvotes: 2
Reputation: 7621
You need to write some Javascript to query the endpoint periodically. I used the approach in this answer which makes a request every two seconds, without making a second call when a request is under way.
You'll need to build a Flask route which returns only JSON with the sensor data. I mocked this with random numbers:
import random
@app.route('/read_sensor')
def read_sensor():
# return the actual sensor data here:
return {'a1': random.choice(range(1,400))}
Then use the following JS which makes a request every 2000ms. I had to tweak your example slightly, changing the div to a canvas to get guage.js
to work properly:
<html>
<body>
<div class="chart">
<canvas id="PT1"></canvas>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gauge.js/1.3.7/gauge.min.js" integrity="sha512-J0d1VfdfTSDoDPEsahCtf2nC+groXdWkuQFyJjS+s3CpKj63X9Hf3pMEJtjIJt/ODh0QwTRx2/OioL+9fMoqSA==" crossorigin="anonymous"></script>
<script type='text/javascript'>
//
// Guage init code
//
var PT1 = new Gauge(
document.getElementById("PT1"), {
max: 400,
dialStartAngle: 135,
dialEndAngle: 45,
label: function(value) {
return Math.round(value * 100) / 100;
}
}
);
//
// End guage init code
//
function callme(){
//This promise will resolve when the network call succeeds
//Feel free to make a REST fetch using promises and assign it to networkPromise
var networkPromise = fetch('/read_sensor')
.then(response => response.json())
.then(data => {
console.log(data);
//
// Set guage code
//
PT1.set(data['a1']);
//
// End set guage code
//
});;
//This promise will resolve when 2 seconds have passed
var timeOutPromise = new Promise(function(resolve, reject) {
// 2 Second delay
setTimeout(resolve, 2000, 'Timeout Done');
});
Promise.all(
[networkPromise, timeOutPromise]).then(function(values) {
console.log("Atleast 2 secs + TTL (Network/server)");
//Repeat
callme();
});
}
callme();
</script>
</body>
</html>
Here's what this renders like:
Upvotes: 0
Reputation: 33
Thanks for your reply and example. I just cant get your example to work with my gauge... Can you please show an example of the rest of the flask route? Like the part with "return / render html"
Here is a simplified copy of my old Flask: (that works, but not updating)
@app.route('/')
def index():
a1 = sensors()
return render_template("index.html", a1=a1)
def sensors():
a1 = "%0.2f" % (287.8 + random())
return a1
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80, debug=True)
Isnt there an easy way to just get the "a1" to be updated inside the JS for the gauge?
(function loop() {
var value1 = {{a1}}
PT1.setValueAnimated(value1, 1);
setTimeout(loop, 1000);
})();
If I replace {{a1}} with "Math.random() * 100," then its updating every second.
Full example of the gauges here: https://codepen.io/ernestoulloa/pen/abmGYyY (I am using gauge1)
Upvotes: 0