Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*=================================================================================================
- In case of compilation errors in Arduino IDE (library TFT_eSPI) in ESP32 core 3.0.x
- Open the library folder TFT_eSPI:
- (i.e. Windows) - C:\Users\Your_User_Name\OneDrive\Documents\Arduino\libraries\TFT_eSPI\
- Folder C:\Users\Your_User_Name\OneDrive\Documents\Arduino\libraries\TFT_eSPI\Processors - file:
- - TFT_eSPI_ESP32.h
- - TFT_eSPI_ESP32_S3.h
- - TFT_eSPI_ESP32_C3.h
- ====================================================================================================
- just below the line:
- #include "hal/gpio_ll.h"
- add:
- #include "driver/gpio.h" // add this line to fix problems during compilation (ESP32 core 3.0.x)
- ====================================================================================================
- sketch for ESP32-3248S035 - VERSION WITHOUT the library WiFiManager.h
- If a WiFi connection cannot be made, a Web server is started to store the WiFi credentials.
- SHOULD COMPILE ON CORE 3.0.x (Arduino IDE: boards manager: ESP32 - espressif)
- ====================================================================================
- Arduino IDE - board: ESP32 Dev Module of DOIT ESP32 DEVKIT V1
- https://nl.aliexpress.com/item/1005006398547061.html
- https://nl.aliexpress.com/item/1005005900820162.html
- ====================================================================================*/
- #include <WiFi.h>
- #include <ArduinoJson.h> // https://github.com/bblanchon/ArduinoJson
- #include <WebServer.h>
- #include <Preferences.h>
- #include <HTTPClient.h> // for API connection
- #include <TFT_eSPI.h> // https://github.com/Bodmer/TFT_eSPI
- TFT_eSPI tft = TFT_eSPI(); // User_Setup.h settings available on: https://espgo.be board ESP32-3248S035
- WebServer server(80);
- Preferences flash;
- #define SHOW_ITEMS 34 // max number of records you want to process.
- #define VALUE_RED 100 // electricity price in red color if higher than this value
- #define UTC_OFFSET_SUMMER 7200
- #define UTC_OFFSET_WINTER 3600
- struct tm tInfo; // https://cplusplus.com/reference/ctime/tm/
- bool chart = true, freshStart = true;
- const char* time_Zone = "CET-1CEST,M3.5.0,M10.5.0/3"; // https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
- double prijzen[SHOW_ITEMS]; // most recent 34 prices
- double prices[SHOW_ITEMS * 2]; // all prices returned by the API
- double priceNow; // price of current hour
- time_t epo[SHOW_ITEMS]; // most recent 34 epoch times
- time_t epoc[SHOW_ITEMS * 2]; // all epoch times returned by the API
- uint8_t API_ITEMS;
- String my_link, webText, buttons, Ssid, Pasw;
- char* connect[] = { "WiFi: no connection", "Connect to hotspot", "S035_ESP", "Start a browser - address",
- "192.168.4.1", "to save network", "and password" };
- void setup() {
- Serial.begin(115200);
- pinMode(0, INPUT_PULLUP); // flash button
- tft.init();
- tft.setRotation(3);
- tft.setTextWrap(false);
- tft.fillScreen(TFT_BLACK); // delete output from previous sessions
- connectWiFi();
- configTzTime(time_Zone, "be.pool.ntp.org");
- showStartupData();
- }
- void loop() {
- display_Time();
- if (!digitalRead(0)) changeView(); // flash button changes between chart or list of figures
- // if (priceNow < 0) startHeavyPowerConsumer(); // priceNow = current price
- // else stopHeavyPowerConsumer();
- }
- void showStartupData() {
- tft.fillScreen(TFT_BLACK);
- tft.drawCentreString("Retrieving SNTP time", 240, 160, 4);
- getLocalTime(&tInfo);
- delay(3000);
- tft.fillScreen(TFT_BLACK);
- tft.setTextColor(TFT_ORANGE);
- tft.drawCentreString("Retrieving Json Data", 240, 160, 4);
- }
- void changeView() {
- chart = !chart;
- chart ? show_Chart() : show_Data();
- showCurrentPrice(), delay(800); // 800 = UI debouncing (button)
- }
- void display_Time() {
- char theDate[11], theTime[9];
- getLocalTime(&tInfo); // SNTP sync at startup and every 3 hours thereafter (ESP32)
- time_t now;
- time(&now); // assign current epoch time (UTC) to "now"
- tft.drawRect(-1, 26, 482, 2, WiFi.isConnected() ? TFT_GREEN : TFT_RED);
- tft.setTextColor(TFT_GREEN, TFT_BLACK);
- strftime(theDate, sizeof(theDate), "%d-%m-%G", &tInfo); // https://cplusplus.com/reference/ctime/strftime/
- tft.drawString(theDate, 2, 0, 4);
- tft.setTextColor(TFT_WHITE, TFT_BLACK);
- strftime(theTime, sizeof(theTime), "%T", &tInfo);
- tft.drawString(theTime, 135, 0, 4);
- if ((freshStart) || ((((epo[SHOW_ITEMS - 1] - now) / 3600) < 9) && (tInfo.tm_min == 2) && (tInfo.tm_sec == 1))) {
- if (WiFi.isConnected()) retrieve_Data(); // ^^from 1400 hrs: try to retrieve new data every hour until it succeeds
- chart ? show_Chart() : show_Data(), showCurrentPrice();
- if (!freshStart) {
- tft.setTextColor(TFT_DARKGREY, TFT_BLACK);
- tft.drawRightString(String((epo[SHOW_ITEMS - 1] - now) / 3600), 480, 0, 2);
- if (((epo[SHOW_ITEMS - 1] - now) / 3600) > 8) tft.fillRect(444, 0, 36, 22, TFT_BLACK);
- }
- Serial.println(my_link); // debugging
- Serial.println((epo[SHOW_ITEMS - 1] - now) / 3600); // number of hours of future available data
- freshStart = false;
- }
- if ((tInfo.tm_min == 0) && (tInfo.tm_sec == 0)) { // refresh data (local) every hour
- chart ? show_Chart() : show_Data();
- showCurrentPrice(), delay(950);
- }
- }
- void retrieve_Data() { // prepare string with epoch times and retrieve energy data
- memset(prijzen, 0, sizeof(prijzen));
- memset(epo, 0, sizeof(epo));
- memset(prices, 0, sizeof(prices));
- memset(epoc, 0, sizeof(epoc));
- my_link = "https://api.energy-charts.info/price?bzn=BE&start=";
- time_t now;
- time(&now); // assign current epoch time (UTC) to "now"
- now = now - (now % 3600); // round down to the whole hour
- now = now + ((tInfo.tm_isdst) ? UTC_OFFSET_SUMMER : UTC_OFFSET_WINTER);
- my_link = my_link + String(now - (24 * 3600)) + "&end=" + String(now + (SHOW_ITEMS * 3600));
- if (my_link.length() > 56) get_JsonData(); // do not send empty input (e.g., if SNTP times out)
- else { // composing string (to send to API) = failed
- tft.fillRect(0, 200, 320, 40, TFT_BLACK);
- tft.drawCentreString("Link API incomplete", 160, 200, 4);
- }
- tft.setCursor(264, 0, 4);
- tft.setTextColor(TFT_SILVER, TFT_BLACK);
- tft.print("/MWh:");
- tft.fillCircle(255, 10, 9, TFT_SILVER); // euro symbol
- tft.fillCircle(255, 10, 7, TFT_BLACK), tft.fillRect(258, 5, 8, 12, TFT_BLACK);
- tft.drawRect(247, 8, 9, 2, TFT_SILVER), tft.drawRect(249, 11, 6, 2, TFT_SILVER);
- }
- void show_Chart() { // Json data in chart on display
- tft.fillRect(0, 28, 480, 292, TFT_BLACK);
- tft.setTextColor(TFT_WHITE);
- for (uint8_t i = 0; i < 6; i++) { // draw lines with values -50, 0, 50, 100 etc.
- tft.drawFastHLine(0, 40 + i * 50, 480, tft.color565(64, 64, 64));
- for (uint8_t j = 0; j < 3; j++) // j handles the horizontal coordinate
- tft.drawRightString(String(i * 50 - 50), j * 228 + 23, 286 - i * 50, 1);
- }
- for (uint8_t i = 0; i < SHOW_ITEMS; i++) {
- struct tm* cor; // to convert epoch times to tm structure in local time
- if (epo[i]) { // do not show empty data
- cor = localtime(&epo[i]); // adjust epoch times in the list to local time / dst
- if ((cor->tm_hour == tInfo.tm_hour) && (cor->tm_mday == tInfo.tm_mday)) {
- priceNow = prijzen[i];
- tft.drawFastVLine(6 + i * 14, 26, 292, TFT_MAGENTA);
- tft.fillTriangle((i * 14) - 4, 300, (i * 14) - 4, 310, 6 + i * 14, 305, TFT_MAGENTA);
- tft.fillTriangle((i * 14) - 4, 55, (i * 14) - 4, 65, 6 + i * 14, 60, TFT_MAGENTA);
- }
- tft.setTextColor(prijzen[i] > 0 ? TFT_BLACK : TFT_YELLOW);
- uint16_t mijnKleur = prijzen[i] < VALUE_RED ? TFT_CYAN : TFT_RED;
- if (prijzen[i] < 50) mijnKleur = TFT_GREEN;
- if (prijzen[i] < 0) {
- mijnKleur = TFT_YELLOW;
- tft.fillRect(i * 14, 240, 13, 0 - prijzen[i], mijnKleur);
- tft.drawFastVLine(i * 14 + 13, 240, 0 - prijzen[i], TFT_BLACK);
- } else {
- tft.fillRect(i * 14, 240 - prijzen[i], 13, prijzen[i], mijnKleur);
- tft.drawFastVLine(i * 14 + 13, 240 - prijzen[i], prijzen[i], TFT_BLACK);
- }
- tft.setCursor(1 + i * 14, 230, 1); // hours at the bottom of chart
- tft.printf("%02d", cor->tm_hour);
- tft.setTextColor(TFT_RED);
- tft.setCursor(1 + i * 14, 243, 1);
- tft.printf("%02d", cor->tm_hour);
- }
- }
- }
- void show_Data() { // display Json data in 2 colums time / price
- tft.fillRect(0, 28, 480, 292, TFT_BLACK);
- tft.drawRect(240, 26, 2, 292, WiFi.isConnected() ? TFT_GREEN : TFT_RED);
- struct tm* cor;
- for (uint8_t i = 0; i < SHOW_ITEMS; i++) {
- if (epo[i]) {
- cor = localtime(&epo[i]);
- tft.setTextColor(TFT_LIGHTGREY, TFT_BLACK);
- tft.setCursor(((i < 18) ? 0 : 260), 33 + (i % 18) * 16, 2);
- tft.printf(" %02d. ", i + 1);
- if ((cor->tm_hour == tInfo.tm_hour) && (cor->tm_mday == tInfo.tm_mday)) {
- priceNow = prijzen[i];
- tft.setTextColor(TFT_MAGENTA, TFT_BLACK);
- } else tft.setTextColor(TFT_WHITE, TFT_BLACK);
- tft.printf("%02d-%02d-%02d %02d:%02d", cor->tm_mday, cor->tm_mon + 1, cor->tm_year + 1900, cor->tm_hour, cor->tm_min);
- tft.setTextColor((prijzen[i] < VALUE_RED) ? TFT_CYAN : TFT_RED);
- if (prijzen[i] < 50) tft.setTextColor(TFT_GREEN, TFT_BLACK);
- if (prijzen[i] < 0) tft.setTextColor(TFT_YELLOW, TFT_BLACK);
- tft.drawRightString(String(prijzen[i]), (i < 18 ? 220 : 480), 33 + (i % 18) * 16, 2);
- }
- }
- }
- void showCurrentPrice() { // price (upper right corner of display)
- tft.setTextColor(priceNow < VALUE_RED ? TFT_CYAN : TFT_RED);
- if (priceNow < 50) tft.setTextColor(TFT_GREEN);
- if (priceNow < 0) tft.setTextColor(TFT_YELLOW);
- tft.fillRect(344, 0, 100, 22, TFT_BLACK);
- tft.setCursor(344, 0, 4);
- tft.printf("%3.2F", priceNow);
- }
- void get_JsonData() {
- HTTPClient http;
- http.begin(my_link);
- delay(3000);
- if (http.GET() == 200) {
- DynamicJsonDocument doc(8192); // choose value large enough to contain the data
- auto error = deserializeJson(doc, http.getString());
- if (error) {
- tft.drawCentreString("deserializeJson() failed", 240, 200, 4);
- tft.drawCentreString(error.c_str(), 240, 250, 4);
- }
- for (uint8_t i = 0; i < SHOW_ITEMS * 2; i++) { // actually more data than we can show on display
- prices[i] = doc["price"][i];
- epoc[i] = doc["unix_seconds"][i];
- API_ITEMS = i; // count number of returned items
- }
- } else { // http.get has failed
- tft.fillScreen(TFT_BLACK);
- tft.drawCentreString("Error in API response", 240, 160, 4);
- tft.drawCentreString("Restart in 18 seconds", 240, 190, 4);
- delay(2000);
- sleep16Sec();
- }
- http.end();
- uint8_t j = SHOW_ITEMS + 1;
- for (uint8_t i = API_ITEMS; i >= 0; i--) { // select the most recent Json data
- if (epoc[i] != 0) { // ignore empty data
- j--; // counter for results
- prijzen[j - 1] = prices[i]; // transferring valid prices from API results
- epo[j - 1] = epoc[i]; // also hours to "local" array
- if (j == 0) break; // stop when we have 34 items
- }
- }
- }
- void sleep16Sec() {
- esp_sleep_enable_timer_wakeup(16000000); // 16 seconds
- esp_deep_sleep_start(); // deep sleep: this will reset the clock & force a new time sync
- }
- void connectWiFi() {
- WiFi.disconnect();
- flash.begin("login_data", true); // true = read only
- Ssid = flash.getString("ssid", "");
- Pasw = flash.getString("pasw", "");
- flash.end();
- WiFi.begin(Ssid.c_str(), Pasw.c_str());
- if (testWifi()) return;
- else { // no WiFi connection
- messageNoConnection();
- setupAP();
- startWebServer();
- server.begin();
- }
- while ((WiFi.status() != WL_CONNECTED)) server.handleClient();
- }
- bool testWifi() {
- tft.fillScreen(TFT_BLACK);
- tft.setCursor(44, 0, 4);
- tft.setTextColor(TFT_GREEN, TFT_BLACK);
- tft.print("Connect to WiFi");
- tft.fillCircle(160, 138, 10, TFT_YELLOW);
- tft.drawRect(10, 190, 300, 20, TFT_CYAN);
- byte c = 0;
- while (c < 180) {
- if (WiFi.isConnected()) {
- WiFi.setAutoReconnect(true);
- WiFi.persistent(true);
- return true;
- }
- delay(20);
- for (byte t = 0; t < 4; t++) { // animation logo wifi
- tft.drawSmoothArc(160, 140, (c % 20) + 20 + (t * 20), (c % 20) + 14 + (t * 20), 135, 225, TFT_YELLOW, TFT_YELLOW, true);
- tft.drawSmoothArc(160, 140, (c % 20) + 14 + (t * 20), (c % 20) + 13 + (t * 20), 120, 240, TFT_BLACK, TFT_BLACK, true);
- }
- tft.drawFastVLine(c + 11, 192, 16, TFT_CYAN);
- ++c;
- }
- return false;
- }
- void messageNoConnection() {
- tft.fillScreen(TFT_NAVY);
- tft.setTextColor(TFT_YELLOW), tft.setTextFont(4);
- for (uint8_t i = 0; i < 7; i++) tft.drawCentreString(connect[i], 240, 40 + i * 30, 4);
- }
- void setupAP(void) {
- WiFi.mode(WIFI_STA);
- WiFi.disconnect();
- delay(500);
- int n = WiFi.scanNetworks();
- delay(5000);
- for (int i = 0; i < n; ++i) { // html to put found networks on buttons on web page
- buttons += "\n<button onclick='scrollNaar(this.id)' id='" + WiFi.SSID(i) + "'>" + WiFi.SSID(i) + "</button><br>";
- }
- delay(1000);
- WiFi.softAP("S035_ESP");
- startWebServer();
- server.begin();
- }
- void startWebServer() {
- server.on("/", []() {
- IPAddress ip = WiFi.softAPIP();
- webText = "<!DOCTYPE HTML>\n<html lang='en'>\n<head><title>Setup</title>\n<meta name='viewport' ";
- webText += "content='width=device-width, initial-scale=1.0'>";
- webText += "\n<style>\np {\n font-family: Arial, Helvetica, sans-serif;\n font-size: 18px;\n margin: 0;\n text-align: ";
- webText += "center;\n}\n\nbutton, input[type=submit] {\n width: 250px;\n border-radius: 5px;\n color: White;\n padding:";
- webText += " 4px 4px;\n margin-top: 16px;\n margin: 0 auto;\n display:block;\n font-size: 18px;\n font-weight: 600;";
- webText += "\n background: DodgerBlue;\n}\n\ninput {\n width: 250px;\n font-size: 18px;\n font-weight: 600;\n}";
- webText += "\n</style>\n</head>\n<body><p style='font-family:arial; ";
- webText += "font-size:240%;'>WiFi setup\n</p><p style='font-family:arial; font-size:160%;'>\n<br>";
- webText += "Networks found:<br> Click on item to select or<br>Enter your network data<br> in the boxes below:</p><br>";
- webText += buttons;
- webText += "\n<form method='get' action='setting'>\n<p><b>\nSSID: <br>\n<input id='ssid' name='ssid'>";
- webText += "<br>PASW: </b><br>\n<input type='password' name='pass'><br><br>\n<input type='submit' value='Save'>";
- webText += "\n</p>\n</form>\n<script>\nfunction scrollNaar(tekst) {\n document.getElementById('ssid')";
- webText += ".value = tekst;\n window.scrollTo(0, document.body.scrollHeight);\n}\n</script>\n</body>\n</html>";
- server.send(200, "\ntext/html", webText);
- });
- server.on("/setting", []() { // store data in flash
- webText = "<!DOCTYPE HTML>\n<html lang='en'>\n<head><title>Setup</title>\n<meta name='viewport' ";
- webText += "content='width=device-width, initial-scale=1.0'>\n<style>\np {\n font-family: Arial, Helvetica";
- webText += ", sans-serif;\n font-size: 45px;\n font-weight: 600;\n margin: 0;\n text-align: center;\n}";
- webText += "\n</style>\n</head>\n<body><p>ESP will reboot\n<br>Close this window</p><br>\n</body>\n</html>";
- server.send(200, "\ntext/html", webText);
- delay(500);
- String myssid = server.arg("ssid"); // we want to store this in flash memory
- String mypasw = server.arg("pass");
- if (myssid.length() > 0 && mypasw.length() > 0) {
- flash.begin("login_data", false); // false = write to "flash/login_data"
- flash.putString("ssid", myssid);
- flash.putString("pasw", mypasw);
- flash.end();
- ESP.restart();
- }
- });
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement