🍅

M5StackCore2(C)でポモドーロタイマーを作った

2023/04/05に公開

作ったもの

  • ポモドーロタイマー(トマトタイマー)
  • 例えば、赤画面(25分)→緑画面(5分)を無限ループする
    • 設定変更には書き込みが必要
  • タイマーが0になったときに音を鳴らす(+バイブレーション)
  • 立てると実行、倒して画面を上に向けると一時停止
  • 右ボタンで一時停止してリセットするか確認(左ボタン:YES、中ボタン:NO)

TODO

  • メニューダイアログで設定を変えられるようにしたい

デモ

(デモ用に赤10秒、緑5秒)

コード

M5Core2 Version 0.1.5

音を鳴らす部分は公式のisoをそのまま使っています。

  • workTimer_secbreakTimer_secで2つのタイマー時間(秒)を設定
#include <M5Core2.h>
#include <Wire.h>

const int workTimer_sec = 10; // Total time in seconds for the work timer
const int breakTimer_sec = 5; // Total time in seconds for the break timer

enum TimerState {
  STOPPED,
  RUNNING,
  FINISHED
};

enum Orientation {
  Up,
  Side
};

TimerState timerState = STOPPED;
int remainingTime = workTimer_sec; // Initialize with the work timer duration
bool workTimer = true;  // true: work timer (workTimer_sec), false: break timer (breakTimer_sec)
bool resetPrompt = false;
Orientation getOrientation(float xOffset = 0.0, float yOffset = 0.0, float threshold = 0.5) {
  float ax, ay, az;
  M5.IMU.getAccelData(&ax, &ay, &az);

  ax -= xOffset;
  ay -= yOffset;

  if (abs(ax) > threshold || abs(ay) > threshold) {
    return Side;
  }

  return Up; // Default orientation
}

void displayTime(int minutes, int seconds, uint32_t bgColor) {
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setBrightness(200);
  M5.Lcd.fillScreen(bgColor);

  String timeStr = "";
  if (minutes < 10) {
    timeStr += "0";
  }
  timeStr += String(minutes) + ":";
  if (seconds < 10) {
    timeStr += "0";
  }
  timeStr += String(seconds);
  M5.Lcd.setTextFont(7);
  M5.Lcd.setTextSize(1);
  M5.Lcd.setCursor(320 / 2 - 75, 240 / 2 - 25);
  M5.Lcd.print(timeStr);
}

void displayResetPrompt() {
  M5.Lcd.setTextFont(1);
  M5.Lcd.setTextSize(2);
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setBrightness(200);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(60, 150);
  M5.Lcd.print("Reset?");
  M5.Lcd.setCursor(40, 200);
  M5.Lcd.print("Yes");
  M5.Lcd.setCursor(150, 200);
  M5.Lcd.print("No");
}

void setup() {
  M5.begin();
  M5.Lcd.begin();
  M5.IMU.Init();
  M5.Lcd.setBrightness(200);

  int minutes = remainingTime / 60;
  int seconds = remainingTime % 60;

  displayTime(minutes, seconds, workTimer ? RED : GREEN);
}

void loop() {
  M5.update();

  if (resetPrompt) {
    if (M5.BtnA.wasPressed()) {
      resetPrompt = false;
      workTimer = true;
      remainingTime = workTimer_sec;
      int minutes = remainingTime / 60;
      int seconds = remainingTime % 60;
      displayTime(minutes, seconds, workTimer ? RED : GREEN);
    } else if (M5.BtnB.wasPressed()) {
      resetPrompt = false;
      int minutes = remainingTime / 60;
      int seconds = remainingTime % 60;
      displayTime(minutes, seconds, workTimer ? RED : GREEN);
    }
    return;
  }

  static uint32_t timerStart = millis();
  static uint32_t elapsedTime = 0;

  Orientation orientation = getOrientation(0.0, 0.0, 0.5);

  if (orientation == Side && (timerState == STOPPED || timerState == RUNNING)) {
    timerState = RUNNING;

    if (millis() - timerStart >= 1000) {
      elapsedTime += 1000;
      timerStart = millis();
      remainingTime--;

      if (remainingTime >= 0) {
        int minutes = remainingTime / 60;
        int seconds = remainingTime % 60;
        displayTime(minutes, seconds, workTimer ? RED : GREEN);
      } else {
        // Timer has finished
    M5.Axp.SetLDOEnable(3, true); 
    delay(100);
    M5.Axp.SetLDOEnable(3, false);
    delay(100);
    M5.Spk.DingDong(); 
        workTimer = !workTimer; // Switch to the other timer
        remainingTime = workTimer ? workTimer_sec : breakTimer_sec;
        int minutes = remainingTime / 60;
        int seconds = remainingTime % 60;
        displayTime(minutes, seconds, workTimer ? RED : GREEN);
      }
    }
  } else if (orientation == Up) {
    timerState = STOPPED;
  }

  // Right button (Button C) pressed
  if (M5.BtnC.wasPressed()) {
    resetPrompt = true;
    displayResetPrompt();
  }

  if (resetPrompt) {
    if (M5.BtnA.wasPressed()) {
      resetPrompt = false;
      workTimer = true;
      remainingTime = 10;
      int minutes = remainingTime / 60;
      int seconds = remainingTime % 60;
      displayTime(minutes, seconds, workTimer ? RED : GREEN);
    } else if (M5.BtnB.wasPressed()) {
      resetPrompt = false;
      int minutes = remainingTime / 60;
      int seconds = remainingTime % 60;
      displayTime(minutes, seconds, workTimer ? RED : GREEN);
    }
    return;
  }
}

まとめ

  • M5StackCore2でポモドーロタイマーを作りました
  • おおむねChatGPTにコードを書いてもらって細かい修正は自分で
  • あまり電池がもたないのがネックかもしれません

Discussion