電子ペーパーモジュール入門

# はじめに
既製品を組み合わせてなるべく短時間で、
電子ペーパーに表示する内容をカスタマイズ可能なプロトタイプを作成することを目的とします。
あくまでプロトタイプなので、費用やオペレーションコストについては考えません。


# 用意するもの
### Raspberry Pi WH Zero WH
[^1]
<img src="https://d2air1d4eqhwg2.cloudfront.net/images/3646/500x500/8d037ed2-9a5b-4619-baa6-9fb208fb9cb8.jpg" width=300>

似たような製品に**Raspberry Pi Zero W**があります。
**Raspberry Pi Zero WH**は**Raspberry Pi Zero W**にピンヘッダが実装されたモデルです。
はんだごてをお持ちでない方には**Raspberry Pi Zero WH**をお勧めします。
スイッチサイエンスさんから購入できます。
[Raspberry Pi Zero WH - スイッチサイエンス](https://www.switch-science.com/catalog/3646/)

### 2.7インチ 264×176 E-Ink 赤/黒/白 3色 電子ペーパーモジュール for RaspberryPi

[^2]
<img src="https://www.sengoku.co.jp/item/images/th800/7b578e208343225488e769f8a6f165c0b2c61f6652dd844fa64a86d25bb7efd4.jpg" width=300>

秋葉原の千石電商さんでも購入できます。
ディスプレイのサイズ・色数のバリエーションがあります。
今回は**2.7inch/赤・黒・白**のモデルを選択しました。
千石電商さんから購入できます。
[WaveShare 13357 2.7インチ 264×176 E-Ink 赤/黒/白 3色 電子ペーパーモジュール for RaspberryPi](https://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=EEHD-58WK)

### microSDカード/microUSB端子に対応した電源
Rapsberry Piを使うなら必須のアイテム。
microSDカードは容量が8GB以上のものを使いましょう。
電源は1.2A以上の給電能力が必要です[^3]。

### （オプショナル）キーボード/miniHDMIケーブル
sshを使わない場合に必要になります。

# Raspberry Pi Zero WHをセットアップする

OSは[こちら](https://www.raspberrypi.org/downloads/raspbian/)からダウンロードできます。
OSは執筆時点（2020/03/28）で最新のRaspibian Buster Liteを採用しました。

microSDにOSを書き込む手順は「Raspberry Pi セットアップ」などのキーワードで検索していただければ日本語の記事がヒットします。
公式からインストールガイドも公開されていますので載せておきます。
[Installing operating system images - Raspberry Pi Documentation](https://www.raspberrypi.org/documentation/installation/installing-images/README.md)

ディスプレイに繋ぐのが面倒な人は、この設定をしておくと初期設定のためにディスプレイに接続する必要がなくなります。
[Raspberry Piの無線LANをmicroSDで設定する - Qiita](https://qiita.com/mascii/items/0d1a280ac58ed8f6f999)

# 電子ペーパーモジュールとRaspberry Pi Zero WHを接続する

こんな風に接続します。
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334984/77ffc5a9-3caf-01d3-950e-cdd57c9de86c.jpeg width=400>

別角度から。
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334984/d74daa77-c6d1-77d7-de83-01f187fcff23.jpeg width=400>


# サンプルコードを実行する

WaveShare社が公開している[公式Wiki](https://www.waveshare.com/wiki/2.7inch_e-Paper_HAT_(B))の通りに作業します。

ターミナルを開き、以下のコマンドを実行してください。

```shell
sudo raspi-config
```

すると設定画面が表示されます。
「Interfacing Options」を選択、
→「SPI」を選択、
→「Yes」を選択してください。
[^4]
<img src="https://www.waveshare.com/w/upload/1/1e/RPI_open_spi.png" width=600/>

以下のコマンドを実行して再起動します

```shell
sudo reboot
```

必要なライブラリをインストールします。

```shell
# install bcm2835 libraries
wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.60.tar.gz
tar zxvf bcm2835-1.60.tar.gz 
cd bcm2835-1.60/
sudo ./configure
sudo make
sudo make check
sudo make install

# install wiringPi libraries
sudo apt-get install wiringpi

# install Python3 libraries
sudo apt-get update
sudo apt-get install python3-pip
sudo apt-get install python3-pil
sudo apt-get install python3-numpy
sudo pip3 install RPi.GPIO
sudo pip3 install spidev
```

Waveshareさんが[GitHubで公開しているリポジトリ](https://github.com/waveshare/e-Paper)をクローンします。

```shell
sudo git clone https://github.com/waveshare/e-Paper
```

サンプルコードのあるディレクトリに移動して実行してみましょう。

```shell
cd e-Paper/RaspberryPi\&JetsonNano/python/examples
sudo python3 epd_2in7b_test.py
```

実行時の様子は動画にしましたので、こちらをご覧ください。2分ぐらいあります。
[![epd_2in7b_test.py](https://i.vimeocdn.com/video/867770427_640.jpg)](https://vimeo.com/399654308)

サンプルコード[^5]をみてみましょう。

```python:epd_2in7b_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 epd2in7b
import time
from PIL import Image,ImageDraw,ImageFont
import traceback

logging.basicConfig(level=logging.DEBUG)

try:
    logging.info("epd2in7b Demo")
    
    epd = epd2in7b.EPD()
    logging.info("init and Clear")
    epd.init()
    epd.Clear()
    time.sleep(1)
    
    # Drawing on the image
    logging.info("Drawing")
    blackimage = Image.new('1', (epd.width, epd.height), 255)  # 255: clear the frame
    redimage = Image.new('1', (epd.width, epd.height), 255)  # 255: clear the frame
    
    font24 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 24)
    font18 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 18)
    

    # Drawing on the Horizontal image
    logging.info("1.Drawing on the Horizontal image...")
    HBlackimage = Image.new('1', (epd.height, epd.width), 255)  # 298*126
    HRedimage = Image.new('1', (epd.height, epd.width), 255)  # 298*126    
    
    drawblack = ImageDraw.Draw(HBlackimage)
    drawred = ImageDraw.Draw(HRedimage)
    drawblack.text((10, 0), 'hello world', font = font24, fill = 0)
    drawblack.text((10, 20), '2.9inch e-Paper', font = font24, fill = 0)
    drawblack.text((150, 0), u'微雪电子', font = font24, fill = 0)    
    drawblack.line((20, 50, 70, 100), fill = 0)
    drawblack.line((70, 50, 20, 100), fill = 0)
    drawblack.rectangle((20, 50, 70, 100), outline = 0)    
    drawred.line((165, 50, 165, 100), fill = 0)
    drawred.line((140, 75, 190, 75), fill = 0)
    drawred.arc((140, 50, 190, 100), 0, 360, fill = 0)
    drawred.rectangle((80, 50, 130, 100), fill = 0)
    drawred.chord((200, 50, 250, 100), 0, 360, fill = 0)
    epd.display(epd.getbuffer(HBlackimage), epd.getbuffer(HRedimage))
    time.sleep(2)
    
    # Drawing on the Vertical image
    logging.info("2.Drawing on the Vertical image...")
    LBlackimage = Image.new('1', (epd.width, epd.height), 255)  # 126*298
    LRedimage = Image.new('1', (epd.width, epd.height), 255)  # 126*298
    drawblack = ImageDraw.Draw(LBlackimage)
    drawred = ImageDraw.Draw(LRedimage)
    
    drawblack.text((2, 0), 'hello world', font = font18, fill = 0)
    drawblack.text((2, 20), '2.9inch epd', font = font18, fill = 0)
    drawblack.text((20, 50), u'微雪电子', font = font18, fill = 0)
    drawblack.line((10, 90, 60, 140), fill = 0)
    drawblack.line((60, 90, 10, 140), fill = 0)
    drawblack.rectangle((10, 90, 60, 140), outline = 0)
    drawred.line((95, 90, 95, 140), fill = 0)
    drawred.line((70, 115, 120, 115), fill = 0)
    drawred.arc((70, 90, 120, 140), 0, 360, fill = 0)
    drawred.rectangle((10, 150, 60, 200), fill = 0)
    drawred.chord((70, 150, 120, 200), 0, 360, fill = 0)
    epd.display(epd.getbuffer(LBlackimage), epd.getbuffer(LRedimage))
    time.sleep(2)
    
    logging.info("3.read bmp file")
    HBlackimage = Image.open(os.path.join(picdir, '2in7b-b.bmp'))
    HRedimage = Image.open(os.path.join(picdir, '2in7b-r.bmp'))
    epd.display(epd.getbuffer(HBlackimage), epd.getbuffer(HRedimage))
    time.sleep(2)
    
    logging.info("4.read bmp file on window")
    blackimage1 = Image.new('1', (epd.height, epd.width), 255)  # 298*126
    redimage1 = Image.new('1', (epd.height, epd.width), 255)  # 298*126    
    newimage = Image.open(os.path.join(picdir, '100x100.bmp'))
    blackimage1.paste(newimage, (50,10))    
    epd.display(epd.getbuffer(blackimage1), epd.getbuffer(redimage1))
    
    logging.info("Clear...")
    epd.init()
    epd.Clear()
    
    logging.info("Goto Sleep...")
    epd.sleep()
        
except IOError as e:
    logging.info(e)
    
except KeyboardInterrupt:    
    logging.info("ctrl + c:")
    epd2in7b.epdconfig.module_exit()
    exit()
```

電子ペーパーに表示したい内容はPillowのImageオブジェクトで渡してあげればいいことがわかります。
`epd.getbuffer()`の第一引数には黒で描画したいイメージを、第二引数には赤で描画したいイメージを指定します。

```python
epd.display(epd.getbuffer(LBlackimage), epd.getbuffer(LRedimage))
```

# カスタマイズしてみた
![e-tag.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334984/760ddb36-5c30-4105-8a74-65903fdcc083.jpeg)


日本語フォントを使うには`ImageFont`でフォントファイルを読み込みます。

[ImageFont Module — Pillow (PIL Fork) 7.0.0 documentation](https://pillow.readthedocs.io/en/stable/reference/ImageFont.html)
# 附録

## 費用

| 項目 | 金額 |
|--:|--:|
| 電子ペーパーモジュール | ¥2,590 |
| Raspberry Pi Zero WH | ¥1,848 |
| microSDカード 16GB | ¥800 |

microSDカードは価格幅が広いので参考程度に。
合計すると¥5,300ぐらいです。
ここには含めませんでしたが、電源も必要です。


## 消費電力

公式サイトのFAQをみるとRaspberry Pi Zero WHの平常時の消費電流は0.15Aです。
電源が近くにないような場面ではモバイルバッテリーによる電力供給も考えられますが、
何時間稼働させられるんでしょうか？

[Pi Zero Wはモバイルバッテリーでどのくらいの時間動作するか](https://denor.jp/pi-zero-w%E3%81%AF%E3%83%A2%E3%83%90%E3%82%A4%E3%83%AB%E3%83%90%E3%83%83%E3%83%86%E3%83%AA%E3%83%BC%E3%81%A7%E3%81%A9%E3%81%AE%E3%81%8F%E3%82%89%E3%81%84%E3%81%AE%E6%99%82%E9%96%93%E5%8B%95%E4%BD%9C)
↑こちらの記事によると、
> 5200mAhのバッテリーで、Pi Zero W本体のみ動作した時間は28時間42分

と書かれています。たかだか1日しか稼働させられないので用途は限られますね。


別の選択肢として、公式から[PoE HAT](https://www.raspberrypi.org/products/poe-hat/)が発売されています。
ただし、対応するモデルは**Raspberry Pi 4 Model BとRaspberry Pi 3 Model B+のみ**です。
これを接続すればイーサネットケーブルで給電できます。

## 電子ペーパーモジュール使用上の注意

目を通すのを忘れがちなユーザマニュアルに大事なことが書いてあったので一部抜粋して掲載します。
[公式ユーザマニュアル](https://www.waveshare.com/w/upload/3/32/2.7inch-e-paper-hat-b-user-manual-en.pdf)

> The e-Paper cannot be powered on for long time, you must set e-Paper to sleep mode or power off when it needn’t refresh, otherwise, e-Paper keeps in high voltage status for long time, which will damage e-Paper and cannot be fixed.

電子ペーパーに電圧をかけた状態をキープすると、電子ペーパーがダメージを受けるのでスリープを設定してください。

> We suggest you update e-Paper once every 24 hours or at least 10 days to update again. Otherwise, ghost of the last content may cannot be cleared.

毎日１回、最低でも10日に１回は電子ペーパーを更新することを推奨します。
そうしないと、ゴーストが生じる恐れがあります。

> The e-Paper cannot refresh directly under sunlight. The refresh steps should be
done indoor

電子ペーパーは日光のあたるところでリフレッシュできません。リフレッシュは屋内でするようにしてください。

## NFC対応電子ペーパー

Waveshareさんから電源不要でNFCで表示切替できる製品が発売されています。
[4.2inch Passive NFC-Powered e-Paper, No Battery, Wireless Powering & Data Transfer](https://www.waveshare.com/4.2inch-nfc-powered-e-paper.htm)
<img src="https://www.waveshare.com/img/devkit/LCD/4.2inch-NFC-Powered-e-Paper/4.2inch-NFC-Powered-e-Paper-Details-02.jpg" width=300>


[^1]: [Raspberry Pi Zero WH - スイッチサイエンス](https://www.switch-science.com/catalog/3646/)より引用
[^2]: [WaveShare 13357 2.7インチ 264×176 E-Ink 赤/黒/白 3色 電子ペーパーモジュール for RaspberryPi](https://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=EEHD-58WK)より引用
[^3]: [FAQs - Raspberry Pi Documentation](https://www.raspberrypi.org/documentation/faqs/#power)のPower > What are the power requirements?を参照
[^4]: [2.7inch e-Paper HAT (B) - Waveshare Wiki](https://www.waveshare.com/wiki/2.7inch_e-Paper_HAT_(B))のRaspberry Pi > Hardware connectionより引用
[^5]: [e-Paper/epd_2in7b_test.py at master · waveshare/e-Paper](https://github.com/waveshare/e-Paper/blob/master/RaspberryPi&JetsonNano/python/examples/epd_2in7b_test.py)