Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
|
I got some gift card money and decided to try making something with ESP8266. While I was adding to my cart I saw a deal on OLED screens too. Once I got past "Hello World". This is what I came up with.
I first thought I was going to use something like IFTTT but soon realized I could go direct for what I wanted. The trick is to use Google Apps Script.
Google Apps Scripthttps://www.google.com/script/start/
Create the script for you calendar that you want to use. I created a new calendar named "Countdown". This is a separate calendar just for this device. I am not sure about the security, but I don't care who knows about my countdown calendar.
Once you save and confirm that it is working. You will need to publish it as a web app.
If you want more calendars or the phases of the moon, repeat above. I only was interested in the new moon, so I filtered on that and only have the one graphic. It is up to you to expand the code if you want more phases to display.
The wiring is pretty simple, and so is the code. I am using the WiFi manger library to make it more portable. The WiFi manager allows you to move it from access point to access point without having to update your code.
Go ahead and modify how you see fit. I started with one calendar then added another and moved everything around.
function doGet(e) {
// name of you calendar
var cal = CalendarApp.getCalendarsByName('Countdown')[0];
if (cal === undefined) {
return ContentService.createTextOutput('no access to calendar');
}
const now = new Date();
var start = new Date(); start.setHours(0, 0, 0); // start at midnight
const oneday = 24*3600000; // [msec]
const stop = new Date(start.getTime() + 365 * oneday);
var events = cal.getEvents(start, stop);
var str = '';
var event=events[0];
var startDate=event.getStartTime();
var daysTil = Math.ceil(((startDate - now) / oneday));
//Logger.log(daysTil);
str += event.getTitle() + '\t' + daysTil +'\n';
return ContentService.createTextOutput(str);
}
function doGet(e) {
var cal = CalendarApp.getCalendarsByName('Phases of the Moon')[0];
if (cal === undefined) {
return ContentService.createTextOutput('no access to calendar');
}
const now = new Date();
var start = new Date(); start.setHours(0, 0, 0); // start at midnight
const oneday = 24*3600000; // [msec]
const stop = new Date(start.getTime() + 30 * oneday);
var events = cal.getEvents(start, stop, {search: 'Full moon'});
var str = '';
var event=events[0];
var startDate=event.getStartTime();
var daysTil = Math.ceil(((startDate - now) / oneday));
var moonStart = event.getTitle().slice(10);
// Logger.log(daysTil);
// Logger.log(moonStart);
str += moonStart + '\t' + daysTil +'\n';
return ContentService.createTextOutput(str);
}
#include <Arduino.h>
#include <U8g2lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g2(U8G2_R0, D2, D1, U8X8_PIN_NONE); // All Boards without Reset of the Display
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
#include "HTTPSRedirect.h"
//Connection Settings
const char* host = "script.google.com";
const char* googleRedirHost = "script.googleusercontent.com";
const int httpsPort = 443;
const String delimeter = "|";
String eventTitle = "";
String eventCount = "";
String eventTitle2 = "";
String eventCount2 = "";
String eventTime2 = "";
//
static const unsigned char fullmoon_xbm[] U8X8_PROGMEM = {
0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x80, 0x83, 0x70, 0x00, 0x00,
0x00, 0x60, 0x81, 0xC0, 0x01, 0x00, 0x00, 0x98, 0x00, 0x21, 0x06, 0x00,
0x00, 0x46, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x21, 0x50, 0x81, 0x26, 0x00,
0x80, 0x00, 0x48, 0x9B, 0x4F, 0x00, 0x40, 0x12, 0xA0, 0x00, 0xFF, 0x00,
0x20, 0x04, 0xE9, 0x2A, 0x86, 0x01, 0x10, 0x12, 0xF2, 0x11, 0x40, 0x02,
0x10, 0x08, 0xD2, 0xF7, 0xC2, 0x02, 0x88, 0x85, 0xE9, 0xFE, 0x79, 0x05,
0x88, 0x22, 0xC8, 0x77, 0xFA, 0x04, 0x84, 0x44, 0xFA, 0xFF, 0xFF, 0x08,
0xE4, 0x9B, 0x08, 0xFF, 0xFD, 0x08, 0xC6, 0x0D, 0x3C, 0x37, 0x74, 0x11,
0xA6, 0x0D, 0x80, 0x2E, 0x30, 0x15, 0xC2, 0xA3, 0x38, 0xFC, 0x00, 0x11,
0xE5, 0x09, 0x0A, 0xC8, 0x00, 0x29, 0xC9, 0x55, 0x33, 0x00, 0x40, 0x33,
0xB1, 0x8B, 0x02, 0x00, 0x08, 0x24, 0xEB, 0x17, 0x01, 0x00, 0x50, 0x20,
0x83, 0x46, 0x2B, 0x00, 0x00, 0x30, 0x6F, 0xA1, 0x51, 0x00, 0x00, 0x20,
0xF7, 0xC0, 0x06, 0x00, 0x10, 0x20, 0x8D, 0x10, 0x02, 0x00, 0x00, 0x20,
0xBF, 0x8A, 0x80, 0x00, 0x00, 0x30, 0x3F, 0x10, 0x16, 0x00, 0x00, 0x30,
0xBE, 0x48, 0x18, 0x00, 0x00, 0x10, 0xFE, 0x11, 0xDB, 0x00, 0x00, 0x10,
0x7E, 0x9A, 0x74, 0x00, 0x08, 0x10, 0xFC, 0xCF, 0x0F, 0x00, 0x00, 0x08,
0xEC, 0xBF, 0xFF, 0x00, 0x02, 0x08, 0xF8, 0xFF, 0xAF, 0x41, 0x00, 0x04,
0xE8, 0xBF, 0xE1, 0x00, 0x00, 0x04, 0xD0, 0xEF, 0xC1, 0x00, 0x04, 0x02,
0x90, 0x5B, 0x5D, 0x00, 0x00, 0x03, 0x60, 0x8F, 0x17, 0x02, 0x00, 0x01,
0x40, 0xE8, 0x77, 0x00, 0x80, 0x00, 0x80, 0x50, 0x77, 0x01, 0x40, 0x00,
0x00, 0x01, 0x05, 0x00, 0x20, 0x00, 0x00, 0x0E, 0x04, 0x04, 0x18, 0x00,
0x00, 0x18, 0x00, 0x08, 0x06, 0x00, 0x00, 0x60, 0x40, 0x80, 0x01, 0x00,
0x00, 0x80, 0x33, 0x72, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00,
};
unsigned long previousMillis = 0;
const long interval = 3600000;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.flush();
//WiFiManager
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
//reset settings - for testing
//wifiManager.resetSettings();
//sets timeout until configuration portal gets turned off
//useful to make it all retry or go to sleep
//in seconds
wifiManager.setTimeout(180);
//fetches ssid and pass and tries to connect
//if it does not connect it starts an access point with the specified name
//here "AutoConnectAP"
//and goes into a blocking loop awaiting configuration
if(!wifiManager.autoConnect("AutoConnectAP")) {
Serial.println("failed to connect and hit timeout");
delay(3000);
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(5000);
}
//if you get here you have connected to the WiFi
Serial.println("connected... :)");
u8g2.begin();
// init calendars
//replace with you gscript ids
getCalendar1("BHfycWje68avEHz6n09mOPsMWTq_Y7JHuGBNIC320jAmm2aYiE");
getCalendar2("MKfl1QedMs5004Z35Fer9HxgPDfuSHP8olhkJJ8yICn3H8H_Fn");
}
void loop() {
u8g2.firstPage();
do {
calendar1();
} while ( u8g2.nextPage() );
delay(10000);
u8g2.firstPage();
do {
calendar2();
} while( u8g2.nextPage() );
delay(10000);
// update calendar each hour
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
getCalendar1("BHfycWje68avEHz6n09mOPsMWTq_Y7JHuGBNIC320jAmm2aYiE");
getCalendar2("MKfl1QedMs5004Z35Fer9HxgPDfuSHP8olhkJJ8yICn3H8H_Fn");
}
}
//Get calendar entries from google
String fetchDataFromGoogle(String GScriptId) {
String url = String("/macros/s/") + GScriptId + "/exec";
HTTPSRedirect client(httpsPort);
Serial.print("Connecting to ");
Serial.println(host);
if (!client.connected())
client.connect(host, httpsPort);
String data = client.getData(url, host, googleRedirHost);
// Serial.println(data);
return(data);
}
String getValue(String data, char separator, int index)
{
int found = 0;
int strIndex[] = { 0, -1 };
int maxIndex = data.length() - 1;
for (int i = 0; i <= maxIndex && found <= index; i++) {
if (data.charAt(i) == separator || i == maxIndex) {
found++;
strIndex[0] = strIndex[1] + 1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}
void calendar1(){
u8g2.setFont(u8g2_font_helvB08_tr);
u8g2.setCursor(0, 14);
u8g2.print(eventTitle);
if (eventCount == "today"){
u8g2.setFont(u8g2_font_logisoso24_tr);
u8g2.setCursor(20, 44);
}else{
u8g2.setFont(u8g2_font_logisoso46_tr);
u8g2.setCursor(0, 64);
}
u8g2.print(eventCount);
}
void getCalendar1(String GScriptId){
String data = fetchDataFromGoogle(GScriptId);
// Serial.println(data);
eventTitle = getValue(data, '\t', 0);
eventCount = getValue(data, '\t', 1);
if (eventCount.toInt()>0) {
eventCount = String(eventCount + "d");
} else {
eventCount = "today";
}
Serial.println(eventTitle);
Serial.println(eventCount);
}
void calendar2(){
u8g2.setFont(u8g2_font_helvB08_tr);
u8g2.setFontMode(1);
u8g2.setCursor(0, 14);
u8g2.print(eventTitle2);sub
if (eventCount2 == "today"){
u8g2.setFont(u8g2_font_logisoso24_tr);
u8g2.setCursor(20, 44);
}else{
u8g2.setFont(u8g2_font_logisoso24_tr);
u8g2.setCursor(54, 44);
}
u8g2.print(eventCount2);
u8g2.setFont(u8g2_font_logisoso16_tr);
u8g2.setCursor(54, 64);
u8g2.print("DAYS");
u8g2.drawXBM(0, 18, 46, 46, fullmoon_xbm);
}
void getCalendar2(String GScriptId){
String data = fetchDataFromGoogle(GScriptId);
// Serial.println(data);
eventTime2 = getValue(data, '\t', 0);
eventCount2 = getValue(data, '\t', 1);
if (eventCount.toInt()>9) {
eventCount2 = String("0" + eventCount2);
}
eventTitle2 = "New Moon @ " + eventTime2;
Serial.println(eventTitle2);
Serial.println(eventCount2);
}
Comments