比叡山国際トレイル50kmコースの試走(後半)

12/9に比叡山国際トレイル50kmコースの残りの試走に行ってきました。
夏の暑い時に前半を走ろうと行ってみたものの暑さに負けて途中でリタイア。1回目は根本中堂から坂本まで
alasixosaka.hatenablog.com
しばらくたって続きを走りに行って、2回目は坂本から仰木峠までと試走しました。
alasixosaka.hatenablog.com

今回は残りの部分、仰木峠からゴールの根本中堂まで走ってきました。
電車と地下鉄、バスを乗り継いで、大原の戸寺バス停へ。土井しば漬け本舗の本店が目の前にある(写真撮り忘れました)。
時刻は朝の9時。バスを降りると、数名の中高年ハイカーがたむろしている。京都駅から来たバスに乗ってきたのかな。
自分が準備をしている間に出発していった。
こちらも準備を済ませて出発する。
今回の装備は、冬場ということで、ザックは大きめのレイドライトのResponsiv24。ウェアは上が、ファイントラックのドライレイヤーにモンベルのウィックロンZEOの長袖シャツ、その上にクロスランナー。下は、クロスランナーの長ズボン。靴は、久しぶりにHOKAのスピードゴートを試した。今回は、足の爪対策として、アマゾンで買ったシリコンゴム製のプロテクターを着けてみた。

似たようなのがアマゾンでいっぱい売られていて、実際に買ったのは上のものとは違うメーカーのものだが、中身は同じものかもしれない。
これを付けると、5本指ソックスが履けなくなるので、今回は、足袋型の靴下を履いた。SYNというやつ。
シリコンのプロテクターを着けてみた感想は、着け心地は悪くなく走っていても気にならなかった。肝心の効果の方は、多少あるかなというくらい。今回は両方の足の親指にはめて走ったが、左の方は内出血せずに済んでいるみたい。右の方は着けても内出血はしている感じ。ただ、いつもだと翌日はかなり腫れて痛いがそこまで痛みは感じないのでそれなりに効果はあるのかなという感じ。
食料は、いつものおにぎり2つ。行動食として、アンドゥー2つ、エナジージェル1つ、一本満足バー1つ。予備として、ナッツを少々と柿の種一袋。水分は1.5Lのハイドレーションにクエン酸と塩(ぬちまーす)を溶かした水。
緊急時用にエマージェンシーシート、ヘッドライト。それに、最近熊があちこちで出没しているので熊鈴。
今回は新しく買ったガーミンのForerunner255にコースを入れてを持って行った。
また、今回は本番を想定してランニングポーチを着けてみた。ポーチと言っても大きな入れ物があるわけではなくベルト状のもので、うすっぺたいものなら入るというやつ。そこに補給食を入れておいた。レイドライトのザックは前ポケットが少なく、今回はハイドレーションを使ったので空いていたが、ソフトフラスクを入れるとそのほかのものがあまり入らない。本番はサロモンのADVSKINを使う予定でポケットはいっぱいあるけど結構深くて前回のダイヤモンドトレイルの時に使いづらかった。補給食や、エイドで水をもらったときに溶かして使う塩やクエン酸の入った容器をポーチに入れておけば出し入れしやすいかと思って使ってみた。使った感想は胸のポケットよりもずっと使いやすくまた、締め付けも気にならないので本番でも使ってみようと思っている。
戸寺のバス停からすぐに山に入っていく。まずは前回のゴールの仰木峠まで登っていく。ここは京都一周トレイルのコースになっているところ。前回は東海自然歩道の方を降りて野村別れまで行ったが、おそばを食べるのが目的だったので、今回はまだ行ったことないルートを選んでみた。東海自然歩道は以前にも東海自然歩道をたどって二ノ瀬から大津京まで行ったときに通っているし。
alasixosaka.hatenablog.com
この道は地図にはボーイスカウト道と書いてあってどういうことかなと思ったら。ボーイスカウトの人たちが整備をしているらしく、木の碑が立っていた。

ボーイスカウト連盟の碑

しばらく登ると東海自然歩道と合流。

東海自然歩道と合流

またしばらく登ってようやく仰木峠に到着。

仰木峠

ここまでにバス停にいたハイカーさんたちに追いつくかと思ったら誰もいなかった。彼らは山登りのような恰好をしていたけど山に登ったわけではかなったみたい。また、この日は予想では最高気温が20℃くらいになるという12月とは思えない気候で、3枚着ていた上を暑くて1枚脱いだ。
さて、ここからようやくトレランのコースイン。
仰木峠からは比良山地の方へ続く尾根道をしばらくたどる。この辺りはアップダウンも緩くて比較的走りやすい。しばらく行くと尾根の右手が開けて琵琶湖が見えた。

仰木峠の少し北の尾根上から琵琶湖を望む

しばらく尾根沿いに進む。
大尾山の手前でいったん林道と合流する。しばらく林道を進むが、林道が尾根から外れて行ってちょっと気を付けないとと思っていたら案の定、林道が行き止まりになっていた。どうやら途中で尾根道に入りなおさないといけないところを見逃したみたい。仕方ないので、尾根道まで斜面をよじ登る。
しばらく尾根道を進むと、大尾山の山頂に到着。仰木峠から大尾山に登ってくる途中で、登りを歩きながら一本満足バーを食べて最初の補給をした。ただ、結構食べ応えがあって1回で食べきれずに3回に分けて食べた。もう少し小さいやつの方が食べやすくて良いかもしれない。

大尾山山頂

そこから少し進んだところで比良山系への縦走ルートとお別れして右に折れる。

縦走ルートと別れて右の枝尾根を降りる

ここの下りがすごかった。途中にロープがいくつも張ってあって劇下りの連続。季節柄下に落ち葉が大量にあって滑るし、2度ほどしりもちをついてしまった。1月の石舞台100を思い出してしまった。たぶんここがコース一の難所。
途中にパラグライダー場があった。

パラグライダー場
眺めは良い

ようやく下り終えて林道に出るが、出口がわからず、適当に崖のようなところから降りてしまった。

林道に出たところ。右手の崖のようなところから降りてきた。

