AWS IoT/MQTTで３Dをグリグリ動かそうとした話

## 初めに
   
   こんにちは。[CYBIRDエンジニア Advent Calendar](http://qiita.com/advent-calendar/2016/cybird)、19日目の[cy-katsuhiro-miura](http://qiita.com/cy-katsuhiro-miura)です。
         
18日目は[@cy-hiroshi-chiba](http://qiita.com/cy-hiroshi-chiba)さんの「[Amazon QuickSightを試してみる](http://qiita.com/cy-hiroshi-chiba/items/87ce829b87674601c2cf)」でした。

QuickSightは僕も試したくてアカウントだけは作ったんですが、そこから先に進めていなかったので、こういう記事はタメになりますね！

そういえば、記事を書き始めて気づきましたが、[去年](http://qiita.com/advent-calendar/2015/cybird)も[@cy-hiroshi-chiba](http://qiita.com/cy-hiroshi-chiba)さんの翌日だったので、僕も２年連続１９日目でしたね。

## IoT

さて、これからはIoTの時代だそうです。
ネットにそう書いてあったので間違いないようです。
僕も時代にのって、IoTとやらをやってみたい、そう思いました。


## 構成
```bash:構成
+--------+          +--------+          +---------+
| Things |--(MQTT)->| Broker |--(MQTT)->| Browser |
+--------+   Pub    +--------+   Sub    +---------+
```	
とりあえずこんな構成を考えてみます。
IoTならよくある構成ですね。

ここのThingsには、ArudinoとかRaspberryPiとかがよく使われるようですが、
僕の乏しいお小遣いではとても買えませんし、妻にはおもちゃにしか見えないガジェットの購入申請が通るとも思えません。

しょうがないので、手持ちの資産でなんとかしてみましょう。


## ９軸センサー
IoTでよくやるのは何かしらのセンサーの情報を取得するとかでしょうか。

例えば、９軸センサー。
重力加速度センサーで、３軸の重力加速度。
回転速度センサーで、３軸のジャイロ。
地磁気センサーで、３軸のコンパス。
これら全部合わせてで９軸。

センサーモジュールであれば、MPU-9250/9150とかがメジャーでしょうか。
Arudinoがあれば、モーションシールドを購入してもいいでしょう。

でも僕にはそういうのはないので、手持ちのiPhoneとJavascriptでどうにかしてみましょう。
重力加速度や回転速度を取得するには、"devicemotion"、コンパスを取得するには"deviceorientation"を利用します。

```:javascript
window.addEventListener('devicemotion', function(e){
    //重力加速度センサー
    gravity = e.accelerationIncludingGravity;
    gx = gravity.x;
    gy = gravity.y;
    gz = gravity.z;
    
    //回転速度センサー
	rotation = e.rotationRate;
    rx = rotation.beta;
    ry = rotation.gamma;
    rz = rotation.alpha;	
}
window.addEventListener('deviceorientation',function(e){
    //地磁気センサー
    mx = e.beta;
    my = e.gamma;
    mz = e.alpha;
}
```
![IMG_5995.PNG](https://qiita-image-store.s3.amazonaws.com/0/62573/b1a5cc0f-fbd8-7641-607d-34d21b977125.png "IMG_5995.PNG")

[サンプル：端末で9dof取得](http://jsdo.it/MiuraKatsu/gmx2)

## MQTT Broker 
集めた９軸センサー情報をMQTTで送るためには、MQTT Broker Serverが必要ですが、サーバとか立てるとお金かかっちゃいますよね。
そこで、サーバ立てずにすむMQTT Brokerサービスを探してみました。
・[ニフティクラウド MQTT](http://cloud.nifty.com/service/mqtt.htm)
今年の３月３１日まではβということで無料だったのですが、４月からは有料になってしまいました。

・[時雨堂 sango](https://sango.shiguredo.jp/)
時雨堂さんのMQTTブローカー「Akane」のホスティングサービスです。
ライトプランなら０円！スタンダード・プランでも５００円/月！

・[AWS IoT Message Broker](http://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-message-broker.html)
[AWSさんのIoTプラットフォーム](https://aws.amazon.com/jp/iot/)に対するPub/Sub/メッセージの送受信サービスです。
従量課金の為、使わなければ０円で、初めの１年は無料利用枠が使えます。
まあ、有料でも１００万通で６＄程なので、僕のお小遣いでもなんとかなる範囲です。

今回は、AWS IoTを使ってみましょう。

## AWS IoT
９軸センサーの取得をJavascriptでやってしまったので、MQTT ClientもJavascriptで実装してみます。

とゆうか、クラスメソッドさんの[「AWS IoTのMQTT over WebSocketをCognito（Unauth）で認証して使ってみた」](http://dev.classmethod.jp/cloud/aws/aws-iot-mqtt-over-websocket-cognito-identity-unatuh/)をほぼそのまま使いました。
ポイントは、AWS IoTの認証をCognitoを使って一時的なAWS Credentialsで実行してるところ。これでJavascriptのソースを見られても、まあ。

実はsangoもMQTT over WebSocketで使えるんですが、ユーザ名とパスワードをソースに埋め込まないと行けないので、今回はちょっと。

[サンプル：Aws IoTにCognitoのUnauth認証使ってMQTT over WebSocket](http://jsdo.it/MiuraKatsu/C3DG)

## Publish

上記のサンプルを使って、９軸センサーの情報をPublishしてみます。
[サンプル：端末で9dof取得してMQTT over WebsocketでAws IoTにPub](http://jsdo.it/MiuraKatsu/osT9)

## subscribe
さらに送られた９軸センサーの情報を別ブラウザで受けてみます。
数字だけだとちょっとさみしいので、なんとなく重力加速度だけグラフ表示してみました。
![スクリーンショット 2016-12-18 21.40.24.png](https://qiita-image-store.s3.amazonaws.com/0/62573/15e345d0-c6e9-e145-143c-f4143acc2bb8.png "スクリーンショット 2016-12-18 21.40.24.png")

[サンプル：Aws IoTにMQTT接続してSubした9dofデータを表示](http://jsdo.it/MiuraKatsu/oUce)


## 完成？
これで、一応完成です。わりとさくっとできてしまいますね。
javascriptで取得してるところをarudinoあたりで実装すれば、それはもうIoT。
[AWS IoT SDK](http://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-sdks.html)には
・Arduino
・組み込みC
・javascript
が用意されているので、お好きなものを使って頂けると良いかと思います。

## UnityでMQTT
あれ？って思った方、いらっしゃるかと思います。
そうですね。対応しているSDK少なくね？ってことですね。
実は、単純にMQTTやるだけならもっと全然対応している言語いっぱいあります。
MQTTクライアントで最大手というと[paho](http://www.eclipse.org/paho/)でしょうか。
[言語毎の対応表](http://www.eclipse.org/paho/downloads.php)を見ると、いっぱいあるので、まあ各自実装してください、ということでしょう。

.Net(C#)のクライアントもちゃんとありますので、UnityでもMQTTできるんじゃないの？ってちょっと思いますよね。
９軸センサーの情報をMQTTでUnityに送って、Unity内部の３Dオブジェクトをグリグリ動かせるんじゃねって？ってちょっと思いますよね。
そうですね。まあ、MQTTだけならなんとかなります。

## Unityで AWS IoT
問題はMQTTブローカーがAWS IoTの場合です。
実はAWS IoTはMQTTの場合TLSv1.2しか対応していません。
[AWS IoT Hardware Program FAQ](https://aws.amazon.com/jp/partners/iot-hardware/faqs/)
>Q. What are different authentication mechanisms for AWS IoT?
>Devices/Clients will be able to connect to the IoT service via 4 main authentication mechanisms: MQTT/HTTP via TLS 1.2 Certs (Recommended), HTTP via Sigv4, HTTPS via Cognito or IAM user.

pahoの.Net MQTT Clientは[v4.3.0.0でTLSv1.2に対応している](https://m2mqtt.wordpress.com/2015/12/06/324/)のですが、Unityは.Net3.5準拠でして、TLS1.1、TLS1.2は選択できず、TLS1.0までしかありません。
このため、単純にパッケージを導入してもTLS1.2を使おうとするとビルドエラーになってしまいます。
エラーの原因は.NET Framework 3.5 では TLS1.1 および TLS1.2 が SecurityProtocolType 列挙体に宣言がないためなので、以下のような実装を行えば、ビルドエラーは回避できましたが・・・、きちんと動かすところまで検証できていません。
誰か是非トライしてみてください。（他力本願）

```cs:SecurityProtocolTypeExtensions.cs
namespace System.Net
{
    using System.Security.Authentication;
    public static class SecurityProtocolTypeExtensions
    {
        public const SecurityProtocolType Tls12 = (SecurityProtocolType)SslProtocolsExtensions.Tls12;
        public const SecurityProtocolType Tls11 = (SecurityProtocolType)SslProtocolsExtensions.Tls11;
        public const SecurityProtocolType SystemDefault = (SecurityProtocolType)0;
    }
}
```
```cs:SslProtocolsExtensions.cs
namespace System.Security.Authentication
{
    public static class SslProtocolsExtensions
    {
        public const SslProtocols Tls12 = (SslProtocols)0x00000C00;
        public const SslProtocols Tls11 = (SslProtocols)0x00000300;
    }
}
```

```cs:Net/MqttNetworkChannel.cs
        public static SslProtocols ToSslPlatformEnum(MqttSslProtocols mqttSslProtocol)
        {
            switch (mqttSslProtocol)
            {
                case MqttSslProtocols.None:
                    return SslProtocols.None;
                case MqttSslProtocols.SSLv3:
                    return SslProtocols.Ssl3;
                case MqttSslProtocols.TLSv1_0:
                    return SslProtocols.Tls;
                case MqttSslProtocols.TLSv1_1:
                    return SslProtocolsExtensions.Tls11;
                case MqttSslProtocols.TLSv1_2:
                    return SslProtocolsExtensions.Tls12;
                default:
                    throw new ArgumentException("SSL/TLS protocol version not supported");
            }
        }
```
[参考：.NET Framework で TLS1.1 および 1.2 を有効化する方法](https://blogs.technet.microsoft.com/jpieblog/2015/04/07/net-framework-tls1-1-1-2/)


## クォータニオン
さて、UnityでMQTTするのは諦めるとして、３Dオブジェクトをグリグリする件です。
３Dオブジェクトをグリグリするには、クォータニオンというのが必要なんです。
僕にはよくわからないですが、[yyama2](http://qiita.com/yyama2)さんが言っていたので、間違いないです。
なんか行列とか使って、計算すれば自分でもクォータニオン取得できるらしいのですが、世の中にはjavascriptでクォータニオン取得できるライブラリもあるようでして。
https://github.com/infusion/Quaternion.js
もうコレを使えばいいんじゃないかと。

そんなわけで、Quaternion.jsのサンプルをちょこっといじって、
![IMG_5997.PNG](https://qiita-image-store.s3.amazonaws.com/0/62573/e2562fea-388e-eb1a-580a-7810ae92f9bc.png "IMG_5997.PNG")
端末側で取得したQuaternionデータをMQTTでPubして、
![スクリーンショット 2016-12-19 0.14.25.png](https://qiita-image-store.s3.amazonaws.com/0/62573/453bc11b-f2e5-a1f5-9bdc-4622ea38a6e8.png "スクリーンショット 2016-12-19 0.14.25.png")
PCのブラウザでSubして受けとって、同期して動かしてみました。

[サンプル：端末でQuaternion取得してMQTT over WebsocketでAws IoTにPub](http://jsdo.it/MiuraKatsu/0gBJ)
[サンプル：Aws IoTにMQTT接続してSubしたQuaternionデータでQuaternion.jsを動かす](http://jsdo.it/MiuraKatsu/o4IJ)

## 最後に。
これで、一応、「IoTで３Dをグリグリ動かす」というお題はクリアになりますでしょうか。
ホントはWebGLとかにもチャレンジしたかったんですが、時間切れでそこまでたどり着けませんでした。
Unityでなんとかしたかったんですが、.Netの壁は厚かった・・・
それでも、Javascriptだけでここまでできるってのもすごいですね。



[CYBIRDエンジニア Advent Calendar](http://qiita.com/advent-calendar/2016/cybird) 明日は、僕のUnityの師匠の[yyama2](http://qiita.com/yyama2)さんです！楽しみですね！