Updated WebUI

This commit is contained in:
Marcel Peterkau 2023-04-13 00:32:50 +02:00
parent 427e5e5d16
commit 4507c80eba
28 changed files with 17591 additions and 4398 deletions

View File

@ -3,198 +3,453 @@
<head>
<meta charset="utf-8" />
<title>%DEVICE_NAME%</title>
<meta http-equiv="content-type" content="text/html;charset=UTF-8">
<title>%DEVICENAME%</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="static/css/bootstrap.min.css">
<link rel="stylesheet" href="static/css/custom.css">
<script src="static/js/jquery-3.3.1.min.js"></script>
<script src="static/js/bootstrap.bundle.min.js"></script>
<link rel="stylesheet" href="static/css/tweaks.css">
<script src="static/js/jquery.min.js"></script>
<script src="static/js/bootstrap.min.js"></script>
<script src="static/js/websocket.js"></script>
<link rel="apple-touch-icon" sizes="180x180" href="static/img/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="static/img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="static/img/favicon-16x16.png">
<link rel="manifest" href="static/img/site.webmanifest">
<link rel="mask-icon" href="static/img/safari-pinned-tab.svg" color="#111111">
<link rel="shortcut icon" href="static/img/favicon.ico">
<meta name="msapplication-TileColor" content="#111111">
<meta name="msapplication-config" content="static/img/browserconfig.xml">
<meta name="theme-color" content="#111111">
<script type="text/javascript">
var opacity = 0;
var intervalID = 0;
window.onload = setTimeout(() => { fadeout(); }, 4000);
function fadeout() {
intervalID = setInterval(hide, 200);
}
function hide() {
var responseMessage = document.getElementById("responseMessage");
opacity =
Number(window.getComputedStyle(responseMessage).getPropertyValue("opacity"))
if (opacity > 0) {
opacity = opacity - 0.1;
responseMessage.style.opacity = opacity
}
else {
responseMessage.remove()
clearInterval(intervalID);
}
}
</script>
</head>
<body>
<header class="sticky-top">
<nav class="navbar navbar-expand-sm navbar-dark bg-dark">
<a class="navbar-brand" href="#">
<img src="static/img/logo.png" width="30" height="30" class="d-inline-block align-top" alt="">
%DEVICE_NAME%</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup"
aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<nav class="navbar fixed-top navbar-dark bg-primary" id="navbar1">
<a class="navbar-brand" href="#">
<img src="static/img/logo.png" width="30" height="30" class="d-inline-block align-top mr-1" alt="">
%DEVICENAME%
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsingNavbar"
aria-controls="collapsingNavbar" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsingNavbar">
<ul class="navbar-nav nav mr-auto mt-2 mt-lg-0">
<div class="collapse navbar-collapse pr-2 mt-2 bg-secondary" id="navbarNavAltMarkup">
<ul class="navbar-nav nav align-items-end">
<li class="nav-item">
<a class="nav-link active" href="#tab_home" data-toggle="tab">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#tab_settings" data-toggle="tab">Settings</a>
</li>
</ul>
</div>
</nav>
</header>
<li class="nav-item"><a class="nav-link active" role="tab" data-toggle="tab" href="#tab_home">Home</a></li>
<li class="nav-item"><a class="nav-link" role="tab" data-toggle="tab" href="#tab_maintenance">Wartung</a></li>
<li class="nav-item"><a class="nav-link" role="tab" data-toggle="tab" href="#tab_source">Einstellungen</a></li>
<li class="nav-item"><a class="nav-link" role="tab" data-toggle="tab" href="#tab_sysinfo">Systeminfo</a></li>
<li class="nav-item"><a class="nav-link" role="tab" data-toggle="tab" href="#tab_fwupdate">Update</a></li>
</ul>
</div>
</nav>
<main class="container">
<main class="container-fluid py-3 flex-fill">
<!-- Tabs Content -->
<div class="tab-content">
<!-- Div Tab Home-->
<div class="tab-pane fade show active" id="tab_home" role="tabpanel">
<!-- Jumbotron -->
<div class="jumbotron text-center">
<p class="p-4">
<img src="static/img/logo.png">
</p>
<h3>%DEVICE_NAME%</h3>
</div>
<!-- AlertMessageBox-->
<div id="responseMessage" class="alert alert-%RESP_MESSAGE_TYPE%" %SHOW_RESP_MESSAGE%>
%RESP_MESSAGE%
</div>
<div class="container-fluid pb-5">
<h4>BATTERY: %BATTERY_TYPE%</h4>
<div class="progress">
<div class="progress-bar text-light" role="progressbar" aria-valuenow="%BAT_REMAIN_CAPACITY%"
aria-valuemin="0" aria-valuemax="100" style="width: %BAT_REMAIN_CAPACITY%&#37;">
%BAT_REMAIN_CAPACITY%&#37; / %BAT_VOLTAGE% V
</div>
<div id="tab_home" class="tab-pane fade show active" role="tabpanel">
<div class="col text-center">
<div class="jumbotron">
<img src="static/img/logo.png" width="120" height="120" class="img-fluid" alt="">
<h3 class="pt-3">%DEVICENAME%</h3>
</div>
</div>
<div class="container-fluid pb-5">
<h4>FACTIONS</h4>
<div class="table-responsive">
<table class="table text-light text-center">
<thead>
<tr>
<th scope="col">Faction</td>
<th scope="col">Time</td>
</tr>
</thead>
<tbody>
<tr>
<td class="align-items-center justify-content-center" scope="col">
<a href="#">
<img src="static/img/logo_fac1.png" class="img-responsive" alt="" />
<div class="desc">
<p class="desc_content">%NAME_FAC_1%</p>
</div>
</a>
</td>
<td class="align-items-center justify-content-center" scope="col">%POINTS_FAC_1%</td>
</tr>
<tr>
<td class="align-items-center justify-content-center" scope="col">
<a href="#">
<img src="static/img/logo_fac2.png" class="img-responsive" alt="" />
<div class="desc">
<p class="desc_content">%NAME_FAC_2%</p>
</div>
</a>
</td>
<td class="align-items-center justify-content-center" scope="col">%POINTS_FAC_2%</td>
</tr>
<tr>
<td class="align-items-center justify-content-center" scope="col">
<a href="#">
<img src="static/img/logo_fac3.png" class="img-responsive" alt="" />
<div class="desc">
<p class="desc_content">%NAME_FAC_3%</p>
</div>
</a>
</td>
<td class="align-items-center justify-content-center" scope="col">%POINTS_FAC_3%</td>
</tr>
</tbody>
</table>
<!-- Div Group Battery remain -->
<hr />
<p>
<h4>Akku Ladestand</h4>
<div class="progress">
<div class="progress-bar text-light" role="progressbar" aria-valuenow="%BAT_REMAIN_CAPACITY%"
aria-valuemin="0" aria-valuemax="100" style="width: %BAT_REMAIN_CAPACITY%&#37;">
%BAT_REMAIN_CAPACITY%&#37;
</div>
</div>
<div class="container-fluid pb-5" %SHOW_DTC_TABLE%>
</p>
<!-- Div Group Battery remain -->
<!-- Div Group current Mode -->
<hr />
<p>
<h4>aktueller Modus</h4>
<input class="form-control" type="text" placeholder="%SYSTEM_STATUS%" readonly>
</p>
<!-- Div Group current Mode -->
<!-- Div Group DTC Table -->
<div %SHOW_DTC_TABLE%>
<hr />
<p>
<h4>Fehlercodes</h4>
<table class="table text-light">
<table class="table">
<tbody>
<tr>
<th class="col-md-4" scope="col">Timestamp</td>
<th class="col-md-4" scope="col">DTC</td>
<th class="col-md-4" scope="col">active</td>
<th class="col-6" scope="col">Zeitstempel</th>
<th class="col-2" scope="col">Fehlercode</th>
<th class="col-2" scope="col">Schwere</th>
<th class="col-2" scope="col">Aktiv</th>
</tr>
%DTC_TABLE%
</tbody>
</table>
</p>
</div>
<!-- Div Group DTC Table -->
</div>
<!-- Div Tab Home-->
<!-- Div Tab Settings-->
<div class="tab-pane fade" id="tab_settings" role="tabpanel">
<h3>Settings</h3>
<hr>
<form method="POST">
<!-- Div Tab Maintenance -->
<div id="tab_maintenance" class="tab-pane fade" role="tabpanel">
<h3>Wartung</h3>
<!-- Div Group EEPROM formatting -->
<hr />
<p>
<h4>EEPROM formatieren</h4>
<div class="alert alert-primary alert-dismissable show fade" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<strong>Achtung!</strong><br>
Das Formatieren der EEPROM-Bereiche sollte nur ausgeführt werden wenn es unbedingt erforderlich ist!
Hierdurch werden alle Einstellungen zurück gesetzt bzw. alle Betriebsdaten gehen verloren.
Folgende Situationen erfordern unter anderem eine Formatierung:
- Erstinitialisierung (bei neu aufgebautem Gerät)
- Firmware-Update (nur wenn es die Release-Notes fordern)
</div>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<label for="commandInput" class="col-sm-2 col-form-label">Command</label>
<div class="col-sm-10">
<input type="text" name="commandInput" class="form-control bg-light" id="commandInput"
placeholder="type command here...">
<div class="offset-4 col-8">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="reset_ee_cfg" id="reset_ee_cfg">
<label class="form-check-label" for="reset_ee_cfg">
Bereich "CFG"
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="reset_ee_pds" id="reset_ee_pds">
<label class="form-check-label" for="reset_ee_pds">
Bereich "PDS"
</label>
</div>
</div>
</div>
<div class="form-group row">
<div class="col-sm-12">
<button name="cmdsubmit" type="submit" class="btn btn-primary float-right">Apply</button>
<div class="col text-center">
<button name="reset_ee_btn" type="submit" class="btn btn-outline-primary">EEPROM formatieren</button>
</div>
</div>
</form>
</p>
<!-- Div Group EEPROM formatting -->
<!-- Div Group Device Reboot -->
<hr />
<p>
<h4>Ger&auml;t neustarten</h4>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<div class="col text-center">
<button name="reboot" type="submit" class="btn btn-outline-primary">Reboot</button>
</div>
</div>
</form>
</p>
<!-- Div Group Device Reboot -->
</div>
<!-- Div Tab Maintenance -->
<!-- Div Tab Settings-->
<div id="tab_source" class="tab-pane fade" role="tabpanel">
<h3>Einstellungen</h3>
<!-- Div Group Battery Type -->
<hr />
<p>
<h4>Akku-Variante</h4>
<form action="post.htm" method="POST" class="form-horizontal">
<div class="form-group row">
<label for="sourceselect" class="control-label col-4">Akku</label>
<div class="col-8">
<select id="sourceselect" name="sourceselect" class="select form-control">
%BATTERY_SELECT_OPTIONS%
</select>
</div>
</div>
<div class="form-group row">
<div class="col text-center">
<button name="sourcesave" type="submit" class="btn btn-outline-primary">&Uuml;bernehmen</button>
</div>
</div>
</form>
</p>
<!-- Div Group Battery Type -->
</div>
<!-- Div Tab Settings -->
<!-- Div Tab SystemInfo -->
<div id="tab_sysinfo" class="tab-pane fade" role="tabpanel">
<h3>Systeminfo</h3>
<!-- Div Group Sysinfo:Geraeteinfo -->
<hr />
<p>
<h4>Ger&auml;t</h4>
<table class="table">
<tbody>
<tr>
<th class="col-7" scope="col">Parameter</td>
<th class="col-5" scope="col">Value</td>
</tr>
<tr>
<td>Hostname</td>
<td>%HOSTNAME%</td>
</tr>
</table>
</p>
<!-- Div Group Sysinfo:Geraeteinfo -->
<!-- Div Group Sysinfo:Settings -->
<hr />
<p>
<h4>Einstellungen</h4>
<table class="table">
<tbody>
<tr>
<th class="col-7" scope="col">Parameter</td>
<th class="col-5" scope="col">Value</td>
</tr>
<tr>
<td>Battery_type</td>
<td>%BATTERY_TYPE%</td>
</tr>
<tr>
<td>EEPROM Version</td>
<td>%EEPROM_VERSION%</td>
</tr>
<tr>
<td>Checksum</td>
<td>%CONFIG_CHECKSUM%</td>
</tr>
</tbody>
</table>
</p>
<!-- Div Group Sysinfo:Settings -->
<!-- Div Group Sysinfo:Persistance -->
<hr />
<p>
<h4>Betriebsdaten</h4>
<table class="table">
<tbody>
<tr>
<th class="col-7" scope="col">Parameter</td>
<th class="col-5" scope="col">Value</td>
</tr>
<tr>
<td>writeCycleCounter</td>
<td>%WRITE_CYCLE_COUNT%</td>
</tr>
<tr>
<td>PersistenceMarker</td>
<td>%PERSISTENCE_MARKER%</td>
</tr>
<tr>
<td>activeFaction</td>
<td>%ACTIVE_FACTION%</td>
</tr>
<tr>
<td>faction_1_timer</td>
<td>%FACTION_1_TIMER%</td>
</tr>
<tr>
<td>faction_2_timer</td>
<td>%FACTION_2_TIMER%</td>
</tr>
<tr>
<td>faction_3_timer</td>
<td>%FACTION_3_TIMER%</td>
</tr>
<tr>
<td>checksum</td>
<td>%PERSISTANCE_CHECKSUM%</td>
</tr>
</table>
</p>
<!-- Div Group Sysinfo:Persistance -->
<!-- Div Group LiveDebug -->
<hr />
<p>
<h4>Live Debug</h4>
<div class="form-group row">
<textarea class="form-control" spellcheck="false" id="livedebug-out" rows="3" readonly></textarea>
</div>
<div class="form-group row">
<div class="col text-center">
<button id="btn-ws-start" class="btn btn-outline-primary">Start</button>
<button id="btn-ws-stop" class="btn btn-outline-primary ml-2">Stop</button>
</div>
</div>
</p>
<!-- Div Group LiveDebug -->
</div>
<!-- Div Tab SystemInfo -->
<!-- Div Tab Firmware Update-->
<div id="tab_fwupdate" class="tab-pane fade" role="tabpanel">
<h3>Firmware</h3>
<!-- Div Group VersionInfo -->
<hr />
<p>
<h4>Version-Info</h4>
<table class="table">
<tbody>
<tr>
<th class="col-7" scope="col">Parameter</td>
<th class="col-5" scope="col">Value</td>
</tr>
<tr>
<td>Firmware Version</td>
<td>%SW_VERSION%</td>
</tr>
<tr>
<td>Flash Version</td>
<td>%FS_VERSION%</td>
</tr>
<tr>
<td>Git Revision</td>
<td>%GIT_REV%</td>
</tr>
</table>
</p>
<!-- Div Group VersionInfo -->
<!-- Div Group EEPROM Backup -->
<hr />
<p>
<h4>EEPROM-Backup</h4>
<div class="form-group row">
<div class="col text-center">
<a class="btn btn-outline-primary" href="eejson" role="button" id="ee-backup-download">Download</a>
</div>
</div>
</p>
<!-- Div Group EEPROM Backup -->
<!-- Div Group EEPROM Restore -->
<hr />
<p>
<h4>EEPROM-Restore</h4>
<form method='POST' action='eeRestore' enctype='multipart/form-data'>
<div class="form-group row">
<div class="custom-file">
<input type="file" name="ee-restore-file" class="custom-file-input" id="ee-restore-file" accept=".ee.json"
required />
<label class="custom-file-label" for="ee-restore-file">EEPROM-Backup ausw&auml;hlen</label>
</div>
</div>
<div class="form-group row">
<div class="col text-center">
<button name="submit" type="submit" class="btn btn-outline-primary">Restore starten</button>
</div>
</div>
</form>
</p>
<!-- Div Group EEPROM Restore -->
<!-- Div Group Firmware Update -->
<hr />
<p>
<h4>Firmware-Update</h4>
<form method='POST' action='doUpdate' enctype='multipart/form-data'>
<div class="form-group row">
<div class="custom-file">
<input type="file" name="fw-update-file" class="custom-file-input" id="fw-update-file"
accept=".fw.bin,.fs.gz" required />
<label class="custom-file-label" for="fw-update-file">Firmware-Update ausw&auml;hlen</label>
</div>
</div>
<div class="form-group row">
<div class="col text-center">
<button name="submit" type="submit" class="btn btn-outline-primary">Update starten</button>
</div>
</div>
</form>
</p>
<!-- Div Group Firmware Update -->
</div>
<!-- Div Tab Firmware Update-->
</div>
<!-- Tabs Content -->
</main>
<!-- Footer -->
<footer class="fixed-bottom bg-secondary font-weight-light text-light text-center py-3">
<!-- Copyright -->
<span class=" footer-copyright">
© 2022 <a class="text-reset fw-bold" href="https://hiabuto.de/">Hiabuto Defence Systems</a>
</span>
<!-- Copyright -->
<footer class="page-footer navbar-dark bg-primary font-small fixed-bottom">
<div class="container-fluid text-center">
<div class="footer-copyright text-center py-3">
<span class="text-muted">© 2023 -
<a class="text-reset fw-bold" href="https://hiabuto.de/">Hiabuto Defence Systems</a></span>
</div>
</div>
</footer>
<!-- Footer -->
<!-- Modal Dialog -->
<div class="modal fade" id="dtcModal" tabindex="-1" role="dialog" aria-labelledby="dtcModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="dtcModalLabel">DTC-Description</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p class="dtc-desc">DTC Description</p>
<p class="dtc-debugval">DTC DebugVal</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<!-- Modal Dialog -->
<script>
$('.navbar-nav>li>a').on('click', function () {
$('.navbar-collapse').collapse('hide');
});
document.querySelector('.custom-file-input').addEventListener('change', function (e) {
var fileName = document.getElementById("fw-update-file").files[0].name;
var nextSibling = e.target.nextElementSibling
nextSibling.innerText = fileName
});
$(document).ready(function () {
$("tr[data-dtc]").each(function (i) {
$(this).attr('data-toggle', "modal");
$(this).attr('data-target', "#dtcModal");
});
});
$('#dtcModal').on('show.bs.modal', function (event) {
var dtctr = $(event.relatedTarget)
var dtc = dtctr.data('dtc')
var debugval = dtctr.data('debugval')
var modal = $(this)
$.getJSON('static/tt_dtc/dtc_' + dtc + '.json', function (data) {
modal.find('.modal-title').text(data.title)
modal.find('.dtc-desc').text(data.description)
if (debugval > 0) {
modal.find('.dtc-debugval').text("Debugvalue: " + debugval)
}
else {
modal.find('.dtc-debugval').remove()
}
}).fail(function () {
console.log("An error has occurred.");
modal.find('.modal-title').text("Fehler")
modal.find('.dtc-desc').text("DTC-Beschreibung konnte nicht geladen werden")
});
});
</script>
</body>
</html>