メインのトレイルはここまでで、今日のコースはあとは主に林道や舗装路を走る。
しばらく林道を走って右に折れるが、ここの分岐はあっさり通過してしまった。ガーミンにコースアウトの警告をされて気づいた。ガーミンのコースアウト警告はCOROSに比べるとやや遅いが、しょっちゅう警告されるCOROSよりはこれくらいの方がいいように思う。

林道の分岐。はじめは気づかずに通過してしまった。

ここからは林道をひた走る。ただ、本チャンではここまででかなり走ってきていてしかも大きなアップダウンを繰り返しているのでかなり疲れていることが想像される。この日は最後の登りで疲れた状態でどのくらい走れるかを試す意味もあって頑張って飛ばして走った。

途中の林道の分岐。ここもちょっと行き過ぎたがガーミンの警告が来る前に気づいた。

頑張って走ろうと思えば走れるが、自分のようなロートルのしかも、遅いランナーにはかなりきつそう。この辺りは上位と下位でかなりタイム差がつきそうなポイントに思えた。

仰木のエイドステーションのあたり。この辺をガンガン走れるとタイムはかなり縮めることができるのだろうが。

仰木のエイドステーションのあたりで、アンドゥーを補給。
林道をガンガン走って仰木の里の方へ下っていく。今回はとにかく下りきるまで頑張って走ってみた。仰木の里に下りたところで折り返し。ここには元三大師ウォーターステーションが設置されていることになっている。折り返すと当然登り、流石に登りは全然走れなかった。

仰木の里で折り返してここで左に分岐。来るときは右の道から降りてくる。

さて、いい加減くたばったところで横川の登りにかかる。はじめは林道を緩やかに登る(これはこれで結構きつい)が、途中で木段が現れてきついのぼりになる。

横川の手前まで木段の道が続く

ここがかなりきつかった。本番ではここまで40km以上走ってきているのでもうヘロヘロになっているに違いないここはかなりこたえると思った。
この日も下りで飛ばしたのがこたえてやっぱりヘロヘロ。おまけに補給のタイミングを間違えて登り坂の途中でハンガーノックになりかけて、エイドのある横川まで頑張ろうと思っていたが、こらえきれなくて途中で止まっておにぎりを頬張る。
木段を上り切ってようやく比叡山ドライブウェイ脇の東海自然歩道と合流したときはほっとした。

木段を上り切って東海自然歩道と合流
ドライブウェイの下をくぐる

ドライブウェイくぐってしばらく登ると3差路に出る。ここでまた、コースミス。横川中堂の文字に惹かれて左に行ってしまった。本当は右に行って駐車場の方に行かないといけない。

ここは右。駐車場の方へ行く。

横川駐車場から横川の境内に少し入ったところが最後のエイドステーション。ただ、その手前に拝観受付がある。中に入らないといけないので今回はお金を払って中に入る。ついでに、横川の中堂と元三大師堂を拝観した。

横川中堂。下から見たところ
元三大師堂
おみくじ発祥の地の碑

元三大師堂はおみくじ発祥の地だそうで、以前テレビでやっていたのを思い出した。ここのおみくじはお坊さんが願い事や悩み事を聞いて、お坊さんが祈祷してから引くという独特のものらしい。
横川には初めて来たが、横川地区は根本中堂のある東塔からかなり離れていて訪れる人も少なくひっそりとしていい雰囲気だった。お参りしている人もかなり信心深い人たちのようで一生懸命お参りしていたのが印象的だった。
横川の参拝が少し休憩になって、ちょっと回復。ここから坂本へ降りる登山道を行く。ここからゴールまでは約5kmだが、そのうち約3.5kmは延々と続く下りをまた走ることになる。タイムリミットが迫っていると疲れていてもいやが応なく走ることになるだろう。ただ最後の坂は地獄になると思うが。

登山道を離れて、東塔方面に登り返す。

最後の登りは印象としては横川への登りよりもきつくなかったが、時間と争っているときにこの最後の登りはかなりきついはず。誰かのブログに嘆きの坂と書いてあったが、時間は迫るが走ろうと思っても走れないという状況なら嘆きの坂と呼ばれるのも納得する。
坂を上り切って延暦寺会館脇を抜けて根本中堂前へ出てゴール。

根本中堂前でゴール

途中で横川を参拝していたのでトータルで5時間ほどかかった。実際に走っていたのは4時間半くらい。平均でkmあたり11分を切っていた。最近12分とか13分台だったので、久々に走りとしてはいい走りができた。その分しんどかったけど。
横川で買った参拝券が東塔でも使えるということなので、せっかくなので根本中堂を拝観した。現在は大修理中で外側はビニールのシートで覆われていた。まあ、修理中の状態を見学するのは今しかないと思うのでそれも一興かと思うが。通常は中は撮影禁止になっているが、今回は修理中の様子は撮ってもいいということなので写真を撮らせてもらった。

修理中の様子、鉄柱の奥がメインの屋根
こちらも修理中の屋根。手前側に当たる部分

帰りは坂本までケーブルカーで降りた。
延暦寺の所にケーブルカーの案内が出ていて、毎時0分と30分発と書いてあった。時計を見ると出発時刻まであと7分。1本逃すと30分待つことになるので、走って駅まで行った。帰りはゆっくりと歩いて帰るつもりだったのにここでも走る羽目になるとは。
しかも、坂本まで降りてからJRの駅まで歩いていくと、ちょうど湖西線の列車が来るところで、ここでも走って飛び乗った。
なんともバタバタの帰り道でもう少しゆったりとしたかったがタイミングなので仕方ないか。

これで、比叡山国際トレイルの試走は終了。3回に分けて走ったので疲労とかそういうのはわからない部分も多いがコースの状況は大体把握することができた。細かいシミュレーションは後日することにして、全体の印象としては、前半はきつい上り下りのトレイルコース、後半はひたすら林道を走るコースという印象。たしかに要項にフルマラソンを4時間切る走力が必要と書いてあるわけがわかったような気がした。特に後半の林道部分で走れないとタイム的にはきついことになるのではないかという気がした。最近あまりスピードを出す練習をしていないが、本番に向けてはちょっとスピード練習を取り入れていった方がいいのかもしれない。
まだ、エントリーは開始していないが、今年の要項を見ると50kmの部の参加要件がトレイルランで40km以上の完走というのになっていた。たしか、以前は35kmだったと思ったがまたハードルが上がっている。まあ、弘法トレイルを完走しているので40kmでも問題はないのだが。35kmなら、六甲縦走トレイルの38kmでOKと思っていたのでいつの間にという感じ。

