26
32

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.

開発初心者でもできるFitbit Clock Faceの作り方

Last updated at Posted at 2020-03-01

はじめに

某研究室においてfitbit Ionicを使っていたのですが、新発売されたVersa2に最近乗り換えました。

fitbitの時計盤は心拍数や歩数などを表示でき、ストアから様々なものをイントールできます。
筆者はデジタル時計はなぜか苦手で、アナログ表記でないと時間の感覚が掴みづらいのに加え、シンプルなデザインを求めていました。
しかし、いざ探してみると、デジタル盤やデザインがごちゃごちゃしているものが多く、求めている自分好みのシンプルな時計盤がなかなかない、、

そこで、ストアにないなら自分で作ろう、ということで開発初心者なりに作ってみました。

日本語の記事はまだまだ少ないのでなるべく丁寧に書いていこうと思います。


fitbitの公式サイトはこちら

目的の時計盤

  • シンプルなアナログ時計
  • 心拍数、歩数、バッテリー、日付、曜日を表示
  • 上記情報をタッチで隠せる

これを目標に作っていきます。

開発準備

Getting Startedに沿って準備を進めていきます。

開発者アカウント作成

まず、アカウントのサインアップセットアップ、シミュレータのダウンロードを行います。
次にfitbit studioにアクセスし、Startからfitbitユーザアカウントでログインします。
sdk_start.png

これにより、開発者ツールが使用可能になります。

Project作成

New ProjectからProjectの名前を入力し、Templateを選択します。
スクリーンショット 2020-03-02 8.43.28.png

デジタル時計のサンプルがありますが、今回は完全オリジナルで作成するためEmpty Projectで進めます。
スクリーンショット 2020-03-02 8.44.58.png

この画面が出たら準備完了です!
スクリーンショット 2020-03-02 8.45.49.png

コーディング、シミュレートから実機へのインストールまで全てこのfitbit studio上のみでできます。便利。

ただし、自分の好きなエディタで開発したい!という方にはこの記事を参考にしてみてください。
Fitbit アプリケーションをコマンドラインで開発する | ひよこまめ

#フォルダ構成
フォルダ構成についてざっくりまとめました。
詳しくはGuidesを参照。

  • app/index.js*
    • 実機での実装を記述
  • companion/index.js
    • スマホ側の実装を記述
    • appとのやり取りや、インターネット通信を行う場合はここで処理
    • 今回は使いませんが、例えば天気情報を時計盤に表示したい時はここを使います
  • resources/
    • GUI関係の記述、画像ファイルの置き場
  • resources/index.gui*
    • SVGでレイアウトを記述
  • resources/widgets.gui*
    • 外部importなど
  • resources/style.cdd
    • レイアウトの装飾を記述
    • 簡単なものであればindex.guiへの記述だけで済みます
  • package.json*
    • 各種設定やPermissionを記載
    • fitbit studioではUIで設定可能です

*がついているファイルは必須のものです。

これらを以下のように用意します。
スクリーンショット 2020-02-21 3.04.42.png

いざ、開発

各ファイルごとにポイントを示していきます。

レイアウトの定義

画面全体をpageとし、時計盤本体と各種情報の2つに大別しています。

index.gui
<svg id="page" pointer-events="visible">
  <svg>
    <image id="background" href="screen.png" x="0" y="0" width="100%" height="100%"/>
    <g id="mins" pointer-events="visible" transform="translate(50%, 50%)">
      <rect x="$-4" y="-110" rx="3" ry="3" width="7" height="100" fill="fb-white"/>
    </g>
    <g id="hours" pointer-events="visible" transform="translate(50%, 50%)">
      <rect x="$-6" y="-75" rx="3" ry="3" width="7" height="65" fill="fb-white" />
    </g>
    <g id="secs" pointer-events="visible" transform="translate(50%, 50%)">
      <rect x="$" y="-110" width="2" height="110" fill="fb-red" />
      <circle cx="$-1" cy="-110" r="3" fill="fb-red" />
    </g>
    <circle cx="50%" cy="50%" r="10" fill="#111111" />
  </svg>
  
  <svg id="Informations" font-family="SevilleSharp-Book" fill="fb-white">
    <svg id="stepsContainer" x="0" y="83%">
      <image id="steps_icon" href="steps.png" x="20" y="0" width ="25" height="25"/>
      <text id="steps" x="0" y="45" font-size="25">10000</text>
    </svg>
    <svg id="hearContainer" x="86%"y="83%">
      <image id="heart_icon" href="heart.png" x="2" y="0" width ="25" height="25" />
      <text id="hrm" x="0" y="45" font-size="25">100</text>
    </svg>
    <svg id="batteryContainer" x="10" y="10">
      <image id="thunder_icon" href="thunder.png" x="3" y="0" width="25" height="25"/>
      <text id="battery" x="0" y="45" font-size="25">100</text>
    </svg>
    <svg id="dateContainer" x="83%" y="10%">
      <text id="date" x="10" y="2" font-size="30">15</text>
      <text id="day" x="0" y="25" font-size="25">Sun</text>
    </svg>
  </svg>
</svg>
  • 時計盤
    背景を記述するのは面倒だったので画像を作成し読み込み
    時計の針関係はGuidesのClock facesを参照

  • 各種情報
    アイコンはここのIconsからダウンロード
    <text>には表示されうる最大桁数で適当な数字を設定
    これらはapp/index.jsで毎秒更新

表示場所や大きさ、色なども全てここで指定しています。
もちろんcssで記述しても構いません。

