M5Stackでオフィス用のインターホンを作ってslackで来客通知しよう！



こんにちは！

「あなたのマイスター」などを運営するユアマイスター株式会社で現在大学に通いながらエンジニアインターンとして働いているむらかみです。

突然ですが、ユアマイスターのオフィスにはある大きな問題がありました。
それが、**「受付がない」**ということ。

オフィスは7階建ての7階、エレベーターを上がったらエレベーターホールがあってドアの先にオフィスがある、という構造なのですが、受付や呼び出し装置はありません。

![玄関.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/8f31fa32-b4cb-ae95-e729-42b5b68e9231.jpeg)
↑ユアマイスターのエントランス

なのでこれまでどうしていたかというと、

**・お客さんが勇気を出してドアを開ける**
**・気づいたドア付近のメンバーがエレベーターホールで困っていそうなお客さんに話しかける**

のどちらかでした。

この状態だとお客さんもどうすればいいかわからず、ドア付近のメンバーの集中力も途切れてしまうのではないかという課題をずっと感じていました。実際に営業チームによると、7階まで来たのに受付が無いために1階に引き返してお電話を下さったお客様もいらっしゃったそうです。

さて、ちょうどそのころ、私は3ヶ月くらい前の「いい買い物の日」に**絶対なにか買わねば！！！**という衝動に駆られ、M5Stackを格安で購入したのですが、特に何をするわけでもなくチョロっとチュートリアルなんかをやって放置していたことを思い出しました。

そこで私は思いました。

**「M5Stackでインターホンを作ってSlackで来客通知が来るようになればみんなハッピーになれるのでは？」**

ということで、**思いついたらやってみよう**ということで早速作ってみました！

#完成品の概要
![インターホン斜め.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/deb1225e-4dc8-3f8d-3e5c-5d379610ba37.jpeg)

完成品はこちら。
M5Stackの3つのボタンで、「面接」「訪問」「宅配」を選択できるようになっています。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%B3%E7%94%9F?src=hash&amp;ref_src=twsrc%5Etfw">#インターン生</a> が作ってくれた、会社のインターフォン。<br><br>押すと流れる音楽は、<a href="https://twitter.com/hashtag/%E3%81%82%E3%81%AA%E3%81%9F%E3%81%AE%E3%83%9E%E3%82%A4%E3%82%B9%E3%82%BF%E3%83%BC?src=hash&amp;ref_src=twsrc%5Etfw">#あなたのマイスター</a> のCM曲です！<br>オフィスにお越しの方はぜひ、ボタンを押してこの曲に耳を傾けてみてください！<br>/<br>あ〜な〜た〜の〜マイっスタ〜♪<br>\ <a href="https://t.co/FesPffN8Bn">pic.twitter.com/FesPffN8Bn</a></p>&mdash; ユアマイスター株式会社 (@yms_saiyou) <a href="https://twitter.com/yms_saiyou/status/1238390850113032192?ref_src=twsrc%5Etfw">March 13, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

「面接」「訪問」ボタンを押すと、「あなたのマイスタ〜♫」のチャイムが鳴り、「宅配」ボタンを押すと「ピンポ〜ン」と鳴ります。音が鳴った後は、slackの専用チャンネル #notice_intercom に通知が来るようになっています。

![slackキャプチャ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/7f6aeb2c-6b21-56cb-4c34-492b68710726.jpeg)
↑初めてピンポンダッシュ以外のまじめな通知が来た瞬間（「value」はユアマイスターの大事にしている5つの項目がランダムで帰ってくるbotです）

お客様がどんな目的で来社されたのかは通知を見ればパッとわかるようになっているので、ご案内もしやすいです！

#用意するもの

完成品を見たところで、今回使用したものを見ていきましょう！

