added misc helper scripts

This commit is contained in:
Nic Limper
2024-03-22 11:55:11 +01:00
parent 587d7c86c0
commit b7e0d1af93
7 changed files with 390 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
# Google Calendar
To use the 'clandar' content type, you need a helper script, using Google Apps Script. 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](https://script.google.com) and clicking on "New project".
* Paste the content of the calendar.js file into the editor
This App Script 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 'run as' to 'me', and the access to "Anyone, even anonymous"
* 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

@@ -0,0 +1,38 @@
function getEventsForNextDay(days) {
var start = new Date();
start.setHours(0, 0, 0, 0);
var end = new Date();
if (days == undefined) days = 1;
end.setDate(end.getDate() + parseInt(days, 10));
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({
calendar: i,
title: event.getTitle(),
start: Math.floor(event.getStartTime().getTime() / 1000),
end: Math.floor(event.getEndTime().getTime() / 1000),
isallday: event.isAllDayEvent()
});
}
}
events.sort(function(a, b) {
return a.start - b.start;
});
return JSON.stringify(events);
}
function doGet(e) {
if(!e) {
e = {parameter: {days: 1}};
}
const params = e.parameter;
var content = getEventsForNextDay(params.days);
var output = ContentService.createTextOutput(content);
output.setMimeType(ContentService.MimeType.JSON);
return output;
}

View File

@@ -0,0 +1,3 @@
# Day Ahead Energy Prices
Note: this script is for reference and documentation only. You don't need to deploy it yourself to use the Day Ahead content in OpenEpaperLink, as it makes use of a common install.

View File

