私しか使わない？初心者がキャンプや登山などアウトドアで使えるLineBot「標高クン」を作成してみた。

皆さんこんにちは。

突然ですがキャンプや登山などアウトドア活動はお好きでしょうか？
私はキャンプ、特に秋冬の寒い時期に行うキャンプが大好きです。

とにかく寒い秋冬キャンプで重要なのは、しっかりとした寒さ対策が必要です。
しかし、キャンプ場によっては正確な気温が調べられないこともあり大変です。
そこで私がよく参考にするのが「気温と標高」の関係です。

__標高が100m高くなると約0.6度気温が下がるといわれています。__

キャンプ場の標高を仮に1300ｍだとすると、標高0ｍの場所と比べ7.8度気温差が生まれます。
この関係を参考に私はキャンプ場の気温を予測しますが、正確な標高を調べるのも大変です。

そこで今回は、位置情報を送信するとその場所の標高を返信してくれるLineBot「標高クン」を作成してみました！

##環境
今回実装した時の環境は以下の通りです。

◆実行環境
Node.js 16.10.0
ngrok 2.3.40

◆パッケージ
npm 7.24.0
axios 0.23.0
@line/bot-sdk

◆API（国土交通省 地理院地図）
・https://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php?<パラメータ>

◆コーディング
・Visual Studio Code 1.61.0




##ソースコード

こちらのコードを実行する前にLineBotを作成する必要があります。
作成方法は今回割愛させていただきますが、意外と簡単に作成できますので皆さん調べてみてください。



```.js
'use strict';

// ########################################
//               初期設定など
// ########################################

// パッケージを使用します
const express = require('express');
const line = require('@line/bot-sdk');
const axios = require('axios');
const { text } = require('stream/consumers');

// ローカル（自分のPC）でサーバーを公開するときのポート番号です
const PORT = process.env.PORT || 3000;

// Messaging APIで利用するクレデンシャル（秘匿情報）です。
const config = {
    channelSecret: '<LineBotのチャネルシークレット>',
    channelAccessToken: 'LineBotのチャネルアクセストークン'
};

// ########## ▼▼▼ メイン関数始まり ▼▼▼ ##########
const mainFunction = async (event) => {
  const res = await axios.get("https://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php?lon=" + event.message.longitude + "&lat=" + event.message.latitude + "&outtype=JSON");
  console.log(res.data.elevation);

  return client.replyMessage(event.replyToken, {
    type: 'text',
    text: event.message.address + "の標高は" + res.data.elevation + "mです"
  })

}
// ########## ▲▲▲ メイン関数終わり ▲▲▲ ##########



// ########################################
//  LINEサーバーからのWebhookデータを処理する部分
// ########################################

// LINE SDKを初期化します
const client = new line.Client(config);

// LINEサーバーからWebhookがあると「サーバー部分」から以下の "handleEvent" という関数が呼び出されます
async function handleEvent(event) {
    // 受信したWebhookが「テキストメッセージ以外」であればnullを返すことで無視します
    if (event.message.type !== 'location') {
      return client.replyMessage(event.replyToken, {
        type: 'text',
        text: '位置情報を送信してください'
      })
    }
    
    // メイン関数を実行します
    return mainFunction(event);
}

// ########################################
//          Expressによるサーバー部分
// ########################################

// expressを初期化します
const app = express();

// HTTP POSTによって '/webhook' のパスにアクセスがあったら、POSTされた内容に応じて様々な処理をします
app.post('/webhook', line.middleware(config), (req, res) => {
  
  // 検証ボタンをクリックしたときに飛んできたWebhookを受信したときのみ以下のif文内を実行
  if (req.body.events.length === 0) {
    res.send('Hello LINE BOT! (HTTP POST)'); // LINEサーバーに返答します（なくてもよい）
    console.log('検証イベントを受信しました！'); // ターミナルに表示します
    return; // これより下は実行されません
  } else {
    // 通常のメッセージなど … Webhookの中身を確認用にターミナルに表示します
    console.log('受信しました:', req.body.events);
  }

  // あらかじめ宣言しておいた "handleEvent" 関数にWebhookの中身を渡して処理してもらい、
  // 関数から戻ってきたデータをそのままLINEサーバーに「レスポンス」として返します
  Promise.all(req.body.events.map(handleEvent)).then((result) => res.json(result));
});

// 最初に決めたポート番号でサーバーをPC内だけに公開します
// （環境によってはローカルネットワーク内にも公開されます）
app.listen(PORT);
console.log(`ポート${PORT}番でExpressサーバーを実行中です…`);

```



##実行結果
コード実行しLineBotを稼働させると以下のようになりました。


![結果.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2123201/4b8dc5a1-42b8-5b4a-f38d-0ea10d6e6b05.png)

Lineの機能で位置情報（緯度・経度）を送信することができるため、その情報をもとにAPIを叩き結果を返信してくれます。
この際位置情報以外のコメントを送信すると「位置情報を送信してください」といったメッセージを返します。







また位置情報は今のところスマホアプリ版でしか送信できません。
送信方法は以下画像の赤丸通りです。

![IMG_6320.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2123201/f61ee603-bb61-b515-9c35-51c64337a6b5.png)

![IMG_6321.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2123201/a0eeb40f-b9e3-1f1f-6ff0-c3800ab42cbf.png)

##まとめ
今回、経度・緯度の情報を渡し標高を結果として取得するAPIを使用し、結果を返してくれるLineBot「標高クン」を作成してみました。
個人的に位置情報を送るとすぐに標高を返してくれる「標高クン」は大満足なのですが、残念ながら需要はない気がしています。。
もし__私も標高が知りたい！__という方がいらっしゃいましたら是非参考にしてみてください。

また、今回採用した国土交通省のAPIを見つける前はyahooさんが提供している「標高API」を採用して構築していました。ただ返ってくる標高の結果が若干曖昧なデータだったため、よりよいAPIを求め今の国土交通省のAPIを見つけることができました。（こちらはだいぶ正確な値を取得してくれます）同じような結果を取得できるAPIはたくさんあると思いますが、目的に沿ってAPIの取捨選択しよりよいシステムの構築を心がけたいと思います。



##参考
【国土交通省 地理院地図】
https://maps.gsi.go.jp/development/elevation_s.html