今回のルートです。約25km。

Garmin ウォッチ用ウォッチフェイスを作る(その5)

前回まででウォッチフェイスの表示についてはほぼ完成しました。
alasixosaka.hatenablog.com
今回は、フォントをオリジナルに変えてみようと思います。
やり方は、いつも参考にしているmayoさんのブログに詳しく書いてあります。
note.com
ここでは簡単に概略だけを書いておきます。ほぼ参考サイトのやり方通りで動きます。
まず、フォントデータを用意するためにBMfontというソフトをダウンロードします。
インストールは不要です。ダウンロードしたファイルのbmfont64.exeをクリックすると起動します(OSが64bitの場合、32bitならbmfont32.exeを選ぶ)。起動したら、ガーミンウォッチに表示したいフォントを選びます。
色々あって悩みますが、今回は、HPSimplifiedというフォントを選びました。その辺は好みだと思うのですが、自分的には明朝系のフォントよりもゴチック系のフォントの方が好みです。また、このフォントはパソコンがHPだからインストールされているのかもしれません(確認はしてませんが)。
とりあえず、フォントが決まったらサイズを適当な大きさにします。文字盤のメインの表示だと96pixelくらいがちょうどよいようです。それも好みの問題ですが。
フォントとサイズが決まったら、save bitmap as で適当な名前を付けて保存します。このとき、参考サイトだと拡張子がfntのファイルとpngのファイルができると書いてありますが、自分の場合デフォルトではfntとtgaの拡張子のファイルができました。どちらでも特に問題はなく、fntのファイルだけあればよいようです。
できたフォントを、プロジェクトのresourceフォルダにfontsというフォルダを作って格納します。そして、そのフォルダにfont.xmlを作って、

<fonts>
    <font id = "HP" filename="HP.fnt"/>
</fonts>

のように記述します。ファイル名は先ほどダウンロードしたfntファイルのもの。font id はプログラム中で使う識別子です。
次に、layout.xmlで作ったフォントを表示したい部分のフォント名をfont = @Fonts.HPというように修正します。
これで、オリジナルフォントが表示されるようになります。

フォントがオリジナルに変更された

実機で試す

さて、結構お気に入りのウォッチフェイスができたので実機で試してみました。
やり方はあちこちに書いてあるので今更ですが、ガーミンウォッチをパソコンに接続し、プロジェクトのbinフォルダのxxxx,prg(xxxxはプロジェクト名)というファイルをウォッチのGarmin>Appsというフォルダにコピーして格納します。ケーブルを取り外すとそのまま新しいウォッチフェイスが動きます。

Low Power Modeにはまる

これでお気に入りのウォッチフェイスができて、めでたしめでたしと思いきや、様子が変。秒針(デジタルなので正確には秒表示というべきか)がすぐに止まってしまう。時計を動かすとまた動き出すが、しばらくするとまた止まる。この動きはどっかで見たような。そう、COROSとおなじではないか。COROSも節電のために秒針は常に動いておらず腕を動かすと動き出して、しばらくすると止まる。たしかに、前にも書いたようにスマートウォッチってそういうもんでしょと言われればそれまでなんですが、特に有機ELを表示に使っているウォッチなんかは表示そのものが消えてしまったりする。ただ、個人的には普段使いの時計として使うなら秒針は常に動いていて欲しいと思っているし、現に、ガーミンではデフォルトでインストールされているウォッチフェイスだと秒針は常に動いている。また、ConnectIQからインストールしたウォッチフェイスでも秒針は常に動いていた。ということは何か方法があるはず。
色々調べると、ウォッチの種類によるようなのですが、アクティブモードとローパワーモードがあってアクティビティー中や腕を動かしたときはアクティブモードに入って毎秒更新になり、アクティビティー中でない通常のスマートウォッチモードの時は10秒後にローパワーモードに入って節電をするらしい。
つまり、プログラム中のonUpdate()はアクティブモードでは1秒毎に動作し、ローパワーモードでは1分毎に動作する。ローパワーモードで1秒ごとに動作するには別にonPartialUpdate()という関数が用意されていて、ローパワーモードの時に1秒毎に呼び出される。
ということで早速やってみた。
基本に戻って、新しいプロジェクトを作成し、秒の表示の部分をonPartialUpdate()関数を作ってその中に書いてみた。
シミュレータではsettingからLow Power Modeを選んでチェックを入れるとローパワーモードに入る。
これで万事解決と思ったらそうは問屋が卸さない。しばらくすると秒針が59秒で止まる。
ちなみに、onUpdate()の所と、onPartialUpdate()の所に、System.println("full update"); System.println("partial update");と書いて動作を確認してみた。この辺はArduinoみたいで結構原始的。一応デバッグモードも用意されているが、ブレークポイントで止まってくれるくらいで、その時の変数の状態などは全然表示してくれないので、原始的な方法がデバッグには必要なようだ。
コメントを見て、動作を見てみると、しばらくはパーシャルアップデートが動いているが、1分経過後の次のフルアップデートのタイミングで必ず止まる。
実機でも試してみたが動作は同じ。これは完全に行き詰ったか、と思ったが、実際に毎秒動くプログラムを書いている人がいるので絶対に何か解決策があるはず。色々探してようやく解決策が見つかった。ただそれも簡単ではなくいろいろ試行錯誤が必要で、その辺の詳しくはまた次回に書いてみたいと思います。

Garmin ウォッチ用ウォッチフェイスを作る(その4)

前回は、日付と曜日、バッテリー容量の表示などを行いました。
alasixosaka.hatenablog.com
だいぶやり方もわかってきたので、残りの表示を一気に片付けてしまいます。

表示したい情報を決める。

