耳年齢を判定するLINE Bot×Iotの作成

##概要
前回こちらの記事で老眼とモスキート音による加齢性難聴をチェックするLINE Bot×Iotを作成しました。
[老眼と加齢性難聴のチェックができるLINE Bot×Iotの作成](https://qiita.com/doikatsuyuki/items/fb14483b69a3d3202bed)

こちらを使ってみると老眼チェックの機能と組み合わせたため、加齢性難聴のチェックがしにくいことが分かりました。今回は、加齢性難聴のチェックのみに機能を絞ったBotをobnizと組み合わせて作成しました。
##実装
LINE BOtとobnizの連携。スピーカーから発せられる音を聞きながら、LINE上で質問に答えていくと自分の耳年齢が分かるBOT。
##概念図
node.js expressでLINE bot APIとobnizを連携しました。
![rougann.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/c6992a6f-b0c9-466c-9301-ca0b66cd5bb1.jpeg)
##作成方法
**1.obnizの準備**
obnizをPCと接続します。 
[obniz公式サイト](https://obniz.io/ja/) 
[Node.jsのダウンロード](https://nodejs.org/ja/download/) 

obnizを使えるようにWifiに接続し、画面上にQRコードと8桁の数字が表れるようにします。

スピーカーを準備し、obnizのio0とio1にさします。 
![IMG-0707.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/caea2c80-f52c-8a8e-0268-da7fab2a7210.jpeg)
今回は、圧電スピーカー（圧電サウンダ）（１３ｍｍ）ＰＫＭ１３ＥＰＹＨ４０００－Ａ０を使用しました。


[obniz speaker参照](https://obniz.io/ja/sdk/parts/Speaker/README.md)


**2. Botアカウントを作成する**

**3. Node.jsでBot開発**

**4. ngrokでトンネリング**

上記の2～4を以下の参考記事の通りに行います。
[1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 ](https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d)

**5.obnizとの連携**

コードを以下のように書き換えます。
今回は、LINE Developersの確認テンプレートメッセージを使いました。
[LINE Developers](https://developers.line.biz/ja/reference/messaging-api/?fbclid=IwAR2DtZhpwt5RTYMnWfpnCOkhsXWbBBt5Dw3qTIOazY-rjb1sowRzcTkQyW8#confirm
)

```js
'use strict';

const express = require('express');
const line = require('@line/bot-sdk');
const PORT = process.env.PORT || 3000;

const config = {
    channelSecret: 'channelSecretを入力',
    channelAccessToken: 'channelAccessTokenを入力'
};

// Obnizの準備
var Obniz = require("obniz");
var obniz = new Obniz("Obniz ID を入力");  // Obniz ID を入力
var speaker; // 全体で使えるようにするスコープ
obniz.onconnect = async function () {
    speaker = obniz.wired("Speaker", {signal:0, gnd:1});
}

const app = express();

app.get('/', (req, res) => res.send('Hello LINE BOT!(GET)')); //ブラウザ確認用(無くても問題ない)
app.post('/webhook', line.middleware(config), (req, res) => {
  console.log(req.body.events);
  
  //ここのif分はdeveloper consoleの"接続確認"用なので削除して問題ないです。
  if(req.body.events[0].replyToken === '00000000000000000000000000000000' && req.body.events[1].replyToken === 'ffffffffffffffffffffffffffffffff'){
    res.send('Hello LINE BOT!(POST)');
    console.log('疎通確認用');
    return; 
  }
  
  Promise
      .all(req.body.events.map(handleEvent))
      .then((result) => res.json(result));
});

    
const client = new line.Client(config);

function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  // LINE botのプログラム
  let ans = "";
  let question = event.message.text;
  
  let hz;//モスキート音のhz

  let yes = "";
  let  no = "";
  if (question == "開始") {
    hz = 8000;
    ans = "今流れているモスキート音は8000Hzです。聞こえますか？";
    yes = "8000Hzはい";
    no = "8000Hzいいえ";
  } else if (question == "8000Hzはい") {
    hz = 10000;
    ans = "今流れているモスキート音は10000Hzです。聞こえますか？";
    yes = "10000Hzはい";
    no = "10000Hzいいえ";
  } else if (question == "10000Hzはい") {
    hz = 12000;
    ans = "今流れているモスキート音は12000Hzです。聞こえますか？";
    yes = "12000Hzはい";
    no = "12000Hzいいえ";
  } else if (question == "12000Hzはい") {
    hz = 14000;
    ans = "今流れているモスキート音は14000Hzです。聞こえますか？";
    yes = "14000Hzはい";
    no = "14000Hzいいえ";
  } else if (question == "14000Hzはい") {
    hz = 15000;
    ans = "今流れているモスキート音は15000Hzです。聞こえますか？";
    yes = "15000Hzはい";
    no = "15000Hzいいえ";
  } else if (question == "15000Hzはい") {
    hz = 16000;
    ans = "今流れているモスキート音は16000Hzです。聞こえますか？";
    yes = "16000Hzはい";
    no = "16000Hzいいえ";
  } else if (question == "16000Hzはい") {
    hz = 0;
    ans = "加齢性難聴の疑いはありません。高音域の聴力は20歳未満相当と思われます。";
  } else if (question == "8000Hzいいえ") {
    hz = 0;
    ans = "加齢性難聴の疑いがあります。高音域の聴力は70歳以上相当と思われます。";
  } else if (question == "10000Hzいいえ") {
    hz = 0;
    ans="加齢性難聴の疑いがあります。高音域の聴力は60～69歳相当と思われます。";
  } else if (question == "12000Hzいいえ") {
    hz = 0;
    ans = "加齢性難聴の疑いがあります。高音域の聴力は50～59歳相当と思われます。";
  } else if (question == "14000Hzいいえ") {
    hz = 0;
    ans = "加齢性難聴の疑いがあります。高音域の聴力は40～49歳相当と思われます。";
  } else if (question == "15000Hzいいえ") {
    hz = 0;
    ans = "加齢性難聴の疑いがあります。高音域の聴力は30～39歳相当と思われます。";
  } else if (question == "16000Hzいいえ") {
    hz = 0;
    ans = "加齢性難聴の疑いがあります。高音域の聴力は20～29歳相当と思われます。";
  }

  speaker.play(hz);


  if (yes == "") {
　　//通常のメッセージ
    return client.replyMessage(event.replyToken, {
      type: 'text',
      text: ans
    }); 
  } else {
　　//確認テンプレートメッセージ
    return client.replyMessage(event.replyToken, {
      "type": "template",
      "altText": "this is a confirm template",
      "template": {
          "type": "confirm",
          "text": ans,
          "actions": [
              {
                "type": "message",
                "label": "はい",
                "text": yes
              },
              {
                "type": "message",
                "label": "いいえ",
                "text": no
              }
          ]
      }
    });
  }
 
}

app.listen(PORT);
console.log(`Server running at ${PORT}`);
```

##動作確認
ちゃんと動いています。
<img width="375" alt="unnamed1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/e1a05bbd-df0e-a516-9783-367baa3b71a7.png">
<img width="375" alt="unnamed.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/5398e1c5-ed07-e887-4ddc-84452a7ae146.png">

動画です。スピーカーから音も出ています。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">耳年齢bot <a href="https://t.co/dPnnfn75HQ">pic.twitter.com/dPnnfn75HQ</a></p>&mdash; 病気のセルフチェック (@Selfcheckhealt1) <a href="https://twitter.com/Selfcheckhealt1/status/1186623007390781440?ref_src=twsrc%5Etfw">October 22, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

##考察
高音性難聴判定に機能を絞ったことで使いやすいBotになりました。
最初以下のようなフローチャートのように質問に答えていくコードを書いたのですがうまく動きませんでした。

```js
'use strict';

const express = require('express');
const line = require('@line/bot-sdk');
const PORT = process.env.PORT || 3000;

const config = {
    channelSecret: 'channelSecretを入力',
    channelAccessToken: 'channelAccessTokenを入力'
};

// Obnizの準備
var Obniz = require("obniz");
var obniz = new Obniz(" Obniz ID を入力");  // Obniz ID を入力
var speaker; // 全体で使えるようにするスコープ
obniz.onconnect = async function () {
    speaker = obniz.wired("Speaker", {signal:0, gnd:1});
}

const app = express();

app.get('/', (req, res) => res.send('Hello LINE BOT!(GET)')); //ブラウザ確認用(無くても問題ない)
app.post('/webhook', line.middleware(config), (req, res) => {
  console.log(req.body.events);
  
  //ここのif分はdeveloper consoleの"接続確認"用なので削除して問題ないです。
  if(req.body.events[0].replyToken === '00000000000000000000000000000000' && req.body.events[1].replyToken === 'ffffffffffffffffffffffffffffffff'){
    res.send('Hello LINE BOT!(POST)');
    console.log('疎通確認用');
    return; 
  }
  
  Promise
      .all(req.body.events.map(handleEvent))
      .then((result) => res.json(result));
});

    
const client = new line.Client(config);

function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  // LINE botのプログラム
  let ans = "";
  let question = event.message.text;
  
  let hz;//モスキート音のhz

  if (question=="開始") {
    ans = "今流れているモスキート音は8000Hzです。聞こえますか？　「はい」か「いいえ」を入力してください。";
    hz = 8000;
    if (question == "はい") {
      ans = "今流れているモスキート音は10000Hzです。聞こえますか？　「はい」か「いいえ」を入力してください。";
      hz = 10000;    
      if (question == "はい") {
        ans = "今流れているモスキート音は12000Hzです。聞こえますか？　「はい」か「いいえ」を入力してください。";
        hz = 12000;
        if (question == "はい") {
          ans = "今流れているモスキート音は14000Hzです。聞こえますか？　「はい」か「いいえ」を入力してください。";
          hz = 14000;
          if (question == "はい") {
            ans = "今流れているモスキート音は15000Hzです。聞こえますか？　「はい」か「いいえ」を入力してください。";
            hz = 16000;
            if (question == "はい") {
              ans = "今流れているモスキート音は16000Hzです。聞こえますか？　「はい」か「いいえ」を入力してください。";
              hz = 18000;
              if (question == "はい") {
                ans = "加齢性難聴の疑いはありません。高音域の聴力は20歳未満相当と思われます。";
                hz = 0;
              }else{
                ans = "加齢性難聴の疑いがあります。高音域の聴力は20～29歳相当と思われます。";
                 hz = 0;
               }
            }else{
              ans = "加齢性難聴の疑いがあります。高音域の聴力は30～39歳相当と思われます。";
               hz = 0;
             }
          }else{
            ans = "加齢性難聴の疑いがあります。高音域の聴力は40～49歳相当と思われます。";
             hz = 0;
           }
        }else{
          ans = "加齢性難聴の疑いがあります。高音域の聴力は50～59歳相当と思われます。";
           hz = 0;
         }
      }else{
        ans = "加齢性難聴の疑いがあります。高音域の聴力は60～69歳相当と思われます。";
         hz = 0;
       }
  } else {
      ans = "加齢性難聴の疑いがあります。高音域の聴力は70歳以上相当と思われます。";
       hz = 0;
     }
  } else {
    ans = "「開始」を入力してください。";
    hz = 0;
  }
 
  console.log(ans);
  speaker.play(hz);


  return client.replyMessage(event.replyToken, {
    type: 'text',
    text: ans
  });

}

app.listen(PORT);
console.log(`Server running at ${PORT}`);

```

LINE BotのQ&Aは1対1で対応しないとうまく動かないようなので、確認テンプレートメッセージを使って書き換えるとうまくいきました。
LINEで音声ファイルを送ることもできるようなので、そちらを使ってデバイスを使わない方法も試したいと思います。