AWS IoT ボタンと Amazon Connect でトイレが詰まったら管理事務所に自動で電話する


# 我が社のトイレは詰まりやすい

---

## どんなオフィスなのか
会社の占有エリアに関しては綺麗
![office01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142668/13bc06e1-44f2-1cc9-ba49-3259a2135647.jpeg)

しかしながら建物がとても年季入った味のあるビル
![bldg01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142668/d9b4b537-e39a-d6f2-65d5-fb5988216dca.jpeg)
![bldg02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142668/dfc22f2e-eb57-8db7-a136-8c9993dbf526.jpeg)

共有設備のトイレも古いので詰まりやすいんだと思います。

---

## 詰まらせたら赤っ恥
![sl01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142668/257e400c-00ae-b493-3290-923019aefe0e.png)
![sl02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142668/755b710d-9033-5e29-a375-c4c47f67b67c.png)
![sl03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142668/16f9d23d-40b1-25ea-6928-b497a742a035.png)


---

##### 毎日お腹壊す僕としては、いつ自分の番が来るかと気が気でない


---

## 現状詰まった時の対応フロー
1. ヘルプデスクに伝える
2. ビル管理に電話する

つまり、ビル管理の電話番号を控えておけば、自分で電話することで大衆に晒すことなく事態を収拾できる
が、ここは無駄にエンジニアリングする

---

# 匿名で連絡する仕組み

---

## アーキテクチャ
![clogged toilet architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142668/eef6dcb8-fa29-241c-9c42-2b11fe8aadd6.png)


---

## [AWS IoT 1-Click](https://aws.amazon.com/jp/iot-1-click/)
対応機器のボタンをトリガーに Lambda などに連携できるサービス
$0.25/device

---

## [AWS IoT ボタン](https://www.amazon.co.jp/dp/B075FPHHGG)
AWS IoT 1-Click 対応機器
WiFiにつなげて使う
¥2,500/個
![button.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142668/93f007bd-46cb-b777-867d-b7429e74fd6b.jpeg)

---

## [Amazon Connect](https://aws.amazon.com/jp/connect/)
クラウドコールセンター
このAPIでビル管理に電話をかける
電話番号: $0.10/日
発信(日本): $0.1000/分

---

## [AWS Lambda](https://aws.amazon.com/jp/lambda/)
サーバーレスのコンピューティングサービス
これで Amazon Connect の API を叩く
[料金](https://aws.amazon.com/jp/lambda/pricing/)

---

# 構築

---

## Step1. Amazon Connect の contact flow を作成する

- 最低限ボイスと文言設定して電話切ればOK！
![connect01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142668/7ce3da85-4036-1b81-f3fd-de634126b03f.png)
- 左側に表示されているARN の instance id と contact flow id をあとの実装で使用します

---

## Step2. AWS IoT 1-Click にデバイス登録する

- スマホに AWS IoT 1-Click アプリをインストールして、デバイスを登録
- デバイスを有効にする
- WiFiを設定する

---

## Step3. Lambda Function を実装する

```ts:main.ts
import Connect from "aws-sdk/clients/connect";

const connect = new Connect({ region: "ap-northeast-1" });

export const handler = async () => {
  const result = await connect
    .startOutboundVoiceContact({
      InstanceId: process.env.INSTANCE_ID as string,
      ContactFlowId: process.env.CONTACT_FLOW_ID as string,
      SourcePhoneNumber: process.env.SOURCE_PHONE_NUMBER as string,
      DestinationPhoneNumber: process.env.DESTINATION_PHONE_NUMBER as string
    })
    .promise();

  return result;
};
```

```rb:lambda.tf
# Configure the AWS Provider
provider "aws" {
  version = "~> 2.0"
  region  = "ap-northeast-1"
}

# Create a IAM role for Lambda
resource "aws_iam_role" "lambda" {
  name               = "CloggedToiletReporterLambdaRole"
  assume_role_policy = data.aws_iam_policy_document.assume_role_lambda.json
}

data "aws_iam_policy_document" "assume_role_lambda" {
  statement {
    effect  = "Allow"
    actions = ["sts:AssumeRole"]

    principals {
      type        = "Service"
      identifiers = ["lambda.amazonaws.com"]
    }
  }
}

resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
  role       = aws_iam_role.lambda.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

resource "aws_iam_role_policy_attachment" "amazon_connect" {
  role       = aws_iam_role.lambda.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonConnectFullAccess"
}

// Create a Lambda function
data "archive_file" "function" {
  type        = "zip"
  source_dir  = "./dist"
  output_path = "code.zip"
}

resource "aws_lambda_function" "clogged_toilet_reporter" {
  filename         = data.archive_file.function.output_path
  source_code_hash = data.archive_file.function.output_base64sha256
  function_name    = "CloggedToiletReporter"
  handler          = "main.handler"
  role             = aws_iam_role.lambda.arn
  runtime          = "nodejs10.x"
  timeout          = 60
  environment {
    variables = {
      INSTANCE_ID              = var.INSTANCE_ID
      CONTACT_FLOW_ID          = var.CONTACT_FLOW_ID
      SOURCE_PHONE_NUMBER      = var.SOURCE_PHONE_NUMBER
      DESTINATION_PHONE_NUMBER = var.DESTINATION_PHONE_NUMBER
    }
  }
}

variable "INSTANCE_ID" {}
variable "CONTACT_FLOW_ID" {}
variable "SOURCE_PHONE_NUMBER" {}
variable "DESTINATION_PHONE_NUMBER" {}
```

---

# Step4. AWS IoT 1-Click プロジェクトを作成する
- AWS コンソールで AWS IoT 1-Click サービスを開き、プロジェクトを作成
- 上記 Lambda function を紐づけるデバイステンプレートを作成
- デバイステンプレートに上記ボタンを紐づけるプレイスメントを作成

---

# 疎通確認
隣の席の人にかけるように設定しました
![test01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142668/361d5f84-2b63-4399-f0b5-29c7d9e923e6.jpeg)
ボタンを押します
![test02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142668/c8c1ad02-2850-9aad-d2ed-5162dd12cb15.jpeg)
電話きました
![test03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142668/f7e94f8d-ea8c-62bb-b2ff-36f0442a7c63.jpeg)
「３階男子トイレ手前側です。うんちが詰まりました。ご対応よろしくお願いいたします。」
![test04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142668/6fb74c04-7cbe-b97a-5a48-e63c58e40967.jpeg)

うまくできましたので、あとは通話先をビル管理に変更して、ボタンをトイレに置いて完了です

---

# まとめ
- ボタンは 2.4GHz しか繋げない
- ボタンの電池は交換できなくて、寿命は約2000回。
- でも詰まるのは月1ペースなので約166年間使える。
- ソース: https://github.com/boiyaa/clogged-toilet-reporter

---

# 参考リンク
- [[Amazon Connect] 自動発信(Automated Outbound Calling)を利用したサンプル（その１）〜キャンペーンの案内を送って興味あるお客様をリストアップする〜](https://dev.classmethod.jp/cloud/aws/amazon-connect-outbound-sample/)
- [簡単にコールセンター！IoT Buttonをポチるとamazon connectから自動アウトバウンドコールがやってくる！](https://deferloader.blog.uhuru.co.jp/6648/)