M5Stackでポケ○ンウォッチを再現したい

12 min read読了の目安(約11400字

アローラ!!!!

クソアプリアドベントカレンダー15日目です。
14日目はde_teiu_tkgさんが香ばしいクソアプリをリリースしてくれました!

成果物(結論)

Twitterに動画をあげました

https://twitter.com/vr_min_chan/status/1335204849466494978?s=20

Twitter見れない人向け↓


M5Stackに初めて触る

M5Stackは今年の2月に誕生日祝いとして頂いたのですが、使い道を思いつかずそのまま積んでいました。クソアプリアドベントカレンダーを書くにあたって、こいつを使ってクソアプリが作れないか検討することにしました。

私はこの見た目に既視感を覚えました。なんだこの既視感は……これは…ポケ○ンウォッチ!!!!!! 小中学生だったころのポケ×ン ダイヤモンドパールの記憶を思い出しました。早くリメイク出してくれ!!

今回は 万歩計とか明らかに実装無理だけど 可能な範囲でポケ○ンウォッチを再現してみることにしました。

注意事項

本記事ではM5StackのGUIアプリを開発すべく、M5UI.Flowを使用し、NoCodeでクソアプリを作成します。残念ながらM5UI.Flowを正しく理解していないので、クソみたいな作りになってしまいました。調べてもあまり情報量がなく、心が折れています。知見があるマサカリを投げてくれる心優しいエンジニアはなにとぞ容赦のないマサカリをお願いします。

環境構築(Windows10)

  1. https://m5stack.com/pages/download から M5BurnerCP2014 Driver(CP201X) をダウンロード

  2. インストーラーを起動し、CP201X をインストール

  3. PCとM5StackをUSB接続して、M5Burnerを起動

  4. COMをCOM3、Baudrateを921600にして、UIFLOW(CORE)をDownloadして、Burnする

  5. Burnが終わるとSET UPボタンが一瞬だけ表示されるのでそれを押す(タイミングを逃したら赤ボタンで再起動)

  6. SET UPから「WiFi via AP」を選択し、Wi-Fiの設定を確認して、スマートフォンのWifi設定画面に同様のSSIDが接続可能になるので、接続する

  7. 上記画面に表示されたIPアドレス(192.168.4.1)にスマートフォンのブラウザでアクセスして、使用可能なWi-FiのSSIDとパスワードを設定する。顔文字の画面が出たら成功!

  8. 再度SET UPを開き、Generate new apikeyを選択

  9. 表示されたAPIキーをhttps://flow.m5stack.com/ に入力する(今回はv1.4.5を使用)

上記手順で環境構築は完了です。画面右上の▶ボタンを押すと、M5Stackに自動で作成したアプリが入れられてビルドします。

ソースコード(自動生成されたもの)

実際の作業はGUIの操作でRect(枠)、Label(文字)でほぼすべてを画面に配置し、表示非表示を切り替えて生成しています。GUIは複数選択ができないので、非常に操作がきつかったです。
画面遷移というよりは、DOM操作みたいな、ひとつひとつの表示非表示を切り替えて作りました。絶対ダメなやり方なので、いいやり方があるかもしれません。ちなみに プロジェクトファイル方法がわからなかったので、プロジェクトファイルは消滅しました。

from m5stack import *
from m5ui import *
from uiflow import *

setScreenColor(0x2a8f2a)


page = None


header = M5Title(title="Digital clock", x=3, fgcolor=0xFFFFFF, bgcolor=0x0000FF)
rectangle3 = M5Rect(56, 78, 20, 130, 0x3c3c3c, 0x3c3c3c)
rectangle4 = M5Rect(10, 188, 60, 20, 0x3c3c3c, 0x3c3c3c)
rectangle2 = M5Rect(16, 78, 60, 20, 0x3c3c3c, 0x3c3c3c)
rectangle5 = M5Rect(111, 86, 20, 130, 0x3c3c3c, 0x3c3c3c)
rectangle6 = M5Rect(81, 78, 20, 50, 0x3c3c3c, 0x3c3c3c)
rectangle7 = M5Rect(91, 78, 40, 20, 0x3c3c3c, 0x3c3c3c)
rectangle8 = M5Rect(158, 93, 20, 20, 0x3c3c3c, 0x3c3c3c)
rectangle9 = M5Rect(226, 78, 20, 130, 0x3c3c3c, 0x3c3c3c)
rectangle10 = M5Rect(158, 158, 20, 20, 0x3c3c3c, 0x3c3c3c)
rectangle11 = M5Rect(190, 78, 20, 60, 0x3c3c3c, 0x3c3c3c)
rectangle12 = M5Rect(190, 133, 40, 20, 0x3c3c3c, 0x3c3c3c)
rectangle13 = M5Rect(259, 133, 50, 20, 0x3c3c3c, 0x3c3c3c)
rectangle14 = M5Rect(259, 78, 50, 20, 0x3c3c3c, 0x3c3c3c)
rectangle15 = M5Rect(259, 188, 50, 20, 0x3c3c3c, 0x3c3c3c)
rectangle16 = M5Rect(289, 78, 20, 130, 0x3c3c3c, 0x3c3c3c)
rectangle1 = M5Rect(10, 78, 20, 130, 0x3c3c3c, 0x3c3c3c)
rectangle0 = M5Rect(10, 26, 10, 40, 0x3c3c3c, 0x3c3c3c)
rectangle17 = M5Rect(10, 26, 290, 5, 0x3c3c3c, 0x3c3c3c)
rectangle18 = M5Rect(10, 61, 290, 5, 0x3c3c3c, 0x3c3c3c)
rectangle19 = M5Rect(299, 26, 10, 40, 0x3c3c3c, 0x3c3c3c)
rectangle20 = M5Rect(40, 168, 30, 30, 0x2a8f2a, 0x3d3d3d)
rectangle21 = M5Rect(91, 78, 30, 30, 0x2a8f2a, 0x3d3d3d)
rectangle22 = M5Rect(140, 78, 30, 30, 0x2a8f2a, 0x3d3d3d)
rectangle23 = M5Rect(41, 210, 80, 30, 0x2a8f2a, 0x3d3d3d)
rectangle24 = M5Rect(40, 78, 30, 30, 0x2a8f2a, 0x3d3d3d)
rectangle25 = M5Rect(40, 128, 30, 30, 0x2a8f2a, 0x3d3d3d)
rectangle26 = M5Rect(140, 123, 30, 30, 0x2a8f2a, 0x3d3d3d)
rectangle27 = M5Rect(91, 123, 30, 30, 0x2a8f2a, 0x3d3d3d)
rectangle28 = M5Rect(190, 123, 30, 30, 0x2a8f2a, 0x3d3d3d)
rectangle29 = M5Rect(91, 168, 30, 30, 0x2a8f2a, 0x3d3d3d)
rectangle30 = M5Rect(233, 123, 30, 30, 0x2a8f2a, 0x3d3d3d)
rectangle31 = M5Rect(140, 168, 30, 30, 0x2a8f2a, 0x3d3d3d)
rectangle32 = M5Rect(190, 168, 30, 30, 0x2a8f2a, 0x3d3d3d)
rectangle33 = M5Rect(233, 168, 30, 30, 0x2a8f2a, 0x3d3d3d)
rectangle34 = M5Rect(140, 210, 30, 30, 0x2a8f2a, 0x3d3d3d)
rectangle35 = M5Rect(190, 210, 80, 30, 0x2a8f2a, 0x3d3d3d)
rectangle36 = M5Rect(190, 78, 80, 30, 0x2a8f2a, 0x3d3d3d)
label0 = M5TextBox(56, 35, "* 8 8 8 8 8 8 8 8 8 8", lcd.FONT_DejaVu18, 0x444444, rotate=0)
label1 = M5TextBox(48, 219, "0", lcd.FONT_DejaVu18, 0x444444, rotate=0)
label2 = M5TextBox(48, 177, "1", lcd.FONT_DejaVu18, 0x444444, rotate=0)
label3 = M5TextBox(153, 219, ".", lcd.FONT_DejaVu18, 0x444444, rotate=0)
label4 = M5TextBox(201, 219, "=", lcd.FONT_DejaVu18, 0x444444, rotate=0)
label5 = M5TextBox(101, 177, "2", lcd.FONT_DejaVu18, 0x444444, rotate=0)
label6 = M5TextBox(148, 177, "3", lcd.FONT_DejaVu18, 0x444444, rotate=0)
label7 = M5TextBox(48, 132, "4", lcd.FONT_DejaVu18, 0x444444, rotate=0)
label8 = M5TextBox(101, 132, "5", lcd.FONT_DejaVu18, 0x444444, rotate=0)
label9 = M5TextBox(148, 132, "6", lcd.FONT_DejaVu18, 0x444444, rotate=0)
label10 = M5TextBox(48, 86, "7", lcd.FONT_DejaVu18, 0x444444, rotate=0)
label11 = M5TextBox(101, 86, "8", lcd.FONT_DejaVu18, 0x444444, rotate=0)
label12 = M5TextBox(148, 86, "9", lcd.FONT_DejaVu18, 0x444444, rotate=0)
label13 = M5TextBox(195, 86, "C", lcd.FONT_DejaVu18, 0x444444, rotate=0)
label14 = M5TextBox(192, 128, "+", lcd.FONT_DejaVu18, 0x444444, rotate=0)
label15 = M5TextBox(197, 177, "x", lcd.FONT_DejaVu18, 0x444444, rotate=0)
label16 = M5TextBox(244, 132, "-", lcd.FONT_DejaVu18, 0x444444, rotate=0)
label17 = M5TextBox(239, 175, "/", lcd.FONT_Default, 0x444444, rotate=0)
rectangle37 = M5Rect(70, 68, 180, 70, 0x2a8f2a, 0x575757)
rectangle38 = M5Rect(120, 146, 80, 70, 0x2a8f2a, 0x575757)
label19 = M5TextBox(140, 160, "C", lcd.FONT_DejaVu56, 0x4b4b4b, rotate=0)
label18 = M5TextBox(71, 78, "00000", lcd.FONT_DejaVu56, 0x4b4b4b, rotate=0)



def buttonA_wasPressed():
  global page
  page = 1 + page
  if page==0:
    header.setTitle('Digital clock')
    label18.hide()
    label19.hide()
    rectangle37.hide()
    rectangle38.hide()
    rectangle1.show()
    rectangle2.show()
    rectangle3.show()
    rectangle4.show()
    rectangle5.show()
    rectangle6.show()
    rectangle7.show()
    rectangle8.show()
    rectangle9.show()
    rectangle10.show()
    rectangle11.show()
    rectangle12.show()
    rectangle13.show()
    rectangle14.show()
    rectangle15.show()
    rectangle16.show()
  elif page==1:
    header.setTitle('Calculator')
    rectangle0.show()
    rectangle1.hide()
    rectangle2.hide()
    rectangle3.hide()
    rectangle4.hide()
    rectangle5.hide()
    rectangle6.hide()
    rectangle7.hide()
    rectangle8.hide()
    rectangle9.hide()
    rectangle10.hide()
    rectangle11.hide()
    rectangle12.hide()
    rectangle13.hide()
    rectangle14.hide()
    rectangle15.hide()
    rectangle16.hide()
    rectangle17.show()
    rectangle18.show()
    rectangle19.show()
    rectangle20.show()
    rectangle21.show()
    rectangle22.show()
    rectangle23.show()
    rectangle24.show()
    rectangle25.show()
    rectangle26.show()
    rectangle27.show()
    rectangle28.show()
    rectangle29.show()
    rectangle30.show()
    rectangle31.show()
    rectangle32.show()
    rectangle33.show()
    rectangle34.show()
    rectangle35.show()
    rectangle36.show()
    label0.show()
    label1.show()
    label2.show()
    label3.show()
    label4.show()
    label5.show()
    label6.show()
    label7.show()
    label8.show()
    label9.show()
    label10.show()
    label11.show()
    label12.show()
    label13.show()
    label14.show()
    label15.show()
    label16.show()
    label17.show()
  elif page==2:
    header.setTitle('Pedometer')
    rectangle0.hide()
    rectangle17.hide()
    rectangle18.hide()
    rectangle19.hide()
    rectangle20.hide()
    rectangle21.hide()
    rectangle22.hide()
    rectangle23.hide()
    rectangle24.hide()
    rectangle25.hide()
    rectangle26.hide()
    rectangle27.hide()
    rectangle28.hide()
    rectangle29.hide()
    rectangle30.hide()
    rectangle31.hide()
    rectangle32.hide()
    rectangle33.hide()
    rectangle34.hide()
    rectangle35.hide()
    rectangle36.hide()
    label0.hide()
    label1.hide()
    label2.hide()
    label3.hide()
    label4.hide()
    label5.hide()
    label6.hide()
    label7.hide()
    label8.hide()
    label9.hide()
    label10.hide()
    label11.hide()
    label12.hide()
    label13.hide()
    label14.hide()
    label15.hide()
    label16.hide()
    label17.hide()
    page = -1
    rectangle38.show()
    rectangle37.show()
    label18.show()
    label19.show()
  else:
    pass
  pass
btnA.wasPressed(buttonA_wasPressed)


page = 0
rectangle17.hide()
rectangle18.hide()
rectangle19.hide()
rectangle20.hide()
rectangle21.hide()
rectangle22.hide()
rectangle23.hide()
rectangle24.hide()
rectangle25.hide()
rectangle26.hide()
rectangle27.hide()
rectangle28.hide()
rectangle29.hide()
rectangle30.hide()
rectangle31.hide()
rectangle32.hide()
rectangle33.hide()
rectangle34.hide()
rectangle35.hide()
rectangle36.hide()
label0.hide()
label1.hide()
label2.hide()
label3.hide()
label4.hide()
label5.hide()
label6.hide()
label7.hide()
label8.hide()
label9.hide()
label10.hide()
label11.hide()
label12.hide()
label13.hide()
label14.hide()
label15.hide()
label16.hide()
label17.hide()
label18.hide()
label19.hide()
rectangle37.hide()
rectangle38.hide()
rectangle0.hide()
rectangle1.show()
rectangle2.show()
rectangle3.show()
rectangle4.show()
rectangle5.show()
rectangle6.show()
rectangle7.show()
rectangle8.show()
rectangle9.show()
rectangle10.show()
rectangle11.show()
rectangle12.show()
rectangle13.show()
rectangle14.show()
rectangle15.show()
rectangle16.show()

最後に

ロジックさえ組み立てる力があれば、スクラッチみたいにNoCodeでもいろいろ遊べるので、教育向けにもいいかも(英語きちぃけど)

あと、M5Stack Watchを装備にすると よりダサくそれっぽくなって オススメです!
僕は注文しました。

つかAmazonで売ってたわ

https://www.amazon.co.jp/タカラトミー-TAKARA-TOMY-ポケットモンスター-ポケットモンスターDP/dp/B000JX5WCY

16日目のmkn_39さんにバトンをお渡しします。