LoginSignup
1
3

More than 3 years have passed since last update.

AWS(Lambda, API Gateway)でLINEの天気予報botを作ってみる

Last updated at Posted at 2020-12-17

完成物

郵便番号or地名を入れると、そのエリアの天気予報が返ってくるLINE bot
天気予報bot.gif

今回使うもの

  • LINE Messaging API
  • Amazon API Gateway
  • AWS Lambda(言語:node.js)
  • OpenWeatherMap API

LINE botの作成

まずはLINE botを準備しましょう。

このページの「LINEアカウントでログイン」から、自分のLINEアカウントのアドレス、パスワードでログインします。

②プロバイダーを好きな名前で作成します。

③チャネル選択画面が出てくるので、「Messaging API」を選択します。

④必須項目を入力し「作成」を押します。
 チャネル名はLINE botの名前になります(この場合は「天気予報bot」)

⑤チャネル一覧が出てくるので、作成したチャネルを選択します。
 「Messaging API設定」タブ→画面下部のチャネルアクセストークンをコピーしておいてください。

この後の設定で必要になるので、この画面は開いたままにしておきましょう。

OpenWeatherMap APIの準備

このページからアカウントを作成します。
このページにアクセスし、API Keyをコピーしておいてください。

AWS Lambdaの作成

次はいよいよLambda関数の作成です。

このページから、node.jsの新しいLambda関数を作成します。

②ローカルで、以下の通りにモジュールをインストールします。

$ npm install @line/bot-sdk

③上記で作成されたnode_modulesフォルダと同じ階層にindex.jsを作成し、以下のコードを貼り付けて保存します。

index.js
const line = require('@line/bot-sdk');
const https = require('https');

let event;
const research_mode = 0; //0:郵便番号検索、1:地名検索

exports.handler = (_event, _context) => {
    let url;
    event = _event;

    let userMessage = JSON.parse(event.body).events[0].message.text;

    if (typeof userMessage === "string") {

        if (research_mode === 0) {
            if (userMessage.length !== 8) {
                //ハイフンが入力されなかった場合はハイフンを入れる
                let _userMessage = userMessage.slice(0, 3) + "-" + userMessage.slice(3, 8); 
                userMessage = _userMessage;
            }
            url = 'https://api.openweathermap.org/data/2.5/forecast?&units=metric&zip=' + userMessage + ',jp&APPID=' + process.env.API_KEY;
        } else {
            url = 'https://api.openweathermap.org/data/2.5/forecast?&units=metric&q=' + userMessage + ',jp&APPID=' + process.env.API_KEY;
        }

        main(url);
    }
};

