-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1da0c8d
commit 4a708c8
Showing
9 changed files
with
1,056 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
#include <SD.h> | ||
#include <AsyncFsWebServer.h> | ||
|
||
// Timezone definition to get properly time from NTP server | ||
#define MYTZ "CET-1CEST,M3.5.0,M10.5.0/3" | ||
#include <time.h> | ||
|
||
#define PIN_CS 14 | ||
#define PIN_SCK 13 | ||
#define PIN_MOSI 12 | ||
#define PIN_MISO 11 | ||
|
||
|
||
AsyncFsWebServer server(80, SD, "myServer"); | ||
struct tm ntpTime; | ||
const char* basePath = "/csv"; | ||
|
||
//////////////////////////////// NTP Time ///////////////////////////////////////// | ||
void getUpdatedtime(const uint32_t timeout) { | ||
uint32_t start = millis(); | ||
do { | ||
time_t now = time(nullptr); | ||
ntpTime = *localtime(&now); | ||
delay(1); | ||
} while (millis() - start < timeout && ntpTime.tm_year <= (1970 - 1900)); | ||
} | ||
|
||
|
||
//////////////////////////////// Filesystem ///////////////////////////////////////// | ||
bool startFilesystem(){ | ||
if (SD.begin(PIN_CS)){ | ||
server.printFileList(SD, "/", 2); | ||
return true; | ||
} | ||
else { | ||
Serial.println("ERROR on mounting filesystem. It will be formmatted!"); | ||
ESP.restart(); | ||
} | ||
return false; | ||
} | ||
|
||
//////////////////////////// Append a row to csv file /////////////////////////////////// | ||
bool appenRow() { | ||
getUpdatedtime(10); | ||
|
||
char filename[24]; | ||
snprintf(filename, sizeof(filename), | ||
"%s/%04d_%02d_%02d.csv", | ||
basePath, | ||
ntpTime.tm_year + 1900, | ||
ntpTime.tm_mon + 1, | ||
ntpTime.tm_mday | ||
); | ||
|
||
File file; | ||
if (SD.exists(filename)) { | ||
file = SD.open(filename, "a"); // Append to existing file | ||
} | ||
else { | ||
file = SD.open(filename, "w"); // Create a new file | ||
file.println("timestamp, free heap, largest free block, connected, wifi strength"); | ||
} | ||
|
||
if (file) { | ||
char timestamp[25]; | ||
strftime(timestamp, sizeof(timestamp), "%c", &ntpTime); | ||
|
||
char row[64]; | ||
#ifdef ESP32 | ||
snprintf(row, sizeof(row), "%s, %d, %d, %s, %d", | ||
timestamp, | ||
heap_caps_get_free_size(0), | ||
heap_caps_get_largest_free_block(0), | ||
(WiFi.status() == WL_CONNECTED) ? "true" : "false", | ||
WiFi.RSSI() | ||
); | ||
#elif defined(ESP8266) | ||
uint32_t free; | ||
uint16_t max; | ||
ESP.getHeapStats(&free, &max, nullptr); | ||
snprintf(row, sizeof(row), | ||
"%s, %d, %d, %s, %d", | ||
timestamp, free, max, | ||
(WiFi.status() == WL_CONNECTED) ? "true" : "false", | ||
WiFi.RSSI() | ||
); | ||
#endif | ||
Serial.println(row); | ||
file.println(row); | ||
file.close(); | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
|
||
void setup() { | ||
SPI.begin(PIN_SCK, PIN_MISO, PIN_MOSI, PIN_CS); | ||
Serial.begin(115200); | ||
|
||
delay(1000); | ||
startFilesystem(); | ||
|
||
// Create csv logs folder if not exists | ||
if (!SD.exists(basePath)) { | ||
SD.mkdir(basePath); | ||
} | ||
|
||
server.setAP("ESP32_CSVLOGGER", "123456789"); | ||
IPAddress myIP = server.startWiFi(15000); | ||
|
||
// Enable ACE FS file web editor and add FS info callback fucntion | ||
server.enableFsCodeEditor(); | ||
#ifdef ESP32 | ||
server.setFsInfoCallback([](fsInfo_t* fsInfo) { | ||
fsInfo->totalBytes = SD.totalBytes(); | ||
fsInfo->usedBytes = SD.usedBytes(); | ||
fsInfo->fsName = "SD"; | ||
}); | ||
#endif | ||
|
||
// Start server | ||
server.init(); | ||
Serial.print(F("\nAsync ESP Web Server started on IP Address: ")); | ||
Serial.println(myIP); | ||
Serial.println(F( | ||
"This is \"scvLoggerSdFat.ino\" example.\n" | ||
"Open /setup page to configure optional parameters.\n" | ||
"Open /edit page to view, edit or upload example or your custom webserver source files." | ||
)); | ||
|
||
// Set NTP servers | ||
#ifdef ESP8266 | ||
configTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org"); | ||
#elif defined(ESP32) | ||
configTzTime(MYTZ, "time.google.com", "time.windows.com", "pool.ntp.org"); | ||
#endif | ||
|
||
// Wait for NTP sync (with timeout) | ||
getUpdatedtime(5000); | ||
|
||
appenRow(); | ||
} | ||
|
||
void loop() { | ||
if (server.getCaptivePortal()) | ||
server.updateDNS(); | ||
|
||
static uint32_t updateTime; | ||
if (millis()- updateTime > 30000) { | ||
updateTime = millis(); | ||
appenRow(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
/* Misc */ | ||
html, body { | ||
font-family: "Helvetica","Arial",sans-serif; | ||
font-size: 14px; | ||
font-weight: 400; | ||
line-height: 20px; | ||
} | ||
body { | ||
margin: 0; | ||
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; | ||
font-size: 1rem; | ||
font-weight: 400; | ||
line-height: 1.5; | ||
color: #212529; | ||
text-align: left; | ||
background-color: #fff; | ||
} | ||
|
||
h1 { | ||
margin: 5px; | ||
text-align: center; | ||
} | ||
|
||
p { | ||
font-size: 0.9rem; | ||
margin: 0.5rem 0 1.5rem 0; | ||
} | ||
|
||
a, | ||
a:visited { | ||
color: #08C; | ||
text-decoration: none; | ||
} | ||
|
||
a:hover, | ||
a:focus { | ||
color: #69c773; | ||
cursor: pointer; | ||
} | ||
|
||
a.delete-file, | ||
a.delete-file:visited { | ||
color: #CC0000; | ||
margin-left: 0.5rem; | ||
vertical-align: middle; | ||
} | ||
|
||
button { | ||
display: inline-block; | ||
border-radius: 3px; | ||
border: none; | ||
font-size: 0.9rem; | ||
padding: 0.5rem 1em; | ||
background: #86b32d; | ||
border-bottom: 1px solid #5d7d1f; | ||
color: white; | ||
margin: 5px 0; | ||
text-align: center; | ||
} | ||
|
||
button:hover { | ||
opacity: 0.75; | ||
cursor: pointer; | ||
} | ||
|
||
#page-wrapper { | ||
width: 95%; | ||
background: #FFF; | ||
padding: 1.25rem; | ||
margin: 1rem auto; | ||
min-height: 800px; | ||
border-top: 5px solid #69c773; | ||
box-shadow: 0 2px 10px rgba(0,0,0,0.8); | ||
} | ||
|
||
#content { | ||
width: 85%; | ||
overflow: auto; | ||
height: 86vh; | ||
} | ||
|
||
#files { | ||
width: 15%; | ||
} | ||
|
||
#files ul { | ||
margin: 20px 0; | ||
padding: 0.5rem 1rem; | ||
overflow-y: auto; | ||
list-style: square; | ||
background: #F7F7F7; | ||
border: 1px solid #D9D9D9; | ||
border-radius: 5px; | ||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1); | ||
max-height: 75vh; | ||
} | ||
|
||
#files li { | ||
margin-left: 8px; | ||
font-size: 14px; | ||
display: flex; | ||
justify-content: space-between; | ||
align-items: center; | ||
} | ||
|
||
.container { | ||
display: flex; | ||
flex-direction: row; | ||
align-content: flex-start; | ||
justify-content: space-between; | ||
align-items: flex-start; | ||
column-gap: 10px; | ||
height: 86vh; | ||
} | ||
|
||
.delete { | ||
font-size: 24px; | ||
transition: 0.3s; | ||
margin-top:5px; | ||
} | ||
|
||
.delete-all{ | ||
color: #f44336; | ||
font-size: 12px; | ||
background-color: transparent; | ||
background-repeat: no-repeat; | ||
border: none; | ||
cursor: pointer; | ||
overflow: hidden; | ||
} | ||
|
||
/* Tables */ | ||
.table-holder { | ||
margin-top: 20px; | ||
border: 1px solid lightgray; | ||
border-radius: 5px; | ||
border-bottom: 0px; | ||
border-bottom-left-radius: 0px; | ||
border-bottom-right-radius: 0px; | ||
} | ||
|
||
.tables { | ||
margin-bottom: 50px; | ||
} | ||
|
||
table { | ||
width: 100%; | ||
border-bottom: 0px; | ||
} | ||
|
||
table, th, td { | ||
border: 1px solid lightgrey; | ||
border-collapse: collapse; | ||
padding-left: 5px; | ||
} | ||
|
||
table tr:nth-child(even) { | ||
background-color: white; | ||
} | ||
|
||
table tr:nth-child(odd) { | ||
background-color: #f2f2f2; | ||
} | ||
|
||
table th { | ||
background-color: #e1e1e1; | ||
color: black; | ||
} | ||
|
||
/* Sections */ | ||
|
||
.section { | ||
box-shadow: 10px 10px 10px 10px; | ||
background-color: #e5e5e5; | ||
padding: 10px; | ||
padding-top: 20px; | ||
font-size: 18px; | ||
} | ||
|
||
.section-lightgrey { | ||
background-color: #f9f9f9; | ||
} | ||
|
||
/* 100% Image Width on Smaller Screens */ | ||
@media only screen and (max-width: 700px){ | ||
.modal-content { | ||
width: 100%; | ||
} | ||
} |
Oops, something went wrong.