M5StickC Plusでマイポモドーロタイマーを作る

## はじめに

タスクを効率的にこなすための時間管理術として、ポモドーロテクニック[^1]が知られています。これは25分間のタスク集中期間と5分間の休憩期間を繰り返し、タスクをこなしていく手法です。

時間の計測手段はキッチンタイマーでも良いですし、ポモドーロテクニックに特化したWebサービスを利用するのも手です。しかしながらキッチンタイマーはハードとして完成している都合上、機能拡張が難しいです。またWebサービスは便利なのですが周りのノイズが気になります(タイマー起動前についついネットサーフィンしてしまったり…)。
そこで今回、M5StickC Plusと呼ばれる製品を利用して、キッチンタイマーよりも少し高機能なポモドーロタイマーを作りました。
<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61029/80ec932e-ff47-84b6-39ed-b0d4eafc60a0.png">

[^1]: [Wikipedia ポモドーロテクニック](https://ja.wikipedia.org/wiki/%E3%83%9D%E3%83%A2%E3%83%89%E3%83%BC%E3%83%AD%E3%83%BB%E3%83%86%E3%82%AF%E3%83%8B%E3%83%83%E3%82%AF#:~:text=%E3%83%9D%E3%83%A2%E3%83%89%E3%83%BC%E3%83%AD%E3%83%BB%E3%83%86%E3%82%AF%E3%83%8B%E3%83%83%E3%82%AF%EF%BC%88%E8%8B%B1%3A%20Pomodoro,%E3%82%92%E3%80%8C%E3%83%9D%E3%83%A2%E3%83%89%E3%83%BC%E3%83%AD%E3%80%8D%E3%81%A8%E5%91%BC%E3%81%B6%E3%80%82)

## 開発環境

今回用いた環境は以下となります。Windows PCにM5StickC Plusを接続し、プログラムの書き込みを行っています。M5StickC Plusは[スイッチサイエンス](https://www.switch-science.com/catalog/6470/)で購入しました。

- Windows10 Pro
- M5StickC Plus
- Arduino IDE

## M5StickC Plusのセットアップ

M5StickC Plusのセットアップに少し手間取ったので、下記に手順を書いておきます。

### ドライバのインストール

M5StickC Plusの開発を始めるにあたって、PCにドライバをインストールする必要があります。通常、CP2104 Driverと呼ばれるものをインストールすることで、デバイスマネージャーから認識されるようですが、私の環境では"不明なデバイス"と表示されている状況でした。
そこで色々と試してみたところ、[FTDIドライバ](https://www.ftdichip.com/Drivers/VCP.htm)の2.12.26をインストールすることで正常に認識されるようになりました(記事執筆時点の最新バージョンは2.12.28ですが、2.12.28では認識されませんでした)。
デバイスマネージャーで正常に認識されることで、Arduino IDEからの書き込みが可能となります。

### M5StickC Plusでのサンプルプログラムの実行

PCで正常に認識された後、Arduino IDEからM5Stick Cのライブラリをインストールし、サンプルプログラムを動作させてみました。しかし画面表示が小さく、なんだかおかしいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61029/12e9335a-7ff2-af28-3a29-4bf0df3ce602.png)

スイッチサイエンスの商品ページにも書かれていますが、M5StickCとM5StickC Plusではライブラリが異なり、M5StickC Plus用のライブラリをインストールする必要があります。
M5StickC Plus用のライブラリは[GitHub](https://github.com/m5stack/M5StickC-Plus)で公開されています。GitHubのページからzip形式でファイルをダウンロードし、Arduino IDEのスケッチ→ライブラリをインクルード→.ZIP形式のライブラリをインストールから、ダウンロードしたZIPファイルを読み込むことで、M5StickC Plus用のライブラリが利用可能になります。
このライブラリにはFactoryTestのサンプルプログラムしか同梱されていませんが、M5StickCのサンプルプログラムについてもプログラム中の`#include <M5StickC.h>`を`#include <M5StickCPlus.h>`と変更することで実行できます(簡単にしか検証していないので、動かないものもあるかもしれません)。


## ポモドーロタイマーの機能

セットアップが完了したためポモドーロタイマーの製作に入っていきます。今回実装した機能は下記です。

- 液晶にはタイマー、1日のポモドーロ数、累計ポモドーロ数が表示される
- 正面のボタン（BtnA)を押すと25分のカウントダウンタイマー(集中期間)が開始する
- 25分経過するとブザーが鳴り、1日のポモドーロ数と累計ポモドーロ数がカウントアップする。同時に5分のカウントダウンタイマー(休憩期間)が開始する
- タイマーのカウントダウン中に正面のボタンを押すとタイマーがリセットされる
- 下部のボタン(BtnB)を押すと1日のポモドーロ数がリセットされる
- 累計ポモドーロ数は電源OFFされてもリセットされないようにEEPROMに情報を書き込む


## プログラム

上記機能を実装したプログラムは下記のようなものです。
タイマー部分は[M5Stack TFT_Clock_Digitalのサンプル](https://github.com/m5stack/M5Stack/blob/master/examples/Advanced/Display/TFT_Clock_Digital/TFT_Clock_Digital.ino)を参考にしています。


```C
#include <M5StickCPlus.h>
#include "EEPROM.h" 

const uint8_t PomodoroMinute = 25;
const uint8_t BreakMinute = 5;
const uint8_t LcdWidth = 240;
const uint8_t LcdHeight = 135;
const uint8_t Offset = 15;
const int EEPROMAddress = 0;

uint8_t mm = PomodoroMinute;
uint8_t ss = 0;
uint32_t targetTime = 0;

uint8_t dailyPomo = 0;
int totalPomo = 0;

enum Status{
  SLEEP,
  POMODORO,
  BREAK,
};
enum Status status = SLEEP;

void setup(){
  M5.begin();
  M5.Lcd.setRotation(3);
  EEPROM.begin(10);
  totalPomo=EEPROM.read(EEPROMAddress);
  printTime();
  printDailyPomodoro();
  printTotalPomodoro();
}

void loop() {
  M5.update();
  if(M5.BtnA.wasReleased()) {
    // タイマー未起動の場合は起動、起動中の場合はリセット
    alert(1);
    switch(status){
      case SLEEP:
        targetTime = millis() + 1000;
        status = POMODORO;
        break;
      case POMODORO:
      case BREAK:
        mm = PomodoroMinute;
        ss = 0;
        status = SLEEP;
        M5.Lcd.fillScreen(TFT_BLACK);              
        M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);
        break;
    }
  }
  // Pomodoroカウントをリセット
  if(M5.BtnB.wasReleased()) {
    dailyPomo=0;
  }
  // タイマー起動中の場合は1秒ごとにカウントダウン
  if (status == POMODORO || status == BREAK){
    if (targetTime < millis()) {
      targetTime += 1000;
      ss--;
      if (ss == 255) {
        ss = 59;
        mm--;
        if(mm == 255) {
          alert(3);
          // カウントが終了した場合
          switch(status){
            case POMODORO:  // BREAKステータスに移行
              status = BREAK;
              mm = BreakMinute;
              ss = 0;
              // pomodoroカウントをカウントアップ
              dailyPomo++;
              totalPomo++;
              EEPROM.write(EEPROMAddress, totalPomo);
              EEPROM.commit();
              
              M5.Lcd.fillScreen(TFT_DARKCYAN);
              M5.Lcd.setTextColor(TFT_WHITE, TFT_DARKCYAN);
              break;
            case BREAK:  // SLEEPステータスに移行
              status = SLEEP;
              mm = PomodoroMinute;
              ss = 0;
              M5.Lcd.fillScreen(TFT_BLACK);              
              M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);
              break;
          }
        }
      }
    }
  }
  printTime();
  printDailyPomodoro();
  printTotalPomodoro();
}

void printTime() {
  M5.Lcd.setTextSize(8);
  M5.Lcd.setCursor(Offset, Offset);
  M5.Lcd.printf("%02d:%02d", mm, ss);
}

void printDailyPomodoro() {
  M5.Lcd.setTextSize(3);
  M5.Lcd.setCursor(LcdWidth/2 + 8, 80);
  M5.Lcd.printf("%4dP", dailyPomo);  
}

void printTotalPomodoro() {
  M5.Lcd.setTextSize(3);
  M5.Lcd.setCursor(LcdWidth/2 + 8, 110);
  M5.Lcd.printf("%4dP", totalPomo);  
}

void alert(int count) {
  for(int i = 0; i < count; i++){
    M5.Beep.tone(800);
    delay(100);
    M5.Beep.mute();
    delay(100);    
  }
}
```

## 動作の様子

上記プログラムを動作させた様子が以下です。
ボタンを押すとタイマーが始まります。
<img width="400" alt="pomodoro.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61029/5ef263cd-8261-ad35-eb04-35ca061b48c1.gif">

25分経過すると、ポモドーロ数がカウントアップし、5分のタイマーが起動します。
<img width="400" alt="pomodoro2.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61029/3cff3bdd-5fb1-6910-57d2-bca09b4bf9e7.gif">

## おわりに

理想のポモドーロタイマーが欲しい！ということで作ってみましたが、今のところ特に不自由なく活用できています。累計ポモドーロ数が表示されるのが案外良く、数字が徐々に増えていくのが楽しいです。
常時給電しないと25分持たずにバッテリー切れになってしまうので、電源には常に接続しています。万一電源が切れた場合についても、累計ポモドーロ数はEEPROMに記録されているので消失しません。
機能拡張は自由自在であるため、過去の履歴を表示したり、ネットワーク接続してポモドーロ数を外部DBに記録したりしても面白いかもしれません。
マイポモドーロタイマーが欲しい方はぜひ試してみてください！