屋内環境を手軽にモニタリングする～⑨モーション検知(HC-SR501 / RCWL-0516)をJavaで取得する(GPIO / Pi4J)～

以前、[こちらの記事](https://qiita.com/s5uishida/items/9c31e6fd9b6eb0fa9c96)で、屋内環境(自宅/オフィス/工場)で一般的な環境情報をモニタリングする簡易ツールについて書いたことがあります。このような環境情報のモニタリング用にツールにまとめられたオープンソースは意外と見当たらず、以下のコンセプトイメージを立てて、プライベートで作成しました。
<img width="800" alt="rainy_concept_jp.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457466/fd3ed272-ccc4-88b5-e81c-93c1c3562dd5.png">
各センサーならびに産業オートメーション機器から取得した情報を以下のように利用することができます。

- Webブラウザから時系列グラフでモニタリングする。(ダッシュボード)
- 他の用途で利用できるようにJSON化してMQTTで出力する。(オフライン分析用にクラウドやストレージに蓄積するとか、 何某かのイベントのトリガーに使うとか)

この簡易ツールは最小限、センサーとRaspberry Pi 3B or 4Bで完結するように作成しました。今回、このツールをモーション検知センサーに対応してみました。

## モーション検知センサーについて
今回、採用したモーション検知センサーは、以下の二種類です。

- [HC-SR501](https://www.mpja.com/download/31227sc.pdf) - 焦電型赤外線方式
- [RCWL-0516](https://www.epitran.it/ebayDrive/datasheet/19.pdf) - マイクロ波ドップラーレーダー方式

それぞれにJavaのライブラリ([hc-sr501-driver](https://github.com/s5uishida/hc-sr501-driver)、[rcwl-0516-driver](https://github.com/s5uishida/rcwl-0516-driver))を作成してGithubで公開しています。OSとセンサーの設定手順も書いておきました。また、これらライブラリを組み込んだ環境情報モニタリングの簡易ツールは、[こちらのGithub](https://github.com/s5uishida/rainy)で公開しています。

これらのモーション検知センサーの利用イメージの例は、以下のような感じです。
<img width="800" alt="rainy_motion_detector_overview.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457466/c4d1076c-b708-150e-e786-b4ea6d16efca.png">

- HC-SR501は、所謂「人感センサー」と呼ばれるタイプで、物体の熱源から放射される赤外線を使用します。最大検知距離は7mです。赤外線を使用しますので、間に遮るものがあると検知できません。
- RCWL-0516は、熱源の有無に関係なく物体の動きを検知できるよう、3.2GHzのマイクロ波を照射して、その反射波のドップラー遷移から物体の動きを検知するタイプです。最大検知距離は9mです。例えば、家屋の壁の向こう側の物体の動きにも反応します。この特徴は、用途によっては長所にも短所にもなると思います。

このような特徴を考慮して、用途に応じて使い分けられるように、二種類に対応しました。

## Javaライブラリの基本的な使い方
Qiitaなので、コードの使い方のサンプルを少し掲載します。

- [hc-sr501-driver](https://github.com/s5uishida/hc-sr501-driver)の使い方

以下のサンプルコードでは、モーション検知信号の受信にGPIO12を使用しています。モーションを検知した際に呼び出される`handle()`を実装しています。

```Java
import com.pi4j.io.gpio.Pin;
import com.pi4j.io.gpio.RaspiPin

import io.github.s5uishida.iot.device.hcsr501.driver.HCSR501Driver;
import io.github.s5uishida.iot.device.hcsr501.driver.IHCSR501Handler;

public class MyHCSR501 {
    private static final Logger LOG = LoggerFactory.getLogger(MyHCSR501.class);
    
    public static void main(String[] args) {
        HCSR501Driver hcsr501 = HCSR501Driver.getInstance(RaspiPin.GPIO_12, new MyHCSR501Handler());
        hcsr501.open();

//      if (hcsr501 != null) {
//          hcsr501.close();
//      }
    }
}

class MyHCSR501Handler implements IHCSR501Handler {
    private static final Logger LOG = LoggerFactory.getLogger(MyHCSR501Handler.class);

    private static final String dateFormat = "yyyy-MM-dd HH:mm:ss.SSS";
    private static final SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);

    @Override
    public void handle(String pinName, boolean detect, Date date) {
        LOG.info("[{}] {} {}", pinName, detect, sdf.format(date));
    }
}
```

- [rcwl-0516-driver](https://github.com/s5uishida/rcwl-0516-driver)の使い方

以下のサンプルコードでは、モーション検知信号の受信にGPIO18を使用しています。モーションを検知した際に呼び出される`handle()`を実装しています。

```Java
import com.pi4j.io.gpio.Pin;
import com.pi4j.io.gpio.RaspiPin

import io.github.s5uishida.iot.device.rcwl0516.driver.RCWL0516Driver;
import io.github.s5uishida.iot.device.rcwl0516.driver.IRCWL0516Handler;

public class MyRCWL0516 {
    private static final Logger LOG = LoggerFactory.getLogger(MyRCWL0516.class);
    
    public static void main(String[] args) {
        RCWL0516Driver rcwl0516 = RCWL0516Driver.getInstance(RaspiPin.GPIO_18, new MyRCWL0516Handler());
        rcwl0516.open();

//      if (rcwl0516 != null) {
//          rcwl0516.close();
//      }
    }
}

class MyRCWL0516Handler implements IRCWL0516Handler {
    private static final Logger LOG = LoggerFactory.getLogger(MyRCWL0516Handler.class);

    private static final String dateFormat = "yyyy-MM-dd HH:mm:ss.SSS";
    private static final SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);

    @Override
    public void handle(String pinName, boolean detect, Date date) {
        LOG.info("[{}] {} {}", pinName, detect, sdf.format(date));
    }
}
```

どちらのコードもシンプルですね。なお、[Pi4J](https://pi4j.com/)というRaspberry PiのGPIOを使用するためのJavaライブラリを使用して作成しました。

## 最後に
簡易ツールでは、利用し易いように、これらのモーション検知をイベントとしてJSON形式でMQTTで送信します。これをトリガーに、続く何某かの処理(カメラやマイクをONにするとか)に繋げる、という用途が考えられます。なお、これらのモーション検知センサーが数百円で入手できるのは良いですね。

最後に、簡易ツールは[こちらのGithub](https://github.com/s5uishida/rainy)で公開しています。

## 一連の記事
このシリーズは、以下の記事から構成されます。
1. [動機とコンセプト](https://qiita.com/items/9c31e6fd9b6eb0fa9c96)
2. [Bluetooth LEアドバタイズ信号をJavaでキャッチする(Bluetooth LE / bluez-dbus)](https://qiita.com/items/a4543c9e7fb13b4c7c6e)
　関連するGithubは[こちら](https://github.com/s5uishida/bluetooth-scanner)。
3. [TI SensorTag CC2650から温度/湿度/照度などをJavaで取得する(Bluetooth LE / bluez-dbus)](https://qiita.com/items/79a2de6a7026ef230e9b)
　関連するGithubは[こちら](https://github.com/s5uishida/cc2650-driver)。
4. [MH-Z19BからCO2濃度をJavaで取得する(シリアル通信 / jSerialComm)](https://qiita.com/items/1759498f8f706c4c3314)
　関連するGithubは[こちら](https://github.com/s5uishida/mh-z19b-driver)。
5. [PPD42NSからPM2.5濃度をJavaで取得する(GPIO / Pi4J)](https://qiita.com/items/4ae7784aeaf50df1e3d3)
　関連するGithubは[こちら](https://github.com/s5uishida/ppd42ns-driver)。
6. [産業オートメーション機器の稼動情報をJavaで取得する(OPC-UA / Eclipse Milo)](https://qiita.com/s5uishida/items/60954d356a3ea1048c61)
　関連するGithubは[こちら](https://github.com/s5uishida/rainy-opcua)。
7. [簡易ツールにまとめる](https://qiita.com/items/c56f1444c6856656b128)
　関連するGithubは[こちら](https://github.com/s5uishida/rainy)。
8. [後記](https://qiita.com/s5uishida/items/d2a888eb2d68e72f32ae)
9. **モーション検知(HC-SR501 / RCWL-0516)をJavaで取得する(GPIO / Pi4J)(今回)**
　関連するGithubは[こちら(HC-SR501)](https://github.com/s5uishida/hc-sr501-driver)と[こちら(RCWL-0516)](https://github.com/s5uishida/rcwl-0516-driver)。
10. [BME280(代用)から温度/湿度/気圧をJavaで取得する(I2C / Pi4J)](https://qiita.com/s5uishida/items/cb791d015dba41202e90)
　関連するGithubは[こちら](https://github.com/s5uishida/bme280-driver)。
11. [BH1750FVI(代用)から照度をJavaで取得する(I2C / Pi4J)](https://qiita.com/s5uishida/items/1a75c46e7d63fa480e34)
　関連するGithubは[こちら](https://github.com/s5uishida/bh1750fvi-driver)。