ESP32电子墨水屏日历
多年来,我一直在尝试打破实体日历和数字日历之间的障碍 - 创建可以挂在客厅/厨房中的美观电子墨水日历。现在这个想法以非常令人满意的方式实现了,我很想分享自己是如何实现它的。
日历能够显示特定用户在选定的Google日历中的前9个事件。我选了我太太、我自己和我们两个共同的家庭日历。除日历外,我还在日历的角上创建了一个微型天气,显示来自OpenWeather Maps的图标以及温度和风速。
该项目使用了7.5 Waveshare电子墨水屏、ESP32微控制器和LIPO电池。采用13x18宜家Ribba像框包装。除了微控制器的Arduino代码外,我还创建了一个脚本来从Google提取日历项。
归功于Git上的ESP32电子墨水气象站项目,在编写该项目时我从中学到了很多。
在此处找到该项目的代码:https://github.com/kristiantm/eink-family-calendar-esp32
感谢Ibsendk对instructable和代码进行了对错和完整性检查。
耗材:
总费用:〜 100欧元
作为替代方案,Waveshare提供了带有E-Ink端口的自定义ESP32单元(可以避免接线)-但LOLIN32没有随附的电池插头,因此必须通过5V移动电源为其供电或自行接线连接到3V和GND连接器上。
步骤1 将屏幕连接到ESP32开发板
屏幕随附一根连接器电缆,可以将其直接连接到开发板上。但我发现占用了像框太多空间,决定使用自己的电线连接电路板。
Waveshare 7.5 ↔ LOLIN32
Vcc ↔ 3V
GND ↔ GND
DIN ↔ 14
CLK ↔13
CS ↔ 15
DC ↔ 27
RST ↔ 26
BUSY ↔25
可以下载GxEPD2库来测试连接。如果使用的是Visual Studio Code,可以通过PlatformIO获取,也可以通过Arduino的库来获取。
要使用正确的引脚来初始化显示,在库中的示例中使用以下代码:
GxEPD2_3C display(GxEPD2_750c_Z08(/*CS=*/ 15, /*DC=*/ 27, /*RST=*/ 26, /*BUSY=*/ 25));
完成示例工作(在显示屏上获取演示文本/图形)后,继续进行下一步。
步骤2 从Google日历获取事件
Google的日历难以集成,我不得不通过Google脚本进行变通,使日历条目可访问。
在scripts.google.com上创建一个新的web应用来获得访问权限,然后将下面的代码粘贴到其中。
- 转到scripts.google.com并选择新项目
- 将下面代码粘贴到其中
- 用一个“好”名字来保存
4。 点击“Publish”,然后选择“Anyone, even anonymous”作为安全设置
- 在项目中根据需要复制链接"https://script.google.com/macros/s/[UNIQUE CODE]/exec"
注:获得链接的任何人都可以获得日历中公开的条目。但链接是唯一的且只有你自己拥有。我也喜欢其他关于集成的想法-但目前这个就可以用了。
将带有UNIQUE CODE的URL粘贴到浏览器中来测试脚本。应该看到用分号分隔的事件列表。在看到此之前,请不要进行下一步。
<p>function doGet(e) {</p><p> var calendars = CalendarApp.getAllCalendars();</p><p>
//var cal = CalendarApp.getCalendarsByName('NAME_OF_CALENDAR')[0]; // 0 is subcalendar ID, mostly "0"
//var cal = CalendarApp.getDefaultCalendar();
var calendars = CalendarApp.getAllCalendars();
if (calendars == undefined) {
Logger.log("No data");
return ContentService.createTextOutput("no access to calendar hubba");
}</p><p> var calendars_selected = [];
for (var ii = 0; ii < calendars.length; ii++) {
if (calendars[ii].isSelected()) {
calendars_selected.push(calendars[ii]);
Logger.log(calendars[ii].getName());
}
}
Logger.log("Old: " + calendars.length + " New: " + calendars_selected.length);</p><p> 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() + 14 * oneday); //get appointments for the next 14 days
//var events = cal.getEvents(start, stop); //pull start/stop time
var events = mergeCalendarEvents(calendars_selected, start, stop); //pull start/stop time
var str = '';
for (var ii = 0; ii < events.length; ii++) {</p><p> var event=events[ii];
var myStatus = event.getMyStatus();
// define valid entryStatus to populate array
switch(myStatus) {
case CalendarApp.GuestStatus.OWNER:
case CalendarApp.GuestStatus.YES:
case CalendarApp.GuestStatus.NO:
case CalendarApp.GuestStatus.INVITED:
case CalendarApp.GuestStatus.MAYBE:
default:
break;
}
// Show just every entry regardless of GuestStatus to also get events from shared calendars where you haven't set up the appointment on your own
str += event.getStartTime() + ';' +
//event.isAllDayEvent() + '\t' +
//event.getPopupReminders()[0] + '\t' +
event.getTitle() +';' +
event.isAllDayEvent() + ';';
}
return ContentService.createTextOutput(str);
}</p><p>function mergeCalendarEvents(calendars, startTime, endTime) {</p><p> var params = { start:startTime, end:endTime, uniqueIds:[] };</p><p> return calendars.map(toUniqueEvents_, params)
.reduce(toSingleArray_)
.sort(byStart_);
}</p><p>function toCalendars_(id) { return CalendarApp.getCalendarById(id); }</p><p>function toUniqueEvents_ (calendar) {
return calendar.getEvents(this.start, this.end)
.filter(onlyUniqueEvents_, this.uniqueIds);
}</p><p>function onlyUniqueEvents_(event) {
var eventId = event.getId();
var uniqueEvent = this.indexOf(eventId) < 0;
if(uniqueEvent) this.push(eventId);
return uniqueEvent;
}</p><p>function toSingleArray_(a, b) { return a.concat(b) }</p><p>function byStart_(a, b) {
return a.getStartTime().getTime() - b.getStartTime().getTime();
}</p>
步骤3 配置项目
现在对ESP32开发板进行编程。
为此可以使用Visual Studio Code(带有Platform IO)或Arduino。
对于这两个平台,请下载代码其到自己的项目库中。
代码链接:https://github.com/kristiantm/eink-family-calendar-esp32
- 确保已安装Platformio并作为工作区打开项目文件夹
- 如果配置正确,PlatformIO应该自己获取所需的库。如果没有,则必须转到PlatformIO / Libraries并安装 "GxEPD2" 和 "ArduinoJson"
Arduino:
- 转到setting,并将"https://dl.espressif.com/dl/package_esp32_index.json" 粘贴到"Additional Boards manager URL"中
(译注:应为首选项Preferences,不是setting)
- 转到Tools/Boards/Boards Manager(工具/主板/主板管理器)。搜索ESP32并安装开发板套件。
- 选择WEMOS LOLIN32板(或你自己购买的板型号)
- 转到库管理器并安装"GxEPD2" 和 "ArduinoJson"
从这里开始,你必须专注于调整credentials.h。
设置wifi上网ssid和密码
<p>// Change to your WiFi credentials<br>const char* ssid1 = "[YOUR_NETWORK_SSID]"; // For your network
const char* password1 = "[YOUR_NETWORK_KEY]"; // For your network</p>
注册并获取OpenWeatherMaps.com的API:
// Use your own API key by signing up for a free developer account at <a href="https://openweathermap.org/" rel="nofollow"> https://openweathermap.org/<br>String ><br>String OWMapikey = "[YOUR OPEN WEATHERMAPS API]"; <br>
更改你的位置信息来获取当地天气 - 谷歌地图是获取纬度和经度的好伙伴:
String City = "Copenhagen"; // Your home city See: <a href="http://bulk.openweathermap.org/sample/" rel="nofollow"> <a href="http://bulk.openweathermap.org/sample/" rel="nofollow"> http://bulk.openweathermap.org/sample/
</a>
</a>
String Lattitude = "[YOUR_LATTITUDE]"; // Your lattitude - use google maps
String Longitude = "[YOUR_LONGITUDE]"; // Your longitude - use google maps
String Country = "Denmark"; // Your country
String Language = "EN"; // NOTE: Only the weather description (not used) is translated by OWM
复制Google的webapp网址,获取你的个人事件:
char calendarServer[] = "script.google.com"; <br>String calendarRequest = "https://script.google.com/macros/s/[YOUR_UNIQUE_ID]/exec"; // Write the path for your google script to fetch calendar events
剩下的部分你可以在第一次让它工作的时候继续。
现在单击compile“编译”,希望不会报任何错误。一切就绪后,使用Microusb线将LOLIN32板连接至计算机,并对板子进行编程。
如果一切顺利,约20秒后看到Waveshare面板刷新,显示接下来14天的活动以及当地天气。如果没有显示,尝试串行连接到LOLIN32板提供的COM端口(通过Windows中的设备管理器识别端口号)。可以使用类似PuTTY的程序连接到串行端口,并观察在什么地方链路断开了。
步骤4 启用电池电量测量
为避免电池完全放电,需要启用电池测量仪。
项目中的代码会读取电池的当前电压,并在屏幕上显示电池图标,显示满电量、3/4电量、1/2电量、1/4电量或电量耗尽。电量耗尽后,项目会进入永久性深度睡眠状态,直到再次充电。
如果主板是LOLIN D32,电池测量值已经内置在GPIO35引脚中-只需要在代码"uint8_t batteryPin = 35"中调整该引脚即可。