12
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

KLab EngineerAdvent Calendar 2021

Day 11

Fitbit Versa 3 / Sense の文字盤を作る

Last updated at Posted at 2021-12-10

はじめに

スマートウォッチ、アクティビティトラッカーでは聞きなじみの多い「Fitbit」。Fitbit Versa や Sense といったスマートウォッチでは、ギャラリーにある膨大な種類の文字盤から好きなものを選んで、自分好みのスマートウォッチへと変えることができます。また、自分でも JavaScript や TypeScript を使って作ることができます。

自分で作るための 2 つの手法

Fitbit Studio を使う

一番オーソドックスなやり方かと思います。ウェブ上でコーディングができ、データは Fitbit のサーバー上に保存されます。特別準備がなくても、WiFi 接続の準備ができている手持ちの Fitbit もしくは PC にインストールしてある Fitbit OS Simulator (Windows 版, Mac 版) があればサイドロードもできたりします。
一方で、少し試した感じでは入力補完が利かなさそうなので、そのあたり頼りにしてるような僕みたいな人には向かないかもしれないです。
開発環境だけの用意なので、ギャラリーへ公開する際は生成物をダウンロードして別ページでおこなう必要があります。ワンストップでいけるわけじゃないんですね…。

ローカル環境コマンドラインを叩いて作る

PC ローカルでお好きなエディターを使って開発することもできます。
Node.js をインストールしておき、コマンドを入力することで環境を作ることができます。1
また、Fitbit Studio でできるデバイスへのサイドロードなどはコマンドでもできます。

今回はこちらのやり方で説明します。

環境を準備する

必要なのは以下の通りです。

  • Fitbit Studio にアクセスし開発者として登録しておく
    • 利用規約への同意が最初に必要です。ログインは Fitbit アカウントで OK です。コマンドライン上でビルドする際に、このアカウント情報を要求されます。
  • Fitbit Versa 3 または Sense
    • 今回は Fitbit OS 5.x (SDK 5.0 以上) の 2 デバイスに対してのおはなしですが、 Versa 2 などの OS 4.x (SDK 4.x) も作ることが可能です。
    • デバイスにサイドロードする際は、デバイスがインターネットに接続できるよう準備をしておいてください。また、デバイスの「設定」から「開発者用ブリッジ接続」を選んで「オンにする」のトグルをオンにし、開発者モードを有効にしておきます。
  • Fitbit OS Simulator
    • Windows 版Mac 版があります。上記デバイスを持っていない人でもこれで開発が可能ですし、自分のデバイスにいきなり突っ込むのもなー…っていう方にも。
  • Node.js
    • Windows 環境では入ってるケースあまりないと思うので入れます。バージョンはよっぽど古くなければ大丈夫なはず。
  • (参考) Fitbit アプリとスマートフォン
    • Companion と呼ばれる機能を作成するようにした場合、デバイスにサイドロードする際は、デバイスと紐付けをしたスマートフォンもあわせて必要です。
    • 文字盤を作る際に必要となるケースでは、設定項目を作りたいときなどには Comapnion を使うことになります。

プロジェクトを作る

ターミナルなどを立ち上げ、プロジェクトを生成したいディレクトリへ移動し、以下のコマンドを入力します。

npx create-fitbit-app [プロジェクト名]

Versa 3 / Sense よりも前のデバイスを対象としたものを作りたい場合は、オプションで SDK バージョンを指定することができます。ただし、4.x と 5.x とでは互換性がないため、Versa 2 と Versa 3 / Sense 両方に対応した文字盤を作ることはできません。

npx create-fitbit-app test-clock-3 --sdk-version 4.3.1