表示する情報としては、

  • 日付と曜日
  • 時、分、秒
  • バッテリー残量
  • 心拍数
  • 歩数
  • スマホとのBluetooth接続の有無
  • スマホへのメッセージの有無

の7つにする。そのうち、3つ目までは前回のブログで完成しているので、今回は残りの4つを表示させてみることにする。

情報の取得

表示するための情報の取得については、いつものこちらのサイトを参考にしました。
take4-blue.com
心拍数に関しては

ActivityMonitor.getHeartRateHistory(1, true).next().heartRate

で取得できる。取得できなかった場合は、
ActivityMonitor.INVALID_HR_SAMPLE がTrueになる。
歩数は、

ActivityMonitor.getInfo().steps

Bluetooth接続の有無と、メッセージの数はそれぞれ

System.getDeviceSettings().phoneConnected
System.getDeviceSettings().notificationCount

で取得することができます。

アイコンを決める

前回も紹介したこちらのサイトから適当なアイコンを選んでダウンロードしました。
www.mingcute.com

プログラムの全文

いきなりですが、全文公開です。

layout.xml

まずレイアウトから

<layout id="WatchFace">
    <label id="TimeLabel" x="center" y="60" font="Graphics.FONT_NUMBER_THAI_HOT" justification="Graphics.TEXT_JUSTIFY_CENTER" color="Graphics.COLOR_BLUE" />
    <label id="Label" x="200" y="140" font="Graphics.FONT_LARGE" justification="Graphics.TEXT_JUSTIFY_CENTER" color="Graphics.COLOR_BLUE" />
    <label id ="DayLabel" x="center" y="30" font="Graphics.FONT_LARGE" justification="Graphics.TEXT_JUSTIFY_CENTER" color="Graphics.COLOR_WHITE" />
    <label id ="BatLabel" x="180" y="195" font="Graphics.FONT_TINY" justification="Graphics.TEXT_JUSTIFY_CENTER" color="Graphics.COLOR_WHITE" />
    <label id ="HeartLabel" x="90" y="170" font="Graphics.FONT_TINY" justification="Graphics.TEXT_JUSTIFY_CENTER" color="Graphics.COLOR_WHITE" />
    <label id ="shoeLabel" x="150" y="220" font="Graphics.FONT_TINY" justification="Graphics.TEXT_JUSTIFY_CENTER" color="Graphics.COLOR_GREEN" />
</layout>

TimeLabelというのが時と分を表示する部分で、単なるLabelが秒の表示です。このあたりはまだテストプログラムの名残です。
DayLabelが日付と曜日、BatLabelがバッテリー残量。HeartLabelが心拍数、shoeLabelが歩数です。

drawable.xml

次がdrawable(画像関係)

<drawables>
    <bitmap id="LauncherIcon" filename="launcher_icon.png" />
    <bitmap id="heart" filename="heart_fill.png" />
    <bitmap id="BT" filename="bluetooth_line.png" />
    <bitmap id="mes" filename="message_2_fill.png" />
    <bitmap id="shoe" filename="shoe_line.png" />
</drawables>

LauncherIconはデフォルトのままで弄っていません。heartが心拍数を表すハートのアイコン。BTがbluetoothのアイコン。mesが通知を知らせるアイコン。shoeが歩数表示のための靴のアイコンです。画像ファイル(png形式)はdrawableフォルダに入れておきます。

プログラム本体

プログラム本体のWatchfaceView.mcの部分です。長いですが。

import Toybox.Graphics;
import Toybox.Lang;
import Toybox.System;
import Toybox.WatchUi;
import Toybox.Time;

var BT;
var mes;
var heart;
var shoe;

class watchfaceView extends WatchUi.WatchFace {

    function initialize() {
        WatchFace.initialize();
    }

    // Load your resources here
    function onLayout(dc as Dc) as Void {
        heart = WatchUi.loadResource(Rez.Drawables.heart);
        BT = WatchUi.loadResource(Rez.Drawables.BT);
        mes = WatchUi.loadResource(Rez.Drawables.mes);
        shoe = WatchUi.loadResource(Rez.Drawables.shoe);
        setLayout(Rez.Layouts.WatchFace(dc));
    }

    // Called when this View is brought to the foreground. Restore
    // the state of this View and prepare it to be shown. This includes
    // loading resources into memory.
    function onShow() as Void {
    }

    // Update the view
    function onUpdate(dc as Dc) as Void {
        
        // Get and show the current time
        var clockTime = System.getClockTime();
        var now = Time.now();
        var nowM = Time.Gregorian.info(now, Time.FORMAT_MEDIUM);
        var nowS = Time.Gregorian.info(now, Time.FORMAT_SHORT);
        var batt = System.getSystemStats().battery;
        var hearts = ActivityMonitor.getHeartRateHistory(1, true).next().heartRate;
        var info = System.getDeviceSettings();
        var timeString = Lang.format("$1$:$2$", [clockTime.hour, clockTime.min.format("%02d")]);
        var timeString2 = Lang.format("$1$", [clockTime.sec.format("%02d")]);
        var dayString = Lang.format("$1$/$2$ $3$", [nowS.month, nowS.day, nowM.day_of_week]);
        var battString = Lang.format("$1$%", [batt.format("%02d")]);
        var heartString = Lang.format("$1$", [hearts]);
        var stepstring = Lang.format("$1$", [ActivityMonitor.getInfo().steps.format("%5d")]);
        //System.println (hearts);
        var view = View.findDrawableById("TimeLabel") as Text;
        var view2 = View.findDrawableById("Label") as Text;
        var view3 = View.findDrawableById("DayLabel") as Text;
        var view4 = View.findDrawableById("BatLabel") as Text;
        var view5 = View.findDrawableById("HeartLabel") as Text;
        var view6 = View.findDrawableById("shoeLabel") as Text;
        view.setText(timeString);
        view2.setText(timeString2);
        view3.setText(dayString);
        view4.setText(battString);
        if (hearts != ActivityMonitor.INVALID_HR_SAMPLE){
            view5.setText(heartString);
        }else{
            view5.setText("---");
        }
        view6.setText(stepstring);
        //BAT1.draw(dc);
        // Call the parent onUpdate function to redraw the layout
        View.onUpdate(dc);
        if (info.phoneConnected) {
            dc.drawBitmap(50,195, BT);
        }
        if (info.notificationCount > 0) {
            dc.drawBitmap(80,195, mes);
        }
        if (batt>=50){
            //dc.drawBitmap(140,210, BAT4);
        }else{
            //dc.drawBitmap(140,210, BAT1);
        }
        dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
        dc.drawRectangle(140, 202, 20, 10);
        dc.fillRectangle(140, 202, 20*batt/100, 10);
        dc.drawBitmap(50,170, heart);
        dc.drawBitmap(80, 220, shoe);
    }

