#define ENABLE_GxEPD2_GFX 0 #include #include #include #include #include #include #include "credentials.h" #include "logo.h" #if defined(ESP32) GxEPD2_BW display(GxEPD2_750(/*CS=*/ 15, /*DC=*/ 27, /*RST=*/ 26, /*BUSY=*/ 25)); #endif #define uS_TO_S_FACTOR 1000000 // Conversion of seconds (S) to microseconds (uS) #define SLEEPING_TIME 1800 // Time in Seconds e.g. 1800s = 0.5 hours RTC_DATA_ATTR int bootCount = 0; // Boot counter after deep sleep // Creating instances WiFiClientSecure client; void setup() { Serial.begin(115200); display.init(115200); SPI.end(); // Do not use standard SPI pins SPI.begin(13, 12, 14, 15); // Remap SPI pins for Waveshare ESP32 module display.fillScreen(GxEPD_WHITE); display.setRotation(3); // Rotate Dislay orientation 180° Serial.println("DEBUG: Setup EPD Display complete"); delay(2000); connectToWifi(); esp_sleep_enable_timer_wakeup(SLEEPING_TIME * uS_TO_S_FACTOR); ++bootCount; Serial.println("INFO: Boot number: " + String(bootCount)); } void loop() { DisplayShowerthought(); Serial.println("INFO: Going to deep sleep"); esp_wifi_stop(); esp_bt_controller_disable(); esp_deep_sleep_start(); } ////////////////////////////////////////////////// ///// WiFi Setup ///// ////////////////////////////////////////////////// void connectToWifi() { WiFi.begin(ssid, password); int connectTries = 0; // Counter for unsuccessful connects to WiFi Serial.print("WIFI: Connecting "); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); if(connectTries % 4 == 3) { WiFi.begin(ssid, password); } if(connectTries >= 20) { Serial.println("WIFI: Unable to connect to " + WiFi.SSID() + ". ESP32 going to deep sleep."); esp_wifi_stop(); esp_bt_controller_disable(); esp_deep_sleep_start(); } connectTries++; } Serial.println("WIFI: Connected to network: " + WiFi.SSID()); Serial.println(WiFi.localIP()); Serial.println(WiFi.macAddress()); } const char TitleText[] = "Reddit | Showerthoughts"; void DisplayShowerthought() { Serial.println("DEBUG: Printing Showerthought to display"); display.setFont(&FreeMonoBold9pt7b); display.setTextColor(GxEPD_BLACK); int16_t tbx, tby; uint16_t tbw, tbh; display.getTextBounds(TitleText, 0, 0, &tbx, &tby, &tbw, &tbh); uint16_t x = ((display.width() - tbw) / 2) - tbx; uint16_t y = ((display.height() - tbh) / 2) - tby; display.setFullWindow(); display.firstPage(); // Full refresh String Thought = getShowerthought(); do { display.fillScreen(GxEPD_WHITE); display.drawBitmap(130, 90, logo, 125, 125, GxEPD_BLACK); display.setCursor(x, y); display.print(TitleText); display.drawRect(x-16, y-20, tbw+32, tbh+18, GxEPD_BLACK); display.setCursor(0, 450); display.print(Thought); } while (display.nextPage()); } ////////////////////////////////////////////////// ///// Reddit utils ///// ////////////////////////////////////////////////// String getShowerthought() { // Connect to reddit.com and fetch the showerthought data using the web client Serial.println("Fetching Showerthougt"); if(!client.connect(host, port)) { Serial.println("SECURE CLIENT: Connection 1 failed!"); return "Unable to connect to Reddit"; } String url = "/r/Showerthoughts/random.json?sort=hot&limit=1&t=day"; client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "User-Agent: ESP32/0.1\r\n" + "Connection: close\r\n\r\n"); unsigned long timeout = millis(); while (client.available() == 0) { if (millis() - timeout > 5000) { Serial.println("SECURE CLIENT: Client Timeout!"); client.stop(); return "Reddit did not respond in time"; } } // get the random post url (redirection) String headerLine = ""; String locationUrl; while(headerLine != "\r") { headerLine = client.readStringUntil('\n'); if(headerLine.indexOf("location: ") ==0) { locationUrl = headerLine.substring(10, headerLine.indexOf("?")); break; } } client.stop(); // get the content of the url we just got if(!client.connect(host, port)) { Serial.println("connection 2 failed!"); return "Impossible to reconnect to Reddit"; } client.print(String("GET ") + locationUrl + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "User-Agent: ESP32/0.1\r\n" + "Connection: close\r\n\r\n"); timeout = millis(); while (client.available() == 0) { if (millis() - timeout > 5000) { Serial.println(">>> Client Timeout !"); client.stop(); return "Shower thought did not arrived in time"; } } // get rid of header while(client.connected()) { String line = client.readStringUntil('\n'); if (line == "\r") { Serial.println("DEBUG: Headers received"); break; } } // Get the response from the reddit.com server String quote = client.readStringUntil('\n'); client.stop(); // As the JSON-formatted response text can be too long, we'll parse it manually instead of using ArduinoJson int quote_start = quote.indexOf("\"title\""); // The showerthought quote ends right before a ', "' substring int quote_end = quote.indexOf(", \"", quote_start+1); // we start the search from the position where "title" is String showerthought = quote.substring(quote_start+9, quote_end); // Sanitize the string a bit showerthought.replace("\\\"","'"); // get rid of escaped quotes in the text ('\"') int junkIndex = showerthought.indexOf("\\u"); while(junkIndex >= 0) { showerthought.remove(junkIndex, 5); showerthought.setCharAt(junkIndex, '\''); junkIndex = showerthought.indexOf("\\u"); } return showerthought; Serial.print(showerthought); }