E-Ink Magic Calendar that automatically syncs to Google Calendar and runs off a battery powered Raspberry Pi Zero

Overview

MagInkCal

This repo contains the code needed to drive an E-Ink Magic Calendar that uses a battery powered (PiSugar2) Raspberry Pi Zero WH to retrieve events from a Google Calendar, format it into the desired layout, before pushing it to a Waveshare 12.48" tri-color E-Ink display. Note that the code has only been tested on the specific hardware mentioned, and customization of the code is necessary for it to work with other E-Ink displays or Battery/RTC add-ons. That said, enjoy working on your project and hopefully this helps to jump-start your magic calendar journey.

20210924_175459

Background

Back in 2019, I started a thread in Reddit to bounce an idea I had with the community: to replicate the Android Magic Calendar concept that inspired many DIY projects in the subsequent years. But specifically, I wanted it to run on battery so I could position it anywhere in house, and even hang it on the wall without a wire dangling beneath it. I also wanted the parts to be plug and play since I had neither the desire nor the steady hands needed to solder anything. After sitting on that idea for close to a year, I finally got my act together and ordered the parts I needed for this project. I posted another update to Reddit in 2020, but got overwhelmed with life/work so it took me almost another year before posting the full set of instructions and code here. An update was also posted on Reddit to share this with the community.

Hardware Required

How It Works

Through PiSugar2's web interface, the onboard RTC can be set to trigger the RPi to boot up daily at 6AM. Upon boot, a cronjob on the RPi is triggered to run a Python script that fetches calendar events from Google Calendar for the next few weeks, and formats them into the desired layout before displaying it on the E-Ink display. The RPi then shuts down to conserve battery. The calendar remains displayed on the E-Ink screen, because well, E-Ink...

Some features of the calendar:

  • Battery life is the big question so I'll address it first. I'm getting around 3-4 weeks before needing to recharge the PiSugar2. I'm fairly happy with this but I'm sure this can be extended if I optimize the code further.
  • Since I had the luxury of using red for the E-Ink display, I used it to highlight the current date, as well as recently added/updated events.
  • I don't like having long bars that span across multiple days for multi-day events, so I chose to display only the start and end dates for those events, and adding small left/right arrows accordingly,
  • Given limited space (oh why are large E-Ink screens still so expensive!) and resolution on the display, I could only show 3 events per day and an indicator (e.g. 4 more) for those not displayed
  • The calendar always starts from the current week, and displays the next four (total 35 days). If the dates cross over to the new month, it's displayed in grey instead of black.

MagInkCal Basics

Setting Up Raspberry Pi Zero

  1. Start by flashing Raspberrypi OS Lite to a MicroSD Card.

  2. After setting up the OS, run the following commmand in the RPi Terminal, and use the raspi-config interface to setup Wifi connection, enable SSH, I2C, SPI, and set the timezone to your location.

sudo raspi-config
  1. Run the following commands in the RPi Terminal to setup the environment to run the Python scripts.
sudo apt update
sudo apt-get install python3-pip
sudo apt-get install chromium-chromedriver
pip3 install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
  1. Run the following commands in the RPi Terminal to install the libraries needed to drive the E-Ink display. See this page for more details.
sudo apt-get install python3-pil
sudo pip3 install RPi.GPIO
sudo pip3 install spidev
  1. Run the following commands in the RPi Terminal to install the web interface for PiSugar2 display. See this page for more details. After running the command, you would be able to access the web interface at http://:8421 in your browser. From there you should be able specify when you wish to schedule the PiSugar2 boot up your RPi.
curl http://cdn.pisugar.com/release/Pisugar-power-manager.sh | sudo bash
  1. Download the over the files in this repo to a folder in your PC first.

  2. In order for you to access your Google Calendar events, it's necessary to first grant the access. Follow the instructions here on your PC to get the credentials.json file from your Google API. Don't worry, take your time. I'll be waiting here.

  3. Once done, copy the credentials.json file to the "gcal" folder in this project. Run the following command on your PC. A web browser should appear, asking you to grant access to your calendar. Once done, you should see a "token.pickle" file in your "gcal" folder.