    // Called when this View is removed from the screen. Save the
    // state of this View here. This includes freeing resources from
    // memory.
    function onHide() as Void {
    }

    // The user has just looked at their watch. Timers and animations may be started here.
    function onExitSleep() as Void {
    }

    // Terminate any active timers and prepare for slow updates.
    function onEnterSleep() as Void {
    }

}

ここまでその1から読んでいただければそんなに難しくないのでわかると思いますが、ポイントだけ簡単に説明しておきます。
まず、画像を表示するための変数を4つ定義します。

var BT;
var mes;
var heart;
var shoe;

の部分がそうです。
次にfunction onLayoutで

    function onLayout(dc as Dc) as Void {
        heart = WatchUi.loadResource(Rez.Drawables.heart);
        BT = WatchUi.loadResource(Rez.Drawables.BT);
        mes = WatchUi.loadResource(Rez.Drawables.mes);
        shoe = WatchUi.loadResource(Rez.Drawables.shoe);
        setLayout(Rez.Layouts.WatchFace(dc));
    }

の部分で、画像ファイルと紐づけをします。
あとは、画面の更新のfunction onUpdateの部分で表示を制御してやります。前回から追記した部分を中心に説明すると、変数heartsに心拍数が入ります。
Bluetooth接続の有無とメッセージの数は、一旦、変数infoで受けておいて、後で、info.phoneConnectedとinfo.notificationCountからそれぞれの情報を得ています。
心拍数の数値は、文字列のbattStringに代入し、歩数の数値はstepStringに代入します。それぞれ変数view5、view6を使って表示をします。
心拍数は取得できていない時があるので、ActivityMonitor.INVALID_HR_SAMPLEがfalseの時だけ表示し、trueの時は、"---”を表示するようにしています。この辺は参考サイトのやり方を踏襲しています。
また、info.phoneConnectedがtrueならBluetoothのアイコンを表示し、info.notificationCountが1以上であればメッセージアイコンを表示します。

        if (info.phoneConnected) {
            dc.drawBitmap(50,195, BT);
        }
        if (info.notificationCount > 0) {
            dc.drawBitmap(80,195, mes);
        }

の部分がそうです。
こんな感じで表示されます。

一応全部入りで表示してます。

受け取ったメッセージの数を表示することもできますが、今回はしていません。使いながらあった方がいいと思えば追加するかもしれません。
次回は、フォントをオリジナルに変更しようと思っています。

Garmin ウォッチ用ウォッチフェイスを作る(その3)

前回は、文字表示について、時、分を大きな文字で表示し、その下に秒の表示、更に、上部に月、日、曜日を表示するところまでやりました。
alasixosaka.hatenablog.com
今回は、グラフィックスを使ってバッテリーの残量表示をしてみたいと思います。
まずは、バッテリーの残量を取得しないといけません。いつもお世話になっているこのサイトによると、
take4-blue.com
バッテリーの残量は、System.getSystemStats().battery で取得することができそうです。
そこでまず、例によってlayout.xmlを編集して下の一行を追加します。

<label id ="BatLabel" x="180" y="210" font="Graphics.FONT_TINY" justification="Graphics.TEXT_JUSTIFY_CENTER" color="Graphics.COLOR_WHITE" />

ラベルのIdはBatLabelでフォントは小さくするためTINYを使いました。
次にfunction onUpdateに次の一行を追加します。

var batt = System.getSystemStats().battery;

これで、変数battにバッテリーの残量が入ります。
そして、

var battString = Lang.format("$1$%", [batt.format("%02d")]);

var view4 = View.findDrawableById("BatLabel") as Text;

更に

view4.setText(battString);

を追記すると右下に小さくバッテリー残量が表示されます。

バッテリー残量が表示された

グラフィックスを追加する

確かにこれで残量が数字で表示されるようになったんですが、やっぱりアイコンチックなものが欲しい。
そこで、数字の左にアイコンを表示するようにしてみた。
アイコンはフリーの素材のがいろいろネットに落ちているので好きなのを選んでダウンロードして使えばよいが、自分はここのサイトのを使ってみた。
www.mingcute.com
サイズが豊富なのと色も自由に変更できるのが良い。
色々サイズを試してみたが、24pxelがちょうどよいようだ。バッテリーのアイコンを適当にダウンロードして、drawableのフォルダに入れる。
参考にさせていただいているmayoさんのこちらのサイトにも画像を表示する方法が書いてあるが、実はここに書いてある、layout.xmlにビットマップを追記する方法だと常に表示されることになってしまう。つまり、書いたり消したりが自由にできない。
note.com
どうも、文字盤の背景なんかを表示する方法のようだ。
バッテリーの残量表示は残量によってアイコンを切り替えたいので、常に表示は困る。試しに、2つのアイコンを登録してみたが、2つのアイコンが重なって表示され、後に書いた方で上書きされてしまった。また、スマホbluetoothで接続されているかどうかをアイコンで表示したり、メッセージがスマホに来ているかどうかをアイコンで表示したりするのにも必要に応じてアイコンを書いたり消したりする必要がある。
別の方法はないかと探したところ、connect IQのフォーラムに、下記の記事を見つけた。
forums.garmin.com
この方法によると、ビットマップをdrawableに登録して表示するらしい。Androidでもdrawableにビットマップを登録して表示していたので、そうなんじゃないかと思っていたがやっぱりそうだった。具体的には下記の手順で追記をすればよい。
まず、drawableにビットマップを登録する。デフォルトではランチャーアイコンが登録されてるはずなので、その下に次の文を追記する。ファイル名は先ほどdrawableフォルダにダウンロードしたアイコンのファイル名。

