added content: google calendar

via google apps script, see /data/calendar.txt
This commit is contained in:
Nic Limper
2023-03-23 23:40:06 +01:00
parent 059ab15722
commit e19c9dc612
6 changed files with 168 additions and 5 deletions

View File

@@ -0,0 +1,46 @@
To use Google Apps Script to get all events for the next day and return them via JSON in a web app, you can follow these steps:
Create a new Google Apps Script project by going to https://script.google.com and clicking on "New project".
In the script editor, create a new function called "getEventsForNextDay" that will fetch all events for the next day and return them in JSON format:
function getEventsForNextDay() {
var start = new Date();
var end = new Date();
end.setDate(end.getDate() + 1);
var calendars = CalendarApp.getAllCalendars();
var events = [];
for (var i = 0; i < calendars.length; i++) {
var calendar = calendars[i];
var eventsInCalendar = calendar.getEvents(start, end);
for (var j = 0; j < eventsInCalendar.length; j++) {
var event = eventsInCalendar[j];
events.push({
title: event.getTitle(),
start: Math.floor(event.getStartTime().getTime() / 1000),
end: Math.floor(event.getEndTime().getTime() / 1000),
location: event.getLocation(),
description: event.getDescription()
});
}
}
// Sort events by start date/time
events.sort(function(a, b) {
return a.start - b.start;
});
return JSON.stringify(events);
}
function doGet() {
var content = getEventsForNextDay();
var output = ContentService.createTextOutput(content);
output.setMimeType(ContentService.MimeType.JSON);
return output;
}
This function calls the getEventsForNextDay() function to get the events in JSON format, creates a text output with the JSON content, sets the MIME type to JSON, and returns the output.
Deploy the web app by clicking on "Deploy > New Deployment" in the script editor. Choose "Web app" as the deployment type, set the access to "Anyone, even anonymous", and click on "Deploy". Make sure to take note of the web app URL generated by Google.
Test the web app by visiting the web app URL in a web browser. You should see the events for the next day in JSON format.

View File

@@ -35,6 +35,7 @@
<option value="6">memo text</option>
<option value="7">image url</option>
<option value="10">qr code</option>
<option value="11">google calendar</option>
<option value="5">firmware update</option>
</select>
</p>

View File

@@ -8,7 +8,7 @@ const WAKEUP_REASON_FIRSTBOOT = 0xFC;
const WAKEUP_REASON_NETWORK_SCAN = 0xFD;
const WAKEUP_REASON_WDT_RESET = 0xFE;
const contentModes = ["Static image", "Current date", "Counting days", "Counting hours", "Current weather", "Firmware update", "Memo text", "Image url", "Weather forecast", "RSS feed", "QR code"];
const contentModes = ["Static image", "Current date", "Counting days", "Counting hours", "Current weather", "Firmware update", "Memo text", "Image url", "Weather forecast", "RSS feed", "QR code", "Calendar"];
const models = ["1.54\" 152x152px", "2.9\" 296x128px", "4.2\" 400x300px"];
const displaySizeLookup = { 0: [152, 152], 1: [128, 296], 2: [400, 300] };
const colorTable = { 0: [255, 255, 255], 1: [0, 0, 0], 2: [255, 0, 0], 3: [255, 0, 0] };
@@ -24,6 +24,7 @@ contentModeOptions[7] = ["url","interval"];
contentModeOptions[8] = ["location"];
contentModeOptions[9] = ["title", "url", "interval"];
contentModeOptions[10] = ["title", "qr-content"];
contentModeOptions[11] = ["title", "apps_script_url", "interval"];
const imageQueue = [];
let isProcessing = false;

View File

