Nature Remoを支援

KickstarterでNature Remoを支援した。
https://www.kickstarter.com/projects/926103613/nature-remo-make-any-room-air-conditioner-smart

Nature Remoは、現在使っている赤外線リモコンを飛ばすiRKitの作者である大塚さんがメンバーとなって手がけているIoTデバイスである。
http://nature.global/remo-jp/

Nature Remo(ネイチャーリモ)は、コントローラー機能と電源制御機能を有するデバイスと、スマートフォン アプリとで構成するIoTプロダクトです。スマートフォンアプリを使えば、インターネットを 通じて、どこからでもエアコンを含めた家電のリモコン操作が可能になります。またデバイ スには、温度計機能、湿度計機能、人感センサー、照度センサー、ノイズセンサーも搭載し、室内の 人やペットを検知したり、過去の操作履歴を学習し、電気代を節約します。

IRKitは赤外線リモコンを飛ばすだけだったが、Nature Remoにはいろいろなセンサーがオールインワンになっているので電子工作でセンサーをくっつける手間が省けて自宅ハックに専念できる。8月頃に届く予定だがこの手のガジェットは届いたらラッキーくらいの気持ちで気長に待つ。

IRKit同様にNature RemoでもAPIが公開されるようなのでまたPebbleと連携して操作できるだろう。

IRKitにコマンドを送るPebbleアプリは以下で公開している。
IRKit Remote

IRKit Remote watchappのPebble Time Round対応

PebbleからIRKitにリモコンコマンドを送信するIRKit Remote watchappをPebble Time Roundに対応して公開した。アプリの検索でirkitで検索すると見つかるはず。まだ暖房をつけずに頑張っているので冬の季節には間に合った。

やったこと

  • Pebble SDK 3.7をインストール
  • PBL_ROUNDの時、ステータスバーの残り容量を表示しない
  • PBL_ROUNDの時、メニューのヘッダを追加しない
  • PBL_ROUNDの時、ローディング表示を中央に
GitHubにソースコードを置いてある
https://github.com/makotokw/pebble-irkit-remote

menu_cell_basic_header_draw

メインのリスト表示はPebble SDKのMenuLayerを使っていたのでPebble SDKが良きに計らってくれる、と思っていた。実際に良きに計らってくれた。

セルの文字列が自動でセンター寄せになって、フォーカスのあるセルが画面の中央に来るようになる。ただし menu_cell_basic_header_draw で描画したヘッダは良きに計らってくれなかた。

微妙な左寄せ。

テキストのCommandsに情報量がないのでPBL_RECTのときだけヘッダをつけるように。

  menu_layer_set_callbacks(s_menu_layer, NULL, (MenuLayerCallbacks){
    .get_num_sections = menu_get_num_sections_callback,
    .get_num_rows = menu_get_num_rows_callback,
#ifdef PBL_RECT
    .get_header_height = menu_get_header_height_callback,
    .draw_header = menu_draw_header_callback,
#endif
    .draw_row = menu_draw_row_callback,
    .select_click = menu_select_callback,
  });

ヘッダ、フッタの調整

Pebble Timeからステータスバーを自前で描画していた。(Pebble Time向けのwatchappビルド)

その時の実装が絶対位置指定で残りバッテリーの表示がはみ出てしまうのでこれもPBL_RECTの時だけ表示するように。

またローディング中などの状態表示に使っていた TextLayer も丸型だとはみ出てしまうのでPBL_ROUNDの場合は中央に持ってくるようにした。

丸型UI

Pebble Time Roundの対応、思ったより時間がかかった。丸型UIを舐めていた。もともと既存のPebble向けの実装でも144×168の解像度でハードコーディングするのではなく layer_get_bounds でWindowの領域を取得してUIコントロールをレイアウトしていたのでそれほど修正は必要ないだろうと考えいた。大分甘かった。

Pebble Time Round、仕様上は180×180の解像度になっているけど実際面積は180×180ではない。

スマホのUIだとメニューアイコンなどは四隅に配置しがち。隅でなくても上部のステータスバーや、下部のボトムバーを使ったりする。しかし丸型の場合は四隅がない、そして上部と下部も領域が非常に狭く、中央の小さなスペースにアイコンか文字を出すしか無い。結果的に必要なコントロールは画面中央に持ってこざるを得ない。

今まで丸型のUIをデザインしたことが無かったからそういった難しさをわかっていなかった。シンプルなUIのWatchappだったが、それでもいろいろ勉強になった。