<bitmap id="BAT1" filename="battery_1_line.png" />

それから、watchfaceView.mcに戻って、ビットマップ表示のための変数を定義する。ここではBAT1とした。

var BAT1;

次に、function onLayoutに下記の文を追記する。

BAT1 = WatchUi.loadResource(Rez.Drawables.BAT1);

最後に、function onUpdateのView.onUpdate(dc);の後に

dc.drawBitmap(140,210, BAT1);

を追記する。これでアイコンが表示される。表示したくない時は最後に追記した文を実行しなければよい。if文などで判断して表示するしないを決定すればよい。

バッテリーのアイコンが表示された

図形描画で対応させてみる

上の方法で、バッテリー残量によってアイコンの表示を切り替えて表示しようと最初は考えていたが、APIを読んでいると、四角形を描画するコマンドが用意されているのを発見した。アイコンで何段階かに分けてアイコンを切り替えていく方法もよいが、図形描画を使えばもっと細かく視覚的に表示が可能になる。
しかも、描画の方が簡単で手間が少ない。
やり方はfunction onUpdateの最後に下記の3文を追記するだけです。

dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_BLACK);
dc.drawRectangle(140, 217, 20, 10);
dc.fillRectangle(140, 217, 20*batt/100, 10);
残量がグラフィカルに表示された

だいぶコツがつかめてきた。この調子で残りの表示部分も完成させてみたいと思っています。

Garmin ウォッチ用のウォッチフェイスを作る(その2)

前回は、開発環境を整えて、とりあえず基本的なプログラムをシミュレータで動かすところまでやりました。
alasixosaka.hatenablog.com
そのままでは、文字がちっちゃいし、時と分のみの表示で面白くないので、今回は、表示を色々弄ってみたいと思います。
今回は、基本的にはこちらのサイトを参考にしました。
note.com
何回か記事があるので、順番に読んでいけばかなり参考になります。
実は、前回参考にしたこちらのサイトの続きの記事で結構いいウォッチフェイスを作っておられたのでそのまま使わせてもらおうかと思ったのですが、ここに掲載されているプログラムそのままでは動きませんでした。世の中そう甘くはないか。
take4-blue.com
どうも、SDKの仕様が変わっているらしく、メインのソースコードだけでは動かない仕様になっているらしい。細かいことは、mayoさんのサイトの記事を読んでいけばいろいろと書いてあるのでここでは詳しくは書きませんが、manifestがあったり、drawableやlayoutやらStringなど何となくAndroidチックになっている。Andoroidのアプリ開発の経験があればmayoさんの記事を読んでいくだけで何となくやり方がわかっていくのではないかと思います。

秒の表示とテキストの表示

まず、上にリンクを貼ったmayoさんの記事の通りに、秒の表示とその上に重ねるように”aaa"の表示をやってみました。当然同じ結果になりました。なので、詳細は省略します。とりあえず、やってみて感じをつかむのが大事。
次に、時、分の表示とは別に秒の表示をさせてみました。
1行で秒まで表示していたのを時と分の表示にするようにデフォルトに戻します。
それから、layout.xmlに1行追加します。mayoさんの記事の通りやっていれば、すでに追加されているはずです。追加されていれば書き換えます。追加するのは、次の一行です。

<label id="Label" x="140" y="180" font="Graphics.FONT_LARGE" justification="Graphics.TEXT_JUSTIFY_CENTER" color="Graphics.COLOR_BLUE" />

xとyの値は表示の位置を示しています。位置の設定は、center, top, bottom, left, rightという位置指定以外に、相対位置指定(多分前の表示からの相対位置)と絶対位置指定の3種類があります。ここでは絶対位置指定を使っています。
それから、watchfaceView.mcのfunction onUpdateに次の3行を追加します。ちなみに、watchfaceというのはこのプロジェクトの名前です。ですので、プロジェクト名View.mcというファイル名ということです。

var timeString2 = Lang.format("$1$", [clockTime.sec.format("%02d")]);
var view2 = View.findDrawableById("Label") as Text;
view2.setText(timeString2);

これで秒が少し離れた右下に表示されます。

秒が右下に表示された

文字を大きくしてみる

このままではまだ文字が小さくて見づらいので、時、分の表示を大きくしてみます。公式のAPIを見るとフォントはいろいろあるようですが、用意されているフォントはどれも形はほぼ同じでサイズが違うだけのようです。
developer.garmin.com
この中で、時計のメインの表示である時、分の表示に使えそうな大きな文字は、HOTかTHAI_HOTとついているやつです。layout.xmlのfont="Graphics.FONT_LARGEの部分をfont="Graphics.FONT_NUMBER_THAI_HOT"として、一番大きな文字にしてみました。

時、分のフォントを大きくしてみた

だいぶ見やすくなりました。

日付、曜日の表示

時刻が表示できたので、今度は日付と曜日を表示してみます。
時刻は、ひな形のまんま、var clockTime = System.getClockTime(); で取得していますが、このまま、例えば

var dayString = Lang.format("$1$/$2$", [clockTime.month, clockTime.day.format("%02d")]);

などとやってもエラーになって日時が取得できません。
日時はTimeから取得しないといけないようです。また、元に戻って、こちらのサイトを参考にしました。
take4-blue.com
例によってlayout.xmlに次の一文を挿入します。表示の位置は真ん中の上の方にしました。

<label id ="DayLabel" x="center" y="50" font="Graphics.FONT_LARGE" justification="Graphics.TEXT_JUSTIFY_CENTER" color="Graphics.COLOR_WHITE" />

それから、watchfaceView.mcを変更します。まず冒頭に

import Toybox.Time;

の一文を挿入します。たいていのブログではimport ではなく、usingを使っていますが、ひな形がimportになっていたので、importを使っています。今のところこれでエラーは出ていません。
次に、function.onUpdate に次の文を挿入します。
まず、現在日時の取得。これは、var clockTime = System.getClockTime(); の下に入れました。

