水が無くなったらSlack通知が来る装置をつくってオフィスのQOLを上げよう！


この記事は[ユアマイスター Advent Calendar 2019](https://qiita.com/advent-calendar/2019/yourmystar)14日目の記事です。

みなさんこんにちは。
現在大学に通いながらユアマイスターでエンジニアインターンとして働いている、むらかみです。

突然ですがユアマイスターには現在、大きな問題があります。

それがこちら
<img width="1016" alt="スクリーンショット 2019-12-10 20.26.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/7a525733-80b8-1f2b-08d4-a49eb35c4546.png">

ウォーターサーバーの水が定期的に無くなってしまうにも関わらず、スムーズに報告が行き渡らないことです。

現在ユアマイスターでは、ウォーターサーバーの水タンクが3個以下になったらエンジニアの社員であるFさんに報告することになっています。しかし、エンジニアって話しかけるタイミングがウルトラ難しいですよね。

とくにFさんは、自分のカレンダーの12時から14時までの間の時間を「できるだけ予定入れないでほしい時間」というようにブロックしているほど自分の世界に入るエンジニア。自分の世界に入りすぎて、時々繰り出す発言*も混沌を極めたものばかりです。

そんなFさんが集中しているときに、**「また反応に困る発言を言われるのではないか…」**という不安と戦いながら、「水無くなったから注文しといて〜」なんて気軽に話しかけられません…

しかしFさんはあくまでも私のメンターでありユアマイスターのCWO（Chief Water Officer）…
このまま「すみません、水無くなりました」発言が社内チャットツールに何度も流れることがあれば、Fさんの信用も失われてしまうことでしょう。

そこで私は考えました。

**「水タンクの在庫チェックを自動でやれるようになれば、スムーズに在庫の管理ができFさんの作業効率も上がるのではないか？？」**

というわけで、ユアマイスターのQOLを上げるべく今回は水タンクの在庫管理ができるIoT装置を作ってみました！

*`「天下一品神田店は僕の東京支部本部」` `「プログラミング言語界のノンシリコンシャンプー」`など

#設計図
<img width="821" alt="スクリーンショット 2019-12-13 12.47.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/485f09f3-dfb5-c4c1-245d-52bf8e3f07f4.png">


こんな感じの設計図で作っていきます。
今回は10kgまで測れる圧力センサを4つ足の台の1つにつけることで、40kgまで測ることができるようにしました。圧力センサと木材の間に切ったクリアファイルを貼り付けることでセンサに圧力もかかりやすくなっています。


#用意するもの
設計も掴んだところで、用意するものを見ていきましょう！

**・[ESP-WROOM-32](http://akizukidenshi.com/catalog/g/gM-11819/)**
**・圧力センサ**
今回は[10kgまで測れるもの](https://www.amazon.co.jp/gp/product/B07QCVNYN4/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1)を買いました。

<img width="797" alt="スクリーンショット 2019-12-13 11.50.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/a8dfca14-6bde-c82c-6a5a-c6b3ebeca46e.png">

下準備として、電線をはんだ付けし使いやすいように加工しましょう。

**・抵抗(330Ω)**
**・ブレッドボード**
**・USBコード**
ESP32とPCの接続を安定させるために、最も重要なのがコードとの相性です…！
しっかり接続が安定するものを使いましょう。ちなみに私は家にあるコードをかき集めやっと3本目で神コードに出会いました。いいコードを選ぶとシリアルポートの認識の良さが格段に違います。
**・Wi-Fi環境**
5G環境はESP32が対応していないので、2Gなどが好ましいです。
**・木材**
土台となる厚みのある正方形の板と、足用の丸い板を買いました。
色をつけたい人はペンキやカラースプレーなどを準備して塗っておくと良さそうです。
**・クリアファイル**
切れ端を少しだけ使います。いらないものを用意しておきましょう。
**・はんだ**
圧力センサの下準備と最後の仕上げに使います。
**・接着剤**
木材の接着に使います。

#作り始めるまでの準備〜ESP32の環境を整える〜
まずはじめに、ESP32の環境構築をしていきます。
手順は以下のとおりです。

**1.ArduinoIDEをダウンロード**
[こちら](https://www.arduino.cc/en/Main/Software)からダウンロードできます。

**2.環境設定でURL入力**
<img width="811" alt="スクリーンショット 2019-12-13 11.44.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/b04d4bcd-db63-f33e-5177-7e37e5df75a0.png">

ArduinoIDEを開きファイル→環境設定から追加のボードマネージャのURLを選択肢、以下のURLを追加して保存します。

```
https://dl.espressif.com/dl/package_esp32_index.json
```

**3.ESP32のライブラリをダウンロード**
次にメニューから ツール→ボード→ボードマネージャを選択し、ESP32と検索した後に「esp32 by Espressif Systems」を選択し最新バージョンをインストールします。

**4.【重要】Macの人はドライバをダウンロードする**
ここを飛ばすと以下のようなエラーが出現します。これが出るということは正しいシリアルポートが選択できる状態にない状態です。

`A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header`

ドライバは[こちら](https://jp.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers)からダウンロードできます。

**5.ESP32をPCにつなぐ**

**6.ボードを"ESP32 Dev Module"に、シリアルポートを先程ダウンロードしたものに選択する**

ESP32のLEDが赤く光ったら完了です！

#さっそく圧力センサの値を出力してみよう！
まずは、Arduinoなどと同じように圧力センサの値をアナログ出力してみましょう。
（アナログ出力＝数字で出るもの、デジタル出力＝0か1のもの）

回路は以下のとおりです。
<img width="824" alt="スクリーンショット 2019-12-13 12.48.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/11d0aadd-9443-7283-6d4d-7dbd66b9d0d8.png">


後々Wi-FiとESP32をつなげる際に普通の環境で出力できてもアナログ入力を使えないピンが存在するので、ここではWi-Fi環境下でも使える**33番ピン**を使います。

```c
void setup(){
  Serial.begin(115200);  // シリアル通信速度
}

void loop(){
  // アナログ入力値を取得
  int a = analogRead(33);

  // 荷重をシリアル通信で送る
  Serial.println(a);
  // 1秒待機
  delay(1000);
}
```

上記のコードをエディタに書き、左上の矢印のマークを押し、「ツール→シリアルプロッタ」を押して115200bpsを選びます。
そうすると、センサが取得した値を1秒ごとに表示してくれます！

<img width="1030" alt="スクリーンショット 2019-12-10 20.23.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/cdece381-d20d-abd3-ee6b-9c140f3eff4c.png">


シリアルプロッタを起動させてみるとこんな感じで重さが測れていることがよくわかりますね！
下準備として、上に水タンク２個を置いた場合と３個になった場合の2つの重さを測っておきましょう。

2個の際はだいたい2800、3個の時はだいたい2940あたりなので、通知のトリガーを2880と決めます。

#ESP32をWi-Fiにつないでみよう！
ここまではArduinoなどと変わりませんでしたが、ここからがESP32の腕の見せどころです。
ファイル→スケッチ例→WebServer→HelloServerを選んでみましょう。

```
const char* ssid = "........"; //自分のWi-FiのSSIDを入れる
const char* password = "........"; //自分のWi-FiのPassを入れる
```

スケッチ例は、上記の箇所を変更するのみで大丈夫です。

<img width="770" alt="スクリーンショット 2019-12-10 18.48.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/526c32aa-b710-1d4a-12e8-24841257e11a.png">

シリアルモニタに出たIPアドレスを、同じWi-Fiにつないだデバイスのブラウザで表示すると、「hello from esp8266!」と表示されます！
これでESP32がWi-Fiにつながったことがわかりました！

※ESP32は5G環境には対応していないので、複数のWi-Fi回線がある場合は他のものを選びましょう。

#圧力センサをつけたESP32をWi-Fiをつなげて、IFTTTと連結してみよう！
さて、いよいよ最終段階です。
これまでやった２つのことを合体させて、IoT装置を作ってしまいましょう！

##下準備
そのまえに、まずはIFTTTの設定をします。

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

###レシピを作ろう！
そんなIFTTTを使って、今回は「Webhook」をトリガーに、「Slack」通知をしてみましょう！
<img width="1064" alt="スクリーンショット 2019-12-10 19.20.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/b1c12c63-bbb2-ae2c-969d-4baaa873613c.png">

「create your own」を選び、上の図のように、「This」に「webhook」、「That」に「Slack」を選択し、必要な項目を入力します。EventNameはコードにも書くのでわかりやすい名前を付けましょう！

次に、このレシピがきちんと動くかのテストをします。

<img width="773" alt="スクリーンショット 2019-12-13 12.50.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/5604ec10-2e3d-7bf2-b2a5-4aa2260cbcf5.png">


まず、IFTTTのトップページからWebhookを選択します。
次に、右上のSettingsボタンを押してAccount Infoの中のURLをコピーして開きます。

<img width="626" alt="スクリーンショット 2019-12-14 10.23.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/8de69eac-6241-f1e4-90c7-a385d132973c.png">


このページが表示できたら、先程レシピを作る際に自分で考えたEventNameを｛event｝と書かれたところに入力します。この状態で、「Test It!」を押すと該当のSlackチャンネルにテスト通知が飛びます。

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

##IFTTTとESP32を連携させる

最後に、ESP32に書き込むコードを書いていきます！

```c
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <Ticker.h>

// wifi設定
const char* ssid = "wifiのssidを入力";
const char* password = "wifiのパスワードを入力";

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

Ticker ticker;
bool readyForTicker = false;
bool isStopNortification = false;

void setReadyForTicker() {
  // フラグを立てる
  readyForTicker = true;
}

// 荷重を計測して一定以下の重さだった場合Slack通知する
void checkWeightAndNortify() {
  int a = analogRead(33);

  // 荷重をシリアル通信で送る
  Serial.println(a);
  // 1秒待機
  delay(1000);

  // 荷重が2880以下でisStopNortificationがtrueでない場合
  if ((a <= 2880) && (!(isStopNortification))) {
    WiFiClientSecure client;
    Serial.print("connecting to ");
    Serial.println(host);
    if (!client.connect(host, httpsPort)) {
      Serial.println("connection failed");
      return;
    }

    // IFTTTのトリガーを設定
    String url = "/trigger/自分で決めたEventNameを入れる/with/key/自分のWebhookキーを入れる";
    Serial.print("requesting URL: ");
    Serial.println(url);
  
    
    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');
  
    Serial.println("reply was:");
    Serial.println("==========");
    Serial.println(line);
    Serial.println("==========");
    Serial.println("closing connection");
    isStopNortification = true;
  } else if ((a > 2880) && (isStopNortification)) {
    isStopNortification = false;
  }
  
  // フラグを落とす
  readyForTicker = false;
}

// セットアップ
void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.print("connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  // 1時間（3600秒）ごとに計測する
  ticker.attach(3600, setReadyForTicker);
}

// 繰り返す処理
void loop() {
  if (readyForTicker) {
    checkWeightAndNortify();
    // 通知が複数回行かないようにする処理
    if (isStopNortification) {
      Serial.println("Nortification: stop");
    } else {
      Serial.println("Nortification: continue");
    }
  }
}
```

このコードをESP32に書き込むと…

<img width="693" alt="スクリーンショット 2019-12-13 11.43.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/ae43dcb5-8c6c-7d6a-ca78-906e3ce32db5.png">

イベントが正常に動作したことがわかります！
Slackにもちゃんと通知が来ていました。これでESP32の書き込みは終了です！


#装置を組み立てよう！
中身のプログラムの書き込みができたら、最後に装置自体の組み立てをしていきましょう！

<img width="953" alt="スクリーンショット 2019-12-10 20.13.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529505/4eb06140-7de8-8e09-c4fd-8ef057acd2a2.png">

①材料はこんな感じです。足は高さがESP32を付けても床に当たらないくらいのものにしましょう。今回はホームセンターで買った丸い木材の高さが１つでは足りなかったので２つくっつけていい感じの高さにしました。

②足を板に合わせて白く塗ります。足なので多少色ムラがあっても無視しましょう！！！

③センサを付けるところ以外の足を接着剤で均等に接着します。

④ブレッドボードに挿していた抵抗とセンサをはんだ付けします。余裕があればで大丈夫です。

⑤板とセンサの間にセンサより一回り小さく切り取ったクリアファイルを接着し、板とセンサ、クリアファイルと最後の足を接着します。

⑥最後にESP32にACアダプタをつければ完成です！！！

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ESP32と圧力センサで水タンクが2個以下になったらslack通知を送るデバイスを作ってオフィスに設置した。IoT！ <a href="https://t.co/24o1VOJtSb">pic.twitter.com/24o1VOJtSb</a></p>&mdash; むらかみ (@murakami_reiwa) <a href="https://twitter.com/murakami_reiwa/status/1200422132808732673?ref_src=twsrc%5Etfw">November 29, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

無事に設置までできてよかったです！！
これでもう水不足に苦しまれることもありません！！！！！！！
Fさんも長期的に超集中状態を継続できます。これで開発がバリバリに進むことでしょう。
これこそ**ハッピートライアングル**ですね！！

（と、思いきやデリケートなので触ったり移動させたりすると通知が飛んだり、まだ動作は不安定な状態です…試行錯誤を繰り返しながらの運用をしていきます）

#所感
今回始めてESP32を使ったのですが、Wi-Fiとの接続がかんたんにできることで可能性の幅と想像力がグッと広がりました！いろいろやってみたいことが増えたので、今度はESP32を内蔵したM5Stackなどでも何かを作ってみたいと思います！

**おことわり**
※この記事に登場するエンジニアはフィクションです。実在の人物とは一切関係ありません。
話しかけにくいエンジニアなどこの会社に1人もいません。本当です。

#参考
・[macOSでESP32-dev-moduleを実験する。](https://leico.github.io/TechnicalNote/Arduino/mac-esp32-dev)
・[LINEに通知してくれるおむつ用ごみ箱](https://cubic9.com/Devel/%C5%C5%BB%D2%B9%A9%BA%EE/ESP32/LINE%A4%CB%C4%CC%C3%CE%A4%B7%A4%C6%A4%AF%A4%EC%A4%EB%A4%AA%A4%E0%A4%C4%CD%D1%A4%B4%A4%DF%C8%A2/)
・[How to Trigger LED using IFTTT and ESP32 with Email Notification](https://iotdesignpro.com/projects/how-trigger-led-using-ifttt-and-esp32-email-notification)
・[【ESP32】Wifi接続時のanalogReadについて](http://rikoubou.hatenablog.com/entry/2017/07/26/193021)