[プロジェクト名] がディレクトリ名となり、中に必要なファイルが準備されます。
image.png
しばらくすると作るアプリの種類やアプリ名などが聞かれます。まずアプリの種類は、今回は文字盤を作るので clockface を選択します。
image.png
次にアプリ名ですが、プロジェクト名と同じであればこのまま Enter キーで次へ進んでもかまいませんが、ここで好きなアプリ名へ変更することもできます。
image.png
Companion コンポーネントを作るかどうかを聞かれます。文字盤の設定画面を作るときなどには Y を入力します。今回は作らないので N で OK です。
image.png
最後にどのデバイス向けに作るかですが、今回は Versa 3 と Sense しか選べない上、文字盤の作成に際してどちらも変わりはないので、どちらも対応としておいて大丈夫です。
SDK 4.x 対応のデバイスに向けて作る場合、Versa シリーズと Ionic とではディスプレイ解像度が違うなど差異があることに注意してください。
image.png
これでできあがりました。修正したい場合は、プロジェクト内にある package.json を編集します。

これでもう作ることは可能ですが、作成したプロジェクトのディレクトリへ移動し、以下のコマンドを入力することで TypeScript への変換および入力補完に対応します。

npx fitbit-sdk-types

とりあえず作ってみる

文字盤なのでとりあえず時間を出すところから始めます。 resources/index.view が文字盤の表示になります。SVG っぽい何かで書けますが、ひとまずこんな具合にしておきます。

index.view
<svg viewport-fill="black">
	<text id="timeText" font-size="30" fill="white" text-length="10"/>
</svg>

続いてコード側です。メインになるのは app/index.ts なので、ここに以下のようにコードを入力します。

index.ts
import clock from "clock";
import document from "document";

const timeText = document.getElementById("timeText") as TextElement;

clock.granularity = "seconds";
clock.addEventListener("tick", () => {
    const date = new Date();
    timeText.text = `${date.getHours()}:${date.getMinutes()}.${date.getSeconds()}`;
});

割と雑ですがこれで OK です。

実際に確認してみる

これで一旦確認してみます。まず、サイドロードしたいデバイスか、Fitbit OS Simulator を準備します。どちらかだけ起動・有効にしておいてください。
ターミナルでプロジェクトのディレクトリへ移動し、以下のコマンドを入力します。

npx fitbit

初回起動の際、開発者アカウントとしてのログインを求められます。ブラウザーが自動で立ちあがり、ログイン済みであればそのままログインが完了します。この状態で

build

を入力するとビルドができます。そこから

install

を入力することで、現在接続が待機しているデバイス・シミュレーターのどちらかに自動接続し、サイドローディングがおこなわれます。
image.png
これでできあがりです。やりましたね!
なお、 build install をいっぺんにできる bi コマンドもあります。作っては試しを繰り返すならこのコマンドの方が楽です。

心拍数や歩数なども取得してみる

スマートウォッチといえばこれらセンサーへのアクセスですよね。SDK ではセンサーへのアクセスも用意されています。
使用したいセンサーはそれぞれユーザーの許可が必要になります2ので、 package.json に必要なパーミッションを宣言しておく必要があります。

package.json
"fitbit": {
  (省略)
  "requestedPermissions": [
    "access_activity",
    "access_heart_rate"
  ],
  (省略)
}

今回は Activity として別ファイルにクラスとして作成します。 app/Activity.ts を作成し、以下のようなコードを入力します。

Activity.ts
import { me } from "appbit";
import { today } from "user-activity";
import { HeartRateSensor } from "heart-rate";
import clock from "clock";

export class Activity {
    public stepsCallback: (steps: string) => void;
    public heartRateCallback: (rate: string) => void;

    private deniedText = "DENIED";
    private hrm: HeartRateSensor = null;

    public initialize() {
        // 歩数の取得許可チェック
        if (me.permissions.granted("access_activity")) {
            clock.granularity = "seconds";
            clock.addEventListener("tick", this.updateSteps);
        } else {
            this.stepsCallback(this.deniedText);
        }

        // 心拍数の取得許可チェック
        if (HeartRateSensor && me.permissions.granted("access_heart_rate")) {
            this.hrm = new HeartRateSensor();
            this.hrm.addEventListener("reading", this.updateHeartRate);
            this.hrm.start();
        } else {
            this.heartRateCallback(this.deniedText);
        }
    }

    private updateSteps = () => {
        const step = (today.adjusted.steps || 0);
        this.stepsCallback(step.toString());
    }