エミュレーター

しかしながら、Pebble SDKのエミュレータは便利すぎる。今ではPebble向けのアプリを作ろうとすると最大3つのプラットフォームに対応する必要がある。

機種 Pebble(Steel) Pebble Time(Steel) Pebble Time Round
プラットフォーム名 aplite basalt chalk
解像度 144×168 144×168 180×180
PBL_RECT PBL_RECT PBL_ROUND
PBL_BW PBL_COLOR PBL_COLOR

考え方としては(PBL_RECT,PBL_ROUND) x (PBL_BW, PBL_COLOR)でPBL_ROUNDxPBL_BW(白黒の丸型)がないマトリクスになる。もう少し細かい機種ごとの違いはHardware Comparisonを参照。

一応、3つのプラットフォームのPebbleを持っているけど1台のスマホから3つのPebbleを管理してデバッグするのは辛い。そこでエミュレータの出番になる。画面が小さいので並べて比較することができて、UIの確認は非常に楽だった。

アプリの公開にアセットが必要

日曜日にビルドしてPebble appstoreにアップロードしたけどなかなか公開されなかった。それもそのはずで、Pebble appstoreではプラットフォームごとにアプリの説明、スクリーンショットを登録しなければならず、それができていないとアップロードしたアプリは公開されない。(Publishボタンが押せない)

iOSの癖で「なかなか審査終わらねーな」と思いつつも待っていたんだけど、「Pebble watchappって審査無いよな?」と気づいたのが今日。前回、Pebble Time(basalt)に対応した時も同じことに遭遇していたのにこの学習能力の無さ。

Pebble Time向けのwatchappビルド

IRKit Remote watchappをPebble Time向けにビルドした。

やったこと

  • HomebrewでSDK3をインストール
  • Pebble Timeプロジェクト変換
  • エミュレータ用に設定ページを変更
  • ステータスバー対応
  • メニューの色を水色に
  • App Storeアイコンの変更

基本的に SDK 3.x Migration Guide を参考にした。

GitHubにソースコードを置いてある
https://github.com/makotokw/pebble-irkit-remote

HomebrewでSDK3をインストール

OS XではPebble SDKをHomebrewでインストールできるようになった。依存関係も解決してくれるので楽になった。

brew install pebble/pebble-sdk/pebble-sdk

Pebble Timeプロジェクト変換

Pebble Time用のプロジェクト変換は以下のコマンドでできる。 appinfo.jsonwscript が変換される。

pebble convert-project

Pebble SDK 3からはPebbleとPebble Time向けの両方のバイナリをビルドしてpbwに両方含めるようになった。Pebble向けの白黒画像やPebble Time向けのカラー画像を同居できる。iOSの Universal Binary の感じ。

エミュレータ用に設定ページを変更

Pebble SDKにエミュレータが入った。PebbleとPebble Timeの両方で確認しないといけなくなったのでエミュレータを活用することにした。エミュレータは以下のようなコマンドで起動できる。

# Pebble Time
pebble install --emulator basalt
# Pebble
pebble install --emulator aplite

エミュレータ用に設定ページを変更する必要があった。実機では設定ページはiOS/Android側のPebbleアプリ内のブラウザで pebblejs://close# に結果を渡せたけどエミュレータの場合は普通に開発PCのブラウザで開くので以下のような技を使う必要があるらしい。
参考: Pebble Smartwatch Emulator in CloudPebble!

 // Get query variables
  function getQueryParam(variable, defaultValue) {
    // Find all URL parameters
    var query = location.search.substring(1);
    var vars = query.split('&');
    for (var i = 0; i < vars.length; i++) {
      var pair = vars[i].split('=');

      // If the query variable parameter is found, decode it to use and return it for use
      if (pair[0] === variable) {
        return decodeURIComponent(pair[1]);
      }
    }
    return defaultValue || false;
  }

  $(document).ready(function () {
    $('#saveButton').click(function () {
      var settings = validateSettings();
      if (settings) {
        var returnTo = getQueryParam('return_to', 'pebblejs://close#');
        document.location = returnTo + encodeURIComponent(JSON.stringify(settings));
      }
    });
  });

ステータスバー対応

Pebble Timeではステータスバーが表示されなくなり、完全なフルスクリーンアプリになった。ステータスバーを表示したい場合は自力で描画する必要がある。
SDK 3.x Migration Guide#Using the Status Bar

