From 66475edad4179b9219117c8776b79686ca7101c5 Mon Sep 17 00:00:00 2001 From: Victus Date: Sun, 10 May 2026 20:46:23 +0200 Subject: [PATCH] Dodanie Captive Portal z logarytmami --- include/ADXL345FreshSPI.h | 2 +- include/APIClient.h | 19 +++ include/Display.h | 19 ++- include/Measure.h | 8 +- include/Network.h | 34 ++--- include/Settings.h | 2 +- include/UploadManager.h | 31 ++++ include/Version.h | 2 +- src/ADXL345FastSPI.cpp | 9 +- src/APIClient.cpp | 124 +++++++++++++++ src/Config.cpp | 16 +- src/Display.cpp | 313 +++++++++++++++++++++++--------------- src/Measure.cpp | 14 +- src/Network.cpp | 239 ++++++++++++++++++----------- src/Settings.cpp | 6 +- src/UploadManager.cpp | 117 ++++++++++++++ src/main.cpp | 137 ++++++++++------- 17 files changed, 776 insertions(+), 316 deletions(-) create mode 100644 include/APIClient.h create mode 100644 include/UploadManager.h create mode 100644 src/APIClient.cpp create mode 100644 src/UploadManager.cpp diff --git a/include/ADXL345FreshSPI.h b/include/ADXL345FreshSPI.h index 9c0b34e..2cdad53 100644 --- a/include/ADXL345FreshSPI.h +++ b/include/ADXL345FreshSPI.h @@ -21,7 +21,7 @@ public: ADXL345FreshSPI() = default; - // --- Init (SPI only) --- + // --- Init (SPI) --- // Uwaga: ADXL345 wymaga SPI MODE3, zegar ≤ ~5 MHz. bool begin(SPIClass *spi, uint8_t csPin, uint32_t clockHz = 5000000); diff --git a/include/APIClient.h b/include/APIClient.h new file mode 100644 index 0000000..a0a2c2b --- /dev/null +++ b/include/APIClient.h @@ -0,0 +1,19 @@ +#ifndef APICLIENT_H +#define APICLIENT_H + +#include +#include +#include +#include +#include +#include "Config.h" +#include "Watchdog.h" + +class APIClient { +public: + APIClient(); + + bool uploadMeasurement(const String& filePath); +}; + +#endif diff --git a/include/Display.h b/include/Display.h index 8289bb6..62fb6ad 100644 --- a/include/Display.h +++ b/include/Display.h @@ -60,10 +60,6 @@ public: void setCursor(int16_t x, int16_t y); void showAccel(float a, float b, float c); void displayOnOffM(bool measure, String myDir, String myFile); - - // Metoda sterująca ikoną SSL (dodana do klasy) - void setSSLStatus(bool active); - void initMeasure( bool measure, // czy pomiar ciągły? bool run, // czy uruchomiony? @@ -78,9 +74,20 @@ public: private: LiquidCrystal_I2C *_lcd; RTC_DS3231 &rtc_; - uint8_t _address; uint8_t _columns; uint8_t _rows; + uint8_t _address; + + // Poprzednie + uint16_t oyear; + uint8_t omonth; + uint8_t oday; + uint8_t ohour; + uint8_t omin; + uint8_t osec; + float ospace; + uint8_t oadxlcnt; + bool omode; }; -#endif \ No newline at end of file +#endif diff --git a/include/Measure.h b/include/Measure.h index 6dbdce5..78490d6 100644 --- a/include/Measure.h +++ b/include/Measure.h @@ -17,8 +17,6 @@ static constexpr uint32_t SPI_HZ = 5000000; // 5 MHz (MODE3) static constexpr float ODR_HZ = 3200.0f; // maks. ODR // Zakres ustawiany w main.cpp przez ADXL345FastSPI::begin(..., RANGE_2G, ...) -//extern Display display; - struct FileInfo { String path; // np. "/3/00000057.wmt" uint64_t size; // bajty @@ -31,7 +29,7 @@ struct SpaceInfo { }; class DataCapture { - // --- Nagłówek pliku WMT (jak w oryginale) --- + // --- Nagłówek pliku WMT --- struct FileHeader { char magic[3]; // "WMT" uint16_t version; // 1 @@ -42,7 +40,7 @@ class DataCapture { } __attribute__((packed)); public: - // --- Rekord próbki (jak w oryginale) --- + // --- Rekord próbki --- struct Sample { uint32_t offset; // µs od startu akwizycji (wspólny dla ramki) uint8_t sensor_id; // 0..3 @@ -105,8 +103,6 @@ private: return ispress; } // szybkidigitalRead : czy BTN stop??? - - // Helpers (zachowane z Twojej wersji) public: bool isAllDigits(const char *s); uint32_t toUint(const char *s); diff --git a/include/Network.h b/include/Network.h index 74068e2..736b17e 100644 --- a/include/Network.h +++ b/include/Network.h @@ -9,13 +9,12 @@ #include #include #include + #include #elif defined(ESP8266) #include #include - #include + #include #endif - -#include // Dodano dla Captive Portal //#include //#include //#include @@ -28,11 +27,6 @@ #include // OTA -#include "Display.h" // Dodano dla obsługi komunikatów na LCD - -extern Config config; // Deklaracja zewnętrznej struktury config -extern ConfigManager configManager; // Deklaracja zewnętrznego managera (to naprawi błąd) - class WiFiManager { public: WiFiManager(); @@ -50,11 +44,11 @@ class WiFiManager { int rssiToPercent(int rssi); // rssi na procenty int8_t getRSSI(); - /** - * NOWA METODA: Portal konfiguracyjny (Captive Portal) - * Uruchamiany automatycznie przy braku połączenia. - */ - void startConfigPortal(Display &display); + void handleClient(); + void startCaptivePortal(); + void handleRoot(); + void handleSave(); + void handleNotFound(); /** * Aktualizacja systemu przez internet z adresu config.updateUrl. @@ -75,18 +69,10 @@ class WiFiManager { private: bool isAccessPoint = false; - - // Obiekty serwerów dla Portalu (ESP32/ESP8266) -#ifdef ESP32 + bool captivePortalActive = false; WebServer server{80}; -#elif defined(ESP8266) - ESP8266WebServer server{80}; -#endif DNSServer dnsServer; - void handleRoot(); - void handleSave(); + int expectedCaptchaAnswer = 0; }; -extern WiFiManager wifi; - -#endif // WIFIMANAGER_H \ No newline at end of file +#endif // WIFIMANAGER_H diff --git a/include/Settings.h b/include/Settings.h index d8711b8..0653c68 100644 --- a/include/Settings.h +++ b/include/Settings.h @@ -24,7 +24,7 @@ class Settings { // bool is1and3(); bool isBtnReset(); - + bool isSetClock(); bool readBtnUp() { return digitalRead(BTN_UP) == LOW; } bool readBtnOk() { return digitalRead(BTN_OK) == LOW; } bool readBtnDown() { return digitalRead(BTN_DOWN) == LOW; } diff --git a/include/UploadManager.h b/include/UploadManager.h new file mode 100644 index 0000000..db40a5b --- /dev/null +++ b/include/UploadManager.h @@ -0,0 +1,31 @@ +#ifndef UPLOADMANAGER_H +#define UPLOADMANAGER_H + +#include +#include +#include +#include "APIClient.h" +#include "RTClib.h" +#include "Measure.h" + +class UploadManager { +public: + UploadManager(APIClient& client, RTC_DS3231& rtc, DataCapture& capture); + + // Call this to upload a specific file immediately + void uploadFile(const String& filePath); + + // Call this in the background when WiFi is connected + void processPendingUploads(); + +private: + APIClient& apiClient; + RTC_DS3231& rtc_; + DataCapture& capture_; + + bool isAlreadyUploaded(const String& filePath); + void appendLog(const String& filePath, const String& status); + String getCurrentTimestamp(); +}; + +#endif diff --git a/include/Version.h b/include/Version.h index d4d6536..d06b09f 100644 --- a/include/Version.h +++ b/include/Version.h @@ -1,7 +1,7 @@ #ifndef VERSION_H #define VERSION_H -#define VERSION "1.3.2" +#define VERSION "1.3.4.1" // 1: graphical 128x64, 2: LCD I2C Text 4x20 #define LCD_TYPE 2 diff --git a/src/ADXL345FastSPI.cpp b/src/ADXL345FastSPI.cpp index 07efeb1..5cd48d1 100644 --- a/src/ADXL345FastSPI.cpp +++ b/src/ADXL345FastSPI.cpp @@ -1,4 +1,5 @@ #include "ADXL345FastSPI.h" +#include "Watchdog.h" static const char *TAG_FRESH = "ADXLFAST"; @@ -43,8 +44,14 @@ bool ADXL345FastSPI::availableAll() { uint8_t ADXL345FastSPI::readAlignedOnce(int16_t* x, int16_t* y, int16_t* z, uint32_t* ts_us){ // 1) Czekaj aż każdy ma ≥1 próbkę (DATA_READY => FIFO>0) + uint32_t start_wait = millis(); while (!availableAll()) { - // micro-spin; w razie potrzeby można dodać yield() / feed watchdog poza hot-path + if (millis() - start_wait > 100) { + ESP_LOGE(TAG_FRESH, "Timeout waiting for sensors data!"); + return 0; + } + Watchdog::feed(); + yield(); } // 2) Zdejmij najstarszą z każdego sensora diff --git a/src/APIClient.cpp b/src/APIClient.cpp new file mode 100644 index 0000000..a87d042 --- /dev/null +++ b/src/APIClient.cpp @@ -0,0 +1,124 @@ +#include "APIClient.h" +#include +#include + +static const char *TAG_API = "API"; + +APIClient::APIClient() {} + +bool APIClient::uploadMeasurement(const String &filePath) { + if (WiFi.status() != WL_CONNECTED) { + ESP_LOGE(TAG_API, "No WiFi connection."); + return false; + } + + File file = SD.open(filePath, FILE_READ); + if (!file) { + ESP_LOGE(TAG_API, "Failed to open file %s", filePath.c_str()); + return false; + } + + // Wyciągnij samą nazwę pliku (bez ścieżki) + String filename = filePath; + int slashIndex = filename.lastIndexOf('/'); + if (slashIndex >= 0) { + filename = filename.substring(slashIndex + 1); + } + + // multipart/form-data boundary + String boundary = "----ESP32WMTBoundary"; + String head = "--" + boundary + "\r\n" + + "Content-Disposition: form-data; name=\"file\"; filename=\"" + + filename + "\"\r\n" + + "Content-Type: application/octet-stream\r\n\r\n"; + String tail = "\r\n--" + boundary + "--\r\n"; + + size_t fileSize = file.size(); + size_t totalLength = head.length() + fileSize + tail.length(); + + // Połączenie z hostem + WiFiClient client; + String host = String(config.restURL); + int port = config.restPort; + + // Usuń prefiks protokołu z hosta + host.replace("http://", ""); + host.replace("https://", ""); + + ESP_LOGI(TAG_API, "Connecting to %s:%d for upload", host.c_str(), port); + if (!client.connect(host.c_str(), port)) { + ESP_LOGE(TAG_API, "Connection failed to host %s:%d", host.c_str(), port); + file.close(); + return false; + } + + ESP_LOGI(TAG_API, "Uploading %s (%d bytes)", filePath.c_str(), fileSize); + + // --- HTTP Request --- + // Endpoint wg dokumentacji API IoT + client.println("POST /api/v1/measurements/measurements/upload HTTP/1.1"); + client.println("Host: " + host + ":" + String(port)); + + // Basic Auth: base64(serial:password) + String auth = String(config.restUser) + ":" + String(config.restPass); + String authBase64 = base64::encode(auth); + client.println("Authorization: Basic " + authBase64); + + client.println("Content-Length: " + String(totalLength)); + client.println("Content-Type: multipart/form-data; boundary=" + boundary); + client.println("Connection: close"); + client.println(); + + // Multipart body: head + file data + tail + client.print(head); + + uint8_t buffer[2048]; + while (file.available()) { + size_t len = file.read(buffer, sizeof(buffer)); + client.write(buffer, len); + Watchdog::feed(); + } + + client.print(tail); + file.close(); + + // --- Parsowanie odpowiedzi --- + int httpCode = 0; + String responseLine; + unsigned long timeout = millis(); + while (client.connected() && millis() - timeout < 15000) { + if (client.available()) { + responseLine = client.readStringUntil('\n'); + responseLine.trim(); + if (responseLine.startsWith("HTTP/1.1 ")) { + httpCode = responseLine.substring(9, 12).toInt(); + } + if (responseLine.length() == 0) + break; + } + Watchdog::feed(); + } + + String responseBody = ""; + while (client.available()) { + responseBody += client.readString(); + } + client.stop(); + + // --- Obsługa kodów odpowiedzi wg dokumentacji API --- + if (httpCode == 201) { + ESP_LOGI(TAG_API, "Upload successful: 201 Created"); + return true; + } else if (httpCode == 401) { + ESP_LOGE(TAG_API, "Unauthorized 401: Wrong serial or password!"); + } else if (httpCode == 403) { + ESP_LOGE(TAG_API, "Forbidden 403: Device not authorized or user tried upload."); + } else if (httpCode == 400) { + ESP_LOGE(TAG_API, "Bad Request 400: %s", responseBody.c_str()); + } else { + ESP_LOGE(TAG_API, "Upload failed with code %d. Response: %s", httpCode, + responseBody.c_str()); + } + + return false; +} diff --git a/src/Config.cpp b/src/Config.cpp index 7d56d82..f17182b 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -22,7 +22,7 @@ void ConfigManager::begin() { // Check is EEPROM is empty bool ConfigManager::isEEPROMEmpty() { - if (EEPROM.read(0) != 251){ + if (EEPROM.read(0) != 253){ ESP_LOGI(TAG_CONF, "EEPROM is new!"); return true; } else { @@ -40,7 +40,7 @@ void ConfigManager::readConfig() { void ConfigManager::saveConfig() { ESP_LOGI(TAG_CONF, "SAVE CONFIG"); EEPROM.put(1, config); - EEPROM.write(0, 251); + EEPROM.write(0, 253); if (EEPROM.commit()) { ESP_LOGI(TAG_CONF, "Config saved"); } else { @@ -77,15 +77,15 @@ void ConfigManager::resetToDefaults() { strcpy(config.user, "admin"); strcpy(config.pass, "admin"); strcpy(config.ntp, "pl.pool.ntp.org"); - config.connect = 0; // urządzenie połączone z siecią lub 0 offline + config.connect = 1; // urządzenie połączone z siecią lub 0 offline config.measure = 1; // włącz automatyczny pomiar co x sekunt (pause) config.duration = 5; // czas trwania pomiaru 5 sekund config.pause = 10000; // odstęp pomiędzy pomiarami w ms //strcpy(config.ntp, "0.pl.pool.ntp.org"); - strcpy(config.restURL, "http://62.93.60.19/accels/api1"); - config.restPort = 8000; - strcpy(config.restUser, "wmt"); - strcpy(config.restPass, "Zaq12wsx"); + strcpy(config.restURL, "http://62.93.60.19"); + config.restPort = 5004; + strcpy(config.restUser, "SN001234ABCD56789012"); + strcpy(config.restPass, "device001"); strcpy(config.S0, "ACCEL1"); strcpy(config.S1, "ACCEL2"); strcpy(config.S2, "ACCEL3"); @@ -95,7 +95,7 @@ void ConfigManager::resetToDefaults() { strcpy(config.S6, "ACCEL7"); strcpy(config.S7, "ACCEL8"); EEPROM.put(1, config); - EEPROM.write(0, 251); + EEPROM.write(0, 253); saveConfig(); readConfig(); isRebootRequired = true; diff --git a/src/Display.cpp b/src/Display.cpp index 597b154..c6ce2de 100644 --- a/src/Display.cpp +++ b/src/Display.cpp @@ -3,9 +3,6 @@ static const char *DISP = "display"; -// Flaga informująca o aktywnym trybie SSL -static bool _sslActive = false; - Display::Display(RTC_DS3231 &rtc, uint8_t address, uint8_t columns, uint8_t rows):rtc_(rtc) { _lcd = new LiquidCrystal_I2C(address, columns, rows); _address = address; @@ -28,9 +25,6 @@ bool Display::begin(TwoWire *wire) { return true; } -void Display::setSSLStatus(bool active) { - _sslActive = active; -} void Display::initMeasure(bool measure, bool run, bool runmes, uint16_t pause, uint8_t duration, bool connect, long counter, String gdate, String gtime) { @@ -43,54 +37,97 @@ void Display::initMeasure(bool measure, bool run, bool runmes, uint16_t pause, u String type = "Sample:" + String(duration) + "s Pause:" + String(pause/1000)+"s"; textCenter(2, type.c_str()); textCenter(3, String("Time:" + gtime).c_str()); -} - -void Display::welcomeScreen() { - _lcd->clear(); - _lcd->setCursor(0, 0); - _lcd->print(" VICTUS SYSTEM "); - _lcd->setCursor(0, 1); - _lcd->print(" VIBRATION LOGGER "); - _lcd->setCursor(0, 2); - _lcd->print(" V " + String(VERSION) + " "); - _lcd->setCursor(0, 3); - _lcd->print("WMT Stalowa Wola '25"); -} - -void Display::clearRow(uint16_t line) { - _lcd->setCursor(0, line); - for (int i = 0; i < _columns; i++) { - _lcd->print(" "); - } -} - -void Display::textCenter(uint8_t line, const char *txt) { - int len = strlen(txt); - int pos = (_columns - len) / 2; - if (pos < 0) pos = 0; - _lcd->setCursor(pos, line); - _lcd->print(txt); -} - -void Display::text(uint8_t line, const char *text) { - _lcd->setCursor(0, line); - _lcd->print(text); -} - -void Display::textStatus(const char *text) { - clearRow(3); - _lcd->setCursor(0, 3); - _lcd->print(text); + textStatus("initialisation"); } void Display::clear() { - _lcd->clear(); + _lcd->clear(); } -void Display::mainScreen() { - // Twoja logika mainScreen - _lcd->clear(); - textCenter(1, "MAIN SCREEN"); +void Display::textCenter(uint8_t line, const char *txt){ + if (line >= _rows) { + ESP_LOGE(DISP, "Line >= max rows!"); + return; + } + _lcd->setCursor(0, line); + int len = strlen(txt); + if (len < _columns) { + int pad = (_columns - len) / 2; + for (int i = 0; i < pad; i++) { + _lcd->print(" "); + } + } + _lcd->print(txt); +} + +void Display::text(uint8_t line, const char *text) { + if (line >= _rows) { + ESP_LOGE(DISP, "Line >= max rows!"); + return; + } + _lcd->setCursor(0, line); + _lcd->print(text); +} + +void Display::welcomeScreen() { + ESP_LOGI(DISP, "Info screen"); + clear(); + textCenter(0, "** Vibra Dude **"); + textCenter(1, "WMT Stalowa Wola"); + String firm = String(VERSION); + firm.trim(); + textCenter(2, firm.c_str()); + //_lcd->print(VERSION); +} + +void Display::mainScreen(){ + ESP_LOGI(DISP, "Main screen"); + clear(); + textCenter(0, "** Vibra Dude **"); + textCenter(1, "WMT Stalowa Wola"); + //String firm = String(VERSION).trim(); + //textCenter(2, firm.c_str()); + //_lcd->print(VERSION); + ESP_LOGI(DISP, "Finish main screen"); +} + +void Display::clearRow(uint16_t line){ + _lcd->setCursor(0, line); + _lcd->print(" "); + _lcd->setCursor(0, line); +} + +void Display::textStatus(const char *text){ + clearRow(3); + _lcd->setCursor(0, 3); + _lcd->print(text); +} + + +void Display::updateNetwork(String ip, bool connected) { + // przykładowa prosta implementacja: + // clear(); + // text(0, connected ? "NET: OK" : "NET: OFF"); + // _lcd->setCursor(0, 1); + // _lcd->print(ip); +} + +void Display::updateBarWiFi(long signal, bool connected) { + // tu możesz wykorzystać np. init_bargraph / draw_horizontal_graph + // (void)signal; + // (void)connected; +} + +void Display::textStyle(const uint8_t st, String text) { + // miejsce na różne style tekstu + //(void)st; +// clear(); + //text(0, text.c_str()); +} + +void Display::message(String text) { + // clear(); + //text(0, text.c_str()); } void Display::print(String text) { @@ -99,77 +136,96 @@ void Display::print(String text) { void Display::println(String text) { _lcd->print(text); + _lcd->print("\n"); } void Display::setCursor(int16_t x, int16_t y) { - _lcd->setCursor(x, y); -} - -void Display::updateNetwork(String ip, bool connected) { - _lcd->setCursor(0, 0); - if (connected) { - _lcd->print("IP:" + ip); - } else { - _lcd->print("IP: DISCONNECTED "); - } -} - -void Display::updateBarWiFi(long signal, bool connected) { - _lcd->setCursor(17, 0); - if (connected) { - if (signal > -60) _lcd->print("((("); - else if (signal > -80) _lcd->print(" (("); - else _lcd->print(" ("); - } else { - _lcd->print(" "); - } -} - -void Display::textStyle(const uint8_t st, String text) { - // Twoja implementacja stylów (np. bold/inwersja jeśli używasz) - _lcd->print(text); -} - -void Display::message(String text) { - clear(); - textCenter(1, text.c_str()); - delay(2000); + _lcd->setCursor((uint8_t)x, (uint8_t)y); } void Display::showAccel(float a, float b, float c) { - _lcd->setCursor(0, 1); - _lcd->print("X:"); _lcd->print(a, 2); - _lcd->setCursor(0, 2); - _lcd->print("Y:"); _lcd->print(b, 2); - _lcd->setCursor(0, 3); - _lcd->print("Z:"); _lcd->print(c, 2); + clear(); + // _lcd->setCursor(0, 0); + // _lcd->print("Ax: "); + // _lcd->print(a, 2); + // _lcd->setCursor(0, 1); + // _lcd->print("Ay: "); + // _lcd->print(b, 2); + // _lcd->setCursor(0, 2); + // _lcd->print("Az: "); + // _lcd->print(c, 2); } -void Display::displayOffline(bool measure, uint8_t count, float freeSpace, long licznik, bool refresh) { - static uint8_t oadxlcnt = 255; - static bool omode = false; - static long last_tick = 0; - - if (refresh) clear(); - - DateTime now = rtc_.now(); - char buf[21]; - snprintf(buf, sizeof(buf), "%02d:%02d:%02d %02d/%02d", now.hour(), now.minute(), now.second(), now.day(), now.month()); - _lcd->setCursor(0, 0); - _lcd->print(buf); - - // Znacznik SSL "S" - if (_sslActive) { - _lcd->setCursor(19, 0); - _lcd->print("S"); +void Display::displayOffline(bool measure, uint8_t count, float freeSpace, long licznik, bool refresh){ + if(refresh){ + oyear, omonth, oday, ohour, omin, osec, ospace, oadxlcnt = 100; + _lcd->clear(); + _lcd->setCursor(0, 0); } - _lcd->setCursor(0, 1); - _lcd->print("SD FREE: "); - _lcd->print(freeSpace, 2); - _lcd->print(" GB "); + DateTime now = rtc_.now(); + uint16_t year = now.year(); + uint8_t month = now.month(); + uint8_t day = now.day(); + uint8_t hour = now.hour(); + uint8_t min = now.minute(); + uint8_t sec = now.second(); - if ((oadxlcnt != count) || (omode != config.measure) || (refresh)){ + // DEBUG + //ESP_LOGI(DISP, "RTC: %d:%d:%d %d:%d:%d", now.day(), now.month(), now.year(), now.hour(), now.minute(), now.second()); + //ESP_LOGI(DISP, "RTC: %d:%d:%d %d:%d:%d", oday, omonth, oyear, ohour, omin, osec); + + if ((hour != ohour) || (refresh)) { + ohour = hour; + _lcd->setCursor(0, 0); + if (hour < 10) _lcd->print('0'); + _lcd->print(hour); + _lcd->setCursor(2, 0); + _lcd->print(':'); + } + + if ((min != omin) || (refresh)) { + omin = min; + _lcd->setCursor(3, 0); + if (min < 10) _lcd->print('0'); + _lcd->print(min); + _lcd->print(':'); + } + + if ((sec != osec) || (refresh)) { + _lcd->setCursor(6, 0); + osec = sec; + if (sec < 10) _lcd->print('0'); + _lcd->print(sec); + } + + if ((day != oday || month != omonth || year != oyear) || (refresh)){ + _lcd->setCursor(10, 0); + if (day < 10) _lcd->print('0'); + _lcd->print(day); + _lcd->print('.'); + if (month < 10) _lcd->print('0'); + _lcd->print(month); + _lcd->print('.'); + _lcd->print(year); + oday = day; + omonth = month; + oyear = year; + if(!config.measure) + textStatus("OK: Start MEASURE"); + else + textStatus("Wait for NEXT"); + } + + if((freeSpace != ospace) || (refresh)){ + ospace = freeSpace; + _lcd->setCursor(0, 1); + _lcd->print("FREE:"); + _lcd->print(freeSpace); + _lcd->print("GB"); + } + + if((count != oadxlcnt) || (omode != config.measure) || (refresh)){ oadxlcnt = count; omode = config.measure; _lcd->setCursor(0, 2); @@ -178,25 +234,24 @@ void Display::displayOffline(bool measure, uint8_t count, float freeSpace, long _lcd->print(" MODE:"); _lcd->print(config.measure ? "AUTO ":"MANUAL "); } - - if (millis() - last_tick > 1000) { - last_tick = millis(); - _lcd->setCursor(0, 3); - _lcd->print("SYSTEM READY "); - _lcd->print(licznik % 2 == 0 ? "*" : " "); - } } +// Podczas pomiaru void Display::displayOnOffM(bool measure, String myDir, String myFile) { clear(); _lcd->setCursor(0, 0); _lcd->print(measure ? "MEASURE STARTED" : "MEASURE STOPPED"); _lcd->setCursor(0, 1); _lcd->print("DIR: " + myDir); + //_lcd->print(myDir); + //_lcd->setCursor(0, 2); + //_lcd->print("FILE:"); + //_lcd->setCursor(0, 3); _lcd->setCursor(0, 2); _lcd->print(myFile); } +/* Podsumowanie po pomiarze: ramki, sampling, etc. */ void Display::displaySampleRateSummary(uint32_t reccount, uint32_t captureSeconds, float khz, String filename){ clear(); _lcd->setCursor(0, 0); @@ -205,12 +260,20 @@ void Display::displaySampleRateSummary(uint32_t reccount, uint32_t captureSecond delay(1000); return; } - float fs = (float)reccount / (float)captureSeconds; - _lcd->print("DONE: " + filename); - _lcd->setCursor(0, 1); - _lcd->print("Recs: " + String(reccount)); - _lcd->setCursor(0, 2); - _lcd->print("Freq: " + String(fs, 1) + " Hz"); - _lcd->setCursor(0, 3); - _lcd->print("Target: " + String(khz, 1) + " kHz"); -} \ No newline at end of file + float fs = (float)reccount / (float)captureSeconds; // Hz (ramki/s) + float fs_kHz = fs / 1000.0f; + _lcd->setCursor(0,0); + _lcd->print("Frames:"); + _lcd->print((unsigned)reccount); + _lcd->setCursor(0,1); + _lcd->print("Time:"); + _lcd->print((unsigned)captureSeconds); + _lcd->print("s."); + _lcd->setCursor(0,2); + _lcd->print("Rate:"); + _lcd->print(fs_kHz); + _lcd->print("kHz"); + + _lcd->setCursor(0,3); + _lcd->print(filename); +} diff --git a/src/Measure.cpp b/src/Measure.cpp index ff30751..42ef797 100644 --- a/src/Measure.cpp +++ b/src/Measure.cpp @@ -264,12 +264,22 @@ bool DataCapture::capture(uint32_t captureSeconds, const char *filename) { } // Czekamy na dane z sensora + uint32_t start_wait = millis(); while (!adxl_.availableAll()) { - if(isEscape()) break; + if (isEscape()) break; + if (millis() - start_wait > 500) { + ESP_LOGE(TAG_CAPTURE, "Sensor data timeout - aborting capture."); + measurementActive_ = false; + break; + } + Watchdog::feed(); + yield(); } + if (!measurementActive_) break; + const uint8_t got = adxl_.readAlignedOnce(X, Y, Z, TS); - if (got != presentCnt) continue; + if (got == 0 || got != presentCnt) continue; // Wspólny timestamp ramki uint32_t tmin = UINT32_MAX; diff --git a/src/Network.cpp b/src/Network.cpp index 01d06e4..9e07e3a 100644 --- a/src/Network.cpp +++ b/src/Network.cpp @@ -1,7 +1,8 @@ #include -#include "Watchdog.h" // Dodano dla feed() w portalu +#include static const char *WIFI = "wifi"; +extern ConfigManager configManager; WiFiManager::WiFiManager() {} @@ -19,62 +20,6 @@ void WiFiManager::begin() { setupMDNS(); } -// NOWA FUNKCJA: Portal konfiguracyjny (Captive Portal) -void WiFiManager::startConfigPortal(Display &display) { - WiFi.mode(WIFI_AP); - WiFi.softAP(ssidAP.c_str(), passwordAP.c_str()); - - dnsServer.start(53, "*", WiFi.softAPIP()); - - server.on("/", [this]() { this->handleRoot(); }); - server.on("/save", [this]() { this->handleSave(); }); - server.onNotFound([this]() { this->handleRoot(); }); - server.begin(); - - display.clear(); - display.textCenter(0, "WIFI SETUP MODE"); - display.textCenter(1, ssidAP.c_str()); - display.textCenter(2, "IP: 192.168.4.1"); - - ESP_LOGI(WIFI, "Portal started: %s", ssidAP.c_str()); - - while (true) { - dnsServer.processNextRequest(); - server.handleClient(); - Watchdog::feed(); // Użycie Twojego Watchdoga z Watchdog.h - delay(10); - // Pętla trwa do momentu restartu w handleSave() - } -} - -void WiFiManager::handleRoot() { - String html = ""; - html += ""; - html += "