View File

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<title>%DEVICE_NAME%</title>
<title>KTM CAN Chain Oiler</title>
<meta http-equiv="content-type" content="text/html;charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="static/css/bootstrap.min.css">
@ -14,7 +14,7 @@
<link rel="icon" type="image/png" sizes="32x32" href="static/img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="static/img/favicon-16x16.png">
<link rel="manifest" href="static/img/site.webmanifest">
<meta http-equiv="refresh" content="3; url='/index.htm'" />
<meta http-equiv="refresh" content="3; url='index.htm'" />
</head>
<body>

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
@font-face {
font-family: 'Comfortaa';
font-style: normal;
font-weight: 300;
src: url(../fonts/comfortaa.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
body {
padding-top: 70px;
margin-bottom: 70px;
}
hr {
height: 2px;
border-width: 0;
color: gray;
background-color: gray
}
.dtc-debugval {
color: #F2771A;
font: 0.8rem Inconsolata, monospace;
background-color: black;
padding: 10px;
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,84 @@
var gateway = `ws://${window.location.hostname}/ws`;
var websocket;
window.addEventListener("load", onLoad);
function initWebSocket() {
console.log("Trying to open a WebSocket connection...");
websocket = new WebSocket(gateway);
websocket.onopen = onOpen;
websocket.onclose = onClose;
websocket.onmessage = onMessage; // <-- add this line
}
function initButtons() {
document
.getElementById("btn-ws-stop")
.addEventListener("click", livedebug_stop);
document
.getElementById("btn-ws-start")
.addEventListener("click", livedebug_start);
}
function onOpen(event) {
console.log("Connection opened");
}
function onClose(event) {
console.log("Connection closed");
setTimeout(initWebSocket, 2000);
}
function onMessage(event) {
var livedebug_out = document.getElementById("livedebug-out");
var textarea_heigth = livedebug_out.scrollHeight;
livedebug_out.value += event.data;
livedebug_out.scrollTop = livedebug_out.scrollHeight;
do_resize(livedebug_out);
}
function onLoad(event) {
initWebSocket();
initButtons();
}
function livedebug_start() {
websocket.send("start");
}
function livedebug_stop() {
websocket.send("stop");
}
function do_resize(textbox) {
var maxrows = 15;
var minrows = 3;
var txt = textbox.value;
var cols = textbox.cols;
var arraytxt = txt.split("\n");
var rows = arraytxt.length;
for (i = 0; i < arraytxt.length; i++)
rows += parseInt(arraytxt[i].length / cols);
if (rows > maxrows) textbox.rows = maxrows;
else if (rows < minrows) textbox.rows = minrows;
else textbox.rows = rows;
}
function notifyMe() {
if (!("Notification" in window)) {
alert("This browser does not support desktop notification");
} else if (Notification.permission === "granted") {
const notification = new Notification("Hi there!");
// …
} else if (Notification.permission !== "denied") {
Notification.requestPermission().then((permission) => {
if (permission === "granted") {
const notification = new Notification("Hi there!");
// …
}
});
}
}

View File

@ -0,0 +1,4 @@
{
"title": "kein EEPROM gefunden",
"description": "Es wurde kein EEPROM gefunden. Dies lässt einen Hardware-Defekt vermuten."
}

View File

@ -0,0 +1,4 @@
{
"title": "Power-Monitor Fehler",
"description": "Es gibt ein Problem mit dem Power-Monitoring. Die Akku-Überwachung ist ohne Funktion! Bitte Hardware prüfen"
}

View File

@ -0,0 +1,4 @@
{
"title": "Akku-Spannung niedrig",
"description": "Die Akkuspannung ist niedrig. Bitte Akku bald aufladen!"
}

View File

@ -0,0 +1,4 @@
{
"title": "Akku-Spannung kritisch",
"description": "Die Akkuspannung ist sehr niedrig. Bitte Akku umgehend ersetzen um eine schändliche Tiefentladung zu vermeiden!"
}

View File

@ -0,0 +1,4 @@
{
"title": "EEPROM CFG Checksumme",
"description": "Die Checksumme der Config-Partition des EEPROM ist ungültig. Setzen sie den EEPROM-Bereich 'CFG' im Menu 'Wartung' zurück"
}

View File

@ -0,0 +1,4 @@
{
"title": "EEPROM PDS Checksumme",
"description": "Die Checksumme der Betriebsdaten-Partition des EEPROM ist ungültig. Setzen sie den EEPROM-Bereich 'PDS' im Menu 'Wartung' zurück"
}

View File

@ -0,0 +1,4 @@
{
"title": "EEPROM PDS Adresse",
"description": "Die Adresse der Betriebsdaten-Partition im EEPROM ist ungültig. Setzen sie den EEPROM-Bereich 'PDS' im Menu 'Wartung' zurück"
}

View File

@ -0,0 +1,4 @@
{
"title": "EEPROM Version falsch",
"description": "Die Layout-Version des EEPROM stimmt nicht mit der Firmware-Version überein. Setzen sie den EEPROM-Bereich 'CFG' im Menu 'Wartung' zurück"
}

View File

@ -0,0 +1,4 @@
{
"title": "Flashstorage Fehler",
"description": "Der Flashstorage konnte nicht initialisiert werden. Aktualisieren sie Flash & Firmware"
}

View File

@ -0,0 +1,4 @@
{
"title": "Flashstorage Version falsch",
"description": "Die Version des Flashstorage stimmt nicht mit der Firmware-Version überein. Aktualisieren sie den Flash mit der passenden Update-Datei"
}

View File

@ -0,0 +1,4 @@
{
"title": "Config-Validierung",
"description": "Ein oder mehrer Einstellungswerte sind ausserhalb plausibler Werte. Prüfen Sie Ihre Einstellungen"
}

View File

@ -0,0 +1,4 @@
{
"title": "LoRa-Modul Fehler",
"description": "Es gibt ein Problem mit dem LoRa-Modul. Es konnte keine LoRa-Verbindung aufgebaut werden. Bitte Hardware prüfen"
}

View File

@ -1 +1 @@
1.0
1.1

View File

@ -2,52 +2,46 @@
AsyncWebServer webServer(80);
typedef enum
{
RESPMSG_HIDE,
RESPMSG_SUCCESS,
RESPMSG_INFO,
RESPMSG_WARNING,
RESPMSG_DANGER
} statusResponseMessage_Type_t;
char StatusResponseMessage[64];
statusResponseMessage_Type_t StatusResponseMessage_Type = RESPMSG_INFO;
#ifdef CAPTIVE
DNSServer dnsServer;
#endif
AsyncWebServer server(80);
const char *PARAM_MESSAGE = "message";
String processor(const String &var);
void WebserverPOST_Callback(AsyncWebServerRequest *request);
void WebserverNotFound_Callback(AsyncWebServerRequest *request);
void Webserver_Callback(AsyncWebServerRequest *request);
void WebserverCommands_Callback(String input);
void WebserverFirmwareUpdate_Callback(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final);
void WebserverEERestore_Callback(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final);
void WebServerEEJSON_Callback(AsyncWebServerRequest *request);
void GetFlashVersion(char *buff, size_t buff_size);
AsyncWebSocket webSocket("/ws");
void WebsocketEvent_Callback(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len);
void Websocket_HandleMessage(void *arg, uint8_t *data, size_t len);
void initWebUI()
{
if (!LittleFS.begin())
{
Serial.println("An Error has occurred while mounting LittleFS");
Debug_pushMessage("An Error has occurred while mounting LittleFS\n");
MaintainDTC(DTC_FLASHFS_ERROR, DTC_CRITICAL, true);
return;
}
GetFlashVersion(globals.FlashVersion, sizeof(globals.FlashVersion));
if (strcmp(globals.FlashVersion, QUOTE(FLASH_FS_VERSION)))
char buffer[6];
snprintf(buffer, sizeof(buffer), "%d.%02d", constants.Required_Flash_Version_major, constants.Required_Flash_Version_minor);
if (strcmp(globals.FlashVersion, buffer))
{
MaintainDTC(DTC_FLASHFS_VERSION_ERROR, DTC_WARN, true);
}
MDNS.begin(globals.DeviceName);
MDNS.addService("telnet", "tcp", 23);
MDNS.addService("http", "tcp", 80);
webSocket.onEvent(WebsocketEvent_Callback);
webServer.addHandler(&webSocket);
webServer.serveStatic("/static/", LittleFS, "/static/").setCacheControl("max-age=360000");
webServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->redirect("/index.htm"); });
@ -63,51 +57,63 @@ void initWebUI()
webServer.begin();
}
void Webserver_Process()
{
webSocket.cleanupClients();
}
String processor(const String &var)
{
if (var == "HOSTNAME")
return String(globals.DeviceName);
if (var == "SYSTEM_STATUS")
return String(globals.systemStatustxt);
if (var == "SW_VERSION")
{
char buffer[6];
snprintf(buffer, sizeof(buffer), "%d.%02d", constants.FW_Version_major, constants.FW_Version_minor);
return String(buffer);
}
if (var == "FS_VERSION")
return String(globals.FlashVersion);
if (var == "GIT_REV")
return String(constants.GitHash);
if (var == "SHOW_DTC_TABLE")
return globals.systemStatus == sysStat_Error ? "" : "hidden";
if (var == "SHOW_RESP_MESSAGE")
return StatusResponseMessage_Type != RESPMSG_HIDE ? "" : "hidden";
if (var == "RESP_MESSAGE_TYPE")
{
switch (StatusResponseMessage_Type)
{
case RESPMSG_SUCCESS:
return "success";
case RESPMSG_INFO:
return "info";
case RESPMSG_WARNING:
return "warning";
case RESPMSG_DANGER:
return "danger";
default:
return "info";
}
}
if (var == "RESP_MESSAGE")
return String(StatusResponseMessage);
if (var == "BAT_REMAIN_CAPACITY")
return String(globals.battery_level);
if (var == "DEVICE_NAME")
if (var == "DEVICENAME")
return String(globals.DeviceName);
if (var == "BATTERY_TYPE")
return String(ConfigData.batteryType);
if (var == "BAT_VOLTAGE")
return String((float)globals.loadvoltage_mV / 1000.0);
if (var == "PERSISTANCE_CHECKSUM")
{
char buffer[7];
sprintf(buffer, "0x%04X", PersistenceData.checksum);
return String(buffer);
}
if (var == "WRITE_CYCLE_COUNT")
return String(PersistenceData.writeCycleCounter);
if (var == "PERSISTENCE_MARKER")
return String(globals.eePersistanceAdress);
if (var == "EEPROM_VERSION")
return String(ConfigData.EEPROM_Version);
if (var == "CONFIG_CHECKSUM")
{
char buffer[7];
sprintf(buffer, "0x%04X", ConfigData.checksum);
return String(buffer);
}
if (var == "DTC_TABLE")
{
String temp;
String temp = "";
char buff_timestamp[16]; // Format: DD-hh:mm:ss:xxx
for (uint32_t i = 0; i < MAX_DTC_STORAGE; i++)
{
if (DTCStorage[i].Number > 0)
if (DTCStorage[i].Number < DTC_LAST_DTC)
{
sprintf(buff_timestamp, "%02d-%02d:%02d:%02d:%03d",
DTCStorage[i].timestamp / 86400000, // Days
@ -116,8 +122,23 @@ String processor(const String &var)
DTCStorage[i].timestamp / 1000 % 60, // Seconds
DTCStorage[i].timestamp % 1000); // milliseconds
temp = "<tr><td>" + String(buff_timestamp);
temp = temp + "<tr data-dtc=" + String(DTCStorage[i].Number);
temp = temp + " data-debugval=" + String(DTCStorage[i].debugVal) + "><td>" + String(buff_timestamp);
temp = temp + "</td><td>" + String(DTCStorage[i].Number) + "</td><td>";
temp = temp + "<img src=static/img/";
switch (DTCStorage[i].severity)
{
case DTC_CRITICAL:
temp = temp + "critical";
break;
case DTC_WARN:
temp = temp + "warn";
break;
case DTC_INFO:
temp = temp + "info";
break;
}
temp = temp + ".png></td><td>";
if (DTCStorage[i].active == DTC_ACTIVE)
temp = temp + "active";
@ -174,20 +195,15 @@ String processor(const String &var)
if (var == "NAME_FAC_3")
return FACTION_3_NAME;
if (var == "TITLE")
return DEVICE_NAME;
if (var == "BATTERY_LEVEL")
if (var == "BATTERY_SELECT_OPTIONS")
{
return String(globals.battery_level);
}
if (var == "BATTERY_TYPE")
{
return String(BatteryString[ConfigData.batteryType]);
}
if (var == "BATTERY_VOLTAGE")
{
return String((float)globals.loadvoltage_mV / 1000.0);
String temp;
for (uint32_t i = 0; i < BatteryString_Elements; i++)
{
String selected = ConfigData.batteryType == i ? " selected " : "";
temp = temp + "<option value=\"" + i + "\"" + selected + ">" + BatteryString[i] + "</option>";
}
return temp;
}
return String();
@ -196,19 +212,24 @@ String processor(const String &var)
void Webserver_Callback(AsyncWebServerRequest *request)
{
request->send(LittleFS, "/index.htm", "text/html", false, processor);
StatusResponseMessage_Type = RESPMSG_HIDE;
}
void WebserverPOST_Callback(AsyncWebServerRequest *request)
{
request->send(LittleFS, "/post.htm", "text/html", false, processor);
Debug_pushMessage("POST:\n");
int paramsNr = request->params();
for (int i = 0; i < paramsNr; i++)
{
AsyncWebParameter *p = request->getParam(i);
if (p->name() == "commandInput")
WebserverCommands_Callback(p->value());
Debug_pushMessage("%s : %s\n", p->name().c_str(), p->value().c_str());
// begin: POST Form Settings
if (p->name() == "cmdsubmit")
globals.requestEEAction = EE_CFG_SAVE;
// end: POST Form Settings
}
request->send(LittleFS, "/index.htm", "text/html", false, processor);
}
void WebserverNotFound_Callback(AsyncWebServerRequest *request)
@ -216,41 +237,6 @@ void WebserverNotFound_Callback(AsyncWebServerRequest *request)
request->send(404, "text/html", "Not found");
}
void WebserverCommands_Callback(String input)
{
String command = input.substring(0, input.indexOf(' '));
command.toUpperCase();
StatusResponseMessage_Type = RESPMSG_HIDE;
if (command == "RESET")
{
strcpy(StatusResponseMessage, "Counter Reset done");
StatusResponseMessage_Type = RESPMSG_SUCCESS;
PersistenceData.faction_1_timer = 0;
PersistenceData.faction_2_timer = 0;
PersistenceData.faction_3_timer = 0;
PersistenceData.activeFaction = NONE;
}
else if (command == "BAT3S")
{
strcpy(StatusResponseMessage, "Set BatteryType to LiPo 3S");
StatusResponseMessage_Type = RESPMSG_SUCCESS;
ConfigData.batteryType = BATTERY_LIPO_3S;
globals.requestEEAction = EE_CFG_SAVE;
}
else if (command == "BAT2S")
{
strcpy(StatusResponseMessage, "Set BatteryType to LiPo 2S");
StatusResponseMessage_Type = RESPMSG_SUCCESS;
ConfigData.batteryType = BATTERY_LIPO_2S;
globals.requestEEAction = EE_CFG_SAVE;
}
}
void GetFlashVersion(char *buff, size_t buff_size)
{
File this_file = LittleFS.open("version", "r");
@ -273,7 +259,7 @@ void WebserverFirmwareUpdate_Callback(AsyncWebServerRequest *request, const Stri
if (!index)
{
Serial.println("Update");
Debug_pushMessage("Update");
size_t content_len = request->contentLength();
int cmd = (filename.indexOf(".fs") > -1) ? U_FS : U_FLASH;
Update.runAsync(true);
@ -289,7 +275,7 @@ void WebserverFirmwareUpdate_Callback(AsyncWebServerRequest *request, const Stri
}
else
{
Serial.printf("Progress: %d%%\n", (Update.progress() * 100) / Update.size());
Debug_pushMessage("Progress: %d%%\n", (Update.progress() * 100) / Update.size());
}
if (final)
@ -304,8 +290,7 @@ void WebserverFirmwareUpdate_Callback(AsyncWebServerRequest *request, const Stri
}
else
{
Serial.println("Update complete");
Serial.flush();
Debug_pushMessage("Update complete\n");
globals.systemStatus = sysStat_Shutdown;
}
}
@ -313,31 +298,68 @@ void WebserverFirmwareUpdate_Callback(AsyncWebServerRequest *request, const Stri
void WebserverEERestore_Callback(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final)
{
bool ee_done = false;
bool validext = false;
static bool validext = false;
static char *buffer = NULL;
static uint32_t read_ptr = 0;
DeserializationError error;
if (!index)
{
Serial.println("EEPROM restore");
validext = (filename.indexOf(".ee.json") > -1);
if (validext)
{
buffer = (char *)malloc(1536);
read_ptr = 0;
if (buffer == NULL)
Debug_pushMessage("malloc() failed for EEPROM-Restore");
}
}
if (validext)
if (buffer != NULL)
{
Serial.println("Restoring EEPROM-Stuff");
memcpy(buffer + read_ptr, data, len);
read_ptr = read_ptr + len;
}
if (final)
{
if (buffer != NULL)
{
Serial.print(buffer);
StaticJsonDocument<1536> doc;
error = deserializeJson(doc, buffer);
if (error)
{
Debug_pushMessage("deserializeJson() failed: %s\n", error.f_str());
}
else
{
ConfigData.batteryType = (batteryType_t)doc["config"]["batteryType"].as<uint32_t>();
ConfigData.EEPROM_Version = doc["config"]["EEPROM_Version"].as<uint32_t>();
PersistenceData.writeCycleCounter = doc["persis"]["writeCycleCounter"].as<uint16_t>();
PersistenceData.activeFaction = (factions_t)doc["persis"]["activeFaction"].as<uint32_t>();
PersistenceData.faction_1_timer = doc["persis"]["faction_1_timer"].as<uint32_t>();
PersistenceData.faction_2_timer = doc["persis"]["faction_2_timer"].as<uint32_t>();
PersistenceData.faction_3_timer = doc["persis"]["faction_3_timer"].as<uint32_t>();
PersistenceData.checksum = doc["persis"]["checksum"].as<uint32_t>();
ee_done = true;
}
}
free(buffer);
AsyncWebServerResponse *response = request->beginResponse(302, "text/plain", "Please wait while the device reboots");
response->addHeader("Refresh", "20");
response->addHeader("Location", "/");
request->send(response);
if (ee_done)
{
Serial.println("Update complete");
Serial.flush();
Debug_pushMessage("Update complete");
globals.systemStatus = sysStat_Shutdown;
}
else
@ -355,13 +377,16 @@ void WebServerEEJSON_Callback(AsyncWebServerRequest *request)
char buffer[16];
fwinfo["DeviceName"] = globals.DeviceName;
fwinfo["FW-Version"] = QUOTE(SW_VERSION);
sprintf(buffer, "%d.%02d", constants.Required_Flash_Version_major, constants.Required_Flash_Version_minor);
fwinfo["FW-Version"] = buffer;
fwinfo["FS-Version"] = globals.FlashVersion;
snprintf_P(buffer, sizeof(buffer), "%s", constants.GitHash);
fwinfo["Git-Hash"] = buffer;
JsonObject config = json.createNestedObject("config");
config["EEPROM_Version"] = ConfigData.EEPROM_Version;
config["batteryType"] = ConfigData.batteryType;
sprintf(buffer, "0x%08X", ConfigData.checksum);
config["checksum"] = buffer;
@ -373,7 +398,10 @@ void WebServerEEJSON_Callback(AsyncWebServerRequest *request)
JsonObject persis = json.createNestedObject("persis");
persis["writeCycleCounter"] = PersistenceData.writeCycleCounter;
persis["activeFaction"] = PersistenceData.activeFaction;
persis["faction_1_timer"] = PersistenceData.faction_1_timer;
persis["faction_2_timer"] = PersistenceData.faction_2_timer;
persis["faction_3_timer"] = PersistenceData.faction_3_timer;
sprintf(buffer, "0x%08X", PersistenceData.checksum);
persis["checksum"] = buffer;
@ -382,4 +410,52 @@ void WebServerEEJSON_Callback(AsyncWebServerRequest *request)
response->addHeader("Content-disposition", "attachment; filename=backup.ee.json");
request->send(response);
}
void WebsocketEvent_Callback(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)
{
switch (type)
{
case WS_EVT_CONNECT:
Debug_pushMessage("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
break;
case WS_EVT_DISCONNECT:
Debug_pushMessage("WebSocket client #%u disconnected\n", client->id());
break;
case WS_EVT_DATA:
Websocket_HandleMessage(arg, data, len);
break;
case WS_EVT_PONG:
case WS_EVT_ERROR:
break;
}
}
void Websocket_HandleMessage(void *arg, uint8_t *data, size_t len)
{
AwsFrameInfo *info = (AwsFrameInfo *)arg;
if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT)
{
data[len] = 0;
Debug_pushMessage("Got WebSocket Message: %s \n", (char *)data);
if (strcmp((char *)data, "start") == 0)
{
SetDebugportStatus(dbg_Webui, enabled);
}
else if (strcmp((char *)data, "stop") == 0)
{
SetDebugportStatus(dbg_Webui, disabled);
}
else if (strcmp((char *)data, "foo") == 0)
{
Debug_pushMessage("Got WebSocket Message 'foo' from client\n");
}
}
}
void Websocket_PushLiveDebug(String Message)
{
webSocket.textAll(Message + "\n");
}