var now = Time.now();
var nowM = Time.Gregorian.info(now, Time.FORMAT_MEDIUM);
var nowS = Time.Gregorian.info(now, Time.FORMAT_SHORT);

nowMとnowSの2つを使っている理由は、参考サイトに書いてありますが、FOTMAT_MEDIUMを使うと日時表示の時に月や日まで表示されてしまうためのようです。
それから、次の2文をその下らへんに挿入。

var dayString = Lang.format("$1$/$2$ $3$", [nowS.month, nowS.day, nowM.day_of_week]);
var view3 = View.findDrawableById("DayLabel") as Text;

最後に、下の1文をBT.draw(dc); の前に挿入。

view3.setText(dayString);

ちなみに、シミュレータ側の言語セッティングを日本語にしておかないと曜日が英語で表示されてしまいます。

日時と曜日が表示された

ようやくまともな時計らしくなってきました。まだ、スマートウォッチっぽさは全くないですが。次は、画像を表示させてみたいと思います。まだまだ先は長そうだ。

garmin ウォッチ用のウォッチフェイスを作る(その1)

前回、Garmin Forerunner255を衝動買いした件について書きました。
alasixosaka.hatenablog.com
しばらく使ったらレポートを書こうと思っていたんですが、先にオリジナルのウォッチフェイスを作成するという話になってしまいました。
もちろん、使い始めているのですが、まだいろいろ書くほど使ってないので。レポートはもっと使い込んでから書くことにします。
そして今回のお題ですが、何故自分でウォッチフェイスを作ろうと思ったかというと、ガーミンのオリジナルのウォッチフェイスはバッテリーの残量が数字で表示されないんです、バッテリーの残量はグラフィックスで減っていくのがわかるだけ、よくスマホなんかである残量表示のあれが出てくるのあれです。スマホだと数字も表示されるのが普通ですが、ガーミンウォッチは数字がありません。これはちょっと不便と思ったら、Connect IQというアプリを使うと、いろんな人が作ったウォッチフェイスが使うことができて、その中にはバッテリーの残量が数字で表示できるのもあります。ものすごく沢山のウォッチフェイスがあって選ぶのに困るほどあるのですが、なかなか自分的に気に入ったのが見つからず。ようやく、ちょっと気に入ったのが見つかったのですが、時計表示のフォントがなんとなく気に入らない。それなら自分で作ってしまえということで作成に取り掛かったという次第です。

準備に必要なもの

  • パソコン

自作のウォッチフェイスと作るためにはアプリでは無理で、パソコンが必要です。WindowsでもMacでもできるようです。自分の場合はWindowsでやりました。

  • 開発環境

Visual Studio Code(VSC)かEclipseを使うのが一般的なようです。自分の場合は、プログラミング用のノートパソコンにVSCがインストールされていたのでそっちを使いました。個人的にはEclipseの方が好きなんですが。まあ、その辺は使う人の好みですね。

  • VSC用のMonkey C Extention

Connect IQのプログラミングはMonkey Cという言語を使うようです。それ用のコンパイラと自分では理解しています。

  • Connect IQ SDK

Connect IQを動かすためのSDKです。

これだけそろえれば一応オリジナルのウォッチフェイスを作ることができます。フォントをオリジナルのにしようとするとまた別のソフトが必要ですが、それはまたおいおい書いてみたいと思います。

開発環境を整える

基本的にはこのサイトを参考に作業を進めました。
qiita.com

Monkey C Extentionのインストール

VSCがインストールされている前提で、VSC上でまず、Monkey C Extentionをインストールします。VSCを立ち上げて、左下の四角いアイコンをクリックし、Monkey Cを検索、インストールします。Garmin謹製のものとサードパーティのものがありますが、Garmin謹製のものを選択します。

Connect IQ SDKのインストール

GarminのサイトからConnect IQ SDKをダウンロードし、sdkmanager.exeを起動してインストールします。

Javaが必要

その後の作業は上記の参考サイトの通り進めればよいのですが、Connect IQなのかMonkey CなのかとにかくJavaが必要なようです。自分のノートパソコンにはJavaがインストールされていなかったので、VSCにJavaの場所がわからないんだけどどこ? みたいな表示が出てきました。JavaJREJDKがありますが、JREの方をインストールすればOKです。オラクルのサイトからダウンロードできます。

VSC上での作業

あとは、Monkey C: Verifi Installationの実行。developer keyの作成。Run > Add Configuration。Monkey C: Set Products by Product Categoryの実行とButton WealablesとTouch Wealabelsにチェックを入れ、OK。という手順で準備が完了します。

とりあえずなんか作ってみる。

take4-blue.com
こちらのサイトを参考に、プロジェクトを作ってみます。
プロジェクトの作成ですが、VSCを立ち上げてF1(ないしCntrl+Shift+P)で、Monkey CのNew Projectを選択します。プロジェクト名は適当で。今回はWatchfaceとしました。まず、アプリケーションのタイプを選択する画面が出ます。これから作るのはウォッチフェイスなので、watchfaceを選択します。いろいろ選べるみたいで、ウィジットやデータフィールドなどもオリジナルのが作れるみたいです。データフィールドについても不満点があるので、ウォッチフェイスが無事に出来上がったらチャレンジしてみたいと思います。
それから、アプリケーションテンプレートを指定します。Simpleの方でいいと思います。with setting の方は、ウォッチにもともと入っているウォッチフェイスのようにいろいろ設定できるようにするためのものだと思いますが、たぶん処理が面倒なので今回はSimpleで行きます。
それから、最低バージョンの選択があります。何も考えずに一番新しいバージョンにしました。(不具合があれば後で直せばいいやと思って)
最後に、対応デバイスを選択する画面が出ます。これは、上記の参考サイトに書いてないのですが、自分の場合は、Forerunner255用のウォッチフェイスを作るのでForerunner255にだけチェックを入れました。機種によって画面の形、解像度などいろいろあるので、マルチに対応させるのは結構めんどくさそうです。

対応デバイスはForerunner255を選択

とりあえず動かしてみる。

まずは、Manifestを弄る

