電子ペーパーをカレンダーとして使用する

# きっかけ
5年ぐらい前に作ったやつだけど、せっかくなので投稿してみるか

当時の自分「電子ペーパーの書き換え回数は数万回って聞いたことあるので、1日1回書き換えるカレンダーとして使えば人間の寿命と同じぐらい長く使えるんじゃね？」

ちなみに用意したe-Paperはこれ

https://www.waveshare.com/7.5inch-e-Paper-HAT-B.htm

![71H5Zaat0kL._AC_SL1440_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513034/2c6cd0ed-4b4c-febd-29e8-972729a92125.jpeg)


# 実装手順

- 以下手順で電子ペーパーを動作させる環境を構築する
・電子ペーパーをラズパイのSPIポートに接続する
・SPIの設定を有効化する
・BCM2835ライブラリをインストールする
・必要なPythonのライブラリをインストールする
・メーカーのサンプルプログラムをダウンロードする
→ https://github.com/waveshareteam/e-Paper
<br>
↓詳細はこちら

https://qiita.com/_shin_/items/0e9e7804531368ff0e90


　今回は7.5inchの赤黒白モデルを買ったので以下のサンプルプログラムを使ってカレンダーを描画するプログラムを作る


- `epd_7in5b_V2_test.py`を以下の通り編集する(リファクタリングは後で...)
  ※コード中に登場する日本語フォントはaptでインストールしていた気がする...
  ~追記~
  日本語フォントは以下コマンドでインストールする
  ```
  $ sudo apt install fonts-noto-cjk
  ```
  