@@ -0,0 +1,189 @@
function doGet(e) {
var logger = Logger.log;
var country = e?.parameter?.country || 'NL';
var cache = CacheService.getScriptCache();
var cachedData = cache.get("output" + country);
if (false && cachedData != null) {
logger('from cache');
return ContentService.createTextOutput(cachedData)
.setMimeType(ContentService.MimeType.JSON);
}
var factor = 1;
if (country.startsWith('NO')) {
// https://github.com/bkper/exchange-app
factor = cache.get("currencyNOK");
if (factor == null) {
// factor = ExchangeApp.convert(1, 'EUR', 'NOK');
factor = 11.4;
cache.put("currencyNOK", factor, 3600 * 24);
}
}
if (country.startsWith('DK')) {
// https://github.com/bkper/exchange-app
factor = cache.get("currencyDKK");
if (factor == null) {
// factor = ExchangeApp.convert(1, 'EUR', 'DKK');
factor = 7.45;
cache.put("currencyDKK", factor, 3600 * 24);
}
}
if (country.startsWith('SE')) {
// https://github.com/bkper/exchange-app
factor = cache.get("currencySEK");
if (factor == null) {
// factor = ExchangeApp.convert(1, 'EUR', 'SEK');
factor = 11.25;
cache.put("currencySEK", factor, 3600 * 24);
}
}
var domain = lookupValue(country);
logger(country + ': ' + domain + ' currency: ' + factor);
var xmlUrl = 'https://web-api.tp.entsoe.eu/api?documentType=A44&out_Domain=' + domain + '&in_Domain=' + domain + '&periodStart=' + getFormattedMidnightUTC(-1) + '&periodEnd=' + getFormattedMidnightUTC(2) + '&securityToken=*********';
var cachedXml = cache.get(xmlUrl);
if (cachedXml) {
logger('Using cached XML content.');
var xmlContent = cachedXml;
} else {
logger('Fetching XML content from ' + xmlUrl);
var response = UrlFetchApp.fetch(xmlUrl);
var xmlContent = response.getContentText();
cache.put(xmlUrl, xmlContent, 3600);
}
xmlContent = xmlContent.replace(/xmlns(:[a-z0-9]+)?=["'][^"']*["']/g, '');
xmlContent = xmlContent.replace(/<([a-z0-9]+):/g, '<').replace(/<\/([a-z0-9]+):/g, '</');
var document = XmlService.parse(xmlContent);
var root = document.getRootElement();
var timeSeriesList = getDescendantsByTagName(root, 'TimeSeries');
if (timeSeriesList.length > 0) {
var jsonData = [];
for (var j = 0; j < timeSeriesList.length; j++) {
var timeSeries = timeSeriesList[j];
var period = timeSeries.getChild('Period');
if (period) {
var startTime = period.getChild('timeInterval').getChildText('start');
logger(startTime);
var points = period.getChildren('Point');
for (var i = 0; i < points.length; i++) {
var position = points[i].getChildText('position');
var priceAmount = points[i].getChildText('price.amount') * factor;
// Convert ISO date to epoch time (in seconds)
var epochTime = new Date(startTime).getTime() / 1000 + (position - 1) * 3600;
jsonData.push({
time: epochTime,
price: parseFloat(priceAmount)
});
}
} else {
logger('Error: No <Period> element found in TimeSeries ' + (j + 1));
}
}
if (jsonData.length > 36) {
jsonData.splice(0, jsonData.length - 36);
}
cache.put("output" + country, JSON.stringify(jsonData), 3600);
logger('All Data: ' + JSON.stringify(jsonData));
return ContentService.createTextOutput(JSON.stringify(jsonData))
.setMimeType(ContentService.MimeType.JSON);
} else {
logger('Error: No <TimeSeries> elements found in Publication_MarketDocument');
return ContentService.createTextOutput('Error: No <TimeSeries> elements found in Publication_MarketDocument');
}
}
function getDescendantsByTagName(element, tagName) {
var matchingElements = [];
function findDescendants(currentElement) {
var children = currentElement.getChildren();
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (child.getName() === tagName) {
matchingElements.push(child);
}
findDescendants(child);
}
}
findDescendants(element);
return matchingElements;
}
function getFormattedMidnightUTC(offsetDays) {
var now = new Date(); // current date and time
var localMidnight = new Date(now.getFullYear(), now.getMonth(), now.getDate() + offsetDays, 0, 0, 0, 0);
var utcMidnight = new Date(localMidnight.getTime());
var year = utcMidnight.getUTCFullYear();
var month = ('0' + (utcMidnight.getUTCMonth() + 1)).slice(-2); // Months are zero-based
var day = ('0' + utcMidnight.getUTCDate()).slice(-2);
var hours = ('0' + utcMidnight.getUTCHours()).slice(-2);
var minutes = ('0' + utcMidnight.getUTCMinutes()).slice(-2);
var formattedTime = year + month + day + hours + minutes;
return formattedTime;
}
// https://transparency.entsoe.eu/content/static_content/Static%20content/web%20api/Guide.html#_areas
function lookupValue(country) {
var countryValues = {
'AT': '10YAT-APG------L',
'BE': '10YBE----------2',
'CH': '10YCH-SWISSGRIDZ',
'CZ': '10YCZ-CEPS-----N',
'DE': '10Y1001A1001A82H',
'DK1': '10YDK-1--------W',
'DK2': '10YDK-2--------M',
'EE': '10Y1001A1001A39I',
'ES': '10YES-REE------0',
'FI': '10YFI-1--------U',
'FR': '10YFR-RTE------C',
'LT': '10YLT-1001A0008Q',
'LU': '10Y1001A1001A82H',
'LV': '10YLV-1001A00074',
'NL': '10YNL----------L',
'NO1': '10YNO-1--------2',
'NO2': '10YNO-2--------T',
'NO3': '10YNO-3--------J',
'NO4': '10YNO-4--------9',
'NO5': '10Y1001A1001A48H',
'PL': '10YPL-AREA-----S',
'RO': '10YRO-TEL------P',
'SE1': '10Y1001A1001A44P',
'SE2': '10Y1001A1001A45N',
'SE3': '10Y1001A1001A46L',
'SE4': '10Y1001A1001A47J',
'SI': '10YSI-ELES-----O',
'SK': '10YSK-SEPS-----K'
};
var value = countryValues[country] || '10YNL----------L';
return value;
}

View File

@@ -0,0 +1 @@
Place the source truetype fonts in this folder

View File

