mirror of
https://github.com/CopterExpress/clever-show.git
synced 2026-05-26 23:19:33 +00:00
Added more buttons from Qt GUI
This commit is contained in:
28
Server/app_routes/file_sender.py
Normal file
28
Server/app_routes/file_sender.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from flask import Blueprint, request, jsonify
|
||||
from web_server_models import copters
|
||||
|
||||
file_sender_api = Blueprint('file_sender_api', __name__, template_folder='templates')
|
||||
|
||||
|
||||
@file_sender_api.route('/set/animation', methods=['GET', 'POST'])
|
||||
def set_animation():
|
||||
if request.method == 'POST':
|
||||
f = request.files['file']
|
||||
print(f, 'ip', request.args.get('ip'))
|
||||
return jsonify({'m': 'ok'})
|
||||
|
||||
|
||||
@file_sender_api.route('/set/config', methods=['GET', 'POST'])
|
||||
def set_config():
|
||||
if request.method == 'POST':
|
||||
f = request.files['file']
|
||||
print(f, 'ip', request.args.get('ip'))
|
||||
return jsonify({'m': 'ok'})
|
||||
|
||||
|
||||
@file_sender_api.route('/set/aruco', methods=['GET', 'POST'])
|
||||
def set_aruco():
|
||||
if request.method == 'POST':
|
||||
f = request.files['file']
|
||||
print(f, 'ip', request.args.get('ip'))
|
||||
return jsonify({'m': 'ok'})
|
||||
15
Server/app_routes/misc.py
Normal file
15
Server/app_routes/misc.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from flask import Blueprint, request, jsonify
|
||||
from web_server_models import delay, set_delay_manually, get_delay_manually
|
||||
|
||||
misc_api = Blueprint('misc_api', __name__, template_folder='templates')
|
||||
|
||||
|
||||
@misc_api.route('/set/delay', methods=['GET', 'POST'])
|
||||
def set_delay():
|
||||
set_delay_manually(int(request.args.get('delay')))
|
||||
return jsonify({'m': 'ok'})
|
||||
|
||||
|
||||
@misc_api.route('/get/delay', methods=['GET', 'POST'])
|
||||
def get_delay():
|
||||
return jsonify(get_delay_manually())
|
||||
69
Server/app_routes/selfcheck.py
Normal file
69
Server/app_routes/selfcheck.py
Normal file
@@ -0,0 +1,69 @@
|
||||
from flask import Blueprint, request, jsonify
|
||||
from web_server_models import copters, WebCopter
|
||||
from server import Client
|
||||
|
||||
selfcheck_api = Blueprint('selfcheck_api', __name__, template_folder='templates')
|
||||
|
||||
|
||||
@selfcheck_api.route('/selfcheck/selected', methods=["GET", "POST"])
|
||||
def selfcheck_selected():
|
||||
data = dict()
|
||||
ip = request.args.get("ip")
|
||||
for copter in copters:
|
||||
if copter.ip == ip:
|
||||
copter.refresh()
|
||||
data = {
|
||||
'anim_id': copter.anim_id,
|
||||
'batt_voltage': copter.batt_voltage,
|
||||
'cell_voltage': copter.cell_voltage,
|
||||
'selfcheck': copter.selfcheck,
|
||||
'time': copter.time,
|
||||
'name': copter.name,
|
||||
}
|
||||
# data = {"anim_id": "No animation", "batt_voltage": 3.259999990463257, "cell_voltage": 1.0850000381469727,
|
||||
# "ip": "192.168.43.31", "name": "CLever7", "selfcheck": "OK", "time": 1554723269.57106}
|
||||
return jsonify(data)
|
||||
|
||||
|
||||
@selfcheck_api.route('/selfcheck/all', methods=["GET", "POST"])
|
||||
def selfcheck_all():
|
||||
data = []
|
||||
for copter in copters:
|
||||
copter.refresh()
|
||||
data.append({
|
||||
'anim_id': copter.anim_id,
|
||||
'batt_voltage': copter.batt_voltage,
|
||||
'cell_voltage': copter.cell_voltage,
|
||||
'selfcheck': copter.selfcheck,
|
||||
'ip': copter.ip,
|
||||
'time': copter.time,
|
||||
'name': copter.name,
|
||||
})
|
||||
# data = [{"anim_id": "No animation", "batt_voltage": 4.259999990463257, "cell_voltage": 4.0850000381469727,
|
||||
# "ip": "192.168.43.31", "name": "CLever7", "selfcheck": "OK", "time": 4554723269.57106}]
|
||||
# data *= 12
|
||||
return jsonify(data)
|
||||
|
||||
|
||||
@selfcheck_api.route('/refresh_copters')
|
||||
def refresh_copters():
|
||||
try:
|
||||
for client_ip in Client.clients.keys():
|
||||
is_in = False
|
||||
for copter in copters:
|
||||
if client_ip == copter.ip:
|
||||
is_in = True
|
||||
if not is_in:
|
||||
copters.append(WebCopter(client_ip, Client.clients[client_ip]))
|
||||
return jsonify({'m': 'Ok'})
|
||||
except:
|
||||
return jsonify({'m': 'Error'})
|
||||
|
||||
|
||||
@selfcheck_api.route('/test_led/selected', methods=['GET', 'POST'])
|
||||
def test_led_selected():
|
||||
ip = request.args.get("ip")
|
||||
for copter in copters:
|
||||
if copter.ip == ip:
|
||||
copter.client.send_message("led_test")
|
||||
return jsonify({'m': 'ok'})
|
||||
@@ -48,4 +48,8 @@ html {
|
||||
|
||||
.btn-group button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dropdown-menu div {
|
||||
width: 200px;
|
||||
}
|
||||
224
Server/static/css/ply.css
Normal file
224
Server/static/css/ply.css
Normal file
@@ -0,0 +1,224 @@
|
||||
/* Global loading */
|
||||
.ply-global-loading {
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
padding: 30px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin: -100px 0 0 -60px;
|
||||
z-index: 100000;
|
||||
position: fixed;
|
||||
border-radius: 10%;
|
||||
background-color: rgba(255,255,255,.5);
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,.2);
|
||||
}
|
||||
|
||||
.ply-loading-spinner {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: .9;
|
||||
background: #fff;
|
||||
border-radius: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,.6);
|
||||
}
|
||||
|
||||
.ply-loading-spinner::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: #333;
|
||||
max-height: 0;
|
||||
-webkit-animation: loading 3s normal infinite;
|
||||
animation: loading 3s normal infinite;
|
||||
}
|
||||
|
||||
@keyframes loading {
|
||||
0% { max-height: 0; }
|
||||
50% { max-height: 100%; top: 0; }
|
||||
100% { max-height: 0; top: 120%; }
|
||||
}
|
||||
|
||||
@-webkit-keyframes loading {
|
||||
0% { max-height: 0; }
|
||||
50% { max-height: 100%; top: 0; }
|
||||
100% { max-height: 0; top: 120%; }
|
||||
}
|
||||
|
||||
|
||||
/* Layer */
|
||||
.ply-layer {
|
||||
color: #333;
|
||||
min-width: 280px;
|
||||
box-shadow: 0 0 3px rgba(0,0,0,.3);
|
||||
background-color: #fff;
|
||||
border-radius: 20px;
|
||||
font-size: 16px;
|
||||
font-family: "Arial", Helvetica;
|
||||
}
|
||||
.ply-layer.alert .ply-content,
|
||||
.ply-layer.confirm .ply-content {
|
||||
padding: 20px 0 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ply-layer.base .ply-footer,
|
||||
.ply-layer.alert .ply-footer,
|
||||
.ply-layer.confirm .ply-footer,
|
||||
.ply-layer.prompt .ply-footer {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ply-inside {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.ply-header {
|
||||
margin: -20px -20px 20px;
|
||||
padding: 10px 20px;
|
||||
font-size: 18px;
|
||||
background-color: #f1f1f1;
|
||||
border-radius: 2px 2px 0 0;
|
||||
}
|
||||
|
||||
.ply-content {
|
||||
}
|
||||
|
||||
.ply-footer {
|
||||
}
|
||||
.ply-footer .ply-ctrl {
|
||||
margin-left: 20px;
|
||||
}
|
||||
.ply-footer .ply-ctrl:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
|
||||
/* Controls */
|
||||
.ply-x {
|
||||
top: 12px;
|
||||
right: 5px;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
z-index: 1000;
|
||||
position: absolute;
|
||||
font-size: 20px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.ply-ok,
|
||||
.ply-cancel {
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
padding: 5px 20px;
|
||||
box-shadow: 0 1px 1px rgba(0,0,0,.2);
|
||||
background-color: #39C082;
|
||||
border-radius: 3px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.ply-ok {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.ply-cancel {
|
||||
background-color: #b2b2b2;
|
||||
}
|
||||
.ply-ok:focus,
|
||||
.ply-cancel:focus {
|
||||
box-shadow: 0 0 1px 2px rgba(255, 180, 0, .6);
|
||||
border: 2px solid rgb(255, 210, 102)\9;
|
||||
}
|
||||
|
||||
.ply-ok::-moz-focus-inner,
|
||||
.ply-cancel::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Forms */
|
||||
.ply-input {
|
||||
width: 100%;
|
||||
border: 2px solid #ccc;
|
||||
outline: 0;
|
||||
padding: 5px 10px;
|
||||
margin-top: 15px;
|
||||
font-size: 16px;
|
||||
font-family: "Arial", Helvetica;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ply-input:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.ply-input:focus {
|
||||
border-color: #39C082;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Global modifiers */
|
||||
.ply-invalid .ply-input {
|
||||
border-color: #c00;
|
||||
}
|
||||
|
||||
.ply-loading:before {
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: block;
|
||||
content: '';
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.ply-loading .ply-ok {
|
||||
color: rgba(255,255,255,.7);
|
||||
-webkit-animation: ply-ok-loading 1s linear infinite;
|
||||
-moz-animation: ply-ok-loading 1s linear infinite;
|
||||
animation: ply-ok-loading 1s linear infinite;
|
||||
-webkit-background-size: 30px 30px;
|
||||
-moz-background-size: 30px 30px;
|
||||
background-size: 30px 30px;
|
||||
background-image: -webkit-gradient(linear, left top, right bottom,
|
||||
color-stop(.25, rgba(255, 255, 255, .15)), color-stop(.25, transparent),
|
||||
color-stop(.5, transparent), color-stop(.5, rgba(255, 255, 255, .15)),
|
||||
color-stop(.75, rgba(255, 255, 255, .15)), color-stop(.75, transparent),
|
||||
to(transparent));
|
||||
background-image: -webkit-linear-gradient(135deg, rgba(255, 255, 255, .15) 25%, transparent 25%,
|
||||
transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%,
|
||||
transparent 75%, transparent);
|
||||
background-image: -moz-linear-gradient(135deg, rgba(255, 255, 255, .15) 25%, transparent 25%,
|
||||
transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%,
|
||||
transparent 75%, transparent);
|
||||
background-image: -ms-linear-gradient(135deg, rgba(255, 255, 255, .15) 25%, transparent 25%,
|
||||
transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%,
|
||||
transparent 75%, transparent);
|
||||
background-image: -o-linear-gradient(135deg, rgba(255, 255, 255, .15) 25%, transparent 25%,
|
||||
transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%,
|
||||
transparent 75%, transparent);
|
||||
background-image: linear-gradient(135deg, rgba(255, 255, 255, .15) 25%, transparent 25%,
|
||||
transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%,
|
||||
transparent 75%, transparent);
|
||||
}
|
||||
|
||||
@-webkit-keyframes ply-ok-loading {
|
||||
to { background-position: 60px; }
|
||||
}
|
||||
|
||||
@-moz-keyframes ply-ok-loading {
|
||||
to { background-position: 60px; }
|
||||
}
|
||||
|
||||
@keyframes ply-ok-loading {
|
||||
to { background-position: 60px; }
|
||||
}
|
||||
7
Server/static/js/bootstrap.min.js
vendored
Normal file
7
Server/static/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -3,42 +3,25 @@ let configInput = document.getElementById('configFile');
|
||||
let arucoInput = document.getElementById('arucoFile');
|
||||
|
||||
animationInput.onchange = function (e) {
|
||||
document.getElementById('animationFileLabel').innerText = animationInput.files[0].name;
|
||||
sendRows(table.getSelectedRows(), animationInput.files[0], 'animation');
|
||||
};
|
||||
configInput.onchange = function (e) {
|
||||
document.getElementById('configFileLabel').innerText = configInput.files[0].name;
|
||||
sendRows(table.getSelectedRows(), configInput.files[0], 'config');
|
||||
};
|
||||
arucoInput.onchange = function (e) {
|
||||
document.getElementById('arucoFileLabel').innerText = arucoInput.files[0].name;
|
||||
sendRows(table.getSelectedRows(), arucoInput.files[0], 'aruco');
|
||||
};
|
||||
|
||||
function sendRows(selectedRows) {
|
||||
var animationFile = animationInput.files[0];
|
||||
var configFile = configInput.files[0];
|
||||
var arucoFile = arucoInput.files[0];
|
||||
function sendRows(selectedRows, file, file_type) {
|
||||
spinner.style.display = 'inline-block';
|
||||
setTimeout(function () {
|
||||
selectedRows.forEach(function (element) {
|
||||
if (animationFile) {
|
||||
let animReq = new XMLHttpRequest();
|
||||
let animFormData = new FormData();
|
||||
animFormData.append("file", animationFile);
|
||||
animReq.open("POST", '/set/animation?ip=' + element._row.data.ip, false);
|
||||
animReq.send(animFormData);
|
||||
}
|
||||
if (configFile) {
|
||||
let configReq = new XMLHttpRequest();
|
||||
let congifFormData = new FormData();
|
||||
congifFormData.append("file", configFile);
|
||||
configReq.open("POST", '/set/config?ip=' + element._row.data.ip, false);
|
||||
configReq.send(congifFormData);
|
||||
}
|
||||
if (arucoFile) {
|
||||
let arucoReq = new XMLHttpRequest();
|
||||
let arucoFormData = new FormData();
|
||||
arucoFormData.append("file", arucoFile);
|
||||
arucoReq.open("POST", '/set/animation?ip=' + element._row.data.ip, false);
|
||||
arucoReq.send(arucoFormData);
|
||||
if (file) {
|
||||
let fileReq = new XMLHttpRequest();
|
||||
let fileFormData = new FormData();
|
||||
fileFormData.append("file", file);
|
||||
fileReq.open("POST", '/set/' + file_type + '?ip=' + element._row.data.ip, false);
|
||||
fileReq.send(fileFormData);
|
||||
}
|
||||
element.deselect();
|
||||
});
|
||||
|
||||
4
Server/static/js/jquery.min.js
vendored
Normal file
4
Server/static/js/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -1,6 +1,22 @@
|
||||
let spinner = document.getElementById('spinner');
|
||||
var tabledata = [];
|
||||
var delay = 0;
|
||||
updateData();
|
||||
updateDelay();
|
||||
|
||||
function updateDelay() {
|
||||
let req = new XMLHttpRequest();
|
||||
req.open('POST', '/get/delay', false);
|
||||
req.send();
|
||||
delay = parseInt(req.response);
|
||||
document.getElementById('delay').innerText = 'Set time (now is ' + delay.toString() + ')';
|
||||
}
|
||||
|
||||
function setDelay(delay) {
|
||||
let req = new XMLHttpRequest();
|
||||
req.open('POST', '/set/delay?delay=' + delay.toString(), false);
|
||||
req.send();
|
||||
}
|
||||
|
||||
function updateData() {
|
||||
let req = new XMLHttpRequest();
|
||||
@@ -16,12 +32,11 @@ var table = new Tabulator("#copters-table", {
|
||||
layout: "fitColumns",
|
||||
columns: [
|
||||
{title: "Name", field: "name"},
|
||||
{title: "IP", field: "ip"},
|
||||
{title: "Animation id", field: "anim_id"},
|
||||
{title: "Batt voltage", field: "batt_voltage"},
|
||||
{title: "Cell voltage", field: "cell_voltage"},
|
||||
{title: "Selfcheck", field: "selfcheck"},
|
||||
{title: "Time", field: "time"},
|
||||
{title: "Time delta", field: "time"},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -48,4 +63,56 @@ function refreshSelected() {
|
||||
|
||||
function refreshAll() {
|
||||
refreshRows(table.getRows());
|
||||
}
|
||||
|
||||
function selectAll() {
|
||||
table.getRows().forEach(function (element) {
|
||||
element.select();
|
||||
});
|
||||
}
|
||||
|
||||
function deselectAll() {
|
||||
table.getRows().forEach(function (element) {
|
||||
element.deselect();
|
||||
});
|
||||
}
|
||||
|
||||
function testLedSelected() {
|
||||
spinner.style.display = 'inline-block';
|
||||
setTimeout(function () {
|
||||
table.getSelectedRows().forEach(function (element) {
|
||||
let req = new XMLHttpRequest();
|
||||
req.open('POST', '/test_led/selected?ip=' + element._row.data.ip);
|
||||
req.send();
|
||||
});
|
||||
deselectAll();
|
||||
spinner.style.display = 'none';
|
||||
}, 20);
|
||||
}
|
||||
|
||||
function pauseCopters() {
|
||||
|
||||
}
|
||||
|
||||
function stopCopters() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
function emLand() {
|
||||
|
||||
}
|
||||
|
||||
function setStartTime() {
|
||||
Ply.dialog("prompt", {
|
||||
title: "Set animation delay",
|
||||
form: {delay: "Delay"}
|
||||
}).done(function (ui) {
|
||||
setDelay(parseInt(ui.data.delay));
|
||||
updateDelay();
|
||||
});
|
||||
}
|
||||
|
||||
function startAnimation() {
|
||||
|
||||
}
|
||||
2
Server/static/js/ply.js
Normal file
2
Server/static/js/ply.js
Normal file
File diff suppressed because one or more lines are too long
5
Server/static/js/popper.min.js
vendored
Normal file
5
Server/static/js/popper.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -4,15 +4,44 @@
|
||||
<meta charset="UTF-8">
|
||||
<title>Clever Show </title>
|
||||
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/static/css/ply.css">
|
||||
<link rel="stylesheet" href="/static/css/tabulator.min.css">
|
||||
<link rel="stylesheet" href="/static/css/spinner.css">
|
||||
<link rel="stylesheet" href="/static/css/main.css">
|
||||
<script lang="js" src="/static/js/jquery.min.js"></script>
|
||||
<script lang="js" src="/static/js/popper.min.js"></script>
|
||||
<script lang="js" src="/static/js/bootstrap.min.js"></script>
|
||||
<script lang="js" src="/static/js/ply.js"></script>
|
||||
<script lang="js" src="/static/js/tabulator.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark sticky-top"
|
||||
style=" width: 100%; display: flex; flex-direction: row; justify-content: space-between;">
|
||||
<a href="" class="navbar-brand">Clever Show</a>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false">
|
||||
Actions
|
||||
</a>
|
||||
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<div class="dropdown-item">
|
||||
<label for="animationFile" class="btn">Set animation</label>
|
||||
<input id="animationFile" style="visibility:hidden;" type="file">
|
||||
</div>
|
||||
<div class="dropdown-item">
|
||||
<label for="configFile" class="btn">Set configuration</label>
|
||||
<input id="configFile" style="visibility:hidden;" type="file">
|
||||
</div>
|
||||
<div class="dropdown-item">
|
||||
<label for="arucoFile" class="btn">Set ArUco map</label>
|
||||
<input id="arucoFile" style="visibility:hidden;" type="file">
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div style="display: none;" id="spinner" class="lds-spinner">
|
||||
<div></div>
|
||||
<div></div>
|
||||
@@ -35,30 +64,24 @@
|
||||
<div class="command-container">
|
||||
<div class="action-container">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-primary btn-lg" onclick="refreshSelected()">Refresh selected
|
||||
<button type="button" class="btn btn-primary btn-lg" onclick="selectAll()">Select all
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary btn-lg" onclick="refreshAll()">Refresh all</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="action-container">
|
||||
<label>Set animation</label>
|
||||
<div class="custom-file">
|
||||
<input type="file" class="custom-file-input" id="animationFile">
|
||||
<label id="animationFileLabel" class="custom-file-label" for="animationFile">Choose file</label>
|
||||
</div>
|
||||
<label class="my-label">Set configuration</label>
|
||||
<div class="custom-file">
|
||||
<input type="file" class="custom-file-input" id="configFile">
|
||||
<label id="configFileLabel" class="custom-file-label" for="configFile">Choose file</label>
|
||||
</div>
|
||||
<label class="my-label">Set ArUco map</label>
|
||||
<div class="custom-file">
|
||||
<input type="file" class="custom-file-input" id="arucoFile">
|
||||
<label id="arucoFileLabel" class="custom-file-label" for="arucoFile">Choose file</label>
|
||||
<button type="button" class="btn btn-secondary btn-lg" onclick="deselectAll()">Deselect all</button>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-primary btn-lg" onclick="sendSelected()">Save to selected</button>
|
||||
<button type="button" class="btn btn-secondary btn-lg" onclick="sendAll()">Save to all</button>
|
||||
<button type="button" class="btn btn-info btn-lg" onclick="refreshSelected()">Selfcheck</button>
|
||||
<button type="button" class="btn btn-info btn-lg" onclick="testLedSelected()">Test led</button>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button id="delay" type="button" class="btn btn-success btn-lg" onclick="setStartTime()">Set time (now is 0)</button>
|
||||
<button type="button" class="btn btn-success btn-lg" onclick="startAnimation()">Start animation</button>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-warning btn-lg" onclick="pauseCopters()">Pause</button>
|
||||
<button type="button" class="btn btn-warning btn-lg" onclick="stopCopters()">Stop</button>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-danger btn-lg" onclick="emLand()">Emergency landing</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="action-container"></div>
|
||||
|
||||
@@ -1,109 +1,22 @@
|
||||
import threading
|
||||
from web_server_models import WebCopter
|
||||
from server import *
|
||||
from flask import Flask, render_template, jsonify, request, send_from_directory
|
||||
from server import Server
|
||||
from flask import Flask, render_template
|
||||
from app_routes.selfcheck import selfcheck_api, refresh_copters
|
||||
from app_routes.file_sender import file_sender_api
|
||||
from app_routes.misc import misc_api
|
||||
|
||||
app = Flask(__name__, static_url_path='/static')
|
||||
copters = []
|
||||
app.register_blueprint(selfcheck_api)
|
||||
app.register_blueprint(file_sender_api)
|
||||
app.register_blueprint(misc_api)
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def home():
|
||||
data = dict()
|
||||
data['clients'] = []
|
||||
refresh_copters()
|
||||
for client in Client.clients.keys():
|
||||
data['clients'].append([client, Client.clients[client].copter_id])
|
||||
return render_template('main.html', data=data)
|
||||
|
||||
|
||||
@app.route('/refresh_copters')
|
||||
def refresh_copters():
|
||||
try:
|
||||
for client_ip in Client.clients.keys():
|
||||
is_in = False
|
||||
for copter in copters:
|
||||
if client_ip == copter.ip:
|
||||
is_in = True
|
||||
if not is_in:
|
||||
copters.append(WebCopter(client_ip, Client.clients[client_ip].copter_id))
|
||||
return jsonify({'m': 'Ok'})
|
||||
except:
|
||||
return jsonify({'m': 'Error'})
|
||||
|
||||
|
||||
@app.route('/selfcheck/selected', methods=["GET", "POST"])
|
||||
def selfcheck_selected():
|
||||
data = dict()
|
||||
ip = request.args.get("ip")
|
||||
for copter in copters:
|
||||
if copter.ip == ip:
|
||||
copter.refresh()
|
||||
data = {
|
||||
'anim_id': copter.anim_id,
|
||||
'batt_voltage': copter.batt_voltage,
|
||||
'cell_voltage': copter.cell_voltage,
|
||||
'selfcheck': copter.selfcheck,
|
||||
'time': copter.time,
|
||||
'name': copter.name,
|
||||
}
|
||||
# data = {"anim_id": "No animation", "batt_voltage": 3.259999990463257, "cell_voltage": 1.0850000381469727,
|
||||
# "ip": "192.168.43.31", "name": "CLever7", "selfcheck": "OK", "time": 1554723269.57106}
|
||||
return jsonify(data)
|
||||
|
||||
|
||||
@app.route('/selfcheck/all', methods=["GET", "POST"])
|
||||
def selfcheck_all():
|
||||
data = []
|
||||
for copter in copters:
|
||||
copter.refresh()
|
||||
data.append({
|
||||
'anim_id': copter.anim_id,
|
||||
'batt_voltage': copter.batt_voltage,
|
||||
'cell_voltage': copter.cell_voltage,
|
||||
'selfcheck': copter.selfcheck,
|
||||
'ip': copter.ip,
|
||||
'time': copter.time,
|
||||
'name': copter.name,
|
||||
})
|
||||
# data = [{"anim_id": "No animation", "batt_voltage": 4.259999990463257, "cell_voltage": 4.0850000381469727,
|
||||
# "ip": "192.168.43.31", "name": "CLever7", "selfcheck": "OK", "time": 4554723269.57106}]
|
||||
# data *= 12
|
||||
return jsonify(data)
|
||||
|
||||
|
||||
@app.route('/set/animation', methods=['GET', 'POST'])
|
||||
def set_animation():
|
||||
if request.method == 'POST':
|
||||
f = request.files['file']
|
||||
print(f, 'ip', request.args.get('ip'))
|
||||
return jsonify({'m': 'ok'})
|
||||
|
||||
|
||||
@app.route('/set/config', methods=['GET', 'POST'])
|
||||
def set_config():
|
||||
if request.method == 'POST':
|
||||
f = request.files['file']
|
||||
print(f, 'ip', request.args.get('ip'))
|
||||
return jsonify({'m': 'ok'})
|
||||
|
||||
|
||||
@app.route('/set/aruco', methods=['GET', 'POST'])
|
||||
def set_aruco():
|
||||
if request.method == 'POST':
|
||||
f = request.files['file']
|
||||
print(f, 'ip', request.args.get('ip'))
|
||||
return jsonify({'m': 'ok'})
|
||||
|
||||
|
||||
class ServerThread(threading.Thread):
|
||||
def run(self):
|
||||
server = Server()
|
||||
server.start()
|
||||
while True:
|
||||
pass
|
||||
|
||||
|
||||
server_thread = ServerThread()
|
||||
server_thread.start()
|
||||
server = Server()
|
||||
server.start()
|
||||
app.run(host='0.0.0.0', debug=False)
|
||||
|
||||
@@ -1,23 +1,36 @@
|
||||
from server import Client
|
||||
|
||||
copters = []
|
||||
delay = 0
|
||||
|
||||
|
||||
def set_delay_manually(_delay):
|
||||
global delay
|
||||
delay = _delay
|
||||
|
||||
|
||||
def get_delay_manually():
|
||||
return delay
|
||||
|
||||
|
||||
class WebCopter:
|
||||
def __init__(self, ip, name):
|
||||
def __init__(self, ip, client):
|
||||
self.anim_id = None
|
||||
self.batt_voltage = None
|
||||
self.cell_voltage = None
|
||||
self.selfcheck = None
|
||||
self.time = None
|
||||
self.ip = ip
|
||||
self.name = name
|
||||
self.name = client.copter_id
|
||||
self.client = client
|
||||
self.refresh()
|
||||
|
||||
def refresh(self):
|
||||
Client.clients[self.ip].get_response("anim_id", save, callback_args=(self, 'anim_id'))
|
||||
Client.clients[self.ip].get_response("batt_voltage", save, callback_args=(self, 'batt_voltage'))
|
||||
Client.clients[self.ip].get_response("cell_voltage", save, callback_args=(self, 'cell_voltage'))
|
||||
Client.clients[self.ip].get_response("selfcheck", save, callback_args=(self, 'selfcheck'))
|
||||
Client.clients[self.ip].get_response("time", save, callback_args=(self, 'time'))
|
||||
self.client.get_response("anim_id", save, callback_args=(self, 'anim_id'))
|
||||
self.client.get_response("batt_voltage", save, callback_args=(self, 'batt_voltage'))
|
||||
self.client.get_response("cell_voltage", save, callback_args=(self, 'cell_voltage'))
|
||||
self.client.get_response("selfcheck", save, callback_args=(self, 'selfcheck'))
|
||||
self.client.get_response("time", save, callback_args=(self, 'time'))
|
||||
|
||||
|
||||
def save(m, self, param_name):
|
||||
|
||||
Reference in New Issue
Block a user