低価格の温度センサーとして売られているDHT11ですが、
Android Thingsからは直接扱えません。
今回はDHT11をAndroidThingsで扱うために、ArduinoでDHT11からデータを読み取り、AndroidThingsに送ります。
DHT11とAndroid Things
上にも書きましたが、現状(2017/12/07)、Android ThingsではDHT11は扱えません。
諸々議論はこのスレッドでされています。
簡単に言うと、Android Thingsでは、GPIOからデータを呼び出すのに230us位かかるのですが、
DHT11では、データを読み取るのに20usの速さが必要であり、現状Android Thingsでは直接データを読み取ることが実質不可能となっています。
Android ThingsとArduino
そこでDHT11等を扱うために、Arduinoでデータを読み取り、Android Thingsに送ってしまうという方法を思いつくわけです。
Arduino、AndroidThings間はUARTを利用して、双方向でデータをやり取りします。
実際にやってみる
回路
Arduino側のコード
Arduino側のコードです。
AndroidThingsからUARTを利用して、データが送信されるので、Serial.readで取得します。
取得するのは温度を取得するか(T
)、湿度を取得するか(H
)のコマンドなので、コマンドに合わせて、DHT11から読み取ります。
なおDHT11の温度や湿度は、adafruitのライブラリを利用して、取得します。
そして取得したデータをSerialに流し、Android Thingsへ送ります。
#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の初期化を行い、データの取得を行います。
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では定期的にデータを読み取ってログに流すだけです。
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などに任せたほうが楽です。
参考
なお今回はUARTを使いましたが、I2Cで送る方法もあるようです。
https://github.com/theangels/AndroidThings_Thingworx_Demo