python3 quickstart.py
  1. Copy all the files over to your RPi using your preferred means.

  2. Run the following command in the RPi Terminal to open crontab.

crontab -e
  1. Specifically, add the following command to crontab so that the MagInkCal Python script runs each time the RPi is booted up.
@reboot cd /location/to/your/maginkcal && python3 maginkcal.py
  1. That's all! Your Magic Calendar should now be refreshed at the time interval that you specified in the PiSugar2 web interface!

PS: I'm aware that the instructions above may not be complete, especially when it comes to the Python libraries to be installed, so feel free to ping me if you noticed anything missing and I'll add it to the steps above.

Acknowledgements

Contributing

I won't be updating this code much, since it has been serving me well. Nevertheless, feel free to fork the repo and modify it for your own purpose. At the same time, check out other similar projects, such as InkyCal. It's much more polished and also actively developed.

What's Next

Honestly, the cost of this project is way too high for a single purpose device. Personally, I've been looking at E-Ink tablets that emulate the experience of writing on paper, and allow the users to take notes on the go. Those familiar with this range of products would be aware of the reMarkable tablet, Ratta Supernote, Kobo Elipsa and many others. My next project is likely to enhance one of these devices such that the calendar will be displayed when it's not in use. While this is usually possible by manually setting the sleep screen image / screensaver, I'm looking to have the screensaver updated automatically on a daily basis, like how it was done in this project.