**・[M5Stack](https://www.switch-science.com/catalog/3647/)**
Wifiで通信ができるESP-32、小型ディスプレイ、microSDカードスロット、スピーカーなどがコンパクトに内蔵されたスマートなマイコンです。いい買い物の日で調子に乗った私は9軸センサ付きのM5Stack Grayを買いましたが、インターホンをやるなら1000円くらい安いBasicで全く問題ありません。

**・Type-Cの延長ケーブル**
M5Stackの充電用ケーブルです。インターホンを設置する場所と電源供給元のバランスをいい感じに見積もって最適な長さのものを選びましょう。

**・microSDカード**
M5Stackに画像を表示するために使います。

**・Wi-Fi環境**
5G環境はESP32が対応していないので、2Gなどが好ましいです。

#下準備
用意するものが揃ったら、さっそく下準備をしましょう！

##M5Stackの環境構築
ArduinoIDEをダウンロードして、環境構築をしましょう。
やり方は以下の記事を参考にしてみてください。↓

[【心折れずに】MacでM5stackをはじめる](https://qiita.com/hmmrjn/items/2b2da09eecffcbdbad85)

##IFTTTの設定
事前に、M5Stackからslackに通知を送るための準備をしておきましょう！

###IFTTTって何？
**IFTTT(イフト)**とは、「if this then that」の略でTwitterやSpreadsheetなど、数あるWebサービスを連携させることができるサービスです。
例えば、「Twitterで特定の単語を含むツイートをSpreadSheetに自動保存する」など、細かいものを自動化する際にとても便利なサービスです。

###レシピの作り方
![ifttt設定.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/4682c6bd-c1bd-e01f-d7fc-1fe622e58e30.jpeg)

「create your own」をクリックし、IFの場合に**webhook**を選択し、任意のトリガー文字列(EventName)を設定します。また、THENの場合に**slack**を選択し、任意のチャンネルに任意のメッセージを送信するように設定しておきましょう！（もちろん、LINEなどでも同様のことができますよ！）

私は以下のように設定しました↓

| EventName|Slackメッセージ |
|:-----------------|:------------------|
| ym-mensetsu      | `面接` のお客様がいらっしゃいました！ @here |
| ym-houmon     | `訪問` のお客様がいらっしゃいました！ @here |
| ym-takuhai      | `宅配` のお客様がいらっしゃいました！ @here |


###レシピのテストをしよう！

レシピができたら、きちんとslack上で動くかテストをします。
![IFTTTtest.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/d310c987-a32d-05c8-0f3d-6810d37c9bcd.png)

まず、IFTTTのトップページからWebhookを選択します。
次に、右上のSettingsボタンを押してAccount Infoの中のURLをコピーして開きます。
![IFTTTtest.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/65fe4749-75b4-b5fe-a107-ffdaa19f06c5.jpeg)
このページが表示できたら、先程レシピを作る際に自分で考えたEventNameを｛event｝と書かれたところに入力します。この状態で、「Test It!」を押すと該当のSlackチャンネルにテスト通知が飛びます。

これでIFTTTの設定は完了です！

##表示する画像の準備
<img width="980" alt="スクリーンショット 2020-03-12 0.43.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/82d29125-22c2-f977-46c3-fa0eaab7f51e.png">

320×240で4枚の画像を用意します。ラインナップは以下のようになっています。

1.デフォルトの画像
2.「面接」ボタンが押された時の画像
3.「訪問」ボタンが押された時の画像
4.「宅配」ボタンが押された時の画像

必ず「画像名.jpg」で保存して、microSDカードに書き込んでください。
画像をカッコよく作れると**完成品ができた時のテンションが一気に爆上がりする**ので、ここが正直一番大事なフェーズかもしれませんwがんばりましょう。

##流す音の準備
今回は、「面接」「訪問」ボタンが押された場合はCMの「あなたのマイスター」のオリジナルソング（耳コピ）を、「宅配」ボタンが押された場合は普通のインターホンの音が鳴るようにしました。

```c
// 音の設定
void beep(int freq, int duration, uint8_t volume) {
  // freq(Hz), duration(ms), volume(1~255)
  int t = 1000000 / freq / 2;
  unsigned long start = millis();
  while ((millis() -start) < duration) {
    dacWrite(SPEAKER_PIN, 0);
    delayMicroseconds(t);
    dacWrite(SPEAKER_PIN, volume);
    delayMicroseconds(t);
  }
  dacWrite(SPEAKER_PIN, 0);
}
```

今回スピーカーで流す音のメソッドはこのようなコードで設定しています。
beepの**1つ目の引数は周波数（Hz）、2つ目の引数は音の長さ（ms）、3つ目の引数は音の大きさ**です。

M5Stackのスピーカーで音階を指定するには、周波数を1つ目の引数に書き込む必要があります。
音階に対する周波数は以下のようになっています。

(半音上がりの音階などもっと幅広い周波数が知りたい方は[こちらのサイト](https://tomari.org/main/java/oto.html)を参考にしてみてください。)

| 音階 | 周波数 | 
|:---|-------:|
| ド   | 261 |
| レ   | 293 |
| ミ   | 329 |
| ファ   | 349 |
| ソ   | 391 |
| ラ   | 440 |
| シ   | 493 |
| ド   | 523 |


「あなたのマイスター」オリジナルCMソング（耳コピ）は**ラ#ファソファレッラ〜#**なので周波数変換すると**466 349 391 349 587 466**で、インターホンの音は**ミッ、ド〜ミッ、ド〜**なので、周波数変換すると**659 523 659 523**となります。

音階がわかったら、あとは2つ目の引数でその音をどれだけ長く流すか、3つ目の引数でその音をどれだけ大きく流すかの設定をします。休符はdelay(ms)で設定できるのでコードを書くあらかじめ曲のイメージを頭の中に持っておき、周波数をメモしておきましょう。

#M5Stackにコードを書き込む

ここまで準備ができたら、最後にM5Stackに画像を保存したMicroSDカードを差し込み、以下のコードを読み込ませます！

M5Stackの端子はTypeCなのにも関わらず上下があるので上手くマイコンを認識してくれない場合は逆方向に差し直してみてください。
また、読み込んだ直後は画像が表示されない場合があるので、その場合は左側面にある赤いボタンを押してみてください。

```c

#include <M5Stack.h>
#include <WiFiClientSecure.h>
#include <WiFi.h>

#define SPEAKER_PIN 25

// wifi設定
const char* ssid = "wifiのSSIDを書き込む";
const char* password = "wifiのパスワードを書き込む";

// ifttt設定
const char* host = "maker.ifttt.com";
const int httpsPort = 443;

void setup() {
  M5.begin();
  WiFi.begin(ssid,password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }

  // デフォルト画像設定
  M5.Lcd.drawJpgFile(SD, "/デフォルトの画像.jpg");
}

// 音の設定
void beep(int freq, int duration, uint8_t volume) {
  // freq(Hz), duration(ms), volume(1~255)
  int t = 1000000 / freq / 2;
  unsigned long start = millis();
  while ((millis() -start) < duration) {
    dacWrite(SPEAKER_PIN, 0);
    delayMicroseconds(t);
    dacWrite(SPEAKER_PIN, volume);
    delayMicroseconds(t);
  }
  dacWrite(SPEAKER_PIN, 0);
}

void loop() {
  M5.update();

  // 「面接」ボタンが押された場合
  if (M5.BtnA.wasPressed()) {
    // CMソングを流す(音量はここの3番目の引数で調整できます！)
    beep(466, 300, 10);
    beep(349, 300, 10);
    beep(391, 300, 10);
    beep(349, 300, 10);
    beep(587, 200, 10);
    delay(400);
    beep(466, 1000, 10);
    
    // 画像を変更
    M5.Lcd.drawJpgFile(SD, "/面接の画像.jpg");

    WiFiClientSecure client;
    if (!client.connect(host, httpsPort)) {
      Serial.println("connection failed");
      return;
    }
    String url = "/trigger/ym-mensetsu/with/key/自分のwebhookキーを入力";
    client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                   "Host: " + host + "\r\n" +
                   "User-Agent: BuildFailureDetectorESP32\r\n" +
                   "Connection: close\r\n\r\n");
    Serial.println("request sent");
    while (client.connected()) {
      String line = client.readStringUntil('\n');
      if (line == "\r") {
        Serial.println("headers received");
        break;
      }
    }
  
    String line = client.readStringUntil('\n');

    // 押されてから20秒は待機設定にする
    delay(20000);
    M5.Lcd.clear();
    
    // デフォルト画像に戻す
    M5.Lcd.drawJpgFile(SD, "/デフォルトの画像.jpg");
  
  // 「訪問」ボタンが押された場合
  } else if (M5.BtnB.wasPressed()) {
    // CMソングを流す
    beep(466, 300, 10);
    beep(349, 300, 10);
    beep(391, 300, 10);
    beep(349, 300, 10);
    beep(587, 200, 10);
    delay(400);
    beep(466, 1000, 10);
    M5.Lcd.drawJpgFile(SD, "/訪問の画像.jpg");

    WiFiClientSecure client;
    if (!client.connect(host, httpsPort)) {
      Serial.println("connection failed");
      return;
    }
    String url = "/trigger/ym-houmon/with/key/自分のwebhookキーを入力";
    client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                   "Host: " + host + "\r\n" +
                   "User-Agent: BuildFailureDetectorESP32\r\n" +
                   "Connection: close\r\n\r\n");
    Serial.println("request sent");
    while (client.connected()) {
      String line = client.readStringUntil('\n');
      if (line == "\r") {
        Serial.println("headers received");
        break;
      }
    }
  
    String line = client.readStringUntil('\n');
    delay(20000);
    M5.Lcd.clear();
    M5.Lcd.drawJpgFile(SD, "/デフォルトの画像.jpg");
  
  // 「宅配」ボタンが押された場合
  } else if (M5.BtnC.wasPressed()) {
    // ピンポーンの音
    beep(659, 500, 10);
    beep(523, 1000, 10);
    delay(400);
    beep(659, 500, 10);
    beep(523, 1000, 10);
    M5.Lcd.drawJpgFile(SD, "/宅配の画像.jpg");

    WiFiClientSecure client;
    if (!client.connect(host, httpsPort)) {
      Serial.println("connection failed");
      return;
    }
    String url = "/trigger/ym-takuhai/with/key/自分のwebhookキーを入力";
    client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                   "Host: " + host + "\r\n" +
                   "User-Agent: BuildFailureDetectorESP32\r\n" +
                   "Connection: close\r\n\r\n");
    Serial.println("request sent");
    while (client.connected()) {
      String line = client.readStringUntil('\n');
      if (line == "\r") {
        Serial.println("headers received");
        break;
      }
    }
  
    String line = client.readStringUntil('\n');
    delay(20000);
    M5.Lcd.clear();
    M5.Lcd.drawJpgFile(SD, "/デフォルトの画像.jpg");
  } 
}
```

正しく書き込みができたら、オリジナルインターホンの完成です！

#最後に

いかがでしたか？万能マイコンM5Stackを使うと、意外にも簡単にインターホンが作れてしまうんですね！

これを設置した結果、エレベーターホールでウロウロしてしまうお客様が減り、ドア付近でお仕事をされている社員さんやインターンの方からもとても感謝されました。

しかし、**ボタンがあると無性に押したくなってしまう**のが人間の性なので、初日は社員（主に開発チーム）による**ピンポンダッシュが多発してしまいました。**（ `@here` されるので、女性社員から怒られていました）
今後はカメラの部品などを導入するなどして、ピンポンダッシュ対策にも力を入れたいと思います！！！

課題を感じている人に解決策として自分の作ったものが受け入れられ、日常の一部になるまで使ってもらえるということは、モノづくりをする側にとってこれ以上無いほど嬉しいことですね。本当に作ってよかったです！

次はM5StickVなどでAI×IoTの世界の開発にも挑戦してみたいと思います！

#参考
・[みんなのM5Stack入門](https://www.amazon.co.jp/%E3%81%BF%E3%82%93%E3%81%AA%E3%81%AEM5Stack%E5%85%A5%E9%96%80-%E4%B8%8B%E5%B3%B6-%E5%81%A5%E5%BD%A6/dp/4865942092/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=%E3%81%BF%E3%82%93%E3%81%AA%E3%81%AEM5Stack&qid=1584114788&sr=8-1)