查看: 2147|回复: 6

ESP32电子墨水屏日历

[复制链接]

ESP32电子墨水屏日历

202008247221..png

多年来,我一直在尝试打破实体日历和数字日历之间的障碍 - 创建可以挂在客厅/厨房中的美观电子墨水日历。现在这个想法以非常令人满意的方式实现了,我很想分享自己是如何实现它的。

日历能够显示特定用户在选定的Google日历中的前9个事件。我选了我太太、我自己和我们两个共同的家庭日历。除日历外,我还在日历的角上创建了一个微型天气,显示来自OpenWeather Maps的图标以及温度和风速。

202008249404..png

该项目使用了7.5 Waveshare电子墨水屏、ESP32微控制器和LIPO电池。采用13x18宜家Ribba像框包装。除了微控制器的Arduino代码外,我还创建了一个脚本来从Google提取日历项。

202008243190..png

202008242770..png

归功于Git上的ESP32电子墨水气象站项目,在编写该项目时我从中学到了很多。

在此处找到该项目的代码:https://github.com/kristiantm/eink-family-calendar-esp32

感谢Ibsendk对instructable和代码进行了对错和完整性检查。

耗材:

  • Waveshare 7.5英寸E-ink屏幕(800×600版)〜76欧元。购买链接:Amazon.de(链接是黄色(C)的版本,我找不到红色(B)的版本了)
  • Aliexpress上购买LOLIN32 ESP32〜8-9 美元 (我使用的是老版本,不过由于D32或D32 Pro在引脚35上集成了电池电量计,因此也可以用D32或D32 Pro)
  • Amazon.de上的1800 mAHLIPO电池 〜 13 欧元
  • IKEA Ribba 13x18框架 〜 3 欧元(宜家)

总费用:〜 100欧元

作为替代方案,Waveshare提供了带有E-Ink端口的自定义ESP32单元(可以避免接线)-但LOLIN32没有随附的电池插头,因此必须通过5V移动电源为其供电或自行接线连接到3V和GND连接器上。

步骤1 将屏幕连接到ESP32开发板

202008241083..png

屏幕随附一根连接器电缆,可以将其直接连接到开发板上。但我发现占用了像框太多空间,决定使用自己的电线连接电路板。

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的库来获取。

202008244798..png

要使用正确的引脚来初始化显示,在库中的示例中使用以下代码:

GxEPD2_3C display(GxEPD2_750c_Z08(/*CS=*/ 15, /*DC=*/ 27, /*RST=*/ 26, /*BUSY=*/ 25));

完成示例工作(在显示屏上获取演示文本/图形)后,继续进行下一步。

步骤2 从Google日历获取事件

Google的日历难以集成,我不得不通过Google脚本进行变通,使日历条目可访问。

在scripts.google.com上创建一个新的web应用来获得访问权限,然后将下面的代码粘贴到其中。

  1. 转到scripts.google.com并选择新项目
  2. 将下面代码粘贴到其中
  3. 用一个“好”名字来保存
    4。 点击“Publish”,然后选择“Anyone, even anonymous”作为安全设置
  4. 在项目中根据需要复制链接"https://script.google.com/macros/s/[UNIQUE CODE]/exec"

202008244212..png

注:获得链接的任何人都可以获得日历中公开的条目。但链接是唯一的且只有你自己拥有。我也喜欢其他关于集成的想法-但目前这个就可以用了。

将带有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

Platform IO:

  1. 确保已安装Platformio并作为工作区打开项目文件夹
  2. 如果配置正确,PlatformIO应该自己获取所需的库。如果没有,则必须转到PlatformIO / Libraries并安装 "GxEPD2" 和 "ArduinoJson"

Arduino:

  1. 转到setting,并将"https://dl.espressif.com/dl/package_esp32_index.json" 粘贴到"Additional Boards manager URL"中

(译注:应为首选项Preferences,不是setting)

  1. 转到Tools/Boards/Boards Manager(工具/主板/主板管理器)。搜索ESP32并安装开发板套件。
  2. 选择WEMOS LOLIN32板(或你自己购买的板型号)
  3. 转到库管理器并安装"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"中调整该引脚即可。




如果是普通的ESP32,则需要在电池和选定的模拟IO引脚之间插入一个分压器 - 使电池的3.7电压低于开发板能够测量的3V。

在我的设置中,我使用了30K和100K电阻器设置,并从引脚34读取。




设置起来有点复杂,但如果没有设置,在忘记给电池充电时可能会耗尽电量并损坏电池。

步骤5 组装家庭日历

202008241702..png

现在要做的就是将日历妥妥的组装在新的IKEA像框中。Ribba像框非常适合此类IOT项目,它的屏幕和背板之间有一个很大的封闭空间。

202008248117..png

首先将墨水屏放在像框白色垫子的最上方,上下左右调整一下直到满意为止。

把与像框一起的纸放在屏幕的顶部,但引导屏幕连接器滑过像框的一侧。用白色塑料内框将其固定-用宽的一面在屏幕上施加轻微的压力。

将墨水屏连接主板,LOLIN板和电池粘在纸上,使其在连接后自然悬挂。

接通电池后,开发板将启动并刷新屏幕。此时对墨水屏的位置进行最终调整。

关上并固定像框的后盖。考虑加一条短的USB线为像框供电(如图所示,在后盖上切一个小孔)。充电周期为2-3个月。

202008242466..png

你现在是自己独一无二电子墨水屏家庭日历的骄傲拥有者。

原文链接:https://www.instructables.com/id/E-Ink-Family-Calendar-Using-ESP32/
作者: kristiantm
翻译:szjuliet
202008246193..png

eink-family-calendar-esp32-master.zip

722.77 KB, 下载次数: 24

代码

20060606  高级技匠

发表于 2020-8-26 06:41:54

这个屏幕得挺贵
回复

使用道具 举报

unQAzcWF  学徒

发表于 2020-8-26 09:31:41

很时尚的屏幕,想自己做一个!
回复

使用道具 举报

 初级技师

发表于 2020-8-26 21:14:22

不错的项目,我也想自己做一个!
回复

使用道具 举报

DFHJtzlT1q8  学徒

发表于 2020-8-28 15:06:48

低调而不失内涵,不错。
回复

使用道具 举报

gada888  版主

发表于 2020-8-30 15:31:11

这屏很贵的
回复

使用道具 举报

队长911  学徒

发表于 2020-9-9 12:57:43

查了一下造价,相当于人民币800元,就为了显示个日历,有点小贵.
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2020 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail