M5StickCである一定の音域が検出されたらSwitchBotを作動させる

## 動作イメージ
M5StickCにはマイクが内蔵されており、それを使ってなんか物音がしたら部屋の電気などをつけてみようかと思います。
泥棒や指パッチンでも使えるかも…？

[![Image from Gyazo](https://i.gyazo.com/d97a614436475a4ffb4b573611fc37df.png)](https://gyazo.com/d97a614436475a4ffb4b573611fc37df)

## 開発環境、使った機材

- Mac OS10.15.4
- M5StickC (https://www.switch-science.com/catalog/5517)
- SwitchBot (https://www.switchbot.jp/bot/)
- Arduino 1.8.10 (https://www.arduino.cc/)
- ESP32ライブラリ 1.0.4
- M5StickCライブラリ 0.1.1
- arduinoFFTライブラリ 1.5.5

## 注意点
以下は今回のとは関係なく既存である問題ですね…

- ESP32への書き込みエラー
  - Mac OSX 10.15系でのみ、出る
  - A0とGNDをピンでつなげる
  - USB接続
  - 書き込み
  - ピンを抜き、M5StickCの再起動(電源ボタン6秒押し、その後2秒押し)
  - [参考サイト](https://qiita.com/SamAkada/items/fa32d6072a832a10cd84)
- M5StickCのディスプレイがつかない  
  - Arduinoのスケッチの例のM5StickC内の「Hello World」を書き込む

ちなみにArduinoのダウンロードやESP32系に対して書き込む設定だったりは省略します。

## ソースコード
GitHubで共有しました！
https://github.com/tkyko13/M5StickC-SwitchBot

### プログラムの変更、調整

```C
#include <M5StickC.h>
#include <driver/i2s.h>
#include "arduinoFFT.h"
#include "BLEDevice.h"

// 5kHz -> 5/0.17=29.411... の四捨五入整数 = 29
// 値が-1の場合、周波数はなし
#define TH_FREQ_BAND -1
// 音量閾値
#define TH_VOLUME 0.1

// 手元のSwitchBotのMACアドレス
#define MAC_SWITCHBOT "Your_SwitchBot_MAC"
<---以下省略--->
```

#### 閾値変更
`TH_VOLUME`の値を変更することで音量による閾値を設定できます。
0.1でも結構大きい音じゃないと反応しないです。

#### 周波数フィルタリング機能
`TH_FREQ_BAND`の値を変えることで、検出する周波数帯を変更します。
`周波数`ではなく`周波数帯`です。
1帯域につき0.17kHzです。
例えば`TH_FREQ_BAND 0`であれば、0kHzから0.17kHzの間の音量だけを検出します。
5kHzの周波数を検出したい場合、`TH_FREQ_BAND 29`になります。(29*0.17=4.93)

#### MACアドレスの変更
SwitchBotの個体と接続することができます。
MACアドレスの取得方法と変更箇所は以下です。

##### 手持ちSwitchBotのBLEのMACアドレスの取得
- スマートフォンアプリ「SwitchBot」をダウンロード 
    - [Androidアプリ](https://play.google.com/store/apps/details?id=com.theswitchbot.switchbot&hl=ja)
    - [iOSアプリ](https://apps.apple.com/jp/app/switchbot/id1087374760)
- スマートフォンのアプリから接続
- 「Botセット」画面から右上のボタン
[![Image from Gyazo](https://i.gyazo.com/b91dae753986ec0a95f1ecce84dd7c0c.png)](https://gyazo.com/b91dae753986ec0a95f1ecce84dd7c0c)
画像元サイト : [https://webnetforce.net/unlock-auto-door-with-switchbot/](https://webnetforce.net/unlock-auto-door-with-switchbot/)

##### ソースコード変更
MAC_SWITCHBOTの`Your_SwitchBot_MAC`を変更します。  
01:23:45:67:89:abみたいな文字列ですね。

#### 実は

```c++
if (addr.equalsIgnoreCase(MAC_SWITCHBOT)) {
// SwitchBot を発見
// if (advertisedDevice.getServiceUUID().equals(SERV_SWITCHBOT)) {
          log("found");
```

SwitchBotのMACアドレスがわからなかったり面倒であればわからなくても大丈夫です。
上記の部分を探して、

```c++
// if (addr.equalsIgnoreCase(MAC_SWITCHBOT)) {
// SwitchBot を発見
if (advertisedDevice.getServiceUUID().equals(SERV_SWITCHBOT)) {
          log("found");
```

このように変更するとよいです。
詳しくは説明しないですが、BLEの中のサービスというのがあって、SwitchBotではそれがすべて同じ値なのでその値でSwitchBotを探しています。
これでもいいですが、もしかしたら隣の部屋の人のSwitchBotが動いちゃうかも？？

## 実際実装してみて
### M5StickCでBluetooth接続失敗の取得方法
SwitchBotを探すスキャンは安定していますが、どうしても接続するときに失敗が起きます。
これは別のアプリで、関係ないものと接続してもなるので、仕方ないことなのかと思います。
ただ、Arduinoで書くM5StickCの接続で、失敗の取得がスマートにはできないです。
具体的には、

```c++
pClient->connect(myDevice)
```

非公式日本語リファレンスでは、こちらの引数で失敗したらfalseが返ってくるはずですが、処理が止まっちゃいます。
接続開始する前にフラグを立てておき、接続失敗イベント（接続が切れたイベント）を貼っておき、成功か失敗かを取得します。
失敗していたら、処理が止まっているため再接続ではなく再起動しています…
幸いラズパイなんかよりかは断然再起動早いのでまぁいいかなくらいです。

```C++
bool connecting = false;

// 略

connecting = true;
pClient->setClientCallbacks(new MyClientCallback());
pClient->connect(myDevice);
connecting = false;

// 略

class MyClientCallback : public BLEClientCallbacks {
    void onDisconnect(BLEClient* pclient) {
      Serial.println("onDisconnect");
      if (connecting) {
        esp_restart();
      }
    }
};
```

抜粋するとこんなコードになります。
connect処理で止まって次の行に行かないです、onDisconnectイベントは実行されるけど…

## 雑談
MacOSがカタリナだと書き込みも面倒だったので、古いMacbook取り出して開発しちゃってました。
ATOM Lite（https://www.switch-science.com/catalog/6262/） も同じマイコンを使っているはずですが、カタリナで書き込めたらしい…
ほしい…