@@ -0,0 +1,15 @@
### Convert your own fonts to .vlw format
Use Processing (https://processing.org/) along with the script in this folder, to convert Truetype fonts to .vlw bitmap fonts.
You have to select a subset of the characters to convert, by providing the unicode ranges, or by providing a list of characters.
### Truetype font sources
We cannot upload the source Truetype files, but these fonts are currently used:
- twcondensed.ttf Tw Cen MT Condensed by Microsoft
- bahnschrift.ttf Bahnschrift by Microsoft
- calibrib.ttf Calibri Bold by Microsoft
- REFSAN.ttf MS Reference Sans Serif
- BellCentennialStd-Address.ttf Bell Centennial Std Address by Adobe

View File

@@ -0,0 +1,129 @@
import java.awt.Desktop;
int curY = 0;
PFont myFont;
PrintWriter logOutput;
void setup() {
size(1200, 1000);
boolean smooth = true;
boolean crisp = false;
curY = 0;
int[] unicodeBlocks = {
0x0021, 0x007E, //Basic Latin, 128, 128, Latin (52 characters), Common (76 characters)
0x0080, 0x00FF, //Latin-1 Supplement, 128, 128, Latin (64 characters), Common (64 characters)
0x0100, 0x017F, //Latin Extended-A, 128, 128, Latin
0x0180, 0x024F, //Latin Extended-B, 208, 208, Latin
//0x0250, 0x02AF, //IPA Extensions, 96, 96, Latin
//0x02B0, 0x02FF, //Spacing Modifier Letters, 80, 80, Bopomofo (2 characters), Latin (14 characters), Common (64 characters)
//0x0030, 0x0039, //Example custom range (numbers 0-9)
//0x0041, 0x005A, //Example custom range (Upper case A-Z)
//0x0061, 0x007A, //Example custom range (Lower case a-z)
//0xF000, 0xF0FF, //weather font
};
int blockCount = unicodeBlocks.length;
int firstUnicode = 0;
int lastUnicode = 0;
char[] charset;
int index = 0, count = 0;
for (int i = 0; i < blockCount; i+=2) {
firstUnicode = unicodeBlocks[i];
lastUnicode = unicodeBlocks[i+1];
if (lastUnicode < firstUnicode) {
delay(100);
System.err.println("ERROR: Bad Unicode range secified, last < first!");
System.err.print("first in range = 0x" + hex(firstUnicode, 4));
System.err.println(", last in range = 0x" + hex(lastUnicode, 4));
while (true);
}
count += (lastUnicode - firstUnicode + 1);
}
charset = new char[count];
for (int i = 0; i < blockCount; i+=2) {
firstUnicode = unicodeBlocks[i];
lastUnicode = unicodeBlocks[i+1];
for (int code = firstUnicode; code <= lastUnicode; code++) {
charset[index] = Character.toChars(code)[0];
index++;
}
}
String str = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_abcdefghijklmnopqrstuvwxyz{|}~°ÄÅÆÖØÚÜßáäåæéíöøúüýąČěľłńŘřŚŠź";
char[] charsetbasic = str.toCharArray();
str = "ACDEFHIJLMNOPRSTUVWZiortzÁØÚČŚŠ0123456789-";
char[] charsetdaynames = str.toCharArray();
str = "0123456789.°-";
char[] charsetnumbers = str.toCharArray();
createAndSaveFont("twcondensed", ".ttf", charsetdaynames, 20, crisp);
createAndSaveFont("bahnschrift", ".ttf", charsetbasic, 20, crisp);
createAndSaveFont("bahnschrift", ".ttf", charsetbasic, 30, crisp);
createAndSaveFont("bahnschrift", ".ttf", charsetnumbers, 70, crisp);
createAndSaveFont("calibrib", ".ttf", charsetbasic, 30, crisp);
createAndSaveFont("calibrib", ".ttf", charset, 16, crisp);
createAndSaveFont("REFSAN", ".ttf", charset, 12, crisp);
createAndSaveFont("BellCentennialStd-Address", ".ttf", charset, 10, crisp);
try {
String path = sketchPath();
Desktop.getDesktop().open(new File(path+"/FontFiles"));
}
catch(IOException e) {
println("Failed to create the file");
}
}
void createAndSaveFont(String fontName, String fontType, char charset[], int fontSize, boolean smooth) {
int displayFontSize = fontSize;
myFont = createFont(fontName+fontType, displayFontSize, smooth, charset);
fill(0, 0, 0);
textFont(myFont);
int gapx = displayFontSize*10/8;
int gapy = displayFontSize*10/8;
int index = 0;
fill(0);
textSize(displayFontSize);
curY += gapy;
for (int y = curY; y < height-gapy; y += gapy) {
int x = 10;
curY = y;
while (x < width) {
int unicode = charset[index];
float cwidth = textWidth((char)unicode) + 2;
if ( (x + cwidth) > (width - gapx) ) break;
text(new String(Character.toChars(unicode)), x, y);
x += cwidth;
index++;
if (index >= charset.length) break;
}
if (index >= charset.length) break;
}
PFont font;
font = createFont(fontName + fontType, fontSize, smooth, charset);
println("Created font " + fontName + str(fontSize) + ".vlw");
try {
print("Saving to sketch FontFiles folder... ");
OutputStream output = createOutput("FontFiles/" + fontName + str(fontSize) + ".vlw");
font.save(output);
output.close();
println("OK!");
delay(100);
}
catch (IOException e) {
println("Doh! Failed to create the file");
}
}