forked from Akcelerometry_drgania_WMT/PI_mikrokontroler
355 lines
10 KiB
Markdown
355 lines
10 KiB
Markdown
# 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
|