Initial commit

This commit is contained in:
2026-01-02 20:52:43 +01:00
commit e9d2257d73
854 changed files with 164132 additions and 0 deletions

410
pagecontent/bridge-editor.php Executable file
View File

@@ -0,0 +1,410 @@
<?php
// Diese Seite ist für den Brücken-Editor
session_start();
$db = new SQLite3('../db-test/test.db');
$view = $_GET["view"];
$meta = $_GET["meta"];
$_SESSION["meta"]=$meta;
switch($view) {
case "add": // Neue Brücke anlegen
?>
<div class="content-header">Brücken-Editor - Neu anlegen</div>
<div class="plug-table">
<?php
$url = '../stecker.php?data=';
?>
<canvas id="bridge-editor-img" meta="<?php echo urlencode('[]'); ?>" style="background-image: url('<?php echo $url; ?>');" width="500" height="100"></canvas>
<script>
// Dieses Skript ist zum Großteil aus dem Internet kopiert, jedoch dann an die eigenen Bedürfnisse angepasst worden - Quelle: keine Ahnung
var canvas = document.getElementById('bridge-editor-img');
var ctx = canvas.getContext('2d');
var offscreenCanvas = document.createElement('canvas');
offscreenCanvas.width = canvas.width;
offscreenCanvas.height = canvas.height;
var offCtx = offscreenCanvas.getContext('2d');
var rects = [
// Obere Zeile
{id: 31, x: 405, y: 20}, {id: 32, x: 370, y: 20}, {id: 33, x: 335, y: 20},
{id: 34, x: 300, y: 20}, {id: 35, x: 265, y: 20}, {id: 36, x: 230, y: 20},
{id: 37, x: 195, y: 20}, {id: 38, x: 160, y: 20}, {id: 39, x: 125, y: 20},
{id: 30, x: 70, y: 20},
// Mittlere Zeile
{id: 21, x: 405, y: 44}, {id: 22, x: 370, y: 44}, {id: 23, x: 335, y: 44},
{id: 24, x: 300, y: 44}, {id: 25, x: 265, y: 44}, {id: 26, x: 220, y: 44},
{id: 27, x: 185, y: 44}, {id: 28, x: 150, y: 44}, {id: 29, x: 115, y: 44},
{id: 20, x: 70, y: 44},
// Untere Zeile
{id: 11, x: 405, y: 68}, {id: 12, x: 370, y: 68}, {id: 13, x: 335, y: 68},
{id: 14, x: 300, y: 68}, {id: 15, x: 265, y: 68}, {id: 16, x: 230, y: 68},
{id: 17, x: 195, y: 68}, {id: 18, x: 160, y: 68}, {id: 19, x: 125, y: 68},
{id: 10, x: 70, y: 68}
];
var colorID = 0;
var RECT_WIDTH = 25;
var RECT_HEIGHT = 10;
var drawing = false;
var startPoint = null;
function getCenterIfInRect(x, y) {
for (var rect of rects) {
if (
x >= rect.x &&
x <= rect.x + RECT_WIDTH &&
y >= rect.y &&
y <= rect.y + RECT_HEIGHT
) {
return {
x: rect.x + RECT_WIDTH / 2,
y: rect.y + RECT_HEIGHT / 2,
id: rect.id
};
}
}
return null;
}
canvas.addEventListener('mousedown', (e) => {
var rect = canvas.getBoundingClientRect();
var mouseX = e.clientX - rect.left;
var mouseY = e.clientY - rect.top;
var center = getCenterIfInRect(mouseX, mouseY);
if (center) {
startPoint = center;
drawing = true;
}
});
canvas.addEventListener('mousemove', (e) => {
if (!drawing || !startPoint) return;
var rect = canvas.getBoundingClientRect();
var mouseX = e.clientX - rect.left;
var mouseY = e.clientY - rect.top;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(offscreenCanvas, 0, 0);
ctx.beginPath();
ctx.moveTo(startPoint.x, startPoint.y);
ctx.lineTo(mouseX, mouseY);
ctx.strokeStyle = "red";
offCtx.lineWidth = 3;
ctx.stroke();
});
canvas.addEventListener('mouseup', (e) => {
if (!drawing || !startPoint) return;
var rect = canvas.getBoundingClientRect();
var mouseX = e.clientX - rect.left;
var mouseY = e.clientY - rect.top;
var endPoint = getCenterIfInRect(mouseX, mouseY);
drawing = false;
if (endPoint && startPoint.id !== endPoint.id) {
connectPins(startPoint.id, endPoint.id, "canvas");
ctx.clearRect(0, 0, canvas.width, canvas.height);
} else {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(offscreenCanvas, 0, 0);
}
startPoint = null;
});
</script>
<?php
echo '
</div>
<div class="pin-table">'; // Hier folgt die eigentliche Bearbeitungs-Fläche
$pinTable_row = 0;
foreach ($nodes as $nodeItem) { // Anzahl an Gesamt-Brücken-Elementen (Dies ist Wichtig, da appliedPinRowNumber ein Funktionsparameter ist, damit JS weiß, an welcher Stelle ein neues Element mit welchem Index erstellt werden muss!)
$pinTable_row++;
}
$appliedPinRowNumber = $pinTable_row;
// im Folgenden die Eingabefelder anzeigen (mit aufsteigender ID)
$pinTable_row = 0;
foreach ($nodes as $nodeItem) {
echo '
<div class="row" id="pinRow_' . $pinTable_row . '">
<span>' . $nodeItem[0] . '</span>
<img src="/vendor/icons/data-transfer-both.svg" height="30px" />
<span>' . $nodeItem[1] . '</span>
<img style="transform: rotate(0deg); padding-top: 17.5px;" src="/vendor/icons/trash.svg" onclick="removePin(' . $pinTable_row . ')" height="30px"/>
</div>';
$pinTable_row++;
}
?>
</div>
<button hidden id="bridge-editor-edit" value=""></button>
<div class="save-button" onclick="save('bridge-editor','add')"><img src="/vendor/icons/floppy-disk.svg" \>Speichern</div>
<?php
break;
case "edit": // Bestehende Brücke bearbeiten
?>
<div class="content-header">Brücken-Editor - Bearbeiten</div>
<div class="plug-table">
<?php
$settings = json_decode(file_get_contents("../settings.json"), true);
$plug = $settings["plug"]; //$plug ist die plug-ID!
$result = $db->query("
SELECT * FROM bridges WHERE plug_id = '" . $plug . "' AND id = '" . $meta . "';
");
$result = $result->fetchArray(SQLITE3_ASSOC);
// Skelettstruktur: Die "Row" sorgt hier für das typische Layout, insbesodere für die Darstellung der Brückennummer
?>
<div class="row">
<?php
print('
<div class="label">
<span>' . $result["id"] . '</span>
</div>'); // Brückennummer
$nodes_url = [];
$nodes = $db->query("
SELECT node_from,node_to
FROM nodes WHERE required_by = '". $result['id'] ."';
");
while ($node = $nodes->fetchArray(SQLITE3_ASSOC)) {
$nodes_url[] = [$node['node_from'], $node['node_to']];
}
$url = '../stecker.php?data=' . urlencode(json_encode($nodes_url)); // URL parsen
$nodes = $nodes_url; // die Nodes speichern (hier stecken alle Daten drin)
?>
</div>
<canvas id="bridge-editor-img" meta="<?php echo urlencode(json_encode($nodes_url)); ?>" style="background-image: url('<?php echo $url; ?>');" width="500" height="100"></canvas>
<script>
// Dieses Skript ist zum Großteil aus dem Internet kopiert, jedoch dann an die eigenen Bedürfnisse angepasst worden - Quelle: keine Ahnung
var canvas = document.getElementById('bridge-editor-img');
var ctx = canvas.getContext('2d');
var offscreenCanvas = document.createElement('canvas');
offscreenCanvas.width = canvas.width;
offscreenCanvas.height = canvas.height;
var offCtx = offscreenCanvas.getContext('2d');
var rects = [
// Obere Zeile
{id: 31, x: 405, y: 20}, {id: 32, x: 370, y: 20}, {id: 33, x: 335, y: 20},
{id: 34, x: 300, y: 20}, {id: 35, x: 265, y: 20}, {id: 36, x: 230, y: 20},
{id: 37, x: 195, y: 20}, {id: 38, x: 160, y: 20}, {id: 39, x: 125, y: 20},
{id: 30, x: 70, y: 20},
// Mittlere Zeile
{id: 21, x: 405, y: 44}, {id: 22, x: 370, y: 44}, {id: 23, x: 335, y: 44},
{id: 24, x: 300, y: 44}, {id: 25, x: 265, y: 44}, {id: 26, x: 220, y: 44},
{id: 27, x: 185, y: 44}, {id: 28, x: 150, y: 44}, {id: 29, x: 115, y: 44},
{id: 20, x: 70, y: 44},
// Untere Zeile
{id: 11, x: 405, y: 68}, {id: 12, x: 370, y: 68}, {id: 13, x: 335, y: 68},
{id: 14, x: 300, y: 68}, {id: 15, x: 265, y: 68}, {id: 16, x: 230, y: 68},
{id: 17, x: 195, y: 68}, {id: 18, x: 160, y: 68}, {id: 19, x: 125, y: 68},
{id: 10, x: 70, y: 68}
];
var colorID = 0;
var RECT_WIDTH = 25;
var RECT_HEIGHT = 10;
var drawing = false;
var startPoint = null;
function getCenterIfInRect(x, y) {
for (var rect of rects) {
if (
x >= rect.x &&
x <= rect.x + RECT_WIDTH &&
y >= rect.y &&
y <= rect.y + RECT_HEIGHT
) {
return {
x: rect.x + RECT_WIDTH / 2,
y: rect.y + RECT_HEIGHT / 2,
id: rect.id
};
}
}
return null;
}
canvas.addEventListener('mousedown', (e) => {
var rect = canvas.getBoundingClientRect();
var mouseX = e.clientX - rect.left;
var mouseY = e.clientY - rect.top;
var center = getCenterIfInRect(mouseX, mouseY);
if (center) {
startPoint = center;
drawing = true;
}
});
canvas.addEventListener('mousemove', (e) => {
if (!drawing || !startPoint) return;
var rect = canvas.getBoundingClientRect();
var mouseX = e.clientX - rect.left;
var mouseY = e.clientY - rect.top;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(offscreenCanvas, 0, 0);
ctx.beginPath();
ctx.moveTo(startPoint.x, startPoint.y);
ctx.lineTo(mouseX, mouseY);
ctx.strokeStyle = "red";
offCtx.lineWidth = 3;
ctx.stroke();
});
canvas.addEventListener('mouseup', (e) => {
if (!drawing || !startPoint) return;
var rect = canvas.getBoundingClientRect();
var mouseX = e.clientX - rect.left;
var mouseY = e.clientY - rect.top;
var endPoint = getCenterIfInRect(mouseX, mouseY);
drawing = false;
if (endPoint && startPoint.id !== endPoint.id) {
connectPins(startPoint.id, endPoint.id, "canvas");
ctx.clearRect(0, 0, canvas.width, canvas.height);
} else {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(offscreenCanvas, 0, 0);
}
startPoint = null;
});
</script>
<?php
echo '
</div>
<div class="pin-table">'; // Hier folgt die eigentliche Bearbeitungs-Fläche
$pinTable_row = 0;
foreach ($nodes as $nodeItem) { // Anzahl an Gesamt-Brücken-Elementen (Dies ist Wichtig, da appliedPinRowNumber ein Funktionsparameter ist, damit JS weiß, an welcher Stelle ein neues Element mit welchem Index erstellt werden muss!)
$pinTable_row++;
}
$appliedPinRowNumber = $pinTable_row;
// im Folgenden die Eingabefelder anzeigen (mit aufsteigender ID)
$pinTable_row = 0;
foreach ($nodes as $nodeItem) {
echo '
<div class="row" id="pinRow_' . $pinTable_row . '">
<span>' . $nodeItem[0] . '</span>
<img src="/vendor/icons/data-transfer-both.svg" height="30px" />
<span>' . $nodeItem[1] . '</span>
<img style="transform: rotate(0deg); padding-top: 17.5px;" src="/vendor/icons/trash.svg" onclick="removePin(' . $pinTable_row . ')" height="30px"/>
</div>';
$pinTable_row++;
}
?>
</div>
<button id="bridge-editor-edit" value="" onclick="save('bridge-editor','edit','<?php echo $meta; ?>')">Speichern</button>
<?php
break;
default: // Standard: Übersicht
?>
<div class="content-header">Brücken-Editor - Übersicht</div>
<div class="action-menu">
<img src="/vendor/icons/plus.svg" onclick="window.location.href='#bridge-editor'; pageload('add');" />
</div>
<div class="plug-table">
<?php
$settings = json_decode(file_get_contents("../settings.json"), true);
$plug = $settings["plug"]; //$plug ist die plug-ID!
$result = $db->query("SELECT * FROM bridges WHERE plug_id = '" . $plug . "';");
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
?>
<div class="row">
<?php
print('
<div class="label">
<span>' . $row['id'] . '</span>
</div>');
$nodes_url = [];
$nodes = $db->query("
SELECT node_from,node_to
FROM nodes WHERE required_by = ". $row['id'] .";
");
while ($node = $nodes->fetchArray(SQLITE3_ASSOC)) {
$nodes_url[] = [$node['node_from'], $node['node_to']];
}
$url = '../stecker.php?data=' . urlencode(json_encode($nodes_url)); // URL parsen
print('<img id="bridge-editor-img" src="' . $url . '" />');
print('
<div class="options">
<img src="/vendor/icons/edit-pencil.svg" onclick="window.location.href=\'#bridge-editor\'; pageload(\'edit\',\'' . $row["id"] . '\');"/>
<img src="/vendor/icons/trash.svg" onclick="if(confirm(\'Sicher? Diese Änderung kann nicht rückgängig gemacht werden!\') == true){save(\'bridge-editor\',\'remove\',\'' . $row["id"] . '\')}" />
</div>
');
?>
</div>
<?php
}
$result = $db->query("SELECT COUNT(*) as anzahl FROM bridges WHERE plug_id = '" . $plug . "';");
$row = $result->fetchArray(SQLITE3_ASSOC);
$number = $row['anzahl'];
if($number <= 0) {
print("<p align='center'>Es sind keine Brücken für diesen Stecker gespeichert.<br>Eventuell muss ein anderer Stecker gewählt werden.</p>");
}
?>
</div>
<?php
break;
}

13
pagecontent/cable-check.php Executable file
View File

@@ -0,0 +1,13 @@
<?php
session_start();
?>
<div class="content-header">Spurkabel prüfen</div>
<hr />
<p>Automatische Erkennung</p>
<i>Verbinden Sie die Enden des Spurkabels mit dem Gerät. Vermeiden Sie Bewegungen während der Messung.</i>
<div class="save-button" onclick="window.location.href='#start-cable';$('.save-button').html('<img src=\'/vendor/icons/load.gif\' \>Initialisieren...'); "><img src="/vendor/icons/play.svg" \>Jetzt prüfen</div>

322
pagecontent/database-search.php Executable file
View File

@@ -0,0 +1,322 @@
<?php
// Diese Seite durchsucht die Datenbank nach gespeicherten Werten (keine Brücken, Programme, etc..)
$meta = $_GET["meta"];
$view = $_GET["view"];
$db = new SQLite3('../db-test/test.db');
// Die Suche, auf welche nach der Durchführung einer Messung zugegriffen wird (ganz unten: möchten Sie die Messung in die Datenbank aufnehmen...)
if($view == "results") {
?>
<div class="inventory-table">
<?php
$result = 0;
// Hole die Orte
$result = $db->query(" SELECT * FROM places WHERE name LIKE '%" . strtolower($meta) . "%' ");
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
// Wenn die suche leer ist, sollen auch keine Ergebnisse kommen (siehe Vorschläge ignorieren)
if($meta == "") {
return;
}
?>
<div class="row" style="cursor: pointer" onclick="$('#database-search-term').val('<?php echo $row["name"]; ?>'); search('results');">
<img src="/vendor/icons/map-pin.svg" class="map" /><span><?php echo $row["name"]; ?></span>
</div>
<?php
}
// Wenn ein Ergebnis gefunden wird...
if($result == 1) {
// ... biete an, alle Vorschläge zu ignorieren
?>
<div class="row" style="cursor: pointer; width:50%;margin:15px auto;background-color: #f6615173" onclick="$('#database-search-term').attr('onkeyup',''); search('results','x');">
<img src="/vendor/icons/xmark.svg" class="" /><span align="center">Vorschläge ignorieren</span>
</div>
<?php
}
// Ende der Sucherergebnisse
?>
</div>
<?php
}
// Hier wird der Bestand angezeigt, der in der Bestandsuche nach einem Tastenanschlag erscheint
if($view == "program" && isset($meta) && !empty($meta)) {
// weil die Bestandssuche (im Gegensatz zur Ortssuche) die Programmbezeichnung durhcsucht, ist hier etwas mehr Aufwand erforderlich
// hole die Programmbezeichnung via 2x JOIN aus der Datenbank
$result = $db->query("
SELECT
m.id AS measurement_id,
m.comment AS comment,
m.timestamp AS timestamp,
m.place_name AS place_name,
b.value AS bit_value,
b.position AS bit_position
FROM
measurements m
JOIN places p ON p.name = m.place_name
JOIN measurement_program_id_bits b ON b.measurement_id = m.id
ORDER BY m.id
");
/*
Ausgabe sieht z.B. so aus:
| measurement_id | comment | timestamp | place_name | bit_value | bit_position |
| -------------- | ------- | --------- | ------------ | --------- | ------------ |
| 1 | xyz.. | 34535454 | Dudweiler Df | S | 0 |
| 1 | xyz.. | 34535454 | Dudweiler Df | - | 1 |
| 1 | xyz.. | 34535454 | Dudweiler Df | 4 | 2 |
| 1 | xyz.. | 34535454 | Dudweiler Df | - | 3 |
| 1 | xyz.. | 34535454 | Dudweiler Df | - | 4 |
| 7 | abc.. | 48548574 | Mannheim Hbf | A | 0 |
| 7 | abc.. | 48548574 | Mannheim Hbf | 6 | 1 |
| 7 | abc.. | 48548574 | Mannheim Hbf | 4 | 2 |
| 7 | abc.. | 48548574 | Mannheim Hbf | - | 3 |
| 7 | abc.. | 48548574 | Mannheim Hbf | S | 4 |
*/
// Die Datenbank wird als dreifach indexiertes Array gespeichert
$database_db = [];
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$database_db[$row["place_name"]][$row["measurement_id"]]["program_id_bits"][$row["bit_position"]] = $row["bit_value"];
$database_db[$row["place_name"]][$row["measurement_id"]]["comment"] = $row["comment"];
$database_db[$row["place_name"]][$row["measurement_id"]]["timestamp"] = $row["timestamp"];
}
/*
$database_db
└── $row["place_name"]
└── $row["measurement_id"]
├── "program_id_bits"
│ └── $row["bit_position"]
│ └── $row["bit_value"]
├── "program_id_string"
│ └── implode('', $bits)
├── "comment"
│ └── $row["comment"]
└── "timestamp"
└── $row["timestamp"]
*/
// speichere die Bits als String, damit diese einfacher durchsuchbar sind
foreach ($database_db as $place => $entries) {
foreach ($entries as $index => $info) {
$bits = $info['program_id_bits'];
$database_db[$place][$index]['program_id_string'] = implode('', $bits);
}
}
// durchsuche nach der Query im Programm-ID-String
foreach($database_db as $place_name => $measurements) {
$found = false;
foreach ($measurements as $measurement_id => $measurement) {
if(str_contains(strtolower($measurement["program_id_string"]), strtolower($meta))) {
$found = true;
}
}
if($found != true) {
continue;
}
?>
<div class="row">
<img src="/vendor/icons/map-pin.svg" class="map" />
<span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <?php echo $place_name; ?>
</span>
<div class="plug-table" style="display: block;" id="<?php echo $database_db[$place_name]; ?>">
<?php
foreach ($measurements as $measurement_id => $measurement) {
if(!str_contains(strtolower($measurement["program_id_string"]), strtolower($meta))) {
continue;
}
print('
<div class="row">
<div class="label" style="width: 180px;">
<span>');
$i = 0;
foreach($measurement["program_id_bits"] as $programIDChar) {
echo '<span class="label-char">' . $programIDChar . '</span>';
$i++;
}
print('
</span>
</div>
<div>
<div class="label" style="width: 50%;">
<span>' . date("d.m.Y H:i:s", $measurement["timestamp"]) . '</span>
</div>');
?>
<div class="options">
<img src="/vendor/icons/trash.svg" onclick="if(confirm('Sicher? Diese Änderung kann nicht rückgängig gemacht werden! )') == true){save('inventory','remove','<?php echo $measurement_id; ?>')}">
</div>
<?php
print('
</div>
</div>');
if(!empty($measurement["comment"])) {
print('
<div class="row" style="position: relative; height: auto;padding: 0 15;padding-left: 40px;box-sizing:border-box;">
<img src="/vendor/icons/info-circle.svg" style=" top: 2.5px;left: 10px;" />');
echo $measurement["comment"];
print('
</div>');
}
}
?>
</div>
</div>
<?php
}
}
// Hier wird der Bestand angezeigt, der in der Bestandssuche nach dem Klick auf "Alle Einträge holen" angezeigt wird
elseif ($view == "program") {
/*
Ausgabe sieht z.B. so aus:
| measurement_id | comment | timestamp | place_name | bit_value | bit_position |
| -------------- | ------- | --------- | ------------ | --------- | ------------ |
| 1 | xyz.. | 34535454 | Dudweiler Df | S | 0 |
| 1 | xyz.. | 34535454 | Dudweiler Df | - | 1 |
| 1 | xyz.. | 34535454 | Dudweiler Df | 4 | 2 |
| 1 | xyz.. | 34535454 | Dudweiler Df | - | 3 |
| 1 | xyz.. | 34535454 | Dudweiler Df | - | 4 |
| 7 | abc.. | 48548574 | Mannheim Hbf | A | 0 |
| 7 | abc.. | 48548574 | Mannheim Hbf | 6 | 1 |
| 7 | abc.. | 48548574 | Mannheim Hbf | 4 | 2 |
| 7 | abc.. | 48548574 | Mannheim Hbf | - | 3 |
| 7 | abc.. | 48548574 | Mannheim Hbf | S | 4 |
*/
$result = $db->query("
SELECT
m.id AS measurement_id,
m.comment AS comment,
m.timestamp AS timestamp,
m.place_name AS place_name,
b.value AS bit_value,
b.position AS bit_position
FROM
measurements m
JOIN places p ON p.name = m.place_name
JOIN measurement_program_id_bits b ON b.measurement_id = m.id
ORDER BY m.id
");
// Die Datenbank wird als dreifach indexiertes Array gespeichert
$database_db = [];
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$database_db[$row["place_name"]][$row["measurement_id"]]["program_id_bits"][$row["bit_position"]] = $row["bit_value"];
$database_db[$row["place_name"]][$row["measurement_id"]]["comment"] = $row["comment"];
$database_db[$row["place_name"]][$row["measurement_id"]]["timestamp"] = $row["timestamp"];
}
/*
$database_db
└── $row["place_name"]
└── $row["measurement_id"]
├── "program_id_bits"
│ └── $row["bit_position"]
│ └── $row["bit_value"]
├── "program_id_string"
│ └── implode('', $bits)
├── "comment"
│ └── $row["comment"]
└── "timestamp"
└── $row["timestamp"]
*/
foreach($database_db as $place_name => $measurements) {
?>
<div class="row">
<img src="/vendor/icons/map-pin.svg" class="map" /><span>[<?php echo count($database_db[$place_name]); ?>] <?php echo $place_name; ?></span>
<img src="/vendor/icons/arrow-down-tag.svg" class="down" onclick="$('#<?php echo preg_replace('/[^a-zA-Z0-9]/', '',$place_name); ?>').css('display','block');"/>
<div class="plug-table" style="display: none;" id="<?php echo preg_replace('/[^a-zA-Z0-9]/', '',$place_name); ?>">
<?php
foreach ($measurements as $measurement_id => $measurement) {
print('
<div class="row" style="margin-bottom: 0;">
<div class="label" style="width: 180px;">
<span>');
foreach($measurement["program_id_bits"] as $programIDChar) {
echo '
<span class="label-char">' . $programIDChar . '</span>';
}
print('
</span>
</div>
<div>
<div class="label" style="width: 50%;">
<span>' . date("d.m.Y H:i:s", $measurement["timestamp"]) . '</span>
</div>');
?>
<div class="options"><img src="/vendor/icons/trash.svg" onclick="if(confirm('Sicher? Diese Änderung kann nicht rückgängig gemacht werden! )') == true){save('inventory','remove','<?php echo $measurement_id; ?>')}"></div>
<?php
print('
</div>
</div>');
if(!empty($measurement["comment"])) {
print('
<div class="row" style="position: relative; height: auto;padding: 0 15;padding-left: 40px;box-sizing:border-box;"><img src="/vendor/icons/info-circle.svg" style=" top: 2.5px;left: 10px;" />');
echo $measurement["comment"];
print('
</div>');
}
}
?>
</div>
</div>
<?php
}
}

220
pagecontent/export.php Executable file
View File

@@ -0,0 +1,220 @@
<?php
session_start();
ini_set('display_errors', 1); ini_set('display_startup_errors', 1); error_reporting(E_ALL);
$_SESSION["meta"]=$meta;
error_reporting(E_ALL);
ini_set('display_errors', 1);
$db = new SQLite3('../db-test/test.db');
// weil die Bestandssuche (im Gegensatz zur Ortssuche) die Programmbezeichnung durhcsucht, ist hier etwas mehr Aufwand erforderlich
// hole die Programmbezeichnung via 2x JOIN aus der Datenbank
$result = $db->query("
SELECT
m.id AS measurement_id,
m.comment AS comment,
m.timestamp AS timestamp,
m.place_name AS place_name,
b.value AS bit_value,
b.position AS bit_position,
n.node_from AS node_from,
n.node_to AS node_to
FROM
measurements m
JOIN places p ON p.name = m.place_name
JOIN measurement_program_id_bits b ON b.measurement_id = m.id
JOIN measurement_nodes n ON n.required_by = m.id
");
/*
Ausgabe sieht z.B. so aus:
| measurement_id | comment | timestamp | place_name | bit_value | bit_position | node_from | node_to |
| -------------- | ------- | --------- | ------------ | --------- | ------------ | --------- | ------- |
| 1 | xyz.. | 34535454 | Dudweiler Df | S | 0 | 20 | 28 |
| 1 | xyz.. | 34535454 | Dudweiler Df | S | 0 | 28 | 30 |
| 1 | xyz.. | 34535454 | Dudweiler Df | - | 1 | 20 | 28 |
| 1 | xyz.. | 34535454 | Dudweiler Df | - | 1 | 28 | 30 |
| 1 | xyz.. | 34535454 | Dudweiler Df | 4 | 2 | 20 | 28 |
| 1 | xyz.. | 34535454 | Dudweiler Df | 4 | 2 | 28 | 30 |
| 1 | xyz.. | 34535454 | Dudweiler Df | - | 3 | 20 | 28 |
| 1 | xyz.. | 34535454 | Dudweiler Df | - | 3 | 28 | 30 |
| 1 | xyz.. | 34535454 | Dudweiler Df | - | 4 | 20 | 28 |
| 1 | xyz.. | 34535454 | Dudweiler Df | - | 4 | 28 | 30 |
*/
// Die Datenbank wird als dreifach indexiertes Array gespeichert
$database_db = [];
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$id = $row["measurement_id"];
// Basisdaten setzen (überschreiben macht nichts)
$database_db[$id]["comment"] = $row["comment"];
$database_db[$id]["timestamp"] = $row["timestamp"];
$database_db[$id]["place_name"] = $row["place_name"];
// Programmbits: nur setzen, wenn nicht schon vorhanden
if (!isset($database_db[$id]["program_id_bits"][$row["bit_position"]])) {
$database_db[$id]["program_id_bits"][$row["bit_position"]] = $row["bit_value"];
}
// Nodes: nur hinzufügen, wenn noch nicht vorhanden
$node_pair = [$row["node_from"], $row["node_to"]];
if (
!isset($database_db[$id]["nodes"]) ||
!in_array($node_pair, $database_db[$id]["nodes"])
) {
$database_db[$id]["nodes"][] = $node_pair;
}
}
// Ersetzen der $database_db[$id]["nodes"] zu einem String
$bitLength = 5;
$placeholder = '?';
foreach ($database_db as $index => $row) {
$programIdBits = isset($row['program_id_bits']) ? $row['program_id_bits'] : [];
$programIdString = '';
// Baue ein Array mit fester Länge ($bitLength), fülle fehlende Positionen mit Platzhalter
for ($i = 0; $i < $bitLength; $i++) {
$programIdString .= isset($programIdBits[$i]) ? $programIdBits[$i] : $placeholder;
}
$database_db[$index]['program_id_string'] = $programIdString;
}
// $list ist die CSV-Datei
//$list[] = array("Gemessen am / um", "Stw-Name / Ort" ,"Erkannte Brücken (Pin-zu-Pin)", "(automatisch) ermittelte Programm-Nummer", "Freitext-Besonderheiten");
// gehe jeden Datenwankeintrag durch
foreach($database_db as $database_entry) {
// leere dne node_string zu Beginn
$node_string = "";
// erstelle einen Brücken-String, der erweitert wird
foreach($database_entry["nodes"] as $node) {
$node_string .= $node[0] . "<->" . $node[1] . ", ";
}
$imagePath = 'http://localhost/stecker.php?data=' . urlencode(json_encode($database_entry["nodes"])); // URL parsen
// Schreibe ins Array
$list[] = array(date('d.m.Y H:i:s',$database_entry["timestamp"]), $database_entry["place_name"] ,$node_string, $database_entry["program_id_string"], $database_entry["comment"], $imagePath);
}
function svgUrlToPngViaRsvg(string $svgUrl, string $outputPath): bool {
$svgData = file_get_contents($svgUrl);
if ($svgData === false) return false;
$tempSvg = '../tmp/stecker_' . uniqid() . '.svg';
file_put_contents($tempSvg, $svgData);
$cmd = escapeshellcmd("rsvg-convert -o " . escapeshellarg($outputPath) . " " . escapeshellarg($tempSvg));
$result = shell_exec($cmd);
unlink($tempSvg);
return file_exists($outputPath);
}
require '../vendor/composer/vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
// Neue Excel-Datei erzeugen
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
// Spaltenüberschriften
$sheet->setCellValue('A1', 'Zeitstempel');
$sheet->setCellValue('B1', 'Ort');
$sheet->setCellValue('C1', 'Brücken');
$sheet->setCellValue('D1', 'Programmbezeichnung');
$sheet->setCellValue('E1', 'Notizen');
// Durch das Array iterieren und Daten + Bild einfügen
$row = 2; // Start in Zeile 2
foreach ($list as $entry) {
[$timestamp,$place,$bridges,$program_number, $extra, $imagePath] = $entry;
// Namen einfügen
$sheet->setCellValue("A$row", $timestamp);
$sheet->setCellValue("B$row", $place);
$sheet->setCellValue("C$row", $bridges);
$sheet->setCellValue("D$row", $program_number);
$sheet->setCellValue("E$row", $extra);
$svgUrl = $imagePath;
$tmpPng = '../tmp/stecker_' . uniqid() . '.png';
// Bild einfügen, wenn Datei existiert
if (svgUrlToPngViaRsvg($svgUrl, $tmpPng)) {
$drawing = new Drawing();
$drawing->setPath($tmpPng);
$drawing->setCoordinates("F$row");
$drawing->setHeight(80);
$sheet->getRowDimension($row)->setRowHeight(80 * 0.75);
$drawing->setWorksheet($sheet);
} else {
$sheet->setCellValue("F$row", 'Bildkonvertierung fehlgeschlagen');
}
$row++;
}
// Spaltenbreite anpassen
$sheet->getColumnDimension('A')->setAutoSize(true);
$sheet->getColumnDimension('B')->setWidth(20); // Platz fürs Bild
// Datei speichern
$writer = new Xlsx($spreadsheet);
$writer->save('../temp.xlsx');
shell_exec("rm ../tmp/*");
?>
<div class="content-header">Export - Fertig</div>
<hr />
<p>
Ihr Datenexport ist fertig vorbereitet.
</p>
<div class="save-button" onclick="window.location.href='../temp.xlsx'"); "><img src="/vendor/icons/play.svg" \>Herunterladen</div>

15
pagecontent/index.php Executable file
View File

@@ -0,0 +1,15 @@
<?php
// Hauptseite
session_start();
?>
<div class="content-header">Federleiste prüfen</div>
<hr />
<p>Automatische Erkennung</p>
<i>Verbinden Sie den zu messenden Stecker mit dem Gerät. Vermeiden Sie Bewegungen während der Messung.</i>
<div class="save-button" onclick="window.location.href='#start';$('.save-button').html('<img src=\'/vendor/icons/load.gif\' \>Prüfung läuft...'); "><img src="/vendor/icons/play.svg" \>Jetzt prüfen</div>

18
pagecontent/inventory.php Executable file
View File

@@ -0,0 +1,18 @@
<div class="content-header">Bestand</div>
<div class="action-menu">
<img src="/vendor/icons/download.svg" onclick="window.location.href='#export'; $(this).attr('src','/vendor/icons/load.gif'); message('Der Export wird vorbereitet. Das kann etwas dauern...');" />
</div>
<hr />
<div class="search-container">
<input type="text" id="database-search-term" onkeyup="search('program')" placeholder="Programm durchsuchen..." />
<div class="results">
</div>
</div>
<hr />
<div class="inventory-table" id="database-program-search" onload="search('program')">
<div class="save-button" onclick="search('program')"><img src="/vendor/icons/restart.svg" \>Alle Datensätze holen</div>
</div>

1
pagecontent/plug-select.php Executable file
View File

@@ -0,0 +1 @@
Aktuell werden keine verschiedenen Steckerarten unterstützt.

230
pagecontent/program-editor.php Executable file
View File

@@ -0,0 +1,230 @@
<?php
// Diese Seite lädt alle (Unter)Seiten des Programmeditors
session_start();
$db = new SQLite3('../db-test/test.db');
$view = $_GET["view"];
$meta = $_GET["meta"];
$_SESSION["meta"]=$meta;
$plug = json_decode(file_get_contents("../settings.json"), true)["plug"];
switch($view) {
default: // Standardseite (Übersicht)
?>
<div class="content-header">Programm-Editor - Übersicht</div>
<div class="action-menu">
<img src="/vendor/icons/plus.svg" onclick="window.location.href='#program-editor'; pageload('add');" />
</div>
<div class="plug-table">
<?php
// Hole die Programme aus der Datenbank
$result = $db->query("SELECT * FROM programs WHERE plug_id = '" . $plug . "';");
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$results = true;
?>
<div class="row">
<?php
print('
<div class="label" style="width: 30%">
<span>');
// Stelle die einzelnen Programmziffern dar
$program_identifiers = $db->query("SELECT * FROM program_id_bits WHERE program_id = '" . $row['id'] . "';");
while ($program_identifier = $program_identifiers->fetchArray(SQLITE3_ASSOC)) {
echo '<span class="label-char">' . $program_identifier["value"] . '</span>';
}
print('
</span>
</div>');
// Die erforderlichen Brücken werden aus der Datenbank geholt (via program_bridge_relation)
$bridges_url = [];
$bridges = $db->query("SELECT * FROM program_bridge_relation WHERE program_id = '" . $row['id'] . "';");
while ($bridge = $bridges->fetchArray(SQLITE3_ASSOC)) {
$bridges_url[] = $bridge["bridge_id"];
}
$url = '../stecker.php?translate=true&data=' . urlencode(json_encode($bridges_url)); // URL parsen; Modus: Programmanzeige
print('<img id="bridge-editor-img" style="width: 55%" src="' . $url . '" />');
// Aktionsmenü (mit hässlichem Inline-Code)
print('
<div class="options">
<img src="/vendor/icons/edit-pencil.svg" onclick="window.location.href=\'#program-editor\'; pageload(\'edit\',\'' . $row['id'] . '\');"/>
<img src="/vendor/icons/trash.svg"onclick="
if(confirm(\'Sicher? Diese Änderung kann nicht rückgängig gemacht werden! (Die darin enthaltenen Brücken bleiben erhalten und werden nicht gelöscht )\') == true){
save(\'program-editor\',\'remove\',\'' . $row['id'] . '\')
}" />
</div>
');
?>
</div>
<?php
}
?>
</div>
<?php
// Wenn Ergebnisliste leer
if($results != true) {
print("<p align='center'>Es sind keine Programme für diesen Stecker gespeichert.<br>Eventuell muss ein anderer Stecker gewählt werden.</p>");
}
break;
// Neues Hinzufügen eines Programms
case "add":
$meta = json_decode(urldecode($meta), true);
?>
<div class="content-header">Programm-Editor - Neu anlegen</div>
<img id="program-editor-img" src="../stecker.php" />
<hr />
<p>Zugehörige Brücken</p>
<i>Wählen Sie die Brücken, welche von diesem Programm gefordert werden</i>
<div class="program-field">
<?php
//zählen der Ergebnisse
$result = $db->query("SELECT COUNT(*) as anzahl FROM bridges WHERE plug_id = '" . $plug . "';");
$row = $result->fetchArray(SQLITE3_ASSOC);
$results_full = $row['anzahl'];
$count = 0;
// Holen der Ergebnisse
$result = $db->query("SELECT * FROM bridges WHERE plug_id = '" . $plug . "';");
// Zeigt ein horizonales Auswhl-Menü an, das alle Brücken als auswahl bietet
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
?>
<label class="checkbox-container">
<input onchange="programBridge(<?php echo $results_full; ?>)" type="checkbox" id="programSelect_<?php echo $count; ?>" value="<?php echo $row['id']; ?>">
<span class="checkbox-text">
<?php echo $row['id']; ?>
</span>
</label>
<?php
$count++;
}
?>
</div>
<hr />
<p>Name für dieses Programm</p>
<i>
Hinweis: Der Name kann aus Sicherheitsgründen im Nachhinein nicht mehr geändert werden. Bei dieser Stellwerksart ist die ID fünfstellig<br>Ein '-' kennzeichnet ein "Don't-Care". Darüber hinaus sind nur Großbuchstaben und Zahlen zugelassen
</i>
<div class="distinctly-input">
<input oninput="distinctlyInput(1)" type="text" maxlength="1" class="code-input" id="distinctlyInput1">
<input oninput="distinctlyInput(2)" type="text" maxlength="1" class="code-input" id="distinctlyInput2">
<input oninput="distinctlyInput(3)" type="text" maxlength="1" class="code-input" id="distinctlyInput3">
<input oninput="distinctlyInput(4)" type="text" maxlength="1" class="code-input" id="distinctlyInput4">
<input oninput="distinctlyInput(5)" type="text" maxlength="1" class="code-input" id="distinctlyInput5">
</div>
<hr />
<p>Beschreibung für dieses Programm</p>
<textarea id="program-description" placeholder="Wählen Sie eine möglichst präzise Beschreibung. Zum Beispiel: 'Relaisgruppe für eine nicht isolierte Weiche, die eine einfache Kreuzungsweiche mit Bogenfahrt über den Plusstrang ist'"></textarea>
<hr />
<div class="save-button" onclick="save('program-editor','add',<?php echo $results_full; ?>)"><img src="/vendor/icons/floppy-disk.svg" \>Speichern</div>
<?php
break;
case "edit":
$meta = json_decode(urldecode($meta), true);
?>
<div class="content-header">Programm-Editor - Bearbeiten</div>
<?php
$bridges_url = [];
$bridges = $db->query("SELECT * FROM program_bridge_relation WHERE program_id = '" . $meta . "';");
while ($bridge = $bridges->fetchArray(SQLITE3_ASSOC)) {
$bridges_url[] = $bridge["bridge_id"];
}
$url = '../stecker.php?translate=true&data=' . urlencode(json_encode($bridges_url)); // URL parsen
print('<img id="program-editor-img" src="../stecker.php?translate=true&data=' . $url . '" />');
?>
<hr />
<p>Zugehörige Brücken</p>
<i>Wählen Sie die Brücken, welche von diesem Programm gefordert werden</i>
<div class="program-field">
<?php
// Hole Anzahl der Brücken aus der DB
$number_bridges = $db->query("SELECT COUNT(*) as anzahl FROM bridges WHERE plug_id = '" . $plug . "';");
$number_bridges = $number_bridges->fetchArray(SQLITE3_ASSOC);
$number_bridges = $number_bridges['anzahl'];
$number_joined = 0;
// Hole zunächst ALLE Brücken aus der DB
$bridges = $db->query("SELECT * FROM bridges WHERE plug_id = '" . $plug . "';");
while ($bridge = $bridges->fetchArray(SQLITE3_ASSOC)) {
// schaue nun, ob diese Brücke Teil des Programms ist
$bridges_contained = $db->query("SELECT COUNT(*) as anzahl FROM program_bridge_relation WHERE plug_id = '" . $plug . "' and bridge_id = '" . $bridge["id"] . "' and program_id = '" . $meta . "';");
$row = $bridges_contained->fetchArray(SQLITE3_ASSOC);
$number = $row['anzahl'];
// Die Anzahl gibt Aufschlus darüber, ob Brücke von Programm gefordert ist -> wenn schon vorhanden, markiere diese Brücke schon vor ("checked"-Attribut)
?>
<label class="checkbox-container">
<input onchange="programBridge(<?php echo $number_bridges; ?>)" type="checkbox" <?php if($number > 0) { echo "checked"; } ?> id="programSelect_<?php echo $number_joined; ?>" value="<?php echo $bridge["id"]; ?>">
<span class="checkbox-text">
<?php echo $bridge["id"]; ?>
</span>
</label>
<?php
$number_joined++;
}
?>
</div>
<hr />
<p>Name für dieses Programm</p>
<i>Darf auf Sicherheitsgründen nicht mehr geändert werden</i>
<div class="distinctly-input">
<?php
// Hole die ganzen Programmbezeichner raus aus der DB
$program_identifiers = $db->query("SELECT * FROM program_id_bits WHERE program_id = '" . $meta . "' ORDER BY position;");
while ($program_identifier = $program_identifiers->fetchArray(SQLITE3_ASSOC)) {
echo '<input type="text" maxlength="1" value="' . $program_identifier["value"] . '" disabled class="code-input">';
}
// Vorausgefüllte Programmbezeichnung
$description = ($row = $db->querySingle("SELECT program_description FROM programs WHERE id = '$meta' and plug_id = '$plug'", true)) ? $row['program_description'] : null;
?>
</div>
<hr />
<p>Beschreibung für dieses Programm</p>
<textarea id="program-description" value="Value" placeholder="Wählen Sie eine möglichst präzise Beschreibung. Zum Beispiel: 'Relaisgruppe für eine nicht isolierte Weiche, die eine einfache Kreuzungsweiche mit Bogenfahrt über den Plusstrang ist'"><?php echo $description; ?></textarea>
<hr />
<div class="save-button" onclick="save('program-editor','edit',<?php echo $number_bridges; ?>)"><img src="/vendor/icons/floppy-disk.svg" \>Speichern</div>
<?php
break;
}

131
pagecontent/selfcheck.php Executable file
View File

@@ -0,0 +1,131 @@
<?php
session_start();
error_reporting(E_ALL);
ini_set('display_errors', 1);
require("../functions.php");
$view = $_GET["view"];
$meta = $_GET["meta"];
$_SESSION["meta"] = $meta;
if ($view == "results") {
//Befehl zum Starten des Skripts
$command = escapeshellcmd('python3 /var/www/html/python/selfcheck.py');
//output und bridges sind die Ergebnisse des Durchlaufs
$output = json_decode(shell_exec($command), true);
$bridges = $output["data"];
//Zeigt schon der Erste durchlauf Fehler auf, kann abgebrochen werden (1. Fehlerfall)
if($output["logs"]["errorcode"] != 10) {
?>
<h3>
Die Prüfung konnte nicht abgeschlossen werden. <i>Fehler <?php echo $output["logs"]["errorcode"]; ?></i>
</h3>
<?php
include("../errorcodes.php");
die();
}
// Isoliere die Brücken und speichere sie als $bridges (hiermit wird später alles weitere verarbeitet)
$bridges = array_map(function($entry) {
return $entry[0];
}, $output["data"]);
//Isoliere die Fehlercodes der ersten Messung; da Messungen identisch reicht erste Messung
$errors = array_filter($output["data"], function($entry) {
return $entry[1] !== 0;
});
//Wenn Fehlerspeicher gefüllt: Ausgabe und Abbruch
if (!empty($errors)) {
measurementsContainErrors($output["data"]);
}
?>
<div class="content-header">Selbstdiagnose - Ergebnisse</div>
<hr />
<style>
table {
font-size: 12px;
line-height: 10px;
}
td {
width: 2.5%;
border: 1px solid black;
}
</style>
<hr>
<h2>Detailansicht</h2>
<p>Der Pin der jeweiligen Spalte wird eingeschaltet; Pins, welche einen Eingang registrieren, werden in der entsprechenden Zeile grün dargestellt.</p>
<table>
<?php
// Kopfzeile
echo "<tr>";
for ($j = 0; $j <= 32; $j++) {
$index = $j - 1;
if ($index == -1) {
echo "<td></td>";
} else {
echo "<td>$index</td>";
}
}
echo "</tr>";
// Matrix
for ($i = 0; $i <= 31; $i++) {
echo "<tr>";
echo "<td>$i</td>";
for ($j = 0; $j <= 31; $j++) {
$search = [$j, $i];
if (in_array($search, $bridges)) {
echo "<td style='color: green;'>&#10004;</td>";
} else {
echo "<td style='color: gray;'>-</td>";
}
}
echo "</tr>";
}
?>
</table>
<hr />
<?php
print("<p>Erklärung:<br>
Jede Verbindung darf nur einmal aufgeführt sein. Gibt es Doppelungen, so besteht eine unzulässige Verbindung zu einem anderen Pin.
Kann sich ein Pin nicht selbst auslesen, so weist dies auf einen internen Kabelbruch oder ein defektes Bauteil hin.
Ist der Fehler spiegelsymmetrisch (z.B. 10-20 und 20-10), deutet dies auf einen Kurzschluss im System hin.
Tritt der Fehler nur einseitig auf, ist ein Bauteil defekt.</p>");
?>
<div class="save-button" onclick="window.location.href='#selfcheck'; pageload();$('.save-button').html('<img src=\'/vendor/icons/load.gif\' \>Bitte warten...');">
<img src="/vendor/icons/nav-arrow-left.svg">Zurück
</div>
<?php
} else {
?>
<div class="content-header">Selbstdiagnose</div>
<p>Sollten während Messungen Fehler aufgetreten sein, kann hier eine interne Diagnose durchgeführt werden. Dabei wird jeder "Pin" einmalig als Ausgang gesetzt und gleichzeitig der Wert ausgelesen. Nur, wenn der Pin selbst gelesen werden kann und keine unzulässigen Verbindungen zu anderen Pins bestehen, wird die Prüfung erfolgreich abgeschlossen.</p>
<hr />
<p><i>Bitte trennen Sie zuvor alle Verbindungen, sodass sich das Gerät im Leerlauf befindet. <b>Angeschlossene Kabel und Stecker verfälschen das Ergebnis!</b></i></p>
<hr />
<div class="save-button" onclick="window.location.href='#selfcheck'; pageload('results');$('.save-button').html('<img src=\'/vendor/icons/load.gif\' \>Bitte warten...');">
<img src="/vendor/icons/ecg-monitoring-icon.svg">Selbstdiagnose ausführen
</div>
<?php
}
?>

122
pagecontent/start-cable.php Executable file
View File

@@ -0,0 +1,122 @@
<?php
session_start();
require("../functions.php");
error_reporting(E_ALL);
ini_set('display_errors', 1);
$db = new SQLite3('../db-test/test.db');
//Befehl zum Starten des Skripts
$command = escapeshellcmd('python3 /var/www/html/python/cable-check.py');
//output1 und bridges1 sind die Ergebnisse des ersten Durchlaufs
$output1 = json_decode(shell_exec($command), true);
$bridges1 = $output1["data"];
//Zeigt schon der Erste durchlauf Fehler auf, kann abgebrochen werden (1. Fehlerfall)
if($output1["logs"]["errorcode"] != 10) {
?>
<h3>
Die Prüfung konnte nicht abgeschlossen werden. <i>Fehler <?php echo $output1["logs"]["errorcode"]; ?></i>
</h3>
<?php
include("../errorcodes.php");
die();
}
//wenn bis hierhin ok: weitere Prüfung
$output2 = json_decode(shell_exec($command), true);
$bridges2 = $output2["data"];
//Die Messungen sind nicht identisch (egal ob wg Fehlercodes oder Daten, ungleiche Messungen sind immer schlecht) -> 2. Fehlerfall
//es wäre schon sehr eigenartig, wenn verschiedene Fehlercodes nacheinander ausgespuckt würden (Wackelkontakt?)
if($bridges1 !== $bridges2) {
measurementsDiffer($bridges1, $bridges2);
}
// Isoliere die Brücken und speichere sie als $bridges (hiermit wird später alles weitere verarbeitet)
$bridges = array_map(function($entry) {
return $entry[0];
}, $bridges1);
//Isoliere die Fehlercodes der ersten Messung; da Messungen identisch reicht erste Messung
$errors = array_filter($bridges1, function($entry) {
return $entry[1] !== 0;
});
//Wenn Fehlerspeicher gefüllt: Ausgabe und Abbruch
if (!empty($errors)) {
measurementsContainErrors($bridges1);
}
// ----------
//Ab hier wird die Logik geprüft, die Messung ist bis hierhin äußerlich in Ordnung
// ----------
$bridges = translateArray($bridges, $translationMap, $translationMap2);
$cleaned_output = [];
$errors = [];
$ok = true;
// iteriere durch die Messung und prüfe, ob stets gilt [[20,20],[22,22]]
//wenn nein: Kurzschluss ($errors)
foreach($bridges as $bridge) {
if($bridge[0] == $bridge[1]) {
$cleaned_output[] = $bridge[0];
}
else {
$ok = false;
$errors[] = $bridge;
}
}
//Haupt-Steckergrafik
$url = 'stecker.php?mode=fill&data=' . urlencode(json_encode($cleaned_output));
?>
<div class="content-header">Ergebnis</div>
<hr />
<h2>Vollständigkeit</h2>
<p><i>Die folgende Grafik zeigt Ihnen, auf welchen Adern eine durchgängige Verbindung erkannt wurde. Nur, wenn alle Pins grün gefüllt sind, ist das Spurkabel in Ordnung!</i></p>
<img src="<?php echo $url; ?>" />
<?php
$url = 'stecker.php?data=' . urlencode(json_encode($errors)); // Kodiert es für die URL
?>
<h2>Unzulässigkeiten</h2>
<p><i>Die folgende Grafik zeigt Ihnen, auf welchen Adern eine Verbindung zu einer anderen Ader erkannt wurde. Ist die Grafik leer, sind alle Adern korrekt isoliert.</i></p>
<?php
if($ok != true) {
?>
<p style='color: red !important'>
Es wurde mindestens ein Kurzschluss gefunden!
</p>
<?php
}
?>
<img src="<?php echo $url; ?>" />
<div class="save-button" onclick="window.location.href='#cable-check';"><img src="/vendor/icons/nav-arrow-left.svg" \>Zurück</div>

625
pagecontent/start.php Executable file
View File

@@ -0,0 +1,625 @@
<?php
session_start();
require("../functions.php");
error_reporting(E_ALL);
ini_set('display_errors', 1);
$db = new SQLite3('../db-test/test.db');
//Befehl zum Starten des Skripts
$command = escapeshellcmd('python3 /var/www/html/python/observer-full.py');
//output1 und bridges1 sind die Ergebnisse des ersten Durchlaufs
$output1 = json_decode(shell_exec($command), true);
$bridges1 = $output1["data"];
//Zeigt schon der Erste durchlauf Fehler auf, kann abgebrochen werden (1. Fehlerfall)
if($output1["logs"]["errorcode"] != 10) {
?>
<h3>
Die Prüfung konnte nicht abgeschlossen werden. <i>Fehler <?php echo $output1["logs"]["errorcode"]; ?></i>
</h3>
<?php
include("../errorcodes.php");
die();
}
//wenn bis hierhin ok: weitere Prüfung
$output2 = json_decode(shell_exec($command), true);
$bridges2 = $output2["data"];
//Die Messungen sind nicht identisch (egal ob wg Fehlercodes oder Daten, ungleiche Messungen sind immer schlecht) -> 2. Fehlerfall
//es wäre schon sehr eigenartig, wenn verschiedene Fehlercodes nacheinander ausgespuckt würden (Wackelkontakt?)
if($bridges1 !== $bridges2) {
measurementsDiffer($bridges1, $bridges2);
}
// Isoliere die Brücken und speichere sie als $bridges (hiermit wird später alles weitere verarbeitet)
$bridges = array_map(function($entry) {
return $entry[0];
}, $bridges1);
//Isoliere die Fehlercodes der ersten Messung; da Messungen identisch reicht erste Messung
$errors = array_filter($bridges1, function($entry) {
return $entry[1] !== 0;
});
//Wenn Fehlerspeicher gefüllt: Ausgabe und Abbruch
if (!empty($errors)) {
measurementsContainErrors($bridges1);
}
// ----------
//Ab hier wird die Logik geprüft, die Messung ist bis hierhin äußerlich in Ordnung
// ----------
//Hier wird jetzt geprüft, dass jede Messung bidirektional aufgenommen wurde, also 10<>20 UND 20<>10
$doubles = []; // Array zur Verfolgung von Doppelungen
$errors = []; // Array für fehlende Doppelungen
// Untersuche die einzelnen aufgenommenen Messpaare
foreach ($bridges as $pair) {
// Jedes Paar MUSS aus zwei Elementen bestehen
if (count($pair) !== 2) {
$errors[] = $pair; // speichere diesen fehlerhaften Eintrag
continue;
}
// Sortiere die Paare, um [23,14] und [14,23] gleich zu behandeln
sort($pair);
// Setze dieses Paar als "Index", um es gleich wieder zu finden
$key = implode("-", $pair);
// Prüfe, ob dieser Eintrag schon einmal da war
if (isset($doubles[$key])) {
$doubles[$key]++; // Verbindung erneut gefunden
}
else {
$doubles[$key] = 1; // Erstmaliges Auftreten
}
}
// Überprüfe, ob jede Verbindung genau zweimal vorhanden ist
foreach ($doubles as $key => $count) {
if ($count !== 2) {
$errors[] = $key;
}
}
// Abbruch bei fehlenden Doppelungen
if (!empty($errors)) {
echo "Die Messung wurde zwar erfolgreich abgeschlossen, die Messergebnisse überzeugten jedoch nicht.<br>Es ist notwendig, dass Kabelbrücken aus beiden Richtungen erkannt werden.<br>Erwägen Sie, eine erneute Messung durchzuführen. Sollte der Fehler erneut auftreten, ist ein interner Defekt des Prüfgeräts wahrscheinlich.<br><br>Die folgende(n) Kabelbrücke(n) konnte(n) nur one-way gemessen werden: <br>";
print_r($errors);
?>
<div class="save-button" onclick="window.location.href='#index'; pageload();$('.save-button').html('<img src=\'load.gif\' \>Bitte warten...');"><img src="/vendor/icons/nav-arrow-left.svg" \>Zurück</div>
<?php
die(); // Skript abbrechen
}
// ----------
//Die Messung ist valide. Es kann ausgegeben werden
// ----------
// Bereinigung der doppelten Einträge
$unique = []; // Array für eindeutige Verbindungen
$seen = []; // Array zur Verfolgung bereits bearbeiteter Verbindungen
foreach ($bridges as $pair) {
// Sortiere das Paar
sort($pair);
$key = implode("-", $pair);
// Füge nur ein Exemplar hinzu
if (!isset($seen[$key])) {
$unique[] = $pair;
$seen[$key] = true; // Markiere als verarbeitet
}
}
//Wichtigste Variable - sieht z.b. so aus: [[20,30],[10,15]] - redundanzfrei und aufsteigend sortiert
$measurement_result = translateArray($unique, $translationMap);
$measurement_result_number = count($measurement_result); // Anzahl gemessener Brücken
//Haupt-Steckergrafik
$url = 'stecker.php?data=' . urlencode(json_encode($measurement_result));
?>
<div class="content-header">Ergebnis</div>
<hr />
<div class="toggle-switch">
<div align="right"><p>Gesamtergebnis</p></div>
<div>
<label class="switch">
<input type="checkbox" onchange='$("#op-1").toggle(this.unchecked);$("#op-2").toggle(this.checked);'>
<span class="slider"></span>
</label>
</div>
<div align="left">
<p>Einzelbrücken</p>
</div>
</div>
<div id="op-1">
<img src="<?php echo $url; ?>" />
</div>
<div id="op-2" style="display: none;">
<?php
foreach($measurement_result as $bridge) {
// Hier muss der übertragene Wert unschön manuell in [] gesetzt werden, da ein äußeres, indexiertes Array erwartet wird...
?>
<img style="margin-bottom: 5px;" src="<?php echo 'stecker.php?data=' . urlencode("[" . json_encode($bridge) . "]"); ?>" />
<?php
}
?>
</div>
<hr />
<h2>Identifizierte Brücken</h2>
<?php
//Hole aktuellen Stecker aus der JSON-Datei
$settings = json_decode(file_get_contents("../settings.json"), true);
$plug = $settings["plug"];
$identified_bridges = [];
//Hole alle Nodes via JOIN aus der Dankebak
$nodes = $db->query("
SELECT
b.id AS bridge_id,
n.node_from,
n.node_to
FROM
bridges b
JOIN
nodes n ON b.id = n.required_by
ORDER BY
b.id
");
/*
Ausgabe sieht z.B. so aus:
| bridge_id | node_from | node_to |
| --------- | --------- | ------- |
| 1 | 20 | 30 |
| 1 | 13 | 17 |
| 2 | 10 | 15 |
*/
//die DB-ausgbe wird als indexiertes Array gespeichert, um einfacher durchsucht werden zu können
$bridges_db = [];
while ($row = $nodes->fetchArray(SQLITE3_ASSOC)) {
//Die Bridge-ID ist der Index, die geforderten Brücken werden im Standardformat eingefügt, z.B.: 1 => [[20,30],[13,17]]
$bridge_id = $row['bridge_id'];
$bridges_db[$bridge_id][] = [$row['node_from'], $row['node_to']];
}
//Vergleiche Datenbank mit gemessenen Werten
//iteriere durch alle Datenabnk-Brücken
foreach($bridges_db as $bridge_db => $required_nodes) {
$satisfied = true;
//iteriere durch alle von einer Brücke geforderten Node-Paare
foreach($required_nodes as $required_nodes_pairs) {
$innerMatch = 0;
// vergleiche die aktuelle Datenbank-Node mit allen gemessenen Nodes (+überkreuz)
for($i=0;$i<$measurement_result_number;$i++) {
if(($required_nodes_pairs[0] == $measurement_result[$i][0] && $required_nodes_pairs[1] == $measurement_result[$i][1] )||($required_nodes_pairs[1] == $measurement_result[$i][0] && $required_nodes_pairs[0] == $measurement_result[$i][1])){
// innerhalb der Node-zu-Node-Verbidnung wurde die Bedingung erfüllt
$innerMatch = 1;
}
}
if($innerMatch != 1) {
// An dieser Stelle wird satisfied direkt negiert, da mind. eine Abhängigkeit, die in der Datenbank gefordert ist, nicht gefunden wurde
$satisfied = false;
}
}
// Kommen alle Nodes vor, wird die Brücke mit ihrem entsprechenden Namen dargestellt
if($satisfied == true) {
//Brücke vollständig enthalten -> speichern für später (Programm-Erkennung)
$identified_bridges[] = $bridge_db;
//Erinnerung: es gilt bridge_db=>bridges_db
$url = '../stecker.php?data=' . urlencode(json_encode($bridges_db[$bridge_db])); // URL parsen
?>
<div class="row">
<?php
print('<div class="label"><span>' . $bridge_db . '</span></div>');
print('<img id="bridge-editor-img" src="' . $url . '" />');
?>
</div>
<?php
}
}
//Speicher für identifizierte Programme
$identified_programs = [];
//Hole Programme aus der Datenbank (via program_bridge_relation)
$programs = $db->query("
SELECT
p.id AS program_id,
p.program_description,
b.id AS bridge_id,
r.plug_id
FROM
program_bridge_relation r
JOIN programs p ON p.id = r.program_id
JOIN bridges b ON b.id = r.bridge_id
WHERE r.plug_id = '" . $plug . "'
");
/*
Ausgabe sieht z.B. so aus:
| program_id | program_description | bridge_id |
| ---------- | ------------------- | --------- |
| 1 | Weiche, die... | 1 |
| 2 | Gs, die... | 1 |
| 2 | Gs, die... | 10 |
*/
$bridges_db = [];
while ($row = $programs->fetchArray(SQLITE3_ASSOC)) {
// Gleiches vorgehen wie bei den Brücken: Programm-ID ist Index, Brücken sind Inhalt (2 => [1,10])
$program_id = $row['program_id'];
$programs_db[$program_id][] = $row['bridge_id'];
$program_descriptions[$program_id] = $row['program_description'];
}
//Ist eine Stelle der Kennung des Programmsteckers zwischendrin doppelt beschrieben woren, wird idse Variable wahr
$double_program_identifier = false;
?>
<hr />
<h2>Identifizierte Programme</h2>
<div class="plug-table">
<?php
$program_cache = ["?","?","?","?","?"]; // Die Steckerbezeichnung ist zu Beginn noch unbestimmt
//iteriere durch alle DB-Programme
foreach($programs_db as $program_db => $required_bridges) {
if(!empty($identified_bridges)) { //Abscicherung, sonst würde ein leeres Programm immer als vollständig enthalten markiert werden
$ok = 1;
}
else {
$ok = 0;
}
// Iteriere durch alle geforderten Brücken
foreach ($required_bridges as $bridge_id) {
// sollte sich eine Programmbrücke nicht unter den identifizierten Messwerte befinden -> ok=0
if (!in_array($bridge_id, $identified_bridges)) {
$ok = 0;
}
}
// Programm ist mit allen Brücken vollständig vertreten
if($ok == 1) {
?>
<div class="row">
<div class="label" style="width: 30%">
<span>
<?php
// Stelle die einzelnen Programmziffern dar, indemdiese aus der DB geladen werden
$program_identifiers = $db->query("SELECT * FROM program_id_bits WHERE program_id = '" . $program_db . "' ORDER BY position;");
while ($program_identifier = $program_identifiers->fetchArray(SQLITE3_ASSOC)) {
echo '<span class="label-char">' . $program_identifier["value"] . '</span>';
if($program_identifier["value"] != "" && $program_identifier["value"] != "-") { // wenn noch nicht anders beschrieben oder leer -> Einfügen in großen "Gesamtspeicher" für später
if($program_cache[$program_identifier["position"]] == "?") {
$program_cache[$program_identifier["position"]] = $program_identifier["value"];
}
else {
// Wenn Stelle schon gesetzt war -> Warnung speichern
$double_program_identifier = true;
}
}
$i++;
}
?>
</span>
</div>
<?php
$url = '../stecker.php?translate=true&data=' . urlencode(json_encode($required_bridges)); // URL parsen
print('<img id="bridge-editor-img" style="width: 55%" src="' . $url . '" />');
?>
</div>
<div class="row" style="position: relative;box-sizing: border-box;padding-left: 45px;">
<img style="max-height: 100%;width: auto;display: inline-block;filter: opacity(.5);position: absolute;left:10px" src="/vendor/icons/info-circle.svg" style=" top: 2.5px;left: 10px;">
<?php echo $program_descriptions[$program_db]; ?>
</div>
<?php
}
}
?>
</div>
<hr />
<h2>Kennungs-Nummer</h2>
<div class="plug-table" style="margin-bottom: 0;">
<div class="row">
<div class="label" style="width: 180px;float: none">
<span>
<?php
// Die Gesamt-Kennung-Nummer wurde zuvor von den identifizierten Programmen bestimmt und wird hier ausgegeben
$ok = 1;
foreach($program_cache as $cacheChar) {
echo '<span class="label-char">' . $cacheChar . '</span>';
if($cacheChar == "?") {
$ok = 0;
}
}
?>
</span>
</div>
</div>
</div>
<?php
if($ok != 1) {
?>
<p style='color: red !important'>
Wichtiger Hinweis: Es sind nicht alle Stellen der Kennungsnummer definiert. Dies deutet darauf hin, dass möglicherweise nicht alle Programme des Steckers korrekt erkannt wurden. Andererseits kann auch die Programm-Datenbank unvollständig sein, sodass eine Erkennung nicht möglich ist.<br>Betrachten Sie daher das Ergebnis mit Vorsicht!
</p>
<?php
}
if ($double_program_identifier == true) {
?>
<p style='color: red !important'>
Wichtiger Hinweis: Im Laufe der Programmabgleiche wurde versucht, eine Stelle der Gesamtkennungsnummer zu übeschreiben, da diese bereits durch ein vorheriges Programm festgelegt wurde. Details dazu finden Sie unter "Indentifizierte Programme". Bitte gleichen Sie die Spalten ab, ob eine doppelte Stellendefinition vorliegt!<br>Betrachten Sie daher das Ergebnis mit Vorsicht!
</p>
<?php
}
?>
<hr />
<h2>Identische Messungen</h2>
<div class="inventory-table">
<?php
//Hole vorherige Messungen aus der DB
$measurement_nodes_db = $db->query("
SELECT
m.id AS measurement_id,
m.comment AS comment,
m.timestamp AS timestamp,
m.place_name AS place_name,
n.node_from AS node_from,
n.node_to AS node_to
FROM
measurements m
JOIN places p ON p.name = m.place_name
JOIN measurement_nodes n ON m.id = n.required_by
ORDER BY m.id
");
/*
Ausgabe sieht z.B. so aus:
| measurement_id | comment | timestamp | place_name | node_from | node_to |
| -------------- | ------- | ---------- | -------------------- | --------- | ------- |
| 1 | abc | 1753357680 | Mannheim-Waldhof Wf | 20 | 26 |
| 1 | abc | 1753357680 | Mannheim-Waldhof Wf | 13 | 16 |
| 1 | abc | 1753357680 | Mannheim-Waldhof Wf | 30 | 35 |
| 2 | def | 1753357548 | Dudweiler Df | 30 | 35 |
| 2 | def | 1753357548 | Dudweiler Df | 10 | 12 |
*/
// Auch hier werden alle Messungen erstmal komplex indexiert (also zwei ineinander indexierte Arrays): measurement_id=>(nodes=>[[30,35],[10,12]], place_name, timestamp, comment)
$measurements_db = [];
while ($row = $measurement_nodes_db->fetchArray(SQLITE3_ASSOC)) {
$measurement_id = $row['measurement_id'];
$measurements_db[$measurement_id]['nodes'][] = [$row['node_from'],$row['node_to']];
$measurements_db[$measurement_id]['place_name'] = $row['place_name'];
$measurements_db[$measurement_id]['timestamp'] = $row['timestamp'];
$measurements_db[$measurement_id]['comment'] = $row['comment'];
}
//Indikator, dass alle Brücken gefunden wurden
$ok = 0;
foreach ($measurements_db as $measurement_db) {
$satisfied = true;
foreach ($measurement_result as $bridge_measure) {
$found = false;
foreach ($measurement_db["nodes"] as $measurement_db_node) {
// Prüfe, ob Brücke identisch (+ überkreuz)
if (
($bridge_measure[0] == $measurement_db_node[0] && $bridge_measure[1] == $measurement_db_node[1]) ||
($bridge_measure[0] == $measurement_db_node[1] && $bridge_measure[1] == $measurement_db_node[0])
) {
$found = true; // Brücke gefunden
break; // Nächste Brücke prüfen
}
}
if (!$found) {
// Diese Brücke nicht in DB gefunden -> Messung nicht erfüllt
$satisfied = false;
break; // weitere Brücken prüfen sinnlos
}
}
if ($satisfied) {
$ok = 1;
?>
<div class="row">
<img src="/vendor/icons/map-pin.svg" class="map">
<span>
<?php
echo $measurement_db["place_name"];
?>
</span>
<?php
if(!empty($measurement_db["comment"])) {
?>
<img src="/vendor/icons/info-circle.svg" style="top: 30px;" class="map">
<span>
<?php
echo $measurement_db["comment"];
?>
</span>
<?php
}
?>
<div class="plug-table" style="display: block;">
<div class="row" style="margin-bottom:0; height: 57px;">
<div>
<div class="label" style="width: 100%;height:auto;">
<span>
<?php
echo "Messung vom/um <b>" . date('d.m.Y H:i:s',$measurement_db["timestamp"]) . "</b>";
?>
</span>
</div>
</div>
</div>
</div>
</div>
<?php
}
}
?>
</div>
<?php
//Wenn keine Messungen gefunden:
if($ok == 0) {
?>
<p>Keine bekannt.</p>
<?php
}
?>
<hr />
<h2>Anpassen der Ergebnisse</h2>
<table class="simple-devider">
<tr>
<td>
<h3>Kennungs-Nr.</h3>
</td>
<td>
<div class="distinctly-input" style="width: 100%;">
<input oninput="distinctlyInput(1)" type="text" maxlength="1" value="<?php echo $program_cache[0]; ?>" class="code-input" id="distinctlyInput1">
<input oninput="distinctlyInput(2)" type="text" maxlength="1" value="<?php echo $program_cache[1]; ?>" class="code-input" id="distinctlyInput2">
<input oninput="distinctlyInput(3)" type="text" maxlength="1" value="<?php echo $program_cache[2]; ?>" class="code-input" id="distinctlyInput3">
<input oninput="distinctlyInput(4)" type="text" maxlength="1" value="<?php echo $program_cache[3]; ?>" class="code-input" id="distinctlyInput4">
<input oninput="distinctlyInput(5)" type="text" maxlength="1" value="<?php echo $program_cache[4]; ?>" class="code-input" id="distinctlyInput5">
</div>
</td>
</tr>
<tr>
<td>
<h3>Sekundärbrücken abwählen</h3>
</td>
<td>
<div class="program-field">
<?php
$i = 0;
$count = count($measurement_result);
foreach ( $measurement_result as $bridge) {
?>
<label class="checkbox-container">
<input checked onchange="excludeBridge(<?php echo $count; ?>)" type="checkbox" id="programSelect_<?php echo $i; ?>" value='[<?php echo $bridge[0] . "," . $bridge[1]; ?>]'>
<span class="checkbox-text">
<?php echo $bridge[0] . "-" . $bridge[1]; ?>
</span>
</label>
<?php
$i++;
} ?>
</div>
</td>
</tr>
<tr>
<td colspan="2">
<img id="result-editor-result" src="../stecker.php" />
</td>
</tr>
<tr>
<td>
<h3>Besonderheiten</h3>
</td>
<td>
<textarea id="database-special" style="height: 80px;" placeholder="z.B. + Brücke 45, - Brücke 13"></textarea>
</td>
</tr>
</table>
<hr />
<h2>Speichern unter...?</h2>
<div class="search-container">
<input type="text" id="database-search-term" onkeyup="search('results')" placeholder="Beginnen Sie zu tippen..." />
<div class="save-button" onclick="save('inventory','add');"><img src="/vendor/icons/floppy-disk.svg" \></div>
<?php
// Speichern für "action/inventory.php"
$_SESSION["bridges"] = $measurement_result;
?>
<input type="hidden" id="database-bridges" value="<?php echo urlencode(json_encode($measurement_result)); ?>" />
<input type="hidden" id="database-bridges-hidden" value="" />
<div class="results"></div>
</div>
<p>
<i>Die dargestellten Vorschläge befinden sich bereits in der Datenbank. Geben Sie einen Ort sein, der noch nicht in der Datenbank vorhanden ist, so wird dieser automatisch erstellt</i>
</p>
<hr />
<div class="save-button" onclick="if (window.confirm('Das Messergebnis wird verworfen, sollte es nicht gespeichert worden sein. Fortfahren?')) { window.location.href='#index'; pageload();$('.save-button').html('<img src=\'load.gif\' \>Bitte warten...');}"><img src="/vendor/icons/nav-arrow-left.svg" \>Zurück</div>

124
pagecontent/stecker.php Executable file
View File

@@ -0,0 +1,124 @@
<?php
// Setze den Content-Type-Header für SVG
header('Content-Type: image/svg+xml');
echo '<?xml version="1.0" encoding="UTF-8"?>';
?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="500" height="100">
<defs>
<style>
@font-face {
font-family: LexendDecaBold;
src: url(http://192.168.37.103/vendor/fonts/LexendDeca-Bold.ttf);
}
* {
font-family: LexendDecaBold;
font-size: 14px;
}
</style>
</defs>
<text x="30" y="5" fill="black" text-anchor="middle" transform="translate(50,50) rotate(-90)">30</text>
<text x="-30" y="5" fill="black" text-anchor="middle" transform="translate(50,50) rotate(-90)">10</text>
<text x="30" y="405" fill="black" text-anchor="middle" transform="translate(50,50) rotate(-90)">31</text>
<text x="-30" y="405" fill="black" text-anchor="middle" transform="translate(50,50) rotate(-90)">11</text>
<path d="M500 0 L50 0" style="stroke:black;stroke-width:5; fill:none;" />
<path d="M50 0 L0 25" style="stroke:black;stroke-width:3; fill:none;" />
<path d="M0 25 L0 75" style="stroke:black;stroke-width:5; fill:none;" />
<path d="M0 75 L50 100" style="stroke:black;stroke-width:3; fill:none;" />
<path d="M50 100 L500 100" style="stroke:black;stroke-width:5; fill:none;" />
<path d="M500 100 L500 0" style="stroke:black;stroke-width:5; fill:none;" />
<rect width="35" height="35" x="452" y="32" rx="5" ry="5" style="stroke:black;stroke-width:3;fill:none" />
<circle r="8" cx="470" cy="50" fill="none" style="stroke:black;stroke-width:3;" />
<rect width="35" height="35" x="13" y="32" rx="5" ry="5" style="stroke:black;stroke-width:3;fill:none" />
<circle r="8" cx="30" cy="50" fill="none" style="stroke:black;stroke-width:3;" />
<rect width="380" height="80" x="60" y="10" rx="5" ry="5" style="stroke:black;stroke-width:3;fill:none" />
<?php
$pin_coordinates = [
10 => [70, 68], 20 => [70, 44], 30 => [70, 20],
11 => [405, 68], 12 => [370, 68], 13 => [335, 68], 14 => [300, 68],
15 => [265, 68], 16 => [230, 68], 17 => [195, 68], 18 => [160, 68], 19 => [125, 68],
21 => [405, 44], 22 => [370, 44], 23 => [335, 44], 24 => [300, 44],
25 => [265, 44], 26 => [220, 44], 27 => [185, 44], 28 => [150, 44], 29 => [115, 44],
31 => [405, 20], 32 => [370, 20], 33 => [335, 20], 34 => [300, 20],
35 => [265, 20], 36 => [230, 20], 37 => [195, 20], 38 => [160, 20], 39 => [125, 20],
];
// Rechtecke einfärben, wenn "fill"-Modus aktiv ist
if ($_GET["mode"] == "fill") {
$data = $_GET["data"];
$data = json_decode(urldecode($data), true);
foreach ($pin_coordinates as $key => $coordinates) {
$fill = in_array($key, $data) ? "green" : "red";
echo '<rect width="25" height="10" x="' . $coordinates[0] . '" y="' . $coordinates[1] . '" rx="1" ry="1" style="stroke:black;stroke-width:3;fill:' . $fill . '" />';
}
} else {
// Nur Umrisse
foreach ($pin_coordinates as $coordinates) {
echo '<rect width="25" height="10" x="' . $coordinates[0] . '" y="' . $coordinates[1] . '" rx="1" ry="1" style="stroke:black;stroke-width:3;fill:none" />';
}
}
// SVG frühzeitig beenden, wenn kein Data vorhanden oder im fill-Modus
if (empty($_GET['data']) || $_GET["mode"] == "fill") {
print "</svg>";
die();
}
// Brückenverbindungen übersetzen, falls aktiviert
if ($_GET["translate"] == "true") {
$db = new SQLite3('db-test/test.db');
$data = json_decode($_GET["data"], true);
$plug = json_decode(file_get_contents("settings.json"), true)["plug"];
$nodes_raw = [];
foreach ($data as $bridge) {
$nodes = $db->query("SELECT node_from, node_to FROM nodes WHERE required_by = " . $bridge);
while ($node = $nodes->fetchArray(SQLITE3_ASSOC)) {
$nodes_raw[] = [$node['node_from'], $node['node_to']];
}
}
$inputArray = $nodes_raw;
} else {
$inputArray = json_decode($_GET['data'], true);
}
// Koordinaten übersetzen
$translatedArray = array_map(function ($pair) use ($pin_coordinates) {
return [
$pin_coordinates[$pair[0]],
$pin_coordinates[$pair[1]],
];
}, $inputArray);
$colors = ["#1a5fb4", "#26a269", "#e5a50a", "#c64600", "#a51d2d", "#613583", "#63452c", "#3d3846"];
// Linien ausgeben
$colorNumber = 0;
foreach ($translatedArray as $line) {
$point1 = $line[0];
$point2 = $line[1];
$point1x = $point1[0] + 10;
$point1y = $point1[1] + 5;
$point2x = $point2[0] + 10;
$point2y = $point2[1] + 5;
echo '<path d="M' . $point1x . ' ' . $point1y . ' L' . $point2x . ' ' . $point2y .
'" style="stroke:' . $colors[$colorNumber] . ';stroke-width:3; fill:none;" />';
$colorNumber = ($colorNumber + 1) % count($colors);
}
?>
</svg>

139
pagecontent/system.php Executable file
View File

@@ -0,0 +1,139 @@
<?php
$view = $_GET["view"];
switch($view) {
default: // Standardseite (Übersicht)
?>
<div class="content-header">System-Aktionen</div>
<hr />
<div class="save-button" style="background-color: #ffadad" onclick="if(confirm('Das System wird heruntergefahren. Fortfahren?') == true){pageload('shutdown')}"><img src="/vendor/icons/system-shut.svg" \>Herunterfahren</div>
<div class="save-button" style="background-color: #adcfff" onclick="if(confirm('Das System wird neu gestartet. Fortfahren?') == true){pageload('reboot')}"><img src="/vendor/icons/restart.svg" \>Neu starten</div>
<div class="save-button" onclick="pageload('info'); $(this).html('<img src=\'/vendor/icons/load.gif\' \>Sammle Systeminfos...');"><img src="/vendor/icons/info-circle.svg" \>Systeminfo</div>
<div class="save-button" onclick="pageload('wifi')"><img src="/vendor/icons/wifi.svg" \>WLAN-/DHCP-Konfig anzeigen</div>
<div class="save-button" onclick="window.location.href='#selfcheck';"><img src="/vendor/icons/ecg-monitoring-icon.svg" \>Selbstdiagnose</div>
<?php
break;
case "info":
?>
<div class="content-header">System-Aktionen: Sys-Info</div>
<hr />
<p>Kernel-Version:</p>
<?php
$output = shell_exec('uname -r');
echo "<pre align='left'>$output</pre>";
?>
<p>Betriebssystem:</p>
<?php
$output = shell_exec('cat /etc/os-release');
echo "<pre align='left'>$output</pre>";
?>
<p>System-Uptime:</p>
<?php
$output = shell_exec('uptime -p');
echo "<pre align='left'>$output</pre>";
?>
<p>Letzter Boot:</p>
<?php
$output = shell_exec('who -b');
echo "<pre align='left'>$output</pre>";
?>
<p>CPU-Infos:</p>
<?php
$output = shell_exec('cat /proc/cpuinfo');
echo "<pre align='left'>$output</pre>";
?>
<p>Arbeitsspeicher:</p>
<?php
$output = shell_exec('free -h');
echo "<pre align='left'>$output</pre>";
?>
<p>Speicherplatz:</p>
<?php
$output = shell_exec('df -h');
echo "<pre align='left'>$output</pre>";
?>
<p>Python-Version:</p>
<?php
$output = shell_exec('python3 --version');
echo "<pre align='left'>$output</pre>";
?>
<p>Top 5 Prozesse nach CPU-Auslastung:</p>
<?php
$output = shell_exec('ps -eo pid,comm,%cpu,%mem --sort=-%cpu | head -n 6');
echo "<pre align='left'>$output</pre>";
?>
<p>CPU-Temperatur:</p>
<?php
$output = shell_exec('vcgencmd measure_temp');
echo "<pre align='left'>$output</pre>";
?>
<p>System-Uhrzeit (PHP):</p>
<?php
setlocale(LC_TIME, 'de_DE.UTF-8'); // optional für deutsche Darstellung
date_default_timezone_set("Europe/Berlin"); // falls nötig
echo "<pre align='left'>" . strftime("%A, %e. %B %Y %H:%M:%S") . "</pre>";
break;
case "wifi":
?>
<div class="content-header">System-Aktionen: WLAN/DHCP</div>
<hr />
<p>Netzwerkverbindungen:</p>
<?php
$output = shell_exec('nmcli connection show');
echo "<pre align='left'>$output</pre>";
?>
<p>Verbundene Geräte:</p>
<?php
$output = shell_exec('ip neigh');
echo "<pre align='left'>$output</pre>";
?>
<p>Netzwerkschnittstellen:</p>
<?php
$output = shell_exec('nmcli device show');
echo "<pre align='left'>$output</pre>";
?>
<p>Ifconfig:</p>
<?php
$output = shell_exec('ifconfig');
echo "<pre align='left'>$output</pre>";
break;
case "reboot":
?>
<div class="content-header">System-Aktionen: Neustart</div>
<hr />
<p>Das Prüfgerät wird nun neu gestartet. Die Verbindung wird in Kürze getrennt.</p>
<p>Stellen Sie sicher, dass Sie sich im Anschluss wieder mit dem Geräte-WLAN verbinden.</p>
<?php
$output = shell_exec('sudo /sbin/reboot 2>&1');
echo "------- Fehlerprotokoll nach dieser Zeile -------<br> $output";
break;
case "shutdown":
?>
<div class="content-header">System-Aktionen: Herunterfahren</div>
<hr />
<p>Das Prüfgerät wird nun heruntergefahren. Die Verbindung wird in Kürze getrennt.</p>
<p>Auf Wiedersehen!</p>
<?php
$output = shell_exec('sudo /sbin/shutdown -h now 2>&1');
echo "------- Fehlerprotokoll nach dieser Zeile -------<br> $output";
break;
}

0
pagecontent/temp.json Executable file
View File