めまいと気圧の関係性を調査するLINE Botの作成

##概要
プログラムの勉強を始めて4か月ほどの開業医です。

秋は天気がころころ変わるため体調を崩す人が多くなると言われています。他にも台風などで気圧が下がると頭痛がしたり、天気が悪いと古傷が痛んだりするように気象の変化によって症状が出現したり悪化することは以前から指摘されていましたが、最近このような状態が**気象病**と呼ばれるようになりました。

すでに天気予測と頭痛予防など気象病に関するアプリはありますが、そもそも気象と病気（今回の場合は気圧低下とめまい）は本当に関連あるかどうかという調査研究報告が内耳が専門の耳鼻咽喉科の学会でもほとんどありません。

たしかに、気圧が低下するとめまい（特にメニエール病）の患者さんが多く受診されるので関係性はありそうです。今回、気圧とめまいの関係性を調査できるように、めまい発症時に気圧が低下していたのかどうかがわかるLINE Botを作成しました。

##実装
LINE上で質問に答えていくとめまいの状態が記録され、めまい発生時の気圧とめまい発生3時間前の気圧を比較し、めまい発生時に気圧が低下していたのかどうかがわかるLINE Bot。
##動画
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">めまいと気圧調査bot-2 <a href="https://t.co/bZ0vqx2tvz">pic.twitter.com/bZ0vqx2tvz</a></p>&mdash; 病気のセルフチェック (@Selfcheckhealt1) <a href="https://twitter.com/Selfcheckhealt1/status/1191927806369947650?ref_src=twsrc%5Etfw">November 6, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

##概念図
node.js expressでOpenWeatherAPIから気象情報を取得し、LINE bot APIと連携しました。

<img width="568" alt="openweather.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/ffa1269d-0b19-482f-b247-5db7070bc2b3.png">


##作成方法
**1. Botアカウントを作成する**

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

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

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

**4. OpenWeatherMap API（気象情報の取得）**
無料で気象情報を取得できるAPIです。
気圧の実測値を取得できるAPIが見つからなかったため、今回はOpenWeatherMapで取得できる3時間毎の気象予報情報を利用しました。
[OpenWeatherMap](https://openweathermap.org/)
マイページの「API keys」から自分のAPIキーをメモしてください。


**5. プログラム作成**

コードを以下のように書き換えます。
今回も、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 axios = require('axios');
const PORT = process.env.PORT || 3000;

const config = {
    channelSecret: '自分のchannelSecretを入力してください',
    channelAccessToken: '自分のchannelAccessTokenを入力してください'
};

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);

async function getPressuer() {
 
    const BASE_URL = "http://api.openweathermap.org/data/2.5/forecast"
    const API_KEY = "自分のOpenWeatherMapのAPIキーを入力してください";  // APIキーの指定
    let Postal_code = "調べたい場所の郵便番号を記入してください";//クリニックの郵便番号
  
    // APIのURL（5日/ 3時間毎の予測データ）
     var url = BASE_URL+"?zip="+Postal_code+",jp&APPID=" + API_KEY+ "&units=metric" ;
  
    let res = await axios.get(url);
     item = res.data.list;
　　//気象データが取得できているか確認用
    console.log(item[0].dt_txt);
    console.log(item[0].main.pressure);
    console.log(item[1].dt_txt);
    console.log(item[1].main.pressure);
    console.log(item[2].dt_txt);
    console.log(item[2].main.pressure);
    console.log(item[3].dt_txt);
    console.log(item[3].main.pressure);
    return item;
  
}

let prepre;//めまい発生3時間前の気圧
let item;
let pressure;
let result;


