Compare commits

..

6 Commits

Author SHA1 Message Date
tugsi e5e3dcba8c gitignore 2025-03-23 17:51:09 +01:00
tugsi 70c8b7bdc0 Delete data directory
Old and not used... Testing from SPIFFS
2025-03-16 19:40:05 +01:00
tugsi c574cc964e Merge branch 'Bambu-Serie-X-MQTT-Fix' of https://github.com/tugsi/Filaman into Bambu-Serie-X-MQTT-Fix 2025-03-16 19:35:08 +01:00
tugsi 9262865b56 - X1C MQTT Fix
- Spoolman Settings Fix
- Spoolman Out Fix
- Spoolman In Fix
2025-03-16 19:30:37 +01:00
tugsi f7c01eb5f0 Merge remote-tracking branch 'upstream/main' into Bambu-Serie-X-MQTT-Fix 2025-03-14 17:43:52 +01:00
tugsi a41ef9e75a docs: update changelog and header for version v1.4.1
- Die MQTT-Puffergröße auf 16.384 Byte (16 KB) erhöht.
Dies sollte ausreichen, um Ihre 15.403 Byte große JSON-Nutzlast mit etwas mehr Spielraum zu verarbeiten. Diese Änderung ermöglicht es dem MQTT-Client, größere JSON-Nachrichten ohne Kürzung zu empfangen und zu verarbeiten.

Einige wichtige Hinweise zu dieser Änderung:
Die neue Puffergröße von 16 KB verbraucht mehr RAM, der ESP32 sollte jedoch ausreichend Speicher dafür haben.
Die Größe ist auf 16 KB festgelegt, um über die benötigten 15.403 Byte hinaus zusätzlichen Puffer-Overhead bereitzustellen.

