🌟

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

2024/01/29に公開

以前、下のようなM5Stackでポモドーロタイマーを作ったのですが、そのときはCPPだったので次はMicroPythonでやってみようということで移植しました。
https://zenn.dev/shimo_s3/articles/08ad0ba30b6fbd
https://twitter.com/shimo_s3/status/1642849296021331969

できたこと、できなかったこと

できた

とりあえずMicroPythonでも同様のものができた。

できなかった

beep音が出せない。
ファームウェアの問題かもしれない。リセットしたときの音は出るのでいまいち理由が不明

準備

前提: M5StackがPCと接続できていること、Wifiがあること

ファームウェア

焼くためにM5Burnerダウンロードする
とりあえず、micropython用の、M5Stack公式のファームウェアを使う(Ulflow)
UIFlow_Core2 v1.13.1
https://docs.m5stack.com/en/quick_start/core2/mpy
https://qiita.com/gaichi/items/97500751492221020586

M5Stack側の接続をWifiにする。API KEYが出る。

https://flow.m5stack.com/
これにアクセスしてAPI KEYを入力して接続、コードを書く。

参考:
(VSCodeの拡張は使えない、ずっと不具合がでているらしい)

MicroPython感想など

  • 慣れていないのもあり使いにくい。Thonnyというものが人気があるらしい。
  • 書き込みするときに毎回リセットするのが面倒なのだけど、エラーしたときはやり直しで書き込みができる
  • MicroPythonは3.4がベースだそうで、例えばf"{}"が使えなかったりする
  • MicroPythonとCppの位置づけは、PoCとプロダクション、みたいなものらしい。スピード、メモリ、電力消費の観点。参考reddit

コード

import time

from imu import IMU
from m5stack import btnA, btnB, btnC, lcd

# Constants and initial setup
WORK_TIMER_SEC = 25 * 60
BREAK_TIMER_SEC = 5 * 60
STOPPED, RUNNING = 0, 1
UP, SIDE = 0, 1
timer_state = STOPPED
remaining_time = WORK_TIMER_SEC
is_work_timer = True
is_reset_prompt = False
imu = IMU()


def setup_lcd():
    lcd.clear()
    lcd.font(lcd.FONT_DejaVu40)
    lcd.setTextColor(lcd.WHITE)


def beep():
    # NOTE: Cannot use sound via UiFlow
    pass


def get_orientation():
    _, _, az = imu.acceleration
    return UP if abs(az) > 0.8 else SIDE


def update_display():
    bg_color = lcd.RED if is_work_timer else lcd.GREEN
    lcd.clear(bg_color)
    lcd.print(
        "{:02d}:{:02d}".format(*divmod(remaining_time, 60)), lcd.CENTER, lcd.CENTER
    )


def display_reset_prompt():
    lcd.clear(lcd.BLACK)
    lcd.font(lcd.FONT_Default)
    lcd.print("Reset?", lcd.CENTER, 150)
    lcd.print("Yes", 40, 200)
    lcd.print("No", 150, 200)


def handle_reset_prompt():
    global is_reset_prompt, is_work_timer, remaining_time, timer_state
    display_reset_prompt()
    while True:
        time.sleep(0.1)  # Debounce delay
        if btnA.wasPressed():
            is_reset_prompt, is_work_timer, remaining_time, timer_state = (
                False,
                True,
                WORK_TIMER_SEC,
                STOPPED,
            )
            lcd.font(lcd.FONT_DejaVu40)
            break
        elif btnB.wasPressed():
            is_reset_prompt = False
            lcd.font(lcd.FONT_DejaVu40)
            break


def check_buttons():
    global is_reset_prompt
    if btnC.wasPressed():
        is_reset_prompt = True


def update_timer():
    global remaining_time, is_work_timer, timer_state
    if timer_state == RUNNING:
        remaining_time -= 1
        if remaining_time <= 0:
            beep()
            is_work_timer = not is_work_timer
            remaining_time = WORK_TIMER_SEC if is_work_timer else BREAK_TIMER_SEC


def loop():
    global timer_state
    check_buttons()
    if is_reset_prompt:
        handle_reset_prompt()
    else:
        orientation = get_orientation()
        timer_state = STOPPED if orientation == UP else RUNNING
        update_timer()
    update_display()


# Main execution starts here
setup_lcd()
while True:
    loop()
    time.sleep(1)  # Main loop delay

次にやりたいこと

  • 時間を変更できるようにする
  • 音を鳴らす
  • ファイル分割
  • いろいろ適当なので直す(0秒の表示がないとか)

Discussion