async function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }
 
  
  // LINE botのプログラム 
  let message = event.message.text;
  let question = "";
  let label1, label2, label3 = "";
  let text1, text2, text3 = "";

    
  if (message == "めまい") {
    question = "どんなめまいですか？";
    label1 = "くるくる回る";
    text1 = "回転性"
    message = text1;
    label2 = "ふらふら揺れる";
    text2 = "動揺性";
    message = text2;
    label3 = "その他";
    text3 = "その他";
    message = text3;
  } else if (message == "回転性" || message == "動揺性" || message == "その他") {
    question = "めまいはどのくらいの時間続きましたか？";
    label1 = "1分以内を何度も繰り返す";
    text1 = "1分以内";
    message = text1;
    label2 = "10分未満";
    text2 = "10分未満";
    message = text2;
    label3 = "10分以上";
    text3 = "10分以上";
    message = text3;
  } else if (message == "1分以内" || message == "10分未満" || message == "10分以上") {
    question = "耳鳴りや聞こえにくさはありますか？";
    label1 = "はい";
    text1 = "耳鳴り、難聴あり";
    message = text1;
    label2 = "いいえ";
    text2 = "耳鳴り、難聴なし";
    message = text2;
    label3 = "以前からある";
    text3 = "耳鳴り、難聴以前から";
    message = text3;
  } else if (message == "耳鳴り、難聴あり" || message == "耳鳴り、難聴なし" || message == "耳鳴り、難聴以前から") {
    question = "頭痛はありますか？";
    label1 = "はい"
    text1 = "頭痛あり";
    message = text1;
    label2 = "いいえ";
    text2 = "頭痛なし";
    message = text2;
    label3 = "選択できません";
    text3 = "めまい";
    message = text3;
    console.log("頭痛");
  } else if (message == "頭痛あり" || message == "頭痛なし") { 
    item = await getPressuer();
    question = "めまいはいつ起こりましたか？";
    label1 = "6時間ほど前"
    text1 = "めまい発症時の気圧:"+String(item[1].main.pressure)+"\nめまい発症3時間前の気圧:"+String(item[0].main.pressure);
    message = text1;
    label2 = "3時間ほど前";
    text2 = "めまい発症時の気圧:"+String(item[2].main.pressure)+"\nめまい発症3時間前の気圧:"+String(item[1].main.pressure);
    message = text2;
    label3 = "今現在";
    text3 = "めまい発症時の気圧:"+String(item[3].main.pressure)+"\nめまい発症3時間前の気圧:"+String(item[2].main.pressure);
    message = text3;
    
    
  } else if (message =="めまい発症時の気圧:"+String(item[1].main.pressure)+"\nめまい発症3時間前の気圧:"+String(item[0].main.pressure)) {
     prepre = item[0].main.pressure
     if (prepre > item[1].main.pressure) {
      result = "めまいは気圧低下時に起こっています。"
   } else {
      result = "めまいは気圧低下時に起こっていません。"
   }          
  } else if (message ==  "めまい発症時の気圧:"+String(item[2].main.pressure)+"\nめまい発症3時間前の気圧:"+String(item[1].main.pressure)) {
     prepre = item[1].main.pressure
    if (prepre> item[2].main.pressure) {
      result = "めまいは気圧低下時に起こっています。"
    } else {
      result = "めまいは気圧低下時に起こっていません。"
    }
  } else if (message == "めまい発症時の気圧:"+String(item[3].main.pressure)+"\nめまい発症3時間前の気圧:"+String(item[2].main.pressure)) {
      prepre = item[2].main.pressure
      if (prepre >item[3].main.pressure) {
        result = "めまいは気圧低下時に起こっています。"
     } else {
        result = "めまいは気圧低下時に起こっていません。"
     }          
  }
    
  if (result == 'めまいは気圧低下時に起こっています。' || result == 'めまいは気圧低下時に起こっていません。') {
    client.replyMessage(event.replyToken, { 
      type: 'text',
      text: result,
    });
    result = ''; // resultを初期化
    return;
  } else {
    return client.replyMessage(event.replyToken, {
          "type": "text",
          "text": question,
          "quickReply": {
            "items": [
              {
                "type": "action",
                "action": {
                  "type": "message",
                  "label": label1,
                  "text": text1
                }
              },
              {
                "type": "action",
                "action": {
                  "type": "message",
                  "label": label2,
                  "text": text2
                }
              },
              {
                "type": "action",
                "action": {
                  "type": "message",
                  "label": label3,
                  "text": text3
                }
              }
            ]
          }
        });
      }

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

##動作確認
ちゃんと動いています。
クイックリプライボタンで表示されます。

![めまい１.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/b2a63bdf-c86b-1fe8-39cd-022c911fc57d.png)

![めまい２.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/a45e8273-fe36-2475-ed2f-1fa558934783.png)

![めまい３.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/ac7ea72f-aed5-cd60-e024-becaf02b8f9d.png)
![めまい４.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/9318d0ff-984b-f5dd-0324-54ffc8add07a.png)
![めまい５.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/aa8e5ae7-7bb1-91ef-99f1-c6e3628ad1fd.png)
めまい発生時の予想気圧とめまい発生3時間前の予想気圧を比較して判定しています。
![last.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/f38f9304-2b9b-6df4-c2a9-9cdb4b2a8013.jpeg)


##考察
OpenWeatherMap APIによる気象情報の取得は調べたい場所の郵便番号で出来ます。今回はクリニックの郵便番号を使い気象情報を取得していますが、利用者がめまいが発生した場所の郵便番号を入力することでその場所での気圧が分かるように改良していきたいと思います。

また、取得した予想気圧と実測気圧との違いがあるかどうかが気になるので、気圧センサーを作って気圧を計測しAPIで取得した値と比較してみたいと思います。精度がよければめまいの患者さんに実際に使って頂いて、本当にめまいと気圧が関連性があるか調査を行いたいと思っています。その調査で気圧とめまいの関連について何か有効なデータが取れればいいなと思います。