OpenWhisk(beta)+Weather Company Dataで今日の天気によって曲が変わる目覚まし時計を作る

この記事はteratailの[「Blumix Advent Calendar」](https://teratail.com/Bluemix#2016-12-07)の参加記事として書きました。
#モチベ

建前:ニュースを見るのがだるい。スマホのロックを解除して天気確認するのもだるい。眠たい朝は視覚情報が頭に入ってこない。そんな人のために起きるのと同時に今日の天気を聴覚で知るという合理的な試みをしてみようと思いました。(本音:技術調査してある程度実現出来そうだった)

目標:大体以下みたいな感じに目覚ましをセットしたい(一部筆者の趣味チョイス)。

晴れの日:kokia:The Power Of Smile
雨の日:稲葉浩志/静かな雨
風の日:ELLEGARDEN/風の日
豪雨:C-999/三年間の雨宿り
雷雨:SMAP/青いイナズマ
曇り:DOES/曇天
雪の日:松たか子/レット・イット・ゴー〜ありのままで〜
霰の日:水森亜土/ワイワイワールド(Dr.スランプ アラレちゃんの主題歌)

#注意点

OpenWhiskは現時点でBeta版です。試験運用と思われる機能なども多々あるとみられ、ある程度、サーバレスアーキテクチャ、REST、SDKで用いられる言語に精通している方でないとハマってしまうのではないかと思われる所が多々あります。が、そこはBeta版なので多めにみましょう。仕組みが分かってしまえば、はまらずにサクサクいけると思います。

#OpenWhiskとは？

AWS Lambdaのようにクラウド上でのデータ更新などのイベントあるいはクライアントからのRESTアクションをトリガーとして設定することで、イベント実行時になんらかの処理を実行します。処理結果をクライアントに送信することも可能。サーバレスなのでわざわざアプリケーションにする必要のないAPIの作成や、アプリケーションと独立なリクエストとして処理できる処理を分離してサーバの負荷分散を行うのに便利です。AWSでいうとHTTP Gateway+Lambdaが一つにまとまったような感じです。

#Set Up
ブラウザエディタだけでも完結できるようですが、一応OpenWhisk CLIも登録しておきます。自身のBlumix OpenWhiskの管理画面

![wsk_start.png](https://qiita-image-store.s3.amazonaws.com/0/99145/ac5e7ee5-2385-348d-92d6-8cdc2721cbb1.png)


から[wsk実行ファイルをダウンロード](https://console.ng.bluemix.net/openwhisk/cli)し、パスを通した後(筆者は(usr/local/bin/wsk)に配置しました)、　指示に従って、以下のように認証情報を設定します。

```shell-session
wsk property set --apihost openwhisk.ng.bluemix.net --auth $user:$password --namespace "$namespace"
```

この時の\$user:$passwordはリクエストを許可する認証情報になるので、外部に漏洩しないように気をつけて下さい。認証情報は

```shell-session
wsk property get --auth 
```

を実行することで確認することができます。リクエストにはAuthorization:Basic ("\$user:$password"をBASE64暗号化)したものをヘッダに含めることで、リクエストが許可されます。また、以下のようにブラウザエディタのコピーボタンをクリックすることで、画像上ではxxxxで伏せられているBasic情報を含んだcURLを使ったリクエストスクリプトをコピーすることができます。

![wsk_browser.png](https://qiita-image-store.s3.amazonaws.com/0/99145/0423c2a9-0e47-2ccc-1322-d82921970862.png)


これでcURL形式のスクリプトが手に入ったので、試しに[Postman](http://www.getpostman.com/)を使って、リクエストしました。(スクリプトをそのままimportできない場合は、-XPOSTを-X POSTと書き直すことでPostmanにcURLのリクエスト内容をimportできます)

![wsk_result.png](https://qiita-image-store.s3.amazonaws.com/0/99145/c30d375a-a6e4-82cf-637e-92c8ab5ecedb.png)


以上のようにリクエストされた内容が上手く返ってきました。これでOpenWhiskを使う準備が整いました。

#バックエンドを準備する
ここからは、各々好きなようにサーバレスアーキテクチャを構成することができます。試しにOpenWhiskに用意された連携のサンプルを眺めてみました。

<img width="1437" alt="short_menu.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/99145/25c0d005-b08a-305e-dba5-f5ebeca2600e.jpeg">


これらはシーケンスにリンクという項目をクリックすると一覧に現れます。OpenWhiskはこのように作成したアクションをパッケージとして保存することで、アクションのテンプレートとして利用したり、シーケンスという機能でパラメータを引き渡しながら、それぞれのアクションを連鎖させることが出来るようです(これは色々独立に設計した機能を後で簡単に結合することが容易なので、個人的に結構便利だと思いました。)。この中で、Weather Company Dataを連携させてみます。カタログからWeather Company DataのCredentialを作成したあと、Hello World With Paramsのシーケンスにリンクします。

![スクリーンショット 2016-12-05 1.47.34.png](https://qiita-image-store.s3.amazonaws.com/0/99145/4f4c8040-0aed-747b-9e43-3fb87d1f9981.png)

ここで、OpenWhiskはmainで最終的に評価された値をレスポンスとしてリクエスト元に返します。Hello World With Paramsアクションはユーザから受け取ったパラメータをレスポンスに入れて返すだけのアクションだったので、Weather Company Dataのレスポンスをそのまま返すようにアクションを以下のように書き換えます。

![スクリーンショット 2016-12-05 1.51.36.png](https://qiita-image-store.s3.amazonaws.com/0/99145/32ce1518-28a5-52db-d0f7-21a93895cde8.png)

しかし、なぜこれでWeather Company Dataへのリクエスト結果が返ってくるようになるのでしょうか？実は、OpenWhisk上では、main関数の引数はreturnで返された値、または、Promiseオブジェクトでresolveされたパラメータが引き渡されてくるようになっています。実際に、Weather Forecastパッケージが行っているアクションのmain関数の一部を確認してみましょう。

![スクリーンショット 2016-12-05 2.27.43.png](https://qiita-image-store.s3.amazonaws.com/0/99145/5ca4f5b4-5267-696b-ae06-06866d987b59.png)

ここで、上記のurlには以下のようにユーザからのリクエストに応じて、Weather Company Dataのエンドポイントが指定されています。

![スクリーンショット 2016-12-05 2.27.29.png](https://qiita-image-store.s3.amazonaws.com/0/99145/385edaf9-e300-e87f-7825-46d3c34a42ed.png)

次のシーケンスへのパラメータはpromiseでresolveされたものがmainの引数として渡されるようです。packageは言わばアクションの出来合い品であり、実装されている機能以上のことはできないので、他のAPIなどを使いたい場合は自分でアクションを定義する必要がありますが、よく使う機能だけをパッケージとして使い回してしまえば、あとは、好きなように組み合わせて処理を行うことができます。APIを作成する際も、それぞれ同じシーケンスが保証されるため、管理や修正が簡単そうですね。また、あるAPIをラップしてアクションとしていることから、OpenWhiskを経由することで不要なエンドポイントを利用者に叩かせることなくAPIが簡単に利用できるという利点もありそうです。今回はこのシーケンスにはweather-reportという名前をつけました。さて、ここで作成したシーケンスをアクティベートしてブラウザ上から実行してみましょう。

![スクリーンショット 2016-12-05 1.51.02.png](https://qiita-image-store.s3.amazonaws.com/0/99145/a4340934-bb63-b57d-1357-fa7da314be14.png)

正しく設定されていれば以上のようにWeather Company Dataのレスポンスが返ってきます。(requestのパラメータを何も設定してないので色々デフォルト値のままです)このリクエストが通る状態であれば、RESTでもシーケンスを実行できるようになっています。エンドポイントはアクションと同じように指定します。試しに東京の緯度経度情報をパラメータとしてPostmanからリクエストを送ってみます。

![short.jpg](https://qiita-image-store.s3.amazonaws.com/0/99145/bde1e7c7-7eb8-f6ee-5ae2-f527ce17453e.jpeg)

無事いけていますね。では、アクションを書き換えて、weather forecastアクションの結果から、現在の天気を抽出して判定するように書き換えます。目覚ましが鳴る時刻における天気だけを判定すればいいはずなので、今回は、面倒がないようにcurrentパラメータを強制するようにvalidationというアクションを作成しました。天気を厳密に判定するにはwx_phraseが天気の叙述になっており、wx_iconが天気を表すenum値になっているようなのでこれを使用すれば良いようです。
ここで問題が発生しました。[Weather Company Dataのドキュメント](https://console.ng.bluemix.net/docs/services/Weather/weather_rest_apis.html#daily_intraday)を読むとwx_iconは48種類あるようです。48種類・・・。


48種類別々に曲を用意するのは流石にちょっと面倒だったで、機会があればちゃんと実装を考えることにして、今回は条件分岐を超単純化して、雨、曇り、晴れだけに限定しました。これらの判定を行うアクション、forecast-resultを追加します。以上から,バックエンド側は以下のような構成になりました。

![スクリーンショット 2016-12-05 7.13.26.jpg](https://qiita-image-store.s3.amazonaws.com/0/99145/6f9c0b25-ab88-7bba-148a-ac0e2e5db96c.jpeg)

風速とかも計測データを取れるのですが削りました。非常にシンプルな実装ですね。

#フロントエンドを準備する

フロントエンドはcronのように時刻で定期的に実行できて音楽を再生できればどんなデバイスで実装してもオッケーです。今回はAndroidで[AlarmManager](https://developer.android.com/reference/android/app/AlarmManager.html)と[RingtoneManager](https://developer.android.com/reference/android/media/RingtoneManager.html)を使用したアプリを用意しました。ここでは、音楽を設定するのだと伝わらないので、目覚まし時計に時刻になったらweather-reportシーケンスのエンドポイントにHTTPリクエストを送って、天気に合わせて再生する音楽を文字で表示する機能を追加しました。

<img width="573" alt="alerm.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/99145/872c3864-0f80-a657-90a9-0e1bdf4b8c73.jpeg">


12月5日は曇りの判定なので、DOESの曇天がかかっています。以上で天気情報に合わせた目覚まし時計が完成しました。

#まとめ

大体、この記事は実装含め１５時間程度で完成しました。特にバックエンドで使いたいAPIの管理や、実装が非常にシンプルで分かりやすかったのではないかと思います。冒頭でも言及しましたがOpenWhiskはまだBeta版なので、多少機能面で分かりづらい面もありましたが、慣れれば、簡単なバックエンドであればOpenWhiskで実装コストを減らせそうだなぁと、また、今回は企画に乗っかって色々IBM Blumixを触ってみましたが、結構面白いことできそうだなと思いました。

[Bluemixアドベントカレンダー](https://teratail.com/Bluemix)で沢山Niceしてもらえると青汁一年分もらえるらしいです。