widgets.guiには以下の通り記述してください。

widgets.gui
<svg>
  <defs>
    <link rel="stylesheet" href="styles.css" />
    <link rel="import" href="/mnt/sysassets/widgets_common.gui"/>
  </defs>
</svg>

針の挙動や情報セット

importとid紐付け

index.js
import document from "document";
import clock from "clock";
import { today } from "user-activity";
import { HeartRateSensor } from "heart-rate";
import { battery } from "power";


let hourHand = document.getElementById("hours");
let minHand = document.getElementById("mins");
let secHand = document.getElementById("secs");

let day = document.getElementById("day");
let date = document.getElementById("date");
let steps = document.getElementById("steps");
let hrm = document.getElementById("hrm");
let btry = document.getElementById("battery")

let page = document.getElementById("page");
let info = document.getElementById("Informations");

画面タッチでの表示変更や時計の針の設定(Guides参照)

index.js
// デフォルトで情報は隠す
info.style.display = "none";

// 画面切り替え関数
function toggle(ele){
  ele.style.display = (ele.style.display === "inline") ? "none" : "inline";                 
}

// 画面タップで情報を隠す隠さないの切り替え
page.onclick = function(){
  toggle(info);
}

//時計の針設定
function hoursToAngle(hours, minutes){
  let hourAngle = (360 / 12) * hours;
  let minAngle = (360/ 12 / 60) * minutes;
  return hourAngle + minAngle;
}

function minutesToAngle(minutes){
  return (360 / 60) * minutes;
}

function secondsToAngle(seconds){
  return (360 / 60) * seconds;
}

各情報をtextにセットする関数

index.js
//日付のテキストセット
function setDate(val) {
  date.text = val;
}

//曜日のテキストセット
//getDayにより0~6で曜日を取得できるためそれぞれを文字に対応
function setDay(val) {
  switch(val){
    case 0:
      day.text="Sun";
      break;
    case 1: 
      day.text="Mon";
      break;
    case 2:
      day.text="Tue";
      break;
    case 3:
      day.text="Wed";
      break;
    case 4:
      day.text="Thu";
      break;
    case 5:
      day.text="Fri";
      break;
    case 6:
      day.text="Sat";
      break;
  }
}

//バッテーリのテキストセット
function setBattery(val){
  btry.text = val;
}

//歩数のテキストセット
function setSteps(val){
  steps.text = val;
}

//心拍数のテキストセット
function setHeartRate(val){
  hrm.text = val;
}

情報を毎秒更新

index.js
//時計の更新頻度を毎秒に設定
clock.granularity = "seconds";

//秒経過ごとに情報更新
clock.ontick = evt =>{
  let d = evt.date;
  let hours = d.getHours() % 12;
  let mins = d.getMinutes();
  let secs = d.getSeconds();

  //時計針の更新
  hourHand.groupTransform.rotate.angle = hoursToAngle(hours, mins);
  minHand.groupTransform.rotate.angle = minutesToAngle(mins);
  secHand.groupTransform.rotate.angle = secondsToAngle(secs);

  //日付
  setDate(d.getDate());
  //曜日
  setDay(d.getDay());
  //バッテリ
  setBattery(Math.floor(battery.chargeLevel))
  //歩数
  setSteps(today.local.steps);
  
  //心拍数
  var hr = new HeartRateSensor();
  hr.onreading = function() {
    setHeartRate(hr.heartRate);
    //Stop monitoring the sensor
    hr.stop();
    }
  //Begin monitoring the sensor
  hr.start();
}

基本的にGuidesに参考コードが載っているのでそのまま使っています。

packageの設定

package.jsonに名前や機種、パーミッションの設定があるので必要に応じて変更してください。

シミュレータで確認

コードを書き終わったらシミュレータでデザインと挙動の確認を行なっていきます。

開発準備でダウンロードしたFitbit OS Simulatorを起動し、以下の手順でシミュレータに表示させます。

  1. fitbit studioのヘッダー真ん中付近のアイコンをクリック
  2. PhonesとDevicesにSimulatorとfitbitの機種が出てきます
  3. それぞれクリックし緑のConnected状態になれば接続完了(出てこなければRefreshや再起動を試してみてください)
スクリーンショット 2020-02-26 19.09.54.png 4. Run(Command+R)でビルドとインストール

このようになれば成功です。
画面クリックで情報の切り替わりの確認や、文字のずれなどの調整も適宜行なってください。
スクリーンショット 2020-03-02 8.07.28.png

実機へのインストール

シミュレータで最終確認を行ったら、いよいよ実機へインストールです。

まず、fitbit実機の設定からDeveloper Bridgeをオンにし、Connected to Serverの状態にします。
fitbit studioのDeviceの欄に実機の名前が出るのでクリックし、緑のConnected状態になることを確認します。
後はシミュレータへのインストールと同様Runで実機にインストールされます。

これで、自分だけの時計盤が使用可能になります!

時計盤の削除

別に開発した時計盤をインストールしたい場合、うまく上書きされない場合があります。
その時は、スマートフォンfitbitアプリの開発者向けメニューからSIDELOADED APPSの中の消したい文字盤を削除してください。

おわりに

シンプルな時計盤開発の方法をざっくりとまとめてみました。
もっと凝ったことをやりたい場合は公式Guidesに載っているのでそちらを参考に。

ほぼ開発経験や技術がなくともなんとなくで作ることができたので、ぜひ自分好みの時計盤を作ってみてください!!

26
32
1

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
26
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?