function main(url) {

    let result;

    https.get(url, (res) => {
        res.on('data', (chunk) => {
            result = JSON.parse(chunk);
        })
       .on('end', (res) => {
            let message;   

            if (result.cod === "200") {
                let contents = []; //6つの天気情報を格納する配列

                let header = {
                    "type": "text",
                    "text": result.list[3].dt_txt.slice(0, 10), //日付
                    "size": "md",
                    "color": "#555555",
                    "flex": 0
                }
                contents.push(header);

                for (let i = 3; i < 10; i++) {
                    let _contents = {};
                    _contents = {
                            "type": "box",
                            "layout": "baseline",
                            "contents": [
                                {
                                    "type": "text",
                                    "text": result.list[i].dt_txt.slice(11, 16), //時刻
                                    "size": "sm",
                                    "color": "#555555",
                                    "flex": 0
                                },
                                {
                                    "type": "text",
                                    "text": return_japanese_weather(result.list[i].weather[0].main), //天気
                                    "size": "sm",
                                    "color": "#111111",
                                    "align": "end"
                                },
                                {
                                    "type": "icon",
                                    "url": "https://openweathermap.org/img/w/" + result.list[i].weather[0].icon + ".png", //アイコン画像
                                    "size": "xl"
                                },
                                {
                                    "type": "text",
                                    "text":  String(Math.round(result.list[i].main.temp)) + '',  //気温
                                    "size": "sm",
                                    "color": "#111111",
                                    "align": "end"
                                }
                            ]
                        }
                    contents.push(_contents);
                }

                message = {
                    "type": "flex",
                    "altText": result.city.name + 'の天気予報',
                    "contents": {
                        "type": "bubble",
                        "styles": {
                            "footer": {
                                "separator": true
                            }
                        },
                        "body": {
                            "type": "box",
                            "layout": "vertical",
                            "contents": [
                                {
                                    "type": "text",
                                    "text": "天気予報",
                                    "weight": "bold",
                                    "size": "xxl",
                                    "margin": "md"
                                },
                                {
                                    "type": "text",
                                    "text": result.city.name, //地名
                                    "size": "md",
                                    "color": "#DC143C",
                                    "wrap": true
                                },  
                                {
                                    "type": "separator",
                                    "margin": "xxl"
                                },
                                {
                                    "type": "box",
                                    "layout": "vertical",
                                    "margin": "xxl",
                                    "spacing": "sm",
                                    "contents": contents
                                }
                            ]
                        }
                    }
                };
            } else {  //該当する天気情報を取得できなかった場合
                message = {
                    type: "text",
                    text: research_mode === 0 ? "該当する郵便番号の天気予報を取得できませんでした。" : "該当する地名の天気予報を取得できませんでした。"
                };
            }
            //メッセージ返信
            const client = new line.Client({
               channelAccessToken: process.env.ACCESSTOKEN
            });
            client.replyMessage(JSON.parse(event.body).events[0].replyToken, message)
            .catch((err) => { console.log(err) });
        });
    });
};

function return_japanese_weather(weather_eng) {
    let weather_jpn = {
        "Thunderstorm" : "雷雨",
        "Drizzle" : "霧雨",
        "Rain" : "",
        "Snow" : "",
        "Clear" : "晴れ",
        "Clouds" : "曇り",
        "Mist" : "",
        "Fog" : "濃霧",
        "Haze" : "",
        "Dust" : "砂塵",
        "Sand" : "砂嵐",
        "Squall" : "スコール",
        "Tornado" : "竜巻"
    }

    return weather_jpn[weather_eng] === "" ? weather_eng : weather_jpn[weather_eng]; //該当するものがない場合はそのまま返す
}

④index.jsとnode_modulesフォルダをzipファイルに圧縮します。
 index.zip
  ┗node_modules
  ┗index.js
この構造になるよう注意

⑤Lambdaの関数コードの「アクション」→「.zipファイルをアップロード」から、上記のzipファイルをアップロードします。

⑥環境変数を設定します。

  • ACCESSTOKEN:LINE botで取得したチャネルアクセストークン
  • API_KEY:OpenWeatherMap APIで取得したAPI Key env_variable.png

※コードを修正した場合は、必ず最後に「デプロイ」を押しましょう

Amazon API Gatewayの作成

最後はAPI Gatewayの作成です。

このページから新しいAPIを作成します。(APIタイプ:REST API)

②作成後に表示されるリソースの画面で、「アクション」→「メソッドの作成」から”/”リソースに「POST」メソッドを作成します。

③以下を設定し保存します。

  • 統合タイプ:Lambda関数
  • Lambda プロキシ統合の使用:チェック
  • Lambda リージョン:ap-northeast-1
  • Lambda関数:先ほど作ったLambda関数名

④Lambda 関数に権限を追加する → OKをクリック

⑤「アクション」→「APIのデプロイ」からAPIをデプロイします。ステージ名は何でもいいです。

⑥画面上部に表示されるURLをLINE botに登録します。
 先程開いたままの画面に戻り、「Webhook URL」に貼り付けます。

webhook.png

これで完成です:relaxed:

まとめ

今回は郵便番号検索にしていますが、コードのresearch_modeを1に変えれば地名検索に切り替わります。
また、天気予報情報は今回3時間おきの情報ですが、現在の天気など様々種類がありますのでこちらで見てみてください。

返ってくるFlexMessageも、ここを参考に文字の大きさなど色々変えることができます。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3