update plot interface with point number selection and pause

master
Nicolò Balzarotti 2023-02-21 19:23:12 +01:00
parent c180ce9ea6
commit a81d2cc6a1
6 changed files with 54 additions and 20 deletions

5
app.py
View File

@ -87,7 +87,10 @@ def recipe():
@socketio.on('new client') @socketio.on('new client')
def handle_new_client(): def handle_new_client():
updateState() updateState()
socketio.emit('sensor history', sensors.get_history())
@socketio.on('get sensors history')
def send_sensors_history(elements=1000):
socketio.emit('sensor history', sensors.get_history(elements))
@socketio.on('manual response') @socketio.on('manual response')
def handle_manual_response(response): def handle_manual_response(response):

37
dist/server.js vendored
View File

@ -63,6 +63,26 @@ function applyState(newstate) {
var enable_draw = true; var enable_draw = true;
var plot_data = {}; var plot_data = {};
function toggle_update_plot() {
enable_draw = !enable_draw;
}
function pause_plotting() {enable_draw = false;}
function resume_plotting() {enable_draw = true;}
function set_plot_points(value) {
let current = localstate.maxpoints;
if (value === undefined) {
value = parseInt(document.getElementById('point-number').value);
}
localstate.maxpoints = value;
if (value <= current) {
// we alredy have all the points we want just set it and let other
// function discard extra points
return;
}
// Ask for more data
socket.emit('get sensors history', value);
}
function add_plot_data(newpoints, render=true) { function add_plot_data(newpoints, render=true) {
for (var i = 0; i < newpoints.length; ++i) { for (var i = 0; i < newpoints.length; ++i) {
let point = newpoints[i] let point = newpoints[i]
@ -77,6 +97,8 @@ function add_plot_data(newpoints, render=true) {
} }
plot_data[key].x.push(point[1]); plot_data[key].x.push(point[1]);
plot_data[key].y.push(point[2]); plot_data[key].y.push(point[2]);
// This is different since we want maxpoints to be the absolute max, not
// for each variable, but good enough for now (or the opposite?)
while (plot_data[key].x.length > localstate.maxpoints) { while (plot_data[key].x.length > localstate.maxpoints) {
plot_data[key].x.shift(); plot_data[key].x.shift();
plot_data[key].y.shift(); plot_data[key].y.shift();
@ -85,28 +107,19 @@ function add_plot_data(newpoints, render=true) {
if (render) render_plot(); if (render) render_plot();
} }
// function set_plot_points(maxpoints) {
// let more = localstate.maxpoints > maxpoints;
// localstate.maxpoints = maxpoints;
// if (more) {
// for (key in plot_data.keys())
// }
// }
function render_plot() { function render_plot() {
if (enable_draw && document.getElementById("data-plot") !== null) { if (enable_draw && document.getElementById("data-plot") !== null) {
Plotly.newPlot('data-plot', Object.values(plot_data)); Plotly.newPlot('data-plot', Object.values(plot_data));
} }
} }
function render_actuators(data) { function render_actuators(data) {
let html = document.getElementById("actuator-list"); let html = document.getElementById("actuator-list");
if (data === undefined || html === null) return; if (data === undefined || html === null) return;
let template = `<div class="content"> let template = `<div class="content">
Total Consumption: {{total}}W<br> Total Consumption: {{total}}Wh<br>
{{#consumption}} {{#consumption}}
{{name}}: {{W}}W</br> {{name}}: {{Wh}}Wh</br>
{{/consumption}} {{/consumption}}
</div>`; </div>`;
let total = 0; let total = 0;
@ -114,7 +127,7 @@ function render_actuators(data) {
for (var key in data.consumption){ for (var key in data.consumption){
let val = data.consumption[key]; let val = data.consumption[key];
total += val; total += val;
out.push({name: key, W: val.toFixed(2)}); out.push({name: key, Wh: val.toFixed(2)});
} }
html.innerHTML = Mustache.render(template, { total: total.toFixed(2), html.innerHTML = Mustache.render(template, { total: total.toFixed(2),

View File

@ -1,6 +1,7 @@
from time import perf_counter from time import perf_counter
from datetime import datetime, timedelta from datetime import datetime, timedelta
from collections import deque from collections import deque
from itertools import islice
import re import re
from os.path import exists from os.path import exists
@ -178,8 +179,9 @@ class Sensors():
def get(self): def get(self):
return self.value_tuple() return self.value_tuple()
def get_history(self): def get_history(self, n=None):
return tuple(self.history) l = len(self.history)
return tuple(islice(self.history, max(0, l - n), l))
sensors = Sensors() sensors = Sensors()

View File

@ -26,11 +26,16 @@
render_sensors(data); render_sensors(data);
}); });
socket.on("sensor history", (...data) => { socket.on("sensor history", (...data) => {
// first clear everything
plot_data = {};
// then add new data
enable_draw = false; enable_draw = false;
data.forEach(add_plot_data); data.forEach(add_plot_data);
enable_draw = true; enable_draw = true;
render_plot(); render_plot();
}); });
// sane default?
socket.emit('get sensors history', 200);
}); });
} }
window.onload = setup; window.onload = setup;

View File

@ -36,8 +36,19 @@
</p> </p>
</header> </header>
<div class="card-content"> <div class="card-content">
<div class="content"> <div class="content">
<div id="data-plot"></div> <div class="field has-addons">
<button class="button is-link" onclick="toggle_update_plot()">Pause/Unpause Plot</button>
<div class="control">
<input class="input" type="number"/ value="1000" id="point-number" />
</div>
<div class="control">
<a class="button is-info" onclick="set_plot_points()">
Update #of points
</a>
</div>
</div>
<div id="data-plot"></div>
<br/> <br/>
</div> </div>
</div> </div>

View File

@ -9,8 +9,8 @@ def consumption_diff(before, after):
def consumption_to_string(dic): def consumption_to_string(dic):
out = '' out = ''
for key in dic: for key in dic:
out += '{0:s}:\t{1:.2f}W\n'.format(key, dic[key]) out += '{0:s}:\t{1:.2f}Wh\n'.format(key, dic[key])
out += 'Total:\t{0:.2f}W'.format(sum(dic.values())) out += 'Total:\t{0:.2f}Wh'.format(sum(dic.values()))
return out return out
def stohms(s): def stohms(s):