Add web visualizer based on python+plotly
This commit is contained in:
parent
31da2af078
commit
c7a4eb16bf
3
visualizer/.gitignore
vendored
Normal file
3
visualizer/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
config.py
|
||||
__pycache__/
|
||||
env/
|
62
visualizer/main.py
Executable file
62
visualizer/main.py
Executable file
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from bottle import Bottle, request, response, template, static_file
|
||||
import serial
|
||||
import json
|
||||
import time
|
||||
|
||||
app = application = Bottle()
|
||||
|
||||
serial_in_use = False
|
||||
|
||||
@app.route('/')
|
||||
@app.route('/index.html')
|
||||
def index():
|
||||
return template('index')
|
||||
|
||||
@app.route('/websocket')
|
||||
def handle_websocket():
|
||||
global serial_in_use
|
||||
|
||||
wsock = request.environ.get('wsgi.websocket')
|
||||
if not wsock:
|
||||
abort(400, 'Expected WebSocket request.')
|
||||
|
||||
if serial_in_use:
|
||||
abort(503, 'Serial connection already in use.')
|
||||
|
||||
with serial.Serial('/dev/ttyUSB0', 38400, timeout=10) as ser:
|
||||
#with open('/dev/null') as ser:
|
||||
serial_in_use = True
|
||||
print("Serial locked.")
|
||||
while True:
|
||||
try:
|
||||
line = ser.readline()
|
||||
#line = '{"vin": 1240, "vout": 15300, "iout": 817, "pout": 12345, "energy": 9387, "pwm": 314}\r\n'
|
||||
time.sleep(1)
|
||||
if line[0] != '{':
|
||||
# print all lines that are probably not JSON
|
||||
print(line)
|
||||
continue
|
||||
|
||||
data = json.loads(line)
|
||||
wsock.send(json.dumps(data))
|
||||
except json.JSONDecodeError:
|
||||
print(f"Failed to decode line as JSON: »{line}«.")
|
||||
except WebSocketError:
|
||||
break
|
||||
serial_in_use = False
|
||||
print("Serial unlocked.")
|
||||
|
||||
|
||||
@app.route('/static/<filename:path>')
|
||||
def send_static(filename):
|
||||
return static_file(filename, root='./static')
|
||||
|
||||
if __name__ == "__main__":
|
||||
from gevent.pywsgi import WSGIServer
|
||||
from geventwebsocket import WebSocketError
|
||||
from geventwebsocket.handler import WebSocketHandler
|
||||
server = WSGIServer(("0.0.0.0", 8080), app,
|
||||
handler_class=WebSocketHandler)
|
||||
server.serve_forever()
|
4
visualizer/requirements.txt
Normal file
4
visualizer/requirements.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
bottle ~= 0.12.25
|
||||
gevent ~= 24.2.1
|
||||
gevent-websocket ~= 0.10.0
|
||||
pyserial ~= 3.5
|
8
visualizer/static/plotly-2.29.1.min.js
vendored
Normal file
8
visualizer/static/plotly-2.29.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
8
visualizer/static/style.css
Normal file
8
visualizer/static/style.css
Normal file
|
@ -0,0 +1,8 @@
|
|||
body {
|
||||
color: black;
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
div.plot {
|
||||
display: inline-block;
|
||||
}
|
173
visualizer/views/index.tpl
Normal file
173
visualizer/views/index.tpl
Normal file
|
@ -0,0 +1,173 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<script type="text/javascript" src="/static/plotly-2.29.1.min.js" charset="utf-8"></script>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="row">
|
||||
<div class="plot" id="plotly_pout"></div>
|
||||
<div class="plot" id="plotly_energy"></div>
|
||||
<div class="plot" id="plotly_pwm"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="plot" id="plotly_vin"></div>
|
||||
<div class="plot" id="plotly_vout"></div>
|
||||
<div class="plot" id="plotly_iout"></div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
/*********************************
|
||||
* Plot setup *
|
||||
*********************************/
|
||||
|
||||
var plot_w = 400;
|
||||
var plot_h = 300;
|
||||
|
||||
// vin plot
|
||||
var plot_data = [
|
||||
{
|
||||
domain: { x: [0, 1], y: [0, 1] },
|
||||
value: 6.2,
|
||||
number: {"suffix": "V"},
|
||||
title: { text: "Eingangsspannung" },
|
||||
type: "indicator",
|
||||
mode: "gauge+number",
|
||||
gauge: {
|
||||
axis: { range: [0, 10] },
|
||||
bar: { color: "blue" }
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
var layout = { width: plot_w, height: plot_h, margin: { t: 0, b: 0 } };
|
||||
Plotly.newPlot('plotly_vin', plot_data, layout);
|
||||
|
||||
var plot_data = [
|
||||
{
|
||||
domain: { x: [0, 1], y: [0, 1] },
|
||||
value: 10,
|
||||
number: {"suffix": "V"},
|
||||
title: { text: "Ausgangsspannung" },
|
||||
type: "indicator",
|
||||
mode: "gauge+number",
|
||||
gauge: {
|
||||
axis: { range: [0, 20] },
|
||||
bar: { color: "yellow" },
|
||||
threshold: {
|
||||
line: { color: "green", width: 4 },
|
||||
thickness: 0.75,
|
||||
value: 12.0
|
||||
},
|
||||
steps: [
|
||||
{ range: [0, 16], color: "white" },
|
||||
{ range: [16, 20], color: "#ff8080" }
|
||||
],
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
var layout = { width: plot_w, height: plot_h, margin: { t: 0, b: 0 } };
|
||||
Plotly.newPlot('plotly_vout', plot_data, layout);
|
||||
|
||||
var plot_data = [
|
||||
{
|
||||
domain: { x: [0, 1], y: [0, 1] },
|
||||
value: 5,
|
||||
number: {"suffix": "W"},
|
||||
title: { text: "Leistung" },
|
||||
type: "indicator",
|
||||
mode: "gauge+number",
|
||||
gauge: {
|
||||
axis: { range: [0, 30] },
|
||||
bar: { color: "orange" },
|
||||
steps: [
|
||||
{ range: [0, 20], color: "white" },
|
||||
{ range: [20, 30], color: "#ff8080" }
|
||||
],
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
var layout = { width: plot_w, height: plot_h, margin: { t: 0, b: 0 } };
|
||||
Plotly.newPlot('plotly_pout', plot_data, layout);
|
||||
|
||||
var plot_data = [
|
||||
{
|
||||
domain: { x: [0, 1], y: [0, 1] },
|
||||
value: 0.7,
|
||||
number: {"suffix": "A"},
|
||||
title: { text: "Ausgangsstrom" },
|
||||
type: "indicator",
|
||||
mode: "gauge+number",
|
||||
gauge: {
|
||||
axis: { range: [0, 2] },
|
||||
bar: { color: "blue" }
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
var layout = { width: plot_w, height: plot_h, margin: { t: 0, b: 0 } };
|
||||
Plotly.newPlot('plotly_iout', plot_data, layout);
|
||||
|
||||
var plot_data = [
|
||||
{
|
||||
domain: { x: [0, 1], y: [0, 1] },
|
||||
value: 0.7,
|
||||
number: {"suffix": "J"},
|
||||
title: { text: "Energie" },
|
||||
type: "indicator",
|
||||
mode: "number"
|
||||
}
|
||||
];
|
||||
|
||||
var layout = { width: plot_w, height: plot_h, margin: { t: 0, b: 0 } };
|
||||
Plotly.newPlot('plotly_energy', plot_data, layout);
|
||||
|
||||
var plot_data = [
|
||||
{
|
||||
domain: { x: [0, 1], y: [0, 1] },
|
||||
value: 321,
|
||||
title: { text: "PWM" },
|
||||
type: "indicator",
|
||||
mode: "gauge+number",
|
||||
gauge: {
|
||||
axis: { range: [0, 486] },
|
||||
bar: { color: "black" }
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
var layout = { width: plot_w, height: plot_h, margin: { t: 0, b: 0 } };
|
||||
Plotly.newPlot('plotly_pwm', plot_data, layout);
|
||||
|
||||
/*********************************
|
||||
* Websocket handling *
|
||||
*********************************/
|
||||
|
||||
var ws = new WebSocket("ws://localhost:8080/websocket");
|
||||
ws.onopen = function() {
|
||||
console.log("Websocket connected.");
|
||||
};
|
||||
ws.onmessage = function (evt) {
|
||||
data = JSON.parse(evt.data);
|
||||
|
||||
if(data) {
|
||||
console.log("Data received:");
|
||||
console.log(data);
|
||||
|
||||
Plotly.restyle('plotly_vin', 'value', [data.vin / 1e3]); // millivolt
|
||||
Plotly.restyle('plotly_vout', 'value', [data.vout / 1e3]); // millivolt
|
||||
Plotly.restyle('plotly_pout', 'value', [data.pout / 1e6]); // microwatt
|
||||
Plotly.restyle('plotly_iout', 'value', [data.iout / 1000.0]); // milliampere
|
||||
Plotly.restyle('plotly_energy', 'value', [data.energy]); // Joule
|
||||
Plotly.restyle('plotly_pwm', 'value', [data.pwm]); // counter
|
||||
} else {
|
||||
console.log("Received data, but no valid JSON:");
|
||||
console.log(evt.data);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue