AndroidThingsとArduino間でやり取りする ~ Android ThingsでDHT11を扱う ~ 

　
低価格の温度センサーとして売られている[DHT11](http://akizukidenshi.com/catalog/g/gM-07003/)ですが、
Android Thingsからは直接扱えません。

今回はDHT11をAndroidThingsで扱うために、ArduinoでDHT11からデータを読み取り、AndroidThingsに送ります。

## DHT11とAndroid Things

上にも書きましたが、現状(2017/12/07)、Android ThingsではDHT11は扱えません。
諸々議論は[このスレッド](https://issuetracker.google.com/issues/37135689)でされています。
簡単に言うと、Android Thingsでは、GPIOからデータを呼び出すのに230us位かかるのですが、
DHT11では、データを読み取るのに20usの速さが必要であり、現状Android Thingsでは直接データを読み取ることが実質不可能となっています。


## Android ThingsとArduino

そこでDHT11等を扱うために、Arduinoでデータを読み取り、Android Thingsに送ってしまうという方法を思いつくわけです。
Arduino、AndroidThings間はUARTを利用して、双方向でデータをやり取りします。

## 実際にやってみる

### 回路

![arduino-wrap.png](https://qiita-image-store.s3.amazonaws.com/0/2965/c03cba71-4098-20d7-783a-3f63f6d4895f.png "arduino-wrap.png")


### Arduino側のコード

Arduino側のコードです。
AndroidThingsからUARTを利用して、データが送信されるので、Serial.readで取得します。
取得するのは温度を取得するか(`T`)、湿度を取得するか(`H`)のコマンドなので、コマンドに合わせて、DHT11から読み取ります。
なおDHT11の温度や湿度は、adafruitのライブラリを利用して、取得します。
そして取得したデータをSerialに流し、Android Thingsへ送ります。


```cpp 
#include <DHT.h>;
#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

void setup() {                
  Serial.begin(115200);  
  dht.begin();
}

void loop() {
    int inByte = Serial.read();
    switch (inByte) {
    case 'T':
      sendTemperature();
      break;
    case 'H':
      sendHumidity();
      break;
  }
}

void sendTemperature(){
  send(dht.readTemperature());
}

void sendHumidity(){
  send(dht.readHumidity());
}

void send(float val) {
  String value = "";
  value += val;
  
  char charBuf[value.length()+1];
  value.toCharArray(charBuf, value.length()+1);
  
  Serial.write(charBuf);
}
```

### Android Things側

全コードは以下にあります。

#### Arduinoへのデータ送信とデータ取得

DHT11のデータ送受信用のクラスです。
UARTDeviceの初期化を行い、データの取得を行います。


```kotlin:DHT11.kt
package com.github.soundtricker.androidthings.sampledht11

import android.util.Log
import com.google.android.things.pio.PeripheralManagerService
import com.google.android.things.pio.UartDevice
import java.io.IOException
import java.nio.ByteBuffer

class DHT11 constructor(uartName: String, pioService: PeripheralManagerService) {

    private val mMessageBuffer = ByteBuffer.allocate(10)
    private var mDevice: UartDevice?

    init {
        mDevice = pioService.openUartDevice(uartName)
        mDevice!!.setDataSize(8)
        mDevice!!.setBaudrate(115200)
        mDevice!!.setParity(0)
        mDevice!!.setStopBits(1)
    }

    fun getTemperature(): String {
        var response = ""
        val buffer = ByteArray(10)

        try {
            return this.fillBuffer(buffer, "T")
        } catch (e: IOException) {
            Log.e("DHT11", "failed read temperature", e)
        }

        return response
    }

    fun getHumidity(): String {
        var response = ""
        val buffer = ByteArray(10)

        try {
            response = this.fillBuffer(buffer, "H")
        } catch (e: IOException) {
            Log.e("DHT11", "failed read temperature", e)
        }

        return response
    }

    @Throws(IOException::class)
    private fun fillBuffer(buffer: ByteArray, mode: String): String {
        this.mDevice!!.write(mode.toByteArray(), mode.length)

        Thread.sleep(500L)
        this.mDevice!!.read(buffer, buffer.size)
        this.processBuffer(buffer)
        return String(this.mMessageBuffer.array(), charset("UTF-8")).replace("\u0000".toRegex(), "")
    }

    private fun processBuffer(buffer: ByteArray) {
        mMessageBuffer.clear()
        buffer.forEach { b ->
            if (b.toInt() != 0) {
                this.mMessageBuffer.put(b)
            }
        }
    }

    @Throws(Exception::class)
    fun close() {
        try {
            this.mDevice?.close()
        } finally {
            this.mDevice = null
        }
    }


}

```

#### MainActivity

MainActivityでは定期的にデータを読み取ってログに流すだけです。

```kotlin:MainActivity.kt

package com.github.soundtricker.androidthings.sampledht11

import android.app.Activity
import android.os.Bundle
import android.os.Handler
import android.util.Log
import com.google.android.things.pio.PeripheralManagerService

/**
 * Skeleton of an Android Things activity.
 *
 * Android Things peripheral APIs are accessible through the class
 * PeripheralManagerService. For example, the snippet below will open a GPIO pin and
 * set it to HIGH:
 *
 * <pre>{@code
 * val service = PeripheralManagerService()
 * val mLedGpio = service.openGpio("BCM6")
 * mLedGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW)
 * mLedGpio.value = true
 * }</pre>
 * <p>
 * For more complex peripherals, look for an existing user-space driver, or implement one if none
 * is available.
 *
 * @see <a href="https://github.com/androidthings/contrib-drivers#readme">https://github.com/androidthings/contrib-drivers#readme</a>
 *
 */
class MainActivity : Activity() {

    companion object {
        private val TAG = MainActivity.javaClass.simpleName
    }

    private var mDht11: DHT11? = null

    private var mHandler: Handler? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mDht11 = DHT11("UART0", PeripheralManagerService())
        mHandler = Handler()
        mHandler!!.post(mRunnable)

    }

    override fun onDestroy() {
        super.onDestroy()
        mDht11?.close()
        mDht11 = null
    }

    private fun run() {
        mHandler!!.postDelayed(mRunnable, 10L)
    }

    private val mRunnable: Runnable = Runnable {
        Log.d(TAG, "Humidity: ${mDht11!!.getHumidity()}")
        Log.d(TAG, "Temperature: ${mDht11!!.getTemperature()}")
        run()
    }
}
```

## まとめ

AndroidThingsではどんなセンサーでも触れる訳ではなく、ちょっとハマりました。
センサー周りの処理はやはりArduinoなどに任せたほうが楽です。

## 参考

https://github.com/mplacona/arduwrap

なお今回はUARTを使いましたが、I2Cで送る方法もあるようです。
https://github.com/theangels/AndroidThings_Thingworx_Demo