しかし自力でステータスバーを描画するとその高さ16を考慮して他のレイヤーを配置しないといけないのでiOS7のステータスバー対応と似たようなことが起きた。

メニューの色を水色に

実際のところPebble Time対応として何もすることがないのでとりあえずハイライトカラーを水色にしてみた。

#ifdef PBL_COLOR
  menu_layer_set_highlight_colors(s_menu_layer, GColorCyan, GColorBlack);
#endif

GColorCyan のような色の定義は Color Picker から選べる。

Pebble

Pebble Time

Pebble TimeではMenu(ListView)の区切り線が表示されなくなった。dividerを描画するAPIは存在するので対応しようかと思ったが、Pebble TimeのTimelineを見ても区切りを配置しないデザインを使っているので特に対応せずPebble Timeのしきたりに合わせることにした。

App Storeアイコンの変更

iOS/Android側のアプリでアイコンが見にくかったのは白黒で背景透過の画像を登録していたせいで、Pebble Timeアプリは背景が黒ベースなので見難くなっていた。そもそもApp Storeに登録するアイコンはPebble側で表示されないので普通にフルカラーのpngで作り直して登録した。

Pebble2IRKit改めIRKit Remote

Pebble2IRKitというPebbleからIRKitに赤外線コマンドを送るというWatchappをPebble appstoreで公開していたが、Pebbleからトレードマークに引っかかるという警告を受けた。

今思うと何故大胆な名前を付けてしまったのかと反省する。以前にもGoogle Calendarって名前が入ったChrome拡張機能をChrome Store公開していたらGoogleから警告されたことがある。その時もそうだけどアプリを提出した時は大丈夫で、公開してしばらくしてから急に怒られるというパターン。

If 30 days is not enough time, please explain to us why and we will review your specific case. If we do not hear from you in the next three months and the name has not been changed, we will remove your app from the appstore.

3ヶ月後にappstoreから削除されてしまうので、IRKit Remoteという名前に変更してsubmitした。IRKit自体がリモコンだからリモートコントロールのリモートコントロールになるし、操作というよりメッセージ投げてるだけだけどわかりやすいかなと思ってその名前にした。(後で Awesome App for Pebble なら良いというのを見つけたのだがPebble Watchappなので for Pebble は自明で冗長かなと思った)

IRKit Remote – Pebble Watchapp

そろそろPebble Timeも手に入るし、Pebble Time対応など欲が出たけど

  • 特に色やタイムラインの必要も無い
  • まだSDK 3.0がBeta版
  • 2.xでビルドしたものは3.0のFirmwareで動く

ということなので2.xの最新であるSDK 2.9でビルドした。Pebble Time向けの開発はPebble Timeが届くか、SDK 3.0の正式版が出てから考えようと思う。

Pebble appstoreを見ると結構な人がアプリ名にPebbleって入れているので、最初に名前をつけた時に影響を受けたと思われる。そしてその結構な人がリネームの必要に迫られていると思うと大変だなと思う。

1.0の互換性問題

アプリの名前を変える時、気持ちが悪いのでプロジェクト名などもまとめて変えてしまう癖がある。GitHubのリポジトリもmakotokw/pebble-irkit-remoteに変えてしまった。

GitHubのリポジトリはリダイレクトしてくれるんだけど、GitHub Pageのgithub.ioのリダイレクトまではさすがにしてくれないようなので1.0の設定ページが404 Not Foundになっているはずである。(Watchappの設定は開発者がWebサイトをホスティングする必要があり、GitHub Pageを利用していた)

申し訳ないが1.0を使っている人は1.1にアップデートするまで設定を変えられない問題が起きている。設定済みのデータはlocalStorageに保存しているので多分大丈夫。

すぐに1.1を入れたい人向けにpebble-irkit-remote_1.1.pbwを置いておく。

Pebble2IRKit iOS版

Pebble2IRKitがiOSでも使えるようになった。Watchappの状態は以下のように変更していった。

  • Public on Android, Waiting for JavaScript bundling on iOS
  • → Public on Android, Waiting for release of iOS app 2.6.4
  • → Feb 04, 2015

WatchappにJavascriptのコードを埋め込んでいる場合は、Appleの規約を守るためWatchappから抜き出さずにPebbleのiOSアプリに含めて配信するという方法が取られているのでiOSアプリの更新を待たないといけない。

