M5Stack BasicにEddystone Beaconを検出したときにMP3ファイルを再生させるまで

# 用意した物
1. microSDカード
1. M5Stack Basicと付属のUSBケーブル
1. Androidスマートフォン
1. [Arduino IDEをセットアップ済みのWindows10](https://qiita.com/yohama/items/9dc5298dfeb3eaa2b22a)

# MP3ファイルの用意

再生させたいMP3ファイルを用意します。

ここでは、[Audionautix](https://audionautix.com/)から、クリエイティブ・コモンズの音楽ファイル[Limosine.mp3](https://audionautix.com/Music/Limosine.mp3)をダウンロードしてくることにします。

別のものを用意した場合には、以下のファイル名Limosine.mp3を、用意したMP3ファイルのファイル名に読み替えてください。

<a href="https://audionautix.com/">Creative Commons Music by Jason Shaw on Audionautix.com</a>

microSDカードをWindows10の動いているPCのカードリーダ・ライタに挿入し、ルートディレクトリに、Limosine.mp3をコピーします。

コピーが終了したら、microSDカードをPCから取り外して、M5Stack Basicに挿入しておきます。

# Eddystone Beaconの送信機の用意

M5Stack Basicに対してEddystone Beaconを送信する機器を用意します。

ここでは、Androidスマートフォン上で動作するアプリ[Beacon Simulator](https://play.google.com/store/apps/details?id=net.alea.beaconsimulator&hl=ja&gl=US)を利用することにします。

Beacon Simulatorのインストール後、起動したら、メイン画面の右下の「＋」をタップします。

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169654/f5034cf6-35ae-2afe-7daf-9c5b666df99e.png)

画面下部にBeaconの種類の選択肢が表示されるので、"Eddystone UID"をタップします。

![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169654/9eba1976-0b2f-727f-4bbc-e24bded56ac9.png)

デフォルトでランダムなNamespace IDのEddystone Beaconの設定に、日付を含むラベル"EddystoneUID-YYYY-MM-DD"がつけられて、候補として表示されます。

変更があれば適切に変更した上で、画面右上の「✓」をタップします。

![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169654/88caf48b-e290-aa7a-80da-f4c6f632f265.png)

メイン画面に戻ると、設定したものが、登録されていることがわかりますが、この状態ではまだEddystone Beaconは送信されていません。

![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169654/8dc125bc-71d1-7353-1654-91666516f985.png)

ここで、設定したEddystone Beaconの横にある灰色の長丸印をタップすると、オレンジ色となってEddystone Beaconの送信が始まります。

![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169654/7ed4034d-f4f0-adda-bf7a-65895a21aba0.png)

この時点では、送信できているかどうかは不明ですが、オレンジ色になっている長丸印をタップして灰色に変わることを確認し、Eddystone Beaconの送信を停止させておきます。

# Arduino IDEでESP8266Audioをインクルード

Arduino IDEを起動して、メニューバーの「スケッチ」→「ライブラリをインクルード」→「ライブラリを管理」を選択します。

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169654/0f4e3d09-ee85-8e39-3ad1-74c28624b23c.png)

ライブラリマネージャのウィンドウが起動するので、検索窓に"ESP8266Audio"とキーボードで入力します。

しばらくすると、検索結果がウィンドウ内の下部に表示されるので、「インストール」ボタンをクリックしてインストールします。

![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169654/1af58dab-ccb2-8742-2e58-bdc2b1b811bf.png)

インストールが終わったら、「閉じる」ボタンをクリックして、ライブラリマネージャを閉じます。

# スケッチの作成

Windows10上でArduino IDEを起動し、スケッチを作成します。

```cpp
#include <string>

#include <M5Stack.h>
#include <BLEDevice.h>

#include "AudioFileSourceSD.h"
#include "AudioFileSourceID3.h"
#include "AudioGeneratorMP3.h"
#include "AudioOutputI2S.h"

#define EDDYSTONE_BEACON BLEUUID((uint16_t)0xFEAA)
#define BEACON_NAMESPACE \
        {0x51, 0x17, 0xb8, 0x81, 0xc2, 0xc7, 0xd3, 0x0f, 0x47, 0x19}
#define MP3AUDIO_FILEPATH "/Limosine.mp3"
#define BLESCAN_DURATION 120

static uint8_t NS[] = BEACON_NAMESPACE; 
BLEScan* pBLEScan;
bool detected = false;

class playMP3 {
  private:
    AudioGeneratorMP3* _mp3;
    AudioFileSourceID3* _id3;
    AudioOutputI2S* _out;
  public:
    playMP3(char* path): 
      _mp3(new AudioGeneratorMP3()),
      _id3(new AudioFileSourceID3(new AudioFileSourceSD(path))),
      _out(new AudioOutputI2S(0, 1)) {}
    void setParameters(float gain=0.5) {
      _out->SetGain(gain);
      _out->SetOutputModeMono(true);
    }
    void play(void) {
      _mp3->begin(_id3, _out);
      while (_mp3->isRunning()) {
        if (!_mp3->loop()) {
          _mp3->stop();
        }
      } 
    }
};

class myBLEAdvertisedDeviceCB: public BLEAdvertisedDeviceCallbacks {
  private:
    uint8_t* _ns;
    uint8_t _size_ns;
  public:
    myBLEAdvertisedDeviceCB(uint8_t* ns, uint8_t size_ns=10):
      _ns(ns), _size_ns(size_ns) {}
    void onResult(BLEAdvertisedDevice advertisedDevice) {
      uint8_t cServiceData[100];
      std::string strServiceData = advertisedDevice.getServiceData();
      strServiceData.copy((char *)cServiceData, strServiceData.length(), 0);
      if (advertisedDevice.getServiceDataUUID().equals(EDDYSTONE_BEACON)) {
        if (memcmp(cServiceData+2, _ns, _size_ns) == 0) {
          advertisedDevice.getScan()->stop();
          detected = true;
          M5.Lcd.printf("NS:");
          if (_size_ns + 2 < strServiceData.length()){
            for (int i=0; i<_size_ns; i++) {
              M5.Lcd.printf("%02X",cServiceData[i+2]);
            }
          }
          M5.Lcd.printf(" Device:%s\n", advertisedDevice.toString().c_str());
        }
      }
    }
};

void setup()
{
  M5.begin();
  BLEDevice::init("");
  pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new myBLEAdvertisedDeviceCB(NS));
  pBLEScan->setActiveScan(true);
}

void loop()
{
  playMP3 audio(MP3AUDIO_FILEPATH);
  audio.setParameters();
  detected = false;
  M5.Lcd.clear(BLACK);
  M5.Lcd.setCursor(0, 0);
  M5.Lcd.printf("Scanning Eddystone Beacon...\n");
  pBLEScan->start(BLESCAN_DURATION, false);
  if (detected) {
    audio.play();
  }
}
```

gitが使える環境であれば、適当なディレクトリで、git cloneすることで、上記スケッチの雛形をダウンロードできます。

```bash
git clone https://github.com/yohama/PlayMP3TriggeredByEddystone.git
```

ダウンロード後に、PlayMP3TriggeredByEddystone/PlayMP3TriggeredByEddystone.ino内のコードのうち、define文の記述を書き換えてください。

スケッチを作成し終えたら、メニューバーの「ファイル」→「名前を付けて保存」と選択して、適当な名前で保存します。

次に、M5Stack Basicを、USBケーブルで、Arduino IDEの動作しているPCに接続しておきます。

そして、「→」（マイコンボードに書き込む）ボタンをクリックします。

しばらくの間コンパイルが行われ、コンパイル終了後にM5Stack Basicに書き込まれます。

# 動作確認

M5Stack Basicの画面に"Scanning Eddystone Beacon..."と表示されたら、Eddystone Beaconの送信機から、スケッチ内のdefine文でBEACON_NAMESPACEで設定したビーコンを送信します。

M5Stack Basicのスピーカーから、MP3の音声ファイルが再生されたら成功です。

# 参考サイト

https://qiita.com/ktansai/items/f0096495e2ca7fa38eb7

https://decode.red/net/archives/746

https://github.com/earlephilhower/ESP8266Audio

https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLETests/SampleScan.cpp

https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_BLE_beaconscan/ESP32_BLE_beaconscan.ino