6
0

More than 1 year has passed since last update.

Line Botへ現在の天気を表示 ~天気APIを使用しLINE BOTへ自動返信~

Last updated at Posted at 2021-10-28

LINE Botの勉強を始め、おうむ返し は作れました。更に応用することを考えたときにAPIとの連携ができることを知り、作ってみました。

下準備
 ① まずはこちらの記事を参考にLine Botを作る。
    おうむ返しまで完了させる。
     https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d
 ② obnizを扱うので、Visual Studio Codeのターミナルに、npm install obniz
   (今後マトリックスLEDを扱うならば npm install canvas も)を入力し
    実行しておく。
 ③ obnizスターターキットの用意
    obnizの端子にパーツを接続
      LED信号:gnd:0, green:1, yellow:2, red:3
 ④ OpenWeatherMapのAPIキーを取得(以下のHPを参照)
     https://yuukiyg.hatenablog.jp/entry/2019/11/17/182410

実行
  Visual Studio Codeに、以下のコードを入力し、各サーバーを立ち上げ、
  LINE Developersの設定を行う。

 ①ターミナルに、
  cd mylinebot  を実行(mylinbotフォルダ内に入る)。
  node server.js を実行。

 ②もう一つターミナルを開いて、
  npx ngrok http 3000(npm ngrok http 3000 の方もいる)を実行。

 ③npx ngrok http 3000(又はnpm ngrok http 3000)サーバーに表示された
  URL(HTTPSの方)をコピーして、LINE DEpelopersのHPの、Messaging APIタグの、
  Webhook設定のWebhook URLに張り付け、後ろに「/webhook」をつける。

//【”天気”と入れると、今の天気・雲の様子・気温を返し、obinzの天気に対応するLED信号を点灯させる。】
'use strict';

