スマートウォッチPebbleTimeでNEM API を利用する

全くC言語とJavaScriptを触ったことのない私が、cとJsを利用しNEMのAPIにリクエストを送り、PebbleTimeと呼ばれるスマートウォッチにその結果を表示してみたので、記録として書きます。

#必要になる知識
- C言語の基礎的な知識
- JavaScriptの基礎的な知識
- NEM APIについての基礎的な知識
- PebbleチュートリアルPart3[Adding Web Content]までの知識

　C,JavaScriptに関しては省略します。今回のためだけに初めから勉強してみました。本当に基礎的な知識しかおさえていません。
　NEM APIに関しては[別のブログ](https://cryptocurrency.muragon.com/entry/10.html)にて記事を書いているのでそちらを見てみてください。
　[Pebbleチュートリアル](https://developer.pebble.com/tutorials/watchface-tutorial/part1/)は英文ですが、Google翻訳で充分読める他、検索すると日本語の個人ブログなどで取り上げられていたりするので、そちらを探してみてください。

#PebbleKit JS
PebbleチュートリアルPart3[Adding Web Content]を進めている中で最もわかりにくかったのが「今これどこで動くコード書いてるんだ？」というところでした。

これに対する答えは、言葉では説明するよりも図を見たほうが早いと思うので、PebbleKit JSを利用してインターネットにHttpリクエストを送信するときの、インターネットとphoneとwatchの関係を図にしたので載せておきます。
![20171210-1.png](https://qiita-image-store.s3.amazonaws.com/0/216882/97708e52-73f2-aeef-ea4e-1a2472a7a918.png)

　以下、実際に行った手順を書いていきます。

#1.TEMPLATE "HelloWorld"
　前提として、CloudPebbleでSDK4を利用しての作業とします。

　何もないところから書いても良いのですが、今回はNEM APIにアクセスすることが目的だったので、テンプレート使用しました。CREATE NEW PROJECTのTEMPLATEから、HelloWorld(SDK Demos)を選択。実行してもらえれば解ると思いますが、アプリを実行すればPebbleの画面上に"Hi,I'm a Pebble!"が表示されるだけのアプリです。

#2.hello_world.c
　ここから、テンプレートの中身をいじっていきます。とはいえ、記述する内容はほとんど全てチュートリアルのPart3までで出てくる内容なので、それらと同じように記述するだけです。

```c:hello_world.c
#include <pebble.h>

static Window *s_window;
static TextLayer *s_text_layer;
// 追加:AppMessageによりpbhone側から送られてくるmessageを保管するバッファ
static char block_height_buffer[32];

// 追加:phone側からwatch側に送られるmessageの受信に成功した時の処理
// 　　 チュートリアル内では"AppMessageInobxReceived(callback)"と呼ばれる
static void inbox_received_callback(DictionaryIterator *iterator, void *context){
  Tuple *block_height_tuple = dict_find(iterator, MESSAGE_KEY_height);
  if(block_height_tuple){
    snprintf(block_height_buffer, sizeof(block_height_buffer), "blockHeight\n%d", (int)block_height_tuple->value->int32);
    text_layer_set_text(s_text_layer, block_height_buffer);
  }
}

// 追加:messageを取り漏らした時のエラー処理
static void inbox_dropped_callback(AppMessageResult reason, void *context){
  APP_LOG(APP_LOG_LEVEL_ERROR, "Message dropped!");
}

// 追加:message送信を失敗した時のエラー処理
static void outbox_failed_callback(DictionaryIterator *iterator, AppMessageResult reason, void *context){
  APP_LOG(APP_LOG_LEVEL_ERROR, "Outbox send failed!");
}

// 追加:message送信に成功した時の処理
static void outbox_sent_callback(DictionaryIterator *iterator, void *context){
  APP_LOG(APP_LOG_LEVEL_INFO, "Outbox send success!");
}


static void init(void) {
  // 追加:上記で作成したcallbackの登録
  app_message_register_inbox_received(inbox_received_callback);
  app_message_register_inbox_dropped(inbox_dropped_callback);
  app_message_register_outbox_failed(outbox_failed_callback);
  app_message_register_outbox_sent(outbox_sent_callback);
  
  // 追加:AppMessgeをオープンの状態にする
  const int inbox_size  = 128; //set buffer size
  const int outbox_size = 128; //set buffer size
  app_message_open(inbox_size,outbox_size);
  
  // Create a window and get information about the window
  s_window = window_create();
  Layer *window_layer = window_get_root_layer(s_window);
  GRect bounds = layer_get_bounds(window_layer);

/* 以下略 */
	
```

　これでwatch側の変更は終了です。あとはPebbleKitJS用のjsファイルを作成して、phone側の挙動を決めてあげます。


#3.index.js(PebbleKitJS)
　基本的にはチュートリアルのPart3で利用したコードを再利用できます。チュートリアルのPart3が[現在位置の取得]→[成功であればHttpリクエストの送信]であるのに対し、こちらは即Httpリクエストの送信を行っているのでチュートリアルの内容より単純です。

```js:index.js
//チュートリアルPart3で作成したものと同じもの
var xhrRequest = function(url, type, callback){
  var xhr = new XMLHttpRequest();
  xhr.onload = function(){callback(this.responseText);};
  xhr.open(type, url);
  xhr.send();
};


//NEM APIにHttpリクエストを送り、結果をAppMessageを介してwatch側に送信する
function getInfo(){
  //今回はテストなのでurlはハードコードしています
  var url = "http://45.76.107.205:7890/chain/height";
  
  xhrRequest(url,"GET",
    function(responseText){
      //返信をjson形式にパースする
      var json = JSON.parse(responseText);
      
      //jsonからheightを取り出す
      var height = json.height;
      
      //受信message確認用にログを出力
      console.log("json message is :" + height);
      
      //watch側へはjsオブジェクトをAppMessageとして送信するため、
      //送信用のjsオブジェクトを作成する
      var dictionary = {"height":height};
      
      //AppMessageをwatch側へ送信
      Pebble.sendAppMessage(dictionary,
        function(e){
          console.log("info sent to Pebble Success!");
        },
        function(e){
          console.log("Error sending message to Pebble!");
        }
      );
    }
  );
}


//PebbleKitJSがreadyの状態になった時の挙動を決める
Pebble.addEventListener("ready",
  function(e){
    console.log("PebbleKit JS ready!");
    
    //PebbleKitJSがreadyになるタイミングで初回のheightを取得
    //(今回NEM APIにリクエストを送るのはここだけ)
    getInfo();
  }
);
```

　以上で、PebbleKitJSの実装も終了です。watch側のボタン操作でブロック高さの更新や、時間によってポーリングして値を更新するなどしたくなるところですが、していません。単に[アプリが起動]→[アプリが起動するタイミングでPebbleKitJSがreadyになる]→[PebbleKitJSがreadyになるタイミングでHttpリクエストの送信]をしているだけです。

　後は、CloudPebble上でRUN BUILDして動かしてPebble上に"blockHeight ***(block高さ)"が表示されることが確認できれば完了です。

　WatchFaceでブロック高さを取得したら"ブロック高さを時間軸として生きる最高にロックなコイナー"になれますね。「blockheight〇〇〇〇から会議でさー、」みたいな…


#Pebbleで出来そうなこと
　このままだと単に"PebbleKitJSを利用してHttpリクエスト飛ばしてみた"の記事になるので、Pebbleを使って出来そうなことを詳細な仕様を深く考えずに書いてみます。

- 着金、ハーベスト、ノードが落ちた時等の通知機能
- Pebbleに秘密鍵を入れてPebble内でtxに署名(Pebbleのハードウェアウォレット化)
- Pebbleから(phoneを介して)モザイク送信txを送信。ホームIoT遊びなどに
- 受け取りアドレスをQRコードで表示

　カメラも付いていなければ何かを入力するのも厳しく、基本的に今はスマホの補助的な立場で使われていることが多いので通知機能が主になるかもしれませんね。面白いアイデアあれば教えてください。


#さいごに
　正直、cもjsもpebble.cもPebbleKitJSも今は雰囲気で使っている状態ですが、それでもチュートリアルで覚える内容だけ使えばNEMブロックチェーンのステータスを引っ張ってこれるのは良いですね。簡単にブロックチェーンで遊べることが伝われば良いなと思います。

　ついでですが、チュートリアルでは"jsファイルは好きな名前に出来る"とあるけど、実際にはindex.jsにしないとビルドする時に"index.jsが無いぞ"と怒られてダメだった。SDKの仕様変更か何かなのかな？