T5_dashboard/T5_dashboard.ino

349 lines
8.9 KiB
C++

// // include library, include base class, make path known
// #include <GxEPD.h>
// // select the display class to use, only one
// #include <GxGDE0213B72B/GxGDE0213B72B.h> // 2.13" b/w
// #include <GxIO/GxIO_SPI/GxIO_SPI.h>
// #include <GxIO/GxIO.h>
// #if defined(ESP32)
// GxIO_Class io(SPI, /*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16); // arbitrary selection of 17, 16
// GxEPD_Class display(io, /*RST=*/ 16, /*BUSY=*/ 4); // arbitrary selection of (16), 4
// #endif
#include <GxEPD2_BW.h>
#include <GxEPD2_3C.h>
#include <GxEPD2_7C.h>
GxEPD2_BW<GxEPD2_213_B73, GxEPD2_213_B73::HEIGHT> display(GxEPD2_213_B73(/*CS=5*/ SS, /*DC=*/17, /*RST=*/16, /*BUSY=*/4)); // GDEH0213B73
// #include "fonts/alarm_clock32pt7b.h"
// #include "fonts/alarm_clock30pt7b.h"
// #include "fonts/alarm_clock16pt7b.h"
#include "fonts/Pixeltype8pt7b.h"
#include "fonts/Pixeltype16pt7b.h"
#include "fonts/retro_computer_personal_use8pt7b.h"
#include "fonts/retro_computer_personal_use16pt7b.h"
#include "fonts/retro_computer_personal_use24pt7b.h"
#include "images/clear_d.h"
#include "images/clear_n.h"
#include "images/cloud_d.h"
#include "images/cloud_n.h"
#include "images/cloud.h"
#include "images/clouds.h"
#include "images/rain_h.h"
#include "images/rain_l_d.h"
#include "images/rain_l_n.h"
#include "images/thunder.h"
#include "images/snow_d.h"
#include "images/snow_n.h"
#include "images/mist_d.h"
#include "images/mist_n.h"
#include "time.h"
#include <WiFi.h>
#include <WiFiMulti.h>
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <ArduinoJson.h>
#include <WiFiClient.h>
WiFiMulti WiFiMulti;
struct tm timeinfo;
WiFiClient client;
// Allocate the JSON document
// Use arduinojson.org/v6/assistant to compute the capacity.
const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2 * JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(13) + 280;
DynamicJsonDocument weather(capacity);
unsigned long t = 0;
int dt = 0;
int interval = 0;
int refresh = 0;
int update = 0;
void drawTime()
{
getLocalTime(&timeinfo);
display.setTextColor(GxEPD_BLACK);
display.setFont(&retro_computer_personal_use24pt7b);
display.setCursor(78, 65);
display.println(&timeinfo, "%H:%M");
display.setFont(&retro_computer_personal_use16pt7b);
display.setCursor(78, 95);
display.println(&timeinfo, "%d");
display.setFont(&retro_computer_personal_use8pt7b);
display.setCursor(132, 83);
display.println(&timeinfo, "%A");
display.setCursor(132, 95);
display.println(&timeinfo, "%B");
}
void drawWeather()
{
display.fillRect(0, 0, 75, 150, GxEPD_BLACK);
display.setTextColor(GxEPD_WHITE);
display.setFont(&retro_computer_personal_use16pt7b);
int16_t tbx, tby;
uint16_t tbw, tbh;
display.getTextBounds(String(weather["main"]["temp"].as<int>()), 0, 100, &tbx, &tby, &tbw, &tbh);
uint16_t x = ((75 - 10 - tbw) / 2) - tbx;
display.setCursor(x, 100);
display.print(weather["main"]["temp"].as<int>());
display.setFont(&retro_computer_personal_use8pt7b);
display.setCursor(60, 100);
display.println("C");
display.getTextBounds(String(weather["weather"][0]["main"].as<char *>()), 0, 110, &tbx, &tby, &tbw, &tbh);
x = ((75 - tbw) / 2) - tbx;
display.setCursor(x, 120);
display.print(weather["weather"][0]["main"].as<char *>());
const char *code = weather["weather"][0]["icon"];
if (strcmp(code, "01d") == 0)
{
display.drawBitmap(5, 10, clear_d, 64, 64, GxEPD_WHITE);
}
else if (strcmp(code, "01n") == 0)
{
display.drawBitmap(5, 10, clear_n, 64, 64, GxEPD_WHITE);
}
else if (strcmp(code, "02d") == 0)
{
display.drawBitmap(5, 10, cloud_d, 64, 64, GxEPD_WHITE);
}
else if (strcmp(code, "02n") == 0)
{
display.drawBitmap(5, 10, cloud_n, 64, 64, GxEPD_WHITE);
}
else if (strcmp(code, "03d") == 0 || strcmp(code, "03n") == 0)
{
display.drawBitmap(5, 10, cloud, 64, 64, GxEPD_WHITE);
}
else if (strcmp(code, "04d") == 0 || strcmp(code, "04n") == 0)
{
display.drawBitmap(5, 10, clouds, 64, 64, GxEPD_WHITE);
}
else if (strcmp(code, "09d") == 0 || strcmp(code, "09n") == 0)
{
display.drawBitmap(5, 10, rain_h, 64, 64, GxEPD_WHITE);
}
else if (strcmp(code, "10d") == 0)
{
display.drawBitmap(5, 10, rain_l_d, 64, 64, GxEPD_WHITE);
}
else if (strcmp(code, "10n") == 0)
{
display.drawBitmap(5, 10, rain_l_n, 64, 64, GxEPD_WHITE);
}
else if (strcmp(code, "11d") == 0 || strcmp(code, "11n") == 0)
{
display.drawBitmap(5, 10, thunder, 64, 64, GxEPD_WHITE);
}
else if (strcmp(code, "13d") == 0)
{
display.drawBitmap(5, 10, snow_d, 64, 64, GxEPD_WHITE);
}
else if (strcmp(code, "13n") == 0)
{
display.drawBitmap(5, 10, snow_n, 64, 64, GxEPD_WHITE);
}
else if (strcmp(code, "50d") == 0)
{
display.drawBitmap(5, 10, mist_d, 64, 64, GxEPD_WHITE);
}
else if (strcmp(code, "50n") == 0)
{
display.drawBitmap(5, 10, mist_n, 64, 64, GxEPD_WHITE);
}
}
void updateWeather() {
client.setTimeout(10000);
if (!client.connect("api.openweathermap.org", 80))
{
display.println(F("Connection failed"));
return;
}
Serial.println(F("Connected!"));
// Send HTTP request
client.println(F("GET /data/2.5/weather?id=2745909&units=metric&APPID=eb45aa1fa0246863cfa095c79e361e3f HTTP/1.0"));
client.println(F("Connection: close"));
if (client.println() == 0)
{
display.println(F("Failed to send request"));
return;
}
// Check HTTP status
char status[32] = {0};
client.readBytesUntil('\r', status, sizeof(status));
// It should be "HTTP/1.0 200 OK" or "HTTP/1.1 200 OK"
if (strcmp(status + 9, "200 OK") != 0)
{
display.print(F("Unexpected response: "));
display.println(status);
return;
}
// Skip HTTP headers
char endOfHeaders[] = "\r\n\r\n";
if (!client.find(endOfHeaders))
{
display.println(F("Invalid response"));
return;
}
// Parse JSON object
DeserializationError error = deserializeJson(weather, client);
if (error)
{
display.print(F("deserializeJson() failed: "));
display.println(error.c_str());
return;
}
}
void setup()
{
Serial.begin(115200);
display.init(115200); // enable diagnostic output on Serial
delay(10);
Serial.println("T5 Dashboard "__DATE__" "__TIME__);
display.fillScreen(GxEPD_WHITE);
display.setTextColor(GxEPD_BLACK);
display.setFont(&Pixeltype8pt7b);
display.setRotation(1);
display.setPartialWindow(0, 0, display.width(), display.height());
display.firstPage();
display.setCursor(0, 12);
display.println("TTGO T5 V2.3 ePaper");
display.println("T5 Dashboard, "__DATE__" "__TIME__);
display.nextPage();
WiFiMulti.addAP("SSID", "Password");
if (int stat = WiFiMulti.run() != WL_CONNECTED)
{
Serial.println(WiFi.status());
display.print("WiFi connection failed");
display.println(stat);
display.nextPage();
esp_deep_sleep_start();
}
display.printf("WiFi connected to ");
display.println(WiFi.SSID());
display.print("IP address: ");
display.println(WiFi.localIP());
display.nextPage();
ArduinoOTA
.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH)
type = "sketch";
else // U_SPIFFS
type = "filesystem";
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
Serial.println("Start updating " + type);
})
.onEnd([]() {
Serial.println("\nEnd");
})
.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
})
.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR)
Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR)
Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR)
Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR)
Serial.println("Receive Failed");
else if (error == OTA_END_ERROR)
Serial.println("End Failed");
});
ArduinoOTA.begin();
display.println("ArduinoOTA started");
display.nextPage();
interval = timeinfo.tm_sec * 1000;
t = millis();
updateWeather();
delay(1000);
configTime(3600, 3600, "pool.ntp.org");
display.fillScreen(GxEPD_WHITE);
drawTime();
drawWeather();
display.nextPage();
}
void loop()
{
ArduinoOTA.handle();
dt = millis() - t;
t = millis();
if (interval >= 60 * 1000)
{
display.fillScreen(GxEPD_WHITE);
if (refresh >= 5)
{
refresh = 0;
display.setFullWindow();
display.firstPage();
display.nextPage();
display.setPartialWindow(0, 0, display.width(), display.height());
}
else
{
refresh++;
}
if (update >= 15) {
update = 0;
updateWeather();
} else {
update++;
}
drawTime();
drawWeather();
display.nextPage();
interval = timeinfo.tm_sec * 1000;
}
else
{
interval += dt;
}
}