Compare commits
30 Commits
v1.5.12-be
...
recyclingf
Author | SHA1 | Date | |
---|---|---|---|
bc51956793 | |||
5666a58da2 | |||
a35f15eca5 | |||
f28b34e427 | |||
9215560558 | |||
7f6bce1699 | |||
2a4f8bb679 | |||
480e2da23e | |||
ba22602767 | |||
b2c68d5aac | |||
52a7f6b5b6 | |||
4cce9f8d5d | |||
f0eced8585 | |||
02e31878ee | |||
7ff499f984 | |||
fcd637cc30 | |||
587485d0de | |||
e0cc99e993 | |||
d9a8388ac7 | |||
cb77112976 | |||
1c0ddb52ba | |||
17f03e9472 | |||
213b9c099c | |||
687e57b77a | |||
aea11e0c06 | |||
bd8f4606c6 | |||
ac91e71c14 | |||
0d3503f4f1 | |||
1460c6e5f9 | |||
fef7e5aa4b |
70
CHANGELOG.md
70
CHANGELOG.md
@@ -1,5 +1,75 @@
|
||||
# Changelog
|
||||
|
||||
## [2.0.0-beta5] - 2025-08-30
|
||||
### Changed
|
||||
- update platformio.ini for beta version v2.0.0-beta5
|
||||
|
||||
### Fixed
|
||||
- call scale.tare() in setup after starting scale
|
||||
|
||||
|
||||
## [2.0.0-beta4] - 2025-08-29
|
||||
### Changed
|
||||
- update platformio.ini for beta version v2.0.0-beta4
|
||||
|
||||
### Fixed
|
||||
- update createVendor function to use external_id as comment instead of static text
|
||||
- update to_old_version in platformio.ini to reflect correct previous version
|
||||
|
||||
|
||||
## [2.0.0-beta3] - 2025-08-29
|
||||
### Changed
|
||||
- update platformio.ini for beta version v2.0.0-beta3
|
||||
- update createVendor and checkVendor functions to accept JsonDocument payload
|
||||
|
||||
|
||||
## [2.0.0-beta2] - 2025-08-29
|
||||
### Added
|
||||
- add Manufacturer Tags support documentation in German and English
|
||||
|
||||
### Changed
|
||||
- update platformio.ini for beta version v2.0.0-beta2
|
||||
- clarify product URL description for Manufacturer Tags in German and English documentation
|
||||
|
||||
### Fixed
|
||||
- increase delay in start_scale function for improved stability
|
||||
|
||||
|
||||
## [2.0.0-beta1] - 2025-08-29
|
||||
### Changed
|
||||
- update platformio.ini for beta version v2.0.0-beta1
|
||||
- update version to 2.0.0 in platformio.ini
|
||||
|
||||
|
||||
## [1.5.12-beta18] - 2025-08-29
|
||||
### Added
|
||||
- add display delay for vendor, filament, and spool creation processes
|
||||
|
||||
### Changed
|
||||
- update platformio.ini for beta version v1.5.12-beta18
|
||||
|
||||
### Fixed
|
||||
- replace progress bar with message display for remaining weight in sendToApi function
|
||||
|
||||
|
||||
## [1.5.12-beta17] - 2025-08-29
|
||||
### Added
|
||||
- add progress bar updates for vendor and filament creation processes
|
||||
|
||||
### Changed
|
||||
- update platformio.ini for beta version v1.5.12-beta17
|
||||
- optimize page limit detection and remove redundant verification code
|
||||
|
||||
### Fixed
|
||||
- update vendor check to use shorthand key in payload
|
||||
|
||||
|
||||
## [1.5.12-beta16] - 2025-08-29
|
||||
### Changed
|
||||
- update platformio.ini for beta version v1.5.12-beta16
|
||||
- Refactor NFC interface handling and improve error diagnostics
|
||||
|
||||
|
||||
## [1.5.12-beta15] - 2025-08-29
|
||||
### Changed
|
||||
- update platformio.ini for beta version v1.5.12-beta15
|
||||
|
28
README.de.md
28
README.de.md
@@ -27,6 +27,7 @@ Discord Server: [https://discord.gg/my7Gvaxj2v](https://discord.gg/my7Gvaxj2v)
|
||||
- Filamentdaten auf NFC-Tags schreiben.
|
||||
- Verwendet das NFC-Tag-Format von [Openspool](https://github.com/spuder/OpenSpool)
|
||||
- Ermöglicht automatische Spulenerkennung im AMS
|
||||
- **Hersteller Tag Unterstützung:** Automatische Erstellung von Spoolman-Einträgen aus Hersteller NFC-Tags ([Mehr erfahren](README_ManufacturerTags_DE.md))
|
||||
- **Bambulab AMS-Integration:**
|
||||
- Anzeige der aktuellen AMS-Fachbelegung.
|
||||
- Zuordnung von Filamenten zu AMS-Slots.
|
||||
@@ -39,8 +40,35 @@ Discord Server: [https://discord.gg/my7Gvaxj2v](https://discord.gg/my7Gvaxj2v)
|
||||
- Unterstützt das Spoolman Octoprint Plugin
|
||||
|
||||
### Wenn Sie meine Arbeit unterstützen möchten, freue ich mich über einen Kaffee
|
||||
|
||||
<a href="https://www.buymeacoffee.com/manuelw" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 30px !important;width: 108px !important;" ></a>
|
||||
|
||||
## Hersteller Tags Unterstützung
|
||||
|
||||
🎉 **Aufregende Neuigkeiten!** FilaMan unterstützt jetzt **Hersteller Tags** - NFC-Tags, die direkt von Filament-Herstellern vorprogrammiert geliefert werden!
|
||||
|
||||
### Erster Hersteller-Partner: RecyclingFabrik
|
||||
|
||||
Wir freuen uns anzukündigen, dass [**RecyclingFabrik**](https://www.recyclingfabrik.de) der **erste Filament-Hersteller** sein wird, der FilaMan unterstützt, indem sie NFC-Tags im FilaMan-Format auf ihren Spulen anbieten!
|
||||
|
||||
**Demnächst verfügbar:** RecyclingFabrik-Spulen werden NFC-Tags enthalten, die sich automatisch in Ihr FilaMan-System integrieren, manuelle Einrichtung überflüssig machen und perfekte Kompatibilität gewährleisten.
|
||||
|
||||
### Wie Hersteller Tags funktionieren
|
||||
|
||||
Wenn Sie zum ersten Mal einen Hersteller NFC-Tag scannen:
|
||||
1. **Automatische Markenerkennung:** FilaMan erkennt den Hersteller und erstellt die Marke in Spoolman
|
||||
2. **Filament-Typ Erstellung:** Alle Materialspezifikationen werden automatisch hinzugefügt
|
||||
3. **Spulen-Registrierung:** Ihre spezifische Spule wird mit korrektem Gewicht und Spezifikationen registriert
|
||||
4. **Zukünftige Schnellerkennung:** Nachfolgende Scans verwenden Fast-Path-Erkennung für sofortige Gewichtsmessung
|
||||
|
||||
**Für detaillierte technische Informationen:** [Hersteller Tags Dokumentation](README_ManufacturerTags_DE.md)
|
||||
|
||||
### Vorteile für Benutzer
|
||||
- ✅ **Null manuelle Einrichtung** - Einfach scannen und wiegen
|
||||
- ✅ **Perfekte Datengenauigkeit** - Hersteller-verifizierte Spezifikationen
|
||||
- ✅ **Sofortige Integration** - Nahtlose Spoolman-Kompatibilität
|
||||
- ✅ **Zukunftssicher** - Tags funktionieren mit jedem FilaMan-kompatiblen System
|
||||
|
||||
## Detaillierte Funktionalität
|
||||
|
||||
### ESP32-Funktionalität
|
||||
|
28
README.md
28
README.md
@@ -31,6 +31,7 @@ Discord Server: [https://discord.gg/my7Gvaxj2v](https://discord.gg/my7Gvaxj2v)
|
||||
- Write filament data to NFC tags.
|
||||
- uses NFC-Tag Format of [Openspool](https://github.com/spuder/OpenSpool)
|
||||
- so you can use it with automatic Spool detection in AMS
|
||||
- **Manufacturer Tag Support:** Automatic creation of Spoolman entries from manufacturer NFC tags ([Learn more](README_ManufacturerTags_EN.md))
|
||||
- **Bambulab AMS Integration:**
|
||||
- Display current AMS tray contents.
|
||||
- Assign filaments to AMS slots.
|
||||
@@ -43,8 +44,35 @@ Discord Server: [https://discord.gg/my7Gvaxj2v](https://discord.gg/my7Gvaxj2v)
|
||||
- Supports Spoolman Octoprint Plugin
|
||||
|
||||
### If you want to support my work, i would be happy to get a coffe
|
||||
|
||||
<a href="https://www.buymeacoffee.com/manuelw" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 30px !important;width: 108px !important;" ></a>
|
||||
|
||||
## Manufacturer Tags Support
|
||||
|
||||
🎉 **Exciting News!** FilaMan now supports **Manufacturer Tags** - NFC tags that come pre-programmed directly from filament manufacturers!
|
||||
|
||||
### First Manufacturer Partner: RecyclingFabrik
|
||||
|
||||
We're thrilled to announce that [**RecyclingFabrik**](https://www.recyclingfabrik.de) will be the **first filament manufacturer** to support FilaMan by offering NFC tags in the FilaMan format on their spools!
|
||||
|
||||
**Coming Soon:** RecyclingFabrik spools will include NFC tags that automatically integrate with your FilaMan system, eliminating manual setup and ensuring perfect compatibility.
|
||||
|
||||
### How Manufacturer Tags Work
|
||||
|
||||
When you scan a manufacturer NFC tag for the first time:
|
||||
1. **Automatic Brand Detection:** FilaMan recognizes the manufacturer and creates the brand in Spoolman
|
||||
2. **Filament Type Creation:** All material specifications are automatically added
|
||||
3. **Spool Registration:** Your specific spool is registered with proper weight and specifications
|
||||
4. **Future Fast Recognition:** Subsequent scans use fast-path detection for instant weight measurement
|
||||
|
||||
**For detailed technical information:** [Manufacturer Tags Documentation](README_ManufacturerTags_EN.md)
|
||||
|
||||
### Benefits for Users
|
||||
- ✅ **Zero Manual Setup** - Just scan and weigh
|
||||
- ✅ **Perfect Data Accuracy** - Manufacturer-verified specifications
|
||||
- ✅ **Instant Integration** - Seamless Spoolman compatibility
|
||||
- ✅ **Future-Proof** - Tags work with any FilaMan-compatible system
|
||||
|
||||
## Detailed Functionality
|
||||
|
||||
### ESP32 Functionality
|
||||
|
159
README_ManufacturerTags_DE.md
Normal file
159
README_ManufacturerTags_DE.md
Normal file
@@ -0,0 +1,159 @@
|
||||
# Hersteller Tags - Deutsche Dokumentation
|
||||
|
||||
## Überblick
|
||||
|
||||
Das FilaMan NFC-System unterstützt **Hersteller Tags**, die es Filament-Produzenten ermöglichen, standardisierte NFC-Tags für ihre Produkte zu erstellen. Beim Scannen dieser Tags werden automatisch die notwendigen Einträge in Spoolman (Marke, Filament-Typ und Spule) erstellt, ohne dass eine manuelle Einrichtung erforderlich ist.
|
||||
|
||||
## Funktionsweise der Hersteller Tags
|
||||
|
||||
### Ablauf
|
||||
|
||||
1. **Tag-Erkennung**: Wenn ein Tag ohne `sm_id` gescannt wird, prüft das System auf Hersteller Tag Format
|
||||
2. **Marken-Erstellung/Suche**: Das System sucht die Marke in Spoolman oder erstellt sie, falls sie nicht existiert
|
||||
3. **Filament-Typ-Erstellung/Suche**: Der Filament-Typ wird basierend auf Marke, Material und Spezifikationen erstellt oder gefunden
|
||||
4. **Spulen-Erstellung**: Ein neuer Spulen-Eintrag wird automatisch mit der Tag-UID als Referenz erstellt
|
||||
5. **Tag-Update**: Der Tag wird mit der neuen Spoolman Spulen-ID (`sm_id`) aktualisiert
|
||||
|
||||
### Warum Hersteller Tags verwenden?
|
||||
|
||||
- **Automatische Integration**: Keine manuelle Dateneingabe erforderlich
|
||||
- **Standardisiertes Format**: Konsistente Produktinformationen verschiedener Hersteller
|
||||
- **Lagerverwaltung**: Automatische Erstellung vollständiger Spoolman-Einträge
|
||||
- **Rückverfolgbarkeit**: Direkte Verbindung zwischen physischem Produkt und digitalem Inventar
|
||||
|
||||
## Tag-Format Spezifikation
|
||||
|
||||
### JSON-Struktur
|
||||
|
||||
Hersteller Tags müssen eine JSON-Payload mit spezifischen Feldern enthalten, die **kurze Schlüssel** verwenden, um die Tag-Größe zu minimieren:
|
||||
|
||||
```json
|
||||
{
|
||||
"b": "Marke/Hersteller Name",
|
||||
"an": "Artikelnummer",
|
||||
"t": "Filament Typ (PLA, PETG, etc)",
|
||||
"c": "Filament Farbe ohne # (FF5733)",
|
||||
"mc": "Optional Mehrfarben-Filament Farben ohne # (FF0000,00FF00,0000FF)",
|
||||
"mcd": "Optional Mehrfarben-Richtung als Wort (coaxial, longitudinal)",
|
||||
"cn": "Farbname (rot, Blaubeere, Arktisches Blau)",
|
||||
"et": "Extruder Temp als Zahl in C° (230)",
|
||||
"bt": "Bett Temp als Zahl in C° (60)",
|
||||
"di": "Durchmesser als Float (1.75)",
|
||||
"de": "Dichte als Float (1.24)",
|
||||
"sw": "Leeres Spulengewicht als Zahl in g (180)",
|
||||
"u": "URL zum Filament mit der Artikelnummer"
|
||||
}
|
||||
```
|
||||
|
||||
### Pflichtfelder
|
||||
|
||||
- **`b`** (brand): Hersteller/Markenname
|
||||
- **`an`** (article number): Eindeutige Produktkennung
|
||||
- **`t`** (type): Materialtyp (PLA, PETG, ABS, etc.)
|
||||
- **`c`** (color): Hex-Farbcode ohne #
|
||||
- **`cn`** (color name): Lesbare Farbbezeichnung
|
||||
- **`et`** (extruder temp): Empfohlene Extruder-Temperatur in Celsius
|
||||
- **`bt`** (bed temp): Empfohlene Bett-Temperatur in Celsius
|
||||
- **`di`** (diameter): Filamentdurchmesser in mm
|
||||
- **`de`** (density): Materialdichte in g/cm³
|
||||
- **`sw`** (spool weight): Leeres Spulengewicht in Gramm
|
||||
|
||||
### Optionale Felder
|
||||
|
||||
- **`mc`** (multicolor): Komma-getrennte Hex-Farben für Mehrfarben-Filamente
|
||||
- **`mcd`** (multicolor direction): Richtung für Mehrfarben (coaxial, longitudinal)
|
||||
- **`u`** (url): Produkt-URL mit direktem Link zum Artikel zB für Nachbestellung
|
||||
|
||||
### Beispiel Tag
|
||||
|
||||
```json
|
||||
{"b":"Recycling Fabrik","an":"FX1_PETG-S175-1000-DAEM00055","t":"PETG","c":"FF5733","cn":"Lebendiges Orange","et":"230","bt":"70","di":"1.75","de":"1.24","sw":"180","u":"https://www.recyclingfabrik.com/search?q="}
|
||||
```
|
||||
|
||||
## Implementierungsrichtlinien
|
||||
|
||||
### Für Hersteller
|
||||
|
||||
1. **Tag-Kodierung**: NDEF-Format mit MIME-Typ `application/json` verwenden
|
||||
2. **Datenminimierung**: Kompaktes JSON-Format für Tag-Größenbegrenzungen nutzen
|
||||
3. **Qualitätskontrolle**: Sicherstellen, dass alle Pflichtfelder vorhanden und korrekt formatiert sind
|
||||
4. **Testen**: Tags vor der Produktion mit dem FilaMan-System verifizieren
|
||||
|
||||
### Tag-Größe Überlegungen
|
||||
|
||||
- **NTAG213**: 144 Bytes Nutzerdaten (geeignet für einfache Tags)
|
||||
- **NTAG215**: 504 Bytes Nutzerdaten (empfohlen für umfassende Daten)
|
||||
- **NTAG216**: 888 Bytes Nutzerdaten (maximale Kompatibilität)
|
||||
|
||||
### Best Practices
|
||||
|
||||
- Markennamen über alle Produkte hinweg konsistent halten
|
||||
- Standardisierte Materialtypnamen verwenden (PLA, PETG, ABS, etc.)
|
||||
- Genaue Temperaturempfehlungen angeben
|
||||
- Aussagekräftige Farbnamen für bessere Benutzererfahrung verwenden
|
||||
- Tags vor Massenproduktion mit dem FilaMan-System testen
|
||||
|
||||
## System-Integration
|
||||
|
||||
### Spoolman Datenbankstruktur
|
||||
|
||||
Bei der Verarbeitung eines Hersteller Tags erstellt das System:
|
||||
|
||||
1. **Lieferanten-Eintrag**: Markeninformationen in der Spoolman Lieferanten-Datenbank
|
||||
2. **Filament-Eintrag**: Materialspezifikationen und Eigenschaften
|
||||
3. **Spulen-Eintrag**: Einzelne Spule mit Gewicht und NFC-Tag-Referenz
|
||||
|
||||
### Fast-Path Erkennung
|
||||
|
||||
Sobald ein Tag verarbeitet und mit `sm_id` aktualisiert wurde, nutzt er das Fast-Path-Erkennungssystem für schnelle nachfolgende Scans.
|
||||
|
||||
## Fehlerbehebung
|
||||
|
||||
### Häufige Probleme
|
||||
|
||||
- **Tag zu klein**: NTAG215 oder NTAG216 für größere JSON-Payloads verwenden
|
||||
- **Fehlende Felder**: Sicherstellen, dass alle Pflichtfelder vorhanden sind
|
||||
- **Ungültiges Format**: JSON-Syntax und Feldtypen überprüfen
|
||||
- **Spoolman-Verbindung**: Sicherstellen, dass FilaMan mit der Spoolman API verbinden kann
|
||||
|
||||
### Validierung
|
||||
|
||||
Das System validiert:
|
||||
|
||||
- JSON-Format Korrektheit
|
||||
- Vorhandensein der Pflichtfelder
|
||||
- Datentyp-Konformität
|
||||
- Tag-Größe Kompatibilität
|
||||
|
||||
## Technische Details
|
||||
|
||||
### Verarbeitungsalgorithmus
|
||||
|
||||
1. Tag-Scan erkennt kein `sm_id` Feld
|
||||
2. System prüft auf `b` (Marke) und `an` (Artikelnummer) Felder
|
||||
3. `checkVendor()` erstellt oder findet Marke in Spoolman
|
||||
4. `checkFilament()` erstellt oder findet Filament-Typ
|
||||
5. `createSpool()` erstellt neuen Spulen-Eintrag
|
||||
6. Tag wird mit neuer `sm_id` aktualisiert
|
||||
|
||||
### Fehlerbehandlung
|
||||
|
||||
- Graceful Fallback bei Netzwerkproblemen
|
||||
- Detaillierte Protokollierung für Debugging
|
||||
- Benutzer-Feedback bei fehlgeschlagenen Operationen
|
||||
- Wiederholungsmechanismen für temporäre Fehler
|
||||
|
||||
### Systemverhalten
|
||||
|
||||
#### Bei fehlendem sm_id:
|
||||
- System prüft auf `b` (brand) und `an` (artnr) Felder
|
||||
- Falls vorhanden → Hersteller Tag erkannt
|
||||
- Automatische Erstellung von Lieferant, Filament und Spule in Spoolman
|
||||
- Tag wird mit neuer `sm_id` beschrieben
|
||||
|
||||
#### Bei vorhandenem sm_id:
|
||||
- Fast-Path Erkennung für bekannte Spulen
|
||||
- Sofortige Gewichtsmessung ohne vollständige Tag-Analyse
|
||||
- Optimierte Performance für häufig verwendete Tags
|
||||
|
||||
Dieses System ermöglicht eine nahtlose Integration von Hersteller-Filamentprodukten in das FilaMan-Ökosystem unter Beibehaltung von Datenkonsistenz und Benutzererfahrung.
|
145
README_ManufacturerTags_EN.md
Normal file
145
README_ManufacturerTags_EN.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# Manufacturer Tags - English Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
The FilaMan NFC system supports **Manufacturer Tags** that allow filament producers to create standardized NFC tags for their products. When scanned, these tags automatically create the necessary entries in Spoolman (brand, filament type, and spool) without requiring manual setup.
|
||||
|
||||
## How Manufacturer Tags Work
|
||||
|
||||
### Process Flow
|
||||
|
||||
1. **Tag Detection**: When a tag without `sm_id` is scanned, the system checks for manufacturer tag format
|
||||
2. **Brand Creation/Lookup**: The system searches for the brand in Spoolman or creates it if it doesn't exist
|
||||
3. **Filament Type Creation/Lookup**: The filament type is created or found based on brand, material, and specifications
|
||||
4. **Spool Creation**: A new spool entry is automatically created with the tag's UID as reference
|
||||
5. **Tag Update**: The tag is updated with the new Spoolman spool ID (`sm_id`)
|
||||
|
||||
### Why Use Manufacturer Tags?
|
||||
|
||||
- **Automatic Integration**: No manual data entry required
|
||||
- **Standardized Format**: Consistent product information across different manufacturers
|
||||
- **Inventory Management**: Automatic creation of complete Spoolman entries
|
||||
- **Traceability**: Direct link between physical product and digital inventory
|
||||
|
||||
## Tag Format Specification
|
||||
|
||||
### JSON Structure
|
||||
|
||||
Manufacturer tags must contain a JSON payload with specific fields using **short keys** to minimize tag size:
|
||||
|
||||
```json
|
||||
{
|
||||
"b": "Brand/Vendor Name",
|
||||
"an": "Article Number",
|
||||
"t": "Filament Type (PLA, PETG, etc)",
|
||||
"c": "Filament Color without # (FF5733)",
|
||||
"mc": "Optional Multicolor Filament Colors without # (FF0000,00FF00,0000FF)",
|
||||
"mcd": "Optional Multicolor Direction as Word (coaxial, longitudinal)",
|
||||
"cn": "Color Name (red, Blueberry, Arctic Blue)",
|
||||
"et": "Extruder Temp as Number in C° (230)",
|
||||
"bt": "Bed Temp as Number in C° (60)",
|
||||
"di": "Diameter as Float (1.75)",
|
||||
"de": "Density as Float (1.24)",
|
||||
"sw": "Empty Spool Weight as Number in g (180)",
|
||||
"u": "URL to get the Filament with the Article Number"
|
||||
}
|
||||
```
|
||||
|
||||
### Required Fields
|
||||
|
||||
- **`b`** (brand): Manufacturer/brand name
|
||||
- **`an`** (article number): Unique product identifier
|
||||
- **`t`** (type): Material type (PLA, PETG, ABS, etc.)
|
||||
- **`c`** (color): Hex color code without #
|
||||
- **`cn`** (color name): Human-readable color name
|
||||
- **`et`** (extruder temp): Recommended extruder temperature in Celsius
|
||||
- **`bt`** (bed temp): Recommended bed temperature in Celsius
|
||||
- **`di`** (diameter): Filament diameter in mm
|
||||
- **`de`** (density): Material density in g/cm³
|
||||
- **`sw`** (spool weight): Empty spool weight in grams
|
||||
|
||||
### Optional Fields
|
||||
|
||||
- **`mc`** (multicolor): Comma-separated hex colors for multicolor filaments
|
||||
- **`mcd`** (multicolor direction): Direction for multicolor (coaxial, longitudinal)
|
||||
- **`u`** (url): Product URL with direct link to the article e.g. for reordering
|
||||
|
||||
### Example Tag
|
||||
|
||||
```json
|
||||
{"b":"Recycling Fabrik","an":"FX1_PETG-S175-1000-DAEM00055","t":"PETG","c":"FF5733","cn":"Vibrant Orange","et":"230","bt":"70","di":"1.75","de":"1.24","sw":"180","u":"https://www.recyclingfabrik.com/search?q="}
|
||||
```
|
||||
|
||||
## Implementation Guidelines
|
||||
|
||||
### For Manufacturers
|
||||
|
||||
1. **Tag Encoding**: Use NDEF format with MIME type `application/json`
|
||||
2. **Data Minimization**: Use the compact JSON format to fit within tag size limits
|
||||
3. **Quality Control**: Ensure all required fields are present and correctly formatted
|
||||
4. **Testing**: Verify tags work with FilaMan system before production
|
||||
|
||||
### Tag Size Considerations
|
||||
|
||||
- **NTAG213**: 144 bytes user data (suitable for basic tags)
|
||||
- **NTAG215**: 504 bytes user data (recommended for comprehensive data)
|
||||
- **NTAG216**: 888 bytes user data (maximum compatibility)
|
||||
|
||||
### Best Practices
|
||||
|
||||
- Keep brand names consistent across all products
|
||||
- Use standardized material type names (PLA, PETG, ABS, etc.)
|
||||
- Provide accurate temperature recommendations
|
||||
- Include meaningful color names for user experience
|
||||
- Test tags with the FilaMan system before mass production
|
||||
|
||||
## System Integration
|
||||
|
||||
### Spoolman Database Structure
|
||||
|
||||
When a manufacturer tag is processed, the system creates:
|
||||
|
||||
1. **Vendor Entry**: Brand information in Spoolman vendor database
|
||||
2. **Filament Entry**: Material specifications and properties
|
||||
3. **Spool Entry**: Individual spool with weight and NFC tag reference
|
||||
|
||||
### Fast-Path Recognition
|
||||
|
||||
Once a tag is processed and updated with `sm_id`, it uses the fast-path recognition system for quick subsequent scans.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
- **Tag Too Small**: Use NTAG215 or NTAG216 for larger JSON payloads
|
||||
- **Missing Fields**: Ensure all required fields are present
|
||||
- **Invalid Format**: Verify JSON syntax and field types
|
||||
- **Spoolman Connection**: Ensure FilaMan can connect to Spoolman API
|
||||
|
||||
### Validation
|
||||
|
||||
The system validates:
|
||||
- JSON format correctness
|
||||
- Required field presence
|
||||
- Data type compliance
|
||||
- Tag size compatibility
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Processing Algorithm
|
||||
|
||||
1. Tag scan detects no `sm_id` field
|
||||
2. System checks for `b` (brand) and `an` (article number) fields
|
||||
3. `checkVendor()` creates or finds brand in Spoolman
|
||||
4. `checkFilament()` creates or finds filament type
|
||||
5. `createSpool()` creates new spool entry
|
||||
6. Tag is updated with new `sm_id`
|
||||
|
||||
### Error Handling
|
||||
|
||||
- Graceful fallback for network issues
|
||||
- Detailed logging for debugging
|
||||
- User feedback for failed operations
|
||||
- Retry mechanisms for temporary failures
|
||||
|
||||
This system enables seamless integration of manufacturer filament products into the FilaMan ecosystem while maintaining data consistency and user experience.
|
@@ -9,8 +9,8 @@
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[common]
|
||||
version = "1.5.12-beta15"
|
||||
to_old_version = "1.5.0"
|
||||
version = "2.0.0-beta5"
|
||||
to_old_version = "1.5.10"
|
||||
|
||||
##
|
||||
[env:esp32dev]
|
||||
|
125
src/api.cpp
125
src/api.cpp
@@ -9,18 +9,6 @@
|
||||
#include <time.h>
|
||||
volatile spoolmanApiStateType spoolmanApiState = API_IDLE;
|
||||
|
||||
// Returns current date and time in ISO8601 format
|
||||
String getCurrentDateISO8601() {
|
||||
struct tm timeinfo;
|
||||
if(!getLocalTime(&timeinfo)) {
|
||||
Serial.println("Failed to obtain time");
|
||||
return "1970-01-01T00:00:00Z";
|
||||
}
|
||||
char timeStringBuff[25];
|
||||
strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%dT%H:%M:%SZ", &timeinfo);
|
||||
return String(timeStringBuff);
|
||||
}
|
||||
|
||||
//bool spoolman_connected = false;
|
||||
String spoolmanUrl = "";
|
||||
bool octoEnabled = false;
|
||||
@@ -170,7 +158,8 @@ void sendToApi(void *parameter) {
|
||||
//oledShowMessage("Remaining: " + String(remaining_weight) + "g");
|
||||
if(!octoEnabled){
|
||||
// TBD: Do not use Strings...
|
||||
oledShowProgressBar(1, 1, "Spool Tag", ("Done: " + String(remainingWeight) + " g remain").c_str());
|
||||
//oledShowProgressBar(1, 1, "Spool Tag", ("Done: " + String(remainingWeight) + " g remain").c_str());
|
||||
oledShowMessage("Remaining: " + String(remainingWeight) + "g");
|
||||
remainingWeight = 0;
|
||||
}else{
|
||||
// ocoto is enabled, trigger octo update
|
||||
@@ -185,7 +174,8 @@ void sendToApi(void *parameter) {
|
||||
break;
|
||||
case API_REQUEST_OCTO_SPOOL_UPDATE:
|
||||
// TBD: Do not use Strings...
|
||||
oledShowProgressBar(5, 5, "Spool Tag", ("Done: " + String(remainingWeight) + " g remain").c_str());
|
||||
//oledShowProgressBar(5, 5, "Spool Tag", ("Done: " + String(remainingWeight) + " g remain").c_str());
|
||||
oledShowMessage("Remaining: " + String(remainingWeight) + "g");
|
||||
remainingWeight = 0;
|
||||
break;
|
||||
case API_REQUEST_VENDOR_CREATE:
|
||||
@@ -613,7 +603,9 @@ bool updateSpoolBambuData(String payload) {
|
||||
}
|
||||
|
||||
// #### Brand Filament
|
||||
uint16_t createVendor(String vendor) {
|
||||
uint16_t createVendor(const JsonDocument& payload) {
|
||||
oledShowProgressBar(2, 5, "New Brand", "Create new Vendor");
|
||||
|
||||
// Create new vendor in Spoolman database using task system
|
||||
// Note: Due to async nature, the ID will be stored in createdVendorId global variable
|
||||
// Note: This function assumes that the caller has already ensured API is IDLE
|
||||
@@ -625,10 +617,24 @@ uint16_t createVendor(String vendor) {
|
||||
|
||||
// Create JSON payload for vendor creation
|
||||
JsonDocument vendorDoc;
|
||||
vendorDoc["name"] = vendor;
|
||||
vendorDoc["comment"] = "automatically generated";
|
||||
vendorDoc["empty_spool_weight"] = 180;
|
||||
vendorDoc["external_id"] = vendor;
|
||||
vendorDoc["name"] = payload["b"].as<String>();
|
||||
|
||||
// Extract domain from URL if present, otherwise use brand name
|
||||
String externalId = "";
|
||||
if (payload["u"].is<String>()) {
|
||||
String url = payload["u"].as<String>();
|
||||
// Extract domain from URL (e.g., "https://www.blubb.de/f1234/?suche=irgendwas" -> "https://www.blubb.de")
|
||||
int protocolEnd = url.indexOf("://");
|
||||
if (protocolEnd != -1) {
|
||||
int pathStart = url.indexOf("/", protocolEnd + 3);
|
||||
externalId = (pathStart != -1) ? url.substring(0, pathStart) : url;
|
||||
} else {
|
||||
externalId = url; // No protocol found, use as is
|
||||
}
|
||||
} else {
|
||||
externalId = payload["b"].as<String>();
|
||||
}
|
||||
vendorDoc["comment"] = externalId;
|
||||
|
||||
String vendorPayload;
|
||||
serializeJson(vendorDoc, vendorPayload);
|
||||
@@ -665,6 +671,9 @@ uint16_t createVendor(String vendor) {
|
||||
|
||||
vendorDoc.clear();
|
||||
|
||||
// Delay for Display Bar
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
|
||||
// Wait for task completion and return the created vendor ID
|
||||
// Note: createdVendorId will be set by sendToApi when response is received
|
||||
while(createdVendorId == 65535) {
|
||||
@@ -674,11 +683,13 @@ uint16_t createVendor(String vendor) {
|
||||
return createdVendorId;
|
||||
}
|
||||
|
||||
uint16_t checkVendor(String vendor) {
|
||||
uint16_t checkVendor(const JsonDocument& payload) {
|
||||
oledShowProgressBar(1, 5, "New Brand", "Check Vendor");
|
||||
|
||||
// Check if vendor exists using task system
|
||||
foundVendorId = 65535; // Reset to invalid value to detect when API response is received
|
||||
|
||||
String vendorName = vendor;
|
||||
String vendorName = payload["b"].as<String>();
|
||||
vendorName.trim();
|
||||
vendorName.replace(" ", "+");
|
||||
String spoolsUrl = spoolmanUrl + apiUrl + "/vendor?name=" + vendorName;
|
||||
@@ -720,7 +731,7 @@ uint16_t checkVendor(String vendor) {
|
||||
// Check if vendor was found
|
||||
if (foundVendorId == 0) {
|
||||
Serial.println("Vendor not found, creating new vendor...");
|
||||
uint16_t vendorId = createVendor(vendor);
|
||||
uint16_t vendorId = createVendor(payload);
|
||||
if (vendorId == 0) {
|
||||
Serial.println("Failed to create vendor, returning 0.");
|
||||
return 0; // Failed to create vendor
|
||||
@@ -729,7 +740,7 @@ uint16_t checkVendor(String vendor) {
|
||||
return vendorId;
|
||||
}
|
||||
} else {
|
||||
Serial.println("Vendor found: " + vendor);
|
||||
Serial.println("Vendor found: " + payload["b"].as<String>());
|
||||
Serial.print("Vendor ID: ");
|
||||
Serial.println(foundVendorId);
|
||||
return foundVendorId;
|
||||
@@ -737,6 +748,8 @@ uint16_t checkVendor(String vendor) {
|
||||
}
|
||||
|
||||
uint16_t createFilament(uint16_t vendorId, const JsonDocument& payload) {
|
||||
oledShowProgressBar(4, 5, "New Brand", "Create Filament");
|
||||
|
||||
// Create new filament in Spoolman database using task system
|
||||
// Note: Due to async nature, the ID will be stored in createdFilamentId global variable
|
||||
// Note: This function assumes that the caller has already ensured API is IDLE
|
||||
@@ -748,34 +761,34 @@ uint16_t createFilament(uint16_t vendorId, const JsonDocument& payload) {
|
||||
|
||||
// Create JSON payload for filament creation
|
||||
JsonDocument filamentDoc;
|
||||
filamentDoc["name"] = payload["color_name"].as<String>();
|
||||
filamentDoc["name"] = payload["cn"].as<String>();
|
||||
filamentDoc["vendor_id"] = String(vendorId);
|
||||
filamentDoc["material"] = payload["type"].as<String>();
|
||||
filamentDoc["density"] = (payload["density"].is<String>() && payload["density"].as<String>().length() > 0) ? payload["density"].as<String>() : "1.24";
|
||||
filamentDoc["diameter"] = (payload["diameter"].is<String>() && payload["diameter"].as<String>().length() > 0) ? payload["diameter"].as<String>() : "1.75";
|
||||
filamentDoc["material"] = payload["t"].as<String>();
|
||||
filamentDoc["density"] = (payload["de"].is<String>() && payload["de"].as<String>().length() > 0) ? payload["de"].as<String>() : "1.24";
|
||||
filamentDoc["diameter"] = (payload["di"].is<String>() && payload["di"].as<String>().length() > 0) ? payload["di"].as<String>() : "1.75";
|
||||
filamentDoc["weight"] = String(weight);
|
||||
filamentDoc["spool_weight"] = payload["spool_weight"].as<String>();
|
||||
filamentDoc["article_number"] = payload["artnr"].as<String>();
|
||||
filamentDoc["settings_extruder_temp"] = payload["extruder_temp"].is<String>() ? payload["extruder_temp"].as<String>() : "";
|
||||
filamentDoc["settings_bed_temp"] = payload["bed_temp"].is<String>() ? payload["bed_temp"].as<String>() : "";
|
||||
filamentDoc["spool_weight"] = payload["sw"].as<String>();
|
||||
filamentDoc["article_number"] = payload["an"].as<String>();
|
||||
filamentDoc["settings_extruder_temp"] = payload["et"].is<String>() ? payload["et"].as<String>() : "";
|
||||
filamentDoc["settings_bed_temp"] = payload["bt"].is<String>() ? payload["bt"].as<String>() : "";
|
||||
|
||||
if (payload["artnr"].is<String>())
|
||||
if (payload["an"].is<String>())
|
||||
{
|
||||
filamentDoc["external_id"] = payload["artnr"].as<String>();
|
||||
filamentDoc["comment"] = payload["url"].is<String>() ? payload["url"].as<String>() + payload["artnr"].as<String>() : "automatically generated";
|
||||
filamentDoc["external_id"] = payload["an"].as<String>();
|
||||
filamentDoc["comment"] = payload["u"].is<String>() ? payload["u"].as<String>() + payload["an"].as<String>() : "automatically generated";
|
||||
}
|
||||
else
|
||||
{
|
||||
filamentDoc["comment"] = payload["url"].is<String>() ? payload["url"].as<String>() : "automatically generated";
|
||||
filamentDoc["comment"] = payload["u"].is<String>() ? payload["u"].as<String>() : "automatically generated";
|
||||
}
|
||||
|
||||
if (payload["multi_color_hexes"].is<String>()) {
|
||||
filamentDoc["multi_color_hexes"] = payload["multi_color_hexes"].as<String>();
|
||||
filamentDoc["multi_color_direction"] = payload["multi_color_direction"].is<String>() ? payload["multi_color_direction"].as<String>() : "";
|
||||
if (payload["mc"].is<String>()) {
|
||||
filamentDoc["multi_color_hexes"] = payload["mc"].as<String>();
|
||||
filamentDoc["multi_color_direction"] = payload["mcd"].is<String>() ? payload["mcd"].as<String>() : "";
|
||||
}
|
||||
else
|
||||
{
|
||||
filamentDoc["color_hex"] = (payload["color_hex"].is<String>() && payload["color_hex"].as<String>().length() >= 6) ? payload["color_hex"].as<String>() : "FFFFFF";
|
||||
filamentDoc["color_hex"] = (payload["c"].is<String>() && payload["c"].as<String>().length() >= 6) ? payload["c"].as<String>() : "FFFFFF";
|
||||
}
|
||||
|
||||
String filamentPayload;
|
||||
@@ -813,6 +826,9 @@ uint16_t createFilament(uint16_t vendorId, const JsonDocument& payload) {
|
||||
|
||||
filamentDoc.clear();
|
||||
|
||||
// Delay for Display Bar
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
|
||||
// Wait for task completion and return the created filament ID
|
||||
// Note: createdFilamentId will be set by sendToApi when response is received
|
||||
while(createdFilamentId == 65535) {
|
||||
@@ -823,6 +839,8 @@ uint16_t createFilament(uint16_t vendorId, const JsonDocument& payload) {
|
||||
}
|
||||
|
||||
uint16_t checkFilament(uint16_t vendorId, const JsonDocument& payload) {
|
||||
oledShowProgressBar(3, 5, "New Brand", "Check Filament");
|
||||
|
||||
// Check if filament exists using task system
|
||||
foundFilamentId = 65535; // Reset to invalid value to detect when API response is received
|
||||
|
||||
@@ -875,6 +893,8 @@ uint16_t checkFilament(uint16_t vendorId, const JsonDocument& payload) {
|
||||
}
|
||||
|
||||
uint16_t createSpool(uint16_t vendorId, uint16_t filamentId, JsonDocument& payload, String uidString) {
|
||||
oledShowProgressBar(5, 5, "New Brand", "Create new Spool");
|
||||
|
||||
// Create new spool in Spoolman database using task system
|
||||
// Note: Due to async nature, the ID will be stored in createdSpoolId global variable
|
||||
// Note: This function assumes that the caller has already ensured API is IDLE
|
||||
@@ -883,17 +903,14 @@ uint16_t createSpool(uint16_t vendorId, uint16_t filamentId, JsonDocument& paylo
|
||||
String spoolsUrl = spoolmanUrl + apiUrl + "/spool";
|
||||
Serial.print("Create spool with URL: ");
|
||||
Serial.println(spoolsUrl);
|
||||
//String currentDate = getCurrentDateISO8601();
|
||||
|
||||
// Create JSON payload for spool creation
|
||||
JsonDocument spoolDoc;
|
||||
//spoolDoc["first_used"] = String(currentDate);
|
||||
//spoolDoc["last_used"] = String(currentDate);
|
||||
spoolDoc["filament_id"] = String(filamentId);
|
||||
spoolDoc["initial_weight"] = weight > 10 ? String(weight-payload["spool_weight"].as<int>()) : "1000";
|
||||
spoolDoc["spool_weight"] = (payload["spool_weight"].is<String>() && payload["spool_weight"].as<String>().length() > 0) ? payload["spool_weight"].as<String>() : "180";
|
||||
spoolDoc["remaining_weight"] = (payload["weight"].is<String>() && payload["weight"].as<String>().length() > 0) ? payload["weight"].as<String>() : "1000";
|
||||
spoolDoc["lot_nr"] = (payload["lotnr"].is<String>() && payload["lotnr"].as<String>().length() > 0) ? payload["lotnr"].as<String>() : "";
|
||||
spoolDoc["initial_weight"] = weight > 10 ? String(weight - payload["sw"].as<int>()) : "1000";
|
||||
spoolDoc["spool_weight"] = (payload["sw"].is<String>() && payload["sw"].as<String>().length() > 0) ? payload["sw"].as<String>() : "180";
|
||||
spoolDoc["remaining_weight"] = spoolDoc["initial_weight"];
|
||||
spoolDoc["lot_nr"] = (payload["an"].is<String>() && payload["an"].as<String>().length() > 0) ? payload["an"].as<String>() : "";
|
||||
spoolDoc["comment"] = "automatically generated";
|
||||
spoolDoc["extra"]["nfc_id"] = "\"" + uidString + "\"";
|
||||
|
||||
@@ -942,13 +959,8 @@ uint16_t createSpool(uint16_t vendorId, uint16_t filamentId, JsonDocument& paylo
|
||||
// Create optimized JSON structure with sm_id at the beginning for fast-path detection
|
||||
JsonDocument optimizedPayload;
|
||||
optimizedPayload["sm_id"] = String(createdSpoolId); // Place sm_id first for fast scanning
|
||||
|
||||
// Copy all other fields from original payload (excluding sm_id if it exists)
|
||||
for (JsonPair kv : payload.as<JsonObject>()) {
|
||||
if (strcmp(kv.key().c_str(), "sm_id") != 0) { // Skip sm_id to avoid duplication
|
||||
optimizedPayload[kv.key()] = kv.value();
|
||||
}
|
||||
}
|
||||
optimizedPayload["b"] = payload["b"].as<String>();
|
||||
optimizedPayload["cn"] = payload["an"].as<String>();
|
||||
|
||||
String payloadString;
|
||||
serializeJson(optimizedPayload, payloadString);
|
||||
@@ -959,14 +971,17 @@ uint16_t createSpool(uint16_t vendorId, uint16_t filamentId, JsonDocument& paylo
|
||||
optimizedPayload.clear();
|
||||
|
||||
nfcReaderState = NFC_IDLE;
|
||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
||||
|
||||
// Delay for Display Bar
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
|
||||
startWriteJsonToTag(true, payloadString.c_str());
|
||||
|
||||
return createdSpoolId;
|
||||
}
|
||||
|
||||
bool createBrandFilament(JsonDocument& payload, String uidString) {
|
||||
uint16_t vendorId = checkVendor(payload["brand"].as<String>());
|
||||
uint16_t vendorId = checkVendor(payload);
|
||||
if (vendorId == 0) {
|
||||
Serial.println("ERROR: Failed to create/find vendor");
|
||||
return false;
|
||||
|
@@ -235,7 +235,7 @@ void oledShowIcon(const char* icon) {
|
||||
display.display();
|
||||
}
|
||||
|
||||
void oledShowProgressBar(const uint8_t step, const uint8_t numSteps, const char* largeText, const char* statusMessage){
|
||||
void oledShowProgressBar(const uint8_t step, const uint8_t numSteps, const char* largeText, const char* statusMessage) {
|
||||
assert(step <= numSteps);
|
||||
|
||||
// clear data and bar area
|
||||
|
@@ -59,6 +59,7 @@ void setup() {
|
||||
|
||||
// Scale
|
||||
start_scale(touchSensorConnected);
|
||||
scale.tare();
|
||||
|
||||
// WDT initialisieren mit 10 Sekunden Timeout
|
||||
bool panic = true; // Wenn true, löst ein WDT-Timeout einen System-Panik aus
|
||||
|
776
src/nfc.cpp
776
src/nfc.cpp
@@ -324,16 +324,48 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
||||
Serial.print("WARNING: Cannot read declared max page ");
|
||||
Serial.println(maxWritablePage);
|
||||
|
||||
// Find actual maximum writable page by testing backwards
|
||||
// Find actual maximum writable page by testing backwards with optimized approach
|
||||
uint16_t actualMaxPage = maxWritablePage;
|
||||
for (uint16_t testPage = maxWritablePage; testPage >= 4; testPage--) {
|
||||
if (nfc.ntag2xx_ReadPage(testPage, testBuffer)) {
|
||||
actualMaxPage = testPage;
|
||||
Serial.println("Searching for actual maximum writable page...");
|
||||
|
||||
// Use binary search approach for faster page limit detection
|
||||
uint16_t lowPage = 4;
|
||||
uint16_t highPage = maxWritablePage;
|
||||
uint16_t testAttempts = 0;
|
||||
const uint16_t maxTestAttempts = 15; // Limit search attempts
|
||||
|
||||
while (lowPage <= highPage && testAttempts < maxTestAttempts) {
|
||||
uint16_t midPage = (lowPage + highPage) / 2;
|
||||
testAttempts++;
|
||||
|
||||
Serial.print("Testing page ");
|
||||
Serial.print(midPage);
|
||||
Serial.print(" (attempt ");
|
||||
Serial.print(testAttempts);
|
||||
Serial.print("/");
|
||||
Serial.print(maxTestAttempts);
|
||||
Serial.print(")... ");
|
||||
|
||||
if (nfc.ntag2xx_ReadPage(midPage, testBuffer)) {
|
||||
Serial.println("✓");
|
||||
actualMaxPage = midPage;
|
||||
lowPage = midPage + 1; // Search higher
|
||||
} else {
|
||||
Serial.println("❌");
|
||||
highPage = midPage - 1; // Search lower
|
||||
}
|
||||
|
||||
// Small delay to prevent interface overload
|
||||
vTaskDelay(5 / portTICK_PERIOD_MS);
|
||||
yield();
|
||||
}
|
||||
|
||||
Serial.print("Found actual max readable page: ");
|
||||
Serial.println(actualMaxPage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Serial.print("Search completed in ");
|
||||
Serial.print(testAttempts);
|
||||
Serial.println(" attempts");
|
||||
|
||||
maxWritablePage = actualMaxPage;
|
||||
} else {
|
||||
Serial.print("✓ Max page ");Serial.print(maxWritablePage);Serial.println(" is readable");
|
||||
@@ -409,12 +441,12 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
||||
|
||||
Serial.println("✓ Payload passt in den Tag - Schreibvorgang wird fortgesetzt");
|
||||
|
||||
// STEP 1: Read current tag content for debugging
|
||||
// STEP 1: NFC Interface Reset and Reinitialization
|
||||
Serial.println();
|
||||
Serial.println("=== SCHRITT 1: NFC-INTERFACE-DIAGNOSE ===");
|
||||
Serial.println("=== SCHRITT 1: NFC-INTERFACE RESET UND NEUINITIALISIERUNG ===");
|
||||
|
||||
// First, check if the NFC interface is working at all
|
||||
Serial.println("Teste NFC-Interface-Zustand...");
|
||||
Serial.println("Teste aktuellen NFC-Interface-Zustand...");
|
||||
|
||||
// Try to read capability container (which worked during detection)
|
||||
uint8_t ccTest[4];
|
||||
@@ -422,6 +454,88 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
||||
Serial.print("Capability Container (Seite 3) lesbar: ");
|
||||
Serial.println(ccReadable ? "✓" : "❌");
|
||||
|
||||
if (!ccReadable) {
|
||||
Serial.println("❌ NFC-Interface ist nicht funktionsfähig - führe Reset durch");
|
||||
|
||||
// Perform NFC interface reset and reinitialization
|
||||
Serial.println("Führe NFC-Interface Reset durch...");
|
||||
|
||||
// Step 1: Try to reinitialize the NFC interface completely
|
||||
Serial.println("1. Neuinitialisierung des PN532...");
|
||||
|
||||
// Reinitialize the PN532
|
||||
nfc.begin();
|
||||
vTaskDelay(500 / portTICK_PERIOD_MS); // Give it time to initialize
|
||||
|
||||
// Check firmware version to ensure communication is working
|
||||
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||
if (versiondata) {
|
||||
Serial.print("PN532 Firmware Version: 0x");
|
||||
Serial.println(versiondata, HEX);
|
||||
Serial.println("✓ PN532 Kommunikation wiederhergestellt");
|
||||
} else {
|
||||
Serial.println("❌ PN532 Kommunikation fehlgeschlagen");
|
||||
oledShowMessage("NFC Reset failed");
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Step 2: Reconfigure SAM
|
||||
Serial.println("2. SAM-Konfiguration...");
|
||||
nfc.SAMConfig();
|
||||
vTaskDelay(200 / portTICK_PERIOD_MS);
|
||||
|
||||
// Step 3: Re-detect the tag
|
||||
Serial.println("3. Tag-Wiedererkennung...");
|
||||
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
|
||||
uint8_t uidLength;
|
||||
bool tagRedetected = false;
|
||||
|
||||
for (int attempts = 0; attempts < 5; attempts++) {
|
||||
Serial.print("Tag-Erkennungsversuch ");
|
||||
Serial.print(attempts + 1);
|
||||
Serial.print("/5... ");
|
||||
|
||||
if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 1000)) {
|
||||
Serial.println("✓");
|
||||
tagRedetected = true;
|
||||
break;
|
||||
} else {
|
||||
Serial.println("❌");
|
||||
vTaskDelay(300 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
if (!tagRedetected) {
|
||||
Serial.println("❌ Tag konnte nach Reset nicht wiedererkannt werden");
|
||||
oledShowMessage("Tag lost after reset");
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Serial.println("✓ Tag erfolgreich wiedererkannt");
|
||||
|
||||
// Step 4: Test basic page reading
|
||||
Serial.println("4. Test der Grundfunktionalität...");
|
||||
vTaskDelay(200 / portTICK_PERIOD_MS); // Give interface time to stabilize
|
||||
|
||||
ccReadable = nfc.ntag2xx_ReadPage(3, ccTest);
|
||||
Serial.print("Capability Container nach Reset lesbar: ");
|
||||
Serial.println(ccReadable ? "✓" : "❌");
|
||||
|
||||
if (!ccReadable) {
|
||||
Serial.println("❌ NFC-Interface funktioniert nach Reset immer noch nicht");
|
||||
oledShowMessage("NFC still broken");
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Serial.println("✓ NFC-Interface erfolgreich wiederhergestellt");
|
||||
} else {
|
||||
Serial.println("✓ NFC-Interface ist funktionsfähig");
|
||||
}
|
||||
|
||||
// Display CC content for debugging
|
||||
if (ccReadable) {
|
||||
Serial.print("CC Inhalt: ");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
@@ -432,9 +546,13 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
// Test a few different pages to see which ones are accessible
|
||||
Serial.println("=== SCHRITT 2: INTERFACE-FUNKTIONSTEST ===");
|
||||
|
||||
// Test a few critical pages to ensure stable operation
|
||||
uint8_t testData[4];
|
||||
for (uint8_t testPage = 0; testPage <= 10; testPage++) {
|
||||
bool basicPagesReadable = true;
|
||||
|
||||
for (uint8_t testPage = 0; testPage <= 6; testPage++) {
|
||||
bool readable = nfc.ntag2xx_ReadPage(testPage, testData);
|
||||
Serial.print("Seite ");
|
||||
Serial.print(testPage);
|
||||
@@ -449,88 +567,58 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
||||
Serial.println();
|
||||
} else {
|
||||
Serial.println("❌ - Nicht lesbar");
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS); // Small delay between reads
|
||||
}
|
||||
|
||||
Serial.println("=== SCHRITT 2: AKTUELLER TAG-INHALT ===");
|
||||
|
||||
// Only read user data pages that are confirmed to be readable
|
||||
for (uint8_t page = 4; page < 20; page++) {
|
||||
uint8_t pageData[4];
|
||||
if (nfc.ntag2xx_ReadPage(page, pageData)) {
|
||||
Serial.print("Seite ");
|
||||
Serial.print(page);
|
||||
Serial.print(": ");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (pageData[i] < 0x10) Serial.print("0");
|
||||
Serial.print(pageData[i], HEX);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
} else {
|
||||
Serial.print("Fehler beim Lesen von Seite ");
|
||||
Serial.println(page);
|
||||
// If we can't read basic user data pages, there's a fundamental problem
|
||||
if (page <= 6) {
|
||||
Serial.println("KRITISCHER FEHLER: Kann grundlegende User-Data-Seiten nicht lesen!");
|
||||
Serial.println("Möglicherweise NFC-Interface-Problem oder Tag-Zustandsproblem");
|
||||
return 0;
|
||||
if (testPage >= 3 && testPage <= 6) { // Critical pages for NDEF
|
||||
basicPagesReadable = false;
|
||||
}
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS); // Small delay between reads
|
||||
}
|
||||
Serial.println("=========================================");
|
||||
|
||||
Serial.println();
|
||||
Serial.println("=== SCHRITT 3: SCHREIBTEST ===");
|
||||
Serial.println();
|
||||
Serial.println("=== SCHRITT 3: SCHREIBTEST ===");
|
||||
|
||||
// If basic pages are not readable, try to reinitialize NFC interface
|
||||
Serial.println("Versuche NFC-Interface zu stabilisieren...");
|
||||
|
||||
// Give the NFC interface time to stabilize
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
|
||||
// Try to reestablish communication
|
||||
bool interfaceOk = false;
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
Serial.print("NFC-Interface Test ");
|
||||
Serial.print(retry + 1);
|
||||
Serial.print("/3... ");
|
||||
|
||||
uint8_t ccRetest[4];
|
||||
if (nfc.ntag2xx_ReadPage(3, ccRetest)) {
|
||||
Serial.println("✓");
|
||||
interfaceOk = true;
|
||||
break;
|
||||
} else {
|
||||
Serial.println("❌");
|
||||
vTaskDelay(200 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
if (!interfaceOk) {
|
||||
Serial.println("FEHLER: NFC-Interface nicht stabil - Schreibvorgang abgebrochen");
|
||||
oledShowMessage("NFC Interface Error");
|
||||
if (!basicPagesReadable) {
|
||||
Serial.println("❌ KRITISCHER FEHLER: Grundlegende NDEF-Seiten nicht lesbar!");
|
||||
Serial.println("Tag oder Interface ist defekt");
|
||||
oledShowMessage("Tag/Interface defect");
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Serial.println("NFC-Interface ist stabil - fahre mit Schreibtest fort");
|
||||
Serial.println("✓ Alle kritischen Seiten sind lesbar");
|
||||
Serial.println("===================================================");
|
||||
|
||||
Serial.println();
|
||||
Serial.println("=== SCHRITT 3: SCHREIBBEREITSCHAFTSTEST ===");
|
||||
|
||||
// Test write capabilities before attempting the full write
|
||||
Serial.println("Teste Schreibfähigkeiten des Tags...");
|
||||
|
||||
uint8_t testPage[4] = {0xAA, 0xBB, 0xCC, 0xDD}; // Test pattern
|
||||
uint8_t originalPage[4]; // Store original content
|
||||
|
||||
if (!nfc.ntag2xx_WritePage(10, testPage)) { // Use page 10 for test
|
||||
Serial.println("FEHLER: Einfacher Schreibtest fehlgeschlagen!");
|
||||
// First, read original content of test page
|
||||
if (!nfc.ntag2xx_ReadPage(10, originalPage)) {
|
||||
Serial.println("FEHLER: Kann Testseite nicht lesen für Backup");
|
||||
oledShowMessage("Test page read error");
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Serial.print("Original Inhalt Seite 10: ");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (originalPage[i] < 0x10) Serial.print("0");
|
||||
Serial.print(originalPage[i], HEX);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
// Perform write test
|
||||
if (!nfc.ntag2xx_WritePage(10, testPage)) {
|
||||
Serial.println("FEHLER: Schreibtest fehlgeschlagen!");
|
||||
Serial.println("Tag ist möglicherweise schreibgeschützt oder defekt");
|
||||
|
||||
// Additional diagnostics
|
||||
Serial.println("=== ERWEITERTE DIAGNOSE ===");
|
||||
Serial.println("=== ERWEITERTE SCHREIBTEST-DIAGNOSE ===");
|
||||
|
||||
// Check if this is a timing issue
|
||||
Serial.println("Teste Tag-Erkennung erneut...");
|
||||
// Check if tag is still present
|
||||
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
|
||||
uint8_t uidLength;
|
||||
bool tagStillPresent = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 1000);
|
||||
@@ -538,14 +626,14 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
||||
Serial.println(tagStillPresent ? "✓" : "❌");
|
||||
|
||||
if (!tagStillPresent) {
|
||||
Serial.println("URSACHE: Tag wurde während Schreibvorgang entfernt!");
|
||||
oledShowMessage("Tag removed during write");
|
||||
Serial.println("URSACHE: Tag wurde während Schreibtest entfernt!");
|
||||
oledShowMessage("Tag removed");
|
||||
} else {
|
||||
Serial.println("URSACHE: Tag ist vorhanden aber nicht beschreibbar");
|
||||
Serial.println("Möglicherweise: Schreibschutz, Defekt, oder Timing-Problem");
|
||||
Serial.println("Möglicherweise: Schreibschutz, Defekt, oder Interface-Problem");
|
||||
oledShowMessage("Tag write protected?");
|
||||
}
|
||||
Serial.println("===============================");
|
||||
Serial.println("==========================================");
|
||||
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
return 0;
|
||||
@@ -553,8 +641,12 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
||||
|
||||
// Verify test write
|
||||
uint8_t readBack[4];
|
||||
vTaskDelay(20 / portTICK_PERIOD_MS); // Wait for write to complete
|
||||
|
||||
if (!nfc.ntag2xx_ReadPage(10, readBack)) {
|
||||
Serial.println("FEHLER: Kann Testdaten nicht zurücklesen!");
|
||||
oledShowMessage("Test verify failed");
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -581,12 +673,20 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Serial.println("✓ Schreibtest erfolgreich - Tag ist beschreibbar");
|
||||
Serial.println("================================");
|
||||
// Restore original content
|
||||
Serial.println("Stelle ursprünglichen Inhalt wieder her...");
|
||||
if (!nfc.ntag2xx_WritePage(10, originalPage)) {
|
||||
Serial.println("WARNUNG: Konnte ursprünglichen Inhalt nicht wiederherstellen!");
|
||||
} else {
|
||||
Serial.println("✓ Ursprünglicher Inhalt wiederhergestellt");
|
||||
}
|
||||
|
||||
// STEP 3: NDEF initialization with verification
|
||||
Serial.println("✓ Schreibtest erfolgreich - Tag ist voll funktionsfähig");
|
||||
Serial.println("======================================================");
|
||||
|
||||
// STEP 4: NDEF initialization with verification
|
||||
Serial.println();
|
||||
Serial.println("=== SCHRITT 3: NDEF-INITIALISIERUNG ===");
|
||||
Serial.println("=== SCHRITT 4: NDEF-INITIALISIERUNG ===");
|
||||
if (!initializeNdefStructure()) {
|
||||
Serial.println("FEHLER: Konnte NDEF-Struktur nicht initialisieren!");
|
||||
oledShowMessage("NDEF init failed");
|
||||
@@ -617,6 +717,42 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
||||
Serial.println("✓ NDEF-Struktur initialisiert und verifiziert");
|
||||
Serial.println("==========================================");
|
||||
|
||||
// STEP 5: Allow interface to stabilize before major write operation
|
||||
Serial.println();
|
||||
Serial.println("=== SCHRITT 5: NFC-INTERFACE STABILISIERUNG ===");
|
||||
Serial.println("Stabilisiere NFC-Interface vor Hauptschreibvorgang...");
|
||||
|
||||
// Give the interface time to fully settle after NDEF initialization
|
||||
vTaskDelay(200 / portTICK_PERIOD_MS);
|
||||
|
||||
// Test interface stability with a simple read
|
||||
uint8_t stabilityTest[4];
|
||||
bool interfaceStable = false;
|
||||
for (int attempts = 0; attempts < 3; attempts++) {
|
||||
if (nfc.ntag2xx_ReadPage(4, stabilityTest)) {
|
||||
Serial.print("Interface stability test ");
|
||||
Serial.print(attempts + 1);
|
||||
Serial.println("/3: ✓");
|
||||
interfaceStable = true;
|
||||
break;
|
||||
} else {
|
||||
Serial.print("Interface stability test ");
|
||||
Serial.print(attempts + 1);
|
||||
Serial.println("/3: ❌");
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
if (!interfaceStable) {
|
||||
Serial.println("FEHLER: NFC-Interface ist nicht stabil genug für Schreibvorgang");
|
||||
oledShowMessage("NFC Interface unstable");
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Serial.println("✓ NFC-Interface ist stabil - Schreibvorgang kann beginnen");
|
||||
Serial.println("=========================================================");
|
||||
|
||||
// Allocate memory for the complete TLV structure
|
||||
uint8_t* tlvData = (uint8_t*) malloc(totalTlvSize);
|
||||
if (tlvData == NULL) {
|
||||
@@ -677,7 +813,7 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
||||
uint16_t totalBytes = offset + 1;
|
||||
|
||||
Serial.println();
|
||||
Serial.println("=== SCHRITT 4: SCHREIBE NEUE NDEF-DATEN ===");
|
||||
Serial.println("=== SCHRITT 6: SCHREIBE NEUE NDEF-DATEN ===");
|
||||
Serial.print("Schreibe ");
|
||||
Serial.print(totalBytes);
|
||||
Serial.print(" Bytes in ");
|
||||
@@ -701,8 +837,26 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
||||
// Copy data to page buffer
|
||||
memcpy(pageBuffer, &tlvData[bytesWritten], bytesToWrite);
|
||||
|
||||
// Write page to tag
|
||||
if (!nfc.ntag2xx_WritePage(pageNumber, pageBuffer)) {
|
||||
// Write page to tag with retry mechanism
|
||||
bool writeSuccess = false;
|
||||
for (int writeAttempt = 0; writeAttempt < 3; writeAttempt++) {
|
||||
if (nfc.ntag2xx_WritePage(pageNumber, pageBuffer)) {
|
||||
writeSuccess = true;
|
||||
break;
|
||||
} else {
|
||||
Serial.print("Schreibversuch ");
|
||||
Serial.print(writeAttempt + 1);
|
||||
Serial.print("/3 für Seite ");
|
||||
Serial.print(pageNumber);
|
||||
Serial.println(" fehlgeschlagen");
|
||||
|
||||
if (writeAttempt < 2) {
|
||||
vTaskDelay(50 / portTICK_PERIOD_MS); // Wait before retry
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!writeSuccess) {
|
||||
Serial.print("FEHLER beim Schreiben der Seite ");
|
||||
Serial.println(pageNumber);
|
||||
Serial.print("Möglicherweise Page-Limit erreicht für ");
|
||||
@@ -727,13 +881,16 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
||||
Serial.print("... ");
|
||||
|
||||
uint8_t verifyBuffer[4];
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS); // Small delay before verification
|
||||
vTaskDelay(20 / portTICK_PERIOD_MS); // Increased delay before verification
|
||||
|
||||
// Verification with retry mechanism
|
||||
bool verifySuccess = false;
|
||||
for (int verifyAttempt = 0; verifyAttempt < 3; verifyAttempt++) {
|
||||
if (nfc.ntag2xx_ReadPage(pageNumber, verifyBuffer)) {
|
||||
bool writeSuccess = true;
|
||||
bool writeMatches = true;
|
||||
for (int i = 0; i < bytesToWrite; i++) {
|
||||
if (verifyBuffer[i] != pageBuffer[i]) {
|
||||
writeSuccess = false;
|
||||
writeMatches = false;
|
||||
Serial.println();
|
||||
Serial.print("VERIFIKATIONSFEHLER bei Byte ");
|
||||
Serial.print(i);
|
||||
@@ -745,18 +902,32 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!writeSuccess) {
|
||||
Serial.println("❌ SCHREIBVORGANG FEHLGESCHLAGEN!");
|
||||
if (writeMatches) {
|
||||
verifySuccess = true;
|
||||
break;
|
||||
} else if (verifyAttempt < 2) {
|
||||
Serial.print("Verifikationsversuch ");
|
||||
Serial.print(verifyAttempt + 1);
|
||||
Serial.println("/3 fehlgeschlagen, wiederhole...");
|
||||
vTaskDelay(30 / portTICK_PERIOD_MS);
|
||||
}
|
||||
} else {
|
||||
Serial.print("Verifikations-Read-Versuch ");
|
||||
Serial.print(verifyAttempt + 1);
|
||||
Serial.println("/3 fehlgeschlagen");
|
||||
if (verifyAttempt < 2) {
|
||||
vTaskDelay(30 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!verifySuccess) {
|
||||
Serial.println("❌ SCHREIBVORGANG/VERIFIKATION FEHLGESCHLAGEN!");
|
||||
free(tlvData);
|
||||
return 0;
|
||||
} else {
|
||||
Serial.println("✓");
|
||||
}
|
||||
} else {
|
||||
Serial.println("❌ Kann Seite nicht zur Verifikation lesen!");
|
||||
free(tlvData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Serial.print("Seite ");
|
||||
Serial.print(pageNumber);
|
||||
@@ -772,7 +943,7 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
||||
pageNumber++;
|
||||
|
||||
yield();
|
||||
vTaskDelay(5 / portTICK_PERIOD_MS); // Small delay between page writes
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS); // Slightly increased delay between page writes
|
||||
}
|
||||
|
||||
free(tlvData);
|
||||
@@ -799,128 +970,57 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
|
||||
Serial.println("%");
|
||||
Serial.println("✓ Bestehende Daten wurden überschrieben");
|
||||
|
||||
// CRITICAL: Verify the write by reading back the data
|
||||
// CRITICAL: Allow NFC interface to stabilize after write operation
|
||||
Serial.println();
|
||||
Serial.println("=== WRITE VERIFICATION ===");
|
||||
Serial.println("=== SCHRITT 7: NFC-INTERFACE STABILISIERUNG NACH SCHREIBVORGANG ===");
|
||||
Serial.println("Stabilisiere NFC-Interface nach Schreibvorgang...");
|
||||
|
||||
// Wait a moment for tag to stabilize
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
// Give the tag and interface time to settle after write operation
|
||||
vTaskDelay(300 / portTICK_PERIOD_MS); // Increased stabilization time
|
||||
|
||||
// Read back the written data to verify
|
||||
uint8_t verifyBuffer[totalBytes];
|
||||
memset(verifyBuffer, 0, totalBytes);
|
||||
// Test if the interface is still responsive
|
||||
uint8_t postWriteTest[4];
|
||||
bool interfaceResponsive = false;
|
||||
|
||||
bool verificationSuccess = true;
|
||||
uint8_t verifyPage = 4;
|
||||
uint16_t verifyBytesRead = 0;
|
||||
for (int stabilityAttempt = 0; stabilityAttempt < 5; stabilityAttempt++) {
|
||||
Serial.print("Post-write interface test ");
|
||||
Serial.print(stabilityAttempt + 1);
|
||||
Serial.print("/5... ");
|
||||
|
||||
while (verifyBytesRead < totalBytes && verifyPage <= maxWritablePage) {
|
||||
uint8_t pageData[4];
|
||||
if (!nfc.ntag2xx_ReadPage(verifyPage, pageData)) {
|
||||
Serial.print("VERIFICATION FAILED: Cannot read page ");
|
||||
Serial.println(verifyPage);
|
||||
verificationSuccess = false;
|
||||
if (nfc.ntag2xx_ReadPage(3, postWriteTest)) { // Read capability container
|
||||
Serial.println("✓");
|
||||
interfaceResponsive = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
Serial.println("❌");
|
||||
|
||||
// Copy page data to verify buffer
|
||||
uint16_t bytesToCopy = min(4, (int)(totalBytes - verifyBytesRead));
|
||||
memcpy(&verifyBuffer[verifyBytesRead], pageData, bytesToCopy);
|
||||
if (stabilityAttempt < 4) {
|
||||
Serial.println("Warte und versuche Interface zu stabilisieren...");
|
||||
vTaskDelay(200 / portTICK_PERIOD_MS);
|
||||
|
||||
verifyBytesRead += bytesToCopy;
|
||||
verifyPage++;
|
||||
}
|
||||
// Try to re-establish communication with a simple tag presence check
|
||||
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
|
||||
uint8_t uidLength;
|
||||
bool tagStillPresent = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 1000);
|
||||
Serial.print("Tag presence check: ");
|
||||
Serial.println(tagStillPresent ? "✓" : "❌");
|
||||
|
||||
if (verificationSuccess && verifyBytesRead >= totalBytes) {
|
||||
// Compare written data with read data
|
||||
bool dataMatches = true;
|
||||
for (uint16_t i = 0; i < totalBytes; i++) {
|
||||
if (verifyBuffer[i] != tlvData[i]) {
|
||||
Serial.print("VERIFICATION FAILED: Data mismatch at byte ");
|
||||
Serial.print(i);
|
||||
Serial.print(" - Expected: 0x");
|
||||
Serial.print(tlvData[i], HEX);
|
||||
Serial.print(", Read: 0x");
|
||||
Serial.println(verifyBuffer[i], HEX);
|
||||
dataMatches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dataMatches) {
|
||||
Serial.println("✓ WRITE VERIFICATION SUCCESSFUL!");
|
||||
Serial.println("✓ All written data verified correctly");
|
||||
|
||||
// Additional JSON verification - try to parse the written JSON
|
||||
Serial.println("=== JSON VERIFICATION ===");
|
||||
|
||||
// Find and extract JSON from verified data
|
||||
// Look for the JSON payload within the NDEF structure
|
||||
bool jsonFound = false;
|
||||
for (uint16_t i = 0; i < totalBytes - 10; i++) {
|
||||
if (verifyBuffer[i] == '{') {
|
||||
// Found potential JSON start
|
||||
String extractedJson = "";
|
||||
uint16_t jsonEnd = 0;
|
||||
|
||||
for (uint16_t j = i; j < totalBytes; j++) {
|
||||
if (verifyBuffer[j] >= 32 && verifyBuffer[j] <= 126) {
|
||||
extractedJson += (char)verifyBuffer[j];
|
||||
if (verifyBuffer[j] == '}') {
|
||||
jsonEnd = j;
|
||||
if (!tagStillPresent) {
|
||||
Serial.println("Tag wurde während/nach Schreibvorgang entfernt!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Serial.print("Extracted JSON from tag: ");
|
||||
Serial.println(extractedJson);
|
||||
|
||||
// Try to parse the extracted JSON
|
||||
JsonDocument testDoc;
|
||||
DeserializationError error = deserializeJson(testDoc, extractedJson);
|
||||
if (!error) {
|
||||
Serial.println("✓ JSON VERIFICATION SUCCESSFUL!");
|
||||
Serial.print("✓ JSON is valid and parseable");
|
||||
|
||||
if (testDoc["sm_id"].is<String>()) {
|
||||
Serial.print(" - sm_id found: ");
|
||||
Serial.println(testDoc["sm_id"].as<String>());
|
||||
if (!interfaceResponsive) {
|
||||
Serial.println("WARNUNG: NFC-Interface reagiert nach Schreibvorgang nicht mehr stabil");
|
||||
Serial.println("Schreibvorgang war erfolgreich, aber Interface benötigt möglicherweise Reset");
|
||||
} else {
|
||||
Serial.println(" - WARNING: sm_id not found in JSON!");
|
||||
Serial.println("✓ NFC-Interface ist nach Schreibvorgang stabil");
|
||||
}
|
||||
|
||||
jsonFound = true;
|
||||
testDoc.clear();
|
||||
break;
|
||||
} else {
|
||||
Serial.print("JSON parse error: ");
|
||||
Serial.println(error.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!jsonFound) {
|
||||
Serial.println("WARNING: No valid JSON found in verified data!");
|
||||
verificationSuccess = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
verificationSuccess = false;
|
||||
}
|
||||
} else {
|
||||
Serial.println("VERIFICATION FAILED: Could not read back all data");
|
||||
verificationSuccess = false;
|
||||
}
|
||||
|
||||
Serial.println("=========================");
|
||||
Serial.println();
|
||||
|
||||
if (!verificationSuccess) {
|
||||
Serial.println("❌ WRITE FAILED - Data verification unsuccessful");
|
||||
Serial.println("❌ Tag may not contain the expected data");
|
||||
return 0;
|
||||
}
|
||||
Serial.println("==================================================================");
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1144,7 +1244,7 @@ bool decodeNdefAndReturnJson(const byte* encodedMessage, String uidString) {
|
||||
}
|
||||
// Brand Filament not registered to Spoolman
|
||||
else if ((!doc["sm_id"].is<String>() || (doc["sm_id"].is<String>() && (doc["sm_id"] == "0" || doc["sm_id"] == "")))
|
||||
&& doc["brand"].is<String>() && doc["artnr"].is<String>())
|
||||
&& doc["b"].is<String>() && doc["an"].is<String>())
|
||||
{
|
||||
doc["sm_id"] = "0"; // Ensure sm_id is set to 0
|
||||
// If no sm_id is present but the brand is Brand Filament then
|
||||
@@ -1169,7 +1269,7 @@ bool decodeNdefAndReturnJson(const byte* encodedMessage, String uidString) {
|
||||
}
|
||||
|
||||
bool quickSpoolIdCheck(String uidString) {
|
||||
// Fast-path: Read only first 2-3 pages to check for sm_id pattern
|
||||
// Fast-path: Read NDEF structure to quickly locate and check JSON payload
|
||||
// This dramatically speeds up known spool recognition
|
||||
|
||||
// CRITICAL: Do not execute during write operations!
|
||||
@@ -1180,60 +1280,197 @@ bool quickSpoolIdCheck(String uidString) {
|
||||
|
||||
Serial.println("=== FAST-PATH: Quick sm_id Check ===");
|
||||
|
||||
// Read first 3 pages (12 bytes) after NDEF header (pages 4-6)
|
||||
uint8_t quickData[12];
|
||||
memset(quickData, 0, 12);
|
||||
// Read enough pages to cover NDEF header + beginning of payload (pages 4-8 = 20 bytes)
|
||||
uint8_t ndefData[20];
|
||||
memset(ndefData, 0, 20);
|
||||
|
||||
for (uint8_t page = 4; page < 7; page++) {
|
||||
if (!nfc.ntag2xx_ReadPage(page, quickData + (page - 4) * 4)) {
|
||||
for (uint8_t page = 4; page < 9; page++) {
|
||||
if (!nfc.ntag2xx_ReadPage(page, ndefData + (page - 4) * 4)) {
|
||||
Serial.print("Failed to read page ");
|
||||
Serial.println(page);
|
||||
return false; // Fall back to full read
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to string for pattern matching
|
||||
String quickCheck = "";
|
||||
for (int i = 0; i < 12; i++) {
|
||||
if (quickData[i] >= 32 && quickData[i] <= 126) {
|
||||
quickCheck += (char)quickData[i];
|
||||
// Parse NDEF structure to find JSON payload start
|
||||
Serial.print("Raw NDEF data (first 20 bytes): ");
|
||||
for (int i = 0; i < 20; i++) {
|
||||
if (ndefData[i] < 0x10) Serial.print("0");
|
||||
Serial.print(ndefData[i], HEX);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
// Look for NDEF TLV (0x03) at the beginning
|
||||
int tlvOffset = -1;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (ndefData[i] == 0x03) {
|
||||
tlvOffset = i;
|
||||
Serial.print("Found NDEF TLV at offset: ");
|
||||
Serial.println(tlvOffset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Serial.print("Quick data (first 12 bytes): ");
|
||||
Serial.println(quickCheck);
|
||||
if (tlvOffset == -1) {
|
||||
Serial.println("✗ FAST-PATH: No NDEF TLV found");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Look for sm_id pattern at the beginning
|
||||
if (quickCheck.indexOf("\"sm_id\":\"") >= 0 && quickCheck.indexOf("\"sm_id\":\"0\"") < 0) {
|
||||
Serial.println("✓ FAST-PATH: sm_id found in first bytes - known spool detected!");
|
||||
// Parse NDEF record to find JSON payload
|
||||
int ndefRecordStart;
|
||||
if (ndefData[tlvOffset + 1] == 0xFF) {
|
||||
// Extended length format
|
||||
ndefRecordStart = tlvOffset + 4;
|
||||
} else {
|
||||
// Standard length format
|
||||
ndefRecordStart = tlvOffset + 2;
|
||||
}
|
||||
|
||||
// Extract sm_id from quick data if possible
|
||||
int smIdStart = quickCheck.indexOf("\"sm_id\":\"") + 9;
|
||||
int smIdEnd = quickCheck.indexOf("\"", smIdStart);
|
||||
if (ndefRecordStart >= 20) {
|
||||
Serial.println("✗ FAST-PATH: NDEF record starts beyond read data");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (smIdEnd > smIdStart) {
|
||||
String quickSpoolId = quickCheck.substring(smIdStart, smIdEnd);
|
||||
Serial.print("✓ Quick extracted sm_id: ");
|
||||
// Parse NDEF record header
|
||||
uint8_t recordHeader = ndefData[ndefRecordStart];
|
||||
uint8_t typeLength = ndefData[ndefRecordStart + 1];
|
||||
|
||||
// Calculate payload offset
|
||||
uint8_t payloadLengthBytes = (recordHeader & 0x10) ? 1 : 4; // SR flag check
|
||||
uint8_t idLength = (recordHeader & 0x08) ? ndefData[ndefRecordStart + 2 + payloadLengthBytes + typeLength] : 0; // IL flag check
|
||||
|
||||
int payloadOffset = ndefRecordStart + 1 + 1 + payloadLengthBytes + typeLength + idLength;
|
||||
|
||||
Serial.print("NDEF Record Header: 0x");
|
||||
Serial.print(recordHeader, HEX);
|
||||
Serial.print(", Type Length: ");
|
||||
Serial.print(typeLength);
|
||||
Serial.print(", Payload offset: ");
|
||||
Serial.println(payloadOffset);
|
||||
|
||||
// Check if payload starts within our read data
|
||||
if (payloadOffset >= 20) {
|
||||
Serial.println("✗ FAST-PATH: JSON payload starts beyond quick read data - need more pages");
|
||||
|
||||
// Read additional pages to get to JSON payload
|
||||
uint8_t extraData[16]; // Read 4 more pages
|
||||
memset(extraData, 0, 16);
|
||||
|
||||
for (uint8_t page = 9; page < 13; page++) {
|
||||
if (!nfc.ntag2xx_ReadPage(page, extraData + (page - 9) * 4)) {
|
||||
Serial.print("Failed to read additional page ");
|
||||
Serial.println(page);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Combine data
|
||||
uint8_t combinedData[36];
|
||||
memcpy(combinedData, ndefData, 20);
|
||||
memcpy(combinedData + 20, extraData, 16);
|
||||
|
||||
// Extract JSON from combined data
|
||||
String jsonStart = "";
|
||||
int jsonStartPos = payloadOffset;
|
||||
for (int i = 0; i < 36 - payloadOffset && i < 30; i++) {
|
||||
uint8_t currentByte = combinedData[payloadOffset + i];
|
||||
if (currentByte >= 32 && currentByte <= 126) {
|
||||
jsonStart += (char)currentByte;
|
||||
}
|
||||
// Stop at first brace to get just the beginning
|
||||
if (currentByte == '{' && i > 0) break;
|
||||
}
|
||||
|
||||
Serial.print("JSON start from extended read: ");
|
||||
Serial.println(jsonStart);
|
||||
|
||||
// Check for sm_id pattern - look for non-zero sm_id values
|
||||
if (jsonStart.indexOf("\"sm_id\":\"") >= 0) {
|
||||
int smIdStart = jsonStart.indexOf("\"sm_id\":\"") + 9;
|
||||
int smIdEnd = jsonStart.indexOf("\"", smIdStart);
|
||||
|
||||
if (smIdEnd > smIdStart && smIdEnd < jsonStart.length()) {
|
||||
String quickSpoolId = jsonStart.substring(smIdStart, smIdEnd);
|
||||
Serial.print("Found sm_id in extended read: ");
|
||||
Serial.println(quickSpoolId);
|
||||
|
||||
// Only process if sm_id is not "0" (known spool)
|
||||
if (quickSpoolId != "0" && quickSpoolId.length() > 0) {
|
||||
Serial.println("✓ FAST-PATH: Known spool detected!");
|
||||
|
||||
// Set as active spool immediately
|
||||
activeSpoolId = quickSpoolId;
|
||||
lastSpoolId = activeSpoolId;
|
||||
|
||||
oledShowProgressBar(2, octoEnabled?5:4, "Known Spool", "Quick mode");
|
||||
Serial.println("✓ FAST-PATH SUCCESS: Known spool processed quickly");
|
||||
return true; // Skip full tag reading!
|
||||
return true;
|
||||
} else {
|
||||
Serial.println("✗ FAST-PATH: sm_id is 0 - new brand filament, need full read");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for other quick patterns
|
||||
if (quickCheck.indexOf("\"location\":\"") >= 0) {
|
||||
Serial.println("✗ FAST-PATH: No sm_id pattern in extended read");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract JSON payload from the available data
|
||||
String quickJson = "";
|
||||
for (int i = payloadOffset; i < 20 && i < payloadOffset + 15; i++) {
|
||||
uint8_t currentByte = ndefData[i];
|
||||
if (currentByte >= 32 && currentByte <= 126) {
|
||||
quickJson += (char)currentByte;
|
||||
}
|
||||
}
|
||||
|
||||
Serial.print("Quick JSON data: ");
|
||||
Serial.println(quickJson);
|
||||
|
||||
// Look for sm_id pattern in the beginning of JSON - check for known vs new spools
|
||||
if (quickJson.indexOf("\"sm_id\":\"") >= 0) {
|
||||
Serial.println("✓ FAST-PATH: sm_id field found");
|
||||
|
||||
// Extract sm_id from quick data
|
||||
int smIdStart = quickJson.indexOf("\"sm_id\":\"") + 9;
|
||||
int smIdEnd = quickJson.indexOf("\"", smIdStart);
|
||||
|
||||
if (smIdEnd > smIdStart && smIdEnd < quickJson.length()) {
|
||||
String quickSpoolId = quickJson.substring(smIdStart, smIdEnd);
|
||||
Serial.print("✓ Quick extracted sm_id: ");
|
||||
Serial.println(quickSpoolId);
|
||||
|
||||
// Only process known spools (sm_id != "0") via fast path
|
||||
if (quickSpoolId != "0" && quickSpoolId.length() > 0) {
|
||||
Serial.println("✓ FAST-PATH: Known spool detected!");
|
||||
|
||||
// Set as active spool immediately
|
||||
activeSpoolId = quickSpoolId;
|
||||
lastSpoolId = activeSpoolId;
|
||||
|
||||
oledShowProgressBar(2, octoEnabled?5:4, "Known Spool", "Quick mode");
|
||||
Serial.println("✓ FAST-PATH SUCCESS: Known spool processed quickly");
|
||||
return true;
|
||||
} else {
|
||||
Serial.println("✗ FAST-PATH: sm_id is 0 - new brand filament, need full read");
|
||||
return false; // sm_id="0" means new brand filament, needs full processing
|
||||
}
|
||||
} else {
|
||||
Serial.println("✗ FAST-PATH: Could not extract complete sm_id value");
|
||||
return false; // Need full read to get complete sm_id
|
||||
}
|
||||
}
|
||||
|
||||
// Check for other patterns that require full read
|
||||
if (quickJson.indexOf("\"location\":\"") >= 0) {
|
||||
Serial.println("✓ FAST-PATH: Location tag detected");
|
||||
return false; // Need full read for location processing
|
||||
}
|
||||
|
||||
if (quickCheck.indexOf("\"brand\":\"") >= 0 && quickCheck.indexOf("\"sm_id\":\"0\"") >= 0) {
|
||||
Serial.println("✓ FAST-PATH: New brand filament detected (sm_id:0)");
|
||||
if (quickJson.indexOf("\"brand\":\"") >= 0) {
|
||||
Serial.println("✓ FAST-PATH: Brand filament detected - may need full processing");
|
||||
return false; // Need full read for brand filament creation
|
||||
}
|
||||
|
||||
@@ -1312,13 +1549,80 @@ void writeJsonToTag(void *parameter) {
|
||||
}else{
|
||||
oledShowProgressBar(1, 1, "Write Tag", "Done!");
|
||||
}
|
||||
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||
|
||||
// CRITICAL: Properly stabilize NFC interface after write operation
|
||||
Serial.println();
|
||||
Serial.println("=== POST-WRITE NFC STABILIZATION ===");
|
||||
|
||||
// Wait for tag operations to complete
|
||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
|
||||
// Test tag presence and remove detection
|
||||
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
|
||||
uint8_t uidLength;
|
||||
int tagRemovalChecks = 0;
|
||||
|
||||
Serial.println("Warte bis Tag entfernt wird...");
|
||||
|
||||
// Monitor tag presence
|
||||
while (tagRemovalChecks < 10) {
|
||||
yield();
|
||||
esp_task_wdt_reset();
|
||||
while (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 400)) {
|
||||
yield();
|
||||
|
||||
bool tagPresent = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, 500);
|
||||
|
||||
if (!tagPresent) {
|
||||
Serial.println("✓ Tag wurde entfernt - NFC bereit für nächsten Scan");
|
||||
break;
|
||||
}
|
||||
|
||||
tagRemovalChecks++;
|
||||
Serial.print("Tag noch vorhanden (");
|
||||
Serial.print(tagRemovalChecks);
|
||||
Serial.println("/10)");
|
||||
|
||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
if (tagRemovalChecks >= 10) {
|
||||
Serial.println("WARNUNG: Tag wurde nicht entfernt - fahre trotzdem fort");
|
||||
}
|
||||
|
||||
// Additional interface stabilization before resuming normal operations
|
||||
Serial.println("Stabilisiere NFC-Interface für normale Operationen...");
|
||||
vTaskDelay(200 / portTICK_PERIOD_MS);
|
||||
|
||||
// Test if interface is ready for normal scanning
|
||||
uint8_t interfaceTestBuffer[4];
|
||||
bool interfaceReady = false;
|
||||
|
||||
for (int testAttempt = 0; testAttempt < 3; testAttempt++) {
|
||||
// Try a simple interface operation (without requiring tag presence)
|
||||
Serial.print("Interface readiness test ");
|
||||
Serial.print(testAttempt + 1);
|
||||
Serial.print("/3... ");
|
||||
|
||||
// Use a safe read operation that doesn't depend on tag presence
|
||||
// This tests if the PN532 chip itself is responsive
|
||||
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||
if (versiondata != 0) {
|
||||
Serial.println("✓");
|
||||
interfaceReady = true;
|
||||
break;
|
||||
} else {
|
||||
Serial.println("❌");
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
if (!interfaceReady) {
|
||||
Serial.println("WARNUNG: NFC-Interface reagiert nicht - könnte normale Scans beeinträchtigen");
|
||||
} else {
|
||||
Serial.println("✓ NFC-Interface ist bereit für normale Scans");
|
||||
}
|
||||
|
||||
Serial.println("=========================================");
|
||||
|
||||
vTaskResume(RfidReaderTask);
|
||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
@@ -48,9 +48,6 @@ void scale_loop(void * parameter) {
|
||||
Serial.println("Scale Loop started");
|
||||
Serial.println("++++++++++++++++++++++++++++++");
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
scale_tare_counter = 10; // damit beim Starten der Waage automatisch getart wird
|
||||
|
||||
for(;;) {
|
||||
if (scale.is_ready())
|
||||
{
|
||||
@@ -114,18 +111,20 @@ void start_scale(bool touchSensorConnected) {
|
||||
scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
|
||||
|
||||
oledShowProgressBar(6, 7, DISPLAY_BOOT_TEXT, "Tare scale");
|
||||
for (uint16_t i = 0; i < 2000; i++) {
|
||||
for (uint16_t i = 0; i < 3000; i++) {
|
||||
yield();
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
|
||||
if (scale.wait_ready_timeout(1000))
|
||||
{
|
||||
scale.set_scale(calibrationValue); // this value is obtained by calibrating the scale with known weights; see the README for details
|
||||
//scale.tare();
|
||||
while(!scale.is_ready()) {
|
||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
}
|
||||
|
||||
scale.set_scale(calibrationValue);
|
||||
//vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
//scale.tare();
|
||||
|
||||
// Display Gewicht
|
||||
oledShowWeight(0);
|
||||
|
||||
|
Reference in New Issue
Block a user