VICTUS WMT

Konfiguracja WiFi:

"; - html += "
"; - html += "SSID:

"; - html += "Hasło:

"; - html += "
"; - server.send(200, "text/html", html); -} - -void WiFiManager::handleSave() { - String newSsid = server.arg("s"); - String newPass = server.arg("p"); - - if (newSsid.length() > 0) { - strncpy(config.ssid, newSsid.c_str(), sizeof(config.ssid)); - strncpy(config.password, newPass.c_str(), sizeof(config.password)); - configManager.saveConfig(); - - server.send(200, "text/html", "Zapisano dane. Restartuje..."); - ESP_LOGI(WIFI, "WiFi saved. Rebooting..."); - delay(2000); - ESP.restart(); - } -} - -// --- TWOJE ORYGINALNE FUNKCJE (ZACHOWANE W 100%) --- // Konwersja char na IPAddress bool WiFiManager::convertCharToIPAddress(const char *str, IPAddress& ip) { @@ -108,7 +53,7 @@ void WiFiManager::connectToWiFi() { } } - ESP_LOGI(WIFI, "WiFi connecting"); + ESP_LOGI(WIFI, "WiFi connecting to last SSID: %s", config.ssid); int retries = 0; while (WiFi.status() != WL_CONNECTED && retries < 20) { delay(500); @@ -116,6 +61,44 @@ void WiFiManager::connectToWiFi() { updateLED(); } + if (WiFi.status() != WL_CONNECTED) { + ESP_LOGI(WIFI, "Failed. Reading wifi.txt from SD card..."); + File f = SD.open("/wifi.txt"); + if (f) { + while (f.available()) { + String line = f.readStringUntil('\n'); + line.trim(); + if (line.isEmpty()) continue; + int sep = line.indexOf(';'); + if (sep > 0) { + String s = line.substring(0, sep); + String p = line.substring(sep + 1); + s.trim(); + p.trim(); + ESP_LOGI(WIFI, "Trying SSID from list: '%s'", s.c_str()); + WiFi.disconnect(); + WiFi.begin(s.c_str(), p.c_str()); + int tr = 0; + while (WiFi.status() != WL_CONNECTED && tr < 20) { + delay(500); + tr++; + updateLED(); + } + if (WiFi.status() == WL_CONNECTED) { + ESP_LOGI(WIFI, "Connected to %s. Saving to config.", s.c_str()); + strncpy(config.ssid, s.c_str(), sizeof(config.ssid)-1); + strncpy(config.password, p.c_str(), sizeof(config.password)-1); + configManager.saveConfig(); + break; + } + } + } + f.close(); + } else { + ESP_LOGW(WIFI, "wifi.txt not found on SD card."); + } + } + if (WiFi.status() == WL_CONNECTED) { ESP_LOGI(WIFI, "SSID: %s", config.ssid); String ipString = "IP: " + WiFi.localIP().toString(); @@ -125,7 +108,7 @@ void WiFiManager::connectToWiFi() { String dnsInfo = "DNS: " + WiFi.dnsIP().toString(); ESP_LOGI(WIFI, "%s", dnsInfo.c_str()); } else { - String infoWiFi = "WIFI CONNECTION ERROR: " + String(config.ssid); + String infoWiFi = "WIFI CONNECTION ERROR: ALL FAILED"; ESP_LOGI(WIFI, "%s", infoWiFi.c_str()); } updateLED(); @@ -165,31 +148,31 @@ bool WiFiManager::isWiFiOK(){ void WiFiManager::checkWiFiConnection() { if (!isAccessPoint) { - getRSSI(); - if (WiFi.status() != WL_CONNECTED) { - String infoWiFi = "WiFi reconnecting: " + String(config.ssid); - ESP_LOGI(WIFI, "%s", infoWiFi.c_str()); - WiFi.reconnect(); - int retries = 0; - while (WiFi.status() != WL_CONNECTED && retries < 20) { - delay(500); - retries++; - updateLED(); - } - if (WiFi.status() == WL_CONNECTED) { - //String infoWiFi = "WiFi connected: " + String(config.ssid); - //ESP_LOGI(WIFI, "%s", infoWiFi.c_str()); - //String ipString = "IP: " + WiFi.localIP().toString(); - //ESP_LOGI(WIFI, "%s", ipString.c_str()); - getRSSI(); - setupMDNS(); - } else { - String infoWiFi = "WiFi reconnect error: " + String(config.ssid); - ESP_LOGI(WIFI, "%s", infoWiFi.c_str()); + getRSSI(); + if (WiFi.status() != WL_CONNECTED) { + String infoWiFi = "WiFi reconnecting: " + String(config.ssid); + ESP_LOGI(WIFI, "%s", infoWiFi.c_str()); + WiFi.reconnect(); + int retries = 0; + while (WiFi.status() != WL_CONNECTED && retries < 20) { + delay(500); + retries++; + updateLED(); + } + if (WiFi.status() == WL_CONNECTED) { + //String infoWiFi = "WiFi connected: " + String(config.ssid); + //ESP_LOGI(WIFI, "%s", infoWiFi.c_str()); + //String ipString = "IP: " + WiFi.localIP().toString(); + //ESP_LOGI(WIFI, "%s", ipString.c_str()); getRSSI(); - } - } - updateLED(); + setupMDNS(); + } else { + String infoWiFi = "WiFi reconnect error: " + String(config.ssid); + ESP_LOGI(WIFI, "%s", infoWiFi.c_str()); + getRSSI(); + } + } + updateLED(); } } @@ -260,7 +243,7 @@ bool WiFiManager::performOTAUpdate(bool allowInsecureTLS, std::function"; + html += ""; + html += "

