v1 #1
Binary file not shown.
@@ -15,7 +15,8 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="banner-text">⚠️ Niedrige Batterie erkannt!</div>
|
<div class="banner-text">⚠️ Niedrige Batterie erkannt!</div>
|
||||||
<div class="banner-devices" id="battery-devices">
|
<div class="banner-devices" id="battery-devices">
|
||||||
Deine Geräte mit niedriger Batterie: <span id="low-battery-list"></span>
|
Deine Geräte mit niedriger Batterie:
|
||||||
|
<span id="low-battery-list"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -47,9 +48,7 @@
|
|||||||
|
|
||||||
<div id="learning-display" class="learning-mode" style="display: none">
|
<div id="learning-display" class="learning-mode" style="display: none">
|
||||||
<h3>📚 Lernmodus aktiv</h3>
|
<h3>📚 Lernmodus aktiv</h3>
|
||||||
<p>
|
<p>Drücke jetzt den Button für: <span id="learning-button"></span></p>
|
||||||
Drücke jetzt den Button für: <span id="learning-button"></span>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="timer-container">
|
<div class="timer-container">
|
||||||
@@ -193,24 +192,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Namen-Handling
|
// Namen-Handling
|
||||||
if (
|
if ((data.name == "" || !data.name) && data.lane == "start1") {
|
||||||
(data.firstname == "" || data.lastname == "") &&
|
|
||||||
data.lane == "start1"
|
|
||||||
) {
|
|
||||||
name1 = "";
|
name1 = "";
|
||||||
}
|
}
|
||||||
if (
|
if ((data.name == "" || !data.name) && data.lane == "start2") {
|
||||||
(data.firstname == "" || data.lastname == "") &&
|
|
||||||
data.lane == "start2"
|
|
||||||
) {
|
|
||||||
name2 = "";
|
name2 = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.firstname && data.lastname && data.lane) {
|
if (data.name && data.lane) {
|
||||||
if (data.lane === "start1") {
|
if (data.lane === "start1") {
|
||||||
name1 = `${data.firstname} ${data.lastname}`;
|
name1 = data.name;
|
||||||
} else if (data.lane === "start2") {
|
} else if (data.lane === "start2") {
|
||||||
name2 = `${data.firstname} ${data.lastname}`;
|
name2 = data.name;
|
||||||
}
|
}
|
||||||
updateDisplay();
|
updateDisplay();
|
||||||
}
|
}
|
||||||
@@ -482,14 +475,17 @@
|
|||||||
updateLaneDisplay();
|
updateLaneDisplay();
|
||||||
})
|
})
|
||||||
.catch((error) =>
|
.catch((error) =>
|
||||||
console.error("Fehler beim Laden der Lane-Schwierigkeits-Konfiguration:", error)
|
console.error(
|
||||||
|
"Fehler beim Laden der Lane-Schwierigkeits-Konfiguration:",
|
||||||
|
error
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateLaneDisplay() {
|
function updateLaneDisplay() {
|
||||||
const lane1Title = document.querySelector('.lane h2');
|
const lane1Title = document.querySelector(".lane h2");
|
||||||
const lane2Title = document.querySelectorAll('.lane h2')[1];
|
const lane2Title = document.querySelectorAll(".lane h2")[1];
|
||||||
|
|
||||||
if (laneConfigType === 0) {
|
if (laneConfigType === 0) {
|
||||||
// Identische Lanes
|
// Identische Lanes
|
||||||
lane1Title.textContent = "🏊♀️ Bahn 1";
|
lane1Title.textContent = "🏊♀️ Bahn 1";
|
||||||
@@ -498,9 +494,11 @@
|
|||||||
// Unterschiedliche Lanes
|
// Unterschiedliche Lanes
|
||||||
const lane1Icon = lane1DifficultyType === 0 ? "🟢" : "🔴";
|
const lane1Icon = lane1DifficultyType === 0 ? "🟢" : "🔴";
|
||||||
const lane2Icon = lane2DifficultyType === 0 ? "🟢" : "🔴";
|
const lane2Icon = lane2DifficultyType === 0 ? "🟢" : "🔴";
|
||||||
const lane1Difficulty = lane1DifficultyType === 0 ? "Leicht" : "Schwer";
|
const lane1Difficulty =
|
||||||
const lane2Difficulty = lane2DifficultyType === 0 ? "Leicht" : "Schwer";
|
lane1DifficultyType === 0 ? "Leicht" : "Schwer";
|
||||||
|
const lane2Difficulty =
|
||||||
|
lane2DifficultyType === 0 ? "Leicht" : "Schwer";
|
||||||
|
|
||||||
lane1Title.textContent = `${lane1Icon} Bahn 1 (${lane1Difficulty})`;
|
lane1Title.textContent = `${lane1Icon} Bahn 1 (${lane1Difficulty})`;
|
||||||
lane2Title.textContent = `${lane2Icon} Bahn 2 (${lane2Difficulty})`;
|
lane2Title.textContent = `${lane2Icon} Bahn 2 (${lane2Difficulty})`;
|
||||||
}
|
}
|
||||||
|
|||||||
352
data/rfid.html
352
data/rfid.html
@@ -62,7 +62,7 @@
|
|||||||
type="button"
|
type="button"
|
||||||
id="readUidBtn"
|
id="readUidBtn"
|
||||||
class="read-uid-btn"
|
class="read-uid-btn"
|
||||||
onclick="readRFIDUID()"
|
onclick="toggleRFIDReading()"
|
||||||
>
|
>
|
||||||
📡 Read Chip
|
📡 Read Chip
|
||||||
</button>
|
</button>
|
||||||
@@ -70,47 +70,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="vorname">Vorname <span class="required">*</span></label>
|
<label for="name">Name <span class="required">*</span></label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="vorname"
|
id="name"
|
||||||
name="vorname"
|
name="name"
|
||||||
placeholder="Vorname eingeben"
|
placeholder="Name eingeben"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="nachname">Nachname <span class="required">*</span></label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="nachname"
|
|
||||||
name="nachname"
|
|
||||||
placeholder="Nachname eingeben"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="geburtsdatum"
|
|
||||||
>Geburtsdatum <span class="required">*</span></label
|
|
||||||
>
|
|
||||||
<div class="date-input-group">
|
|
||||||
<input
|
|
||||||
type="date"
|
|
||||||
id="geburtsdatum"
|
|
||||||
name="geburtsdatum"
|
|
||||||
required
|
|
||||||
max=""
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
id="ageDisplay"
|
|
||||||
class="age-display"
|
|
||||||
style="display: none"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="btn-container">
|
<div class="btn-container">
|
||||||
<button type="submit" class="btn btn-primary">💾 Speichern</button>
|
<button type="submit" class="btn btn-primary">💾 Speichern</button>
|
||||||
<button type="button" class="btn btn-secondary" onclick="clearForm()">
|
<button type="button" class="btn btn-secondary" onclick="clearForm()">
|
||||||
@@ -124,60 +93,8 @@
|
|||||||
// Globale Variablen
|
// Globale Variablen
|
||||||
let rfidData = [];
|
let rfidData = [];
|
||||||
let isLoading = false;
|
let isLoading = false;
|
||||||
let DBUrl = "ninja.reptilfpv.de:3000";
|
// Lokale Benutzer-Speicherung (geht bei Neustart verloren)
|
||||||
var APIKey;
|
let localUsers = [];
|
||||||
|
|
||||||
// Maximales Datum auf heute setzen
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
|
||||||
const today = new Date().toISOString().split("T")[0];
|
|
||||||
document.getElementById("geburtsdatum").setAttribute("max", today);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Alter berechnen und anzeigen
|
|
||||||
function calculateAge(birthDate) {
|
|
||||||
const today = new Date();
|
|
||||||
const birth = new Date(birthDate);
|
|
||||||
let age = today.getFullYear() - birth.getFullYear();
|
|
||||||
const monthDiff = today.getMonth() - birth.getMonth();
|
|
||||||
|
|
||||||
if (
|
|
||||||
monthDiff < 0 ||
|
|
||||||
(monthDiff === 0 && today.getDate() < birth.getDate())
|
|
||||||
) {
|
|
||||||
age--;
|
|
||||||
}
|
|
||||||
|
|
||||||
return age;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Geburtsdatum Change Event
|
|
||||||
document
|
|
||||||
.getElementById("geburtsdatum")
|
|
||||||
.addEventListener("change", function (e) {
|
|
||||||
const birthDate = e.target.value;
|
|
||||||
const ageDisplay = document.getElementById("ageDisplay");
|
|
||||||
|
|
||||||
if (birthDate) {
|
|
||||||
const age = calculateAge(birthDate);
|
|
||||||
if (age >= 0 && age <= 150) {
|
|
||||||
ageDisplay.textContent = `${age} Jahre`;
|
|
||||||
ageDisplay.style.display = "block";
|
|
||||||
} else {
|
|
||||||
ageDisplay.style.display = "none";
|
|
||||||
if (age < 0) {
|
|
||||||
showErrorMessage(
|
|
||||||
"Das Geburtsdatum kann nicht in der Zukunft liegen!"
|
|
||||||
);
|
|
||||||
e.target.value = "";
|
|
||||||
} else {
|
|
||||||
showErrorMessage("Bitte überprüfen Sie das Geburtsdatum!");
|
|
||||||
e.target.value = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ageDisplay.style.display = "none";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Form Submit Handler
|
// Form Submit Handler
|
||||||
document
|
document
|
||||||
@@ -189,46 +106,40 @@
|
|||||||
|
|
||||||
// Daten aus dem Formular holen
|
// Daten aus dem Formular holen
|
||||||
const uid = document.getElementById("uid").value.trim();
|
const uid = document.getElementById("uid").value.trim();
|
||||||
const vorname = document.getElementById("vorname").value.trim();
|
const name = document.getElementById("name").value.trim();
|
||||||
const nachname = document.getElementById("nachname").value.trim();
|
|
||||||
const geburtsdatum = document.getElementById("geburtsdatum").value;
|
|
||||||
|
|
||||||
// Validierung
|
// Validierung
|
||||||
if (!uid || !vorname || !nachname || !geburtsdatum) {
|
if (!uid || !name) {
|
||||||
showErrorMessage("Bitte füllen Sie alle Pflichtfelder aus!");
|
showErrorMessage("Bitte füllen Sie alle Pflichtfelder aus!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alter berechnen
|
|
||||||
const alter = calculateAge(geburtsdatum);
|
|
||||||
if (alter < 0) {
|
|
||||||
showErrorMessage(
|
|
||||||
"Das Geburtsdatum kann nicht in der Zukunft liegen!"
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loading State
|
// Loading State
|
||||||
setLoadingState(true);
|
setLoadingState(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// API Aufruf zum Erstellen des Benutzers
|
// API Aufruf zum Erstellen des Benutzers (lokal)
|
||||||
|
const requestData = {
|
||||||
|
uid: uid,
|
||||||
|
name: name,
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("Sende Daten:", requestData);
|
||||||
|
console.log("JSON String:", JSON.stringify(requestData));
|
||||||
|
|
||||||
const response = await fetch(`/api/users/insert`, {
|
const response = await fetch(`/api/users/insert`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
...(APIKey && { Authorization: `Bearer ${APIKey}` }),
|
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify(requestData),
|
||||||
uid: uid,
|
|
||||||
vorname: vorname,
|
|
||||||
nachname: nachname,
|
|
||||||
geburtsdatum: geburtsdatum,
|
|
||||||
alter: alter, // Berechnetes Alter wird mit gesendet
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log("Response Status:", response.status);
|
||||||
|
console.log("Response Headers:", response.headers);
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
console.log("Response Result:", result);
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
// Erfolg anzeigen
|
// Erfolg anzeigen
|
||||||
@@ -313,7 +224,6 @@
|
|||||||
|
|
||||||
function clearForm() {
|
function clearForm() {
|
||||||
document.getElementById("rfidForm").reset();
|
document.getElementById("rfidForm").reset();
|
||||||
document.getElementById("ageDisplay").style.display = "none";
|
|
||||||
document.getElementById("uid").focus();
|
document.getElementById("uid").focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,14 +231,13 @@
|
|||||||
window.addEventListener("load", function () {
|
window.addEventListener("load", function () {
|
||||||
document.getElementById("uid").focus();
|
document.getElementById("uid").focus();
|
||||||
checkServerStatus();
|
checkServerStatus();
|
||||||
loadLicence();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Enter-Taste in UID Feld zum nächsten Feld springen
|
// Enter-Taste in UID Feld zum nächsten Feld springen
|
||||||
document.getElementById("uid").addEventListener("keydown", function (e) {
|
document.getElementById("uid").addEventListener("keydown", function (e) {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
document.getElementById("vorname").focus();
|
document.getElementById("name").focus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -340,34 +249,170 @@
|
|||||||
e.target.value = value;
|
e.target.value = value;
|
||||||
});
|
});
|
||||||
|
|
||||||
// RFID UID lesen
|
let rfidReadingMode = false;
|
||||||
|
let statusInterval = null;
|
||||||
|
|
||||||
|
// Toggle RFID Reading Mode
|
||||||
|
async function toggleRFIDReading() {
|
||||||
|
const readBtn = document.getElementById("readUidBtn");
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/rfid/toggle`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
rfidReadingMode = result.reading_mode;
|
||||||
|
|
||||||
|
if (rfidReadingMode) {
|
||||||
|
// RFID Reading gestartet
|
||||||
|
readBtn.innerHTML = "🛑 Stop Reading";
|
||||||
|
readBtn.className = "read-uid-btn reading";
|
||||||
|
showSuccessMessage("RFID Lesen gestartet - Karte auflegen!");
|
||||||
|
|
||||||
|
// Status Polling starten
|
||||||
|
startStatusPolling();
|
||||||
|
} else {
|
||||||
|
// RFID Reading gestoppt
|
||||||
|
readBtn.innerHTML = "📡 Read Chip";
|
||||||
|
readBtn.className = "read-uid-btn";
|
||||||
|
showSuccessMessage("RFID Lesen gestoppt");
|
||||||
|
|
||||||
|
// Status Polling stoppen
|
||||||
|
stopStatusPolling();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showErrorMessage("Fehler beim Toggle RFID: " + result.message);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Toggle RFID Error:", error);
|
||||||
|
showErrorMessage("Fehler beim Toggle RFID");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status Polling für kontinuierliches Lesen
|
||||||
|
function startStatusPolling() {
|
||||||
|
if (statusInterval) {
|
||||||
|
clearInterval(statusInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
statusInterval = setInterval(async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/rfid/status`, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (result.success && result.last_uid && result.last_uid !== "") {
|
||||||
|
// Neue UID gelesen - automatisch stoppen
|
||||||
|
const uidInput = document.getElementById("uid");
|
||||||
|
uidInput.value = result.last_uid;
|
||||||
|
|
||||||
|
// Visuelles Feedback
|
||||||
|
uidInput.style.borderColor = "#28a745";
|
||||||
|
setTimeout(() => {
|
||||||
|
uidInput.style.borderColor = "#e1e5e9";
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
showSuccessMessage("UID gelesen: " + result.last_uid);
|
||||||
|
|
||||||
|
// Automatisch zum nächsten Feld springen
|
||||||
|
setTimeout(() => {
|
||||||
|
document.getElementById("name").focus();
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
// RFID Lesen automatisch stoppen
|
||||||
|
stopRFIDReading();
|
||||||
|
|
||||||
|
// UID im Backend zurücksetzen
|
||||||
|
clearBackendUID();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Status Poll Error:", error);
|
||||||
|
}
|
||||||
|
}, 500); // Alle 500ms prüfen
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status Polling stoppen
|
||||||
|
function stopStatusPolling() {
|
||||||
|
if (statusInterval) {
|
||||||
|
clearInterval(statusInterval);
|
||||||
|
statusInterval = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RFID Reading komplett stoppen (Frontend + Backend)
|
||||||
|
async function stopRFIDReading() {
|
||||||
|
// Status Polling stoppen
|
||||||
|
stopStatusPolling();
|
||||||
|
|
||||||
|
// Backend stoppen
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/rfid/toggle`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (result.success && !result.reading_mode) {
|
||||||
|
rfidReadingMode = false;
|
||||||
|
|
||||||
|
// Button zurücksetzen
|
||||||
|
const readBtn = document.getElementById("readUidBtn");
|
||||||
|
readBtn.innerHTML = "📡 Read Chip";
|
||||||
|
readBtn.className = "read-uid-btn";
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Stop RFID Error:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UID im Backend zurücksetzen
|
||||||
|
async function clearBackendUID() {
|
||||||
|
try {
|
||||||
|
await fetch(`/api/rfid/clear`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Clear UID Error:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Einzelnes Lesen (für Kompatibilität)
|
||||||
async function readRFIDUID() {
|
async function readRFIDUID() {
|
||||||
const readBtn = document.getElementById("readUidBtn");
|
const readBtn = document.getElementById("readUidBtn");
|
||||||
const uidInput = document.getElementById("uid");
|
const uidInput = document.getElementById("uid");
|
||||||
|
|
||||||
// Button Status ändern
|
|
||||||
readBtn.disabled = true;
|
readBtn.disabled = true;
|
||||||
readBtn.className = "read-uid-btn reading";
|
readBtn.innerHTML = "📡 Lese...";
|
||||||
readBtn.innerHTML = "📡 Lese UID...";
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// API Aufruf zum RFID Reader
|
|
||||||
const response = await fetch(`/api/rfid/read`, {
|
const response = await fetch(`/api/rfid/read`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
...(APIKey && { Authorization: `Bearer ${APIKey}` }),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (result.success && result.uid) {
|
if (result.success && result.uid) {
|
||||||
// UID in das Eingabefeld setzen
|
uidInput.value = result.uid;
|
||||||
uidInput.value = result.uid
|
|
||||||
.match(/.{1,2}/g)
|
|
||||||
.join(":")
|
|
||||||
.toUpperCase();
|
|
||||||
uidInput.focus();
|
uidInput.focus();
|
||||||
|
|
||||||
// Visuelles Feedback
|
// Visuelles Feedback
|
||||||
@@ -376,38 +421,20 @@
|
|||||||
uidInput.style.borderColor = "#e1e5e9";
|
uidInput.style.borderColor = "#e1e5e9";
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
|
||||||
showSuccessMessage("UID erfolgreich gelesen!");
|
showSuccessMessage("UID gelesen: " + result.uid);
|
||||||
|
|
||||||
// Automatisch zum nächsten Feld springen
|
// Automatisch zum nächsten Feld springen
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
document.getElementById("vorname").focus();
|
document.getElementById("name").focus();
|
||||||
}, 500);
|
}, 500);
|
||||||
} else {
|
} else {
|
||||||
// Fehler beim Lesen
|
showErrorMessage("Keine Karte erkannt");
|
||||||
const errorMsg = result.error || "Keine UID gefunden";
|
|
||||||
showErrorMessage(`RFID Fehler: ${errorMsg}`);
|
|
||||||
|
|
||||||
// UID Feld rot markieren
|
|
||||||
uidInput.style.borderColor = "#dc3545";
|
|
||||||
setTimeout(() => {
|
|
||||||
uidInput.style.borderColor = "#e1e5e9";
|
|
||||||
}, 10000);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Fehler beim Lesen der UID:", error);
|
console.error("RFID Read Error:", error);
|
||||||
showErrorMessage(
|
showErrorMessage("Fehler beim Lesen");
|
||||||
"Verbindungsfehler zum RFID Reader. Bitte prüfen Sie die Verbindung."
|
|
||||||
);
|
|
||||||
|
|
||||||
// UID Feld rot markieren
|
|
||||||
uidInput.style.borderColor = "#dc3545";
|
|
||||||
setTimeout(() => {
|
|
||||||
uidInput.style.borderColor = "#e1e5e9";
|
|
||||||
}, 3000);
|
|
||||||
} finally {
|
} finally {
|
||||||
// Button Status zurücksetzen
|
|
||||||
readBtn.disabled = false;
|
readBtn.disabled = false;
|
||||||
readBtn.className = "read-uid-btn";
|
|
||||||
readBtn.innerHTML = "📡 Read Chip";
|
readBtn.innerHTML = "📡 Read Chip";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -415,9 +442,7 @@
|
|||||||
async function checkServerStatus() {
|
async function checkServerStatus() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/health", {
|
const response = await fetch("/api/health", {
|
||||||
headers: {
|
headers: {},
|
||||||
...(APIKey && { Authorization: `Bearer ${APIKey}` }),
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
@@ -436,16 +461,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadLicence() {
|
// Seite laden - RFID Status initialisieren
|
||||||
fetch("/api/get-licence")
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
.then((response) => response.json())
|
// Status Polling stoppen falls aktiv
|
||||||
.then((data) => {
|
stopStatusPolling();
|
||||||
APIKey = data.licence || "";
|
|
||||||
})
|
// Server Status prüfen
|
||||||
.catch((error) =>
|
checkServerStatus();
|
||||||
showMessage("Fehler beim Laden der Lizenz", "error")
|
});
|
||||||
);
|
|
||||||
}
|
// Seite verlassen - RFID Reading komplett stoppen
|
||||||
|
window.addEventListener("beforeunload", function () {
|
||||||
|
stopRFIDReading();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
<!-- Navigation Buttons -->
|
<!-- Navigation Buttons -->
|
||||||
<div class="nav-buttons">
|
<div class="nav-buttons">
|
||||||
<a href="/" class="nav-button">🏠 Hauptseite</a>
|
<a href="/" class="nav-button">🏠 Hauptseite</a>
|
||||||
|
<a href="/rfid.html" class="nav-button">🏷️ RFID</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Date & Time Section -->
|
<!-- Date & Time Section -->
|
||||||
|
|||||||
@@ -29,8 +29,7 @@ lib_deps =
|
|||||||
esp32async/ESPAsyncWebServer@^3.7.7
|
esp32async/ESPAsyncWebServer@^3.7.7
|
||||||
esp32async/AsyncTCP@^3.4.2
|
esp32async/AsyncTCP@^3.4.2
|
||||||
mlesniew/PicoMQTT@^1.3.0
|
mlesniew/PicoMQTT@^1.3.0
|
||||||
miguelbalboa/MFRC522@^1.4.12
|
adafruit/Adafruit PN532@^1.3.4
|
||||||
adafruit/RTClib@^2.1.4
|
|
||||||
|
|
||||||
[env:esp32thing_OTA]
|
[env:esp32thing_OTA]
|
||||||
board = esp32thing
|
board = esp32thing
|
||||||
@@ -50,8 +49,8 @@ lib_deps =
|
|||||||
esp32async/ESPAsyncWebServer@^3.7.7
|
esp32async/ESPAsyncWebServer@^3.7.7
|
||||||
esp32async/AsyncTCP@^3.4.2
|
esp32async/AsyncTCP@^3.4.2
|
||||||
mlesniew/PicoMQTT@^1.3.0
|
mlesniew/PicoMQTT@^1.3.0
|
||||||
miguelbalboa/MFRC522@^1.4.12
|
adafruit/Adafruit PN532@^1.3.4
|
||||||
adafruit/RTClib@^2.1.4
|
|
||||||
|
|
||||||
[env:esp32thing]
|
[env:esp32thing]
|
||||||
board = esp32thing_plus
|
board = esp32thing_plus
|
||||||
@@ -69,8 +68,7 @@ lib_deps =
|
|||||||
esp32async/ESPAsyncWebServer@^3.7.7
|
esp32async/ESPAsyncWebServer@^3.7.7
|
||||||
esp32async/AsyncTCP@^3.4.2
|
esp32async/AsyncTCP@^3.4.2
|
||||||
mlesniew/PicoMQTT@^1.3.0
|
mlesniew/PicoMQTT@^1.3.0
|
||||||
miguelbalboa/MFRC522@^1.4.12
|
adafruit/Adafruit PN532@^1.3.4
|
||||||
adafruit/RTClib@^2.1.4
|
|
||||||
|
|
||||||
[env:esp32thing_CI]
|
[env:esp32thing_CI]
|
||||||
platform = espressif32
|
platform = espressif32
|
||||||
@@ -87,8 +85,7 @@ lib_deps =
|
|||||||
esp32async/ESPAsyncWebServer@^3.7.7
|
esp32async/ESPAsyncWebServer@^3.7.7
|
||||||
esp32async/AsyncTCP@^3.4.2
|
esp32async/AsyncTCP@^3.4.2
|
||||||
mlesniew/PicoMQTT@^1.3.0
|
mlesniew/PicoMQTT@^1.3.0
|
||||||
miguelbalboa/MFRC522@^1.4.12
|
adafruit/Adafruit PN532@^1.3.4
|
||||||
adafruit/RTClib@^2.1.4
|
|
||||||
|
|
||||||
[env:esp32-s3-devkitc-1]
|
[env:esp32-s3-devkitc-1]
|
||||||
board = esp32-s3-devkitc-1
|
board = esp32-s3-devkitc-1
|
||||||
@@ -96,12 +93,12 @@ monitor_speed = 115200
|
|||||||
board_upload.flash_size = 16MB
|
board_upload.flash_size = 16MB
|
||||||
board_build.partitions = default_16MB.csv
|
board_build.partitions = default_16MB.csv
|
||||||
build_flags =
|
build_flags =
|
||||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||||
-DBATTERY_PIN=35
|
-DBATTERY_PIN=35
|
||||||
lib_deps =
|
lib_deps =
|
||||||
bblanchon/ArduinoJson@^7.4.1
|
bblanchon/ArduinoJson@^7.4.1
|
||||||
esp32async/ESPAsyncWebServer@^3.7.7
|
esp32async/ESPAsyncWebServer@^3.7.7
|
||||||
esp32async/AsyncTCP@^3.4.2
|
esp32async/AsyncTCP@^3.4.2
|
||||||
mlesniew/PicoMQTT@^1.3.0
|
mlesniew/PicoMQTT@^1.3.0
|
||||||
miguelbalboa/MFRC522@^1.4.12
|
adafruit/Adafruit PN532@^1.3.4
|
||||||
adafruit/RTClib@^2.1.4
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
#include "master.h"
|
#include "master.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
|
||||||
#include <PicoMQTT.h>
|
#include <PicoMQTT.h>
|
||||||
|
|
||||||
@@ -249,34 +251,105 @@ void publishLaneStatus(int lane, String status) {
|
|||||||
* sendet diese ggf. als JSON an das Frontend.
|
* sendet diese ggf. als JSON an das Frontend.
|
||||||
*/
|
*/
|
||||||
void readRFIDfromButton(const char *topic, const char *payload) {
|
void readRFIDfromButton(const char *topic, const char *payload) {
|
||||||
|
loadLicenceFromPrefs();
|
||||||
|
String topicStr(topic);
|
||||||
|
int lastSlash = topicStr.lastIndexOf('/');
|
||||||
|
if (lastSlash < 0)
|
||||||
|
return;
|
||||||
|
String macStr = topicStr.substring(lastSlash + 1);
|
||||||
// Create a JSON document to hold the button press data
|
// Create a JSON document to hold the button press data
|
||||||
StaticJsonDocument<256> doc;
|
StaticJsonDocument<256> doc;
|
||||||
DeserializationError error = deserializeJson(doc, payload);
|
DeserializationError error = deserializeJson(doc, payload);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
const char *mac = doc["buttonmac"] | "unknown";
|
|
||||||
const char *uid = doc["uid"] | "unknown";
|
const char *uid = doc["uid"] | "unknown";
|
||||||
|
|
||||||
Serial.printf("RFID Read from Button:\n");
|
Serial.printf("RFID Read from Button:\n");
|
||||||
Serial.printf(" Button MAC: %s\n", mac);
|
Serial.printf(" Button MAC: %s\n", macStr.c_str());
|
||||||
Serial.printf(" UID: %s\n", uid);
|
Serial.printf(" UID: %s\n", uid);
|
||||||
|
String debugUpperUid = String(uid);
|
||||||
|
debugUpperUid.toUpperCase();
|
||||||
|
Serial.printf(" UID (Upper): %s\n", debugUpperUid.c_str());
|
||||||
|
|
||||||
// Convert buttonmac to byte array for comparison
|
// Convert buttonmac to byte array for comparison
|
||||||
auto macBytes = macStringToBytes(mac);
|
auto macBytes = macStringToBytes(macStr.c_str());
|
||||||
|
|
||||||
// Check if the buttonmac matches buttonConfigs.start1.mac
|
// Check if the buttonmac matches buttonConfigs.start1.mac
|
||||||
if (memcmp(macBytes.data(), buttonConfigs.start1.mac, 6) == 0) {
|
if (memcmp(macBytes.data(), buttonConfigs.start1.mac, 6) == 0) {
|
||||||
// Fetch user data
|
// Zuerst lokal suchen (UID in Großbuchstaben konvertieren)
|
||||||
UserData userData = checkUser(uid);
|
String upperUid = String(uid);
|
||||||
|
upperUid.toUpperCase();
|
||||||
|
UserData userData = checkUser(upperUid);
|
||||||
|
|
||||||
|
if (!userData.exists) {
|
||||||
|
// Nicht lokal gefunden - Online-Server fragen
|
||||||
|
Serial.println("User nicht lokal gefunden, suche online...");
|
||||||
|
|
||||||
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
|
HTTPClient http;
|
||||||
|
http.begin(String(BACKEND_SERVER) + "/api/v1/private/users/find");
|
||||||
|
http.addHeader("Content-Type", "application/json");
|
||||||
|
http.addHeader("Authorization", String("Bearer ") + licence);
|
||||||
|
|
||||||
|
Serial.println("Online-Suche mit Token: " + licence);
|
||||||
|
|
||||||
|
StaticJsonDocument<200> requestDoc;
|
||||||
|
String upperUidForRequest = String(uid);
|
||||||
|
upperUidForRequest.toUpperCase();
|
||||||
|
requestDoc["uid"] =
|
||||||
|
upperUidForRequest; // UID in Großbuchstaben konvertieren
|
||||||
|
String requestBody;
|
||||||
|
serializeJson(requestDoc, requestBody);
|
||||||
|
|
||||||
|
Serial.println("Request Body: " + requestBody);
|
||||||
|
|
||||||
|
int httpCode = http.POST(requestBody);
|
||||||
|
|
||||||
|
if (httpCode == HTTP_CODE_OK) {
|
||||||
|
String response = http.getString();
|
||||||
|
Serial.println("Response: " + response);
|
||||||
|
StaticJsonDocument<512> responseDoc;
|
||||||
|
DeserializationError parseError =
|
||||||
|
deserializeJson(responseDoc, response);
|
||||||
|
|
||||||
|
if (!parseError && responseDoc["success"].as<bool>() &&
|
||||||
|
responseDoc["data"]["exists"].as<bool>()) {
|
||||||
|
// Online gefundenen Benutzer verwenden (nicht lokal speichern)
|
||||||
|
String firstName = responseDoc["data"]["firstname"].as<String>();
|
||||||
|
String lastName = responseDoc["data"]["lastname"].as<String>();
|
||||||
|
String fullName = firstName + " " + lastName;
|
||||||
|
|
||||||
|
// UserData für Frontend erstellen
|
||||||
|
userData.uid = upperUid;
|
||||||
|
userData.firstname = firstName;
|
||||||
|
userData.lastname = "";
|
||||||
|
userData.alter = 0;
|
||||||
|
userData.exists = true;
|
||||||
|
|
||||||
|
Serial.println("User online gefunden: " + fullName);
|
||||||
|
} else {
|
||||||
|
Serial.println("User auch online nicht gefunden für UID: " +
|
||||||
|
upperUid);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Serial.printf("Online-Suche fehlgeschlagen: HTTP %d\n", httpCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
http.end();
|
||||||
|
} else {
|
||||||
|
Serial.println("Keine Internetverbindung für Online-Suche");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wenn Benutzer gefunden wurde (lokal oder online)
|
||||||
if (userData.exists) {
|
if (userData.exists) {
|
||||||
// Log user data
|
// Log user data
|
||||||
Serial.printf("User found for start1: %s %s, Alter: %d\n",
|
Serial.printf("User found for start1: %s\n",
|
||||||
userData.firstname.c_str(), userData.lastname.c_str(),
|
userData.firstname.c_str());
|
||||||
userData.alter);
|
|
||||||
|
|
||||||
// Create JSON message to send to the frontend
|
// Create JSON message to send to the frontend
|
||||||
StaticJsonDocument<128> messageDoc;
|
StaticJsonDocument<128> messageDoc;
|
||||||
messageDoc["firstname"] = userData.firstname;
|
messageDoc["name"] =
|
||||||
messageDoc["lastname"] = userData.lastname;
|
userData.firstname; // Verwende name statt firstname/lastname
|
||||||
messageDoc["lane"] = "start1"; // Add lane information
|
messageDoc["lane"] = "start1"; // Add lane information
|
||||||
|
|
||||||
String message;
|
String message;
|
||||||
@@ -287,23 +360,86 @@ void readRFIDfromButton(const char *topic, const char *payload) {
|
|||||||
Serial.printf("Pushed user data for start1 to frontend: %s\n",
|
Serial.printf("Pushed user data for start1 to frontend: %s\n",
|
||||||
message.c_str());
|
message.c_str());
|
||||||
} else {
|
} else {
|
||||||
Serial.println("User not found for UID: " + String(uid));
|
Serial.println("User nicht gefunden für UID: " + upperUid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check if the buttonmac matches buttonConfigs.start2.mac
|
// Check if the buttonmac matches buttonConfigs.start2.mac
|
||||||
else if (memcmp(macBytes.data(), buttonConfigs.start2.mac, 6) == 0) {
|
else if (memcmp(macBytes.data(), buttonConfigs.start2.mac, 6) == 0) {
|
||||||
// Fetch user data
|
// Zuerst lokal suchen (UID in Großbuchstaben konvertieren)
|
||||||
UserData userData = checkUser(uid);
|
String upperUid = String(uid);
|
||||||
|
upperUid.toUpperCase();
|
||||||
|
UserData userData = checkUser(upperUid);
|
||||||
|
|
||||||
|
if (!userData.exists) {
|
||||||
|
// Nicht lokal gefunden - Online-Server fragen
|
||||||
|
Serial.println("User nicht lokal gefunden, suche online...");
|
||||||
|
|
||||||
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
|
HTTPClient http;
|
||||||
|
http.begin(String(BACKEND_SERVER) + "/api/v1/private/users/find");
|
||||||
|
http.addHeader("Content-Type", "application/json");
|
||||||
|
http.addHeader("Authorization", String("Bearer ") + licence);
|
||||||
|
|
||||||
|
Serial.println("Online-Suche mit Token: " + licence);
|
||||||
|
|
||||||
|
StaticJsonDocument<200> requestDoc;
|
||||||
|
String upperUidForRequest2 = String(uid);
|
||||||
|
upperUidForRequest2.toUpperCase();
|
||||||
|
requestDoc["uid"] =
|
||||||
|
upperUidForRequest2; // UID in Großbuchstaben konvertieren
|
||||||
|
String requestBody;
|
||||||
|
serializeJson(requestDoc, requestBody);
|
||||||
|
|
||||||
|
Serial.println("Request Body: " + requestBody);
|
||||||
|
|
||||||
|
int httpCode = http.POST(requestBody);
|
||||||
|
|
||||||
|
if (httpCode == HTTP_CODE_OK) {
|
||||||
|
String response = http.getString();
|
||||||
|
Serial.println("Response: " + response);
|
||||||
|
StaticJsonDocument<512> responseDoc;
|
||||||
|
DeserializationError parseError =
|
||||||
|
deserializeJson(responseDoc, response);
|
||||||
|
|
||||||
|
if (!parseError && responseDoc["success"].as<bool>() &&
|
||||||
|
responseDoc["data"]["exists"].as<bool>()) {
|
||||||
|
// Online gefundenen Benutzer verwenden (nicht lokal speichern)
|
||||||
|
String firstName = responseDoc["data"]["firstname"].as<String>();
|
||||||
|
String lastName = responseDoc["data"]["lastname"].as<String>();
|
||||||
|
String fullName = firstName + " " + lastName;
|
||||||
|
|
||||||
|
// UserData für Frontend erstellen
|
||||||
|
userData.uid = upperUid;
|
||||||
|
userData.firstname = firstName;
|
||||||
|
userData.lastname = "";
|
||||||
|
userData.alter = 0;
|
||||||
|
userData.exists = true;
|
||||||
|
|
||||||
|
Serial.println("User online gefunden: " + fullName);
|
||||||
|
} else {
|
||||||
|
Serial.println("User auch online nicht gefunden für UID: " +
|
||||||
|
upperUid);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Serial.printf("Online-Suche fehlgeschlagen: HTTP %d\n", httpCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
http.end();
|
||||||
|
} else {
|
||||||
|
Serial.println("Keine Internetverbindung für Online-Suche");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wenn Benutzer gefunden wurde (lokal oder online)
|
||||||
if (userData.exists) {
|
if (userData.exists) {
|
||||||
// Log user data
|
// Log user data
|
||||||
Serial.printf("User found for start2: %s %s, Alter: %d\n",
|
Serial.printf("User found for start2: %s\n",
|
||||||
userData.firstname.c_str(), userData.lastname.c_str(),
|
userData.firstname.c_str());
|
||||||
userData.alter);
|
|
||||||
|
|
||||||
// Create JSON message to send to the frontend
|
// Create JSON message to send to the frontend
|
||||||
StaticJsonDocument<128> messageDoc;
|
StaticJsonDocument<128> messageDoc;
|
||||||
messageDoc["firstname"] = userData.firstname;
|
messageDoc["name"] =
|
||||||
messageDoc["lastname"] = userData.lastname;
|
userData.firstname; // Verwende name statt firstname/lastname
|
||||||
messageDoc["lane"] = "start2"; // Add lane information
|
messageDoc["lane"] = "start2"; // Add lane information
|
||||||
|
|
||||||
String message;
|
String message;
|
||||||
@@ -314,7 +450,7 @@ void readRFIDfromButton(const char *topic, const char *payload) {
|
|||||||
Serial.printf("Pushed user data for start2 to frontend: %s\n",
|
Serial.printf("Pushed user data for start2 to frontend: %s\n",
|
||||||
message.c_str());
|
message.c_str());
|
||||||
} else {
|
} else {
|
||||||
Serial.println("User not found for UID: " + String(uid));
|
Serial.println("User nicht gefunden für UID: " + upperUid);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Serial.println("Button MAC does not match start1.mac or start2.mac");
|
Serial.println("Button MAC does not match start1.mac or start2.mac");
|
||||||
@@ -335,11 +471,11 @@ void setupMqttServer() {
|
|||||||
mqtt.subscribe("#", [](const char *topic, const char *payload) {
|
mqtt.subscribe("#", [](const char *topic, const char *payload) {
|
||||||
// Message received callback
|
// Message received callback
|
||||||
// Serial.printf("Received message on topic '%s': %s\n", topic, payload);
|
// Serial.printf("Received message on topic '%s': %s\n", topic, payload);
|
||||||
if (strncmp(topic, "aquacross/button/", 17) == 0) {
|
if (strncmp(topic, "aquacross/button/rfid/", 22) == 0) {
|
||||||
readButtonJSON(topic, payload);
|
|
||||||
} else if (strncmp(topic, "aquacross/button/rfid/", 22) == 0) {
|
|
||||||
readRFIDfromButton(topic, payload);
|
readRFIDfromButton(topic, payload);
|
||||||
// Handle RFID read messages
|
// Handle RFID read messages
|
||||||
|
} else if (strncmp(topic, "aquacross/button/", 17) == 0) {
|
||||||
|
readButtonJSON(topic, payload);
|
||||||
} else if (strncmp(topic, "aquacross/battery/", 17) == 0) {
|
} else if (strncmp(topic, "aquacross/battery/", 17) == 0) {
|
||||||
handleBatteryTopic(topic, payload);
|
handleBatteryTopic(topic, payload);
|
||||||
} else if (strncmp(topic, "heartbeat/alive/", 16) == 0) {
|
} else if (strncmp(topic, "heartbeat/alive/", 16) == 0) {
|
||||||
|
|||||||
@@ -4,12 +4,21 @@
|
|||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <HTTPClient.h>
|
#include <HTTPClient.h>
|
||||||
#include <preferencemanager.h>
|
#include <preferencemanager.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
const char *BACKEND_SERVER = "https://ninja.reptilfpv.de";
|
const char *BACKEND_SERVER = "https://ninja.reptilfpv.de";
|
||||||
extern String
|
extern String
|
||||||
licence; // Declare licence as an external variable defined elsewhere
|
licence; // Declare licence as an external variable defined elsewhere
|
||||||
String BACKEND_TOKEN =
|
|
||||||
licence; // Use the licence as the token for authentication
|
// Lokale Benutzer-Struktur
|
||||||
|
struct LocalUser {
|
||||||
|
String uid;
|
||||||
|
String name;
|
||||||
|
unsigned long timestamp; // Zeitstempel der Erstellung
|
||||||
|
};
|
||||||
|
|
||||||
|
// Lokale Benutzer-Speicherung (geht bei Neustart verloren)
|
||||||
|
std::vector<LocalUser> localUsers;
|
||||||
|
|
||||||
bool backendOnline() {
|
bool backendOnline() {
|
||||||
|
|
||||||
@@ -21,8 +30,8 @@ bool backendOnline() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HTTPClient http;
|
HTTPClient http;
|
||||||
http.begin(String(BACKEND_SERVER) + "/v1/private/health");
|
http.begin(String(BACKEND_SERVER) + "/api/v1/private/health");
|
||||||
http.addHeader("Authorization", String("Bearer ") + BACKEND_TOKEN);
|
http.addHeader("Authorization", String("Bearer ") + licence);
|
||||||
|
|
||||||
int httpCode = http.GET();
|
int httpCode = http.GET();
|
||||||
bool isOnline = (httpCode == HTTP_CODE_OK);
|
bool isOnline = (httpCode == HTTP_CODE_OK);
|
||||||
@@ -50,42 +59,27 @@ struct UserData {
|
|||||||
UserData checkUser(const String &uid) {
|
UserData checkUser(const String &uid) {
|
||||||
|
|
||||||
UserData userData = {"", "", "", 0, false};
|
UserData userData = {"", "", "", 0, false};
|
||||||
|
String upperUid = uid;
|
||||||
|
upperUid.toUpperCase(); // UID in Großbuchstaben konvertieren
|
||||||
|
|
||||||
if (!backendOnline()) {
|
// Lokale Benutzer durchsuchen
|
||||||
Serial.println("No internet connection, cannot check user.");
|
for (const auto &user : localUsers) {
|
||||||
return userData;
|
String userUpperUid = user.uid;
|
||||||
}
|
userUpperUid.toUpperCase();
|
||||||
|
if (userUpperUid == upperUid) {
|
||||||
|
userData.uid = user.uid;
|
||||||
|
userData.firstname = user.name;
|
||||||
|
userData.lastname = ""; // Nicht mehr verwendet
|
||||||
|
userData.alter = 0; // Nicht mehr verwendet
|
||||||
|
userData.exists = true;
|
||||||
|
|
||||||
HTTPClient http;
|
Serial.println("Lokaler Benutzer gefunden: " + user.name);
|
||||||
http.begin(String(BACKEND_SERVER) + "/v1/private/users/find");
|
return userData;
|
||||||
http.addHeader("Content-Type", "application/json");
|
|
||||||
http.addHeader("Authorization", String("Bearer ") + BACKEND_TOKEN);
|
|
||||||
|
|
||||||
// Create JSON payload
|
|
||||||
StaticJsonDocument<200> requestDoc;
|
|
||||||
requestDoc["uid"] = uid;
|
|
||||||
String requestBody;
|
|
||||||
serializeJson(requestDoc, requestBody);
|
|
||||||
|
|
||||||
int httpCode = http.POST(requestBody);
|
|
||||||
|
|
||||||
if (httpCode == HTTP_CODE_OK) {
|
|
||||||
String payload = http.getString();
|
|
||||||
StaticJsonDocument<512> responseDoc;
|
|
||||||
DeserializationError error = deserializeJson(responseDoc, payload);
|
|
||||||
|
|
||||||
if (!error) {
|
|
||||||
userData.uid = responseDoc["uid"].as<String>();
|
|
||||||
userData.firstname = responseDoc["firstname"].as<String>();
|
|
||||||
userData.lastname = responseDoc["lastname"].as<String>();
|
|
||||||
userData.alter = responseDoc["alter"] | 0;
|
|
||||||
userData.exists = responseDoc["exists"] | false;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Serial.printf("User check failed, HTTP code: %d\n", httpCode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
http.end();
|
Serial.println("Benutzer mit UID " + uid +
|
||||||
|
" nicht in lokaler Datenbank gefunden");
|
||||||
return userData;
|
return userData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +94,7 @@ JsonDocument getAllLocations() {
|
|||||||
|
|
||||||
HTTPClient http;
|
HTTPClient http;
|
||||||
http.begin(String(BACKEND_SERVER) + "/v1/private/locations");
|
http.begin(String(BACKEND_SERVER) + "/v1/private/locations");
|
||||||
http.addHeader("Authorization", String("Bearer ") + BACKEND_TOKEN);
|
http.addHeader("Authorization", String("Bearer ") + licence);
|
||||||
|
|
||||||
int httpCode = http.GET();
|
int httpCode = http.GET();
|
||||||
|
|
||||||
@@ -124,42 +118,47 @@ JsonDocument getAllLocations() {
|
|||||||
bool userExists(const String &uid) { return checkUser(uid).exists; }
|
bool userExists(const String &uid) { return checkUser(uid).exists; }
|
||||||
|
|
||||||
// Fügt einen neuen Benutzer in die Datenbank ein
|
// Fügt einen neuen Benutzer in die Datenbank ein
|
||||||
bool enterUserData(const String &uid, const String &vorname,
|
bool enterUserData(const String &uid, const String &name) {
|
||||||
const String &nachname, const String &geburtsdatum,
|
String upperUid = uid;
|
||||||
int alter) {
|
upperUid.toUpperCase(); // UID in Großbuchstaben konvertieren
|
||||||
if (!backendOnline()) {
|
|
||||||
Serial.println("No internet connection, cannot enter user data.");
|
// Prüfen ob Benutzer bereits existiert
|
||||||
return false;
|
for (const auto &user : localUsers) {
|
||||||
|
String userUpperUid = user.uid;
|
||||||
|
userUpperUid.toUpperCase();
|
||||||
|
if (userUpperUid == upperUid) {
|
||||||
|
Serial.println("Benutzer mit UID " + upperUid + " existiert bereits!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HTTPClient http;
|
// Neuen Benutzer erstellen
|
||||||
http.begin(String(BACKEND_SERVER) + "/v1/private/users/insert");
|
LocalUser newUser;
|
||||||
http.addHeader("Content-Type", "application/json");
|
newUser.uid = upperUid; // UID in Großbuchstaben speichern
|
||||||
http.addHeader("Authorization", String("Bearer ") + BACKEND_TOKEN);
|
newUser.name = name;
|
||||||
|
newUser.timestamp = millis();
|
||||||
|
|
||||||
// Create JSON payload
|
// Benutzer zum lokalen Array hinzufügen
|
||||||
StaticJsonDocument<512> requestDoc;
|
localUsers.push_back(newUser);
|
||||||
requestDoc["uid"] = uid;
|
|
||||||
requestDoc["firstname"] = vorname;
|
|
||||||
requestDoc["lastname"] = nachname;
|
|
||||||
requestDoc["geburtsdatum"] = geburtsdatum;
|
|
||||||
requestDoc["alter"] = alter;
|
|
||||||
|
|
||||||
String requestBody;
|
Serial.println("Benutzer lokal gespeichert:");
|
||||||
serializeJson(requestDoc, requestBody);
|
Serial.println("UID: " + upperUid);
|
||||||
|
Serial.println("Name: " + name);
|
||||||
|
Serial.println("Gespeicherte Benutzer: " + String(localUsers.size()));
|
||||||
|
|
||||||
int httpCode = http.POST(requestBody);
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool success = (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_CREATED);
|
// Gibt alle lokalen Benutzer zurück (für Debugging)
|
||||||
|
String getLocalUsersList() {
|
||||||
|
String result = "Lokale Benutzer (" + String(localUsers.size()) + "):\n";
|
||||||
|
|
||||||
if (success) {
|
for (const auto &user : localUsers) {
|
||||||
Serial.println("User data successfully entered into database");
|
result += "- UID: " + user.uid + ", Name: " + user.name +
|
||||||
} else {
|
", Erstellt: " + String(user.timestamp) + "\n";
|
||||||
Serial.printf("Failed to enter user data, HTTP code: %d\n", httpCode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
http.end();
|
return result;
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Richtet die HTTP-Routen für die Backend-API ein (z.B. Health-Check, User- und
|
// Richtet die HTTP-Routen für die Backend-API ein (z.B. Health-Check, User- und
|
||||||
@@ -175,14 +174,143 @@ void setupBackendRoutes(AsyncWebServer &server) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
server.on("/api/users", HTTP_GET, [](AsyncWebServerRequest *request) {
|
server.on("/api/users", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
if (!backendOnline()) {
|
// Lokale Benutzer als JSON zurückgeben
|
||||||
request->send(503, "application/json",
|
DynamicJsonDocument doc(2048);
|
||||||
"{\"error\":\"Database not connected\"}");
|
JsonArray usersArray = doc.createNestedArray("users");
|
||||||
return;
|
|
||||||
|
for (const auto &user : localUsers) {
|
||||||
|
JsonObject userObj = usersArray.createNestedObject();
|
||||||
|
userObj["uid"] = user.uid;
|
||||||
|
userObj["name"] = user.name;
|
||||||
|
userObj["timestamp"] = user.timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle user retrieval logic here
|
doc["count"] = localUsers.size();
|
||||||
|
|
||||||
|
String response;
|
||||||
|
serializeJson(doc, response);
|
||||||
|
request->send(200, "application/json", response);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Route zum Erstellen eines neuen Benutzers
|
||||||
|
server.on(
|
||||||
|
"/api/users/insert", HTTP_POST,
|
||||||
|
[](AsyncWebServerRequest *request) {
|
||||||
|
Serial.println("API: /api/users/insert aufgerufen");
|
||||||
|
},
|
||||||
|
NULL,
|
||||||
|
[](AsyncWebServerRequest *request, uint8_t *data, size_t len,
|
||||||
|
size_t index, size_t total) {
|
||||||
|
// Diese Funktion wird für den Body aufgerufen
|
||||||
|
static String bodyBuffer = "";
|
||||||
|
|
||||||
|
// Daten anhängen
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
bodyBuffer += (char)data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wenn alle Daten empfangen wurden
|
||||||
|
if (index + len == total) {
|
||||||
|
Serial.println("Request Body empfangen: '" + bodyBuffer + "'");
|
||||||
|
|
||||||
|
if (bodyBuffer.length() == 0) {
|
||||||
|
Serial.println("FEHLER: Request Body ist leer!");
|
||||||
|
DynamicJsonDocument response(200);
|
||||||
|
response["success"] = false;
|
||||||
|
response["error"] = "Request Body ist leer";
|
||||||
|
String jsonString;
|
||||||
|
serializeJson(response, jsonString);
|
||||||
|
request->send(400, "application/json", jsonString);
|
||||||
|
bodyBuffer = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicJsonDocument doc(512);
|
||||||
|
DeserializationError error = deserializeJson(doc, bodyBuffer);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
Serial.println("JSON Parse Error: " + String(error.c_str()));
|
||||||
|
DynamicJsonDocument response(200);
|
||||||
|
response["success"] = false;
|
||||||
|
response["error"] = "Invalid JSON: " + String(error.c_str());
|
||||||
|
String jsonString;
|
||||||
|
serializeJson(response, jsonString);
|
||||||
|
request->send(400, "application/json", jsonString);
|
||||||
|
bodyBuffer = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String uid = doc["uid"].as<String>();
|
||||||
|
String name = doc["name"].as<String>();
|
||||||
|
|
||||||
|
Serial.println("Extrahierte UID: " + uid);
|
||||||
|
Serial.println("Extrahierter Name: " + name);
|
||||||
|
|
||||||
|
if (uid.length() == 0 || name.length() == 0) {
|
||||||
|
DynamicJsonDocument response(200);
|
||||||
|
response["success"] = false;
|
||||||
|
response["error"] = "UID und Name sind erforderlich";
|
||||||
|
String jsonString;
|
||||||
|
serializeJson(response, jsonString);
|
||||||
|
request->send(400, "application/json", jsonString);
|
||||||
|
bodyBuffer = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prüfen ob Benutzer bereits existiert
|
||||||
|
bool userExists = false;
|
||||||
|
for (const auto &user : localUsers) {
|
||||||
|
if (user.uid == uid) {
|
||||||
|
userExists = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userExists) {
|
||||||
|
DynamicJsonDocument response(200);
|
||||||
|
response["success"] = false;
|
||||||
|
response["error"] = "Benutzer bereits vorhanden";
|
||||||
|
String jsonString;
|
||||||
|
serializeJson(response, jsonString);
|
||||||
|
request->send(409, "application/json", jsonString);
|
||||||
|
bodyBuffer = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neuen Benutzer direkt in das Array einfügen
|
||||||
|
LocalUser newUser;
|
||||||
|
newUser.uid = uid;
|
||||||
|
newUser.name = name;
|
||||||
|
newUser.timestamp = millis();
|
||||||
|
|
||||||
|
localUsers.push_back(newUser);
|
||||||
|
|
||||||
|
Serial.println("Benutzer über API eingefügt:");
|
||||||
|
Serial.println("UID: " + uid);
|
||||||
|
Serial.println("Name: " + name);
|
||||||
|
Serial.println("Gespeicherte Benutzer: " + String(localUsers.size()));
|
||||||
|
|
||||||
|
DynamicJsonDocument response(200);
|
||||||
|
response["success"] = true;
|
||||||
|
response["message"] = "Benutzer erfolgreich erstellt";
|
||||||
|
response["uid"] = uid;
|
||||||
|
response["name"] = name;
|
||||||
|
|
||||||
|
String jsonString;
|
||||||
|
serializeJson(response, jsonString);
|
||||||
|
request->send(200, "application/json", jsonString);
|
||||||
|
|
||||||
|
// Buffer zurücksetzen
|
||||||
|
bodyBuffer = "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Debug-Route für lokale Benutzer
|
||||||
|
server.on("/api/debug/users", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
|
String userList = getLocalUsersList();
|
||||||
|
request->send(200, "text/plain", userList);
|
||||||
|
});
|
||||||
|
|
||||||
// Location routes /api/location/
|
// Location routes /api/location/
|
||||||
server.on("/api/location/", HTTP_GET, [](AsyncWebServerRequest *request) {
|
server.on("/api/location/", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
String result;
|
String result;
|
||||||
|
|||||||
@@ -18,18 +18,16 @@
|
|||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <gamemodes.h>
|
#include <gamemodes.h>
|
||||||
#include <licenceing.h>
|
#include <licenceing.h>
|
||||||
|
#include <preferencemanager.h>
|
||||||
#include <rfid.h>
|
#include <rfid.h>
|
||||||
#include <timesync.h>
|
#include <timesync.h>
|
||||||
#include <webserverrouter.h>
|
#include <webserverrouter.h>
|
||||||
#include <wificlass.h>
|
#include <wificlass.h>
|
||||||
#include <preferencemanager.h>
|
|
||||||
|
|
||||||
const char *firmwareversion = "1.0.0"; // Version der Firmware
|
const char *firmwareversion = "1.0.0"; // Version der Firmware
|
||||||
|
|
||||||
// moved to preferencemanager.h
|
// moved to preferencemanager.h
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
@@ -52,7 +50,6 @@ void setup() {
|
|||||||
loadWifiSettings();
|
loadWifiSettings();
|
||||||
loadLocationSettings();
|
loadLocationSettings();
|
||||||
|
|
||||||
|
|
||||||
setupWifi(); // WiFi initialisieren
|
setupWifi(); // WiFi initialisieren
|
||||||
setupOTA(&server);
|
setupOTA(&server);
|
||||||
|
|
||||||
@@ -61,7 +58,8 @@ void setup() {
|
|||||||
setupLED();
|
setupLED();
|
||||||
setupMqttServer(); // MQTT Server initialisieren
|
setupMqttServer(); // MQTT Server initialisieren
|
||||||
// setupBattery();
|
// setupBattery();
|
||||||
// setupRFID();
|
|
||||||
|
setupRFID(); // RFID initialisieren (ganz einfach)
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
@@ -69,5 +67,5 @@ void loop() {
|
|||||||
loopMqttServer(); // MQTT Server in der Loop aufrufen
|
loopMqttServer(); // MQTT Server in der Loop aufrufen
|
||||||
loopWebSocket();
|
loopWebSocket();
|
||||||
// loopBattery(); // Batterie-Loop aufrufen
|
// loopBattery(); // Batterie-Loop aufrufen
|
||||||
// loopRFID(); // RFID Loop aufrufen
|
loopRFID(); // RFID Loop aufrufen
|
||||||
}
|
}
|
||||||
|
|||||||
393
src/rfid.h
393
src/rfid.h
@@ -1,189 +1,145 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "databasebackend.h"
|
#include <Adafruit_PN532.h>
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <MFRC522.h>
|
#include <Wire.h>
|
||||||
#include <SPI.h>
|
|
||||||
|
|
||||||
|
// RFID Konfiguration - KORREKTE ESP32 Thing Plus Pins
|
||||||
|
#define SDA_PIN 23 // ESP32 Thing Plus SDA
|
||||||
|
#define SCL_PIN 22 // ESP32 Thing Plus SCL
|
||||||
|
#define IRQ_PIN 14
|
||||||
|
#define RST_PIN 15
|
||||||
|
|
||||||
// RFID Konfiguration
|
// PN532 RFID Reader (mit IRQ und Reset-Pin)
|
||||||
#define RST_PIN 21 // Configurable, see typical pin layout above
|
Adafruit_PN532 nfc(IRQ_PIN, RST_PIN);
|
||||||
#define SS_PIN 5 // Configurable, see typical pin layout above
|
|
||||||
|
|
||||||
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
|
// RFID Variablen
|
||||||
std::map<String, unsigned long>
|
bool rfidInitialized = false;
|
||||||
blockedUIDs; // Map to store blocked UIDs and their timestamps
|
bool readingMode = false;
|
||||||
const unsigned long BLOCK_DURATION = 10 * 1000; // 10 Seconds in milliseconds
|
|
||||||
|
|
||||||
// Neue Variablen für API-basiertes Lesen
|
|
||||||
bool rfidReadRequested = false;
|
|
||||||
String lastReadUID = "";
|
String lastReadUID = "";
|
||||||
bool rfidReadSuccess = false;
|
unsigned long lastReadTime = 0;
|
||||||
unsigned long rfidReadStartTime = 0;
|
|
||||||
const unsigned long RFID_READ_TIMEOUT =
|
|
||||||
10000; // 10 Sekunden Timeout für API Requests
|
|
||||||
|
|
||||||
// Initialisiert den RFID-Reader und das SPI-Interface.
|
// Initialisiert den RFID-Reader
|
||||||
void setupRFID() {
|
void setupRFID() {
|
||||||
|
// I2C starten mit korrekten Pins
|
||||||
|
Wire.begin(SDA_PIN, SCL_PIN, 100000);
|
||||||
|
delay(100);
|
||||||
|
|
||||||
// SPI und RFID initialisieren
|
// PN532 initialisieren
|
||||||
SPI.begin(); // Init SPI bus
|
if (!nfc.begin()) {
|
||||||
mfrc522.PCD_Init(); // Init MFRC522
|
Serial.println("RFID: PN532 nicht gefunden!");
|
||||||
delay(4); // Optional delay. Some boards need more time after init to be ready
|
return;
|
||||||
mfrc522.PCD_DumpVersionToSerial(); // Show details of PCD - MFRC522 Card
|
}
|
||||||
// Reader details
|
|
||||||
|
// Firmware prüfen
|
||||||
|
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||||
|
if (!versiondata) {
|
||||||
|
Serial.println("RFID: Firmware nicht lesbar!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAM Config
|
||||||
|
nfc.SAMConfig();
|
||||||
|
|
||||||
|
rfidInitialized = true;
|
||||||
|
Serial.println("RFID: Setup erfolgreich!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Liest automatisch eine RFID-Karte ein und blockiert die UID für eine
|
// Prüft ob RFID funktioniert
|
||||||
// bestimmte Zeit.
|
bool checkRFID() {
|
||||||
void handleAutomaticRFID() {
|
if (!rfidInitialized) {
|
||||||
if (!mfrc522.PICC_IsNewCardPresent()) {
|
return false;
|
||||||
return;
|
}
|
||||||
|
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||||
|
return (versiondata != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Liest RFID-Karte - GANZ EINFACH
|
||||||
|
String readRFIDCard() {
|
||||||
|
if (!checkRFID()) {
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select one of the cards
|
uint8_t uid[] = {0, 0, 0, 0, 0, 0, 0};
|
||||||
if (!mfrc522.PICC_ReadCardSerial()) {
|
uint8_t uidLength;
|
||||||
return;
|
|
||||||
|
uint8_t success =
|
||||||
|
nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
return ""; // Keine Karte
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the UID
|
// UID zu String
|
||||||
String uid = "";
|
String uidString = "";
|
||||||
for (byte i = 0; i < mfrc522.uid.size; i++) {
|
for (uint8_t i = 0; i < uidLength; i++) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
uid += ":";
|
uidString += ":";
|
||||||
if (mfrc522.uid.uidByte[i] < 0x10)
|
if (uid[i] < 0x10)
|
||||||
uid += "0";
|
uidString += "0";
|
||||||
uid += String(mfrc522.uid.uidByte[i], HEX);
|
uidString += String(uid[i], HEX);
|
||||||
|
}
|
||||||
|
uidString.toUpperCase();
|
||||||
|
|
||||||
|
Serial.println("RFID: " + uidString);
|
||||||
|
return uidString;
|
||||||
|
}
|
||||||
|
|
||||||
|
// RFID Loop - kontinuierliches Lesen wenn aktiviert
|
||||||
|
void loopRFID() {
|
||||||
|
if (!readingMode) {
|
||||||
|
return; // Lesen nicht aktiviert
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the UID is blocked
|
static unsigned long lastCheck = 0;
|
||||||
unsigned long currentTime = millis();
|
|
||||||
if (blockedUIDs.find(uid) != blockedUIDs.end()) {
|
// Nur alle 200ms prüfen (schneller für bessere Responsivität)
|
||||||
if (currentTime - blockedUIDs[uid] < BLOCK_DURATION) {
|
if (millis() - lastCheck < 200) {
|
||||||
Serial.print(F("UID blocked for 10 seconds. Remaining time: "));
|
return;
|
||||||
Serial.print((BLOCK_DURATION - (currentTime - blockedUIDs[uid])) / 1000);
|
}
|
||||||
Serial.println(F(" seconds."));
|
lastCheck = millis();
|
||||||
Serial.println(uid);
|
|
||||||
return;
|
// Versuchen zu lesen
|
||||||
} else {
|
String uid = readRFIDCard();
|
||||||
// Remove the UID from the blocked list if the block duration has passed
|
if (uid.length() > 0) {
|
||||||
blockedUIDs.erase(uid);
|
// Nur neue UIDs oder nach 2 Sekunden Pause
|
||||||
|
if (uid != lastReadUID || millis() - lastReadTime > 2000) {
|
||||||
|
lastReadUID = uid;
|
||||||
|
lastReadTime = millis();
|
||||||
|
Serial.println("RFID gelesen: " + uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process the UID
|
|
||||||
Serial.print(F("UID: "));
|
|
||||||
Serial.println(uid);
|
|
||||||
|
|
||||||
// Block the UID for 10 seconds
|
|
||||||
blockedUIDs[uid] = currentTime;
|
|
||||||
// show the remaining time for the block
|
|
||||||
Serial.print(F("UID blocked for 10 seconds. Remaining time: "));
|
|
||||||
Serial.print((BLOCK_DURATION - (currentTime - blockedUIDs[uid])) / 1000);
|
|
||||||
Serial.println(F(" seconds."));
|
|
||||||
|
|
||||||
// Halt the card
|
|
||||||
mfrc522.PICC_HaltA();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Neue Funktion für API-basiertes RFID Lesen
|
// API Routes
|
||||||
|
|
||||||
// Liest eine RFID-Karte im API-Modus ein (für Web-Requests).
|
|
||||||
void handleAPIRFIDRead() {
|
|
||||||
unsigned long currentTime = millis();
|
|
||||||
|
|
||||||
// Timeout prüfen
|
|
||||||
if (currentTime - rfidReadStartTime > RFID_READ_TIMEOUT) {
|
|
||||||
Serial.println("RFID API Timeout - keine Karte erkannt");
|
|
||||||
rfidReadRequested = false;
|
|
||||||
rfidReadSuccess = false;
|
|
||||||
lastReadUID = "";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prüfen ob neue Karte vorhanden ist
|
|
||||||
if (!mfrc522.PICC_IsNewCardPresent()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Karte auswählen
|
|
||||||
if (!mfrc522.PICC_ReadCardSerial()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// UID für API lesen (ohne Doppelpunkt-Trenner, Großbuchstaben)
|
|
||||||
String uid = "";
|
|
||||||
for (byte i = 0; i < mfrc522.uid.size; i++) {
|
|
||||||
if (mfrc522.uid.uidByte[i] < 0x10) {
|
|
||||||
uid += "0"; // Leading Zero für einstellige Hex-Werte
|
|
||||||
}
|
|
||||||
uid += String(mfrc522.uid.uidByte[i], HEX);
|
|
||||||
}
|
|
||||||
|
|
||||||
// UID in Großbuchstaben konvertieren
|
|
||||||
uid.toUpperCase();
|
|
||||||
|
|
||||||
Serial.println("RFID API UID gelesen: " + uid);
|
|
||||||
|
|
||||||
// Ergebnis speichern
|
|
||||||
lastReadUID = uid;
|
|
||||||
rfidReadSuccess = true;
|
|
||||||
rfidReadRequested = false;
|
|
||||||
|
|
||||||
// Karte "halt" setzen
|
|
||||||
mfrc522.PICC_HaltA();
|
|
||||||
mfrc522.PCD_StopCrypto1();
|
|
||||||
}
|
|
||||||
|
|
||||||
// API Funktion: RFID Lesevorgang starten
|
|
||||||
|
|
||||||
// Startet einen neuen RFID-Lesevorgang über die API.
|
|
||||||
void startRFIDRead() {
|
|
||||||
Serial.println("RFID API Lesevorgang gestartet...");
|
|
||||||
rfidReadRequested = true;
|
|
||||||
rfidReadSuccess = false;
|
|
||||||
lastReadUID = "";
|
|
||||||
rfidReadStartTime = millis();
|
|
||||||
}
|
|
||||||
|
|
||||||
// API Funktion: Prüfen ob Lesevorgang abgeschlossen
|
|
||||||
|
|
||||||
// Prüft, ob der aktuelle RFID-Lesevorgang abgeschlossen ist.
|
|
||||||
bool isRFIDReadComplete() { return !rfidReadRequested; }
|
|
||||||
|
|
||||||
// API Funktion: Ergebnis des Lesevorgangs abrufen
|
|
||||||
// Gibt das Ergebnis des letzten RFID-Lesevorgangs zurück.
|
|
||||||
String getRFIDReadResult(bool &success) {
|
|
||||||
success = rfidReadSuccess;
|
|
||||||
return lastReadUID;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Richtet die HTTP-API-Routen für RFID-Operationen ein.
|
|
||||||
void setupRFIDRoute(AsyncWebServer &server) {
|
void setupRFIDRoute(AsyncWebServer &server) {
|
||||||
server.on("/api/rfid/read", HTTP_GET, [](AsyncWebServerRequest *request) {
|
// Toggle RFID Reading Mode
|
||||||
Serial.println("api/rfid/read");
|
server.on("/api/rfid/toggle", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||||
|
readingMode = !readingMode;
|
||||||
// Start RFID-Lesevorgang
|
|
||||||
startRFIDRead();
|
|
||||||
unsigned long startTime = millis();
|
|
||||||
|
|
||||||
// Warten, bis eine UID gelesen wird oder Timeout eintritt
|
|
||||||
while (!isRFIDReadComplete()) {
|
|
||||||
if (millis() - startTime > RFID_READ_TIMEOUT) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
delay(10); // Kurze Pause, um die CPU nicht zu blockieren
|
|
||||||
}
|
|
||||||
|
|
||||||
DynamicJsonDocument response(200);
|
DynamicJsonDocument response(200);
|
||||||
|
response["success"] = true;
|
||||||
|
response["reading_mode"] = readingMode;
|
||||||
|
response["message"] =
|
||||||
|
readingMode ? "RFID Lesen gestartet" : "RFID Lesen gestoppt";
|
||||||
|
|
||||||
if (rfidReadSuccess && lastReadUID.length() > 0) {
|
String jsonString;
|
||||||
|
serializeJson(response, jsonString);
|
||||||
|
request->send(200, "application/json", jsonString);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Einzelnes Lesen (wie vorher)
|
||||||
|
server.on("/api/rfid/read", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
|
String uid = readRFIDCard();
|
||||||
|
|
||||||
|
DynamicJsonDocument response(200);
|
||||||
|
if (uid.length() > 0) {
|
||||||
response["success"] = true;
|
response["success"] = true;
|
||||||
response["uid"] = lastReadUID;
|
response["uid"] = uid;
|
||||||
response["message"] = "UID erfolgreich gelesen";
|
response["message"] = "Karte gelesen";
|
||||||
} else {
|
} else {
|
||||||
response["success"] = false;
|
response["success"] = false;
|
||||||
response["error"] = "Keine RFID Karte erkannt oder Timeout";
|
response["error"] = "Keine Karte gefunden";
|
||||||
response["uid"] = "";
|
response["uid"] = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,107 +148,32 @@ void setupRFIDRoute(AsyncWebServer &server) {
|
|||||||
request->send(200, "application/json", jsonString);
|
request->send(200, "application/json", jsonString);
|
||||||
});
|
});
|
||||||
|
|
||||||
server.on(
|
// Status und letzte gelesene UID
|
||||||
"/api/users/insert", HTTP_POST, [](AsyncWebServerRequest *request) {},
|
server.on("/api/rfid/status", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
NULL,
|
DynamicJsonDocument response(300);
|
||||||
[](AsyncWebServerRequest *request, uint8_t *data, size_t len,
|
response["success"] = true;
|
||||||
size_t index, size_t total) {
|
response["rfid_initialized"] = rfidInitialized;
|
||||||
Serial.println("/api/users/insert");
|
response["reading_mode"] = readingMode;
|
||||||
|
response["last_uid"] = lastReadUID;
|
||||||
|
response["message"] =
|
||||||
|
readingMode ? "RFID Lesen aktiv" : "RFID Lesen inaktiv";
|
||||||
|
|
||||||
// Parse the incoming JSON payload
|
String jsonString;
|
||||||
DynamicJsonDocument doc(512);
|
serializeJson(response, jsonString);
|
||||||
DeserializationError error = deserializeJson(doc, data, len);
|
request->send(200, "application/json", jsonString);
|
||||||
|
});
|
||||||
|
|
||||||
DynamicJsonDocument response(200);
|
// UID zurücksetzen (nach erfolgreichem Lesen)
|
||||||
|
server.on("/api/rfid/clear", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||||
|
lastReadUID = ""; // UID zurücksetzen
|
||||||
|
lastReadTime = 0; // Zeit auch zurücksetzen
|
||||||
|
|
||||||
if (error) {
|
DynamicJsonDocument response(200);
|
||||||
Serial.println("Fehler beim Parsen der JSON-Daten");
|
response["success"] = true;
|
||||||
response["success"] = false;
|
response["message"] = "UID zurückgesetzt";
|
||||||
response["error"] = "Ungültige JSON-Daten";
|
|
||||||
} else {
|
|
||||||
// Extract user data from the JSON payload
|
|
||||||
String uid = doc["uid"] | "";
|
|
||||||
String vorname = doc["vorname"] | "";
|
|
||||||
String nachname = doc["nachname"] | "";
|
|
||||||
String geburtsdatum = doc["geburtsdatum"] | "";
|
|
||||||
int alter = doc["alter"] | 0;
|
|
||||||
|
|
||||||
// Validate the data
|
String jsonString;
|
||||||
if (uid.isEmpty() || vorname.isEmpty() || nachname.isEmpty() ||
|
serializeJson(response, jsonString);
|
||||||
geburtsdatum.isEmpty() || alter <= 0) {
|
request->send(200, "application/json", jsonString);
|
||||||
Serial.println("Ungültige Eingabedaten");
|
});
|
||||||
response["success"] = false;
|
}
|
||||||
response["error"] = "Ungültige Eingabedaten";
|
|
||||||
} else {
|
|
||||||
// Process the data using the enterUserData function
|
|
||||||
Serial.println("Benutzerdaten empfangen:");
|
|
||||||
Serial.println("UID: " + uid);
|
|
||||||
Serial.println("Vorname: " + vorname);
|
|
||||||
Serial.println("Nachname: " + nachname);
|
|
||||||
Serial.println("Alter: " + String(alter));
|
|
||||||
|
|
||||||
bool dbSuccess =
|
|
||||||
enterUserData(uid, vorname, nachname, geburtsdatum, alter);
|
|
||||||
|
|
||||||
if (dbSuccess) {
|
|
||||||
response["success"] = true;
|
|
||||||
response["message"] = "Benutzer erfolgreich gespeichert";
|
|
||||||
} else {
|
|
||||||
response["success"] = false;
|
|
||||||
response["error"] = "Fehler beim Speichern in der Datenbank";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send the response back to the client
|
|
||||||
String jsonString;
|
|
||||||
serializeJson(response, jsonString);
|
|
||||||
request->send(200, "application/json", jsonString);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// API Funktion: RFID Reader Status prüfen
|
|
||||||
|
|
||||||
// Prüft, ob der RFID-Reader korrekt funktioniert und gibt den Status zurück.
|
|
||||||
bool checkRFIDReaderStatus() {
|
|
||||||
byte version = mfrc522.PCD_ReadRegister(mfrc522.VersionReg);
|
|
||||||
|
|
||||||
// Bekannte MFRC522 Versionen: 0x91, 0x92
|
|
||||||
if (version == 0x91 || version == 0x92) {
|
|
||||||
Serial.println("RFID Reader OK (Version: 0x" + String(version, HEX) + ")");
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
Serial.println("RFID Reader Fehler (Version: 0x" + String(version, HEX) +
|
|
||||||
")");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hilfsfunktion: Blockierte UIDs aufräumen
|
|
||||||
|
|
||||||
// Entfernt UIDs aus der Blockliste, deren Blockdauer abgelaufen ist.
|
|
||||||
void cleanupBlockedUIDs() {
|
|
||||||
unsigned long currentTime = millis();
|
|
||||||
|
|
||||||
// Iterator für sicheres Löschen während der Iteration
|
|
||||||
for (auto it = blockedUIDs.begin(); it != blockedUIDs.end();) {
|
|
||||||
if (currentTime - it->second >= BLOCK_DURATION) {
|
|
||||||
it = blockedUIDs.erase(it);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hauptschleife für das RFID-Handling (automatisch und API-basiert).
|
|
||||||
void loopRFID() {
|
|
||||||
// Originale Funktionalität für automatisches Lesen
|
|
||||||
if (!rfidReadRequested) {
|
|
||||||
handleAutomaticRFID();
|
|
||||||
}
|
|
||||||
|
|
||||||
// API-basiertes Lesen verarbeiten
|
|
||||||
if (rfidReadRequested) {
|
|
||||||
handleAPIRFIDRead();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,11 @@
|
|||||||
// Zeit-bezogene Variablen und Includes
|
// Zeit-bezogene Variablen und Includes
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "RTClib.h"
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <Wire.h>
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
RTC_PCF8523 rtc;
|
|
||||||
|
|
||||||
// Globale Zeitvariablen
|
// Globale Zeitvariablen
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
struct timezone tz;
|
struct timezone tz;
|
||||||
@@ -90,8 +86,6 @@ bool setSystemTime(long timestamp) {
|
|||||||
// Initialisiert die Zeit-API und richtet die HTTP-Endpunkte ein.
|
// Initialisiert die Zeit-API und richtet die HTTP-Endpunkte ein.
|
||||||
void setupTimeAPI(AsyncWebServer &server) {
|
void setupTimeAPI(AsyncWebServer &server) {
|
||||||
|
|
||||||
// setupRTC();
|
|
||||||
|
|
||||||
// API-Endpunkt: Aktuelle Zeit abrufen
|
// API-Endpunkt: Aktuelle Zeit abrufen
|
||||||
server.on("/api/time", HTTP_GET, [](AsyncWebServerRequest *request) {
|
server.on("/api/time", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
String response = getCurrentTimeJSON();
|
String response = getCurrentTimeJSON();
|
||||||
|
|||||||
Reference in New Issue
Block a user