Compare commits
	
		
			26 Commits
		
	
	
		
			9ed3c70c01
			...
			v1.5.5
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 3bb6c1caf5 | |||
| 37df07f102 | |||
| 8484c1310b | |||
|  | fd7b4c25b3 | ||
| d490b116b9 | |||
| 5bc6192b6f | |||
| 2202d9a1aa | |||
| 7dbca0ab87 | |||
| 24b3521f83 | |||
| 6c9f290bac | |||
|  | eab937d6ca | ||
|  | 27ef8399e4 | ||
| 2920159f32 | |||
| 2e19bccfa9 | |||
| 859e89431e | |||
| 6dc26ca51f | |||
| 0becae7ed6 | |||
| 3d31833f50 | |||
| 599cc47443 | |||
| b1f7923770 | |||
| c78c20979d | |||
| e79c522e46 | |||
| cf8cce72a5 | |||
| 0b356609d1 | |||
| 01f1e123ac | |||
| 012f91851e | 
							
								
								
									
										53
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -1,5 +1,58 @@ | |||||||
| # Changelog | # Changelog | ||||||
|  |  | ||||||
|  | ## [1.5.5] - 2025-07-22 | ||||||
|  | ### Added | ||||||
|  | - Fixes some issues with the new location tags | ||||||
|  |  | ||||||
|  | ### Changed | ||||||
|  | - update platformio.ini for version v1.5.5 | ||||||
|  |  | ||||||
|  | ### Fixed | ||||||
|  | - Merge pull request #40 from janecker/location_bambu_fix | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## [1.5.4] - 2025-07-22 | ||||||
|  | ### Added | ||||||
|  | - Adds new feature to write and read location tags | ||||||
|  | - Adds slight debouncing to the scale loop weight logic | ||||||
|  | - add loadcell desc. | ||||||
|  |  | ||||||
|  | ### Changed | ||||||
|  | - update platformio.ini for version v1.5.4 | ||||||
|  | - Merge branch 'main' of github.com:ManuelW77/Filaman | ||||||
|  | - Merge pull request #39 from janecker/location_tags | ||||||
|  | - Merge pull request #38 from janecker/scale_debouncing | ||||||
|  |  | ||||||
|  | ### Fixed | ||||||
|  | - uncomment monitor_port configuration in platformio.ini | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## [1.5.3] - 2025-04-25 | ||||||
|  | ### Changed | ||||||
|  | - update platformio.ini for version v1.5.3 | ||||||
|  | - Affiliate Links | ||||||
|  |  | ||||||
|  | ### Fixed | ||||||
|  | - update spool weight conditionally based on NFC ID | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## [1.5.2] - 2025-04-23 | ||||||
|  | ### Added | ||||||
|  | - implement multi-color filament display and styles for dropdown options | ||||||
|  | - add remaining weight logging for PUT requests and improve error reporting in sendToApi function | ||||||
|  | - add remaining weight logging and display after successful spool update | ||||||
|  | - add weight field to update payload in updateSpoolTagId function | ||||||
|  |  | ||||||
|  | ### Changed | ||||||
|  | - update platformio.ini for version v1.5.2 | ||||||
|  |  | ||||||
|  | ### Fixed | ||||||
|  | - update weight field in update payload to only include values greater than 10 | ||||||
|  | - increase stack size for sendToApi task to improve stability | ||||||
|  | - adjust tare weight tolerance to ignore deviations of 2g | ||||||
|  | - improve weight stability check before sending to API | ||||||
|  |  | ||||||
|  |  | ||||||
| ## [1.5.1] - 2025-03-30 | ## [1.5.1] - 2025-03-30 | ||||||
| ### Changed | ### Changed | ||||||
| - update version to 1.5.1 and improve OTA update handling with task management | - update version to 1.5.1 and improve OTA update handling with task management | ||||||
|   | |||||||
| @@ -54,7 +54,7 @@ Discord Server: [https://discord.gg/my7Gvaxj2v](https://discord.gg/my7Gvaxj2v) | |||||||
|  |  | ||||||
| ## Hardware-Anforderungen | ## Hardware-Anforderungen | ||||||
|  |  | ||||||
| ### Komponenten | ### Komponenten (Affiliate Links) | ||||||
| - **ESP32 Development Board:** Any ESP32 variant. | - **ESP32 Development Board:** Any ESP32 variant. | ||||||
| [Amazon Link](https://amzn.to/3FHea6D) | [Amazon Link](https://amzn.to/3FHea6D) | ||||||
| - **HX711 5kg Load Cell Amplifier:** For weight measurement. | - **HX711 5kg Load Cell Amplifier:** For weight measurement. | ||||||
| @@ -90,6 +90,12 @@ Discord Server: [https://discord.gg/my7Gvaxj2v](https://discord.gg/my7Gvaxj2v) | |||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | *Die Wägezelle wird bei den meisten HX711 Modulen folgendermaßen verkabelt:   | ||||||
|  | E+ rot   | ||||||
|  | E- schwarz   | ||||||
|  | A- weiß   | ||||||
|  | A+ grün* | ||||||
|  |  | ||||||
| ## Software-Abhängigkeiten | ## Software-Abhängigkeiten | ||||||
|  |  | ||||||
| ### ESP32-Bibliotheken | ### ESP32-Bibliotheken | ||||||
|   | |||||||
| @@ -58,7 +58,7 @@ Discord Server: [https://discord.gg/my7Gvaxj2v](https://discord.gg/my7Gvaxj2v) | |||||||
|  |  | ||||||
| ## Hardware Requirements | ## Hardware Requirements | ||||||
|  |  | ||||||
| ### Components | ### Components (Affiliate Links) | ||||||
| - **ESP32 Development Board:** Any ESP32 variant. | - **ESP32 Development Board:** Any ESP32 variant. | ||||||
| [Amazon Link](https://amzn.to/3FHea6D) | [Amazon Link](https://amzn.to/3FHea6D) | ||||||
| - **HX711 5kg Load Cell Amplifier:** For weight measurement. | - **HX711 5kg Load Cell Amplifier:** For weight measurement. | ||||||
| @@ -94,6 +94,12 @@ Discord Server: [https://discord.gg/my7Gvaxj2v](https://discord.gg/my7Gvaxj2v) | |||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | *The load cell is connected to most HX711 modules as follows:   | ||||||
|  | E+ red   | ||||||
|  | E- black   | ||||||
|  | A- white   | ||||||
|  | A+ green* | ||||||
|  |  | ||||||
| ## Software Dependencies | ## Software Dependencies | ||||||
|  |  | ||||||
| ### ESP32 Libraries | ### ESP32 Libraries | ||||||
|   | |||||||
| @@ -139,6 +139,18 @@ | |||||||
|                 <p id="nfcInfo" class="nfc-status"></p> |                 <p id="nfcInfo" class="nfc-status"></p> | ||||||
|                 <button id="writeNfcButton" class="btn btn-primary hidden" onclick="writeNfcTag()">Write Tag</button> |                 <button id="writeNfcButton" class="btn btn-primary hidden" onclick="writeNfcTag()">Write Tag</button> | ||||||
|             </div> |             </div> | ||||||
|  |  | ||||||
|  |             <div class="feature-box"> | ||||||
|  |                 <h2>Spoolman Locations</h2> | ||||||
|  |                 <label for="locationSelect">Location:</label> | ||||||
|  |                 <div style="display: flex; justify-content: space-between; align-items: center;"> | ||||||
|  |                     <select id="locationSelect" class="styled-select"> | ||||||
|  |                         <option value="">Please choose...</option> | ||||||
|  |                     </select> | ||||||
|  |                 </div> | ||||||
|  |                 <p id="nfcInfoLocation" class="nfc-status"></p> | ||||||
|  |                 <button id="writeLocationNfcButton" class="btn btn-primary hidden" onclick="writeLocationNfcTag()">Write Location Tag</button> | ||||||
|  |             </div> | ||||||
|         </div> |         </div> | ||||||
|  |  | ||||||
|     </div> |     </div> | ||||||
|   | |||||||
							
								
								
									
										96
									
								
								html/rfid.js
									
									
									
									
									
								
							
							
						
						
									
										96
									
								
								html/rfid.js
									
									
									
									
									
								
							| @@ -215,20 +215,6 @@ document.addEventListener('filamentSelected', function (event) { | |||||||
|     updateSpoolButtons(selectedText !== "Please choose..."); |     updateSpoolButtons(selectedText !== "Please choose..."); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| // Hilfsfunktion für kontrastreiche Textfarbe |  | ||||||
| function getContrastColor(hexcolor) { |  | ||||||
|     // Konvertiere Hex zu RGB |  | ||||||
|     const r = parseInt(hexcolor.substr(0,2),16); |  | ||||||
|     const g = parseInt(hexcolor.substr(2,2),16); |  | ||||||
|     const b = parseInt(hexcolor.substr(4,2),16); |  | ||||||
|      |  | ||||||
|     // Berechne Helligkeit (YIQ Formel) |  | ||||||
|     const yiq = ((r*299)+(g*587)+(b*114))/1000; |  | ||||||
|      |  | ||||||
|     // Return schwarz oder weiß basierend auf Helligkeit |  | ||||||
|     return (yiq >= 128) ? '#000000' : '#FFFFFF'; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function updateNfcInfo() { | function updateNfcInfo() { | ||||||
|     const selectedText = document.getElementById("selected-filament").textContent; |     const selectedText = document.getElementById("selected-filament").textContent; | ||||||
|     const nfcInfo = document.getElementById("nfcInfo"); |     const nfcInfo = document.getElementById("nfcInfo"); | ||||||
| @@ -569,7 +555,10 @@ function updateNfcData(data) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // HTML für die Datenanzeige erstellen |     // HTML für die Datenanzeige erstellen | ||||||
|     let html = ` |     let html = ""; | ||||||
|  |  | ||||||
|  |     if(data.sm_id){ | ||||||
|  |         html = ` | ||||||
|         <div class="nfc-card-data" style="margin-top: 10px;"> |         <div class="nfc-card-data" style="margin-top: 10px;"> | ||||||
|             <p><strong>Brand:</strong> ${data.brand || 'N/A'}</p> |             <p><strong>Brand:</strong> ${data.brand || 'N/A'}</p> | ||||||
|             <p><strong>Type:</strong> ${data.type || 'N/A'} ${data.color_hex ? `<span style=" |             <p><strong>Type:</strong> ${data.type || 'N/A'} ${data.color_hex ? `<span style=" | ||||||
| @@ -582,10 +571,27 @@ function updateNfcData(data) { | |||||||
|                 border-radius: 3px; |                 border-radius: 3px; | ||||||
|                 margin-left: 5px; |                 margin-left: 5px; | ||||||
|             "></span>` : ''}</p> |             "></span>` : ''}</p> | ||||||
|     `; |         `; | ||||||
|  |  | ||||||
|  |         // Spoolman ID anzeigen | ||||||
|  |         html += `<p><strong>Spoolman ID:</strong> ${data.sm_id || 'No Spoolman ID'}</p>`; | ||||||
|  |      } | ||||||
|  |      else if(data.location) | ||||||
|  |      { | ||||||
|  |         html = ` | ||||||
|  |         <div class="nfc-card-data" style="margin-top: 10px;"> | ||||||
|  |             <p><strong>Location:</strong> ${data.location || 'N/A'}</p> | ||||||
|  |         `; | ||||||
|  |      } | ||||||
|  |      else | ||||||
|  |      { | ||||||
|  |         html = ` | ||||||
|  |         <div class="nfc-card-data" style="margin-top: 10px;"> | ||||||
|  |             <p><strong>Unknown tag</strong></p> | ||||||
|  |         `; | ||||||
|  |      } | ||||||
|  |  | ||||||
|      |      | ||||||
|     // Spoolman ID anzeigen |  | ||||||
|     html += `<p><strong>Spoolman ID:</strong> ${data.sm_id || 'No Spoolman ID'}</p>`; |  | ||||||
|  |  | ||||||
|     // Nur wenn eine sm_id vorhanden ist, aktualisiere die Dropdowns |     // Nur wenn eine sm_id vorhanden ist, aktualisiere die Dropdowns | ||||||
|     if (data.sm_id) { |     if (data.sm_id) { | ||||||
| @@ -661,16 +667,56 @@ function writeNfcTag() { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function writeLocationNfcTag() { | ||||||
|  |     const selectedText = document.getElementById("locationSelect").value; | ||||||
|  |     if (selectedText === "Please choose...") { | ||||||
|  |         alert('Please select a location first.'); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     // Erstelle das NFC-Datenpaket mit korrekten Datentypen | ||||||
|  |     const nfcData = { | ||||||
|  |         location: String(selectedText) | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     if (socket?.readyState === WebSocket.OPEN) { | ||||||
|  |         const writeButton = document.getElementById("writeLocationNfcButton"); | ||||||
|  |         writeButton.classList.add("writing"); | ||||||
|  |         writeButton.textContent = "Writing"; | ||||||
|  |         socket.send(JSON.stringify({ | ||||||
|  |             type: 'writeNfcTag', | ||||||
|  |             payload: nfcData | ||||||
|  |         })); | ||||||
|  |     } else { | ||||||
|  |         alert('Not connected to Server. Please check connection.'); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| function handleWriteNfcTagResponse(success) { | function handleWriteNfcTagResponse(success) { | ||||||
|     const writeButton = document.getElementById("writeNfcButton"); |     const writeButton = document.getElementById("writeNfcButton"); | ||||||
|     writeButton.classList.remove("writing"); |     const writeLocationButton = document.getElementById("writeLocationNfcButton"); | ||||||
|     writeButton.classList.add(success ? "success" : "error"); |     if(writeButton.classList.contains("writing")){ | ||||||
|     writeButton.textContent = success ? "Write success" : "Write failed"; |         writeButton.classList.remove("writing"); | ||||||
|  |         writeButton.classList.add(success ? "success" : "error"); | ||||||
|  |         writeButton.textContent = success ? "Write success" : "Write failed"; | ||||||
|  |  | ||||||
|  |         setTimeout(() => { | ||||||
|  |             writeButton.classList.remove("success", "error"); | ||||||
|  |             writeButton.textContent = "Write Tag"; | ||||||
|  |         }, 5000); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if(writeLocationButton.classList.contains("writing")){ | ||||||
|  |         writeLocationButton.classList.remove("writing"); | ||||||
|  |         writeLocationButton.classList.add(success ? "success" : "error"); | ||||||
|  |         writeLocationButton.textContent = success ? "Write success" : "Write failed"; | ||||||
|  |  | ||||||
|  |         setTimeout(() => { | ||||||
|  |             writeLocationButton.classList.remove("success", "error"); | ||||||
|  |             writeLocationButton.textContent = "Write Location Tag"; | ||||||
|  |         }, 5000); | ||||||
|  |     } | ||||||
|  |  | ||||||
|      |      | ||||||
|     setTimeout(() => { |  | ||||||
|         writeButton.classList.remove("success", "error"); |  | ||||||
|         writeButton.textContent = "Write Tag"; |  | ||||||
|     }, 5000); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| function showNotification(message, isSuccess) { | function showNotification(message, isSuccess) { | ||||||
|   | |||||||
| @@ -139,6 +139,18 @@ | |||||||
|                 <p id="nfcInfo" class="nfc-status"></p> |                 <p id="nfcInfo" class="nfc-status"></p> | ||||||
|                 <button id="writeNfcButton" class="btn btn-primary hidden" onclick="writeNfcTag()">Write Tag</button> |                 <button id="writeNfcButton" class="btn btn-primary hidden" onclick="writeNfcTag()">Write Tag</button> | ||||||
|             </div> |             </div> | ||||||
|  |  | ||||||
|  |             <div class="feature-box"> | ||||||
|  |                 <h2>Spoolman Locations</h2> | ||||||
|  |                 <label for="locationSelect">Location:</label> | ||||||
|  |                 <div style="display: flex; justify-content: space-between; align-items: center;"> | ||||||
|  |                     <select id="locationSelect" class="styled-select"> | ||||||
|  |                         <option value="">Please choose...</option> | ||||||
|  |                     </select> | ||||||
|  |                 </div> | ||||||
|  |                 <p id="nfcInfoLocation" class="nfc-status"></p> | ||||||
|  |                 <button id="writeLocationNfcButton" class="btn btn-primary hidden" onclick="writeLocationNfcTag()">Write Location Tag</button> | ||||||
|  |             </div> | ||||||
|         </div> |         </div> | ||||||
|  |  | ||||||
|         <!-- Rechte Spalte --> |         <!-- Rechte Spalte --> | ||||||
|   | |||||||
							
								
								
									
										116
									
								
								html/spoolman.js
									
									
									
									
									
								
							
							
						
						
									
										116
									
								
								html/spoolman.js
									
									
									
									
									
								
							| @@ -1,6 +1,7 @@ | |||||||
| // Globale Variablen | // Globale Variablen | ||||||
| let spoolmanUrl = ''; | let spoolmanUrl = ''; | ||||||
| let spoolsData = []; | let spoolsData = []; | ||||||
|  | let locationData = []; | ||||||
|  |  | ||||||
| // Hilfsfunktionen für Datenmanipulation | // Hilfsfunktionen für Datenmanipulation | ||||||
| function processSpoolData(data) { | function processSpoolData(data) { | ||||||
| @@ -133,6 +134,26 @@ function populateVendorDropdown(data, selectedSmId = null) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Dropdown-Funktionen | ||||||
|  | function populateLocationDropdown(data) { | ||||||
|  |     const locationSelect = document.getElementById("locationSelect"); | ||||||
|  |     if (!locationSelect) { | ||||||
|  |         console.error('locationSelect Element nicht gefunden'); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     locationSelect.innerHTML = '<option value="">Bitte wählen...</option>'; | ||||||
|  |     // Dropdown mit gefilterten Herstellern befüllen - alphabetisch sortiert | ||||||
|  |     Object.entries(data) | ||||||
|  |         .sort(([, nameA], [, nameB]) => nameA.localeCompare(nameB)) // Sort vendors alphabetically by name | ||||||
|  |         .forEach(([id, name]) => { | ||||||
|  |             const option = document.createElement("option"); | ||||||
|  |             option.value = name; | ||||||
|  |             option.textContent = name; | ||||||
|  |             locationSelect.appendChild(option); | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  |  | ||||||
| function updateFilamentDropdown(selectedSmId = null) { | function updateFilamentDropdown(selectedSmId = null) { | ||||||
|     const vendorId = document.getElementById("vendorSelect").value; |     const vendorId = document.getElementById("vendorSelect").value; | ||||||
|     const dropdownContentInner = document.getElementById("filament-dropdown-content"); |     const dropdownContentInner = document.getElementById("filament-dropdown-content"); | ||||||
| @@ -169,9 +190,32 @@ function updateFilamentDropdown(selectedSmId = null) { | |||||||
|             option.setAttribute("data-value", spool.filament.id); |             option.setAttribute("data-value", spool.filament.id); | ||||||
|             option.setAttribute("data-nfc-id", spool.extra.nfc_id || ""); |             option.setAttribute("data-nfc-id", spool.extra.nfc_id || ""); | ||||||
|              |              | ||||||
|             const colorHex = spool.filament.color_hex || 'FFFFFF'; |  | ||||||
|  |             // Generate color representation based on filament type (single or multi color) | ||||||
|  |             let colorHTML = ''; | ||||||
|  |              | ||||||
|  |             // Check if this is a multicolor filament | ||||||
|  |             if (spool.filament.multi_color_hexes) { | ||||||
|  |                 // Parse multi color hexes from comma-separated string | ||||||
|  |                 const colors = spool.filament.multi_color_hexes.replace(/#/g, '').split(','); | ||||||
|  |                  | ||||||
|  |                 // Determine the display style based on direction | ||||||
|  |                 const direction = spool.filament.multi_color_direction || 'coaxial'; | ||||||
|  |                  | ||||||
|  |                 // Generate color circles for each color | ||||||
|  |                 colorHTML = '<div class="option-colors">'; | ||||||
|  |                 colors.forEach(color => { | ||||||
|  |                     colorHTML += `<div class="option-color multi-color ${direction}" style="background-color: #${color}"></div>`; | ||||||
|  |                 }); | ||||||
|  |                 colorHTML += '</div>'; | ||||||
|  |             } else { | ||||||
|  |                 // Single color filament | ||||||
|  |                 const colorHex = spool.filament.color_hex || 'FFFFFF'; | ||||||
|  |                 colorHTML = `<div class="option-color" style="background-color: #${colorHex}"></div>`; | ||||||
|  |             } | ||||||
|  |              | ||||||
|             option.innerHTML = ` |             option.innerHTML = ` | ||||||
|                 <div class="option-color" style="background-color: #${colorHex}"></div> |                 ${colorHTML} | ||||||
|                 <span>${spool.id} | ${spool.filament.name} (${spool.filament.material})</span> |                 <span>${spool.id} | ${spool.filament.name} (${spool.filament.material})</span> | ||||||
|             `; |             `; | ||||||
|              |              | ||||||
| @@ -185,12 +229,41 @@ function updateFilamentDropdown(selectedSmId = null) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function updateLocationSelect(){ | ||||||
|  |     const writeLocationNfcButton = document.getElementById('writeLocationNfcButton'); | ||||||
|  |     if(writeLocationNfcButton){ | ||||||
|  |         writeLocationNfcButton.classList.remove("hidden"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| function selectFilament(spool) { | function selectFilament(spool) { | ||||||
|     const selectedColor = document.getElementById("selected-color"); |     const selectedColor = document.getElementById("selected-color"); | ||||||
|     const selectedText = document.getElementById("selected-filament"); |     const selectedText = document.getElementById("selected-filament"); | ||||||
|     const dropdownContent = document.getElementById("filament-dropdown-content"); |     const dropdownContent = document.getElementById("filament-dropdown-content"); | ||||||
|      |      | ||||||
|     selectedColor.style.backgroundColor = `#${spool.filament.color_hex || 'FFFFFF'}`; |     // Update the selected color display | ||||||
|  |     if (spool.filament.multi_color_hexes) { | ||||||
|  |         // Handle multicolor filament display in the selection header | ||||||
|  |         const colors = spool.filament.multi_color_hexes.replace(/#/g, '').split(','); | ||||||
|  |         const direction = spool.filament.multi_color_direction || 'coaxial'; | ||||||
|  |          | ||||||
|  |         // Replace the single color div with multiple color divs | ||||||
|  |         selectedColor.innerHTML = ''; | ||||||
|  |         colors.forEach(color => { | ||||||
|  |             const colorDiv = document.createElement('div'); | ||||||
|  |             colorDiv.className = `color-segment multi-color ${direction}`; | ||||||
|  |             colorDiv.style.backgroundColor = `#${color}`; | ||||||
|  |             selectedColor.appendChild(colorDiv); | ||||||
|  |         }); | ||||||
|  |         // Add multiple color class to the container | ||||||
|  |         selectedColor.classList.add('multi-color-container'); | ||||||
|  |     } else { | ||||||
|  |         // Single color filament - reset to default display | ||||||
|  |         selectedColor.innerHTML = ''; | ||||||
|  |         selectedColor.classList.remove('multi-color-container'); | ||||||
|  |         selectedColor.style.backgroundColor = `#${spool.filament.color_hex || 'FFFFFF'}`; | ||||||
|  |     } | ||||||
|  |      | ||||||
|     selectedText.textContent = `${spool.id} | ${spool.filament.name} (${spool.filament.material})`; |     selectedText.textContent = `${spool.id} | ${spool.filament.name} (${spool.filament.material})`; | ||||||
|     dropdownContent.classList.remove("show"); |     dropdownContent.classList.remove("show"); | ||||||
|      |      | ||||||
| @@ -220,6 +293,14 @@ async function initSpoolman() { | |||||||
|         document.dispatchEvent(new CustomEvent('spoolDataLoaded', {  |         document.dispatchEvent(new CustomEvent('spoolDataLoaded', {  | ||||||
|             detail: spoolsData  |             detail: spoolsData  | ||||||
|         })); |         })); | ||||||
|  |          | ||||||
|  |         locationData = await fetchLocationData(); | ||||||
|  |          | ||||||
|  |         document.dispatchEvent(new CustomEvent('locationDataLoaded', {  | ||||||
|  |             detail: locationData  | ||||||
|  |         })); | ||||||
|  |  | ||||||
|  |  | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|         console.error('Fehler beim Initialisieren von Spoolman:', error); |         console.error('Fehler beim Initialisieren von Spoolman:', error); | ||||||
|         document.dispatchEvent(new CustomEvent('spoolmanError', {  |         document.dispatchEvent(new CustomEvent('spoolmanError', {  | ||||||
| @@ -247,6 +328,25 @@ async function fetchSpoolData() { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | async function fetchLocationData() { | ||||||
|  |     try { | ||||||
|  |         if (!spoolmanUrl) { | ||||||
|  |             throw new Error('Spoolman URL ist nicht initialisiert'); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         const response = await fetch(`${spoolmanUrl}/api/v1/location`); | ||||||
|  |         if (!response.ok) { | ||||||
|  |             throw new Error(`HTTP error! status: ${response.status}`); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         const data = await response.json(); | ||||||
|  |         return data; | ||||||
|  |     } catch (error) { | ||||||
|  |         console.error('Fehler beim Abrufen der Location-Daten:', error); | ||||||
|  |         return []; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| // Event Listener | // Event Listener | ||||||
| document.addEventListener('DOMContentLoaded', () => { | document.addEventListener('DOMContentLoaded', () => { | ||||||
|     initSpoolman(); |     initSpoolman(); | ||||||
| @@ -256,6 +356,11 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|         vendorSelect.addEventListener('change', () => updateFilamentDropdown()); |         vendorSelect.addEventListener('change', () => updateFilamentDropdown()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     const locationSelect = document.getElementById('locationSelect'); | ||||||
|  |     if (locationSelect) { | ||||||
|  |         locationSelect.addEventListener('change', () => updateLocationSelect()); | ||||||
|  |     } | ||||||
|  |      | ||||||
|     const onlyWithoutSmId = document.getElementById('onlyWithoutSmId'); |     const onlyWithoutSmId = document.getElementById('onlyWithoutSmId'); | ||||||
|     if (onlyWithoutSmId) { |     if (onlyWithoutSmId) { | ||||||
|         onlyWithoutSmId.addEventListener('change', () => { |         onlyWithoutSmId.addEventListener('change', () => { | ||||||
| @@ -268,6 +373,10 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|         populateVendorDropdown(event.detail); |         populateVendorDropdown(event.detail); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  |     document.addEventListener('locationDataLoaded', (event) => { | ||||||
|  |         populateLocationDropdown(event.detail); | ||||||
|  |     }); | ||||||
|  |      | ||||||
|     window.onclick = function(event) { |     window.onclick = function(event) { | ||||||
|         if (!event.target.closest('.custom-dropdown')) { |         if (!event.target.closest('.custom-dropdown')) { | ||||||
|             const dropdowns = document.getElementsByClassName("dropdown-content"); |             const dropdowns = document.getElementsByClassName("dropdown-content"); | ||||||
| @@ -297,6 +406,7 @@ window.getSpoolData = () => spoolsData; | |||||||
| window.setSpoolData = (data) => { spoolsData = data; }; | window.setSpoolData = (data) => { spoolsData = data; }; | ||||||
| window.reloadSpoolData = initSpoolman; | window.reloadSpoolData = initSpoolman; | ||||||
| window.populateVendorDropdown = populateVendorDropdown; | window.populateVendorDropdown = populateVendorDropdown; | ||||||
|  | window.populateLocationDropdown = populateLocationDropdown; | ||||||
| window.updateFilamentDropdown = updateFilamentDropdown; | window.updateFilamentDropdown = updateFilamentDropdown; | ||||||
| window.toggleFilamentDropdown = () => { | window.toggleFilamentDropdown = () => { | ||||||
|     const content = document.getElementById("filament-dropdown-content"); |     const content = document.getElementById("filament-dropdown-content"); | ||||||
|   | |||||||
| @@ -759,6 +759,50 @@ a:hover { | |||||||
|     flex-shrink: 0; |     flex-shrink: 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Multi-color filament styles */ | ||||||
|  | .option-colors { | ||||||
|  |     display: flex; | ||||||
|  |     flex-shrink: 0; | ||||||
|  |     gap: 2px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .multi-color { | ||||||
|  |     width: 14px; | ||||||
|  |     height: 14px; | ||||||
|  |     border-radius: 50%; | ||||||
|  |     border: 1px solid #333; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Coaxial pattern (horizontal stripes) */ | ||||||
|  | .multi-color.coaxial { | ||||||
|  |     border-radius: 50%; | ||||||
|  |     position: relative; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Longitudinal pattern (vertical stripes) */ | ||||||
|  | .multi-color.longitudinal { | ||||||
|  |     border-radius: 50%; | ||||||
|  |     position: relative; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Container for multiple colors in selected display */ | ||||||
|  | .multi-color-container { | ||||||
|  |     display: flex !important; | ||||||
|  |     background: none !important; | ||||||
|  |     border: none !important; | ||||||
|  |     gap: 2px; | ||||||
|  |     align-items: center; | ||||||
|  |     justify-content: flex-start; | ||||||
|  |     width: auto !important; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .color-segment { | ||||||
|  |     width: 16px; | ||||||
|  |     height: 16px; | ||||||
|  |     border-radius: 50%; | ||||||
|  |     border: 1px solid #333; | ||||||
|  | } | ||||||
|  |  | ||||||
| .notification { | .notification { | ||||||
|     position: fixed; |     position: fixed; | ||||||
|     top: 20px; |     top: 20px; | ||||||
| @@ -927,31 +971,35 @@ input[type="submit"]:disabled, | |||||||
| } | } | ||||||
|  |  | ||||||
| /* Schreib-Button */ | /* Schreib-Button */ | ||||||
| #writeNfcButton { | #writeNfcButton, #writeLocationNfcButton { | ||||||
|     background-color: #007bff; |     background-color: #007bff; | ||||||
|     color: white; |     color: white; | ||||||
|     transition: background-color 0.3s, color 0.3s; |     transition: background-color 0.3s, color 0.3s; | ||||||
|     width: 160px; |     width: 160px; | ||||||
| } | } | ||||||
|  |  | ||||||
| #writeNfcButton.writing { | #writeNfcButton.writing, #writeLocationNfcButton.writing { | ||||||
|     background-color: #ffc107; |     background-color: #ffc107; | ||||||
|     color: black; |     color: black; | ||||||
|     width: 160px; |     width: 160px; | ||||||
| } | } | ||||||
|  |  | ||||||
| #writeNfcButton.success { | #writeNfcButton.success, #writeLocationNfcButton.success { | ||||||
|     background-color: #28a745; |     background-color: #28a745; | ||||||
|     color: white; |     color: white; | ||||||
|     width: 160px; |     width: 160px; | ||||||
| } | } | ||||||
|  |  | ||||||
| #writeNfcButton.error { | #writeNfcButton.error, #writeLocationNfcButton.error { | ||||||
|     background-color: #dc3545; |     background-color: #dc3545; | ||||||
|     color: white; |     color: white; | ||||||
|     width: 160px; |     width: 160px; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #writeLocationNfcButton{ | ||||||
|  |     width: 250px; | ||||||
|  | } | ||||||
|  |  | ||||||
| @keyframes dots { | @keyframes dots { | ||||||
|     0% { content: ""; } |     0% { content: ""; } | ||||||
|     33% { content: "."; } |     33% { content: "."; } | ||||||
| @@ -959,7 +1007,7 @@ input[type="submit"]:disabled, | |||||||
|     100% { content: "..."; } |     100% { content: "..."; } | ||||||
| } | } | ||||||
|  |  | ||||||
| #writeNfcButton.writing::after { | #writeNfcButton.writing::after, #writeLocationNfcButton.writing::after { | ||||||
|     content: "..."; |     content: "..."; | ||||||
|     animation: dots 1s steps(3, end) infinite; |     animation: dots 1s steps(3, end) infinite; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ | |||||||
| ; https://docs.platformio.org/page/projectconf.html | ; https://docs.platformio.org/page/projectconf.html | ||||||
|  |  | ||||||
| [common] | [common] | ||||||
| version = "1.5.1" | version = "1.5.5" | ||||||
| to_old_version = "1.5.0" | to_old_version = "1.5.0" | ||||||
|  |  | ||||||
| ## | ## | ||||||
| @@ -18,6 +18,7 @@ platform = espressif32 | |||||||
| board = esp32dev | board = esp32dev | ||||||
| framework = arduino | framework = arduino | ||||||
| monitor_speed = 115200 | monitor_speed = 115200 | ||||||
|  | #monitor_port = /dev/cu.usbmodem01 | ||||||
|  |  | ||||||
| lib_deps = | lib_deps = | ||||||
|     tzapu/WiFiManager @ ^2.0.17 |     tzapu/WiFiManager @ ^2.0.17 | ||||||
|   | |||||||
							
								
								
									
										83
									
								
								src/api.cpp
									
									
									
									
									
								
							
							
						
						
									
										83
									
								
								src/api.cpp
									
									
									
									
									
								
							| @@ -11,6 +11,7 @@ String octoUrl = ""; | |||||||
| String octoToken = ""; | String octoToken = ""; | ||||||
|  |  | ||||||
| struct SendToApiParams { | struct SendToApiParams { | ||||||
|  |     SpoolmanApiRequestType requestType; | ||||||
|     String httpType; |     String httpType; | ||||||
|     String spoolsUrl; |     String spoolsUrl; | ||||||
|     String updatePayload; |     String updatePayload; | ||||||
| @@ -90,6 +91,7 @@ void sendToApi(void *parameter) { | |||||||
|     SendToApiParams* params = (SendToApiParams*)parameter; |     SendToApiParams* params = (SendToApiParams*)parameter; | ||||||
|  |  | ||||||
|     // Extrahiere die Werte |     // Extrahiere die Werte | ||||||
|  |     SpoolmanApiRequestType requestType = params->requestType; | ||||||
|     String httpType = params->httpType; |     String httpType = params->httpType; | ||||||
|     String spoolsUrl = params->spoolsUrl; |     String spoolsUrl = params->spoolsUrl; | ||||||
|     String updatePayload = params->updatePayload; |     String updatePayload = params->updatePayload; | ||||||
| @@ -109,8 +111,31 @@ void sendToApi(void *parameter) { | |||||||
|  |  | ||||||
|     if (httpCode == HTTP_CODE_OK) { |     if (httpCode == HTTP_CODE_OK) { | ||||||
|         Serial.println("Spoolman erfolgreich aktualisiert"); |         Serial.println("Spoolman erfolgreich aktualisiert"); | ||||||
|  |  | ||||||
|  |         // Restgewicht der Spule auslesen | ||||||
|  |         String payload = http.getString(); | ||||||
|  |         JsonDocument doc; | ||||||
|  |         DeserializationError error = deserializeJson(doc, payload); | ||||||
|  |         if (error) { | ||||||
|  |             Serial.print("Fehler beim Parsen der JSON-Antwort: "); | ||||||
|  |             Serial.println(error.c_str()); | ||||||
|  |         } else { | ||||||
|  |             if (requestType == API_REQUEST_SPOOL_WEIGHT_UPDATE) { | ||||||
|  |                 uint16_t remaining_weight = doc["remaining_weight"].as<float>(); | ||||||
|  |                 Serial.print("Aktuelles Gewicht: "); | ||||||
|  |                 Serial.println(remaining_weight); | ||||||
|  |                 oledShowMessage("Remaining: " + String(remaining_weight) + "g"); | ||||||
|  |             } | ||||||
|  |             else if ( requestType == API_REQUEST_SPOOL_LOCATION_UPDATE) { | ||||||
|  |                 oledShowMessage("Location updated!"); | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             vTaskDelay(3000 / portTICK_PERIOD_MS); | ||||||
|  |             doc.clear(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|     } else { |     } else { | ||||||
|         Serial.println("Fehler beim Senden an Spoolman!"); |         Serial.println("Fehler beim Senden an Spoolman! HTTP Code: " + String(httpCode)); | ||||||
|         oledShowMessage("Spoolman update failed"); |         oledShowMessage("Spoolman update failed"); | ||||||
|         vTaskDelay(2000 / portTICK_PERIOD_MS); |         vTaskDelay(2000 / portTICK_PERIOD_MS); | ||||||
|     } |     } | ||||||
| @@ -158,6 +183,7 @@ bool updateSpoolTagId(String uidString, const char* payload) { | |||||||
|         Serial.println("Fehler: Kann Speicher für Task-Parameter nicht allokieren."); |         Serial.println("Fehler: Kann Speicher für Task-Parameter nicht allokieren."); | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |     params->requestType = API_REQUEST_SPOOL_TAG_ID_UPDATE; | ||||||
|     params->httpType = "PATCH"; |     params->httpType = "PATCH"; | ||||||
|     params->spoolsUrl = spoolsUrl; |     params->spoolsUrl = spoolsUrl; | ||||||
|     params->updatePayload = updatePayload; |     params->updatePayload = updatePayload; | ||||||
| @@ -166,7 +192,7 @@ bool updateSpoolTagId(String uidString, const char* payload) { | |||||||
|     BaseType_t result = xTaskCreate( |     BaseType_t result = xTaskCreate( | ||||||
|         sendToApi,                // Task-Funktion |         sendToApi,                // Task-Funktion | ||||||
|         "SendToApiTask",          // Task-Name |         "SendToApiTask",          // Task-Name | ||||||
|         4096,                     // Stackgröße in Bytes |         6144,                     // Stackgröße in Bytes | ||||||
|         (void*)params,            // Parameter |         (void*)params,            // Parameter | ||||||
|         0,                        // Priorität |         0,                        // Priorität | ||||||
|         NULL                      // Task-Handle (nicht benötigt) |         NULL                      // Task-Handle (nicht benötigt) | ||||||
| @@ -174,6 +200,9 @@ bool updateSpoolTagId(String uidString, const char* payload) { | |||||||
|  |  | ||||||
|     updateDoc.clear(); |     updateDoc.clear(); | ||||||
|  |  | ||||||
|  |     // Update Spool weight | ||||||
|  |     if (weight > 10) updateSpoolWeight(doc["sm_id"].as<String>(), weight); | ||||||
|  |  | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -196,6 +225,7 @@ uint8_t updateSpoolWeight(String spoolId, uint16_t weight) { | |||||||
|         Serial.println("Fehler: Kann Speicher für Task-Parameter nicht allokieren."); |         Serial.println("Fehler: Kann Speicher für Task-Parameter nicht allokieren."); | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|  |     params->requestType = API_REQUEST_SPOOL_WEIGHT_UPDATE; | ||||||
|     params->httpType = "PUT"; |     params->httpType = "PUT"; | ||||||
|     params->spoolsUrl = spoolsUrl; |     params->spoolsUrl = spoolsUrl; | ||||||
|     params->updatePayload = updatePayload; |     params->updatePayload = updatePayload; | ||||||
| @@ -204,7 +234,46 @@ uint8_t updateSpoolWeight(String spoolId, uint16_t weight) { | |||||||
|     BaseType_t result = xTaskCreate( |     BaseType_t result = xTaskCreate( | ||||||
|         sendToApi,                // Task-Funktion |         sendToApi,                // Task-Funktion | ||||||
|         "SendToApiTask",          // Task-Name |         "SendToApiTask",          // Task-Name | ||||||
|         4096,                     // Stackgröße in Bytes |         6144,                     // Stackgröße in Bytes | ||||||
|  |         (void*)params,            // Parameter | ||||||
|  |         0,                        // Priorität | ||||||
|  |         NULL                      // Task-Handle (nicht benötigt) | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     updateDoc.clear(); | ||||||
|  |  | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint8_t updateSpoolLocation(String spoolId, String location){ | ||||||
|  |     String spoolsUrl = spoolmanUrl + apiUrl + "/spool/" + spoolId; | ||||||
|  |     Serial.print("Update Spule mit URL: "); | ||||||
|  |     Serial.println(spoolsUrl); | ||||||
|  |  | ||||||
|  |     // Update Payload erstellen | ||||||
|  |     JsonDocument updateDoc; | ||||||
|  |     updateDoc["location"] = location; | ||||||
|  |      | ||||||
|  |     String updatePayload; | ||||||
|  |     serializeJson(updateDoc, updatePayload); | ||||||
|  |     Serial.print("Update Payload: "); | ||||||
|  |     Serial.println(updatePayload); | ||||||
|  |  | ||||||
|  |     SendToApiParams* params = new SendToApiParams(); | ||||||
|  |     if (params == nullptr) { | ||||||
|  |         Serial.println("Fehler: Kann Speicher für Task-Parameter nicht allokieren."); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  |     params->requestType = API_REQUEST_SPOOL_LOCATION_UPDATE; | ||||||
|  |     params->httpType = "PATCH"; | ||||||
|  |     params->spoolsUrl = spoolsUrl; | ||||||
|  |     params->updatePayload = updatePayload; | ||||||
|  |  | ||||||
|  |     // Erstelle die Task | ||||||
|  |     BaseType_t result = xTaskCreate( | ||||||
|  |         sendToApi,                // Task-Funktion | ||||||
|  |         "SendToApiTask",          // Task-Name | ||||||
|  |         6144,                     // Stackgröße in Bytes | ||||||
|         (void*)params,            // Parameter |         (void*)params,            // Parameter | ||||||
|         0,                        // Priorität |         0,                        // Priorität | ||||||
|         NULL                      // Task-Handle (nicht benötigt) |         NULL                      // Task-Handle (nicht benötigt) | ||||||
| @@ -234,6 +303,7 @@ bool updateSpoolOcto(int spoolId) { | |||||||
|         Serial.println("Fehler: Kann Speicher für Task-Parameter nicht allokieren."); |         Serial.println("Fehler: Kann Speicher für Task-Parameter nicht allokieren."); | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |     params->requestType = API_REQUEST_OCTO_SPOOL_UPDATE; | ||||||
|     params->httpType = "POST"; |     params->httpType = "POST"; | ||||||
|     params->spoolsUrl = spoolsUrl; |     params->spoolsUrl = spoolsUrl; | ||||||
|     params->updatePayload = updatePayload; |     params->updatePayload = updatePayload; | ||||||
| @@ -243,7 +313,7 @@ bool updateSpoolOcto(int spoolId) { | |||||||
|     BaseType_t result = xTaskCreate( |     BaseType_t result = xTaskCreate( | ||||||
|         sendToApi,                // Task-Funktion |         sendToApi,                // Task-Funktion | ||||||
|         "SendToApiTask",          // Task-Name |         "SendToApiTask",          // Task-Name | ||||||
|         4096,                     // Stackgröße in Bytes |         6144,                     // Stackgröße in Bytes | ||||||
|         (void*)params,            // Parameter |         (void*)params,            // Parameter | ||||||
|         0,                        // Priorität |         0,                        // Priorität | ||||||
|         NULL                      // Task-Handle (nicht benötigt) |         NULL                      // Task-Handle (nicht benötigt) | ||||||
| @@ -283,6 +353,7 @@ bool updateSpoolBambuData(String payload) { | |||||||
|         Serial.println("Fehler: Kann Speicher für Task-Parameter nicht allokieren."); |         Serial.println("Fehler: Kann Speicher für Task-Parameter nicht allokieren."); | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |     params->requestType = API_REQUEST_BAMBU_UPDATE; | ||||||
|     params->httpType = "PATCH"; |     params->httpType = "PATCH"; | ||||||
|     params->spoolsUrl = spoolsUrl; |     params->spoolsUrl = spoolsUrl; | ||||||
|     params->updatePayload = updatePayload; |     params->updatePayload = updatePayload; | ||||||
| @@ -291,7 +362,7 @@ bool updateSpoolBambuData(String payload) { | |||||||
|     BaseType_t result = xTaskCreate( |     BaseType_t result = xTaskCreate( | ||||||
|         sendToApi,                // Task-Funktion |         sendToApi,                // Task-Funktion | ||||||
|         "SendToApiTask",          // Task-Name |         "SendToApiTask",          // Task-Name | ||||||
|         4096,                     // Stackgröße in Bytes |         6144,                     // Stackgröße in Bytes | ||||||
|         (void*)params,            // Parameter |         (void*)params,            // Parameter | ||||||
|         0,                        // Priorität |         0,                        // Priorität | ||||||
|         NULL                      // Task-Handle (nicht benötigt) |         NULL                      // Task-Handle (nicht benötigt) | ||||||
| @@ -487,6 +558,8 @@ bool checkSpoolmanInstance(const String& url) { | |||||||
|                 return strcmp(status, "healthy") == 0; |                 return strcmp(status, "healthy") == 0; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |     } else { | ||||||
|  |         Serial.println("Error contacting spoolman instance! HTTP Code: " + String(httpCode)); | ||||||
|     } |     } | ||||||
|     http.end(); |     http.end(); | ||||||
|     return false; |     return false; | ||||||
|   | |||||||
| @@ -12,6 +12,14 @@ typedef enum { | |||||||
|     API_TRANSMITTING |     API_TRANSMITTING | ||||||
| } spoolmanApiStateType; | } spoolmanApiStateType; | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |     API_REQUEST_OCTO_SPOOL_UPDATE, | ||||||
|  |     API_REQUEST_BAMBU_UPDATE, | ||||||
|  |     API_REQUEST_SPOOL_TAG_ID_UPDATE, | ||||||
|  |     API_REQUEST_SPOOL_WEIGHT_UPDATE, | ||||||
|  |     API_REQUEST_SPOOL_LOCATION_UPDATE | ||||||
|  | } SpoolmanApiRequestType; | ||||||
|  |  | ||||||
| extern volatile spoolmanApiStateType spoolmanApiState; | extern volatile spoolmanApiStateType spoolmanApiState; | ||||||
| extern bool spoolman_connected; | extern bool spoolman_connected; | ||||||
| extern String spoolmanUrl; | extern String spoolmanUrl; | ||||||
| @@ -26,6 +34,7 @@ bool checkSpoolmanExtraFields(); // Neue Funktion zum Überprüfen der Extrafeld | |||||||
| JsonDocument fetchSingleSpoolInfo(int spoolId); // API-Funktion für die Webseite | JsonDocument fetchSingleSpoolInfo(int spoolId); // API-Funktion für die Webseite | ||||||
| bool updateSpoolTagId(String uidString, const char* payload); // Neue Funktion zum Aktualisieren eines Spools | bool updateSpoolTagId(String uidString, const char* payload); // Neue Funktion zum Aktualisieren eines Spools | ||||||
| uint8_t updateSpoolWeight(String spoolId, uint16_t weight); // Neue Funktion zum Aktualisieren des Gewichts | uint8_t updateSpoolWeight(String spoolId, uint16_t weight); // Neue Funktion zum Aktualisieren des Gewichts | ||||||
|  | uint8_t updateSpoolLocation(String spoolId, String location); | ||||||
| bool initSpoolman(); // Neue Funktion zum Initialisieren von Spoolman | bool initSpoolman(); // Neue Funktion zum Initialisieren von Spoolman | ||||||
| bool updateSpoolBambuData(String payload); // Neue Funktion zum Aktualisieren der Bambu-Daten | bool updateSpoolBambuData(String payload); // Neue Funktion zum Aktualisieren der Bambu-Daten | ||||||
| bool updateSpoolOcto(int spoolId); // Neue Funktion zum Aktualisieren der Octo-Daten | bool updateSpoolOcto(int spoolId); // Neue Funktion zum Aktualisieren der Octo-Daten | ||||||
|   | |||||||
| @@ -674,6 +674,7 @@ bool setupMqtt() { | |||||||
|             vTaskDelay(2000 / portTICK_PERIOD_MS); |             vTaskDelay(2000 / portTICK_PERIOD_MS); | ||||||
|             connected = false; |             connected = false; | ||||||
|             oledShowTopRow(); |             oledShowTopRow(); | ||||||
|  |             autoSetToBambuSpoolId = 0; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (!connected) return false; |         if (!connected) return false; | ||||||
| @@ -687,6 +688,8 @@ bool setupMqtt() { | |||||||
| } | } | ||||||
|  |  | ||||||
| void bambu_restart() { | void bambu_restart() { | ||||||
|  |     Serial.println("Bambu restart"); | ||||||
|  |  | ||||||
|     if (BambuMqttTask) { |     if (BambuMqttTask) { | ||||||
|         vTaskDelete(BambuMqttTask); |         vTaskDelete(BambuMqttTask); | ||||||
|         delay(10); |         delay(10); | ||||||
|   | |||||||
| @@ -180,7 +180,8 @@ void loop() { | |||||||
|     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) |     // Abweichung von 2g ignorieren | ||||||
|  |     if (autoTare && (weight > 2 && weight < 7) || weight < -2) | ||||||
|     { |     { | ||||||
|       scale_tare_counter++; |       scale_tare_counter++; | ||||||
|     } |     } | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								src/nfc.cpp
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								src/nfc.cpp
									
									
									
									
									
								
							| @@ -218,11 +218,25 @@ bool decodeNdefAndReturnJson(const byte* encodedMessage) { | |||||||
|     // Sende die aktualisierten AMS-Daten an alle WebSocket-Clients |     // Sende die aktualisierten AMS-Daten an alle WebSocket-Clients | ||||||
|     Serial.println("JSON-Dokument erfolgreich verarbeitet"); |     Serial.println("JSON-Dokument erfolgreich verarbeitet"); | ||||||
|     Serial.println(doc.as<String>()); |     Serial.println(doc.as<String>()); | ||||||
|     if (doc["sm_id"] != "")  |     if (doc.containsKey("sm_id") && doc["sm_id"] != "")  | ||||||
|     { |     { | ||||||
|       Serial.println("SPOOL-ID gefunden: " + doc["sm_id"].as<String>()); |       Serial.println("SPOOL-ID gefunden: " + doc["sm_id"].as<String>()); | ||||||
|       spoolId = doc["sm_id"].as<String>(); |       spoolId = doc["sm_id"].as<String>(); | ||||||
|     } |     } | ||||||
|  |     else if(doc.containsKey("location") && doc["location"] != "") | ||||||
|  |     { | ||||||
|  |       Serial.println("Location Tag found!"); | ||||||
|  |       String location = doc["location"].as<String>(); | ||||||
|  |       if(spoolId != ""){ | ||||||
|  |         updateSpoolLocation(spoolId, location); | ||||||
|  |       } | ||||||
|  |       else | ||||||
|  |       { | ||||||
|  |         Serial.println("Location update tag scanned without scanning spool before!"); | ||||||
|  |         oledShowMessage("No spool scanned before!"); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     } | ||||||
|     else  |     else  | ||||||
|     { |     { | ||||||
|       Serial.println("Keine SPOOL-ID gefunden."); |       Serial.println("Keine SPOOL-ID gefunden."); | ||||||
|   | |||||||
| @@ -74,7 +74,11 @@ void scale_loop(void * parameter) { | |||||||
|         scaleTareRequest = false; |         scaleTareRequest = false; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       weight = round(scale.get_units()); |       // Only update weight if median changed more than 1 | ||||||
|  |       int16_t newWeight = round(scale.get_units()); | ||||||
|  |       if(abs(weight-newWeight) > 1){ | ||||||
|  |         weight = newWeight; | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     vTaskDelay(pdMS_TO_TICKS(100)); |     vTaskDelay(pdMS_TO_TICKS(100)); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user