Calendars now sync
This commit is contained in:
parent
a702f2f9aa
commit
b633bab7cb
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,8 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
extern const unsigned char esphub_lrg [] PROGMEM;
|
||||
extern const unsigned char sun [] PROGMEM;
|
||||
extern const unsigned char full_art_1 [] PROGMEM;
|
||||
|
||||
extern const unsigned char* full_art_array[2];
|
||||
extern const int full_art_array_size;
|
||||
#endif
|
@ -37,6 +37,7 @@ SPIClass hspi(HSPI);
|
||||
#include "config_loader.h"
|
||||
#include "weather.h"
|
||||
#include "helper_fn.h"
|
||||
#include "nextcloud_cal.h"
|
||||
|
||||
// <Fonts>
|
||||
#include <Fonts/FreeMono9pt7b.h>
|
||||
@ -123,33 +124,63 @@ void setup()
|
||||
}
|
||||
text_y += line_height;
|
||||
// Check Nextcloud reachable here
|
||||
// Nextcloud dev check:
|
||||
StartEnd timestamp = calculateStartEnd();
|
||||
String cal_test = downloadICSFile(conf.calUrls[0], String(timestamp.start), String(timestamp.end), conf.calUser, conf.calKey);
|
||||
Serial.println(cal_test);
|
||||
displayActiveFeatures(activeFeatures);
|
||||
bootMsg("Weather Icons sourced from flaticon.com", text_y);
|
||||
text_y += 2 * line_height;
|
||||
bootMsg("Starting main loop...", text_y);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
void loop() {
|
||||
// Loop Vars
|
||||
WeatherData weather;
|
||||
// CalendarData calendar;
|
||||
|
||||
display.setFullWindow(); // Set Full Update Mode
|
||||
if (!activeFeatures.network ||
|
||||
(activeFeatures.homeassistant && haAnybodyHome() < 1)) {
|
||||
displayFullScreenArt(); // Show artwork if no network or nobody is home
|
||||
} else {
|
||||
struct tm timeinfo;
|
||||
if (!getLocalTime(&timeinfo)) {
|
||||
Serial.println("Unable to get time, some features will be buggy");
|
||||
}
|
||||
WeatherData weather = getWeather(conf.latitude, conf.longitude);
|
||||
Serial.printf("Loop iteration %d\n", loopIteration);
|
||||
display.setFullWindow();
|
||||
|
||||
// Fetch weather data if it is active
|
||||
if (activeFeatures.weather) {
|
||||
weather = getWeather(conf.latitude, conf.longitude);
|
||||
}
|
||||
|
||||
// Fetch calendar data if it is active
|
||||
if (activeFeatures.calendar) {
|
||||
// FETCH CALENDAR DATA HERE
|
||||
}
|
||||
|
||||
Serial.printf("Loop iteration %d\n", loopIteration);
|
||||
|
||||
// Update the display
|
||||
do {
|
||||
display.fillScreen(GxEPD_WHITE);
|
||||
display.fillRect(0, 0, 800, 80, GxEPD_BLACK);
|
||||
display.fillRect(0, 0, 800, 80, GxEPD_BLACK); // Header background
|
||||
displayHeaderText(timeinfo);
|
||||
if (activeFeatures.weather && weather.latitude != 0 && weather.longitude != 0) {
|
||||
displayWeather(weather);
|
||||
}
|
||||
if (!activeFeatures.calendar) { // Temporarily inverse the statenment during tests
|
||||
displayCalendar(timeinfo);
|
||||
}
|
||||
} while (display.nextPage());
|
||||
}
|
||||
|
||||
display.hibernate();
|
||||
delay(3600000);
|
||||
delay(3600000); // Sleep for 60 minutes
|
||||
loopIteration++;
|
||||
}
|
||||
|
||||
|
||||
// Places the boot logo in position at the top of the screen
|
||||
void bootLogo() {
|
||||
constexpr int img_x = (800 - 648) / 2;
|
||||
@ -378,18 +409,36 @@ void displayHeaderText(struct tm timeinfo) {
|
||||
void displayWeather(WeatherData weather) {
|
||||
display.setFont(&FreeMonoBold12pt7b);
|
||||
display.setTextColor(GxEPD_WHITE);
|
||||
display.setCursor(5, 23);
|
||||
|
||||
// Display Current Temperature
|
||||
display.setCursor(14, 23);
|
||||
display.print(String((int)round(weather.current.temperature_2m)) + "°C");
|
||||
display.setFont(&FreeMonoBold9pt7b); // Set font for remaining prints
|
||||
|
||||
// Display Max Temp
|
||||
display.drawBitmap(5, 27, hi, 22, 22, GxEPD_WHITE); // Draw 'max temp' bitmap
|
||||
display.setFont(&FreeMonoBold9pt7b);
|
||||
display.setCursor(18, 44);
|
||||
display.setCursor(23, 44);
|
||||
display.print(String((int)round(weather.daily.temperature_2m_max)) + "°C");
|
||||
|
||||
// Display Min Temp
|
||||
display.drawBitmap(5, 50, lo, 22, 22, GxEPD_WHITE); // Draw 'min temp' bitmap
|
||||
display.setCursor(18, 64);
|
||||
display.setCursor(23, 64);
|
||||
display.print(String((int)round(weather.daily.temperature_2m_min)) + "°C");
|
||||
display.drawBitmap(65, 10, getWeatherBitmap(weather.daily.weather_code), 64, 64, GxEPD_WHITE); // Draw Weather Bitmap
|
||||
display.drawBitmap(129, 8, wind, 22, 22, GxEPD_WHITE); // Draw 'wind speed' bitmap
|
||||
display.setCursor(153, 23);
|
||||
|
||||
// Calculate the width of the longest temperature string & adjust x-position of weather bitmap and display
|
||||
int longestTempWidth = 0;
|
||||
int tempMaxWidth = String((int)round(weather.daily.temperature_2m_max)).length();
|
||||
int tempMinWidth = String((int)round(weather.daily.temperature_2m_min)).length();
|
||||
longestTempWidth = max(tempMaxWidth, tempMinWidth);
|
||||
int weather_x = 58; // Default position
|
||||
if (longestTempWidth > 2) {
|
||||
weather_x += (longestTempWidth > 3 ? 9 : 5); // 67 is the correct X value if more than three. =2 will be halfway btwn Default and 67.
|
||||
}
|
||||
display.drawBitmap(weather_x, 8, getWeatherBitmap(weather.daily.weather_code), 64, 64, GxEPD_WHITE); // Draw Weather Bitmap
|
||||
|
||||
// Display wind & gust speed
|
||||
display.drawBitmap(126, 8, wind, 22, 22, GxEPD_WHITE); // Draw 'wind speed' bitmap
|
||||
display.setCursor(150, 23);
|
||||
display.print("km/h");
|
||||
display.setCursor(133, 45);
|
||||
display.print(String(weather.daily.wind_speed_10m_max));
|
||||
@ -397,4 +446,47 @@ void displayWeather(WeatherData weather) {
|
||||
display.print(String(weather.daily.wind_gusts_10m_max));
|
||||
}
|
||||
|
||||
void displayFullScreenArt() {}
|
||||
void displayFullScreenArt() {
|
||||
display.setFullWindow();
|
||||
int randomIdx = random(0, full_art_array_size);
|
||||
display.firstPage();
|
||||
do
|
||||
{
|
||||
display.fillScreen(GxEPD_WHITE);
|
||||
display.drawBitmap(0, 0, full_art_array[randomIdx], 800, 480, GxEPD_BLACK);
|
||||
}
|
||||
while (display.nextPage());
|
||||
}
|
||||
|
||||
void displayCalendar(struct tm timeinfo) {
|
||||
const int cal_y = 80;
|
||||
const int cal_head = 30;
|
||||
const int cal_margin = 30;
|
||||
const char* weekDays[] = {"S", "M", "T", "W", "T", "F", "S"};
|
||||
const char* calNames[] = {"Shared", "Fred", "Jade", "Lucy", "Ava-Rose"};
|
||||
|
||||
// Draw Calendar Lines
|
||||
display.drawLine(0, cal_y + cal_head, 480, cal_y + cal_head, GxEPD_BLACK); // Bottom of Header
|
||||
for (int y = cal_y + cal_head; y <= 480; y += 74) { // Loop to separate into five rows
|
||||
display.drawLine(0, y, 800, y, GxEPD_BLACK);
|
||||
}
|
||||
display.drawLine(cal_margin, cal_y, cal_margin, 480, GxEPD_BLACK); // Right of margin
|
||||
for (int x = cal_margin; x <= 800; x += 154) { // Loop to separate into seven columns
|
||||
display.drawLine(x, cal_y, x, 480, GxEPD_BLACK);
|
||||
}
|
||||
|
||||
// Print Calendar Labels
|
||||
display.setFont(&FreeMonoBold12pt7b);
|
||||
display.setTextColor(GxEPD_BLACK);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
display.setCursor(cal_margin + i * 154 + 10, cal_y + 23);
|
||||
display.print(calNames[i]);
|
||||
}
|
||||
|
||||
// Print Day/Date
|
||||
for (int i = 0; i < 5; i++) {
|
||||
int dayOfWk = (timeinfo.tm_wday + i) % 7;
|
||||
display.setCursor(3, cal_head + i * 74 + 96);
|
||||
display.print(weekDays[dayOfWk]);
|
||||
}
|
||||
}
|
@ -4,8 +4,11 @@
|
||||
|
||||
NotableDay notableDays[] = { // Max characters in a notable day is 39 characters
|
||||
{1, 1, {"New Years Day!"}},
|
||||
{1, 2, {"Ninth Day of Christmas"}},
|
||||
{1, 4, {"National Trivia Day", "World Braille Day"}},
|
||||
{1, 5, {"The Twelfth Night of Christmas"}},
|
||||
{1, 7, {"Festa del Tricolore"}},
|
||||
{1, 8, {"International Typing Day"}},
|
||||
{1, 16, {"Blue Monday"}},
|
||||
{1, 18, {"Whinnie the Pooh Day"}},
|
||||
{1, 24, {"International Day of Education"}},
|
||||
@ -38,12 +41,39 @@ NotableDay notableDays[] = { // Max characters in a notable day is 39 characters
|
||||
{3, 25, {"Transatlantic Slavery Remembrance Day"}},
|
||||
{3, 30, {"International Zero Waste Day"}},
|
||||
{5, 5, {"St. Piran's Day"}},
|
||||
{6, 5, {"St. Boniface's Day"}},
|
||||
{11, 5, {"World Tsunami Awareness Day"}},
|
||||
{11, 14, {"World Diabetes Day"}},
|
||||
{11, 16, {"International Day for Tolerance"}},
|
||||
{11, 19, {"World Toilet Day"}},
|
||||
{11, 20, {"Africa Indistrialisation Day", "World Children's Day"}},
|
||||
{11, 21, {"World Television Day", "World Philosophy Day"}},
|
||||
{11, 24, {"World Conjoined Twins Day"}},
|
||||
{11, 25, {"World Sustainable Transport Day"}},
|
||||
{11, 28, {"Panaman Independence Day", "Bedfordshire Day"}},
|
||||
{11, 29, {"Feast of Illuminata"}},
|
||||
{11, 30, {"St. Andrew's Day", "Computer Security Day"}},
|
||||
{12, 1, {"World AIDS Day"}},
|
||||
{12, 2, {"Day for the Abolition of Slavery"}},
|
||||
{12, 4, {"International Day of Banks"}},
|
||||
{12, 5, {"World Soil Day"}},
|
||||
{12, 7, {"International Civil Aviation Day"}},
|
||||
{12, 9, {"International Anti-Corruption Day"}},
|
||||
{12, 10, {"Human Rights Day"}},
|
||||
{12, 11, {"International Mountain Day"}},
|
||||
{12, 12, {"Internation Day of Neutrality"}},
|
||||
{12, 18, {"Arabic Language Day", "International Migrants Day"}},
|
||||
{12, 20, {"International Human Solidarity Day"}},
|
||||
{12, 21, {"Abolishion of Slavery Day"}},
|
||||
{12, 22, {"Dongzhi Festival"}},
|
||||
{12, 23, {"Flag Flying Day (Sweden)", "Festivus"}},
|
||||
{12, 24, {"Christmas Eve"}},
|
||||
{12, 25, {"Christmas Day"}},
|
||||
{12, 26, {"Boxing Day"}},
|
||||
{12, 27, {"Epidemic Preparedness Day"}},
|
||||
{12, 28, {"Fourth Day of Christmas"}},
|
||||
{12, 29, {"Fifth Day of Christmas"}},
|
||||
{12, 30, {"Sixth Day of Christmas"}},
|
||||
{12, 31, {"New Year's Eve"}}
|
||||
};
|
||||
|
||||
|
87
NewDisplayDriver/esphub/nextcloud_cal.cpp
Normal file
87
NewDisplayDriver/esphub/nextcloud_cal.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <base64.h>
|
||||
#include <Arduino.h>
|
||||
#include <time.h>
|
||||
#include <utility>
|
||||
#include "nextcloud_cal.h"
|
||||
#include "tls_certificates.h"
|
||||
|
||||
String downloadICSFile(const String& url, const String& startTime, const String& endTime, const String& username, const String& password) {
|
||||
WiFiClientSecure client;
|
||||
client.setCACert(letsencrypt_root_ca);
|
||||
|
||||
// Construct full URL with query parameters
|
||||
String fullUrl = url + "?export&start=" + startTime + "&end=" + endTime + "&expand=1";
|
||||
Serial.println("Requesting URL: " + fullUrl);
|
||||
|
||||
// Parse the host and path from the URL
|
||||
int index = fullUrl.indexOf('/');
|
||||
String host = fullUrl.substring(0, index);
|
||||
String path = fullUrl.substring(index);
|
||||
|
||||
// Connect to the server
|
||||
if (!client.connect(host.c_str(), 443)) {
|
||||
Serial.println("Connection failed!");
|
||||
Serial.print("Host: ");
|
||||
Serial.println(host);
|
||||
return "";
|
||||
}
|
||||
|
||||
// Encode credentials in Base64
|
||||
String credentials = username + ":" + password;
|
||||
String authHeader = "Authorization: Basic " + base64::encode(credentials);
|
||||
|
||||
// Send the GET request with the Authorization header
|
||||
client.print(String("GET ") + path + " HTTP/1.1\r\n" +
|
||||
"Host: " + host + "\r\n" +
|
||||
authHeader + "\r\n" +
|
||||
"Connection: close\r\n\r\n");
|
||||
|
||||
// Read the response
|
||||
String response = "";
|
||||
while (client.connected() || client.available()) {
|
||||
response += client.readString();
|
||||
}
|
||||
|
||||
// Check for HTTP status code (assuming response includes headers)
|
||||
int statusCodeStart = response.indexOf(" ") + 1;
|
||||
int statusCodeEnd = response.indexOf(" ", statusCodeStart);
|
||||
int statusCode = response.substring(statusCodeStart, statusCodeEnd).toInt();
|
||||
|
||||
if (statusCode == 200) {
|
||||
// Strip headers if needed
|
||||
int headerEnd = response.indexOf("\r\n\r\n");
|
||||
if (headerEnd != -1) {
|
||||
response = response.substring(headerEnd + 4);
|
||||
}
|
||||
return response;
|
||||
} else {
|
||||
Serial.println("Failed to fetch: " + String(statusCode));
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
StartEnd calculateStartEnd() {
|
||||
struct tm timeinfo;
|
||||
if (!getLocalTime(&timeinfo)) {
|
||||
Serial.println("Failed to obtain time");
|
||||
return {0, 0}; // Return a struct with zero timestamps if time retrieval fails
|
||||
}
|
||||
|
||||
// Calculate 'start' - 00:01 today
|
||||
timeinfo.tm_hour = 0;
|
||||
timeinfo.tm_min = 1;
|
||||
timeinfo.tm_sec = 0;
|
||||
time_t startTimestamp = mktime(&timeinfo);
|
||||
|
||||
// Calculate 'end' - 23:59 10 days later
|
||||
timeinfo.tm_hour = 23;
|
||||
timeinfo.tm_min = 59;
|
||||
timeinfo.tm_sec = 59;
|
||||
timeinfo.tm_mday += 10; // Move forward 10 days
|
||||
time_t endTimestamp = mktime(&timeinfo);
|
||||
|
||||
// Return a struct containing both Unix timestamps
|
||||
StartEnd result = {startTimestamp, endTimestamp};
|
||||
return result;
|
||||
}
|
15
NewDisplayDriver/esphub/nextcloud_cal.h
Normal file
15
NewDisplayDriver/esphub/nextcloud_cal.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef NEXTCLOUD_CAL_H
|
||||
#define NEXTCLOUD_CAL_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <time.h>
|
||||
|
||||
struct StartEnd {
|
||||
time_t start;
|
||||
time_t end;
|
||||
};
|
||||
|
||||
struct StartEnd calculateStartEnd();
|
||||
String downloadICSFile(const String& url, const String& startTime, const String& endTime, const String& username, const String& password);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user