const Obniz = require("obniz");
var obniz = new Obniz("xxxx-xxxx"); //obninzのIDを入力
obniz.onconnect = async function () { 
          //event(この場合はLineへの入力)よりも先にobniz.onconnectをしておく必要がある。
          //全体をobnizの"{ }"で括ると扱いやすい様子。
    var light = obniz.wired("Keyestudio_TrafficLight", {gnd:0, green:1, yellow:2, red:3});

  const express = require('express');
  const line = require('@line/bot-sdk');
  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 handleEvent(event) {
    if (event.type !== 'message' || event.message.type !== 'text') {
      return Promise.resolve(null);
    }

    //返信コードはここから
      if (event.message.text === '天気'){

        const axios = require('axios');
        const main = async () => {
          try {
            let cname = 'Tokyo'
            const res = await const res = await axios.get('http://api.openweathermap.org/data/2.5/weather?q=Tokyo&units=metric&APPID={自分のAPIキー}');  // URLを書き換える
            console.log(res.data); // データ全体を表示する(なくてもOK)

            let currentWeather = res.data.weather[0].main;
            let description = res.data.weather[0].description;
            let temp = res.data.main.temp;
            let temp_max = res.data.main.temp_max;
            let temp_min = res.data.main.temp_min;
            let city = res.data.name;

            var currentDate=new Date();
            var y=currentDate.getFullYear();
            var mo=currentDate.getMonth();
            var d=currentDate.getDate();
            var h=currentDate.getHours();
            var m=currentDate.getMinutes();
            var today=y + '' + mo + '' + d + ''
            var str=h+":"+m;

            const RED_WEATHERS = [
              "Rain",
              "Snow",
              "Thunderstorm",
              "Drizzle",
              "Fog",
              "Squall"
            ];
            const YELLOW_WEATHERS = [
              "Clouds",
              "Mist",
              "Smoke",
              "Dust",
              "Haze",
              "Sand",
              "Ash",
              "Tornado"
            ];
            const GREEN_WEATHERS = ["Clear"];

            let weather = res.data.weather[0].main;
            let weather_ja = '晴れ'
              switch (weather){
                  case 'Clear':
                    weather_ja = '晴れ';
                    break;
                  case 'Clouds':
                    weather_ja = 'くもり';
                    break;
                  case 'Mist':
                    weather_ja = 'もや';
                    break;
                  case 'Smoke':
                    weather_ja = '';
                    break;
                  case 'Dust':
                    weather_ja = 'ほこり';
                    break;
                  case 'Haze':
                    weather_ja = 'かすみ';
                    break;
                  case 'Sand':
                    weather_ja = '';
                    break;
                  case 'Ash':
                    weather_ja = '';
                    break;
                  case 'Tornado':
                    weather_ja = '竜巻';
                    break;
                  case 'Rain':
                    weather_ja = '';
                    break;
                  case 'Snow':
                    weather_ja = '';
                    break;
                  case 'Thunderstorm':
                    weather_ja = '雷雨';
                  case 'Drizzle':
                    weather_ja = '霧雨';
                    break;
                  case 'Fog':
                    weather_ja = '';
                    break;
                  case 'Squall':
                    weather_ja = 'スコール';
                    break;
              }

            let description_ja = 'なし'
              switch (description){
                  case 'thunderstorm with light rain':
                    description_ja = '小雨で雷雨';
                    break;
                  case 'thunderstorm with rain':
                    description_ja = '雨で雷雨';
                    break;
                  case 'thunderstorm with heavy rain':
                    description_ja = '大雨で雷雨';
                    break;
                  case 'light thunderstorm':
                    description_ja = '軽い雷雨';
                    break;
                  case 'thunderstorm':
                    description_ja = '雷雨';
                    break;
                  case 'heavy thunderstorm':
                    description_ja = '激しい雷雨';
                    break;
                  case 'ragged thunderstorm':
                    description_ja = '不規則な雷雨';
                    break;
                  case 'thunderstorm with light drizzle':
                    description_ja = '軽い霧雨と雷雨 ';
                    break;
                  case 'thunderstorm with drizzle':
                    description_ja = '霧雨と雷雨';
                    break;
                  case 'thunderstorm with heavy drizzle':
                    description_ja = '激しい霧雨で雷雨';
                    break;
                  case 'light intensity drizzle':
                    description_ja = '弱い霧雨';
                    break;
                  case 'drizzle':
                    description_ja = '霧雨';
                    break;
                  case 'heavy intensity drizzle':
                    description_ja = '強い霧雨';
                    break;
                  case 'light intensity drizzle rain':
                    description_ja = '弱い霧雨';
                    break;
                  case 'drizzle rain':
                    description_ja = '霧雨';
                    break;
                  case 'heavy intensity drizzle rain':
                    description_ja = '激しい霧雨';
                    break;
                  case 'shower rain and drizzle':
                    description_ja = 'にわか雨と霧雨';
                    break;
                  case 'heavy shower rain and drizzle':
                    description_ja = '強いにわか雨と霧雨';
                    break;
                  case 'shower drizzle':
                    description_ja = 'にわか霧雨';
                    break;
                  case 'light rain':
                    description_ja = '小雨';
                    break;
                  case 'moderate rain':
                    description_ja = '中程度の雨';
                    break;
                  case 'heavy intensity rain':
                    description_ja = '大雨';
                    break;
                  case 'very heavy rain':
                    description_ja = '強い大雨';
                    break;
                  case 'extreme rain':
                    description_ja = 'とても強い大雨';
                    break;
                  case 'freezing rain':
                    description_ja = '凍雨';
                    break;
                  case 'light intensity shower rain':
                    description_ja = '弱いにわか雨';
                    break;
                  case 'shower rain':
                    description_ja = 'にわか雨';
                    break;
                  case 'heavy intensity shower rain':
                    description_ja = '激しいにわか雨';
                    break;
                  case 'ragged shower rain':
                    description_ja = '不規則なにわか雨';
                    break;
                  case 'light snow':
                    description_ja = '軽い雪';
                    break;
                  case 'Snow':
                    description_ja = '';
                    break;
                  case 'Heavy snow':
                    description_ja = '大雪';
                    break;
                  case 'Sleet':
                    description_ja = '霙(みぞれ)';
                    break;
                  case 'Light shower sleet':
                    description_ja = '弱いにわか霙(みぞれ)';
                    break;
                  case 'Shower sleet':
                    description_ja = 'にわか霙(みぞれ)';
                    break;
                  case 'Light rain and snow':
                    description_ja = '小雨と雪';
                    break;
                  case 'Rain and snow':
                    description_ja = '雨と雪';
                    break;
                  case 'Light shower snow':
                    description_ja = '弱いにわか雪';
                    break;
                  case 'Shower snow':
                    description_ja = 'にわか雪';
                    break;
                  case 'Heavy shower snow':
                    description_ja = '強いにわか雪';
                    break;
                  case 'mist':
                    description_ja = '靄(もや)';
                    break;
                  case 'Smoke':
                    description_ja = '';
                    break;
                  case 'Haze':
                    description_ja = '霞(かすみ)';
                    break;
                  case 'sand/ dust whirls':
                    description_ja = '砂/塵旋風';
                    break;
                  case 'fog':
                    description_ja = '霧(きり)';
                    break;
                  case 'sand':
                    description_ja = '';
                    break;
                  case 'dust':
                    description_ja = '';
                    break;
                  case 'volcanic ash':
                    description_ja = '火山灰';
                    break;
                  case 'squalls':
                    description_ja = 'スコール';
                    break;
                  case 'tornado':
                    description_ja = '竜巻';
                    break;
                  case 'clear sky':
                    description_ja = '澄んだ空';
                    break;
                  case 'few clouds':
                    description_ja = '少しの雲';
                    break;
                  case 'scattered clouds':
                    description_ja = '散乱雲';
                    break;
                  case 'broken clouds':
                    description_ja = '壊れた雲';
                    break;
                  case 'overcast clouds':
                    description_ja = '曇り雲';
                    break;
              }
               //LINE Botへの返信 の後に処理を記載すると、「到達できないコード」とエラーがでるので、先に記載をする。
              if (currentWeather === undefined || currentWeather === null) {
                light.green.off();
                light.yellow.off();
                light.red.off();

              }
              if (RED_WEATHERS.includes(currentWeather) === true) {
                  light.red.on();

              } else if (YELLOW_WEATHERS.includes(currentWeather) === true) {
                  light.yellow.on();

              } else if (GREEN_WEATHERS.includes(currentWeather) === true) {
                  light.green.on();

              } else {
                light.green.off();
                light.yellow.off();
                light.red.off();
              }

            let mes = '';  //LINE Botへの返信
            mes = today + ' ' + str + ' ' + city + '\n' + '現在の天気は「'+ weather_ja +'」です。\n'+ '詳細:' + description_ja +'\n' + '気温は' + temp  +'℃です。';

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

          } catch (error) {
            console.error(error);
          }

        }
        main();

      }else if (event.message.text === 'オフ'){
        light.green.off();
        light.yellow.off();
        light.red.off();

      }else {
          return client.replyMessage(event.replyToken, {  
            type: 'text',
            text: '”天気” と入れてください。',
          }); 
      }
        //返信コードはここまで
  }
  app.listen(PORT);
  console.log(`Server running at ${PORT}`);
}  //obniz.onconnectの閉じカッコ。

