SensorTag Android版アプリからIBM IoT Foundationに接続する方法


IOS版は[こちら](https://developer.ibm.com/recipes/tutorials/connect-a-cc2650-sensortag-to-the-iot-foundations-quickstart/)を参考。


SoftLayer Bluemix Community Festa 2016のIoTハンズオンにて、Android版のSensorTagアプリからIoT Foundationに接続できなかったので調べました(調べるといってSensor貸して頂きました。ありがとうございます)。
ハンズオンの資料は[こちら](http://j.mp/slmb-2016-iot-handson)。

## アプリ設定
まず以下を行います。

1. 上記の資料などを参考にIoT Foundation側を設定
1. [アプリをインストール](https://play.google.com/store/apps/details?id=com.ti.ble.sensortag&hl=ja)
1. アプリとセンサを起動
1. SCAN -> 接続するセンサをconnect
1. Advanceボタンを押下 -> Cloud Setup画面を表示

以下の様に設定します。
![Screenshot_2016-04-16-22-51-32.png](https://qiita-image-store.s3.amazonaws.com/0/119101/14eb406e-72ed-6a4b-562f-9d6b6e1eb6a5.png "Screenshot_2016-04-16-22-51-32.png")

IoT Foundationの場合、MQTTのプロパティを以下のように設定するようです。

| プロパティ | 内容 |
|:-----------|:------------|
| Username       |  use-token-auth      |
| Password     |   \<認証トークン\>    |
| Device id | d:\<組織 ID\>:\<デバイス・タイプ\>:\<デバイス ID\>   |
| Broker Address  | \<組織ID\>.messaging.internetofthings.ibmcloud.com   |
| Broker Port  | 1883  |
| Publish Topic  |  iot-2/evt/\<任意の文字列\>/fmt/json |

Device idと書いてありますが、dex2jarとjadをでdecompileしてソースを見たところ、
DeviceIdをClientIdとして使っているみたいでした。

## 繋がらない
上記の設定でワクワクしながらPush to Cloudしてみると以下の画面が！
![Screenshot_2016-04-16-22-56-14.png](https://qiita-image-store.s3.amazonaws.com/0/119101/4f127e77-298c-f4c0-a427-333c0d7c88d7.png "Screenshot_2016-04-16-22-56-14.png")

ぐぐってみると、同様の事象が結構起こっている模様。
実際ハンズオンでもAndroidの人は繋がっていませんでした。
さらにぐぐってみると、[こちらのstackoverflow](http://stackoverflow.com/questions/32458410/unable-to-connect-ti-sensortag-cc2650stk-to-iot-foundation-bluemix
)を見つけました。なるほど。


> You can solve it like that:
>
> - get the SensorTag code here : https://git.ti.com/sensortag-20-android
> - Open "IBMIoTCloudProfile" class
> - line 245, change the connection code from
> 
> client.connect(options, new IMqttActionListener() > {....
> 
> to
> 
> client.connect(options,this.context, new > IMqttActionListener() {...
> 
> compile and install the updated app.


ちゃんとリポジトリあったみたいです。
実際にコードを見てみます。

```java:IBMIoTCloudProfile.java
....
    public boolean connect() {
        try {
            memPer = new MemoryPersistence();
            String url = config.brokerAddress + ":" + config.brokerPort;
            Log.d("IBMIoTCloudProfile","Cloud Broker URL : " + url);
            client = new MqttAndroidClient(this.context,url,config.deviceId);
            MqttConnectOptions options = null;

            if (config.service > CloudProfileConfigurationDialogFragment.DEF_CLOUD_IBMQUICKSTART_CLOUD_SERVICE) {
                options = new MqttConnectOptions();
                options.setCleanSession(config.cleanSession);
                if (config.username.length() > 0)options.setUserName(config.username);
                if (config.password.length() > 0)options.setPassword(config.password.toCharArray());
                Log.d("IBMIoTCloudProfile","Adding Options : Clean Session : " + options.isCleanSession() + ", Username : " + config.username + ", " + "Password : " + "********");
            }

            client.connect(options, new IMqttActionListener() {...});

```

問題の箇所
> client.connect(options, new IMqttActionListener(){...});

ここでclientであるMqttAndroidのコードを見てみます。
MqttAndroidの引数2個バージョンのconnect関数を見ると
1個目の引数にcontext、2個目にIMqttActionListenerとなっています。

```java:MqttAndroidClient.java
	@Override
	public IMqttToken connect(Object userContext, IMqttActionListener callback)
			throws MqttException {
		return connect(new MqttConnectOptions(), userContext, callback);
	}
	
    @Override
	public IMqttToken connect(MqttConnectOptions options, Object userContext,
			IMqttActionListener callback) throws MqttException {

		IMqttToken token = new MqttTokenAndroid(this, userContext,
				callback);
	...
```

-> client.connect(\<MqttConnectOptions\>, \<MqttConnectOptions\>, \<IMqttActionListener\>)という風になっていたのでエラーが起きていました。
なのでcom/example/ti/ble/common/IBMIoTCloudProfile.javaのコードをを以下のどちらかに修正します。
```java
client.connect(options, this.context, new IMqttActionListener() {...});
```

```java
client.connect(this.context, new IMqttActionListener() {...});
```

## ビルド
修正してandroid studioでインポートしてビルド。
実行してみると、通信できているようにみえる！
![Screenshot_2016-04-17-01-44-47.png](https://qiita-image-store.s3.amazonaws.com/0/119101/59c7a54c-f28d-53c8-ce41-5a61df59a799.png "Screenshot_2016-04-17-01-44-47.png")


IoT Foundationを確認してみると、正常にPushできていました。

![スクリーンショット 2016-04-17 1.45.27.png](https://qiita-image-store.s3.amazonaws.com/0/119101/e297c2ab-4a32-371a-c0e9-00745338d488.png "スクリーンショット 2016-04-17 1.45.27.png")

ということで、Androidでも使えました。
署名も何もしていませんが、一応[APK](https://dl.dropboxusercontent.com/u/45487634/BleSensorTag-debug-unaligned.apk)を置いておきます。

これupstreamに反映させるにはどうしたらいいんだろう