Skip to content

Commit e6ff4ca

Browse files
committed
inkplate6 google cal project upload
up
1 parent c922201 commit e6ff4ca

22 files changed

+10954
-0
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
Inkplate10_Google_Calendar for Soldered Inkplate 10
3+
4+
Getting Started:
5+
For setup and documentation, visit: https://inkplate.readthedocs.io/en/latest/
6+
7+
Before You Start:
8+
9+
- Enter your WiFi credentials carefully (they are case-sensitive).
10+
11+
- Update the timeZone variable according to your data
12+
13+
- Get Google Calendar public calendar ID and API key:
14+
1. Calendar ID: Go to calendar.google.com > Settings > Select your calendar > "Integrate calendar" > Copy "Calendar ID" (e.g. [email protected]).
15+
2. API Key: Go to console.cloud.google.com > Select/create a project > "APIs & Services" > "Credentials" > "Create credentials" > API key.
16+
Make sure your calendar is public under "Access permissions" in calendar settings.
17+
*/
18+
19+
#include "src/includes.h" // Include necessary libraries and dependencies for Inkplate and networking
20+
21+
const char *ssid = "Soldered-testingPurposes";
22+
const char *password = "Testing443";
23+
24+
int timeZone = 2; // timeZone is the number in (UTC + number) in your time zone UTC + 2 for Osijek, UTC - 4 for New York City
25+
26+
String calendarID = "[email protected]";
27+
String apiKey = "yourapikey";
28+
29+
// String ntpServer = "pool.ntp.org"; // in case you want to use a different one
30+
31+
Inkplate inkplate(INKPLATE_3BIT);
32+
calendarData calendar;
33+
Network network(calendarID, apiKey);
34+
Gui gui(inkplate);
35+
36+
// --- Deep Sleep Configuration ---
37+
#define uS_TO_S_FACTOR 1000000 // Convert microseconds to seconds
38+
#define TIME_TO_SLEEP 600 // Sleep time: 600 seconds = 10 minutes
39+
40+
void setup()
41+
{
42+
Serial.begin(115200); // Initialize serial monitor for debugging
43+
inkplate.begin(); // Start the Inkplate display
44+
inkplate.clearDisplay(); // Clear the screen
45+
inkplate.setRotation(1); // Portrait mode | if it's upside down do setRotation(3);
46+
47+
// Attempt to connect to WiFi
48+
const unsigned long timeout = 30000;
49+
unsigned long startTime = millis();
50+
bool connected = false;
51+
52+
while (!connected && (millis() - startTime) < timeout)
53+
{
54+
connected = inkplate.connectWiFi(ssid, password, 10, true);
55+
}
56+
57+
// If WiFi failed, display error message
58+
if (!connected)
59+
{
60+
gui.wifiError();
61+
}
62+
else
63+
{
64+
configTime(timeZone * 3600, 0, "pool.ntp.org");
65+
// Fetch and display calendar
66+
if (network.fetchCalendar(&calendar))
67+
{
68+
Serial.println("Calendar loaded.");
69+
gui.showCalendar(&calendar);
70+
}
71+
else
72+
{
73+
Serial.println("Failed to load calendar.");
74+
gui.showError("Failed to load calendar.");
75+
}
76+
}
77+
// Sleep to save power; wakes every 10 minutes
78+
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); // Activate wake-up timer -- wake up after 30mins here
79+
esp_deep_sleep_start(); // Put ESP32 into deep sleep.
80+
}
81+
82+
void loop()
83+
{
84+
// Should remain empty, main logic is in the setup();
85+
}
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
#include "Gui.h"
2+
#include <ctime>
3+
4+
// font
5+
#include "fonts/FreeSans9pt7b.h"
6+
#include "fonts/FreeSans12pt7b.h"
7+
#include "fonts/FreeSans18pt7b.h"
8+
#include "fonts/FreeSans48pt7b.h"
9+
#include "fonts/FreeSansBold48pt7b.h"
10+
#include "fonts/FreeSansBold24pt7b.h"
11+
12+
Gui::Gui(Inkplate &inkplate) : inkplate(inkplate) {}
13+
14+
String Gui::getDayName(int dayIndex)
15+
{
16+
const char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
17+
return days[dayIndex];
18+
}
19+
20+
String Gui::getMonthName(int monthIndex)
21+
{
22+
const char *months[] = {"January", "February", "March", "April", "May", "June",
23+
"July", "August", "September", "October", "November", "December"};
24+
return months[monthIndex];
25+
}
26+
27+
String Gui::formatHour(const String &isoDateTime)
28+
{
29+
if (isoDateTime.length() < 16)
30+
return "";
31+
return isoDateTime.substring(11, 16); // "HH:MM" from ISO 8601
32+
}
33+
34+
String Gui::formatDate(const String &isoDateTime)
35+
{
36+
if (isoDateTime.length() < 10)
37+
return "";
38+
return isoDateTime.substring(8, 10); // "YYYY-MM-DD"
39+
}
40+
41+
void Gui::wifiError()
42+
{
43+
inkplate.clearDisplay();
44+
inkplate.setTextColor(0);
45+
inkplate.setFont(&FreeSans18pt7b);
46+
inkplate.setCursor(50, 150);
47+
inkplate.print("WiFi connection failed.");
48+
inkplate.setCursor(50, 200);
49+
inkplate.print("Check credentials or try again.");
50+
inkplate.display();
51+
}
52+
53+
void Gui::drawHeader(const String &title)
54+
{
55+
inkplate.clearDisplay();
56+
inkplate.setTextSize(3);
57+
inkplate.setTextColor(0);
58+
inkplate.setCursor(10, 10);
59+
inkplate.println(title);
60+
}
61+
62+
String Gui::getShortDayName(int dayIndex)
63+
{
64+
const char *shortDays[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
65+
return shortDays[dayIndex];
66+
}
67+
68+
bool Gui::isCurrentEvent(const String &startTimeStr, const String &endTimeStr)
69+
{
70+
struct tm timeInfo;
71+
if (!getLocalTime(&timeInfo))
72+
return false;
73+
time_t now = mktime(&timeInfo);
74+
75+
struct tm startTm = {}, endTm = {};
76+
startTm.tm_year = startTimeStr.substring(0, 4).toInt() - 1900;
77+
startTm.tm_mon = startTimeStr.substring(5, 7).toInt() - 1;
78+
startTm.tm_mday = startTimeStr.substring(8, 10).toInt();
79+
startTm.tm_hour = startTimeStr.substring(11, 13).toInt();
80+
startTm.tm_min = startTimeStr.substring(14, 16).toInt();
81+
82+
endTm.tm_year = endTimeStr.substring(0, 4).toInt() - 1900;
83+
endTm.tm_mon = endTimeStr.substring(5, 7).toInt() - 1;
84+
endTm.tm_mday = endTimeStr.substring(8, 10).toInt();
85+
endTm.tm_hour = endTimeStr.substring(11, 13).toInt();
86+
endTm.tm_min = endTimeStr.substring(14, 16).toInt();
87+
88+
time_t start = mktime(&startTm);
89+
time_t end = mktime(&endTm);
90+
91+
return (now >= start && now <= end);
92+
}
93+
94+
void Gui::showCalendar(calendarData *calendar)
95+
{
96+
inkplate.clearDisplay();
97+
98+
// === Top Section (Black Header Box) ===
99+
inkplate.fillRect(0, 0, 605, 125, 0); // black box
100+
101+
// Get current time
102+
struct tm timeInfo;
103+
if (!getLocalTime(&timeInfo))
104+
{
105+
showError("Time not available");
106+
return;
107+
}
108+
109+
inkplate.setFont(&FreeSansBold48pt7b);
110+
// === Big Date Number (white) ===
111+
inkplate.setTextColor(7);
112+
inkplate.setCursor(10, 85);
113+
inkplate.println(timeInfo.tm_mday);
114+
115+
inkplate.setFont(&FreeSansBold24pt7b);
116+
117+
// === Day of the Week (white) ===
118+
inkplate.setCursor(125, 50);
119+
inkplate.println(getDayName(timeInfo.tm_wday));
120+
121+
// === Month + Year (white) ===
122+
inkplate.setCursor(125, 100);
123+
inkplate.println(getMonthName(timeInfo.tm_mon) + " " + String(1900 + timeInfo.tm_year));
124+
125+
// === Last Updated Section (Top Right) ===
126+
inkplate.setFont(&FreeSans12pt7b);
127+
inkplate.setCursor(430, 38);
128+
inkplate.println("Last Updated:");
129+
130+
char timeString[6]; // HH:MM
131+
sprintf(timeString, "%02d:%02d", timeInfo.tm_hour, timeInfo.tm_min);
132+
133+
inkplate.setCursor(510, 60);
134+
inkplate.println(timeString);
135+
136+
// === Calendar Events ===
137+
Event *events = calendar->getEvents();
138+
int eventCount = calendar->getEventCount();
139+
int y = 150;
140+
int x = 100;
141+
142+
String lastDate = "";
143+
144+
int counter = 0;
145+
146+
for (int i = 0; i < eventCount; i++)
147+
{
148+
149+
inkplate.setFont(&FreeSans18pt7b);
150+
151+
inkplate.setTextColor(0); // black text again
152+
153+
String eventDate = formatDate(events[i].startTime);
154+
155+
// Draw section header if date changes
156+
if (eventDate != lastDate)
157+
{
158+
y += 50;
159+
160+
// Get day of week from date string (assumes format "YYYY-MM-DD")
161+
struct tm timeStruct = {};
162+
timeStruct.tm_year = timeInfo.tm_year; // use current year as fallback
163+
timeStruct.tm_mon = timeInfo.tm_mon; // use current month as fallback
164+
timeStruct.tm_mday = eventDate.toInt(); // parse day from string
165+
mktime(&timeStruct); // normalize to fill in wday
166+
167+
// Date (big, bold)
168+
inkplate.setFont(&FreeSans18pt7b);
169+
inkplate.setTextColor(0);
170+
inkplate.setCursor(10, y);
171+
inkplate.println(eventDate);
172+
173+
// Short Day (under date)
174+
inkplate.setFont(&FreeSans12pt7b);
175+
inkplate.setCursor(10, y + 30);
176+
inkplate.println(getShortDayName(timeStruct.tm_wday));
177+
178+
lastDate = eventDate;
179+
}
180+
181+
inkplate.setFont(&FreeSans18pt7b);
182+
int yLineStart = y;
183+
int xTime = 480;
184+
185+
// Highlight if it's happening now
186+
bool isNow = isCurrentEvent(events[i].startTime, events[i].endTime);
187+
if (isNow)
188+
{
189+
inkplate.fillRoundRect(x - 10, y - 35, 490, 70, 10, 5); // Draw highlight
190+
String summaryLength = events[i].summary;
191+
// inkplate.drawLine(x, y + 15, x + summaryLength.length() * 15, y + 15, 0);
192+
}
193+
194+
// Draw event summary and time
195+
inkplate.setCursor(x, y);
196+
String summary = events[i].summary;
197+
if (summary.length() > MAX_SUMMARY_LENGTH)
198+
{
199+
summary = summary.substring(0, MAX_SUMMARY_LENGTH) + "...";
200+
}
201+
inkplate.println(summary);
202+
inkplate.setCursor(xTime, y);
203+
inkplate.println(formatHour(events[i].startTime));
204+
inkplate.setTextColor(2);
205+
y += 25;
206+
inkplate.setFont(&FreeSans12pt7b);
207+
inkplate.setCursor(xTime + 25, y);
208+
inkplate.println(formatHour(events[i].endTime));
209+
y += 50;
210+
211+
// margin drawing
212+
inkplate.drawLine(70, yLineStart - 43, 70, y - 43, 0);
213+
inkplate.drawLine(71, yLineStart - 43, 71, y - 43, 0);
214+
inkplate.drawLine(72, yLineStart - 43, 72, y - 43, 0);
215+
216+
counter = i;
217+
218+
if (y >= 725) // Stop drawing if out of vertical space
219+
{
220+
break;
221+
}
222+
}
223+
224+
// Show end message
225+
if (counter == eventCount - 1 && y < 775)
226+
{
227+
inkplate.setTextColor(2);
228+
inkplate.setFont(&FreeSans12pt7b);
229+
inkplate.setCursor(100, y + 15);
230+
inkplate.println("No more events in the next 2 weeks!");
231+
}
232+
233+
inkplate.display();
234+
}
235+
236+
// Shows an error message on the display
237+
void Gui::showError(const String &message)
238+
{
239+
inkplate.clearDisplay();
240+
inkplate.setTextSize(2);
241+
inkplate.setTextColor(0);
242+
inkplate.setCursor(10, 10);
243+
inkplate.println("Error:");
244+
inkplate.println(message);
245+
inkplate.display();
246+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#pragma once
2+
3+
#include <Inkplate.h>
4+
#include "calendarData.h"
5+
6+
#define MAX_SUMMARY_LENGTH 22
7+
8+
class Gui {
9+
public:
10+
Gui(Inkplate &inkplate);
11+
void showCalendar(calendarData *calendar);
12+
void showError(const String &message);
13+
void wifiError();
14+
15+
private:
16+
Inkplate &inkplate;
17+
void drawHeader(const String &title);
18+
String getDayName(int dayIndex);
19+
String getMonthName(int monthIndex);
20+
String formatHour(const String &isoDateTime);
21+
String formatDate(const String &isoDateTime);
22+
String getShortDayName(int dayIndex);
23+
bool isCurrentEvent(const String& startTimeStr, const String& endTimeStr);
24+
};

0 commit comments

Comments
 (0)