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>
|
#include <Arduino.h>
|
||||||
|
|
||||||
extern const unsigned char esphub_lrg [] PROGMEM;
|
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
|
#endif
|
@ -37,6 +37,7 @@ SPIClass hspi(HSPI);
|
|||||||
#include "config_loader.h"
|
#include "config_loader.h"
|
||||||
#include "weather.h"
|
#include "weather.h"
|
||||||
#include "helper_fn.h"
|
#include "helper_fn.h"
|
||||||
|
#include "nextcloud_cal.h"
|
||||||
|
|
||||||
// <Fonts>
|
// <Fonts>
|
||||||
#include <Fonts/FreeMono9pt7b.h>
|
#include <Fonts/FreeMono9pt7b.h>
|
||||||
@ -123,33 +124,63 @@ void setup()
|
|||||||
}
|
}
|
||||||
text_y += line_height;
|
text_y += line_height;
|
||||||
// Check Nextcloud reachable here
|
// 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);
|
displayActiveFeatures(activeFeatures);
|
||||||
bootMsg("Weather Icons sourced from flaticon.com", text_y);
|
bootMsg("Weather Icons sourced from flaticon.com", text_y);
|
||||||
text_y += 2 * line_height;
|
text_y += 2 * line_height;
|
||||||
bootMsg("Starting main loop...", text_y);
|
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;
|
struct tm timeinfo;
|
||||||
if (!getLocalTime(&timeinfo)) {
|
if (!getLocalTime(&timeinfo)) {
|
||||||
Serial.println("Unable to get time, some features will be buggy");
|
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 {
|
do {
|
||||||
display.fillScreen(GxEPD_WHITE);
|
display.fillScreen(GxEPD_WHITE);
|
||||||
display.fillRect(0, 0, 800, 80, GxEPD_BLACK);
|
display.fillRect(0, 0, 800, 80, GxEPD_BLACK); // Header background
|
||||||
displayHeaderText(timeinfo);
|
displayHeaderText(timeinfo);
|
||||||
|
if (activeFeatures.weather && weather.latitude != 0 && weather.longitude != 0) {
|
||||||
displayWeather(weather);
|
displayWeather(weather);
|
||||||
|
}
|
||||||
|
if (!activeFeatures.calendar) { // Temporarily inverse the statenment during tests
|
||||||
|
displayCalendar(timeinfo);
|
||||||
|
}
|
||||||
} while (display.nextPage());
|
} while (display.nextPage());
|
||||||
|
}
|
||||||
|
|
||||||
display.hibernate();
|
display.hibernate();
|
||||||
delay(3600000);
|
delay(3600000); // Sleep for 60 minutes
|
||||||
loopIteration ++;
|
loopIteration++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Places the boot logo in position at the top of the screen
|
// Places the boot logo in position at the top of the screen
|
||||||
void bootLogo() {
|
void bootLogo() {
|
||||||
constexpr int img_x = (800 - 648) / 2;
|
constexpr int img_x = (800 - 648) / 2;
|
||||||
@ -378,18 +409,36 @@ void displayHeaderText(struct tm timeinfo) {
|
|||||||
void displayWeather(WeatherData weather) {
|
void displayWeather(WeatherData weather) {
|
||||||
display.setFont(&FreeMonoBold12pt7b);
|
display.setFont(&FreeMonoBold12pt7b);
|
||||||
display.setTextColor(GxEPD_WHITE);
|
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.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.drawBitmap(5, 27, hi, 22, 22, GxEPD_WHITE); // Draw 'max temp' bitmap
|
||||||
display.setFont(&FreeMonoBold9pt7b);
|
display.setCursor(23, 44);
|
||||||
display.setCursor(18, 44);
|
|
||||||
display.print(String((int)round(weather.daily.temperature_2m_max)) + "°C");
|
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.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.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
|
// Calculate the width of the longest temperature string & adjust x-position of weather bitmap and display
|
||||||
display.setCursor(153, 23);
|
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.print("km/h");
|
||||||
display.setCursor(133, 45);
|
display.setCursor(133, 45);
|
||||||
display.print(String(weather.daily.wind_speed_10m_max));
|
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));
|
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
|
NotableDay notableDays[] = { // Max characters in a notable day is 39 characters
|
||||||
{1, 1, {"New Years Day!"}},
|
{1, 1, {"New Years Day!"}},
|
||||||
|
{1, 2, {"Ninth Day of Christmas"}},
|
||||||
{1, 4, {"National Trivia Day", "World Braille Day"}},
|
{1, 4, {"National Trivia Day", "World Braille Day"}},
|
||||||
{1, 5, {"The Twelfth Night of Christmas"}},
|
{1, 5, {"The Twelfth Night of Christmas"}},
|
||||||
|
{1, 7, {"Festa del Tricolore"}},
|
||||||
|
{1, 8, {"International Typing Day"}},
|
||||||
{1, 16, {"Blue Monday"}},
|
{1, 16, {"Blue Monday"}},
|
||||||
{1, 18, {"Whinnie the Pooh Day"}},
|
{1, 18, {"Whinnie the Pooh Day"}},
|
||||||
{1, 24, {"International Day of Education"}},
|
{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, 25, {"Transatlantic Slavery Remembrance Day"}},
|
||||||
{3, 30, {"International Zero Waste Day"}},
|
{3, 30, {"International Zero Waste Day"}},
|
||||||
{5, 5, {"St. Piran's 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"}},
|
{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, 21, {"Abolishion of Slavery Day"}},
|
||||||
|
{12, 22, {"Dongzhi Festival"}},
|
||||||
|
{12, 23, {"Flag Flying Day (Sweden)", "Festivus"}},
|
||||||
{12, 24, {"Christmas Eve"}},
|
{12, 24, {"Christmas Eve"}},
|
||||||
{12, 25, {"Christmas Day"}},
|
{12, 25, {"Christmas Day"}},
|
||||||
{12, 26, {"Boxing Day"}},
|
{12, 26, {"Boxing Day"}},
|
||||||
{12, 27, {"Epidemic Preparedness 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"}}
|
{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