forked from Akcelerometry_drgania_WMT/PI_mikrokontroler
Dodanie Captive Portal z logarytmami
This commit is contained in:
@@ -21,7 +21,7 @@ public:
|
|||||||
|
|
||||||
ADXL345FreshSPI() = default;
|
ADXL345FreshSPI() = default;
|
||||||
|
|
||||||
// --- Init (SPI only) ---
|
// --- Init (SPI) ---
|
||||||
// Uwaga: ADXL345 wymaga SPI MODE3, zegar ≤ ~5 MHz.
|
// Uwaga: ADXL345 wymaga SPI MODE3, zegar ≤ ~5 MHz.
|
||||||
bool begin(SPIClass *spi, uint8_t csPin, uint32_t clockHz = 5000000);
|
bool begin(SPIClass *spi, uint8_t csPin, uint32_t clockHz = 5000000);
|
||||||
|
|
||||||
|
|||||||
19
include/APIClient.h
Normal file
19
include/APIClient.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef APICLIENT_H
|
||||||
|
#define APICLIENT_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <WiFiClient.h>
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
#include <FS.h>
|
||||||
|
#include <SD.h>
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Watchdog.h"
|
||||||
|
|
||||||
|
class APIClient {
|
||||||
|
public:
|
||||||
|
APIClient();
|
||||||
|
|
||||||
|
bool uploadMeasurement(const String& filePath);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -60,10 +60,6 @@ public:
|
|||||||
void setCursor(int16_t x, int16_t y);
|
void setCursor(int16_t x, int16_t y);
|
||||||
void showAccel(float a, float b, float c);
|
void showAccel(float a, float b, float c);
|
||||||
void displayOnOffM(bool measure, String myDir, String myFile);
|
void displayOnOffM(bool measure, String myDir, String myFile);
|
||||||
|
|
||||||
// Metoda sterująca ikoną SSL (dodana do klasy)
|
|
||||||
void setSSLStatus(bool active);
|
|
||||||
|
|
||||||
void initMeasure(
|
void initMeasure(
|
||||||
bool measure, // czy pomiar ciągły?
|
bool measure, // czy pomiar ciągły?
|
||||||
bool run, // czy uruchomiony?
|
bool run, // czy uruchomiony?
|
||||||
@@ -78,9 +74,20 @@ public:
|
|||||||
private:
|
private:
|
||||||
LiquidCrystal_I2C *_lcd;
|
LiquidCrystal_I2C *_lcd;
|
||||||
RTC_DS3231 &rtc_;
|
RTC_DS3231 &rtc_;
|
||||||
uint8_t _address;
|
|
||||||
uint8_t _columns;
|
uint8_t _columns;
|
||||||
uint8_t _rows;
|
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
|
#endif
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ static constexpr uint32_t SPI_HZ = 5000000; // 5 MHz (MODE3)
|
|||||||
static constexpr float ODR_HZ = 3200.0f; // maks. ODR
|
static constexpr float ODR_HZ = 3200.0f; // maks. ODR
|
||||||
// Zakres ustawiany w main.cpp przez ADXL345FastSPI::begin(..., RANGE_2G, ...)
|
// Zakres ustawiany w main.cpp przez ADXL345FastSPI::begin(..., RANGE_2G, ...)
|
||||||
|
|
||||||
//extern Display display;
|
|
||||||
|
|
||||||
struct FileInfo {
|
struct FileInfo {
|
||||||
String path; // np. "/3/00000057.wmt"
|
String path; // np. "/3/00000057.wmt"
|
||||||
uint64_t size; // bajty
|
uint64_t size; // bajty
|
||||||
@@ -31,7 +29,7 @@ struct SpaceInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class DataCapture {
|
class DataCapture {
|
||||||
// --- Nagłówek pliku WMT (jak w oryginale) ---
|
// --- Nagłówek pliku WMT ---
|
||||||
struct FileHeader {
|
struct FileHeader {
|
||||||
char magic[3]; // "WMT"
|
char magic[3]; // "WMT"
|
||||||
uint16_t version; // 1
|
uint16_t version; // 1
|
||||||
@@ -42,7 +40,7 @@ class DataCapture {
|
|||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// --- Rekord próbki (jak w oryginale) ---
|
// --- Rekord próbki ---
|
||||||
struct Sample {
|
struct Sample {
|
||||||
uint32_t offset; // µs od startu akwizycji (wspólny dla ramki)
|
uint32_t offset; // µs od startu akwizycji (wspólny dla ramki)
|
||||||
uint8_t sensor_id; // 0..3
|
uint8_t sensor_id; // 0..3
|
||||||
@@ -105,8 +103,6 @@ private:
|
|||||||
return ispress;
|
return ispress;
|
||||||
} // szybkidigitalRead : czy BTN stop???
|
} // szybkidigitalRead : czy BTN stop???
|
||||||
|
|
||||||
|
|
||||||
// Helpers (zachowane z Twojej wersji)
|
|
||||||
public:
|
public:
|
||||||
bool isAllDigits(const char *s);
|
bool isAllDigits(const char *s);
|
||||||
uint32_t toUint(const char *s);
|
uint32_t toUint(const char *s);
|
||||||
|
|||||||
@@ -9,13 +9,12 @@
|
|||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <WebServer.h>
|
#include <WebServer.h>
|
||||||
#include <ESPmDNS.h>
|
#include <ESPmDNS.h>
|
||||||
|
#include <DNSServer.h>
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
#include <ESP8266mDNS.h>
|
#include <ESP8266mDNS.h>
|
||||||
#include <ESP8266WebServer.h>
|
#include <DNSServer.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <DNSServer.h> // Dodano dla Captive Portal
|
|
||||||
//#include <Pinout.h>
|
//#include <Pinout.h>
|
||||||
//#include <IPAddress.h>
|
//#include <IPAddress.h>
|
||||||
//#include <WiFiUdp.h>
|
//#include <WiFiUdp.h>
|
||||||
@@ -28,11 +27,6 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
// OTA
|
// 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 {
|
class WiFiManager {
|
||||||
public:
|
public:
|
||||||
WiFiManager();
|
WiFiManager();
|
||||||
@@ -50,11 +44,11 @@ class WiFiManager {
|
|||||||
int rssiToPercent(int rssi); // rssi na procenty
|
int rssiToPercent(int rssi); // rssi na procenty
|
||||||
int8_t getRSSI();
|
int8_t getRSSI();
|
||||||
|
|
||||||
/**
|
void handleClient();
|
||||||
* NOWA METODA: Portal konfiguracyjny (Captive Portal)
|
void startCaptivePortal();
|
||||||
* Uruchamiany automatycznie przy braku połączenia.
|
void handleRoot();
|
||||||
*/
|
void handleSave();
|
||||||
void startConfigPortal(Display &display);
|
void handleNotFound();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aktualizacja systemu przez internet z adresu config.updateUrl.
|
* Aktualizacja systemu przez internet z adresu config.updateUrl.
|
||||||
@@ -75,18 +69,10 @@ class WiFiManager {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool isAccessPoint = false;
|
bool isAccessPoint = false;
|
||||||
|
bool captivePortalActive = false;
|
||||||
// Obiekty serwerów dla Portalu (ESP32/ESP8266)
|
|
||||||
#ifdef ESP32
|
|
||||||
WebServer server{80};
|
WebServer server{80};
|
||||||
#elif defined(ESP8266)
|
|
||||||
ESP8266WebServer server{80};
|
|
||||||
#endif
|
|
||||||
DNSServer dnsServer;
|
DNSServer dnsServer;
|
||||||
void handleRoot();
|
int expectedCaptchaAnswer = 0;
|
||||||
void handleSave();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern WiFiManager wifi;
|
#endif // WIFIMANAGER_H
|
||||||
|
|
||||||
#endif // WIFIMANAGER_H
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class Settings {
|
|||||||
// bool is1and3();
|
// bool is1and3();
|
||||||
|
|
||||||
bool isBtnReset();
|
bool isBtnReset();
|
||||||
|
bool isSetClock();
|
||||||
bool readBtnUp() { return digitalRead(BTN_UP) == LOW; }
|
bool readBtnUp() { return digitalRead(BTN_UP) == LOW; }
|
||||||
bool readBtnOk() { return digitalRead(BTN_OK) == LOW; }
|
bool readBtnOk() { return digitalRead(BTN_OK) == LOW; }
|
||||||
bool readBtnDown() { return digitalRead(BTN_DOWN) == LOW; }
|
bool readBtnDown() { return digitalRead(BTN_DOWN) == LOW; }
|
||||||
|
|||||||
31
include/UploadManager.h
Normal file
31
include/UploadManager.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#ifndef UPLOADMANAGER_H
|
||||||
|
#define UPLOADMANAGER_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <FS.h>
|
||||||
|
#include <SD.h>
|
||||||
|
#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
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#ifndef VERSION_H
|
#ifndef VERSION_H
|
||||||
#define VERSION_H
|
#define VERSION_H
|
||||||
|
|
||||||
#define VERSION "1.3.2"
|
#define VERSION "1.3.4.1"
|
||||||
|
|
||||||
// 1: graphical 128x64, 2: LCD I2C Text 4x20
|
// 1: graphical 128x64, 2: LCD I2C Text 4x20
|
||||||
#define LCD_TYPE 2
|
#define LCD_TYPE 2
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "ADXL345FastSPI.h"
|
#include "ADXL345FastSPI.h"
|
||||||
|
#include "Watchdog.h"
|
||||||
|
|
||||||
static const char *TAG_FRESH = "ADXLFAST";
|
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){
|
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)
|
// 1) Czekaj aż każdy ma ≥1 próbkę (DATA_READY => FIFO>0)
|
||||||
|
uint32_t start_wait = millis();
|
||||||
while (!availableAll()) {
|
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
|
// 2) Zdejmij najstarszą z każdego sensora
|
||||||
|
|||||||
124
src/APIClient.cpp
Normal file
124
src/APIClient.cpp
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
#include "APIClient.h"
|
||||||
|
#include <WiFiClient.h>
|
||||||
|
#include <base64.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ void ConfigManager::begin() {
|
|||||||
|
|
||||||
// Check is EEPROM is empty
|
// Check is EEPROM is empty
|
||||||
bool ConfigManager::isEEPROMEmpty() {
|
bool ConfigManager::isEEPROMEmpty() {
|
||||||
if (EEPROM.read(0) != 251){
|
if (EEPROM.read(0) != 253){
|
||||||
ESP_LOGI(TAG_CONF, "EEPROM is new!");
|
ESP_LOGI(TAG_CONF, "EEPROM is new!");
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@@ -40,7 +40,7 @@ void ConfigManager::readConfig() {
|
|||||||
void ConfigManager::saveConfig() {
|
void ConfigManager::saveConfig() {
|
||||||
ESP_LOGI(TAG_CONF, "SAVE CONFIG");
|
ESP_LOGI(TAG_CONF, "SAVE CONFIG");
|
||||||
EEPROM.put(1, config);
|
EEPROM.put(1, config);
|
||||||
EEPROM.write(0, 251);
|
EEPROM.write(0, 253);
|
||||||
if (EEPROM.commit()) {
|
if (EEPROM.commit()) {
|
||||||
ESP_LOGI(TAG_CONF, "Config saved");
|
ESP_LOGI(TAG_CONF, "Config saved");
|
||||||
} else {
|
} else {
|
||||||
@@ -77,15 +77,15 @@ void ConfigManager::resetToDefaults() {
|
|||||||
strcpy(config.user, "admin");
|
strcpy(config.user, "admin");
|
||||||
strcpy(config.pass, "admin");
|
strcpy(config.pass, "admin");
|
||||||
strcpy(config.ntp, "pl.pool.ntp.org");
|
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.measure = 1; // włącz automatyczny pomiar co x sekunt (pause)
|
||||||
config.duration = 5; // czas trwania pomiaru 5 sekund
|
config.duration = 5; // czas trwania pomiaru 5 sekund
|
||||||
config.pause = 10000; // odstęp pomiędzy pomiarami w ms
|
config.pause = 10000; // odstęp pomiędzy pomiarami w ms
|
||||||
//strcpy(config.ntp, "0.pl.pool.ntp.org");
|
//strcpy(config.ntp, "0.pl.pool.ntp.org");
|
||||||
strcpy(config.restURL, "http://62.93.60.19/accels/api1");
|
strcpy(config.restURL, "http://62.93.60.19");
|
||||||
config.restPort = 8000;
|
config.restPort = 5004;
|
||||||
strcpy(config.restUser, "wmt");
|
strcpy(config.restUser, "SN001234ABCD56789012");
|
||||||
strcpy(config.restPass, "Zaq12wsx");
|
strcpy(config.restPass, "device001");
|
||||||
strcpy(config.S0, "ACCEL1");
|
strcpy(config.S0, "ACCEL1");
|
||||||
strcpy(config.S1, "ACCEL2");
|
strcpy(config.S1, "ACCEL2");
|
||||||
strcpy(config.S2, "ACCEL3");
|
strcpy(config.S2, "ACCEL3");
|
||||||
@@ -95,7 +95,7 @@ void ConfigManager::resetToDefaults() {
|
|||||||
strcpy(config.S6, "ACCEL7");
|
strcpy(config.S6, "ACCEL7");
|
||||||
strcpy(config.S7, "ACCEL8");
|
strcpy(config.S7, "ACCEL8");
|
||||||
EEPROM.put(1, config);
|
EEPROM.put(1, config);
|
||||||
EEPROM.write(0, 251);
|
EEPROM.write(0, 253);
|
||||||
saveConfig();
|
saveConfig();
|
||||||
readConfig();
|
readConfig();
|
||||||
isRebootRequired = true;
|
isRebootRequired = true;
|
||||||
|
|||||||
313
src/Display.cpp
313
src/Display.cpp
@@ -3,9 +3,6 @@
|
|||||||
|
|
||||||
static const char *DISP = "display";
|
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) {
|
Display::Display(RTC_DS3231 &rtc, uint8_t address, uint8_t columns, uint8_t rows):rtc_(rtc) {
|
||||||
_lcd = new LiquidCrystal_I2C(address, columns, rows);
|
_lcd = new LiquidCrystal_I2C(address, columns, rows);
|
||||||
_address = address;
|
_address = address;
|
||||||
@@ -28,9 +25,6 @@ bool Display::begin(TwoWire *wire) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::setSSLStatus(bool active) {
|
|
||||||
_sslActive = active;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Display::initMeasure(bool measure, bool run, bool runmes, uint16_t pause, uint8_t duration,
|
void Display::initMeasure(bool measure, bool run, bool runmes, uint16_t pause, uint8_t duration,
|
||||||
bool connect, long counter, String gdate, String gtime) {
|
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";
|
String type = "Sample:" + String(duration) + "s Pause:" + String(pause/1000)+"s";
|
||||||
textCenter(2, type.c_str());
|
textCenter(2, type.c_str());
|
||||||
textCenter(3, String("Time:" + gtime).c_str());
|
textCenter(3, String("Time:" + gtime).c_str());
|
||||||
}
|
textStatus("initialisation");
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::clear() {
|
void Display::clear() {
|
||||||
_lcd->clear();
|
_lcd->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::mainScreen() {
|
void Display::textCenter(uint8_t line, const char *txt){
|
||||||
// Twoja logika mainScreen
|
if (line >= _rows) {
|
||||||
_lcd->clear();
|
ESP_LOGE(DISP, "Line >= max rows!");
|
||||||
textCenter(1, "MAIN SCREEN");
|
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) {
|
void Display::print(String text) {
|
||||||
@@ -99,77 +136,96 @@ void Display::print(String text) {
|
|||||||
|
|
||||||
void Display::println(String text) {
|
void Display::println(String text) {
|
||||||
_lcd->print(text);
|
_lcd->print(text);
|
||||||
|
_lcd->print("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::setCursor(int16_t x, int16_t y) {
|
void Display::setCursor(int16_t x, int16_t y) {
|
||||||
_lcd->setCursor(x, y);
|
_lcd->setCursor((uint8_t)x, (uint8_t)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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::showAccel(float a, float b, float c) {
|
void Display::showAccel(float a, float b, float c) {
|
||||||
_lcd->setCursor(0, 1);
|
clear();
|
||||||
_lcd->print("X:"); _lcd->print(a, 2);
|
// _lcd->setCursor(0, 0);
|
||||||
_lcd->setCursor(0, 2);
|
// _lcd->print("Ax: ");
|
||||||
_lcd->print("Y:"); _lcd->print(b, 2);
|
// _lcd->print(a, 2);
|
||||||
_lcd->setCursor(0, 3);
|
// _lcd->setCursor(0, 1);
|
||||||
_lcd->print("Z:"); _lcd->print(c, 2);
|
// _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) {
|
void Display::displayOffline(bool measure, uint8_t count, float freeSpace, long licznik, bool refresh){
|
||||||
static uint8_t oadxlcnt = 255;
|
if(refresh){
|
||||||
static bool omode = false;
|
oyear, omonth, oday, ohour, omin, osec, ospace, oadxlcnt = 100;
|
||||||
static long last_tick = 0;
|
_lcd->clear();
|
||||||
|
_lcd->setCursor(0, 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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_lcd->setCursor(0, 1);
|
DateTime now = rtc_.now();
|
||||||
_lcd->print("SD FREE: ");
|
uint16_t year = now.year();
|
||||||
_lcd->print(freeSpace, 2);
|
uint8_t month = now.month();
|
||||||
_lcd->print(" GB ");
|
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;
|
oadxlcnt = count;
|
||||||
omode = config.measure;
|
omode = config.measure;
|
||||||
_lcd->setCursor(0, 2);
|
_lcd->setCursor(0, 2);
|
||||||
@@ -178,25 +234,24 @@ void Display::displayOffline(bool measure, uint8_t count, float freeSpace, long
|
|||||||
_lcd->print(" MODE:");
|
_lcd->print(" MODE:");
|
||||||
_lcd->print(config.measure ? "AUTO ":"MANUAL ");
|
_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) {
|
void Display::displayOnOffM(bool measure, String myDir, String myFile) {
|
||||||
clear();
|
clear();
|
||||||
_lcd->setCursor(0, 0);
|
_lcd->setCursor(0, 0);
|
||||||
_lcd->print(measure ? "MEASURE STARTED" : "MEASURE STOPPED");
|
_lcd->print(measure ? "MEASURE STARTED" : "MEASURE STOPPED");
|
||||||
_lcd->setCursor(0, 1);
|
_lcd->setCursor(0, 1);
|
||||||
_lcd->print("DIR: " + myDir);
|
_lcd->print("DIR: " + myDir);
|
||||||
|
//_lcd->print(myDir);
|
||||||
|
//_lcd->setCursor(0, 2);
|
||||||
|
//_lcd->print("FILE:");
|
||||||
|
//_lcd->setCursor(0, 3);
|
||||||
_lcd->setCursor(0, 2);
|
_lcd->setCursor(0, 2);
|
||||||
_lcd->print(myFile);
|
_lcd->print(myFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Podsumowanie po pomiarze: ramki, sampling, etc. */
|
||||||
void Display::displaySampleRateSummary(uint32_t reccount, uint32_t captureSeconds, float khz, String filename){
|
void Display::displaySampleRateSummary(uint32_t reccount, uint32_t captureSeconds, float khz, String filename){
|
||||||
clear();
|
clear();
|
||||||
_lcd->setCursor(0, 0);
|
_lcd->setCursor(0, 0);
|
||||||
@@ -205,12 +260,20 @@ void Display::displaySampleRateSummary(uint32_t reccount, uint32_t captureSecond
|
|||||||
delay(1000);
|
delay(1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float fs = (float)reccount / (float)captureSeconds;
|
float fs = (float)reccount / (float)captureSeconds; // Hz (ramki/s)
|
||||||
_lcd->print("DONE: " + filename);
|
float fs_kHz = fs / 1000.0f;
|
||||||
_lcd->setCursor(0, 1);
|
_lcd->setCursor(0,0);
|
||||||
_lcd->print("Recs: " + String(reccount));
|
_lcd->print("Frames:");
|
||||||
_lcd->setCursor(0, 2);
|
_lcd->print((unsigned)reccount);
|
||||||
_lcd->print("Freq: " + String(fs, 1) + " Hz");
|
_lcd->setCursor(0,1);
|
||||||
_lcd->setCursor(0, 3);
|
_lcd->print("Time:");
|
||||||
_lcd->print("Target: " + String(khz, 1) + " kHz");
|
_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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -264,12 +264,22 @@ bool DataCapture::capture(uint32_t captureSeconds, const char *filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Czekamy na dane z sensora
|
// Czekamy na dane z sensora
|
||||||
|
uint32_t start_wait = millis();
|
||||||
while (!adxl_.availableAll()) {
|
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);
|
const uint8_t got = adxl_.readAlignedOnce(X, Y, Z, TS);
|
||||||
if (got != presentCnt) continue;
|
if (got == 0 || got != presentCnt) continue;
|
||||||
|
|
||||||
// Wspólny timestamp ramki
|
// Wspólny timestamp ramki
|
||||||
uint32_t tmin = UINT32_MAX;
|
uint32_t tmin = UINT32_MAX;
|
||||||
|
|||||||
239
src/Network.cpp
239
src/Network.cpp
@@ -1,7 +1,8 @@
|
|||||||
#include <Network.h>
|
#include <Network.h>
|
||||||
#include "Watchdog.h" // Dodano dla feed() w portalu
|
#include <SD.h>
|
||||||
|
|
||||||
static const char *WIFI = "wifi";
|
static const char *WIFI = "wifi";
|
||||||
|
extern ConfigManager configManager;
|
||||||
|
|
||||||
WiFiManager::WiFiManager() {}
|
WiFiManager::WiFiManager() {}
|
||||||
|
|
||||||
@@ -19,62 +20,6 @@ void WiFiManager::begin() {
|
|||||||
setupMDNS();
|
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><head><meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1'>";
|
|
||||||
html += "<style>body{font-family:sans-serif;background:#f0f0f0;padding:20px;}input{width:100%;padding:10px;margin:10px 0;}</style></head>";
|
|
||||||
html += "<body><h1>VICTUS WMT</h1><p>Konfiguracja WiFi:</p>";
|
|
||||||
html += "<form action='/save' method='POST'>";
|
|
||||||
html += "SSID:<br><input type='text' name='s' value='" + String(config.ssid) + "'><br>";
|
|
||||||
html += "Hasło:<br><input type='password' name='p'><br>";
|
|
||||||
html += "<input type='submit' value='Zapisz i Restartuj'></form></body></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
|
// Konwersja char na IPAddress
|
||||||
bool WiFiManager::convertCharToIPAddress(const char *str, IPAddress& ip) {
|
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;
|
int retries = 0;
|
||||||
while (WiFi.status() != WL_CONNECTED && retries < 20) {
|
while (WiFi.status() != WL_CONNECTED && retries < 20) {
|
||||||
delay(500);
|
delay(500);
|
||||||
@@ -116,6 +61,44 @@ void WiFiManager::connectToWiFi() {
|
|||||||
updateLED();
|
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) {
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
ESP_LOGI(WIFI, "SSID: %s", config.ssid);
|
ESP_LOGI(WIFI, "SSID: %s", config.ssid);
|
||||||
String ipString = "IP: " + WiFi.localIP().toString();
|
String ipString = "IP: " + WiFi.localIP().toString();
|
||||||
@@ -125,7 +108,7 @@ void WiFiManager::connectToWiFi() {
|
|||||||
String dnsInfo = "DNS: " + WiFi.dnsIP().toString();
|
String dnsInfo = "DNS: " + WiFi.dnsIP().toString();
|
||||||
ESP_LOGI(WIFI, "%s", dnsInfo.c_str());
|
ESP_LOGI(WIFI, "%s", dnsInfo.c_str());
|
||||||
} else {
|
} else {
|
||||||
String infoWiFi = "WIFI CONNECTION ERROR: " + String(config.ssid);
|
String infoWiFi = "WIFI CONNECTION ERROR: ALL FAILED";
|
||||||
ESP_LOGI(WIFI, "%s", infoWiFi.c_str());
|
ESP_LOGI(WIFI, "%s", infoWiFi.c_str());
|
||||||
}
|
}
|
||||||
updateLED();
|
updateLED();
|
||||||
@@ -165,31 +148,31 @@ bool WiFiManager::isWiFiOK(){
|
|||||||
|
|
||||||
void WiFiManager::checkWiFiConnection() {
|
void WiFiManager::checkWiFiConnection() {
|
||||||
if (!isAccessPoint) {
|
if (!isAccessPoint) {
|
||||||
getRSSI();
|
getRSSI();
|
||||||
if (WiFi.status() != WL_CONNECTED) {
|
if (WiFi.status() != WL_CONNECTED) {
|
||||||
String infoWiFi = "WiFi reconnecting: " + String(config.ssid);
|
String infoWiFi = "WiFi reconnecting: " + String(config.ssid);
|
||||||
ESP_LOGI(WIFI, "%s", infoWiFi.c_str());
|
ESP_LOGI(WIFI, "%s", infoWiFi.c_str());
|
||||||
WiFi.reconnect();
|
WiFi.reconnect();
|
||||||
int retries = 0;
|
int retries = 0;
|
||||||
while (WiFi.status() != WL_CONNECTED && retries < 20) {
|
while (WiFi.status() != WL_CONNECTED && retries < 20) {
|
||||||
delay(500);
|
delay(500);
|
||||||
retries++;
|
retries++;
|
||||||
updateLED();
|
updateLED();
|
||||||
}
|
}
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
//String infoWiFi = "WiFi connected: " + String(config.ssid);
|
//String infoWiFi = "WiFi connected: " + String(config.ssid);
|
||||||
//ESP_LOGI(WIFI, "%s", infoWiFi.c_str());
|
//ESP_LOGI(WIFI, "%s", infoWiFi.c_str());
|
||||||
//String ipString = "IP: " + WiFi.localIP().toString();
|
//String ipString = "IP: " + WiFi.localIP().toString();
|
||||||
//ESP_LOGI(WIFI, "%s", ipString.c_str());
|
//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();
|
getRSSI();
|
||||||
}
|
setupMDNS();
|
||||||
}
|
} else {
|
||||||
updateLED();
|
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<void(int
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4) Konfiguracja klienta i wywołanie aktualizacji
|
// 4) Konfiguracja klienta i wywołanie aktualizacji
|
||||||
httpUpdate.rebootOnUpdate(true); // po sukcesie – reboot
|
httpUpdate.rebootOnUpdate(true); // po sukcesie – reboot
|
||||||
t_httpUpdate_return ret;
|
t_httpUpdate_return ret;
|
||||||
|
|
||||||
if (url.startsWith("https://")) {
|
if (url.startsWith("https://")) {
|
||||||
@@ -279,7 +262,7 @@ bool WiFiManager::performOTAUpdate(bool allowInsecureTLS, std::function<void(int
|
|||||||
// 5) Obsługa rezultatów
|
// 5) Obsługa rezultatów
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case HTTP_UPDATE_OK:
|
case HTTP_UPDATE_OK:
|
||||||
ESP_LOGI(WIFI, "[OTA] Sukces - restart nastąpi za chwilę.");
|
ESP_LOGI(WIFI, "[OTA] Sukces – restart nastąpi za chwilę.");
|
||||||
return true; // reboot i tak zaraz nastąpi
|
return true; // reboot i tak zaraz nastąpi
|
||||||
case HTTP_UPDATE_NO_UPDATES:
|
case HTTP_UPDATE_NO_UPDATES:
|
||||||
ESP_LOGW(WIFI, "[OTA] Brak nowej wersji (304/Not Modified).");
|
ESP_LOGW(WIFI, "[OTA] Brak nowej wersji (304/Not Modified).");
|
||||||
@@ -289,4 +272,90 @@ bool WiFiManager::performOTAUpdate(bool allowInsecureTLS, std::function<void(int
|
|||||||
ESP_LOGE(WIFI, "[OTA] Błąd (%d): %s", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str());
|
ESP_LOGE(WIFI, "[OTA] Błąd (%d): %s", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiManager::startCaptivePortal() {
|
||||||
|
ESP_LOGI(WIFI, "Starting Captive Portal");
|
||||||
|
setupAccessPoint(ssidAP.c_str(), passwordAP.c_str());
|
||||||
|
|
||||||
|
// Start DNS Server
|
||||||
|
const byte DNS_PORT = 53;
|
||||||
|
dnsServer.start(DNS_PORT, "*", WiFi.softAPIP());
|
||||||
|
|
||||||
|
// Start Web Server
|
||||||
|
server.on("/", std::bind(&WiFiManager::handleRoot, this));
|
||||||
|
server.on("/save", HTTP_POST, std::bind(&WiFiManager::handleSave, this));
|
||||||
|
server.onNotFound(std::bind(&WiFiManager::handleNotFound, this));
|
||||||
|
server.begin();
|
||||||
|
|
||||||
|
captivePortalActive = true;
|
||||||
|
ESP_LOGI(WIFI, "Captive Portal Started");
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiManager::handleClient() {
|
||||||
|
if (captivePortalActive) {
|
||||||
|
dnsServer.processNextRequest();
|
||||||
|
server.handleClient();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiFiManager::handleRoot() {
|
||||||
|
int bases[] = {2, 2, 2, 2, 3, 3, 10, 10};
|
||||||
|
int vals[] = {4, 8, 16, 32, 9, 27, 100, 1000};
|
||||||
|
int answers[] = {2, 3, 4, 5, 2, 3, 2, 3};
|
||||||
|
int idx = random(0, 8);
|
||||||
|
int base = bases[idx];
|
||||||
|
int val = vals[idx];
|
||||||
|
expectedCaptchaAnswer = answers[idx];
|
||||||
|
|
||||||
|
String html = "<!DOCTYPE html><html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";
|
||||||
|
html += "<style>body{font-family: Arial, sans-serif; text-align: center; margin:0; padding: 20px;}";
|
||||||
|
html += "input[type=text], input[type=password], input[type=number] {width: 100%; padding: 12px; margin: 8px 0; display: inline-block; border: 1px solid #ccc; box-sizing: border-box;}";
|
||||||
|
html += "input[type=submit] {background-color: #4CAF50; color: white; padding: 14px 20px; margin: 8px 0; border: none; cursor: pointer; width: 100%;}";
|
||||||
|
html += "input[type=submit]:hover {opacity: 0.8;}";
|
||||||
|
html += ".container {max-width: 400px; margin: auto; padding: 20px; border: 1px solid #ddd; border-radius: 5px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);}</style></head><body>";
|
||||||
|
html += "<h2>WiFi Configuration</h2>";
|
||||||
|
html += "<div class=\"container\">";
|
||||||
|
html += "<form action=\"/save\" method=\"POST\">";
|
||||||
|
html += "<label for=\"ssid\"><b>SSID</b></label>";
|
||||||
|
html += "<input type=\"text\" placeholder=\"Enter SSID\" name=\"ssid\" required>";
|
||||||
|
html += "<label for=\"password\"><b>Password</b></label>";
|
||||||
|
html += "<input type=\"password\" placeholder=\"Enter Password\" name=\"password\" required>";
|
||||||
|
html += "<label for=\"captcha\"><b>Captcha: What is log<sub>" + String(base) + "</sub>(" + String(val) + ")?</b></label>";
|
||||||
|
html += "<input type=\"number\" placeholder=\"Enter Answer\" name=\"captcha\" required>";
|
||||||
|
html += "<input type=\"submit\" value=\"Save and Restart\">";
|
||||||
|
html += "</form></div></body></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", "");
|
||||||
}
|
}
|
||||||
@@ -30,6 +30,10 @@ bool Settings::isBtnReset() {
|
|||||||
return (digitalRead(BTN_UP) == LOW && digitalRead(BTN_DOWN) == LOW);
|
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
|
Ustawienie opcji
|
||||||
@@ -141,7 +145,7 @@ int Settings::editField(int value, int minVal, int maxVal, const char *label) {
|
|||||||
lastDown = down;
|
lastDown = down;
|
||||||
lastOk = ok;
|
lastOk = ok;
|
||||||
|
|
||||||
delay(80); // prosty debounce + ograniczenie odpytywania
|
delay(80); //debouncing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
117
src/UploadManager.cpp
Normal file
117
src/UploadManager.cpp
Normal file
@@ -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.");
|
||||||
|
}
|
||||||
137
src/main.cpp
137
src/main.cpp
@@ -15,7 +15,8 @@
|
|||||||
#include <Measure.h>
|
#include <Measure.h>
|
||||||
#include <Tool.h>
|
#include <Tool.h>
|
||||||
#include <Settings.h>
|
#include <Settings.h>
|
||||||
#include <Uploader.h> // Dodano moduł wysyłki
|
#include "APIClient.h"
|
||||||
|
#include "UploadManager.h"
|
||||||
|
|
||||||
#define WDT_TIMEOUT 60 // Czas watchdoga do restartu
|
#define WDT_TIMEOUT 60 // Czas watchdoga do restartu
|
||||||
#define MAX_ADXL345_SENSORS 4 // Maksymalna ilość podłączanych sensorów
|
#define MAX_ADXL345_SENSORS 4 // Maksymalna ilość podłączanych sensorów
|
||||||
@@ -23,7 +24,7 @@
|
|||||||
SPIClass SPI_ADXL(FSPI); // SPI2 (VSPI)
|
SPIClass SPI_ADXL(FSPI); // SPI2 (VSPI)
|
||||||
SPIClass SPI_SD(HSPI); // SPI3 (HSPI)
|
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;
|
String name;
|
||||||
|
|
||||||
bool isRebootRequired = false;
|
bool isRebootRequired = false;
|
||||||
@@ -46,14 +47,13 @@ Settings settings(display, rtc); // obsługa przycisków
|
|||||||
WiFiManager wifi;
|
WiFiManager wifi;
|
||||||
|
|
||||||
DataCapture capture(adxl, display, rtc, SD, 8192); // NEW !!! MEASURE!!!
|
DataCapture capture(adxl, display, rtc, SD, 8192); // NEW !!! MEASURE!!!
|
||||||
|
APIClient apiClient;
|
||||||
// Inicjalizacja Uploadera
|
UploadManager uploadManager(apiClient, rtc, capture);
|
||||||
Uploader uploader(display);
|
|
||||||
|
|
||||||
Thread wifiTestThread = Thread(); // Cykliczny test WiFi
|
Thread wifiTestThread = Thread(); // Cykliczny test WiFi
|
||||||
Thread offlineThread = Thread(); // Jeśli offline
|
Thread offlineThread = Thread(); // Jeśli offline
|
||||||
Thread measureThread = Thread(); // Pomiar i zapis na SD
|
Thread measureThread = Thread(); // Pomiar i zapis na SD
|
||||||
Thread uploadThread = Thread(); // Wątek wysyłki SSL
|
Thread uploadThread = Thread(); // Background upload
|
||||||
|
|
||||||
//////// PROTOTYPY /////////////////
|
//////// PROTOTYPY /////////////////
|
||||||
void setup();
|
void setup();
|
||||||
@@ -63,10 +63,7 @@ void resetBtnClick();
|
|||||||
void checkWiFi();
|
void checkWiFi();
|
||||||
void showOfflineScreen();
|
void showOfflineScreen();
|
||||||
void measure();
|
void measure();
|
||||||
void runUploader();
|
void setClockRTCBtn();
|
||||||
void toogleMode();
|
|
||||||
void settingsDevice();
|
|
||||||
void showError(String err);
|
|
||||||
|
|
||||||
/* ******************* SETUP() ************************* */
|
/* ******************* SETUP() ************************* */
|
||||||
void setup() {
|
void setup() {
|
||||||
@@ -84,8 +81,8 @@ void setup() {
|
|||||||
ESP_LOGI(TAG_MAIN, "Rejestrator parametrow");
|
ESP_LOGI(TAG_MAIN, "Rejestrator parametrow");
|
||||||
ESP_LOGI(TAG_MAIN, "Firmware: %s", VERSION);
|
ESP_LOGI(TAG_MAIN, "Firmware: %s", VERSION);
|
||||||
ESP_LOGI(TAG_MAIN, "----------------------");
|
ESP_LOGI(TAG_MAIN, "----------------------");
|
||||||
ESP_LOGI(TAG_MAIN, "ESP32 model: %s Rev %d", ESP.getChipModel(), ESP.getChipRevision());
|
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, "Chip cores: %d", ESP.getChipCores());
|
||||||
|
|
||||||
// Inicjalizacja Watchdoga na 5 sek, panic_on_trigger = true
|
// Inicjalizacja Watchdoga na 5 sek, panic_on_trigger = true
|
||||||
if (Watchdog::init(25, true)) {
|
if (Watchdog::init(25, true)) {
|
||||||
@@ -99,6 +96,8 @@ void setup() {
|
|||||||
|
|
||||||
configManager.begin(); // konfiguracja EEPROM urządzenia
|
configManager.begin(); // konfiguracja EEPROM urządzenia
|
||||||
|
|
||||||
|
//configManager.showConfig();
|
||||||
|
|
||||||
// Test LCD I2C
|
// Test LCD I2C
|
||||||
if (!isI2CDevPresent(0x27)) {
|
if (!isI2CDevPresent(0x27)) {
|
||||||
ESP_LOGE(TAG_MAIN, "LCD 0x27 wire error!");
|
ESP_LOGE(TAG_MAIN, "LCD 0x27 wire error!");
|
||||||
@@ -158,6 +157,10 @@ void setup() {
|
|||||||
settings.setTimeRTC();
|
settings.setTimeRTC();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Przycisk ustawianai czasu: przytrzymaj OK przy starcie systemu
|
||||||
|
if(settings.isSetClock()) setClockRTCBtn();
|
||||||
|
|
||||||
delay(500);
|
delay(500);
|
||||||
|
|
||||||
// Karta SD
|
// 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);
|
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);
|
SPI_SD.begin(SD_SCK, SD_MISO, SD_MOSI);
|
||||||
display.textStatus("SD CARD:");
|
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");
|
ESP_LOGE(TAG_MAIN, "SD mount failed");
|
||||||
display.print("FAILED");
|
display.print("FAILED");
|
||||||
delay(4000);
|
delay(4000);
|
||||||
@@ -181,7 +184,8 @@ void setup() {
|
|||||||
// Inicjalizacja ADXL345
|
// Inicjalizacja ADXL345
|
||||||
ESP_LOGI(TAG_MAIN, "ADXL345 init");
|
ESP_LOGI(TAG_MAIN, "ADXL345 init");
|
||||||
display.textStatus("ADXL345: ");
|
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");
|
ESP_LOGE(TAG_MAIN, "ADXL345 Error");
|
||||||
display.print("FAILED");
|
display.print("FAILED");
|
||||||
isAccelExists = false;
|
isAccelExists = false;
|
||||||
@@ -208,36 +212,23 @@ void setup() {
|
|||||||
delay(1000);
|
delay(1000);
|
||||||
|
|
||||||
if(config.connect){
|
if(config.connect){
|
||||||
display.textStatus("WiFi Connect...");
|
|
||||||
wifi.begin();
|
wifi.begin();
|
||||||
|
wifiTestThread.onRun(checkWiFi);
|
||||||
int retry_count = 0;
|
wifiTestThread.setInterval(5000); // Test WiFi co 3 sekundy
|
||||||
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);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
offlineThread.onRun(showOfflineScreen);
|
offlineThread.onRun(showOfflineScreen);
|
||||||
offlineThread.setInterval(1000);
|
offlineThread.setInterval(1000); // Jeśli offline, to wyświetl ekran co 1 sek
|
||||||
}
|
}
|
||||||
|
|
||||||
measureThread.onRun(measure);
|
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()) {
|
if (Watchdog::addThisTask()) {
|
||||||
ESP_LOGI(TAG_MAIN, "Added main task to Watchdog");
|
ESP_LOGI(TAG_MAIN, "Added main task to Watchdog");
|
||||||
}
|
}
|
||||||
@@ -246,14 +237,23 @@ void setup() {
|
|||||||
display.clear();
|
display.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void runUploader() {
|
// Factory reset
|
||||||
if (!testingNow) {
|
void setClockRTCBtn(){
|
||||||
uploader.processQueue(3);
|
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(){
|
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.");
|
ESP_LOGI(TAG_MAIN, "RESET BTN to 10 sec.");
|
||||||
while(settings.isBtnReset()){
|
while(settings.isBtnReset()){
|
||||||
Serial.print(counter); Serial.print(",");
|
Serial.print(counter); Serial.print(",");
|
||||||
@@ -280,6 +280,8 @@ void resetBtnClick(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void showError(String err){
|
void showError(String err){
|
||||||
Watchdog::feed();
|
Watchdog::feed();
|
||||||
display.clear();
|
display.clear();
|
||||||
@@ -288,6 +290,7 @@ void showError(String err){
|
|||||||
delay(3000);
|
delay(3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void checkWiFi(){
|
void checkWiFi(){
|
||||||
Watchdog::feed();
|
Watchdog::feed();
|
||||||
bool isConnected = WiFi.isConnected();
|
bool isConnected = WiFi.isConnected();
|
||||||
@@ -297,6 +300,7 @@ void checkWiFi(){
|
|||||||
display.updateNetwork(ip, isConnected);
|
display.updateNetwork(ip, isConnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////// Ekran główny tylko gdy brak pomiaru /////////////
|
||||||
void showOfflineScreen(){
|
void showOfflineScreen(){
|
||||||
if((!config.connect) && (!testingNow)) {
|
if((!config.connect) && (!testingNow)) {
|
||||||
bool isGB;
|
bool isGB;
|
||||||
@@ -306,23 +310,26 @@ void showOfflineScreen(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void reboot() {
|
void reboot() {
|
||||||
display.clear();
|
display.clear();
|
||||||
display.textCenter(1, "SYSTEM");
|
display.textCenter(1, "SYSTEM");
|
||||||
display.textCenter(2, "RESTARTING");
|
display.textCenter(2, "RESTARTING");
|
||||||
#if defined(ARDUINO_RASPBERRY_PI_PICO)
|
#if defined(ARDUINO_RASPBERRY_PI_PICO)
|
||||||
watchdog_enable(1, 1);
|
watchdog_enable(1, 1); // 1 ms timeout, restart po upływie
|
||||||
while (true);
|
while (true); // czekaj na watchdog reset
|
||||||
#endif
|
#endif
|
||||||
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
||||||
ESP_LOGI(TAG_MAIN, "RESTART");
|
ESP_LOGI(TAG_MAIN, "RESTART");
|
||||||
ESP.restart();
|
ESP.restart(); // restart ESP
|
||||||
#endif
|
#endif
|
||||||
#if defined(ARDUINO_ARCH_STM32)
|
#if defined(ARDUINO_ARCH_STM32)
|
||||||
NVIC_SystemReset();
|
NVIC_SystemReset(); // restartuj STM32
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// pomiar z Thread START POMIARU TUTAJ
|
||||||
void measure(){
|
void measure(){
|
||||||
Watchdog::feed();
|
Watchdog::feed();
|
||||||
testingNow = true;
|
testingNow = true;
|
||||||
@@ -334,7 +341,7 @@ void measure(){
|
|||||||
snprintf(btime, sizeof(btime), "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
|
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);
|
display.initMeasure(config.measure, testingNow, runMeasure, config.pause, config.duration, config.connect, licznik, bdate, btime);
|
||||||
ESP_LOGI(TAG_MAIN, "MEASURE RUNNING");
|
ESP_LOGI(TAG_MAIN, "MEASURE RUNNING");
|
||||||
|
//delay(1000);
|
||||||
capture.captureAuto(config.duration, "/");
|
capture.captureAuto(config.duration, "/");
|
||||||
testingNow = false;
|
testingNow = false;
|
||||||
Watchdog::feed();
|
Watchdog::feed();
|
||||||
@@ -344,14 +351,21 @@ void measure(){
|
|||||||
ESP_LOGI(TAG_MAIN, "MEASURE FINISH");
|
ESP_LOGI(TAG_MAIN, "MEASURE FINISH");
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGI(TAG_MAIN, "MEASURE INTERRUPT");
|
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;
|
runMeasure = false;
|
||||||
ESP_LOGI(TAG_MAIN, "DISPLAY Offline");
|
ESP_LOGI(TAG_MAIN, "DISPLAY Offline");
|
||||||
display.displayOffline(testingNow, adxl.connectedSensorsCount(), capture.freeSpaceFloat(), licznik, true);
|
display.displayOffline(testingNow, adxl.connectedSensorsCount(), capture.freeSpaceFloat(), licznik, true);
|
||||||
offlineThread.enabled = true;
|
offlineThread.enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void toogleMode(){
|
void toogleMode(){ // tryb ciągłego, pojedynczego pomiaru
|
||||||
config.measure = !config.measure;
|
config.measure = !config.measure;
|
||||||
configManager.saveConfig();
|
configManager.saveConfig();
|
||||||
display.textStatus("Mode changed");
|
display.textStatus("Mode changed");
|
||||||
@@ -385,18 +399,30 @@ void loop() {
|
|||||||
if(settings.isPressed(3)) settingsDevice(); // DOWN
|
if(settings.isPressed(3)) settingsDevice(); // DOWN
|
||||||
if(settings.isPressed(1)) toogleMode(); // UP
|
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(testingNow) {
|
||||||
if((runMeasure) && (settings.isPressed(2))){
|
if((runMeasure) && (settings.isPressed(2))){
|
||||||
runMeasure = false;
|
runMeasure = false;
|
||||||
display.textStatus("STOPPING. WAIT");
|
display.textStatus("STOPPING. WAIT");
|
||||||
}
|
}
|
||||||
return;
|
return; // jeśli trwa akurat test, nic nie rób
|
||||||
}
|
}
|
||||||
|
|
||||||
if(wifiTestThread.shouldRun() && (config.connect))
|
if(wifiTestThread.shouldRun() && (config.connect))
|
||||||
wifiTestThread.run();
|
wifiTestThread.run();
|
||||||
|
|
||||||
if(uploadThread.shouldRun() && (config.connect))
|
if(uploadThread.shouldRun() && config.connect)
|
||||||
uploadThread.run();
|
uploadThread.run();
|
||||||
|
|
||||||
if(offlineThread.shouldRun() && (!config.connect)){
|
if(offlineThread.shouldRun() && (!config.connect)){
|
||||||
@@ -423,11 +449,12 @@ void loop() {
|
|||||||
if (isRebootRequired) {
|
if (isRebootRequired) {
|
||||||
ESP_LOGI(TAG_MAIN, "Reboot required");
|
ESP_LOGI(TAG_MAIN, "Reboot required");
|
||||||
Watchdog::feed();
|
Watchdog::feed();
|
||||||
delay(1000);
|
delay(1000);
|
||||||
reboot();
|
reboot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wifi.handleClient();
|
||||||
Watchdog::feed();
|
Watchdog::feed();
|
||||||
delay(20);
|
delay(20); // 100
|
||||||
licznik ++;
|
licznik ++;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user