@@ -26,7 +26,8 @@ void drawWeather(String &filename, String location, tagRecord *&taginfo, imgPara
void drawForecast(String &filename, String location, tagRecord *&taginfo, imgParam &imageParams);
void drawIdentify(String &filename, tagRecord *&taginfo, imgParam &imageParams);
bool getImgURL(String &filename, String URL, time_t fetched, imgParam &imageParams);
bool getRSSfeed(String &filename, String URL, String title, tagRecord *&taginfo, imgParam &imageParams);
bool getRssFeed(String &filename, String URL, String title, tagRecord *&taginfo, imgParam &imageParams);
bool getCalFeed(String &filename, String URL, String title, tagRecord *&taginfo, imgParam &imageParams);
void drawQR(String &filename, String qrcontent, String title, tagRecord *&taginfo, imgParam &imageParams);
char *formatHttpDate(time_t t);
String urlEncode(const char *msg);

View File

@@ -79,5 +79,5 @@ monitor_port = COM21
build_flags =
-D SIMPLE_AP=2
-D PINOUT=SIMPLE_AP
src_filter =
build_src_filter =
+<*>-<usbflasher.cpp>

View File

@@ -31,6 +31,7 @@ enum contentModes {
Forecast,
RSSFeed,
QRcode,
Calendar,
};
void contentRunner() {
@@ -180,7 +181,7 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
case RSSFeed:
if (getRSSfeed(filename, cfgobj["url"], cfgobj["title"], taginfo, imageParams)) {
if (getRssFeed(filename, cfgobj["url"], cfgobj["title"], taginfo, imageParams)) {
taginfo->nextupdate = now + 60 * (cfgobj["interval"].as<int>() < 5 ? 5 : cfgobj["interval"].as<int>());
updateTagImage(filename, mac, cfgobj["interval"].as<int>(), imageParams);
} else {
@@ -194,6 +195,17 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
taginfo->nextupdate = now + 12 * 3600;
updateTagImage(filename, mac, 0, imageParams);
break;
case Calendar:
if (getCalFeed(filename, cfgobj["apps_script_url"], cfgobj["title"], taginfo, imageParams)) {
taginfo->nextupdate = now + 60 * (cfgobj["interval"].as<int>() < 5 ? 5 : cfgobj["interval"].as<int>());
updateTagImage(filename, mac, cfgobj["interval"].as<int>(), imageParams);
} else {
taginfo->nextupdate = now + 300;
}
break;
}
taginfo->modeConfigJson = doc.as<String>();
@@ -595,7 +607,7 @@ bool getImgURL(String &filename, String URL, time_t fetched, imgParam &imagePara
rssClass reader;
bool getRSSfeed(String &filename, String URL, String title, tagRecord *&taginfo, imgParam &imageParams) {
bool getRssFeed(String &filename, String URL, String title, tagRecord *&taginfo, imgParam &imageParams) {
// https://github.com/garretlab/shoddyxml2
// http://feeds.feedburner.com/tweakers/nieuws
@@ -649,6 +661,108 @@ bool getRSSfeed(String &filename, String URL, String title, tagRecord *&taginfo,
return true;
}
char *epoch_to_display(time_t utc) {
static char display[6];
struct tm local_tm;
localtime_r(&utc, &local_tm);
time_t now;
time(&now);
struct tm now_tm;
localtime_r(&now, &now_tm);
if (local_tm.tm_year < now_tm.tm_year ||
(local_tm.tm_year == now_tm.tm_year && local_tm.tm_mon < now_tm.tm_mon) ||
(local_tm.tm_year == now_tm.tm_year && local_tm.tm_mon == now_tm.tm_mon && local_tm.tm_mday < now_tm.tm_mday) ||
(local_tm.tm_hour == 0 && local_tm.tm_min == 0)) {
strftime(display, sizeof(display), "%d-%m", &local_tm);
} else {
strftime(display, sizeof(display), "%H:%M", &local_tm);
}
return display;
}
bool getCalFeed(String &filename, String URL, String title, tagRecord *&taginfo, imgParam &imageParams) {
// google apps scripts method to retrieve calendar
// see /data/calendar.txt for description
wsLog("get calendar");
time_t now;
time(&now);
struct tm timeinfo;
localtime_r(&now, &timeinfo);
HTTPClient http;
http.begin(URL);
http.setTimeout(10000); // timeout in ms
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
int httpCode = http.GET();
if (httpCode != 200) {
wsErr("http error " + String(httpCode));
return false;
}
DynamicJsonDocument doc(5000);
DeserializationError error = deserializeJson(doc, http.getString());
if (error) {
wsErr(error.c_str());
}
http.end();
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite spr = TFT_eSprite(&tft);
U8g2_for_TFT_eSPI u8f;
u8f.begin(spr);
if (taginfo->hwType == SOLUM_29_033) {
initSprite(spr, 296, 128);
if (title == "" || title == "null") title = "Calendar";
u8f.setFont(u8g2_font_t0_22b_tr); // select u8g2 font from here: https://github.com/olikraus/u8g2/wiki/fntlistall
u8f.setFontMode(0);
u8f.setFontDirection(0);
u8f.setForegroundColor(PAL_BLACK);
u8f.setBackgroundColor(PAL_WHITE);
u8f.setCursor(5, 16);
u8f.print(title);
// u8g2_font_nine_by_five_nbp_tr
// u8g2_font_7x14_tr
// u8g2_font_crox1h_tr
// u8g2_font_miranda_nbp_tr
// u8g2_font_glasstown_nbp_tr
// select u8g2 font from here: https://github.com/olikraus/u8g2/wiki/fntlistall
int n = doc.size();
if (n>7) n=7;
for (int i = 0; i < n; i++) {
JsonObject obj = doc[i];
String eventtitle = obj["title"];
String startz = obj["start"];
time_t starttime = obj["start"];
time_t endtime = obj["end"];
if (starttime<now && endtime>now) {
u8f.setFont(u8g2_font_t0_14b_tr);
u8f.setForegroundColor(PAL_WHITE);
u8f.setBackgroundColor(PAL_RED);
spr.fillRect(0, i * 15 + 21, 296, 14, PAL_RED);
} else {
u8f.setFont(u8g2_font_t0_14_tr);
u8f.setForegroundColor(PAL_BLACK);
u8f.setBackgroundColor(PAL_WHITE);
}
u8f.setCursor(5, 32 + i * 15);
u8f.print(epoch_to_display(obj["start"]));
u8f.setCursor(50, 32 + i * 15);
u8f.print(eventtitle);
}
}
spr2buffer(spr, filename, imageParams);
spr.deleteSprite();
return true;
}
void drawQR(String &filename, String qrcontent, String title, tagRecord *&taginfo, imgParam &imageParams) {
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite spr = TFT_eSprite(&tft);