Gobotを使ってトイレ混雑問題と真剣に向き合ってみた

この記事は[Go3 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/go3)の19日目です。

# はじめに
人類はこれまで幾度となく文明を進化させてきましたが、今だに解決仕切れていない問題があります。
そう、それは「トイレ混雑問題」。人間として生きていくためには避けて通れない問題です。

最近ではこの問題を危惧した様々な企業さん達が、こぞって記事を出しています。

[「トイレの混雑」を改善したリクルートの超アナログな方法](https://diamond.jp/articles/-/202333)

[職場のトイレの個室でソシャゲに没頭する困った大人たち](https://www.moneypost.jp/536375)

[『駅の空いてるトイレが分かる』アプリケーションを開発。「これを待っていた！」とSNSで話題に](https://iot.kddi.com/cases/odakyu/)

弊社もオフィスによっては個室の数が少なく、空いているかいないかのチェックに苦労している人もいるそうです。

その為、この問題をIoTで簡単に解決できないかと考え、「ラズパイ×Gobot」でトイレの混雑検知の仕組みを試作してみました！！！

# 構成

この辺りの記事を参考に構成を組んでいます。

[超音波距離センサ(HC-SR04)を使う](http://make.bcde.jp/raspberry-pi/%E8%B6%85%E9%9F%B3%E6%B3%A2%E8%B7%9D%E9%9B%A2%E3%82%BB%E3%83%B3%E3%82%B5hc-sr04%E3%82%92%E4%BD%BF%E3%81%86/)

[【Raspberry Pi】自作人感センサーの使い方と活用法](https://chasuke.com/motionsensor/)

![iOS の画像 (3).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308887/1c2c8276-82fc-6f08-18d9-96206fd744ac.jpeg)

![iOS の画像 (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308887/0ed1549a-8f7f-53ba-1cba-8f9959e43b87.jpeg)

# ソースコード

人感センサで人を感知した後に、人の背後に置いた超音波センサで人が席を離れたどうかを判定します。
超音波センサの判定距離はデモ用に作っているので、適当に設定しています。
slackへの通知はincoming-webhookを使い、このために作った専用のチャンネルに送信しています。

```Go
import (
	"gobot.io/x/gobot/drivers/gpio"
	"gobot.io/x/gobot/platforms/raspi"
	"time"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"gobot.io/x/gobot"
)

const (
	SensorValueDetect   = 1
	SensorValueUndetect = 0
)

func main() {

	err := motion()

	if err != nil {
		println(err)
	}
}

func motion() error {
	r := raspi.NewAdaptor()
	f := false
	trigPin := gpio.NewDirectPinDriver(r, "11")
	echoPin := gpio.NewDirectPinDriver(r, "13")

	work := func() {
		gobot.Every(3*time.Second, func() {
			// 7番ピンから直接センサーの値を読み取る
			v, _ := r.DigitalRead("7")

			if v == SensorValueDetect {

				if f == false {
					slack.SlackPostIn("誰かが来た様です。")
					f = true
				}

				println("Starting probing ")

				err := trigPin.DigitalWrite(byte(0))

				if err != nil {
					println(err)
					return
				}
				time.Sleep(2 * time.Microsecond)

				err = trigPin.DigitalWrite(byte(1))

				if err != nil {
					println(err)
					return
				}

				start := time.Now()
				end := time.Now()

				for {
					val, err := echoPin.DigitalRead()

					start = time.Now()

					if err != nil {
						println(err)
						break
					}

					if val == 0 {
						continue
					}

					break
				}

				for {
					val, err := echoPin.DigitalRead()
					end = time.Now()
					if err != nil {
						break
					}

					if val == 1 {
						continue
					}
					break
				}

				duration := end.Sub(start)

				distance := duration.Seconds() * 34300
				distance = distance / 2
				println(distance)
				if distance > 1000 {
					println(distance)
					slackPostOut("部屋が空きました。")
					f = false
				}
			}
		})
	}
	robot := gobot.NewRobot("blinkBot",
		[]gobot.Connection{r},
		[]gobot.Device{trigPin, echoPin},
		work,
	)

	robot.Start()

	return nil
}

var IncomingURL string = "incoming-webhookで取得したURL"

// jsonの情報
type Slack struct {
	Text      string `json:"text"`
	Username  string `json:"username"`
	IconEmoji string `json:"icon_emoji"`
	IconURL   string `json:"icon_url"`
	Channel   string `json:"channel"`
}

func slackPostIn(text string) {
	arg := text
	params := Slack{
		Text:      fmt.Sprintf("%s", arg),
		Username:  "Close Push",
		IconEmoji: ":cold_sweat:",
		IconURL:   "",
		Channel:   "",
	}
	jsonparams, _ := json.Marshal(params)
	resp, _ := http.PostForm(
		IncomingURL,
		url.Values{"payload": {string(jsonparams)}},
	)
	body, _ := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()

	println(string(body))
}

func SlackPostOut(text string) {
	arg := text
	params := Slack{
		Text:      fmt.Sprintf("%s", arg),
		Username:  "Open Push",
		IconEmoji: ":relaxed:",
		IconURL:   "",
		Channel:   "",
	}
	jsonparams, _ := json.Marshal(params)
	resp, _ := http.PostForm(
		IncomingURL,
		url.Values{"payload": {string(jsonparams)}},
	)
	body, _ := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()

	println(string(body))
}

```

# 結果

<img width="468" alt="スクリーンショット 2019-12-18 14.57.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308887/4ee1ace7-aa1b-0dd4-ffd5-117553d6244e.png">

...なんか~~鬱陶しい~~メンヘラチックですね。

# さいごに
これ実は弊社の開発合宿で作った成果物でした！下記はその時の内容が書かれているテックブログです。
[【チェックリスト付き】開発合宿 運営マニュアル 〜計画から実施までの流れ〜](https://techblog.zozo.com/entry/devcamp2019summer)

かなり短い時間で開発を行ったのですが、Gobotでの実装がかなり楽ですぐ作ることができました。シビアな実行環境でなければ、組み込みの軽いプロトタイプを作る際におすすめです！

本記事で紹介したソースコードは~~とても汚い~~試作要素が強いので、実行環境によってステータスとかいじって使ってみてください！

トイレにはハードルが高い...という方は普通にGobotの一例として参考にしていただければと思います。