Android Thingsで赤外線人感センサー(HC-SR501)を使う

# 人感センサー(HC-SR501)とは？
英語では「PIR Motion Sensor」（PIRモーションセンサー）
日本語では「焦電型人感センサーモジュール」などと呼ばれています。

赤外線で人が通過、移動している事を検知するセンサーです。
Amazonなどでも安価に購入することが出来ます。

![HC-SR501](https://qiita-image-store.s3.amazonaws.com/0/129712/6bf7ba3b-85e5-dfe4-c380-bceba7726f1d.jpeg)

![HC-SR501](https://qiita-image-store.s3.amazonaws.com/0/129712/6d29ed0e-e8ac-fd6b-4ef1-ddb0f7a3b3c7.jpeg)

# HC-SR501のデータシート
http://www.datasheet.jp/search.php?sWord=HC-SR501
この辺から仕様書をダウンロードできます

# 回路図
![回路図](https://qiita-image-store.s3.amazonaws.com/0/129712/f16b318c-b174-299c-e38f-a6a0292802ee.png)


# Gradleの設定ファイルに追記
app/build.gradleのdependencies内に以下を追記

```
provided 'com.google.android.things:androidthings:0.1-devpreview'
```

# AndroidManifest.xmlに追記
**&lt;application&gt;**直下に以下を追記

```xml
<uses-library android:name="com.google.android.things"/>
```

# MainActivityに必要な記述を追記

```java
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

import com.google.android.things.pio.Gpio;
import com.google.android.things.pio.GpioCallback;
import com.google.android.things.pio.PeripheralManagerService;

import java.io.IOException;

public class MainActivity extends Activity {
    static final String TAG = MainActivity.class.getSimpleName();

    // 上の配線でBCM18の位置に接続している為、BCM18を指定します。
    String mPinName = "BCM18";
    Gpio mGpio;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        PeripheralManagerService service = new PeripheralManagerService();
        try {
            mGpio = service.openGpio(mPinName);

            // ピンをインプットモードで動作させます
            mGpio.setDirection(Gpio.DIRECTION_IN);

            // センサーがHighを返した時にtrueを返すようにします
            mGpio.setActiveType(Gpio.ACTIVE_HIGH);

            // センサーがHigh,Lowどちらかに変更になった場合にコールバック関数を呼び出す
            mGpio.setEdgeTriggerType(Gpio.EDGE_BOTH);
        } catch (IOException e) {
            Log.e(TAG, "Error on PeripheralIO API", e);
        }
    }

    GpioCallback mGpioCallback = new GpioCallback() {
        @Override
        public boolean onGpioEdge(Gpio gpio) {
            try {
                if (gpio.getValue()) {
                    // 人の動きを検知
                    Log.i(TAG, "GPIO High");
                } else {
                    // 人が動かずに一定時間経過
                    Log.i(TAG, "GPIO Low");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return true;
        }

        @Override
        public void onGpioError(Gpio gpio, int error) {
            Log.w(TAG, gpio + ": Error event " + error);
        }
    };

    @Override
    protected void onStart() {
        super.onStart();

        if(mGpio != null) {
            try {
                // コールバックを登録
                mGpio.registerGpioCallback(mGpioCallback);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if(mGpio != null) {
            // コールバックを解除
            mGpio.unregisterGpioCallback(mGpioCallback);
        }
    }
}
```

# 実行結果
- 人の動きを検知した

```
01-05 20:24:49.800 13954 13954 I MainActivity: GPIO High
```
- 人の動きを一定時間検知していない

```
01-05 20:24:51.590 13954 13954 I MainActivity: GPIO Low
```

# Gpio#setDirectionに指定できる値
Pinの入出力タイプとデフォルト値を指定できます

| 値 | 意味 |
|:-:|:-:|
| Gpio.DIRECTION_IN  | 入力モード  |
| Gpio.DIRECTION_OUT_INITIALLY_HIGH  | 出力モード（初期値HIGH）  |
| Gpio.DIRECTION_OUT_INITIALLY_LOW  | 出力モード（初期値LOW）  |

# Gpio#setActiveTypeに指定できる値
HIGHが帰ってきた場合に返す値を指定します

| 値 | 意味 |
|:-:|:-:|
| Gpio.ACTIVE_HIGH  | HIGHが返ってきた時にtrueを返す  |
| Gpio.ACTIVE_LOW  | HIGHが返ってきた時にfalseを返す  |

# Gpio#setEdgeTriggerTypeに指定できる値
何をトリガーに値の変化を検知するかを指定します

| 値 | 意味 |
|:-:|:-:|
| Gpio.EDGE_NONE  | デフォルト値（値の変化を検知しない）  |
| Gpio.EDGE_BOTH  | HIGHもしくはLOWに値が変化した時  |
| Gpio.EDGE_RISING  | LOWからHIGHに値が変化した時  |
| Gpio.EDGE_FALLING  | HIGHからLOWに値が変化した時  |