Diese Änderung betrifft nur den MQTT-Empfangspuffer
--
- Die Task-Stack-Größe von 8192 auf 16384 Wörter erhöht, um mehr Speicher für die JSON-Verarbeitung bereitzustellen
---
- Erhöhung des Keepalive-Intervalls auf 60 Sekunden
- Verbesserte Fehlerbehandlung und Debugging-Ausgaben
- Detaillierte Statusmeldungen für die MQTT-Verbindung
- Periodische Verbindungsüberprüfung alle 30 Sekunden
- Bessere Handhabung von Verbindungsverlusten
---
- Verwendung einer eindeutigen Client-ID mit Zufallssuffix
- Erhöhung der QoS (Quality of Service) auf 1 für zuverlässigere Übertragung
- Einstellung eines Socket-Timeouts von 60 Sekunden
- Aktivierung von Clean Session und Will Message
- Verbessertes Verbindungs-Logging
2025-03-14 17:42:26 +01:00
27 changed files with 447 additions and 927 deletions
+4
View File
@@ -1,3 +1,7 @@
.pio .pio
.vscode .vscode
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
data data
+10
View File
@@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}
+9
View File
@@ -141,6 +141,15 @@
</div> </div>
</div> </div>
<!-- Rechte Spalte -->
<div class="column">
<div class="feature-box">
<h2>Bambu AMS</h2>
<div id="amsDataContainer">
<div class="amsData" id="amsData">Wait for AMS-Data...</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
+161 -104
View File
@@ -53,118 +53,94 @@ function initWebSocket() {
// Wenn eine existierende Verbindung besteht, diese erst schließen // Wenn eine existierende Verbindung besteht, diese erst schließen
if (socket) { if (socket) {
try {
socket.onclose = null; // Remove onclose handler before closing
socket.onerror = null; // Remove error handler
socket.close(); socket.close();
} catch (e) {
console.error('Error closing existing socket:', e);
}
socket = null; socket = null;
} }
try { try {
socket = new WebSocket('ws://' + window.location.host + '/ws'); socket = new WebSocket('ws://' + window.location.host + '/ws');
socket.onopen = function () { socket.onopen = function() {
console.log('WebSocket connection established');
isConnected = true; isConnected = true;
updateConnectionStatus(); updateConnectionStatus();
startHeartbeat(); // Starte Heartbeat nach erfolgreicher Verbindung startHeartbeat(); // Starte Heartbeat nach erfolgreicher Verbindung
}; };
socket.onclose = function () { socket.onclose = function(event) {
console.log('WebSocket connection closed:', event.code, event.reason);
isConnected = false; isConnected = false;
updateConnectionStatus(); updateConnectionStatus();
if (heartbeatTimer) clearInterval(heartbeatTimer); if (heartbeatTimer) {
clearInterval(heartbeatTimer);
heartbeatTimer = null;
}
// Nur neue Verbindung versuchen, wenn kein Timer läuft // Nur neue Verbindung versuchen, wenn kein Timer läuft
if (!reconnectTimer) { if (!reconnectTimer) {
reconnectTimer = setTimeout(() => { reconnectTimer = setTimeout(() => {
console.log('Attempting to reconnect...');
initWebSocket(); initWebSocket();
}, RECONNECT_INTERVAL); }, RECONNECT_INTERVAL);
} }
}; };
socket.onerror = function (error) { socket.onerror = function(error) {
console.error('WebSocket error occurred:', error);
isConnected = false; isConnected = false;
updateConnectionStatus(); updateConnectionStatus();
if (heartbeatTimer) clearInterval(heartbeatTimer); if (heartbeatTimer) {
clearInterval(heartbeatTimer);
// Bei Fehler Verbindung schließen und neu aufbauen heartbeatTimer = null;
if (socket) {
socket.close();
socket = null;
} }
}; };
socket.onmessage = function (event) { socket.onmessage = function(event) {
lastHeartbeatResponse = Date.now(); // Aktualisiere Zeitstempel bei jeder Server-Antwort try {
lastHeartbeatResponse = Date.now();
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
if (data.type === 'amsData') {
displayAmsData(data.payload);
} else if (data.type === 'nfcTag') {
updateNfcStatusIndicator(data.payload);
} else if (data.type === 'nfcData') {
updateNfcData(data.payload);
} else if (data.type === 'writeNfcTag') {
handleWriteNfcTagResponse(data.success);
} else if (data.type === 'heartbeat') {
// Optional: Spezifische Behandlung von Heartbeat-Antworten
// Update status dots
const bambuDot = document.getElementById('bambuDot');
const spoolmanDot = document.getElementById('spoolmanDot');
const ramStatus = document.getElementById('ramStatus');
if (bambuDot) { // Handle different message types
bambuDot.className = 'status-dot ' + (data.bambu_connected ? 'online' : 'offline'); switch(data.type) {
// Add click handler only when offline case 'amsData':
if (!data.bambu_connected) { displayAmsData(data.payload);
bambuDot.style.cursor = 'pointer'; break;
bambuDot.onclick = function () { case 'nfcTag':
if (socket && socket.readyState === WebSocket.OPEN) { updateNfcStatusIndicator(data.payload);
socket.send(JSON.stringify({ break;
type: 'reconnect', case 'nfcData':
payload: 'bambu' updateNfcData(data.payload);
})); break;
} case 'writeNfcTag':
}; handleWriteNfcTagResponse(data.success);
} else { break;
bambuDot.style.cursor = 'default'; case 'heartbeat':
bambuDot.onclick = null; handleHeartbeatResponse(data);
} break;
} case 'setSpoolmanSettings':
if (spoolmanDot) { handleSpoolmanSettingsResponse(data);
spoolmanDot.className = 'status-dot ' + (data.spoolman_connected ? 'online' : 'offline'); break;
// Add click handler only when offline default:
if (!data.spoolman_connected) { console.warn('Unknown message type:', data.type);
spoolmanDot.style.cursor = 'pointer';
spoolmanDot.onclick = function () {
if (socket && socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({
type: 'reconnect',
payload: 'spoolman'
}));
}
};
} else {
spoolmanDot.style.cursor = 'default';
spoolmanDot.onclick = null;
}
}
if (ramStatus) {
ramStatus.textContent = `${data.freeHeap}k`;
}
}
else if (data.type === 'setSpoolmanSettings') {
if (data.payload == 'success') {
showNotification(`Spoolman Settings set successfully`, true);
} else {
showNotification(`Error setting Spoolman Settings`, false);
} }
} catch (error) {
console.error('Error processing WebSocket message:', error);
} }
}; };
} catch (error) { } catch (error) {
console.error('Error initializing WebSocket:', error);
isConnected = false; isConnected = false;
updateConnectionStatus(); updateConnectionStatus();
// Nur neue Verbindung versuchen, wenn kein Timer läuft
if (!reconnectTimer) { if (!reconnectTimer) {
reconnectTimer = setTimeout(() => { reconnectTimer = setTimeout(() => {
console.log('Attempting to reconnect after error...');
initWebSocket(); initWebSocket();
}, RECONNECT_INTERVAL); }, RECONNECT_INTERVAL);
} }
@@ -189,26 +165,26 @@ function updateConnectionStatus() {
} }
// Event Listeners // Event Listeners
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function() {
initWebSocket(); initWebSocket();
// Event Listener für Checkbox // Event Listener für Checkbox
document.getElementById("onlyWithoutSmId").addEventListener("change", function () { document.getElementById("onlyWithoutSmId").addEventListener("change", function() {
const spoolsData = window.getSpoolData(); const spoolsData = window.getSpoolData();
window.populateVendorDropdown(spoolsData); window.populateVendorDropdown(spoolsData);
}); });
}); });
// Event Listener für Spoolman Events // Event Listener für Spoolman Events
document.addEventListener('spoolDataLoaded', function (event) { document.addEventListener('spoolDataLoaded', function(event) {
window.populateVendorDropdown(event.detail); window.populateVendorDropdown(event.detail);
}); });
document.addEventListener('spoolmanError', function (event) { document.addEventListener('spoolmanError', function(event) {
showNotification(`Spoolman Error: ${event.detail.message}`, false); showNotification(`Spoolman Error: ${event.detail.message}`, false);
}); });
document.addEventListener('filamentSelected', function (event) { document.addEventListener('filamentSelected', function(event) {
updateNfcInfo(); updateNfcInfo();
// Zeige Spool-Buttons wenn ein Filament ausgewählt wurde // Zeige Spool-Buttons wenn ein Filament ausgewählt wurde
const selectedText = document.getElementById("selected-filament").textContent; const selectedText = document.getElementById("selected-filament").textContent;
@@ -218,12 +194,12 @@ document.addEventListener('filamentSelected', function (event) {
// Hilfsfunktion für kontrastreiche Textfarbe // Hilfsfunktion für kontrastreiche Textfarbe
function getContrastColor(hexcolor) { function getContrastColor(hexcolor) {
// Konvertiere Hex zu RGB // Konvertiere Hex zu RGB
const r = parseInt(hexcolor.substr(0, 2), 16); const r = parseInt(hexcolor.substr(0,2),16);
const g = parseInt(hexcolor.substr(2, 2), 16); const g = parseInt(hexcolor.substr(2,2),16);
const b = parseInt(hexcolor.substr(4, 2), 16); const b = parseInt(hexcolor.substr(4,2),16);
// Berechne Helligkeit (YIQ Formel) // Berechne Helligkeit (YIQ Formel)
const yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000; const yiq = ((r*299)+(g*587)+(b*114))/1000;
// Return schwarz oder weiß basierend auf Helligkeit // Return schwarz oder weiß basierend auf Helligkeit
return (yiq >= 128) ? '#000000' : '#FFFFFF'; return (yiq >= 128) ? '#000000' : '#FFFFFF';
@@ -389,6 +365,7 @@ function updateSpoolButtons(show) {
}); });
} }
// Verbesserte Funktion zum Behandeln von Spoolman Settings
function handleSpoolmanSettings(tray_info_idx, setting_id, cali_idx, nozzle_temp_min, nozzle_temp_max) { function handleSpoolmanSettings(tray_info_idx, setting_id, cali_idx, nozzle_temp_min, nozzle_temp_max) {
// Hole das ausgewählte Filament // Hole das ausgewählte Filament
const selectedText = document.getElementById("selected-filament").textContent; const selectedText = document.getElementById("selected-filament").textContent;
@@ -419,6 +396,7 @@ function handleSpoolmanSettings(tray_info_idx, setting_id, cali_idx, nozzle_temp
} }
} }
// Verbesserte Funktion zum Behandeln von Spool Out
function handleSpoolOut() { function handleSpoolOut() {
// Erstelle Payload // Erstelle Payload
const payload = { const payload = {
@@ -443,17 +421,21 @@ function handleSpoolOut() {
} }
} }
// Neue Funktion zum Behandeln des Spool-In-Klicks // Verbesserte Funktion zum Behandeln des Spool-In-Klicks
function handleSpoolIn(amsId, trayId) { function handleSpoolIn(amsId, trayId) {
console.log("handleSpoolIn called with amsId:", amsId, "trayId:", trayId);
// Prüfe WebSocket Verbindung zuerst // Prüfe WebSocket Verbindung zuerst
if (!socket || socket.readyState !== WebSocket.OPEN) { if (!socket || socket.readyState !== WebSocket.OPEN) {
showNotification("No active WebSocket connection!", false); showNotification("No active WebSocket connection!", false);
console.error("WebSocket not connected"); console.error("WebSocket not connected, state:", socket ? socket.readyState : "no socket");
return; return;
} }
// Hole das ausgewählte Filament // Hole das ausgewählte Filament
const selectedText = document.getElementById("selected-filament").textContent; const selectedText = document.getElementById("selected-filament").textContent;
console.log("Selected filament:", selectedText);
if (selectedText === "Please choose...") { if (selectedText === "Please choose...") {
showNotification("Choose Filament first", false); showNotification("Choose Filament first", false);
return; return;
@@ -466,53 +448,55 @@ function handleSpoolIn(amsId, trayId) {
if (!selectedSpool) { if (!selectedSpool) {
showNotification("Selected Spool not found", false); showNotification("Selected Spool not found", false);
console.error("Selected spool not found in spoolsData");
return; return;
} }
console.log("Found spool data:", selectedSpool);
// Temperaturwerte extrahieren // Temperaturwerte extrahieren
let minTemp = "175"; let minTemp = "175";
let maxTemp = "275"; let maxTemp = "275";
if (Array.isArray(selectedSpool.filament.nozzle_temperature) && if (selectedSpool.filament &&
Array.isArray(selectedSpool.filament.nozzle_temperature) &&
selectedSpool.filament.nozzle_temperature.length >= 2) { selectedSpool.filament.nozzle_temperature.length >= 2) {
minTemp = selectedSpool.filament.nozzle_temperature[0]; minTemp = selectedSpool.filament.nozzle_temperature[0];
maxTemp = selectedSpool.filament.nozzle_temperature[1]; maxTemp = selectedSpool.filament.nozzle_temperature[1];
} }
// Extrahiere bambu_idx
let bambuIdx = "GFL99"; // Default zu Generic PLA
if (selectedSpool.filament?.extra?.bambu_idx) {
bambuIdx = selectedSpool.filament.extra.bambu_idx.replace(/['"]/g, '');
} else if (selectedSpool.extra?.bambu_idx) {
bambuIdx = selectedSpool.extra.bambu_idx.replace(/['"]/g, '');
}
// Erstelle Payload // Erstelle Payload
const payload = { const payload = {
type: 'setBambuSpool', type: 'setBambuSpool',
payload: { payload: {
amsId: amsId, amsId: amsId,
trayId: trayId, trayId: trayId,
color: selectedSpool.filament.color_hex || "FFFFFF", color: selectedSpool.filament && selectedSpool.filament.color_hex ? selectedSpool.filament.color_hex : "FFFFFF",
nozzle_temp_min: parseInt(minTemp), nozzle_temp_min: parseInt(minTemp),
nozzle_temp_max: parseInt(maxTemp), nozzle_temp_max: parseInt(maxTemp),
type: selectedSpool.filament.material, type: selectedSpool.filament && selectedSpool.filament.material ? selectedSpool.filament.material : "PLA",
brand: selectedSpool.filament.vendor.name, brand: selectedSpool.filament && selectedSpool.filament.vendor ? selectedSpool.filament.vendor.name : "",
tray_info_idx: selectedSpool.filament.extra.bambu_idx?.replace(/['"]+/g, '').trim() || '', tray_info_idx: bambuIdx,
cali_idx: "-1" // Default-Wert setzen cali_idx: "-1" // Default-Wert setzen
} }
}; };
// Prüfe, ob der Key cali_idx vorhanden ist und setze ihn console.log("Sending payload:", payload);
if (selectedSpool.filament.extra.bambu_cali_id) {
payload.payload.cali_idx = selectedSpool.filament.extra.bambu_cali_id.replace(/['"]+/g, '').trim();
}
// Prüfe, ob der Key bambu_setting_id vorhanden ist
if (selectedSpool.filament.extra.bambu_setting_id) {
payload.payload.bambu_setting_id = selectedSpool.filament.extra.bambu_setting_id.replace(/['"]+/g, '').trim();
}
console.log("Spool-In Payload:", payload);
try { try {
socket.send(JSON.stringify(payload)); socket.send(JSON.stringify(payload));
showNotification(`Spool set in AMS ${amsId} Tray ${trayId}. Pls wait`, true); showNotification(`Spool settings sent to printer. Please wait...`, true);
} catch (error) { } catch (error) {
console.error("Fehler beim Senden der WebSocket Nachricht:", error); console.error("Error sending WebSocket message:", error);
showNotification("Error while sending", false); showNotification("Error sending spool settings!", false);
} }
} }
@@ -685,4 +669,77 @@ function showNotification(message, isSuccess) {
setTimeout(() => { setTimeout(() => {
notification.remove(); notification.remove();
}, 300); }, 300);
}, 3000);} }, 3000);
}
// Neue Handler-Funktionen für bessere Modularität
function handleHeartbeatResponse(data) {
const bambuDot = document.getElementById('bambuDot');
const spoolmanDot = document.getElementById('spoolmanDot');
const ramStatus = document.getElementById('ramStatus');
if (bambuDot) {
bambuDot.className = 'status-dot ' + (data.bambu_connected ? 'online' : 'offline');
if (!data.bambu_connected) {
bambuDot.style.cursor = 'pointer';
bambuDot.onclick = function() {
sendReconnectRequest('bambu');
};
} else {
bambuDot.style.cursor = 'default';
bambuDot.onclick = null;
}
}
if (spoolmanDot) {
spoolmanDot.className = 'status-dot ' + (data.spoolman_connected ? 'online' : 'offline');
if (!data.spoolman_connected) {
spoolmanDot.style.cursor = 'pointer';
spoolmanDot.onclick = function() {
sendReconnectRequest('spoolman');
};
} else {
spoolmanDot.style.cursor = 'default';
spoolmanDot.onclick = null;
}
}
if (ramStatus) {
ramStatus.textContent = `${data.freeHeap}k`;
}
}
function handleSpoolmanSettingsResponse(data) {
if (data.payload === 'success') {
showNotification(`Spoolman Settings set successfully`, true);
} else {
showNotification(`Error setting Spoolman Settings`, false);
}
}
function sendReconnectRequest(target) {
if (socket?.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({
type: 'reconnect',
payload: target
}));
}
}
// Verbesserte Funktion zum Senden von WebSocket-Nachrichten
function sendWebSocketMessage(message) {
if (!socket || socket.readyState !== WebSocket.OPEN) {
console.error('WebSocket is not connected');
showNotification("Connection error - please try again", false);
return;
}
try {
const jsonString = JSON.stringify(message);
console.log('Sending WebSocket message:', jsonString);
socket.send(jsonString);
} catch (error) {
console.error('Error sending WebSocket message:', error);
showNotification("Error sending message", false);
}
}
-165
View File
@@ -1,165 +0,0 @@
<!-- head -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FilaMan - Filament Management Tool</title>
<link rel="icon" type="image/png" href="/favicon.ico">
<link rel="stylesheet" href="style.css">
<script>
fetch('/api/version')
.then(response => response.json())
.then(data => {
const versionSpan = document.querySelector('.version');
if (versionSpan) {
versionSpan.textContent = 'v' + data.version;
}
})
.catch(error => console.error('Error fetching version:', error));
</script>
</head>
<body>
<div class="navbar">
<div style="display: flex; align-items: center; gap: 2rem;">
<img src="/logo.png" alt="FilaMan Logo" class="logo">
<div class="logo-text">
<h1>FilaMan<span class="version"></span></h1>
<h4>Filament Management Tool</h4>
</div>
</div>
<nav style="display: flex; gap: 1rem;">
<a href="/">Start</a>
<a href="/waage">Scale</a>
<a href="/spoolman">Spoolman/Bambu</a>
<a href="/about">About</a>
<a href="/upgrade">Upgrade</a>
</nav>
<div class="status-container">
<div class="status-item">
<span class="status-dot" id="bambuDot"></span>B
</div>
<div class="status-item">
<span class="status-dot" id="spoolmanDot"></span>S
</div>
<div class="ram-status" id="ramStatus"></div>
</div>
</div>
<!-- head -->
<div class="connection-status hidden">
<div class="spinner"></div>
<span>Connection lost. Trying to reconnect...</span>
</div>
<div class="content">
<div class="three-column-layout">
<!-- Linke Spalte -->
<div class="column">
<div class="feature-box">
<div class="statistics-header">
<h2>Statistics</h2>
<button id="refreshSpoolman" class="refresh-button">
<span>Refresh Spoolman</span>
</button>
</div>
<div class="statistics-column">
<h3>Spools</h3>
<div class="spool-stat" style="display: flex; justify-content: center; align-items: center;">
<span class="stat-label">total:</span>
<span class="stat-value" id="totalSpools"></span>
<div style="width: auto;"></div>
<span class="stat-label">without Tag:</span>
<span class="stat-value" id="spoolsWithoutTag"></span>
</div>
</div>
<div class="statistics-grid">
<div class="statistics-column">
<h3>Overview</h3>
<ul class="statistics-list">
<li>
<span class="stat-label">Manufacturer:</span>
<span class="stat-value" id="totalVendors"></span>
</li>
<li>
<span class="stat-label">Weight:</span>
<span class="stat-value"><span id="totalWeight"></span></span>
</li>
<li>
<span class="stat-label">Length:</span>
<span class="stat-value"><span id="totalLength"></span></span>
</li>
</ul>
</div>
<div class="statistics-column">
<h3>Materials</h3>
<ul class="statistics-list" id="materialsList">
<!-- Wird dynamisch befüllt -->
</ul>
</div>
</div>
</div>
<div class="feature-box">
<div class="nfc-header">
<h2>NFC-Tag</h2>
<span id="nfcStatusIndicator" class="status-circle"></span>
</div>
<div class="nfc-status-display"></div>
</div>
</div>
<!-- Mittlere Spalte -->
<div class="column">
<div class="feature-box">
<h2>Spoolman Spools</h2>
<label for="vendorSelect">Manufacturer:</label>
<div style="display: flex; justify-content: space-between; align-items: center;">
<select id="vendorSelect" class="styled-select">
<option value="">Please choose...</option>
</select>
<label style="margin-left: 10px;">
<input type="checkbox" id="onlyWithoutSmId" checked onchange="updateFilamentDropdown()">
Only Spools without SM ID
</label>
</div>
</div>
<div id="filamentSection" class="feature-box hidden">
<label>Spool / Filament:</label>
<div class="custom-dropdown">
<div class="dropdown-button" onclick="toggleFilamentDropdown()">
<div class="selected-color" id="selected-color"></div>
<span id="selected-filament">Please choose...</span>
<span class="dropdown-arrow"></span>
</div>
<div class="dropdown-content" id="filament-dropdown-content">
<!-- Optionen werden dynamisch hinzugefügt -->
</div>
</div>
<p id="nfcInfo" class="nfc-status"></p>
<button id="writeNfcButton" class="btn btn-primary hidden" onclick="writeNfcTag()">Write
Tag</button>
</div>
</div>
<!-- Rechte Spalte -->
<div class="column">
<div class="feature-box">
<h2>Bambu AMS</h2>
<div id="amsDataContainer">
<div class="amsData" id="amsData">Wait for AMS-Data...</div>
</div>
</div>
</div>
</div>
</div>
<script src="spoolman.js"></script>
<script src="rfid.js"></script>
</body>
</html>
-31
View File
@@ -57,31 +57,6 @@
toggleOctoFields(); toggleOctoFields();
}; };
function removeBambuCredentials() {
fetch('/api/bambu?remove=true')
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('bambuIp').value = '';
document.getElementById('bambuSerial').value = '';
document.getElementById('bambuCode').value = '';
document.getElementById('autoSend').checked = false;
document.getElementById('autoSendTime').value = '';
document.getElementById('bambuStatusMessage').innerText = 'Bambu Credentials removed!';
// Reload with forced cache refresh after short delay
setTimeout(() => {
window.location.reload(true);
window.location.href = '/';
}, 1500);
} else {
document.getElementById('bambuStatusMessage').innerText = 'Error while removing Bambu Credentials.';
}
})
.catch(error => {
document.getElementById('bambuStatusMessage').innerText = 'Error while removing: ' + error.message;
});
}
function checkSpoolmanInstance() { function checkSpoolmanInstance() {
const url = document.getElementById('spoolmanUrl').value; const url = document.getElementById('spoolmanUrl').value;
const spoolmanOctoEnabled = document.getElementById('spoolmanOctoEnabled').checked; const spoolmanOctoEnabled = document.getElementById('spoolmanOctoEnabled').checked;
@@ -114,11 +89,6 @@
.then(data => { .then(data => {
if (data.healthy) { if (data.healthy) {
document.getElementById('bambuStatusMessage').innerText = 'Bambu Credentials saved!'; document.getElementById('bambuStatusMessage').innerText = 'Bambu Credentials saved!';
// Reload with forced cache refresh after short delay
setTimeout(() => {
window.location.reload(true);
window.location.href = '/';
}, 1500);
} else { } else {
document.getElementById('bambuStatusMessage').innerText = 'Error while saving Bambu Credentials.'; document.getElementById('bambuStatusMessage').innerText = 'Error while saving Bambu Credentials.';
} }
@@ -192,7 +162,6 @@
</div> </div>
<button style="margin: 0;" onclick="saveBambuCredentials()">Save Bambu Credentials</button> <button style="margin: 0;" onclick="saveBambuCredentials()">Save Bambu Credentials</button>
<button style="margin: 0; background-color: red;" onclick="removeBambuCredentials()">Remove Credentials</button>
<p id="bambuStatusMessage"></p> <p id="bambuStatusMessage"></p>
</div> </div>
</div> </div>
+12 -7
View File
@@ -147,13 +147,6 @@ function updateFilamentDropdown(selectedSmId = null) {
if (vendorId) { if (vendorId) {
const filteredFilaments = spoolsData.filter(spool => { const filteredFilaments = spoolsData.filter(spool => {
if (!spool?.filament?.vendor?.id) {
console.log('Problem aufgetreten bei: ', spool?.filament?.vendor);
console.log('Problematische Spulen:',
spoolsData.filter(spool => !spool?.filament?.vendor?.id));
return false;
}
const hasValidNfcId = spool.extra && const hasValidNfcId = spool.extra &&
spool.extra.nfc_id && spool.extra.nfc_id &&
spool.extra.nfc_id !== '""' && spool.extra.nfc_id !== '""' &&
@@ -247,6 +240,18 @@ async function fetchSpoolData() {
} }
} }
/*
// Exportiere Funktionen
window.getSpoolData = () => spoolsData;
window.reloadSpoolData = initSpoolman;
window.populateVendorDropdown = populateVendorDropdown;
window.updateFilamentDropdown = updateFilamentDropdown;
window.toggleFilamentDropdown = () => {
const content = document.getElementById("filament-dropdown-content");
content.classList.toggle("show");
};
*/
// Event Listener // Event Listener
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
initSpoolman(); initSpoolman();
-2
View File
@@ -129,7 +129,6 @@
if (data.status === 'success' || lastReceivedProgress >= 98) { if (data.status === 'success' || lastReceivedProgress >= 98) {
clearTimeout(wsReconnectTimer); clearTimeout(wsReconnectTimer);
setTimeout(() => { setTimeout(() => {
window.location.reload(true);
window.location.href = '/'; window.location.href = '/';
}, 30000); }, 30000);
} }
@@ -165,7 +164,6 @@
status.className = 'status success'; status.className = 'status success';
status.style.display = 'block'; status.style.display = 'block';
setTimeout(() => { setTimeout(() => {
window.location.reload(true);
window.location.href = '/'; window.location.href = '/';
}, 30000); }, 30000);
} }
-10
View File
@@ -55,8 +55,6 @@
<h5 class="card-title">Sacle Calibration</h5> <h5 class="card-title">Sacle Calibration</h5>
<button id="calibrateBtn" class="btn btn-primary">Calibrate Scale</button> <button id="calibrateBtn" class="btn btn-primary">Calibrate Scale</button>
<button id="tareBtn" class="btn btn-secondary">Tare Scale</button> <button id="tareBtn" class="btn btn-secondary">Tare Scale</button>
&nbsp;&nbsp;&nbsp;Enable Auto-TARE <input type="checkbox" id="autoTareCheckbox" onchange="setAutoTare(this.checked);"
{{autoTare}}>
<div id="statusMessage" class="mt-3"></div> <div id="statusMessage" class="mt-3"></div>
</div> </div>
</div> </div>
@@ -141,14 +139,6 @@
payload: 'tare' payload: 'tare'
})); }));
}); });
// Add auto-tare function
function setAutoTare(enabled) {
ws.send(JSON.stringify({
type: 'scale',
payload: 'setAutoTare',
enabled: enabled
}));
}
// WebSocket-Verbindung beim Laden der Seite initiieren // WebSocket-Verbindung beim Laden der Seite initiieren
connectWebSocket(); connectWebSocket();
+2 -2
View File
@@ -9,8 +9,8 @@
; https://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html
[common] [common]
version = "0.2.1" version = "1.4.1"
to_old_version = "0.2.0" to_old_version = "1.4.0"
## ##
[env:esp32dev] [env:esp32dev]
+1 -1
View File
@@ -14,7 +14,7 @@ def copy_file(input_file, output_file):
def should_compress(file): def should_compress(file):
# Skip compression for spoolman.html # Skip compression for spoolman.html
if file == 'spoolman.html' or file == 'waage.html': if file == 'spoolman.html':
return False return False
# Komprimiere nur bestimmte Dateitypen # Komprimiere nur bestimmte Dateitypen
return file.endswith(('.js', '.png', '.css', '.html')) return file.endswith(('.js', '.png', '.css', '.html'))
+5 -16
View File
@@ -3,7 +3,7 @@
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include "commonFS.h" #include "commonFS.h"
volatile spoolmanApiStateType spoolmanApiState = API_INIT; bool spoolman_connected = false;
String spoolmanUrl = ""; String spoolmanUrl = "";
bool octoEnabled = false; bool octoEnabled = false;
String octoUrl = ""; String octoUrl = "";
@@ -85,8 +85,7 @@ JsonDocument fetchSingleSpoolInfo(int spoolId) {
} }
void sendToApi(void *parameter) { void sendToApi(void *parameter) {
spoolmanApiState = API_TRANSMITTING; SendToApiParams* params = (SendToApiParams*)parameter;
SendToApiParams *params = (SendToApiParams *)parameter;
// Extrahiere die Werte // Extrahiere die Werte
String httpType = params->httpType; String httpType = params->httpType;
@@ -95,17 +94,13 @@ void sendToApi(void *parameter) {
String octoToken = params->octoToken; String octoToken = params->octoToken;
HTTPClient http; HTTPClient http;
http.setReuse(false);
http.begin(spoolsUrl); http.begin(spoolsUrl);
http.addHeader("Content-Type", "application/json"); http.addHeader("Content-Type", "application/json");
if (octoEnabled && octoToken != "") http.addHeader("X-Api-Key", octoToken); if (octoEnabled && octoToken != "") http.addHeader("X-Api-Key", octoToken);
int httpCode; int httpCode = http.PUT(updatePayload);
if (httpType == "PATCH") httpCode = http.PATCH(updatePayload); if (httpType == "PATCH") httpCode = http.PATCH(updatePayload);
else if (httpType == "POST") if (httpType == "POST") httpCode = http.POST(updatePayload);
httpCode = http.POST(updatePayload);
else
httpCode = http.PUT(updatePayload);
if (httpCode == HTTP_CODE_OK) { if (httpCode == HTTP_CODE_OK) {
Serial.println("Spoolman erfolgreich aktualisiert"); Serial.println("Spoolman erfolgreich aktualisiert");
@@ -116,12 +111,10 @@ void sendToApi(void *parameter) {
} }
http.end(); http.end();
vTaskDelay(50 / portTICK_PERIOD_MS);
// Speicher freigeben // Speicher freigeben
delete params; delete params;
vTaskDelete(NULL); vTaskDelete(NULL);
spoolmanApiState = API_IDLE;
} }
bool updateSpoolTagId(String uidString, const char* payload) { bool updateSpoolTagId(String uidString, const char* payload) {
@@ -171,7 +164,6 @@ bool updateSpoolTagId(String uidString, const char* payload) {
0, // Priorität 0, // Priorität
NULL // Task-Handle (nicht benötigt) NULL // Task-Handle (nicht benötigt)
); );
updateDoc.clear();
return true; return true;
} }
@@ -208,7 +200,6 @@ uint8_t updateSpoolWeight(String spoolId, uint16_t weight) {
0, // Priorität 0, // Priorität
NULL // Task-Handle (nicht benötigt) NULL // Task-Handle (nicht benötigt)
); );
updateDoc.clear();
return 1; return 1;
} }
@@ -246,7 +237,6 @@ bool updateSpoolOcto(int spoolId) {
0, // Priorität 0, // Priorität
NULL // Task-Handle (nicht benötigt) NULL // Task-Handle (nicht benötigt)
); );
updateDoc.clear();
return true; return true;
} }
@@ -479,8 +469,7 @@ bool checkSpoolmanInstance(const String& url) {
return false; return false;
} }
spoolmanApiState = API_IDLE; spoolman_connected = true;
oledShowTopRow();
return strcmp(status, "healthy") == 0; return strcmp(status, "healthy") == 0;
} }
} }
-7
View File
@@ -6,14 +6,7 @@
#include "website.h" #include "website.h"
#include "display.h" #include "display.h"
#include <ArduinoJson.h> #include <ArduinoJson.h>
typedef enum
{
API_INIT,
API_IDLE,
API_TRANSMITTING
} spoolmanApiStateType;
extern volatile spoolmanApiStateType spoolmanApiState;
extern bool spoolman_connected; extern bool spoolman_connected;
extern String spoolmanUrl; extern String spoolmanUrl;
extern bool octoEnabled; extern bool octoEnabled;
+10 -42
View File
@@ -27,7 +27,6 @@ const char* bambu_serialnr = nullptr;
String g_bambu_ip = ""; String g_bambu_ip = "";
String g_bambu_accesscode = ""; String g_bambu_accesscode = "";
String g_bambu_serialnr = ""; String g_bambu_serialnr = "";
bool bambuDisabled = false;
bool bambu_connected = false; bool bambu_connected = false;
bool autoSendToBambu = false; bool autoSendToBambu = false;
@@ -38,35 +37,6 @@ int ams_count = 0;
String amsJsonData; // Speichert das fertige JSON für WebSocket-Clients String amsJsonData; // Speichert das fertige JSON für WebSocket-Clients
AMSData ams_data[MAX_AMS]; // Definition des Arrays; AMSData ams_data[MAX_AMS]; // Definition des Arrays;
bool removeBambuCredentials()
{
if (BambuMqttTask)
{
vTaskDelete(BambuMqttTask);
}
if (!removeJsonValue("/bambu_credentials.json"))
{
Serial.println("Fehler beim Löschen der Bambu-Credentials.");
return false;
}
// Löschen der globalen Variablen
g_bambu_ip = "";
g_bambu_accesscode = "";
g_bambu_serialnr = "";
bambu_ip = nullptr;
bambu_accesscode = nullptr;
bambu_serialnr = nullptr;
autoSendToBambu = false;
autoSetToBambuSpoolId = 0;
ams_count = 0;
amsJsonData = "";
bambuDisabled = true;
return true;
}
bool saveBambuCredentials(const String& ip, const String& serialnr, const String& accesscode, bool autoSend, const String& autoSendTime) { bool saveBambuCredentials(const String& ip, const String& serialnr, const String& accesscode, bool autoSend, const String& autoSendTime) {
if (BambuMqttTask) { if (BambuMqttTask) {
vTaskDelete(BambuMqttTask); vTaskDelete(BambuMqttTask);
@@ -296,10 +266,8 @@ bool setBambuSpool(String payload) {
JsonDocument doc; JsonDocument doc;
DeserializationError error = deserializeJson(doc, payload); DeserializationError error = deserializeJson(doc, payload);
if (error) { if (error) {
Serial.print("Error parsing setBambuSpool-JSON: "); Serial.print("Error parsing JSON: ");
Serial.println(error.c_str()); Serial.println(error.c_str());
Serial.print("Free Heap-Memory: ");
Serial.println(ESP.getFreeHeap());
return false; return false;
} }
@@ -507,9 +475,7 @@ void mqtt_callback(char* topic, byte* payload, unsigned int length) {
message = ""; message = "";
if (error) if (error)
{ {
Serial.print("Free Heap-Memory: "); Serial.print("Fehler beim Parsen des JSON: ");
Serial.println(ESP.getFreeHeap());
Serial.print("Error parsing MQTT-JSON: ");
Serial.println(error.c_str()); Serial.println(error.c_str());
return; return;
} }
@@ -716,12 +682,10 @@ void mqtt_loop(void * parameter) {
} }
// Periodically check connection status // Periodically check connection status
if (now - lastCheck > 60000) { // Check every 60 seconds if (now - lastCheck > 30000) { // Check every 30 seconds
Serial.print("MQTT Status Check - Connected: "); Serial.print("MQTT Status Check - Connected: ");
Serial.println(client.connected() ? "Yes" : "No"); Serial.println(client.connected() ? "Yes" : "No");
lastCheck = now; lastCheck = now;
Serial.print("Free Heap-Memory: ");
Serial.println(ESP.getFreeHeap());
} }
client.loop(); client.loop();
@@ -736,13 +700,14 @@ bool setupMqtt() {
bool success = loadBambuCredentials(); bool success = loadBambuCredentials();
if (!success) { if (!success) {
bambuDisabled = true; Serial.println("Failed to load Bambu credentials");
oledShowMessage("Bambu Credentials Missing");
vTaskDelay(2000 / portTICK_PERIOD_MS);
return false; return false;
} }
if (success && bambu_ip != "" && bambu_accesscode != "" && bambu_serialnr != "") if (success && bambu_ip != "" && bambu_accesscode != "" && bambu_serialnr != "")
{ {
bambuDisabled = false;
sslClient.setCACert(root_ca); sslClient.setCACert(root_ca);
sslClient.setInsecure(); sslClient.setInsecure();
client.setServer(bambu_ip, 8883); client.setServer(bambu_ip, 8883);
@@ -799,7 +764,10 @@ bool setupMqtt() {
} }
else else
{ {
bambuDisabled = true; Serial.println("Fehler: Keine MQTT-Daten vorhanden");
oledShowMessage("Bambu Credentials Missing");
oledShowTopRow();
vTaskDelay(2000 / portTICK_PERIOD_MS);
return false; return false;
} }
return true; return true;
-2
View File
@@ -30,9 +30,7 @@ extern int ams_count;
extern AMSData ams_data[MAX_AMS]; extern AMSData ams_data[MAX_AMS];
extern bool autoSendToBambu; extern bool autoSendToBambu;
extern int autoSetToBambuSpoolId; extern int autoSetToBambuSpoolId;
extern bool bambuDisabled;
bool removeBambuCredentials();
bool loadBambuCredentials(); bool loadBambuCredentials();
bool saveBambuCredentials(const String& bambu_ip, const String& bambu_serialnr, const String& bambu_accesscode, const bool autoSend, const String& autoSendTime); bool saveBambuCredentials(const String& bambu_ip, const String& bambu_serialnr, const String& bambu_accesscode, const bool autoSend, const String& autoSendTime);
bool setupMqtt(); bool setupMqtt();
-17
View File
@@ -1,23 +1,6 @@
#include "commonFS.h" #include "commonFS.h"
#include <LittleFS.h> #include <LittleFS.h>
bool removeJsonValue(const char *filename)
{
File file = LittleFS.open(filename, "r");
if (!file)
{
return true;
}
file.close();
if (!LittleFS.remove(filename))
{
Serial.print("Fehler beim Löschen der Datei: ");
Serial.println(filename);
return false;
}
return true;
}
bool saveJsonValue(const char* filename, const JsonDocument& doc) { bool saveJsonValue(const char* filename, const JsonDocument& doc) {
File file = LittleFS.open(filename, "w"); File file = LittleFS.open(filename, "w");
if (!file) { if (!file) {
+1 -2
View File
@@ -5,8 +5,7 @@
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <LittleFS.h> #include <LittleFS.h>
bool removeJsonValue(const char *filename); bool saveJsonValue(const char* filename, const JsonDocument& doc);
bool saveJsonValue(const char *filename, const JsonDocument &doc);
bool loadJsonValue(const char* filename, JsonDocument& doc); bool loadJsonValue(const char* filename, JsonDocument& doc);
void initializeFileSystem(); void initializeFileSystem();
-5
View File
@@ -19,11 +19,6 @@ const uint16_t SCALE_LEVEL_WEIGHT = 500;
uint16_t defaultScaleCalibrationValue = 430; uint16_t defaultScaleCalibrationValue = 430;
// ***** HX711 // ***** HX711
// ***** TTP223 (Touch Sensor)
// TTP223 circuit wiring
const uint8_t TTP223_PIN = 25;
// ***** TTP223
// ***** Display // ***** Display
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// On an ESP32: 21(SDA), 22(SCL) // On an ESP32: 21(SDA), 22(SCL)
-1
View File
@@ -10,7 +10,6 @@ extern const uint8_t LOADCELL_DOUT_PIN;
extern const uint8_t LOADCELL_SCK_PIN; extern const uint8_t LOADCELL_SCK_PIN;
extern const uint8_t calVal_eepromAdress; extern const uint8_t calVal_eepromAdress;
extern const uint16_t SCALE_LEVEL_WEIGHT; extern const uint16_t SCALE_LEVEL_WEIGHT;
extern const uint8_t TTP223_PIN;
extern const int8_t OLED_RESET; extern const int8_t OLED_RESET;
extern const uint8_t SCREEN_ADDRESS; extern const uint8_t SCREEN_ADDRESS;
+3 -6
View File
@@ -177,12 +177,9 @@ void oledShowTopRow() {
display.drawBitmap(50, 0, bitmap_off , 16, 16, WHITE); display.drawBitmap(50, 0, bitmap_off , 16, 16, WHITE);
} }
if (spoolmanApiState != API_INIT) if (spoolman_connected == 1) {
{ display.drawBitmap(80, 0, bitmap_spoolman_on , 16, 16, WHITE);
display.drawBitmap(80, 0, bitmap_spoolman_on, 16, 16, WHITE); } else {
}
else
{
display.drawBitmap(80, 0, bitmap_off , 16, 16, WHITE); display.drawBitmap(80, 0, bitmap_off , 16, 16, WHITE);
} }
+19 -38
View File
@@ -15,7 +15,6 @@
bool mainTaskWasPaused = 0; bool mainTaskWasPaused = 0;
uint8_t scaleTareCounter = 0; uint8_t scaleTareCounter = 0;
bool touchSensorConnected = false;
// ##### SETUP ##### // ##### SETUP #####
void setup() { void setup() {
@@ -40,6 +39,7 @@ void setup() {
setupWebserver(server); setupWebserver(server);
// Spoolman API // Spoolman API
// api.cpp
initSpoolman(); initSpoolman();
// Bambu MQTT // Bambu MQTT
@@ -48,16 +48,7 @@ void setup() {
// NFC Reader // NFC Reader
startNfc(); startNfc();
// Touch Sensor start_scale();
pinMode(TTP223_PIN, INPUT_PULLUP);
if (digitalRead(TTP223_PIN) == LOW)
{
Serial.println("Touch Sensor is connected");
touchSensorConnected = true;
}
// Scale
start_scale(touchSensorConnected);
// WDT initialisieren mit 10 Sekunden Timeout // WDT initialisieren mit 10 Sekunden Timeout
bool panic = true; // Wenn true, löst ein WDT-Timeout einen System-Panik aus bool panic = true; // Wenn true, löst ein WDT-Timeout einen System-Panik aus
@@ -93,25 +84,13 @@ uint8_t autoAmsCounter = 0;
uint8_t weightSend = 0; uint8_t weightSend = 0;
int16_t lastWeight = 0; int16_t lastWeight = 0;
// WIFI check variables
unsigned long lastWifiCheckTime = 0; unsigned long lastWifiCheckTime = 0;
const unsigned long wifiCheckInterval = 60000; // Überprüfe alle 60 Sekunden (60000 ms) const unsigned long wifiCheckInterval = 60000; // Überprüfe alle 60 Sekunden (60000 ms)
// Button debounce variables
unsigned long lastButtonPress = 0;
const unsigned long debounceDelay = 500; // 500 ms debounce delay
// ##### PROGRAM START ##### // ##### PROGRAM START #####
void loop() { void loop() {
unsigned long currentMillis = millis(); unsigned long currentMillis = millis();
// Überprüfe den Status des Touch Sensors
if (touchSensorConnected && digitalRead(TTP223_PIN) == HIGH && currentMillis - lastButtonPress > debounceDelay)
{
lastButtonPress = currentMillis;
scaleTareRequest = true;
}
// Überprüfe regelmäßig die WLAN-Verbindung // Überprüfe regelmäßig die WLAN-Verbindung
if (intervalElapsed(currentMillis, lastWifiCheckTime, wifiCheckInterval)) { if (intervalElapsed(currentMillis, lastWifiCheckTime, wifiCheckInterval)) {
checkWiFiConnection(); checkWiFiConnection();
@@ -119,14 +98,9 @@ void loop() {
// Wenn Bambu auto set Spool aktiv // Wenn Bambu auto set Spool aktiv
if (autoSendToBambu && autoSetToBambuSpoolId > 0) { if (autoSendToBambu && autoSetToBambuSpoolId > 0) {
if (!bambuDisabled && !bambu_connected)
{
bambu_restart();
}
if (intervalElapsed(currentMillis, lastAutoSetBambuAmsTime, autoSetBambuAmsInterval)) if (intervalElapsed(currentMillis, lastAutoSetBambuAmsTime, autoSetBambuAmsInterval))
{ {
if (nfcReaderState == NFC_IDLE) if (hasReadRfidTag == 0)
{ {
lastAutoSetBambuAmsTime = currentMillis; lastAutoSetBambuAmsTime = currentMillis;
oledShowMessage("Auto Set " + String(autoSetBambuAmsCounter - autoAmsCounter) + "s"); oledShowMessage("Auto Set " + String(autoSetBambuAmsCounter - autoAmsCounter) + "s");
@@ -160,7 +134,7 @@ void loop() {
// Ausgabe der Waage auf Display // Ausgabe der Waage auf Display
if(pauseMainTask == 0) if(pauseMainTask == 0)
{ {
if (mainTaskWasPaused || (weight != lastWeight && nfcReaderState == NFC_IDLE && (!autoSendToBambu || autoSetToBambuSpoolId == 0))) if (mainTaskWasPaused || (weight != lastWeight && hasReadRfidTag == 0 && (!autoSendToBambu || autoSetToBambuSpoolId == 0)))
{ {
(weight < 2) ? ((weight < -2) ? oledShowMessage("!! -0") : oledShowWeight(0)) : oledShowWeight(weight); (weight < 2) ? ((weight < -2) ? oledShowMessage("!! -0") : oledShowWeight(0)) : oledShowWeight(weight);
} }
@@ -173,18 +147,27 @@ void loop() {
// Wenn Timer abgelaufen und nicht gerade ein RFID-Tag geschrieben wird // Wenn Timer abgelaufen und nicht gerade ein RFID-Tag geschrieben wird
if (currentMillis - lastWeightReadTime >= weightReadInterval && nfcReaderState < NFC_WRITING) if (currentMillis - lastWeightReadTime >= weightReadInterval && hasReadRfidTag < 3)
{ {
lastWeightReadTime = currentMillis; lastWeightReadTime = currentMillis;
// Prüfen ob die Waage korrekt genullt ist // Prüfen ob die Waage korrekt genullt ist
if (autoTare && (weight > 0 && weight < 5) || weight < 0) if ((weight > 0 && weight < 5) || weight < 0)
{ {
scale_tare_counter++; if(scaleTareCounter < 5)
{
scaleTareCounter++;
} }
else else
{ {
scale_tare_counter = 0; scaleTareRequest = true;
scaleTareCounter = 0;
}
}
else
{
scaleTareCounter = 0;
} }
// Prüfen ob das Gewicht gleich bleibt und dann senden // Prüfen ob das Gewicht gleich bleibt und dann senden
@@ -200,8 +183,7 @@ void loop() {
} }
// reset weight counter after writing tag // reset weight counter after writing tag
// TBD: what exactly is the logic behind this? if (currentMillis - lastWeightReadTime >= weightReadInterval && hasReadRfidTag > 1)
if (currentMillis - lastWeightReadTime >= weightReadInterval && nfcReaderState != NFC_IDLE && nfcReaderState != NFC_READ_SUCCESS)
{ {
weigthCouterToApi = 0; weigthCouterToApi = 0;
} }
@@ -209,8 +191,7 @@ void loop() {
lastWeight = weight; lastWeight = weight;
// Wenn ein Tag mit SM id erkannte wurde und der Waage Counter anspricht an SM Senden // Wenn ein Tag mit SM id erkannte wurde und der Waage Counter anspricht an SM Senden
if (spoolId != "" && weigthCouterToApi > 3 && weightSend == 0 && nfcReaderState == NFC_READ_SUCCESS) if (spoolId != "" && weigthCouterToApi > 3 && weightSend == 0 && hasReadRfidTag == 1) {
{
oledShowIcon("loading"); oledShowIcon("loading");
if (updateSpoolWeight(spoolId, weight)) if (updateSpoolWeight(spoolId, weight))
{ {
+98 -272
View File
@@ -7,23 +7,9 @@
#include "api.h" #include "api.h"
#include "esp_task_wdt.h" #include "esp_task_wdt.h"
#include "scale.h" #include "scale.h"
#include <SPI.h>
// Pin definitions for both PN532 chips //Adafruit_PN532 nfc(PN532_SCK, PN532_MISO, PN532_MOSI, PN532_SS);
#define PN532_SCK (18) // SPI SCK Adafruit_PN532 nfc(PN532_IRQ, PN532_RESET);
#define PN532_MISO (19) // SPI MISO
#define PN532_MOSI (23) // SPI MOSI
// CS pins for each PN532
#define PN532_CS1 (5) // CS for first PN532
#define PN532_CS2 (4) // CS for second PN532
// Mifare authentication key
uint8_t keyA[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
// Create two PN532 instances
Adafruit_PN532 nfc1(PN532_SCK, PN532_MISO, PN532_MOSI, PN532_CS1);
Adafruit_PN532 nfc2(PN532_SCK, PN532_MISO, PN532_MOSI, PN532_CS2);
TaskHandle_t RfidReaderTask; TaskHandle_t RfidReaderTask;
@@ -32,7 +18,7 @@ String spoolId = "";
String nfcJsonData = ""; String nfcJsonData = "";
volatile bool pauseBambuMqttTask = false; volatile bool pauseBambuMqttTask = false;
volatile nfcReaderStateType nfcReaderState = NFC_IDLE; volatile uint8_t hasReadRfidTag = 0;
// 0 = nicht gelesen // 0 = nicht gelesen
// 1 = erfolgreich gelesen // 1 = erfolgreich gelesen
// 2 = fehler beim Lesen // 2 = fehler beim Lesen
@@ -42,165 +28,6 @@ volatile nfcReaderStateType nfcReaderState = NFC_IDLE;
// 6 = reading // 6 = reading
// ***** PN532 // ***** PN532
// Buffer for reading data
uint8_t data[32];
// Function to initialize a specific PN532
bool initPN532(Adafruit_PN532 &pn532) {
pn532.begin();
uint32_t versiondata = pn532.getFirmwareVersion();
if (!versiondata) {
Serial.println("Didn't find PN532 board");
return false;
}
// Got valid data, print it out!
Serial.print("Found chip PN5"); Serial.println((versiondata >> 24) & 0xFF, HEX);
Serial.print("Firmware ver. "); Serial.print((versiondata >> 16) & 0xFF, DEC);
Serial.print('.'); Serial.println((versiondata >> 8) & 0xFF, DEC);
// Configure board to read RFID tags
pn532.SAMConfig();
Serial.println("Waiting for an ISO14443A Card ...");
return true;
}
void initNfc() {
// Configure CS pins as outputs
pinMode(PN532_CS1, OUTPUT);
pinMode(PN532_CS2, OUTPUT);
digitalWrite(PN532_CS1, HIGH); // Deselect both chips initially
digitalWrite(PN532_CS2, HIGH);
// Initialize SPI
SPI.begin(PN532_SCK, PN532_MISO, PN532_MOSI);
SPI.setFrequency(1000000); // 1MHz SPI clock
// Initialize both PN532 chips
if (!initPN532(nfc1)) {
Serial.println("Failed to initialize PN532 #1");
return;
}
if (!initPN532(nfc2)) {
Serial.println("Failed to initialize PN532 #2");
return;
}
Serial.println("Both PN532 chips initialized successfully");
}
// Function to read a specific PN532
bool readPN532(Adafruit_PN532 &pn532, uint8_t *uid, uint8_t *uidLength) {
uint8_t success;
success = pn532.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, uidLength);
return success;
}
// Function to write to a specific PN532
bool writePN532(Adafruit_PN532 &pn532, uint8_t *uid, uint8_t uidLength, uint8_t *data, uint8_t dataLen) {
if (!pn532.mifareclassic_AuthenticateBlock(uid, uidLength, 4, 1, keyA)) {
Serial.println("Failed to authenticate block");
return false;
}
if (!pn532.mifareclassic_WriteDataBlock(4, data)) {
Serial.println("Failed to write block");
return false;
}
return true;
}
void loopNfc() {
uint8_t uid1[] = {0, 0, 0, 0, 0, 0, 0};
uint8_t uid2[] = {0, 0, 0, 0, 0, 0, 0};
uint8_t uidLength1 = 0;
uint8_t uidLength2 = 0;
// Try to read from both PN532 chips
bool success1 = readPN532(nfc1, uid1, &uidLength1);
bool success2 = readPN532(nfc2, uid2, &uidLength2);
if (success1 || success2) {
// Process the first tag if found
if (success1) {
processTag(uid1, uidLength1, 1);
}
// Process the second tag if found
if (success2) {
processTag(uid2, uidLength2, 2);
}
}
}
void processTag(uint8_t *uid, uint8_t uidLength, uint8_t readerNumber) {
Adafruit_PN532 &pn532 = (readerNumber == 1) ? nfc1 : nfc2;
Serial.print("Reader "); Serial.print(readerNumber); Serial.println(" found tag:");
Serial.print("UID Length: "); Serial.println(uidLength);
Serial.print("UID Value: ");
for (uint8_t i = 0; i < uidLength; i++) {
Serial.print(" 0x"); Serial.print(uid[i], HEX);
}
Serial.println("");
if (uidLength == 7) {
uint16_t tagSize = readTagSize(pn532);
if(tagSize > 0) {
Serial.print("Tag size: "); Serial.println(tagSize);
uint8_t* data = (uint8_t*)malloc(tagSize);
memset(data, 0, tagSize);
// Mehrere Leseversuche
bool readSuccess = false;
for(int attempt = 0; attempt < 3 && !readSuccess; attempt++) {
readSuccess = true;
uint8_t numPages = tagSize / 4;
for (uint8_t i = 4; i < 4 + numPages; i++) {
if (!pn532.ntag2xx_ReadPage(i, data + (i - 4) * 4)) {
Serial.print("Failed to read page "); Serial.println(i);
readSuccess = false;
break;
}
delay(5); // Kleine Pause zwischen den Seiten
}
if (!readSuccess) {
delay(50); // Pause vor erneutem Versuch
}
}
if (readSuccess) {
Serial.println("Successfully read tag data.");
processNfcData(data, createTagId(uid, uidLength));
} else {
Serial.println("Failed to read tag data after 3 attempts");
oledShowMessage("Read Error");
}
free(data);
}
}
}
void processNfcData(uint8_t *data, String tagId) {
// Process the data and send it via WebSocket
if (decodeNdefAndReturnJson(data)) {
nfcReaderState = NFC_READ_SUCCESS;
sendNfcData(nullptr);
} else {
nfcReaderState = NFC_READ_ERROR;
oledShowMessage("NFC-Tag unknown");
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
}
// Function to write to a specific tag
bool writeNfcTag(uint8_t *uid, uint8_t uidLength, uint8_t *data, uint8_t dataLen, uint8_t readerNumber) {
// Select the appropriate PN532 based on reader number
Adafruit_PN532 &pn532 = (readerNumber == 1) ? nfc1 : nfc2;
return writePN532(pn532, uid, uidLength, data, dataLen);
}
// ##### Funktionen für RFID ##### // ##### Funktionen für RFID #####
void payloadToJson(uint8_t *data) { void payloadToJson(uint8_t *data) {
@@ -253,7 +80,7 @@ bool formatNdefTag() {
// Schreibe die Initialisierungsnachricht auf die ersten Seiten // Schreibe die Initialisierungsnachricht auf die ersten Seiten
for (int i = 0; i < sizeof(ndefInit); i += 4) { for (int i = 0; i < sizeof(ndefInit); i += 4) {
if (!nfc1.ntag2xx_WritePage(pageOffset + (i / 4), &ndefInit[i])) { if (!nfc.ntag2xx_WritePage(pageOffset + (i / 4), &ndefInit[i])) {
success = false; success = false;
break; break;
} }
@@ -262,15 +89,16 @@ bool formatNdefTag() {
return success; return success;
} }
uint16_t readTagSize(Adafruit_PN532 &pn532) { uint16_t readTagSize()
{
uint8_t buffer[4]; uint8_t buffer[4];
memset(buffer, 0, 4); memset(buffer, 0, 4);
pn532.ntag2xx_ReadPage(3, buffer); nfc.ntag2xx_ReadPage(3, buffer);
return buffer[2] * 8; return buffer[2]*8;
} }
uint8_t ntag2xx_WriteNDEF(const char *payload, Adafruit_PN532 &pn532) { uint8_t ntag2xx_WriteNDEF(const char *payload) {
uint16_t tagSize = readTagSize(pn532); uint16_t tagSize = readTagSize();
Serial.print("Tag Size: ");Serial.println(tagSize); Serial.print("Tag Size: ");Serial.println(tagSize);
uint8_t pageBuffer[4] = {0, 0, 0, 0}; uint8_t pageBuffer[4] = {0, 0, 0, 0};
@@ -329,7 +157,11 @@ uint8_t ntag2xx_WriteNDEF(const char *payload, Adafruit_PN532 &pn532) {
int bytesToWrite = (totalSize < 4) ? totalSize : 4; int bytesToWrite = (totalSize < 4) ? totalSize : 4;
memcpy(pageBuffer, combinedData + a, bytesToWrite); memcpy(pageBuffer, combinedData + a, bytesToWrite);
if (!(pn532.ntag2xx_WritePage(4+i, pageBuffer))) //uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
//uint8_t uidLength;
//nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 100);
if (!(nfc.ntag2xx_WritePage(4+i, pageBuffer)))
{ {
Serial.println("Fehler beim Schreiben der Seite."); Serial.println("Fehler beim Schreiben der Seite.");
free(combinedData); free(combinedData);
@@ -337,6 +169,8 @@ uint8_t ntag2xx_WriteNDEF(const char *payload, Adafruit_PN532 &pn532) {
} }
yield(); yield();
//esp_task_wdt_reset();
i++; i++;
a += 4; a += 4;
totalSize -= bytesToWrite; totalSize -= bytesToWrite;
@@ -345,7 +179,7 @@ uint8_t ntag2xx_WriteNDEF(const char *payload, Adafruit_PN532 &pn532) {
// Ensure the NDEF message is properly terminated // Ensure the NDEF message is properly terminated
memset(pageBuffer, 0, 4); memset(pageBuffer, 0, 4);
pageBuffer[0] = 0xFE; // NDEF record footer pageBuffer[0] = 0xFE; // NDEF record footer
if (!(pn532.ntag2xx_WritePage(4+i, pageBuffer))) if (!(nfc.ntag2xx_WritePage(4+i, pageBuffer)))
{ {
Serial.println("Fehler beim Schreiben des End-Bits."); Serial.println("Fehler beim Schreiben des End-Bits.");
free(combinedData); free(combinedData);
@@ -404,43 +238,32 @@ bool decodeNdefAndReturnJson(const byte* encodedMessage) {
void writeJsonToTag(void *parameter) { void writeJsonToTag(void *parameter) {
const char* payload = (const char*)parameter; const char* payload = (const char*)parameter;
// Gib die erstellte NDEF-Message aus
Serial.println("Erstelle NDEF-Message..."); Serial.println("Erstelle NDEF-Message...");
Serial.println(payload); Serial.println(payload);
nfcReaderState = NFC_WRITING; hasReadRfidTag = 3;
vTaskSuspend(RfidReaderTask); vTaskSuspend(RfidReaderTask);
vTaskDelay(50 / portTICK_PERIOD_MS); vTaskDelay(50 / portTICK_PERIOD_MS);
//pauseBambuMqttTask = true;
// aktualisieren der Website wenn sich der Status ändert
sendNfcData(nullptr); sendNfcData(nullptr);
vTaskDelay(100 / portTICK_PERIOD_MS); vTaskDelay(100 / portTICK_PERIOD_MS);
oledShowMessage("Waiting for NFC-Tag"); oledShowMessage("Waiting for NFC-Tag");
// Try both readers // Wait 10sec for tag
uint8_t success = 0; uint8_t success = 0;
String uidString = ""; String uidString = "";
Adafruit_PN532* activeReader = nullptr;
for (uint16_t i = 0; i < 20; i++) { for (uint16_t i = 0; i < 20; i++) {
// Try first reader uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
uint8_t uidLength; uint8_t uidLength;
success = nfc1.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 250); success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 500);
if (!success) {
// Try second reader
success = nfc2.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 250);
if (success) {
activeReader = &nfc2;
}
} else {
activeReader = &nfc1;
}
if (success) { if (success) {
for (uint8_t i = 0; i < uidLength; i++) { for (uint8_t i = 0; i < uidLength; i++) {
uidString += String(uid[i], HEX); uidString += String(uid[i], HEX);
if (i < uidLength - 1) { if (i < uidLength - 1) {
uidString += ":"; uidString += ":"; // Optional: Trennzeichen hinzufügen
} }
} }
foundNfcTag(nullptr, success); foundNfcTag(nullptr, success);
@@ -454,40 +277,48 @@ void writeJsonToTag(void *parameter) {
vTaskDelay(pdMS_TO_TICKS(1)); vTaskDelay(pdMS_TO_TICKS(1));
} }
if (success && activeReader != nullptr) { if (success)
{
oledShowIcon("transfer"); oledShowIcon("transfer");
// Schreibe die NDEF-Message auf den Tag // Schreibe die NDEF-Message auf den Tag
success = ntag2xx_WriteNDEF(payload, *activeReader); success = ntag2xx_WriteNDEF(payload);
if (success) { if (success)
{
Serial.println("NDEF-Message erfolgreich auf den Tag geschrieben"); Serial.println("NDEF-Message erfolgreich auf den Tag geschrieben");
//oledShowMessage("NFC-Tag written");
oledShowIcon("success"); oledShowIcon("success");
vTaskDelay(1000 / portTICK_PERIOD_MS); vTaskDelay(1000 / portTICK_PERIOD_MS);
nfcReaderState = NFC_WRITE_SUCCESS; hasReadRfidTag = 5;
// aktualisieren der Website wenn sich der Status ändert
sendNfcData(nullptr); sendNfcData(nullptr);
pauseBambuMqttTask = false; pauseBambuMqttTask = false;
if (updateSpoolTagId(uidString, payload)) { if (updateSpoolTagId(uidString, payload)) {
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
uint8_t uidLength; uint8_t uidLength;
oledShowIcon("success"); oledShowIcon("success");
while (activeReader->readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 500)) { while (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 500)) {
yield(); yield();
} }
} }
vTaskResume(RfidReaderTask); vTaskResume(RfidReaderTask);
vTaskDelay(500 / portTICK_PERIOD_MS); vTaskDelay(500 / portTICK_PERIOD_MS);
} else { }
else
{
Serial.println("Fehler beim Schreiben der NDEF-Message auf den Tag"); Serial.println("Fehler beim Schreiben der NDEF-Message auf den Tag");
oledShowIcon("failed"); oledShowIcon("failed");
vTaskDelay(2000 / portTICK_PERIOD_MS); vTaskDelay(2000 / portTICK_PERIOD_MS);
nfcReaderState = NFC_WRITE_ERROR; hasReadRfidTag = 4;
} }
} else { }
else
{
Serial.println("Fehler: Kein Tag zu schreiben gefunden."); Serial.println("Fehler: Kein Tag zu schreiben gefunden.");
oledShowMessage("No NFC-Tag found"); oledShowMessage("No NFC-Tag found");
vTaskDelay(2000 / portTICK_PERIOD_MS); vTaskDelay(2000 / portTICK_PERIOD_MS);
nfcReaderState = NFC_IDLE; hasReadRfidTag = 0;
} }
sendWriteResult(nullptr, success); sendWriteResult(nullptr, success);
@@ -503,7 +334,7 @@ void startWriteJsonToTag(const char* payload) {
char* payloadCopy = strdup(payload); char* payloadCopy = strdup(payload);
// Task nicht mehrfach starten // Task nicht mehrfach starten
if (nfcReaderState != NFC_WRITING) { if (hasReadRfidTag != 3) {
// Erstelle die Task // Erstelle die Task
xTaskCreate( xTaskCreate(
writeJsonToTag, // Task-Funktion writeJsonToTag, // Task-Funktion
@@ -518,78 +349,68 @@ void startWriteJsonToTag(const char* payload) {
void scanRfidTask(void * parameter) { void scanRfidTask(void * parameter) {
Serial.println("RFID Task gestartet"); Serial.println("RFID Task gestartet");
if (nfcReaderState != NFC_WRITING) for(;;) {
// Wenn geschrieben wird Schleife aussetzen
if (hasReadRfidTag != 3)
{ {
yield(); yield();
uint8_t success = 0; uint8_t success;
uint8_t uid[] = {0, 0, 0, 0, 0, 0, 0}; uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
uint8_t uidLength; uint8_t uidLength;
Adafruit_PN532 *activeReader = nullptr;
// Try first reader with increased timeout success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 1000);
success = nfc1.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 150);
if (success)
{
activeReader = &nfc1;
}
else
{
delay(50); // Small delay between readers
// Try second reader with increased timeout
success = nfc2.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 150);
if (success)
{
activeReader = &nfc2;
}
}
foundNfcTag(nullptr, success); foundNfcTag(nullptr, success);
if (success && nfcReaderState != NFC_READ_SUCCESS && activeReader != nullptr) if (success && hasReadRfidTag != 1)
{ {
// Display some basic information about the card
Serial.println("Found an ISO14443A card"); Serial.println("Found an ISO14443A card");
nfcReaderState = NFC_READING; hasReadRfidTag = 6;
oledShowIcon("transfer"); oledShowIcon("transfer");
vTaskDelay(500 / portTICK_PERIOD_MS); vTaskDelay(500 / portTICK_PERIOD_MS);
if (uidLength == 7) if (uidLength == 7)
{ {
uint16_t tagSize = readTagSize(*activeReader); uint16_t tagSize = readTagSize();
if (tagSize > 0) if(tagSize > 0)
{ {
uint8_t *data = (uint8_t *)malloc(tagSize); // Create a buffer depending on the size of the tag
uint8_t* data = (uint8_t*)malloc(tagSize);
memset(data, 0, tagSize); memset(data, 0, tagSize);
// We probably have an NTAG2xx card (though it could be Ultralight as well)
Serial.println("Seems to be an NTAG2xx tag (7 byte UID)"); Serial.println("Seems to be an NTAG2xx tag (7 byte UID)");
uint8_t numPages = readTagSize(*activeReader) / 4; uint8_t numPages = readTagSize()/4;
for (uint8_t i = 4; i < 4 + numPages; i++) for (uint8_t i = 4; i < 4+numPages; i++) {
if (!nfc.ntag2xx_ReadPage(i, data+(i-4) * 4))
{ {
if (!activeReader->ntag2xx_ReadPage(i, data + (i - 4) * 4)) break; // Stop if reading fails
{
break;
} }
// Check for NDEF message end
if (data[(i - 4) * 4] == 0xFE) if (data[(i - 4) * 4] == 0xFE)
{ {
break; break; // End of NDEF message
} }
yield(); yield();
esp_task_wdt_reset(); esp_task_wdt_reset();
vTaskDelay(pdMS_TO_TICKS(5)); // Increased delay between page reads vTaskDelay(pdMS_TO_TICKS(1));
} }
if (!decodeNdefAndReturnJson(data)) if (!decodeNdefAndReturnJson(data))
{ {
oledShowMessage("NFC-Tag unknown"); oledShowMessage("NFC-Tag unknown");
vTaskDelay(2000 / portTICK_PERIOD_MS); vTaskDelay(2000 / portTICK_PERIOD_MS);
nfcReaderState = NFC_READ_ERROR; hasReadRfidTag = 2;
} }
else else
{ {
nfcReaderState = NFC_READ_SUCCESS; hasReadRfidTag = 1;
} }
free(data); free(data);
@@ -597,7 +418,7 @@ void scanRfidTask(void * parameter) {
else else
{ {
oledShowMessage("NFC-Tag read error"); oledShowMessage("NFC-Tag read error");
nfcReaderState = NFC_READ_ERROR; hasReadRfidTag = 2;
} }
} }
else else
@@ -606,23 +427,45 @@ void scanRfidTask(void * parameter) {
} }
} }
if (!success && nfcReaderState != NFC_IDLE) if (!success && hasReadRfidTag > 0)
{ {
nfcReaderState = NFC_IDLE; hasReadRfidTag = 0;
//uidString = "";
nfcJsonData = ""; nfcJsonData = "";
Serial.println("Tag entfernt"); Serial.println("Tag entfernt");
if (!autoSendToBambu) if (!autoSendToBambu) oledShowWeight(weight);
oledShowWeight(weight);
} }
// aktualisieren der Website wenn sich der Status ändert
sendNfcData(nullptr); sendNfcData(nullptr);
delay(100); // Add small delay at end of loop
} }
yield(); yield();
} }
}
void startNfc() { void startNfc() {
initNfc(); nfc.begin(); // Beginne Kommunikation mit RFID Leser
delay(1000);
unsigned long versiondata = nfc.getFirmwareVersion(); // Lese Versionsnummer der Firmware aus
if (! versiondata) { // Wenn keine Antwort kommt
Serial.println("Kann kein RFID Board finden !"); // Sende Text "Kann kein..." an seriellen Monitor
//delay(5000);
//ESP.restart();
oledShowMessage("No RFID Board found");
delay(2000);
}
else {
Serial.print("Chip PN5 gefunden"); Serial.println((versiondata >> 24) & 0xFF, HEX); // Sende Text und Versionsinfos an seriellen
Serial.print("Firmware ver. "); Serial.print((versiondata >> 16) & 0xFF, DEC); // Monitor, wenn Antwort vom Board kommt
Serial.print('.'); Serial.println((versiondata >> 8) & 0xFF, DEC); //
nfc.SAMConfig();
// Set the max number of retry attempts to read from a card
// This prevents us from waiting forever for a card, which is
// the default behaviour of the PN532.
//nfc.setPassiveActivationRetries(0x7F);
//nfc.setPassiveActivationRetries(0xFF);
BaseType_t result = xTaskCreatePinnedToCore( BaseType_t result = xTaskCreatePinnedToCore(
scanRfidTask, /* Function to implement the task */ scanRfidTask, /* Function to implement the task */
"RfidReader", /* Name of the task */ "RfidReader", /* Name of the task */
@@ -637,22 +480,5 @@ void startNfc() {
} else { } else {
Serial.println("RFID Task erfolgreich erstellt"); Serial.println("RFID Task erfolgreich erstellt");
} }
}
String createTagId(uint8_t *uid, uint8_t uidLength)
{
String tagId = ""; // Initialisieren Sie einen leeren String
// Erstellen Sie die Tag-ID basierend auf dem UID
for (uint8_t i = 0; i < uidLength; i++)
{
tagId += String(uid[i], HEX); // Konvertieren Sie die UID in einen String
if (i < uidLength - 1)
{
tagId += ":"; // Fügen Sie einen Trennstrich hinzu, wenn es nicht das letzte Element ist
} }
}
return tagId; // Geben Sie die erstellte Tag-ID zurück
Serial.println("tagID:" + tagId);
} }
+5 -21
View File
@@ -1,32 +1,16 @@
#pragma once #ifndef NFC_H
#define NFC_H
#include <Arduino.h> #include <Arduino.h>
#include <Adafruit_PN532.h>
typedef enum
{
NFC_IDLE,
NFC_READING,
NFC_READ_SUCCESS,
NFC_READ_ERROR,
NFC_WRITING,
NFC_WRITE_SUCCESS,
NFC_WRITE_ERROR
} nfcReaderStateType;
void startNfc(); void startNfc();
void startWriteJsonToTag(const char* payload);
void writeJsonToTag(void *parameter);
void scanRfidTask(void * parameter); void scanRfidTask(void * parameter);
void processTag(uint8_t *uid, uint8_t uidLength, uint8_t readerNumber); void startWriteJsonToTag(const char* payload);
void processNfcData(uint8_t *data, String tagId);
bool decodeNdefAndReturnJson(const byte* encodedMessage);
extern TaskHandle_t RfidReaderTask; extern TaskHandle_t RfidReaderTask;
extern String nfcJsonData; extern String nfcJsonData;
extern String spoolId; extern String spoolId;
extern volatile nfcReaderStateType nfcReaderState; extern volatile uint8_t hasReadRfidTag;
extern volatile bool pauseBambuMqttTask; extern volatile bool pauseBambuMqttTask;
// Function declarations #endif
uint16_t readTagSize(Adafruit_PN532 &pn532);
String createTagId(uint8_t *uid, uint8_t uidLength);
+3 -41
View File
@@ -14,7 +14,6 @@ TaskHandle_t ScaleTask;
int16_t weight = 0; int16_t weight = 0;
uint8_t weigthCouterToApi = 0; uint8_t weigthCouterToApi = 0;
uint8_t scale_tare_counter = 0;
bool scaleTareRequest = false; bool scaleTareRequest = false;
uint8_t pauseMainTask = 0; uint8_t pauseMainTask = 0;
uint8_t scaleCalibrated = 1; uint8_t scaleCalibrated = 1;
@@ -22,26 +21,9 @@ uint8_t scaleCalibrated = 1;
Preferences preferences; Preferences preferences;
const char* NVS_NAMESPACE = "scale"; const char* NVS_NAMESPACE = "scale";
const char* NVS_KEY_CALIBRATION = "cal_value"; const char* NVS_KEY_CALIBRATION = "cal_value";
const char *NVS_KEY_AUTOTARE = "auto_tare";
bool autoTare = true;
// ##### Funktionen für Waage ##### // ##### Funktionen für Waage #####
uint8_t setAutoTare(bool autoTareValue) uint8_t tareScale() {
{
Serial.print("Set AutoTare to ");
Serial.println(autoTareValue);
autoTare = autoTareValue;
// Speichern mit NVS
preferences.begin(NVS_NAMESPACE, false); // false = readwrite
preferences.putBool(NVS_KEY_AUTOTARE, autoTare);
preferences.end();
return 1;
}
uint8_t tareScale()
{
Serial.println("Tare scale"); Serial.println("Tare scale");
scale.tare(); scale.tare();
@@ -56,23 +38,11 @@ void scale_loop(void * parameter) {
for(;;) { for(;;) {
if (scale.is_ready()) if (scale.is_ready())
{ {
// Waage automatisch Taren, wenn zu lange Abweichung // Waage nochmal Taren, wenn zu lange Abweichung
if (autoTare && scale_tare_counter >= 5)
{
Serial.println("Auto Tare scale");
scale.tare();
scale_tare_counter = 0;
}
// Waage manuell Taren
if (scaleTareRequest == true) if (scaleTareRequest == true)
{ {
Serial.println("Re-Tare scale"); Serial.println("Re-Tare scale");
oledShowMessage("TARE Scale");
vTaskDelay(pdMS_TO_TICKS(1000));
scale.tare(); scale.tare();
vTaskDelay(pdMS_TO_TICKS(1000));
oledShowWeight(0);
scaleTareRequest = false; scaleTareRequest = false;
} }
@@ -83,21 +53,13 @@ void scale_loop(void * parameter) {
} }
} }
void start_scale(bool touchSensorConnected) void start_scale() {
{
Serial.println("Prüfe Calibration Value"); Serial.println("Prüfe Calibration Value");
float calibrationValue; float calibrationValue;
// NVS lesen // NVS lesen
preferences.begin(NVS_NAMESPACE, true); // true = readonly preferences.begin(NVS_NAMESPACE, true); // true = readonly
calibrationValue = preferences.getFloat(NVS_KEY_CALIBRATION, defaultScaleCalibrationValue); calibrationValue = preferences.getFloat(NVS_KEY_CALIBRATION, defaultScaleCalibrationValue);
// auto Tare
// Wenn Touch Sensor verbunden, dann autoTare auf false setzen
// Danach prüfen was in NVS gespeichert ist
autoTare = (touchSensorConnected) ? false : true;
autoTare = preferences.getBool(NVS_KEY_AUTOTARE, autoTare);
preferences.end(); preferences.end();
Serial.print("Read Scale Calibration Value "); Serial.print("Read Scale Calibration Value ");
+2 -4
View File
@@ -4,19 +4,17 @@
#include <Arduino.h> #include <Arduino.h>
#include "HX711.h" #include "HX711.h"
uint8_t setAutoTare(bool autoTareValue);
uint8_t start_scale(bool touchSensorConnected); uint8_t start_scale();
uint8_t calibrate_scale(); uint8_t calibrate_scale();
uint8_t tareScale(); uint8_t tareScale();
extern HX711 scale; extern HX711 scale;
extern int16_t weight; extern int16_t weight;
extern uint8_t weigthCouterToApi; extern uint8_t weigthCouterToApi;
extern uint8_t scale_tare_counter;
extern uint8_t scaleTareRequest; extern uint8_t scaleTareRequest;
extern uint8_t pauseMainTask; extern uint8_t pauseMainTask;
extern uint8_t scaleCalibrated; extern uint8_t scaleCalibrated;
extern bool autoTare;
extern TaskHandle_t ScaleTask; extern TaskHandle_t ScaleTask;
+36 -65
View File
@@ -22,13 +22,14 @@ AsyncWebServer server(webserverPort);
AsyncWebSocket ws("/ws"); AsyncWebSocket ws("/ws");
uint8_t lastSuccess = 0; uint8_t lastSuccess = 0;
nfcReaderStateType lastnfcReaderState = NFC_IDLE; uint8_t lastHasReadRfidTag = 0;
void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
if (type == WS_EVT_CONNECT) { if (type == WS_EVT_CONNECT) {
Serial.println("Neuer Client verbunden!"); Serial.println("Neuer Client verbunden!");
// Sende die AMS-Daten an den neuen Client // Sende die AMS-Daten an den neuen Client
if (!bambuDisabled) sendAmsData(client); sendAmsData(client);
sendNfcData(client); sendNfcData(client);
foundNfcTag(client, 0); foundNfcTag(client, 0);
sendWriteResult(client, 3); sendWriteResult(client, 3);
@@ -42,7 +43,6 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp
String message = String((char*)data); String message = String((char*)data);
JsonDocument doc; JsonDocument doc;
deserializeJson(doc, message); deserializeJson(doc, message);
bool spoolmanConnected = (spoolmanApiState != API_INIT);
if (doc["type"] == "heartbeat") { if (doc["type"] == "heartbeat") {
// Sende Heartbeat-Antwort // Sende Heartbeat-Antwort
@@ -50,7 +50,7 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp
"\"type\":\"heartbeat\"," "\"type\":\"heartbeat\","
"\"freeHeap\":" + String(ESP.getFreeHeap()/1024) + "," "\"freeHeap\":" + String(ESP.getFreeHeap()/1024) + ","
"\"bambu_connected\":" + String(bambu_connected) + "," "\"bambu_connected\":" + String(bambu_connected) + ","
"\"spoolman_connected\":" + String(spoolmanConnected) + "" "\"spoolman_connected\":" + String(spoolman_connected) + ""
"}"); "}");
} }
@@ -73,11 +73,6 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp
success = calibrate_scale(); success = calibrate_scale();
} }
if (doc["payload"] == "setAutoTare")
{
success = setAutoTare(doc["enabled"].as<bool>());
}
if (success) { if (success) {
ws.textAll("{\"type\":\"scale\",\"payload\":\"success\"}"); ws.textAll("{\"type\":\"scale\",\"payload\":\"success\"}");
} else { } else {
@@ -144,33 +139,34 @@ void foundNfcTag(AsyncWebSocketClient *client, uint8_t success) {
} }
void sendNfcData(AsyncWebSocketClient *client) { void sendNfcData(AsyncWebSocketClient *client) {
if (lastnfcReaderState == nfcReaderState) if (lastHasReadRfidTag == hasReadRfidTag) return;
return; if (hasReadRfidTag == 0) {
// TBD: Why is there no status for reading the tag?
switch (nfcReaderState)
{
case NFC_IDLE:
ws.textAll("{\"type\":\"nfcData\", \"payload\":{}}"); ws.textAll("{\"type\":\"nfcData\", \"payload\":{}}");
break; }
case NFC_READ_SUCCESS: else if (hasReadRfidTag == 1) {
ws.textAll("{\"type\":\"nfcData\", \"payload\":" + nfcJsonData + "}"); ws.textAll("{\"type\":\"nfcData\", \"payload\":" + nfcJsonData + "}");
break; }
case NFC_READ_ERROR: else if (hasReadRfidTag == 2)
{
ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"error\":\"Empty Tag or Data not readable\"}}"); ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"error\":\"Empty Tag or Data not readable\"}}");
break; }
case NFC_WRITING: else if (hasReadRfidTag == 3)
{
ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"info\":\"Schreibe Tag...\"}}"); ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"info\":\"Schreibe Tag...\"}}");
break; }
case NFC_WRITE_SUCCESS: else if (hasReadRfidTag == 4)
ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"info\":\"Tag erfolgreich geschrieben\"}}"); {
break;
case NFC_WRITE_ERROR:
ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"error\":\"Error writing to Tag\"}}"); ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"error\":\"Error writing to Tag\"}}");
break; }
case DEFAULT: else if (hasReadRfidTag == 5)
{
ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"info\":\"Tag erfolgreich geschrieben\"}}");
}
else
{
ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"error\":\"Something went wrong\"}}"); ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"error\":\"Something went wrong\"}}");
} }
lastnfcReaderState = nfcReaderState; lastHasReadRfidTag = hasReadRfidTag;
} }
void sendAmsData(AsyncWebSocketClient *client) { void sendAmsData(AsyncWebSocketClient *client) {
@@ -206,24 +202,18 @@ void setupWebserver(AsyncWebServer &server) {
}); });
// Route für Waage // Route für Waage
server.on("/waage", HTTP_GET, [](AsyncWebServerRequest *request) server.on("/waage", HTTP_GET, [](AsyncWebServerRequest *request){
{
Serial.println("Anfrage für /waage erhalten"); Serial.println("Anfrage für /waage erhalten");
//AsyncWebServerResponse *response = request->beginResponse(LittleFS, "/waage.html.gz", "text/html"); AsyncWebServerResponse *response = request->beginResponse(LittleFS, "/waage.html.gz", "text/html");
//response->addHeader("Content-Encoding", "gzip"); response->addHeader("Content-Encoding", "gzip");
//response->addHeader("Cache-Control", CACHE_CONTROL); response->addHeader("Cache-Control", CACHE_CONTROL);
request->send(response);
String html = loadHtmlWithHeader("/waage.html"); });
html.replace("{{autoTare}}", (autoTare) ? "checked" : "");
request->send(200, "text/html", html); });
// Route für RFID // Route für RFID
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
Serial.println("Anfrage für /rfid erhalten"); Serial.println("Anfrage für /rfid erhalten");
AsyncWebServerResponse *response = request->beginResponse(LittleFS, "/rfid.html.gz", "text/html");
String page = (bambuDisabled) ? "/rfid.html.gz" : "/rfid_bambu.html.gz";
AsyncWebServerResponse *response = request->beginResponse(LittleFS, page, "text/html");
response->addHeader("Content-Encoding", "gzip"); response->addHeader("Content-Encoding", "gzip");
response->addHeader("Cache-Control", CACHE_CONTROL); response->addHeader("Cache-Control", CACHE_CONTROL);
request->send(response); request->send(response);
@@ -296,16 +286,6 @@ void setupWebserver(AsyncWebServer &server) {
} }
String url = request->getParam("url")->value(); String url = request->getParam("url")->value();
if (url.indexOf("http://") == -1 && url.indexOf("https://") == -1)
{
url = "http://" + url;
}
// Remove trailing slash if exists
if (url.length() > 0 && url.charAt(url.length() - 1) == '/')
{
url = url.substring(0, url.length() - 1);
}
bool octoEnabled = (request->getParam("octoEnabled")->value() == "true") ? true : false; bool octoEnabled = (request->getParam("octoEnabled")->value() == "true") ? true : false;
String octoUrl = request->getParam("octoUrl")->value(); String octoUrl = request->getParam("octoUrl")->value();
String octoToken = (request->getParam("octoToken")->value() != "") ? request->getParam("octoToken")->value() : ""; String octoToken = (request->getParam("octoToken")->value() != "") ? request->getParam("octoToken")->value() : "";
@@ -320,18 +300,8 @@ void setupWebserver(AsyncWebServer &server) {
request->send(200, "application/json", jsonResponse); request->send(200, "application/json", jsonResponse);
}); });
// Route für das Überprüfen der Bambu-Instanz // Route für das Überprüfen der Spoolman-Instanz
server.on("/api/bambu", HTTP_GET, [](AsyncWebServerRequest *request) server.on("/api/bambu", HTTP_GET, [](AsyncWebServerRequest *request){
{
if (request->hasParam("remove")) {
if (removeBambuCredentials()) {
request->send(200, "application/json", "{\"success\": true}");
} else {
request->send(500, "application/json", "{\"success\": false, \"error\": \"Fehler beim Löschen der Bambu-Credentials\"}");
}
return;
}
if (!request->hasParam("bambu_ip") || !request->hasParam("bambu_serialnr") || !request->hasParam("bambu_accesscode")) { if (!request->hasParam("bambu_ip") || !request->hasParam("bambu_serialnr") || !request->hasParam("bambu_accesscode")) {
request->send(400, "application/json", "{\"success\": false, \"error\": \"Missing parameter\"}"); request->send(400, "application/json", "{\"success\": false, \"error\": \"Missing parameter\"}");
return; return;
@@ -355,7 +325,8 @@ void setupWebserver(AsyncWebServer &server) {
bool success = saveBambuCredentials(bambu_ip, bambu_serialnr, bambu_accesscode, autoSend, autoSendTime); bool success = saveBambuCredentials(bambu_ip, bambu_serialnr, bambu_accesscode, autoSend, autoSendTime);
request->send(200, "application/json", "{\"healthy\": " + String(success ? "true" : "false") + "}"); }); request->send(200, "application/json", "{\"healthy\": " + String(success ? "true" : "false") + "}");
});
// Route für das Überprüfen der Spoolman-Instanz // Route für das Überprüfen der Spoolman-Instanz
server.on("/reboot", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/reboot", HTTP_GET, [](AsyncWebServerRequest *request){
+1 -1
View File
@@ -59,7 +59,7 @@ void initWiFi() {
if(wm_nonblocking) wm.setConfigPortalBlocking(false); if(wm_nonblocking) wm.setConfigPortalBlocking(false);
//wm.setConfigPortalTimeout(320); // Portal nach 5min schließen //wm.setConfigPortalTimeout(320); // Portal nach 5min schließen
wm.setWiFiAutoReconnect(true); wm.setWiFiAutoReconnect(true);
wm.setConnectTimeout(10); wm.setConnectTimeout(5);
oledShowTopRow(); oledShowTopRow();
oledShowMessage("WiFi Setup"); oledShowMessage("WiFi Setup");