```e-paper/main/RaspberryPi&JetsonNano/python/examples/epd_7in5b_V2_test.py
#!/usr/bin/python
# -*- coding:utf-8 -*-
import sys
import os
picdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'pic')
libdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib')
if os.path.exists(libdir):
    sys.path.append(libdir)

import logging
from waveshare_epd import epd7in5bc_V2
import time
from PIL import Image,ImageDraw,ImageFont,ImageFilter
import traceback
import RPi.GPIO as GPIO
import datetime
import calendar
import jpholiday
logging.basicConfig(level=logging.DEBUG)

GPIO.setmode(GPIO.BCM)
GPIO.setup(23, GPIO.OUT)
GPIO.output(23, GPIO.HIGH)
dt_now = datetime.datetime.now()
day = dt_now.day

def write_cal():        
    try:

        
        #初期化
        epd = epd7in5bc_V2.EPD()
        epd.init()
        epd.Clear()
        time.sleep(1)
        
        #黒色イメージのオブジェクトを作成
        imBlack = Image.new("RGBA",(800,480),"white")
        #赤色イメージのオブジェクトを作成
        imRed = Image.new("RGBA",(800,480),"white")
        
        #黒色の描画をするためのオブジェクト?を作成
        drawBlack = ImageDraw.Draw(imBlack)
        #赤色の描画をするためのオブジェクト?を作成
        drawRed = ImageDraw.Draw(imRed)

        #黒色で枠を描画
        drawBlack.rectangle((0, 0, 799, 479), fill=(255, 255,255), outline=(0, 0, 0), width=3)
        drawBlack.rectangle((0, 0, 799, 60), fill=(0, 0, 0), outline=(0, 0, 0))
        drawBlack.line((0, 60, 799, 60), fill=(0, 0, 0), width=2)
        drawBlack.line((0, 40, 799, 40), fill=(255, 255, 255), width=2)

        #一週間は7日なので縦に7等分する線を描画
        h = 70
        l = 800 / 7
        for  i in [1,2,3,4,5,6]:
            drawBlack.line((0, 60 + i * h, 799, 60 + i * h), fill=(0, 0, 0), width=2)
            drawBlack.line((i * l, 60, i * l, 799), fill=(0, 0, 0), width=2)
            drawBlack.line((i * l, 40, i * l, 60), fill=(255, 255, 255), width=2)

        #年、月、和名、曜日のフォントを定義
        cal_year_font_path = ImageFont.truetype('/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',28)
        cal_month_font_path = ImageFont.truetype('/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',28)
        cal_wamei_font_path = ImageFont.truetype('/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',28)
        cal_week_font_path = ImageFont.truetype('/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc',18)

        #描画する文字列を定義
        cal_year = str(dt_now.year) + "年"
        cal_month = str(dt_now.month) + "月"
        wamei = {1:"睦月",2:"如月",3:"弥生",4:"卯月",5:"皐月",6:"水無月",7:"文月",8:"葉月",9:"長月",10:"神無月",11:"霜月",12:"師走"}
        if dt_now.month in wamei:
            cal_wamei = "ー " + wamei[dt_now.month] + " ー"
        else:
            cal_wamei = ""
        week = {0:"Sun.",1:"Mon.",2:"Tue.",3:"Wed.",4:"Thu.",5:"Fri.",6:"Sat."}
        n = 0
        x = 20

        #年、月、和名を描画
        drawBlack.text((10, 0), cal_year , fill=(255, 255, 255), font=cal_year_font_path)
        drawBlack.text((395, 0), cal_month , fill=(255, 255, 255), font=cal_month_font_path)
        drawBlack.text((600, 0), cal_wamei , fill=(255, 255, 255), font=cal_wamei_font_path)

        #曜日を描画
        while n in range(len(week)):
            cal_week = week[n]
            drawBlack.text((x, 38), cal_week , fill=(255, 255, 255), font=cal_week_font_path)
            x = x + 800 / 7
            n = n + 1

        font_path = ImageFont.truetype('/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc',26)
        week_set = {0:"1",1:"2",2:"3",3:"4",4:"5",5:"6",6:"0"}
        first_week = int(week_set[first_day.weekday()])
        frag = 0

        #日付を描画
        for j in range(1, calendar.monthrange(dt_now.year, dt_now.month)[1]+1):
            text5 = str(j)
            day_x = int(week_set[datetime.datetime(dt_now.year, dt_now.month, j).weekday()])
            if j > 1 and day_x == 0:
                frag = frag + 1

            #祝日と土日を赤色に描画
            if day_x == 0 or day_x == 6 or jpholiday.is_holiday(datetime.date(dt_now.year, dt_now.month, j)) == True:
                drawRed.rectangle(( 1 + day_x * 800 / 7, 61 + frag * 70, (day_x + 1)* 800 /7 , 60 + (frag + 1)* 70), fill=(180, 180, 180), outline=(0, 0, 0))
            #今日を黒丸に描画
            if j == dt_now.day:
                drawBlack.chord((day_x * 800 / 7, 60 + frag * 70, (day_x + 1)* 800 /7- 75, 60 + (frag + 1)* 70 - 32), 0, 360, fill=(0, 0,0))
                drawBlack.text((5 + day_x * 800 / 7, 60 + frag * 70), text5 , fill=(255, 255, 255), font=font_path)
            else:
                drawBlack.text((5 + day_x * 800 / 7, 60 + frag * 70), text5 , fill=(0, 0, 0), font=font_path)


        drawBlack.rectangle((0, 0, 799, 479), fill=None, outline=(0, 0, 0), width=3)

        #黒色と赤色の描画イメージをビットマップで保存
        imBlack.save("/home/pi/e-Paper/RaspberryPi&JetsonNano/python/pic/Black.bmp")
        imRed.save("/home/pi/e-Paper/RaspberryPi&JetsonNano/python/pic/Red.bmp")


        # Drawing on the image
        logging.info("3.read bmp file")
        HBlackimage = Image.open('/home/pi/e-Paper/RaspberryPi&JetsonNano/python/pic/Black.bmp', 'r' )
        HRYimage = Image.open('/home/pi/e-Paper/RaspberryPi&JetsonNano/python/pic/Red.bmp', 'r' )
        epd.display(epd.getbuffer(HBlackimage), epd.getbuffer(HRYimage))
        time.sleep(2)

        # Post process
        epd.sleep()
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(23, GPIO.OUT)
        GPIO.output(23, GPIO.LOW)
        GPIO.cleanup()

    except IOError as e:
        logging.info(e)

    except KeyboardInterrupt:
        logging.info("ctrl + c:")
        epd7in5bc_V2.epdconfig.module_exit()
        exit()


dt_now = datetime.datetime.now()
first_day = datetime.datetime(dt_now.year, dt_now.month, 1)
write_cal()

```

　動かしてみるとこんな感じ
 
![IMG_2185.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513034/b91afcb5-2276-b529-95e7-a005a793eb04.jpeg)


さらに、cronで上記Pythonスクリプトを日付が変わるタイミングで実行すると、自動で更新されるカレンダーになる