残念ながら、Watchappのステータスの変更はメール通知してくれないようだ。しかしよく考えたら、PebbleのiOSアプリの更新が通知代わりになると思ってiPhoneのApp Storeの更新状態を見てみた。

するとPebbleのiOSアプリ 2.6.4は2/17に公開されていた。Watchappを2/4に公開したあと、すぐにPebbleのiOSアプリが審査に入ってくれたんだけど、どうも最近Appleの審査の期間が長いらしく10日くらい待たされた模様。

というわけでiPhoneユーザの人はPebbleアプリがApp Storeで更新されていたら何か使えるWatchappが増えたかチェックしてみると良いと思う。

Pebble2IRKit公開した

需要があるか考えるなPushせよ。

PebbleからIRKitにメッセージ投げて、IoTができるWatchappをPebbleのAppstoreで公開してみた。
Pebble2IRKit

もともと自分で使える分には夏頃できていたけど、冬になってまたエアコンの季節になったので公開できるようにハードコーディングしていた部分を設定画面などを作って対応した。PebbleとIRKit両方持っている人がどれだけ存在するのかとか、IRKit日本でしか売ってなくてPebbleのAppstoreには地域の概念が無いんだけどとか、いろいろ考えると面倒なので勢いで作って、勢いで公開した。Appstoreに無いアプリはMY PEBBLEのところでスクリーンショットが砂嵐で悲しかったし。

Pebble2IRKitはJavascriptのコードが含んであってiOSの場合は、インターネットで取得したコードを実行してはいけないという規約があってそれを回避するためPebbleアプリ本体にWatchAppのJavascriptコードを含めてアップしているため公開まで時間がかかる。今のところWatchAppは Public on Android, Waiting for JavaScript bundling on iOS という状態になっている。Androidはすぐに公開されたのでXperia Tablet Z3 Compactから使えることを確認した。Pebble2IRKitは Remote カテゴリに入っている。

事前にIRKitに送るメッセージを含めたJsonファイルを作ってもらって、それをインターネットに公開してもらうという設定をしてもらわないといけない。ファイルの作り方はここに書いた。これをDropBoxの公開リンクとかで公開してURLをなんとかコピペして設定画面で入力してもらえば動くはず。

Pebble2IRkitはGitHubにソースコードも置いてある
https://github.com/makotokw/pebble-irkit-remote

Watchappの設定画面はWebページを用意しないといけないので若干敷居が高い。今回は面倒なのでGitHub Pageを使った。設定画面のページもGitHubの同じリポジトリに入れてある。

とりあえず自己満足。

Pebbleでエアコンの電源入れた

暑くなって耐えかねたのでPebbleアプリ開発3日目で外出先からの操作に対応した。前回までのバージョンからはIRKitのDevice HTTP APIからInternet HTTP APIに切り替えただけ。

http://getirkit.com/ にある説明の通りに clientkeydeviceid を取得した。スマホのネイティブアプリ内で動いているからCross-Originの制約にも引っかからないし、エスケープする必要なさそうなデータなので単純にXHRでPOSTするだけでうまくいった。ほとんどタイムラグもなくIRKitに届いているようだ。