Comments
  • Multiple calendar, add ids in config.json

    Multiple calendar, add ids in config.json

    Hello there, I really liked this project and the idea. I have multiple calendar on my account so I tried to add multiple calendar without changing your code too much.

    opened by emagra 4
  • Long-lived gcal credential?

    Long-lived gcal credential?

    Hi!

    Thanks so much for sharing your project! It has inspired me to adapt it and build my own.

    I noticed that the google calendar credential expires after a couple days, do you know how to get a long-lived credential?

    Thanks again!

    Matt

    opened by mawise 2
  • Error 'NoneType' object has no attribute 'DEV_ModuleInit'

    Error 'NoneType' object has no attribute 'DEV_ModuleInit'

    Hello, firstly thank you very much about your work on this project!! I think it is a great project ;)

    My problem starts when it starts the phase of drawing in the ink waveshare 7.5 inches b, the logs I see are these:

    pi@raspberrypi:~/MagInkCal $ python3 maginkcal.py 
    /usr/lib/python3/dist-packages/requests/__init__.py:91: RequestsDependencyWarning: urllib3 (1.26.7) or chardet (3.0.4) doesn't match a supported version!
      RequestsDependencyWarning)
    Starting daily calendar update
    Invalid time sync command
    Invalid battery output
    Battery level at start: -1.000
    Time synchronised to 2021-11-26 08:28:24.184037+01:00
    Retrieving events between 2021-11-22T00:00:00+01:00 and 2021-12-26T23:59:59.999999+01:00...
    Calendar events retrieved in 0:00:00.630859
    Screenshot captured and saved to file.
    Image colours processed. Extracted grayscale and red images.
    EPD init...
    'NoneType' object has no attribute 'DEV_ModuleInit'
    Completed daily calendar update
    Checking if configured to shutdown safely - Current hour: 8
    

    As you can see, I think the problem is on third to last line:

    'NoneType' object has no attribute 'DEV_ModuleInit'
    

    I inspect a little bit your code and the error occurs in the line 115 of epdconfig.py file : spi.DEV_ModuleInit

    I have searched on internet and this line should initialize the SPI module, but it does not work.

    I have followed your README.md 2 or 3 times to try to see what I could have missed and I am not able to resolve my problem by myself :(

    On the other way I have used the example python code from waveshare and it works correctly: epd_7in5b_V2_test.py

    @speedyg0nz: Could you help me solving this problem to run your project?

    By the way, I am using a Raspberry pi 4b and the SPI is enabled in my Raspberry pi 4b

    An other thing very curios that happens is:

    • When I reboot the raspberry the waveshare example works correctly
    • But if I have tried to run the python3 maginkcal.py before of running waveshare example, the waveshare example does not work, the screen does not show the images of example and the running apparently is the same but faster without waiting the ending of painting of the ink screen of each image.
    • Nevertheless, the python3 maginkcal.py always returns the output on this comment
    opened by popere 1
  • Some fix for sorting events time display and logger print statements

    Some fix for sorting events time display and logger print statements

    Hello there, I have made a new pull because the event was sorted per calendar list in conf file instead of hour. The event list shouldn't be too long (105 element 3 per day 35 days displayed) so I used sorted. Changed get_short_time to avoid useless char (0 in front of 09:00) Add handler in logger to print on STDOUT Feel free to give me feedback about this changes. Cheers!1

    opened by emagra 0
  • Multiple accounts?

    Multiple accounts?

    Any way to use multiple accounts within this project? All of them have CalDAV option (first acc is iCloud, two others are Gmail) Maybe some kind of CalDAV proxy? Before digging into the source code

    opened by leo150 0
  • Quickstart.py may need a current directory declaration

    Quickstart.py may need a current directory declaration

    Hey @speedyg0nz. Just wanted to let you know of an error I ran into and the method I used to fix it. For some reason running the quickstart.py as is returned an error.

    Adding this to line 22 CURR_DIR = os.path.dirname(os.path.realpath(__file__))

    and changing line 39-41 from this: flow = InstalledAppFlow.from_client_secrets_file( 'credentials.json', SCOPES) creds = flow.run_local_server(port=0)

    to this: credential_file=str(CURR_DIR)+'/credentials.json' flow = InstalledAppFlow.from_client_secrets_file( credential_file, SCOPES) creds = flow.run_local_server(port=0)

    That fixed the issue for me. Unfortunately, I'm having trouble replicating it now so I can't specify what the error it threw actually was. Apologies there. Starting from a fresh repo in a new environment doesn't have the issue at all. This is probably an edge case. I think this is an environment thing but thought it worth sharing regardless in case anyone else encounters it in the future.

    opened by pumodi 0
  • CalDav Calendar Integration

    CalDav Calendar Integration

    This PR allows users to pull calendar events from CalDav instead of Gcal. Almost all major calendar providers (gcal, nextcloud) offer a CalDav interface, so this is useful for custom integrations. In my case, I'm using this to sync Nextcloud calendar configs 😄

    I've tried to keep the same code standard that's currently used.

    Configuring to this instead of gcal is done through the config.json file's calendarSource parameter.

    opened by Ge0rg3 0
  • WIP: Add theming and month abbreviation

    WIP: Add theming and month abbreviation

    Work in Progress // yet not testet on mentioned hardware in README.md:

    • Add the possibility to change between a dark and a light theme/style.
      • Just copy the files (.css/.png) within render/stlye_light-folder or render/style_dark-folder
      • replace the existing files (.css/.png) in render-folder to switch between a dark and a light style of the calendar.
    • Add the possibility to use month abbreviation like 'JAN' instead of month number like '1' Adjustable via config.json: "isMonthAbbr": true --> month abrreviation like 'JAN' displays "isMonthAbbr": false --> default value, month number like '1' displays
    opened by christophbaur 1
Owner
null
An open source bike computer based on Raspberry Pi Zero (W, WH) with GPS and ANT+. Including offline map and navigation.

Pi Zero Bikecomputer An open-source bike computer based on Raspberry Pi Zero (W, WH) with GPS and ANT+ https://github.com/hishizuka/pizero_bikecompute

hishizuka 264 Jan 2, 2023
MohammadReza Sharifi 27 Dec 13, 2022
This program automatically runs Python code copied in clipboard

CopyRun This program runs Python code which is copied in clipboard WARNING!! USE AT YOUR OWN RISK! NO GUARANTIES IF ANYTHING GETS BROKEN. DO NOT COPY

vertinski 4 Sep 10, 2021
DiffQ performs differentiable quantization using pseudo quantization noise. It can automatically tune the number of bits used per weight or group of weights, in order to achieve a given trade-off between model size and accuracy.

Differentiable Model Compression via Pseudo Quantization Noise DiffQ performs differentiable quantization using pseudo quantization noise. It can auto

Facebook Research 145 Dec 30, 2022
BarcodeRattler - A Raspberry Pi Powered Barcode Reader to load a game on the Mister FPGA using MBC

Barcode Rattler A Raspberry Pi Powered Barcode Reader to load a game on the Mist

Chrissy 29 Oct 31, 2022
AoT is a system for automatically generating off-target test harness by using build information.

AoT: Auto off-Target Automatically generating off-target test harness by using build information. Brought to you by the Mobile Security Team at Samsun

Samsung 10 Oct 19, 2022
A lightweight Python-based 3D network multi-agent simulator. Uses a cell-based congestion model. Calculates risk, loudness and battery capacities of the agents. Suitable for 3D network optimization tasks.

AMAZ3DSim AMAZ3DSim is a lightweight python-based 3D network multi-agent simulator. It uses a cell-based congestion model. It calculates risk, battery

Daniel Hirsch 13 Nov 4, 2022
Matlab Python Heuristic Battery Opt - SMOP conversion and manual conversion

SMOP is Small Matlab and Octave to Python compiler. SMOP translates matlab to py

Tom Xu 1 Jan 12, 2022
Dynamic vae - Dynamic VAE algorithm is used for anomaly detection of battery data

Dynamic VAE frame Automatic feature extraction can be achieved by probability di

null 10 Oct 7, 2022
Neural Magic Eye: Learning to See and Understand the Scene Behind an Autostereogram, arXiv:2012.15692.

Neural Magic Eye Preprint | Project Page | Colab Runtime Official PyTorch implementation of the preprint paper "NeuralMagicEye: Learning to See and Un

Zhengxia Zou 56 Jul 15, 2022
Technical Indicators implemented in Python only using Numpy-Pandas as Magic - Very Very Fast! Very tiny! Stock Market Financial Technical Analysis Python library . Quant Trading automation or cryptocoin exchange

MyTT Technical Indicators implemented in Python only using Numpy-Pandas as Magic - Very Very Fast! to Stock Market Financial Technical Analysis Python

dev 34 Dec 27, 2022
Magic tool for managing internet connection in local network by @zalexdev

Megacut ✂️ A new powerful Python3 tool for managing internet on a local network Installation git clone https://github.com/stryker-project/megacut cd m

Stryker 12 Dec 15, 2022
Scalable, Portable and Distributed Gradient Boosting (GBDT, GBRT or GBM) Library, for Python, R, Java, Scala, C++ and more. Runs on single machine, Hadoop, Spark, Dask, Flink and DataFlow

eXtreme Gradient Boosting Community | Documentation | Resources | Contributors | Release Notes XGBoost is an optimized distributed gradient boosting l

Distributed (Deep) Machine Learning Community 23.6k Dec 31, 2022
Scalable, Portable and Distributed Gradient Boosting (GBDT, GBRT or GBM) Library, for Python, R, Java, Scala, C++ and more. Runs on single machine, Hadoop, Spark, Dask, Flink and DataFlow

eXtreme Gradient Boosting Community | Documentation | Resources | Contributors | Release Notes XGBoost is an optimized distributed gradient boosting l

Distributed (Deep) Machine Learning Community 20.6k Feb 13, 2021
A large dataset of 100k Google Satellite and matching Map images, resembling pix2pix's Google Maps dataset.

Larger Google Sat2Map dataset This dataset extends the aerial ⟷ Maps dataset used in pix2pix (Isola et al., CVPR17). The provide script download_sat2m

null 34 Dec 28, 2022
This script runs neural style transfer against the provided content image.

Neural Style Transfer Content Style Output Description: This script runs neural style transfer against the provided content image. The content image m

Martynas Subonis 0 Nov 25, 2021
A very impractical 3D rendering engine that runs in the python terminal.

Terminal-3D-Render A very impractical 3D rendering engine that runs in the python terminal. do NOT try to run this program using the standard python I

null 23 Dec 31, 2022
DRLib:A concise deep reinforcement learning library, integrating HER and PER for almost off policy RL algos.

DRLib:A concise deep reinforcement learning library, integrating HER and PER for almost off policy RL algos A concise deep reinforcement learning libr

null 329 Jan 3, 2023