# Podsumowanie pracy - 9 maja 2026 ## Cel Naprawić upload plików .wmt z ESP32 do REST API - firmware nie wysyłał plików na serwer. --- ## Problem początkowy ### Symptom - User zgłosił: "nie wysyła do api" - API logs pokazywały tylko GET requests do `/api/docs` i `/api/openapi.json` - Brak POST requests do endpoint'u upload - Pliki .wmt generowały się na SD card ale nie były wysyłane ### Przyczyna główna Uploader.cpp zawierał kod ale: 1. **Credentials były błędne**: firmware używał "wmt"/"Zaq12wsx" zamiast "SN001234ABCD56789012"/"device001" 2. **Upload disabled**: konfiguracja miała `uploadEnable=false` w EEPROM 3. **Upload thread nie działał**: nawet jeśli config by się zmienił, thread nigdy się nie启动 --- ## Zmiana 1: Konfiguracja - Poprawienie credentials **Plik**: `src/Config.cpp` **Problem**: Firmware wysyłał HTTP Basic Auth z niemożliwymi do uwierzytelnienia kredencjałami. **Rozwiązanie**: ```cpp // Stare (ŹRÓDŁOWE): strcpy(config.restUser, "wmt"); strcpy(config.restPass, "Zaq12wsx"); // NOWE: strcpy(config.restUser, "SN001234ABCD56789012"); strcpy(config.restPass, "device001"); ``` **Źródło kredencjałów**: `pi_rest/init_db.py` - device seeded w bazie testowej --- ## Zmiana 2: Migracja konfiguracji dla istniejących urządzeń **Plik**: `src/Config.cpp` **Problem**: Firmware był flashowany wielokrotnie - EEPROM przechowuje starą konfigurację z błędnymi kredencjałami. Update do kodu nie wystarczy - trzeba migrować istniejące dane. **Rozwiązanie** - dodana logika w `readConfig()`: ```cpp void ConfigManager::readConfig() { EEPROM.get(1, config); // Jeśli old credentials LUB uploadEnable=false z test device credentials if ((strcmp(config.restUser, "wmt") == 0 && strcmp(config.restPass, "Zaq12wsx") == 0) || strlen(config.restUser) == 0 || strlen(config.restPass) == 0 || (!config.uploadEnable && strcmp(config.restUser, "SN001234ABCD56789012") == 0)) { // Migrate to correct credentials strcpy(config.restUser, "SN001234ABCD56789012"); strcpy(config.restPass, "device001"); config.uploadEnable = true; config.uploadInterval = 5000; saveConfig(); EEPROM.begin(EEPROM_SIZE); EEPROM.get(1, config); } } ``` **Efekt**: Przy każdym boot, jeśli EEPROM zawiera old credentials LUB device ma test credentials ale upload disabled, automatycznie updatuje się i zapisuje nową konfigurację. --- ## Zmiana 3: Diagnostyczne logi w uploadThread **Plik**: `src/main.cpp` **Problem**: Nie wiedzieliśmy czy upload thread się inicjalizuje i uruchamia. **Zmiana**: ```cpp // Line 232-240: Dodane logi w setup() if (config.uploadEnable) { ESP_LOGI(TAG, "[MAIN] Upload enabled, interval: %d ms", config.uploadInterval); uploadThread.setInterval(config.uploadInterval); uploadThread.onRun(uploadTask); uploadThreadController.add(&uploadThread); ESP_LOGI(TAG, "[MAIN] Upload thread configured"); } else { ESP_LOGI(TAG_W, "[MAIN] Upload disabled in config"); } // Line 260-262: Logi w uploadTask wrapper uploadTask() -> "[MAIN] Upload task called" ... "[MAIN] Upload task completed" // Line 428-433: Log gdy thread rzeczywiście sie uruchami if(uploadThread.shouldRun() && (config.connect) && config.uploadEnable) { ESP_LOGI(TAG, "[MAIN] Upload thread running"); ``` **Wynik**: Serial monitor pokazuje jasno co się dzieje z upload thread. --- ## Zmiana 4: Diagnostyczne logi i upload logic w Uploader.cpp **Plik**: `src/Uploader.cpp` ### 4a. process() - Skanowanie SD card **Problem**: Uploader skanuje SD card ale nie widać co dokładnie robi - czy znajduje pliki, czy je przeskakuje? **Zmiana** - dodane szczegółowe logi w `process()`: ```cpp for (File f = root.openNextFile(); f; f = root.openNextFile()) { String fname = String(f.name()); if (f.isDirectory()) { String dirBase = baseNameFromPath(fname); if (isReservedDirectoryName(dirBase)) { ESP_LOGI(TAG_UP, "Skipping reserved dir: %s", fname.c_str()); // <- NEW f.close(); continue; } ESP_LOGI(TAG_UP, "Scanning directory: %s", fname.c_str()); // <- NEW // ... if (ename.endsWith(".wmt")) { String full = dirPath + "/" + ename; ESP_LOGI(TAG_UP, "Found .wmt file: %s", full.c_str()); // <- NEW // upload... } } } if (no files found) { ESP_LOGI(TAG_UP, "Scan complete - no .wmt files found to upload"); // <- NEW } ``` **Wynik**: Serial monitor pokazuje: ``` [UPLOADER] Process called, scanning for .wmt files [UPLOADER] Skipping reserved dir: .Spotlight-V100 [UPLOADER] Scanning directory: 1 [UPLOADER] Found .wmt file: /1/00000001.wmt ``` ### 4b. uploadFile() - Upload logic z obsługą błędów **Implementacja**: 1. **Multipart request** - streaming file w chunks (1024 bytes) 2. **HTTP Basic Auth** - base64 encoded credentials w Authorization header 3. **Response handling** - odczyt status code HTTP i body 4. **Auth diagnostics** - specjalne logowanie dla 401/403: ```cpp if (statusCode == 401 || statusCode == 403) { Serial.printf("[%s] Auth failed (%d). REST credentials must be the device serial/password from pi_rest, not the admin login.\n", TAG_UP, statusCode); } ``` 5. **Success handling (200-299)**: - Przeniesienie pliku do `/uploads/` subfolder - Wpis do `/uploads.csv` z timestamp i status code ```cpp String destPath = dirPath + "/uploaded/" + filename; if (_fs.rename(path.c_str(), destPath.c_str())) { Serial.printf("[%s] Moved to %s\n", TAG_UP, destPath.c_str()); } appendCsvLine(_fs, "/uploads.csv", lineBase + "sent," + path + "\n"); return true; ``` 6. **Failure handling**: - Wpis do `/uploads_failed.csv` - Wiadomość o błędzie w serial ```cpp appendCsvLine(_fs, "/uploads_failed.csv", lineBase + "failed," + path + "\n"); ``` --- ## Problem rozwiązany - ale pojawił się nowy ### ✅ Co zostało naprawione - Upload thread teraz się **uruchamia** - logs pokazują "Upload enabled" i "Upload thread running" - Uploader **znajduje pliki** - logs pokazują "Found .wmt file: /1/00000001.wmt" - Credentials są **prawidłowe** - SN001234ABCD56789012 / device001 ### ❌ Nowy problem Upload nie powiódł się - timeout na connect do 62.93.60.19:5004: ``` [ 11842][I][WiFiClient.cpp:260] connect(): select returned due to timeout 3000 ms for fd 48 ``` --- ## Problem 5: Server REST API jest niedostępny ### Symptom - Firmware próbuje połączyć się z `62.93.60.19:5004` - Każdy connect timeout po 3 sekundy - Ping do 62.93.60.19 pokazuje 100% loss ### Przyczyna Serwer FastAPI (pi_rest) nie jest uruchomiony na tym IP. Adres 62.93.60.19 to kiedyś był serwer produkcyjny ale teraz: - Nie ma dostępu z lokalnej sieci - REST API powinien być uruchomiony lokalnie na `localhost:8000` (z `start_serwer.py`) ### Konfiguracja w firmware **Plik**: `src/Config.cpp` linia 101-102 ```cpp strcpy(config.restURL, "http://62.93.60.19"); config.restPort = 5004; ``` Hardcoded URL - nie da się zmienić bez reflash! --- ## Sieć - Mismatch ``` PC (moje): - WiFi: 192.168.33.7 - Eth2: 192.168.56.1 - Tailscale: 100.94.209.73 ESP32: - WiFi: 192.168.1.9 (na sieci NETBYL) - Gateway: 192.168.1.1 Serwer REST: - Firmware szuka: 62.93.60.19:5004 - Dostępny: ? (nie responduje) ``` ESP32 i PC są na **różnych WiFi sieciach** co utrudnia testowanie. --- ## Zmiany wprowadzone w kodzie ### Zatwierdzené files edits: | Plik | Zmiana | Status | |------|--------|--------| | `src/Config.cpp` | Credentials + migration logic | ✅ Flashed | | `src/main.cpp` | Upload thread diagnostics | ✅ Flashed | | `src/Uploader.cpp` | Detailed scanning logs | ✅ Flashed | ### Build & Flash ``` Compiled: ✅ 27.2% flash usage (907585 bytes) Flashed to: COM12 (Freenove ESP32-S3) Build time: ~25 seconds ``` --- ## Status danych na SD card | Folder | Files | Status | |--------|-------|--------| | `/1/` | 00000001.wmt - 00000351.wmt | ✅ Znalezione | | `/2/` | ? | Nie sprawdzane | | `.Spotlight-V100/` | System macOS | Przeskakiwane | Uploader znajduje i próbuje wysłać `/1/00000001.wmt` ale nie może się podłączyć do serwera. --- ## Następne kroki do wykonania 1. **Uruchomić lokalny REST API server** ```bash cd d:\Prod\pi_rest\api pip install -r requirements.txt python start_serwer.py # Server dostępny na http://localhost:8000 ``` 2. **Zmienić URL w firmware** - albo: - Zmienić `Config.cpp` na `http://192.168.33.7` (PC IP) - ALBO uruchomić serwer na publicznym IP dostępnym z ESP32 3. **Retestować upload** - Zaobserwować serial monitor - Sprawdzić czy multipart request dociera - Weryfikować czy 201 Created response wróci 4. **Weryfikacja** - Check `/uploads/` na SD card czy plik się przeniesie - Check `/uploads.csv` czy wpis się pojawi - Check API database czy measurement record się utworzy --- ## Kluczowe kody i endpoints ### API endpoint ``` POST /api/v1/measurements/measurements/upload Content-Type: multipart/form-data Authorization: Basic base64(SN001234ABCD56789012:device001) Body: file binary data Field name: "file" ``` ### Seeded device w bazie ```python # pi_rest/init_db.py device = Device( serial="SN001234ABCD56789012", password_hashed=bcrypt("device001"), log_type=1 # HTTP BASIC auth ) ``` ### Upload thread scheduling ```cpp uploadThread.setInterval(5000); // every 5 seconds uploadThread.onRun(uploadTask); uploadThreadController.add(&uploadThread); ``` --- ## Podsumowanie błędów i napraw | # | Problem | Naprawa | Plik | Status | |---|---------|---------|------|--------| | 1 | Credentials "wmt"/"Zaq12wsx" | Zmiana na test device | Config.cpp | ✅ Done | | 2 | EEPROM z old config | Migration logic | Config.cpp | ✅ Done | | 3 | uploadEnable=false | Auto-enable w migration | Config.cpp | ✅ Done | | 4 | Nie widać co thread robi | Dodane logi setup/loop | main.cpp | ✅ Done | | 5 | Uploader nie widać co robi | Dodane logi process() | Uploader.cpp | ✅ Done | | 6 | Server nie dostępny | | - | ⏳ TODO | | 7 | URL hardcoded 62.93.60.19 | Wymaga reflash | Config.cpp | ⏳ TODO | --- ## Najważniejsze wnioski 1. **EEPROM persistence** - Stara konfiguracja pozostaje po flash - trzeba migracyjna logika 2. **Diagnostyka** - Logi są niezbędne do debugowania - bez nich nie wiadomo co się dzieje 3. **Credentials w hardware** - Test device musi być seeded w bazie i znany w kodzie 4. **Network isolation** - ESP32 na innej sieci niż PC - utrudnia testowanie 5. **Hardcoded config** - URL serwera hardcoded - brak elastyczności --- ## Wygenerowano - Data: 9 maja 2026 - Firmware: freenove_esp32_s3_wroom - Test Device: SN001234ABCD56789012