下のコードは、上コードを作成するベースに使ったコード
(obnizと連携させる前の、LINE BotとAPIの連携のみのコード)

//【”天気”と入れると、日時、今の天気・雲の様子・気温を返す。】
'use strict';

const express = require('express');
const line = require('@line/bot-sdk');
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 handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  //返信コードはここから
    if (event.message.text === '天気'){

      const axios = require('axios');
      const main = async () => {
        try {
          let cname = 'Tokyo'
          const res = await axios.get('http://api.openweathermap.org/data/2.5/weather?q=Tokyo&units=metric&APPID={自分のAPIキー}');  // URLを書き換える
          console.log(res.data); // データ全体を表示する(なくてもOK)

          let currentWeather = res.data.weather[0].main;
          let description = res.data.weather[0].description;
          let temp = res.data.main.temp;
          let temp_max = res.data.main.temp_max;
          let temp_min = res.data.main.temp_min;
          let city = res.data.name;

          var currentDate=new Date();
          var y=currentDate.getFullYear();
          var mo=currentDate.getMonth();
          var d=currentDate.getDate();
          var h=currentDate.getHours();
          var m=currentDate.getMinutes();
          var today=y + '' + mo + '' + d + ''
          var str=h+":"+m;

          let weather = res.data.weather[0].main;
          let weather_ja = '晴れ'
            switch (weather){
                case 'Clear':
                  weather_ja = '晴れ';
                  break;
                case 'Clouds':
                  weather_ja = 'くもり';
                  break;
                case 'Mist':
                  weather_ja = 'もや';
                  break;
                case 'Smoke':
                  weather_ja = '';
                  break;
                case 'Dust':
                  weather_ja = 'ほこり';
                  break;
                case 'Haze':
                  weather_ja = 'かすみ';
                  break;
                case 'Sand':
                  weather_ja = '';
                  break;
                case 'Ash':
                  weather_ja = '';
                  break;
                case 'Tornado':
                  weather_ja = '竜巻';
                  break;
                case 'Rain':
                  weather_ja = '';
                  break;
                case 'Snow':
                  weather_ja = '';
                  break;
                case 'Thunderstorm':
                  weather_ja = '雷雨';
                case 'Drizzle':
                  weather_ja = '霧雨';
                  break;
                case 'Fog':
                  weather_ja = '';
                  break;
                case 'Squall':
                  weather_ja = 'スコール';
                  break;
            }

          let description_ja = 'なし'
            switch (description){
                case 'thunderstorm with light rain':
                  description_ja = '小雨で雷雨';
                  break;
                case 'thunderstorm with rain':
                  description_ja = '雨で雷雨';
                  break;
                case 'thunderstorm with heavy rain':
                  description_ja = '大雨で雷雨';
                  break;
                case 'light thunderstorm':
                  description_ja = '軽い雷雨';
                  break;
                case 'thunderstorm':
                  description_ja = '雷雨';
                  break;
                case 'heavy thunderstorm':
                  description_ja = '激しい雷雨';
                  break;
                case 'ragged thunderstorm':
                  description_ja = '不規則な雷雨';
                  break;
                case 'thunderstorm with light drizzle':
                  description_ja = '軽い霧雨と雷雨 ';
                  break;
                case 'thunderstorm with drizzle':
                  description_ja = '霧雨と雷雨';
                  break;
                case 'thunderstorm with heavy drizzle':
                  description_ja = '激しい霧雨で雷雨';
                  break;
                case 'light intensity drizzle':
                  description_ja = '弱い霧雨';
                  break;
                case 'drizzle':
                  description_ja = '霧雨';
                  break;
                case 'heavy intensity drizzle':
                  description_ja = '強い霧雨';
                  break;
                case 'light intensity drizzle rain':
                  description_ja = '弱い霧雨';
                  break;
                case 'drizzle rain':
                  description_ja = '霧雨';
                  break;
                case 'heavy intensity drizzle rain':
                  description_ja = '激しい霧雨';
                  break;
                case 'shower rain and drizzle':
                  description_ja = 'にわか雨と霧雨';
                  break;
                case 'heavy shower rain and drizzle':
                  description_ja = '強いにわか雨と霧雨';
                  break;
                case 'shower drizzle':
                  description_ja = 'にわか霧雨';
                  break;
                case 'light rain':
                  description_ja = '小雨';
                  break;
                case 'moderate rain':
                  description_ja = '中程度の雨';
                  break;
                case 'heavy intensity rain':
                  description_ja = '大雨';
                  break;
                case 'very heavy rain':
                  description_ja = '強い大雨';
                  break;
                case 'extreme rain':
                  description_ja = 'とても強い大雨';
                  break;
                case 'freezing rain':
                  description_ja = '凍雨';
                  break;
                case 'light intensity shower rain':
                  description_ja = '弱いにわか雨';
                  break;
                case 'shower rain':
                  description_ja = 'にわか雨';
                  break;
                case 'heavy intensity shower rain':
                  description_ja = '激しいにわか雨';
                  break;
                case 'ragged shower rain':
                  description_ja = '不規則なにわか雨';
                  break;
                case 'light snow':
                  description_ja = '軽い雪';
                  break;
                case 'Snow':
                  description_ja = '';
                  break;
                case 'Heavy snow':
                  description_ja = '大雪';
                  break;
                case 'Sleet':
                  description_ja = '霙(みぞれ)';
                  break;
                case 'Light shower sleet':
                  description_ja = '弱いにわか霙(みぞれ)';
                  break;
                case 'Shower sleet':
                  description_ja = 'にわか霙(みぞれ)';
                  break;
                case 'Light rain and snow':
                  description_ja = '小雨と雪';
                  break;
                case 'Rain and snow':
                  description_ja = '雨と雪';
                  break;
                case 'Light shower snow':
                  description_ja = '弱いにわか雪';
                  break;
                case 'Shower snow':
                  description_ja = 'にわか雪';
                  break;
                case 'Heavy shower snow':
                  description_ja = '強いにわか雪';
                  break;
                case 'mist':
                  description_ja = '靄(もや)';
                  break;
                case 'Smoke':
                  description_ja = '';
                  break;
                case 'Haze':
                  description_ja = '霞(かすみ)';
                  break;
                case 'sand/ dust whirls':
                  description_ja = '砂/塵旋風';
                  break;
                case 'fog':
                  description_ja = '霧(きり)';
                  break;
                case 'sand':
                  description_ja = '';
                  break;
                case 'dust':
                  description_ja = '';
                  break;
                case 'volcanic ash':
                  description_ja = '火山灰';
                  break;
                case 'squalls':
                  description_ja = 'スコール';
                  break;
                case 'tornado':
                  description_ja = '竜巻';
                  break;
                case 'clear sky':
                  description_ja = '澄んだ空';
                  break;
                case 'few clouds':
                  description_ja = '少しの雲';
                  break;
                case 'scattered clouds':
                  description_ja = '散乱雲';
                  break;
                case 'broken clouds':
                  description_ja = '壊れた雲';
                  break;
                case 'overcast clouds':
                  description_ja = '曇り雲';
                  break;
            }

          let mes = '';
          mes = today + ' ' + str + ' ' + city + '\n' + '現在の天気は「'+ weather_ja +'」です。\n'+ '詳細:' + description_ja +'\n' + '気温は' + temp  +'℃です。';

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

        } catch (error) {
          console.error(error);
        }
      }
      main();

    }else {
        return client.replyMessage(event.replyToken, {  
          type: 'text',
          text: '”天気” と入れてください。',
  }); 
  }
  //返信コードはここまで
}
app.listen(PORT);
console.log(`Server running at ${PORT}`);