    private updateHeartRate = () => {
        const rate = this.hrm.heartRate;

        if (rate == null || isNaN(rate)) {
            this.heartRateCallback("---");
        } else {
            this.heartRateCallback(rate.toString());
        }
    }
}

export default Activity;

そして index.view に 2 つの Text オブジェクトを作り、それぞれ stepText hrmText として、 app/index.ts は以下のように追記します

index.ts
import clock from "clock";
import document from "document";
import Activity from "./Activity";

// さっきの時計の部分は省略

const stepText = document.getElementById("stepText") as TextElement;
const hrmText = document.getElementById("hrmText") as TextElement;

const activity = new Activity();

activity.stepsCallback = x => stepText.text = "Steps: " + x;
activity.heartRateCallback = x => hrmText.text = "HRM: " + x;

activity.initialize();

あとは npx fitbit した後にコマンドで bi を入力してサイドローディングすると、歩数と心拍数が表示されるようになります。シミュレーター上では、心拍数は任意の数字を入れることができますが、歩数はシミュレーター側で自動生成です。
image.png
時計としてはあまりにも雑ですが、おおよその構成要素としては満足できるかと思います。ここから、画像を作ったりしてそれっぽく作り替えていけば、オリジナルな文字盤ができるというわけです。
あとはバッテリーの残量や充電状態も取得することができます。こちらは今回省略しますが、Power API のリファレンスをもとに実装すればなんとなく作れると思います。

実際に作ってみた例がこちら

image.png
アナログ時計は公式のガイドに作り方が載っているので、こちらを参考にしてみてください。

注意点

ギャラリーへの公開

Gallery App Manager から公開ができます。初めてアクセスした際、開発者名を求められますが、一度設定すると変更ができないそうなので、適当な名前をつけて後で悲しい目に遭わないように気をつけてください。
準備ができたら、[Create app] をクリックし、ギャラリーに公開するアプリ名、アプリの種類を選択します。今回は文字盤なので Clockface で OK
image.png
概要の設定ページに飛びます。
Tags は自分が作ったものに近いものを選んでチェックします。
General details には、サポート問い合わせ先のメールアドレスまたはウェブサイト URL のどちらかを入力します。どちらかしか入力できないようになっています。
Localized details にはアプリの詳細を記載します。デフォルトの英語はこのまま消せないので、雑に書いておきます。ただし、どの言語も140文字以上の入力が必要です。なので、日本語で「シンプルな時計です」のような説明だけでは保存すらできません。
Manage versions に実際にビルドしたファイルを配置します。作ったものは build/app.fba として保存されていますので、これをドラッグ&ドロップします。横にあるチェックボックスは、このアプリに含まれる権利がすべてクリアになっていることを表明するためのものです。おおよそ大丈夫だと思いますが、チェックを入れないとアップロードを受け付けてくれません。
ファイルをアップロードすると今度はスクリーンショットをアップロードすることができるようになります。スクリーンショットは、文字盤が起動している状態でターミナルから以下のコマンドを入力すると、プロジェクトのディレクトリの直下に png ファイルとして保存されます。

npx fitbit
screenshot

ここまでおこなうと、非公開状態でギャラリーに存在するようになります。ページ上部の Link にあるリンクがアプリのギャラリーページへのリンクになっているので、知っている人だけこの文字盤をインストールすることが可能です。
これをギャラリーの一覧にも載せる公開状態にするには、ページ右上の Submit for Review を押して審査に提出する必要があります。

まとめ

これで、開発の準備からギャラリーへのアップロードといった一連のサイクルができるようになりました。あとはリファレンスなどを駆使し、自分だけの文字盤を作るだけです。
ぜひチャレンジしてみてください。

参考文献たち

  1. WSL を使っての環境整備はサポートされていないようです (当初一生懸命頑張ってうまくいかなくて、ドキュメント見たらサポートしてない旨書かれてました…)

  2. ギャラリーからのインストール時にセンサーへの許可を操作するダイアログが表示されます

12
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?