プログラミング初心者がPebble Time Watchfaceを作ってみた

<img src="https://qiita-image-store.s3.amazonaws.com/0/66860/6ffaa804-5f4b-21cd-18c0-7c4608baacb3.png">


こんにちは、この記事はGoodpatchのエンジニア※がお送りする[Goodpatch Advent Calendar 2015](http://qiita.com/advent-calendar/2015/goodpatch)の22日目の記事です。

先日はAndroidエンジニアの @u-16 [MaterialDesignと戯れてみて思ったこととか](http://qiita.com/u-16/items/f6b3bd47e9a23f6ece0e) でした。

私は[Prott](https://prottapp.com/)でプロジェクトマネージャーをやっています。今回は、プログラミング未経験でPebble TimeのWatchfaceを開発してみた話を非エンジニア枠でひっそり書いてみようと思います。


#Pebble Timeって？

[Pebble Time](https://www.pebble.com/)はスマートウォッチのひとつでApple WatchやAndroid Wearと違う点は

- OS：独自のPebble OS
- ペアリング：AndroidとiOSの両方とペアリングが可能！
- 操作方法：タップではなく、左右についているボタンのみ

です。他、Pebble Time Roundはびっくりするくらい薄くて、普通の時計をつけている感覚でつけていられます。
アニメーションがいい感じで使っていてすごい楽しいです。Watchfaceはおそらく非公式であろうキャラクターものや、アナログ、デジタル共にたくさんあります。

<img width="300" src="https://qiita-image-store.s3.amazonaws.com/0/66860/ffd7fcce-6cea-f45b-9826-994259a6f3cf.png">　<img width="300" src="https://qiita-image-store.s3.amazonaws.com/0/66860/fb346a10-b541-1a26-5f74-77d5067ee862.png">

Pebble Time for Androidはこんなかんじ。


#Watchfaceを作ってみる

##まずはじめに

##開発環境

[Cloud Pebble](https://cloudpebble.net/)という、オンラインの開発環境で今回は開発をしました。



##言語

基本的にC言語での開発になりますが、~~[Simply.js](http://simplyjs.io/)を利用することで~~ [Pebble.js](https://developer.getpebble.com/tutorials/pebble-js-tutorial/part1/)を利用することで JavaScript のみの開発もできるとのこと。

https://developer.getpebble.com/

英語ですが、公式できちんとドキュメントを用意してくれています。

![image](https://qiita-image-store.s3.amazonaws.com/0/66860/c9463b5e-2d3a-2691-7e89-28494edcdbf0.png)


##画面サイズとか

Pebble Timeはシリーズで現在までで、3種類出てるので画面サイズなどはそれぞれ、下記で用意が必要です。

<img width="669" alt="pic 2015-12-22 1.24.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/66860/685158cb-3d0c-472c-0b1f-e09d3f2ce2da.png">

[DEVELOPER GUIDES](https://developer.getpebble.com/guides/)

![pic 2015-12-21 19.39.43.png](https://qiita-image-store.s3.amazonaws.com/0/66860/45f680a0-a5b6-2535-f16d-8be85f8e5be9.png)

[COLOR PICKER](https://developer.getpebble.com/more/color-picker/)

Pebble内では上記の色のみ使用可能なので、デザインするときは上記を参考にしながら作ります。



[BENEFITS OF DESIGN GUIDELINES
](https://developer.getpebble.com/guides/design-and-interaction/benefits/)

デザインガイドラインも用意してあります。



上記に目を通してみて、初めてのプログラミングは、まず簡単にこんな感じに作ってみよう！っていうことで開発をスタート。

![pic 2015-12-21 19.37.50.png](https://qiita-image-store.s3.amazonaws.com/0/66860/0da31b93-7a04-c41d-d652-adb8a289575d.png)

#作ってみた

とりあえず[チュートリアル](https://developer.getpebble.com/tutorials/watchface-tutorial/part2/)とか、サンプルコードを引っ張ってきて、理解しながらやってみました。初めてのプログラミングでも、コードをちゃんと読めば理解できるので、いいかんじ。

```c:main.c

#include <pebble.h>

static Window *s_main_window;

static GBitmap *s_bitmap;
static BitmapLayer *s_bitmap_layer;

static TextLayer *s_time_layer, *s_date_layer;


static void update_time() {
  // Get a tm structure
  time_t temp = time(NULL); 
  struct tm *tick_time = localtime(&temp);

  // Write the current hours and minutes into a buffer
  static char s_buffer[8];
  strftime(s_buffer, sizeof(s_buffer), clock_is_24h_style() ?
                                          "%H:%M" : "%I:%M", tick_time);

  // Display this time on the TextLayer
  text_layer_set_text(s_time_layer, s_buffer);
  
  // Copy date into buffer from tm structure
static char date_buffer[16];
  strftime(date_buffer, sizeof(date_buffer), "%b %d (%a)", tick_time);

// Show the date
  text_layer_set_text(s_date_layer, date_buffer);

}

static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {
  update_time();
}



static void main_window_load(Window *window) {
  // Get information about the Window
  Layer *window_layer = window_get_root_layer(window);
  GRect bounds = layer_get_bounds(window_layer);

  // Create the TextLayer with specific bounds
  s_time_layer = text_layer_create(
      GRect(0, PBL_IF_ROUND_ELSE(48, 52), bounds.size.w, 50));

  // Create time TextLayer
  text_layer_set_background_color(s_time_layer, GColorClear);
  text_layer_set_text_color(s_time_layer, GColorBlack);
  text_layer_set_text(s_time_layer, "00:00");
  text_layer_set_font(s_time_layer, fonts_get_system_font(FONT_KEY_BITHAM_42_MEDIUM_NUMBERS));
  text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter);

  // Add it as a child layer to the Window's root layer
  layer_add_child(window_layer, text_layer_get_layer(s_time_layer));
  
  
  // Create date TextLayer
  s_date_layer = text_layer_create(GRect(0, 93, 180, 40));
  text_layer_set_text_color(s_date_layer, GColorBlack);
  text_layer_set_background_color(s_date_layer, GColorClear);
  text_layer_set_font(s_date_layer, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD));
  text_layer_set_text_alignment(s_date_layer, GTextAlignmentCenter);
  
  // Add to Window
  layer_add_child(window_get_root_layer(window), text_layer_get_layer(s_date_layer));
  
  s_bitmap = gbitmap_create_with_resource(RESOURCE_ID_DOG);
  s_bitmap_layer = bitmap_layer_create(bounds);
  bitmap_layer_set_bitmap(s_bitmap_layer, s_bitmap);
  bitmap_layer_set_compositing_mode(s_bitmap_layer, GCompOpSet);
  layer_add_child(window_layer, bitmap_layer_get_layer(s_bitmap_layer));
}

static void main_window_unload(Window *window) {
  // Destroy TextLayer
  text_layer_destroy(s_time_layer);
  bitmap_layer_destroy(s_bitmap_layer);
  gbitmap_destroy(s_bitmap);
  
}


static void init() {
  // Create main Window element and assign to pointer
  s_main_window = window_create();

  // Set handlers to manage the elements inside the Window
  window_set_window_handlers(s_main_window, (WindowHandlers) {
    .load = main_window_load,
    .unload = main_window_unload
  });

  // Show the Window on the watch, with animated=true
  window_stack_push(s_main_window, true);

  // Make sure the time is displayed from the start
  update_time();

  // Register with TickTimerService
  tick_timer_service_subscribe(MINUTE_UNIT, tick_handler);
}

static void deinit() {
  // Destroy Window
  window_destroy(s_main_window);
}

int main(void) {
  init();
  app_event_loop();
  deinit();
}

```

基礎もなにも勉強してないので、最初によくわからなかったポイントは表示位置の変更ルールでした。

日にちを表示させる
`s_date_layer = text_layer_create(GRect(0, 93, 180, 40));`

ここの`(GRect(0, 93, 180, 40));`数字を動かしてあれやこれややってみて、表示したい位置にしてみたけど本当は

`（x,y,w,h)`できちんと計算してやらなければいけないとのこと。

##画像のアップロード
RESOURCESのADD NEWからファイルがアップロードできます。
IDENTIFITERでコード内で指定する名前に設定。

<img width="669" alt="pic 2015-12-22 0.15.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/66860/7f658b5d-5b15-8a72-4c54-c9bc2b10f932.png">

##フォント
システムフォントが何種類か用意されてます。もちろん、カスタムフォントも使えます。今回はシステムフォントを使っています。

https://developer.getpebble.com/guides/pebble-apps/display-and-animations/ux-fonts/


##動作確認

実機でもエミュレーターでもできます。COMPILATIONからどっちで表示させるか変更する。

<img width="903" alt="pic 2015-12-22 0.26.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/66860/4df85f6f-7758-ddde-502e-d0842d9560bd.png">

###CloudPebbleでの動作確認
<img width="1272" alt="pic 2015-12-22 0.13.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/66860/e4be6f33-ee2e-d56d-c23c-f0a1b4fb28b3.png">

右上の緑の再生ボタンを押すと確認できます。こんな感じ。

###Pebble実機での確認

Pebble TimeアプリをDeveloper Connectionで接続すると、確認できるようになります

<img width="300" src="https://qiita-image-store.s3.amazonaws.com/0/66860/4fc0b708-8bac-658d-609a-6139c48d6eb5.png">


<blockquote class="twitter-tweet" lang="ja"><p lang="ja" dir="ltr">いぬ書いて時計にしてみたよ <a href="https://twitter.com/hashtag/pebbletimeround?src=hash">#pebbletimeround</a> <a href="https://t.co/CswTnz3ozy">pic.twitter.com/CswTnz3ozy</a></p>&mdash; mari okada (@px1717) <a href="https://twitter.com/px1717/status/678961923753295872">2015, 12月 21</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>



作ったものが実機ですぐ確認できます。最初はベースの色を黒ではなく、グレーにしてたんだけどすごく薄く見えたので、黒に変更したりしました。

##とりあえず完成！

一旦、上記の流れで
Watchface内で画像を表示させる、時間を表示させる、日にちを表示させるということをやってみました。
全部含めて、2時間もかかりませんでした！

#もっと動きがあるもの作りたい...

Pebble Watchfaceを見ていると、動きがあってかわいいものが多い。ということで、やってみました。

##Animation png

Pebbleはgif animationが使えないので、apngを作ります。使ったサービスは下記。

- [TinyPNG](https://tinypng.com/)：ファイルサイズを落とす
- [APNG Assembler 2.9](http://littlesvr.ca/apng/assembler/assembler.php)：apngを作る

普通のpng表示と違うコードが必要になります。

https://developer.getpebble.com/guides/pebble-apps/resources/animated-pngs/#using-apngs-in-code


##あれ...動かない。

いろいろやってみたけど、apngまわりでとっても苦戦しました。下記を何度も確認して、やっと動くようになりました...

##Raw binary blobでアップロードしているかどうか

ファイルアップロードする際に、pngとか他のものでアップロードすると動いてくれません。

###ファイルサイズが大きすぎていないか
あまり大きすぎると、Pebble上で動いてくれません。20KB以下くらいがよさそう。10KB以下がベスト。


###コードをみてみる

Pebble公式の[ANIMATED PNGS](https://developer.getpebble.com/guides/pebble-apps/resources/animated-pngs/#using-apngs-in-code) 内のコードで動かしてみたけど、動かず。

[HOW-TO replace with your own animated .gif](https://github.com/ctava/pebble-time-watch-face-animated)

ここを見てやってみたら、動くようになりました。（まだちゃんと確認できていないけど）



###一応動いた！

![image](https://qiita-image-store.s3.amazonaws.com/0/66860/a18a0fc7-49cd-fb70-539f-d8ab4a88f131.gif)

こんなかんじ。だけど、なぜか実機で確認ができない...謎です。まだ解決できていません。。


#一通りやってみて

たのしい。だけど、ちょっと難しいことをやろうとすると全然理解できないので、もっと精進します...
一応簡単なWatchfaceを作れるようになったので、もうちょっとブラッシュアップして、アプリのストアに出してみようと思います！

ŧ‹"ŧ‹"ŧ‹"ŧ‹"(๑´ㅂ`๑)ŧ‹"ŧ‹"ŧ‹"ŧ‹" 

<hr>

明日は @migi さんです。おたのしみに！

#追記：2016/04/21

![スクリーンショット 2016-04-12 9.22.16.png](https://qiita-image-store.s3.amazonaws.com/0/66860/7f3fe0ea-b13b-2b73-7873-fe1a8d0c0408.png)

ひっそり、初めてWatchfaceリリースしてみました。（上記のものとは違うけど） Appstoreへのアップ方法など追ってまとめたいと思います！

https://apps.getpebble.com/en_US/application/570b8e4d5523d02f2e000021