仕様
 ●LINE Botに、”天気” と入力すると、今の天気・雲の様子・気温を返し、
  obinzの天気に対応するLED信号を点灯させる。
 ●”オフ” と入力すると、LED信号を消灯する。
 ●その他の文字を入力すると、「”天気” と入れてください。」と返す。

工夫を要した箇所
 ① 「//返信コードはここから」~「 //返信コードはここまで」の間にLine Botへ
   返信する内容を記載すれば実行できる。以前に作成した「Visual Studio Code
   で、obnizに天気の情報を表示させ、天気に対応するLED信号を光らせる」
     https://qiita.com/21HideK/items/9e8cf1a2ba3f1aae344e
   を利用したので、作成自体は難しくはなかった。しかし記入の仕方が少し
   違うだけでエラーが出てしまうのを修正するのに苦労した。

 ②obniz.onconnectを記載する場所が分からず、何度もエラーを生じた。
  下記HPより、event(この場合はLineへの入力)よりも先にobniz.onconnectを
  しておく必要があることが分かり、解決した。

 ③LINE Botへの返信の後に処理を記載すると、「到達できないコード」とエラー
  がでるので、先に記載をする必要がある。

〔参考にしたHP〕
obnizとLineBotで防犯ツールを作ってみた(NO MORE XX 泥棒)
https://qiita.com/shima-07/items/e4d6a33c460da77e25ec?utm_campaign=popular_items&utm_medium=feed&utm_source=popular_items

6
0
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
6
0