WiFi Configuration

"; + html += "
"; + html += "
"; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += ""; + html += "
"; + + server.send(200, "text/html", html); +} + +void WiFiManager::handleSave() { + String ssid = server.arg("ssid"); + String pass = server.arg("password"); + String captchaStr = server.arg("captcha"); + + if (captchaStr.toInt() != expectedCaptchaAnswer) { + server.send(400, "text/plain", "Incorrect Captcha. Please go back and try again."); + return; + } + + if (ssid.length() > 0) { + File f = SD.open("/wifi.txt", FILE_APPEND); + if (f) { + f.println(ssid + ";" + pass); + f.close(); + server.send(200, "text/plain", "Credentials saved successfully! The device will now restart and try to connect."); + delay(2000); + ESP.restart(); + } else { + server.send(500, "text/plain", "Failed to open wifi.txt on SD card for appending."); + } + } else { + server.send(400, "text/plain", "SSID cannot be empty."); + } +} + +void WiFiManager::handleNotFound() { + server.sendHeader("Location", String("http://") + WiFi.softAPIP().toString(), true); + server.send(302, "text/plain", ""); } \ No newline at end of file diff --git a/src/Settings.cpp b/src/Settings.cpp index c698f3c..82fc781 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -30,6 +30,10 @@ bool Settings::isBtnReset() { return (digitalRead(BTN_UP) == LOW && digitalRead(BTN_DOWN) == LOW); } +bool Settings::isSetClock() { + ESP_LOGI(TAG_SETTINGS, "BTN set clock"); + return (digitalRead(BTN_OK) == LOW); +} /* Ustawienie opcji @@ -141,7 +145,7 @@ int Settings::editField(int value, int minVal, int maxVal, const char *label) { lastDown = down; lastOk = ok; - delay(80); // prosty debounce + ograniczenie odpytywania + delay(80); //debouncing } } diff --git a/src/UploadManager.cpp b/src/UploadManager.cpp new file mode 100644 index 0000000..4a74d3b --- /dev/null +++ b/src/UploadManager.cpp @@ -0,0 +1,117 @@ +#include "UploadManager.h" +#include "Watchdog.h" + +static const char* TAG_UPLOAD = "UPLOAD"; +static const char* LOG_FILE = "/uploaded.csv"; + +UploadManager::UploadManager(APIClient& client, RTC_DS3231& rtc, DataCapture& capture) + : apiClient(client), rtc_(rtc), capture_(capture) {} + +String UploadManager::getCurrentTimestamp() { + DateTime now = rtc_.now(); + char buf[25]; + snprintf(buf, sizeof(buf), "%04u-%02u-%02u %02u:%02u:%02u", + now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second()); + return String(buf); +} + +void UploadManager::appendLog(const String& filePath, const String& status) { + File f = SD.open(LOG_FILE, FILE_APPEND); + if (f) { + f.printf("%s,%s,%s\n", getCurrentTimestamp().c_str(), filePath.c_str(), status.c_str()); + f.close(); + } +} + +bool UploadManager::isAlreadyUploaded(const String& filePath) { + File f = SD.open(LOG_FILE, FILE_READ); + if (!f) return false; + + bool found = false; + while (f.available()) { + String line = f.readStringUntil('\n'); + line.trim(); + if (line.length() == 0) continue; + + int firstComma = line.indexOf(','); + if (firstComma < 0) continue; + int secondComma = line.indexOf(',', firstComma + 1); + if (secondComma < 0) continue; + + String logPath = line.substring(firstComma + 1, secondComma); + String logStatus = line.substring(secondComma + 1); + + if (logPath == filePath) { + if (logStatus == "OK") found = true; + else found = false; // A retry might be needed if last status wasn't OK + } + Watchdog::feed(); + } + f.close(); + return found; +} + +void UploadManager::uploadFile(const String& filePath) { + if (isAlreadyUploaded(filePath)) { + ESP_LOGI(TAG_UPLOAD, "File %s is already uploaded.", filePath.c_str()); + return; + } + + if (WiFi.status() != WL_CONNECTED) { + ESP_LOGE(TAG_UPLOAD, "No WiFi. Cannot upload %s", filePath.c_str()); + appendLog(filePath, "ERROR: No WiFi"); + return; + } + + bool success = apiClient.uploadMeasurement(filePath); + if (success) { + appendLog(filePath, "OK"); + } else { + if (WiFi.status() != WL_CONNECTED) { + appendLog(filePath, "ERROR: WiFi lost during upload"); + } else { + appendLog(filePath, "ERROR: Upload Failed"); + } + } +} + +void UploadManager::processPendingUploads() { + if (WiFi.status() != WL_CONNECTED) return; + + ESP_LOGI(TAG_UPLOAD, "Checking for pending uploads..."); + uint32_t highestDir = capture_.findHighestNumericDir(); + if (highestDir == 0) return; + + for (uint32_t d = 1; d <= highestDir; d++) { + String path = capture_.dirPath(d); + File dir = SD.open(path); + if (!dir || !dir.isDirectory()) { + if(dir) dir.close(); + continue; + } + + for (File f = dir.openNextFile(); f; f = dir.openNextFile()) { + if (f.isDirectory()) { f.close(); continue; } + String childPath = String(f.name()); + if (!childPath.startsWith("/")) { + childPath = path + "/" + childPath; + } + + if (childPath.endsWith(".wmt")) { + if (!isAlreadyUploaded(childPath)) { + ESP_LOGI(TAG_UPLOAD, "Found pending file: %s", childPath.c_str()); + uploadFile(childPath); + delay(1000); + } + } + f.close(); + Watchdog::feed(); + if (WiFi.status() != WL_CONNECTED) { + dir.close(); + return; + } + } + dir.close(); + } + ESP_LOGI(TAG_UPLOAD, "Pending uploads check complete."); +} diff --git a/src/main.cpp b/src/main.cpp index 396c169..5d90aa2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,7 +15,8 @@ #include #include #include -#include // Dodano moduł wysyłki +#include "APIClient.h" +#include "UploadManager.h" #define WDT_TIMEOUT 60 // Czas watchdoga do restartu #define MAX_ADXL345_SENSORS 4 // Maksymalna ilość podłączanych sensorów @@ -23,7 +24,7 @@ SPIClass SPI_ADXL(FSPI); // SPI2 (VSPI) SPIClass SPI_SD(HSPI); // SPI3 (HSPI) -float x, y, z = 0; // Dane odczytane z akcelerometru +float x, y, z = 0; // Dane odczytane z akcelerometru String name; bool isRebootRequired = false; @@ -46,14 +47,13 @@ Settings settings(display, rtc); // obsługa przycisków WiFiManager wifi; DataCapture capture(adxl, display, rtc, SD, 8192); // NEW !!! MEASURE!!! - -// Inicjalizacja Uploadera -Uploader uploader(display); +APIClient apiClient; +UploadManager uploadManager(apiClient, rtc, capture); Thread wifiTestThread = Thread(); // Cykliczny test WiFi Thread offlineThread = Thread(); // Jeśli offline Thread measureThread = Thread(); // Pomiar i zapis na SD -Thread uploadThread = Thread(); // Wątek wysyłki SSL +Thread uploadThread = Thread(); // Background upload //////// PROTOTYPY ///////////////// void setup(); @@ -63,10 +63,7 @@ void resetBtnClick(); void checkWiFi(); void showOfflineScreen(); void measure(); -void runUploader(); -void toogleMode(); -void settingsDevice(); -void showError(String err); +void setClockRTCBtn(); /* ******************* SETUP() ************************* */ void setup() { @@ -84,8 +81,8 @@ void setup() { ESP_LOGI(TAG_MAIN, "Rejestrator parametrow"); ESP_LOGI(TAG_MAIN, "Firmware: %s", VERSION); ESP_LOGI(TAG_MAIN, "----------------------"); - ESP_LOGI(TAG_MAIN, "ESP32 model: %s Rev %d", ESP.getChipModel(), ESP.getChipRevision()); - ESP_LOGI(TAG_MAIN, "Chip cores: %d", ESP.getChipCores()); + ESP_LOGI(TAG_MAIN, "ESP32 model: %s Rev %d", ESP.getChipModel(), ESP.getChipRevision()); + ESP_LOGI(TAG_MAIN, "Chip cores: %d", ESP.getChipCores()); // Inicjalizacja Watchdoga na 5 sek, panic_on_trigger = true if (Watchdog::init(25, true)) { @@ -99,6 +96,8 @@ void setup() { configManager.begin(); // konfiguracja EEPROM urządzenia + //configManager.showConfig(); + // Test LCD I2C if (!isI2CDevPresent(0x27)) { ESP_LOGE(TAG_MAIN, "LCD 0x27 wire error!"); @@ -158,6 +157,10 @@ void setup() { settings.setTimeRTC(); } } + + // Przycisk ustawianai czasu: przytrzymaj OK przy starcie systemu + if(settings.isSetClock()) setClockRTCBtn(); + delay(500); // Karta SD @@ -165,7 +168,7 @@ void setup() { ESP_LOGI(TAG_MAIN, "SPI2 SD SCK: %d, MISO: %d, MOSI: %d, CS: %d", SD_SCK, SD_MISO, SD_MOSI, SD_CS); SPI_SD.begin(SD_SCK, SD_MISO, SD_MOSI); display.textStatus("SD CARD:"); - while(!SD.begin(SD_CS, SPI_SD, 4000000)) { + while(!SD.begin(SD_CS, SPI_SD, 4000000)) { // 10 MHz na start; w razie czego 4 MHz (bez tego często SD Failed) ESP_LOGE(TAG_MAIN, "SD mount failed"); display.print("FAILED"); delay(4000); @@ -181,7 +184,8 @@ void setup() { // Inicjalizacja ADXL345 ESP_LOGI(TAG_MAIN, "ADXL345 init"); display.textStatus("ADXL345: "); - if(!adxl.begin(&SPI_ADXL, 5000000, ADXL345FastSPI::RATE_3200HZ, ADXL345FastSPI::RANGE_16G, 1)){ + //if(!adxl.begin(&SPI_ADXL, 5000000, ADXL345FastSPI::RATE_3200HZ, ADXL345FastSPI::RANGE_16G, 1)){ + if(!adxl.begin(&SPI_ADXL, 2000000, ADXL345FastSPI::RATE_3200HZ, ADXL345FastSPI::RANGE_16G, 1)){ ESP_LOGE(TAG_MAIN, "ADXL345 Error"); display.print("FAILED"); isAccelExists = false; @@ -208,36 +212,23 @@ void setup() { delay(1000); if(config.connect){ - display.textStatus("WiFi Connect..."); wifi.begin(); - - int retry_count = 0; - while (WiFi.status() != WL_CONNECTED && retry_count < 60) { - delay(500); - retry_count++; - Watchdog::feed(); - if(retry_count % 10 == 0) display.print("."); - } - - if (WiFi.status() != WL_CONNECTED) { - ESP_LOGW(TAG_MAIN, "WiFi Failed. Starting Configuration Portal..."); - wifi.startConfigPortal(display); - } else { - ESP_LOGI(TAG_MAIN, "WiFi OK"); - wifiTestThread.onRun(checkWiFi); - wifiTestThread.setInterval(5000); - - uploadThread.onRun(runUploader); - uploadThread.setInterval(30000); - } + wifiTestThread.onRun(checkWiFi); + wifiTestThread.setInterval(5000); // Test WiFi co 3 sekundy } else { offlineThread.onRun(showOfflineScreen); - offlineThread.setInterval(1000); + offlineThread.setInterval(1000); // Jeśli offline, to wyświetl ekran co 1 sek } measureThread.onRun(measure); - measureThread.setInterval(config.pause); + measureThread.setInterval(config.pause); // Test co X sekund + if(config.connect){ + uploadThread.onRun([]() { uploadManager.processPendingUploads(); }); + uploadThread.setInterval(60000); // Co 1 minutę sprawdzaj zaległe + } + + // Dodanie taska loop do WDT if (Watchdog::addThisTask()) { ESP_LOGI(TAG_MAIN, "Added main task to Watchdog"); } @@ -246,14 +237,23 @@ void setup() { display.clear(); } -void runUploader() { - if (!testingNow) { - uploader.processQueue(3); - } -} +// Factory reset +void setClockRTCBtn(){ + ESP_LOGI(TAG_MAIN, "SET DATE TIME"); + while(settings.isSetClock()){ + display.clear(); + display.textCenter(0, " PLEASE "); + display.textCenter(1, "release key"); + display.textCenter(3, "TO SET DATE TIME"); + delay(500); + } + settings.setTimeRTC(); +} + +// Factory reset void resetBtnClick(){ - uint8_t counter = 10; + uint8_t counter = 10; // ile sekund trzymać przycisk na factory reset ESP_LOGI(TAG_MAIN, "RESET BTN to 10 sec."); while(settings.isBtnReset()){ Serial.print(counter); Serial.print(","); @@ -280,6 +280,8 @@ void resetBtnClick(){ } } +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void showError(String err){ Watchdog::feed(); display.clear(); @@ -288,6 +290,7 @@ void showError(String err){ delay(3000); } + void checkWiFi(){ Watchdog::feed(); bool isConnected = WiFi.isConnected(); @@ -297,6 +300,7 @@ void checkWiFi(){ display.updateNetwork(ip, isConnected); } +////// Ekran główny tylko gdy brak pomiaru ///////////// void showOfflineScreen(){ if((!config.connect) && (!testingNow)) { bool isGB; @@ -306,23 +310,26 @@ void showOfflineScreen(){ } } + void reboot() { display.clear(); display.textCenter(1, "SYSTEM"); display.textCenter(2, "RESTARTING"); #if defined(ARDUINO_RASPBERRY_PI_PICO) - watchdog_enable(1, 1); - while (true); + watchdog_enable(1, 1); // 1 ms timeout, restart po upływie + while (true); // czekaj na watchdog reset #endif #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) ESP_LOGI(TAG_MAIN, "RESTART"); - ESP.restart(); + ESP.restart(); // restart ESP #endif #if defined(ARDUINO_ARCH_STM32) - NVIC_SystemReset(); + NVIC_SystemReset(); // restartuj STM32 #endif } + +// pomiar z Thread START POMIARU TUTAJ void measure(){ Watchdog::feed(); testingNow = true; @@ -334,7 +341,7 @@ void measure(){ snprintf(btime, sizeof(btime), "%02d:%02d:%02d", now.hour(), now.minute(), now.second()); display.initMeasure(config.measure, testingNow, runMeasure, config.pause, config.duration, config.connect, licznik, bdate, btime); ESP_LOGI(TAG_MAIN, "MEASURE RUNNING"); - + //delay(1000); capture.captureAuto(config.duration, "/"); testingNow = false; Watchdog::feed(); @@ -344,14 +351,21 @@ void measure(){ ESP_LOGI(TAG_MAIN, "MEASURE FINISH"); } else { ESP_LOGI(TAG_MAIN, "MEASURE INTERRUPT"); + //runMeasure = false; } + + if (config.connect && WiFi.status() == WL_CONNECTED) { + ESP_LOGI(TAG_MAIN, "TRIGGER UPLOAD PENDING..."); + uploadManager.processPendingUploads(); + } + runMeasure = false; ESP_LOGI(TAG_MAIN, "DISPLAY Offline"); display.displayOffline(testingNow, adxl.connectedSensorsCount(), capture.freeSpaceFloat(), licznik, true); offlineThread.enabled = true; } -void toogleMode(){ +void toogleMode(){ // tryb ciągłego, pojedynczego pomiaru config.measure = !config.measure; configManager.saveConfig(); display.textStatus("Mode changed"); @@ -385,18 +399,30 @@ void loop() { if(settings.isPressed(3)) settingsDevice(); // DOWN if(settings.isPressed(1)) toogleMode(); // UP + if (settings.readBtnUp() && settings.readBtnDown()) { + ESP_LOGI(TAG_MAIN, "Manual AP Mode trigger"); + wifi.startCaptivePortal(); + display.clear(); + display.textCenter(1, "AP MODE"); + display.textCenter(2, "192.168.4.1"); + while(settings.readBtnUp() && settings.readBtnDown()) { + Watchdog::feed(); + delay(50); + } + } + if(testingNow) { if((runMeasure) && (settings.isPressed(2))){ runMeasure = false; display.textStatus("STOPPING. WAIT"); } - return; + return; // jeśli trwa akurat test, nic nie rób } if(wifiTestThread.shouldRun() && (config.connect)) wifiTestThread.run(); - if(uploadThread.shouldRun() && (config.connect)) + if(uploadThread.shouldRun() && config.connect) uploadThread.run(); if(offlineThread.shouldRun() && (!config.connect)){ @@ -423,11 +449,12 @@ void loop() { if (isRebootRequired) { ESP_LOGI(TAG_MAIN, "Reboot required"); Watchdog::feed(); - delay(1000); - reboot(); + delay(1000); + reboot(); } + wifi.handleClient(); Watchdog::feed(); - delay(20); + delay(20); // 100 licznik ++; -} \ No newline at end of file +}