Files
PI_mikrokontroler_2/SUMMARY_2026-05-09.md

10 KiB

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:

// 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():

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:

// 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():

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:
    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
    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
    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

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

    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

# pi_rest/init_db.py
device = Device(
    serial="SN001234ABCD56789012",
    password_hashed=bcrypt("device001"),
    log_type=1  # HTTP BASIC auth
)

Upload thread scheduling

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