左のExplorer画面からManifest.xmlを選択して表示させます。ほとんどの設定はそのままでよいのですが、言語を選ぶ欄があるので、Japaneseを選択します。

日本語を選択

あとは、ビルド、実行すると、じつは、これだけで時刻表示をすることができます。
F1を押して、Monkey C: Build Current Projectを選択。
なにやらごちょごちょ表示されますが、BUILD SUCCESSFULと表示されればビルドが成功しています。何かエラーがある場合はエラーメッセージが表示されます。

ビルドの結果画面

Warningが表示されていて、ランチャーアイコンの画像サイズがちっちゃいよというようなことが書かれていますが、デフォルトで入っているものでウォッチフェイスの表示には関係ないので気にしなくてよいと思います。
ビルドが成功したら、Run->Run Without DebuggingでMonkey Cを選択するとシミュレータがスタートします。
こんな感じ。

シミュレータの画面

文字もちっちゃいし、時刻表示だけなので全く面白くないですが、まずはここから初めて、いろいろアレンジしていきます。

やっぱりガーミンが恋しい

新しいGPSウォッチとしてCOROSのAPEX2 Proを選んで、半年ほど使ってみました。
alasixosaka.hatenablog.com
いいところ、悪いところいろいろあるんですが、この間のダイヤモンドトレイルでGPSの軌跡が飛んでた時にはブチ切れそうになりました。
alasixosaka.hatenablog.com

何のために、マルチバント、マルチGNSSの機種を選んだのかと。帰ってからもう一度設定を確認してみましたが、ちゃんとマルチバンドかつマルチGNSSの設定になっていました。
そんなこんなでいろいろあって、やっぱりガーミンが良かったなあと思っている次第です。もちろん、同じ状況になった時にガーミンなら軌跡が飛ばないのかというのは何とも言えませんが。まあ、スマホのアプリを改良してログを取れるようにしておいてよかったというとこではあるのですが。
alasixosaka.hatenablog.com

そこで、COROSのここが気に入った、ここが気に入らないという点を書いてみたいと思います。

COROS(APEX2 Pro)の良いところ。

何といっても一番はコスパです。ガーミンだとFenixに相当するスペックを持っていますが、値段は半分強のお値段で買えてしまいます。
その値段で、チタンのベゼルにサファイアガラスですから。ガーミンだとForerunner955というのが値段的には近く、スペックも近いですが、ベゼルは強化プラスチック(これはこれでありだと個人的には思っていますが)で、ガラスはゴリラガラス。ゴリラガラスについてはレビューを見ると傷が入ったといった記事を見かけます。サファイアガラスのCOROSは何度かぶつけていますが、全くびくともしません。
それから、ジョグダイヤルは意外と便利です。ガーミンだとボタンが5つもあって、とっさにどのボタンを押したらよいか迷うのですが、COROSは画面を切り替える時はジョグダイヤルを回すだけなので、結構簡単ですし、頭も使いません。疲れているときなんかは結構ありがたい。
また、ボタンは基本ロックされていて、ジョグダイヤルを長押ししてやることでロックが解除される仕組みになっていますが、画面の切り替えだけはロックされた状態でも回してやると切り替わります。この辺は結構考えられているかなと思います。ちなみに、地図を表示している状態だと、ロックを解除してやるとジョグダイヤルの回転で地図の縮尺を変更することができます。
あとは、ガーミンでもできる(だろう)機能として、コースアウトの警告、ウェイポイントまでの距離の表示なんかは便利に感じました。ただ、コースアウトの警告はちょっとシビアすぎて、ちゃんとコース上を走っているのに頻繁に警告を食らうので、そのうちオオカミ少年状態でまた警告かという感じになってしまうのがちょっと難点ですね。どのくらい離れたら警告を出すのかを自分で設定できれば良いのですが。
あとは電池の持ちですね。スマートウォッチモードだとほぼ1か月充電せずに動くし、GPSモードでも最大で75時間稼働。2-3日の縦走や100マイルレースでもOKというスペック。

COROSの気に入らない点

次は気に入らない点です。
まず、GPSのつかみが意外に遅い。ガーミンの最新機種なんかのレビューを見ているとGPSのつかみがめちゃめちゃ早いという記事をよく見かけます。COROSの場合、前に使っていたINSTINCTよりは少し早いかなあといった感じで、たぶんガーミンに比べて遅いんだろうという風に思っています。
それから、冒頭に書いたように、GPSの精度の問題。たしかに山の中で衛星がキャッチしずらいというのはわかるのですが、スマホはちゃんととらえているのだから、スマホよりも新しいGPSウォッチにはちゃんとGPSをキャッチしといてほしいと思います。ほんと、これが一番の問題。
それから、通常のスマートウォッチモードでは秒針が止まってしまう点。これは節電のためにこういう仕様になっているのでしょうが、普段使いの時計としてみた場合はちょっと不便。まあ、アップルウォッチなどの有機ELのスマートウォッチも普段は節電のため画面を消していてることを考えると、そんなもんでしょうということになるのかもしれないが、MIP液晶で表示はちゃんと見えているのに、秒の表示だけ0になっているというのは違和感があってちょっと気になる。

じゃあどうするの

もう買い替えようかと思ったのですが、流石にFenixは高いし、Forerunner955でもちょっとお高い。ただ、COROSを使ってて思ったのですが、地図の表示は要らんのではないかと。特に老眼の自分にはあの時計のちっちゃな画面に地図が表示されても、走りながらではまず読み取るのは不可能。ダイヤモンドトレイルの時も何度か地図を確認しようとしたのですが、結局、今自分がコース上を走っているのか外れているのかくらいしか判別がつかなかったです。まあ、登山の時なんかに、ゆっくり歩きながら見れば見れるのでしょうが、それならスマホを取り出してみてもあんまり変わらんかなという気もしますし、少なくともトレランで役に立つ可能性は低そう。それなら、もう一つ下のForerunner255でも十分なのではと。ということで、オークションでちょっと安くなっているのがあったのでポチってしまいました。実はもう手元にあるのですが、Forerunner255の使い勝手についてはもう少し使い込んでからレビューしてみたいと思います。