var irkit = {
  internetHttpApi: 'https://api.getirkit.com',
  clientKey: '',
  deviceId: ''
};
var xhr = new XMLHttpRequest();
xhr.open('POST', irkit.internetHttpApi + '/1/messages', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('clientkey=' + irkit.clientKey + '&deviceid=' + irkit.deviceId + '&message=' + message);

一つ問題があって ++_JS_LIFECYCLE_++:KILLED みたいなログがでてJS側のプロセスが死んでしまうことがある。作ったアプリにバグがあるのか、プロセス管理で殺されることがあるのか、Javascript側のライフタイムについてちゃんと調べていないので調査と対応が必要かも。

JS側が死んでる場合はPebbleでボタンを押しても何も起きないので、JS側でXHRのPOSTが成功したらそこからPebbleにメッセージを飛ばしてPebbleをブルっとさせるようにした。これで送ったつもりが送れていないという問題を回避する。とりあえずJS側が死んでるときはPebble側のアプリを起動しなおせば良さげ。

まぁ普段はPebbleでは時計を表示して、使う時だけwatchappを起動するような形になるから今のデバッグ中にwatchappを起動しっぱなしにしている方がイレギュラーなのかも。

これで今日は帰宅前にPebbleからエアコンを付けて帰ってちゃんと付いてた。Pebbleたっのしぃ(・∀・)

自分用にはこれで満足しているけど、clientkeydeviceid や赤外線コマンドはJS側にハードコーディングしているのでちゃんとアプリにするには設定画面に逃さないといけない。htmlで作った設定画面をJavascrypt Frameworkで表示して値をPebbleに送ったりとかできるらしいので次回はそれを調べる予定。しかし俺はもう今のバージョンで満足してしまっている。

Pebbleでエアコンの電源入れる

ただしまだ室内からのみ。

Pebbleアプリ製作開始から実装を進めた。前回はJavascript(iPhone)からPebbleへメニューの項目を送ってPebble側でメニュー表示するところまでやった。今回は逆にPebbleでメニューを選択したら、選択したメニューのインデックスをJavascript(iPhone)へメッセージを投げるところを実装した。

Javascriptでは以下のようにイベントハンドラを実装できるんだけど、どうやって受け取ったパラメータを取り出すのか良くわからなかった。

Pebble.addEventListener("appmessage",
  function(e) {
    console.log("Received message: " + e.payload);
  }
);

結局、ドキュメントはWorking with the PebbleKit JavaScript Frameworkしかなくてわかりにくかったんだけど送信する時と仕様は同じようだ。

まずappinfo.jsonにキーと対応する数字を設定して(値はてきとー)

"appKeys": {
  "command": 100
},

app_message_outbox_* APIで数値をキーにした値を送る。

pebble_irkit.c
enum {
    MSG_SEND_COMMAND_KEY = 100
};
void send_selected_command(int index) {
  DictionaryIterator *iter;
  app_message_outbox_begin(&iter);
  if (iter == NULL) {
    return;
  }
  dict_write_uint8(iter, MSG_SEND_COMMAND_KEY, index);
  dict_write_end(iter);
  app_message_outbox_send();
}

んで、Javascript側で受け取る。e.payloadappinfo.jsonで指定した名前でパラメータが入る。

Pebble.addEventListener("appmessage",
  function(e) {
    var commandIndex = e.payload.command;
    postMessageToIrkitByDeviceAPI(irkit.commands[commandIndex].message);
  });

ここから先はIRKitのIRKit Device HTTP APIを使っているだけなんだけど、これがLAN内で使うAPIなので部屋の中からしか使えない。もともと外からはサーバとして使っているRaspberry Piを経由していたのでそれで良かったのだけど今回のPebbleアプリでは公開できるようにクラウド経由で使えるIRKit Internet HTTP APIを使うようにしたいと考えてる。くっそ暑くなってきたので早く家の外から操作できるようにしたい。

しかし、屋内だとリモコンを操作するのと等価なのに楽しくてPebbleから何回もエアコンをつけたり消したりしていた(電気の無駄遣い)。Pebble楽しい。(・∀・)

Pebbleアプリ製作開始

そろそろ本気出す。← 最初から出してください。

PebbleについてはCloudPebbleSimplyjsで少し勉強というか戯れていたけど本格的に自分が欲しいものを作り出すことにした。

結局やりたいことをいろいろ考えるとCで書く必要があって、コンパイルや実機での動作を頻繁に繰り返して動きを確認していきたいタイプなのでCloudPebbleは使わずにローカルに開発環境を構築した。こんなaliasを入れてビルドしまくっている。

~/.aliases
# pebble
alias pb='pebble'
alias pbb='pebble build'
alias pbi='pebble install'

いくつか作りたいものがあるけど、まずはPebbleから家の電化製品を操作したくてIRKitと連携するアプリをつくっている。Javascript側からリストデータを受け取って表示するところまではできた。

あとはボタンを押したらJavascript側にメッセージを送ってIRKitにコマンドを送る。XHRでIRKitにコマンドを送る部分は先に確認していたので自分が使う分だけのバージョンはもうすぐできそう。

PebbleとIRKitの両方を持っている人はあまりいなさそうだけど、設定画面を作って誰でも使えるところまで持って行きたいと思っている。

個人的にはPebble SDKはあまり難しくなさそうだった。リスト表示はiOSのTableViewのような形でCallbackを実装していけばいい。サンプルだとヘッダファイルを作らずソースファイルだけで書いているのでプロトタイプ宣言などCのことを知らない人にとってはハマるのかもしれない。難しくはないがlibcなんでも使えるわけじゃなさそうなので使える関数は制限されていて面倒っちゃ面倒だけどPebbleのような非力な環境での開発だからしょうがない。