Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

天気予報(今の天気)のBOTをCakePHP3を利用して作ってみた

More than 1 year has passed since last update.

CakePHP3で動かす

はい、前回の公開から時間が経ってますが、書いていきます。
CakePHP3を使って、LINE BOTを使うというところからですね。

CakePHP3の使い方がわからない人は、調べてください。

BotController作成

BotController.php
<?php
namespace App\Controller;

use App\Controller\AppController;

class BotController extends AppController
{

  // アクセストークン
  protected $ACCESS_TOKEN = 'developerの[メッセージ送受信設定]の[アクセストークン]';

  public function index()
  {
    // autoRenderは使用しません
    $this->autoRender = false;

    // 返却する文字列
    $message_text = "";

    $messageData = array();
    $request = $this->request->getData();

    // ユーザーから送られてきたデータ
    $event = $request['events'][0];
    $type  = $event['type'];
    $replyToken = $event['replyToken'];

    $userId = $event['source']['userId'];

    if($type == 'follow'){
      // 登録された時に文言を返す
      $message_text = "登録ありがとう。よろしくね。";
    }elseif($type == 'unfollow'){
      // 削除された場合の処理
    }elseif($type == "message"){
      // メッセージ
      $messageType = $event['message']['type'];
      if($messageType == 'text') {
        // text そのまま返す
        $message_text = $event['message']['text'];
      }
    }

    // 返信可能な場合に処理する
    if(!empty($message_text)) {
      //レスポンスフォーマット
      $response_format_text = [
        "type" => 'text',
        "text"  => $message_text
      ];

      //ポストデータ
      $post_data = [
        "replyToken" => $replyToken,
        "messages" => [$message_text]
      ];

      //curl実行
      $ch = curl_init("https://api.line.me/v2/bot/message/reply");
      curl_setopt($ch, CURLOPT_POST, true);
      curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
      curl_setopt($ch, CURLOPT_HTTPHEADER, array(
       'Content-Type: application/json; charser=UTF-8',
        'Authorization: Bearer ' . $ACCESS_TOKEN
      ));
      $result = curl_exec($ch);
      curl_close($ch);
    }

    echo 200;
  }
}

コレで、https://hogehoge/botとかをWebhook URLに指定すれば、
前回と同じようなことができますね。

天気予報

では次に。天気予報。
今回はOpenWeatherMapを利用します。
登録して、API KEYを取得したら、「天気予報」と言う言葉に反応して、
沼津市=Numazu, JPの現在の天気を取得します。

WeatherMapComponent作成

まずは、天気予報関連の処理をまとめたいので
WeatherMapComponent.phpを作りましょう。

WeatherMapComponent.php
<?php
namespace App\Controller\Component;

use Cake\Controller\Component;

class WeatherMapComponent extends Component
{
    // 現在の天気を取得
    protected $WEATHER_MAP_WEATHER_URL = "http://api.openweathermap.org/data/2.5/weather";
    // 沼津市を指定
    protected $CITY = "Numazu, JP";
    // api key
    protected $WEATHER_MAP_API = "[OpenWeatherMap の API KEY]";

  /**
   * 天気予報文字列を返す
   * @return string
   */
    public function getWeather(){
      $url = self::getWeatherUrlFromCity();
      $weather = json_decode(file_get_contents($url), true);

      return self::getWeatherText($weather);
    }

  /**
   * 都市名検索URL(現在の天気)
   * @return string
   */
    public function getWeatherUrlFromCity(){
      return $this->WEATHER_MAP_WEATHER_URL. "?q=".$this->CITY."&units=metric&appid=".$this->WEATHER_MAP_API;
    } 


  /**
   * objectから天気予報を取得して文字列を返す
   * @param $weather
   * @return string
   */
   public function getWeatherText($weather){
      $text = '';

      if(isset($weather['weather'][0]['id'])){
        $main = $this->getMainText($weather['weather'][0]['main']);
        $description = $this->getWeatherDescription($weather['weather'][0]['id']);
        $text .= "今の天気は".$main."で、".$description."です。\n";
      }

      // degが風向きを、speedが風速を表してます。
      if(isset($weather['wind']['deg']) && isset($weather['wind']['speed'])){
        $digger = $this->getWindDigger($weather['wind']['deg']);
        $text .= $digger."向きの風、風速".$weather['wind']['speed']."メートル。\n";
      }

      // tempが気温を示しています
      if(isset($weather['main']['temp'])){
        $text .= "気温は".$weather['main']['temp']."度です。";
      }

      return $text;
    }

  /**
   * @param $main
   * @return mixed
   */
    public function getMainText($main){
      $inEnglish = array('Clear', 'Clouds', 'Rain', 'Snow','Mist');
      $inJapanese = array('晴れ', 'くもり', '雨', '雪','霧');
      $key = array_search($main,$inEnglish);
      if($key !== false){
        return $inJapanese[$key];
      }
      return $main;
    }

  /**
   * 天気詳細
   * @param $id
   * @return string
   */
    public function getWeatherDescription($id){
      $description[200] = '雨が降る雷雨';
      $description[201] = '雨が降る雷雨';
      $description[202] = '豪雨による雷雨';
      $description[210] = '雷雨';
      $description[211] = '雷雨';
      $description[212] = '重い雷雨';
      $description[221] = '荒れた雷雨';
      $description[230] = '軽い霧雨で雷雨';
      $description[231] = '雷雨と霧雨';
      $description[232] = '重い霧雨で雷雨';
      $description[300] = '光度の霧雨';
      $description[301] = '霧雨';
      $description[302] = '重い霧雨の霧';
      $description[310] = '光度降雨雨';
      $description[311] = '霧雨';
      $description[312] = '強い霧雨';
      $description[313] = 'にわか雨と霧雨';
      $description[314] = '重いにわか雨と霧雨';
      $description[321] = 'にわか霧雨';
      $description[500] = '小雨';
      $description[501] = '中程度の雨';
      $description[502] = '強い雨';
      $description[503] = '非常に豪雨';
      $description[504] = '極端な雨';
      $description[511] = '雨氷';
      $description[520] = '強度のにわか雨';
      $description[521] = 'にわか雨';
      $description[522] = '激しいにわか雨';
      $description[531] = '不規則なにわか雨';
      $description[600] = '小雪';
      $description[601] = '雪';
      $description[602] = '大雪';
      $description[611] = 'みぞれ';
      $description[612] = 'にわかみぞれ';
      $description[615] = '明るい雨と雪';
      $description[616] = '雨や雪';
      $description[620] = '雷とにわか雪';
      $description[621] = 'にわか雪';
      $description[622] = '重いにわか雪';
      $description[701] = 'ミスト';
      $description[711] = '煙';
      $description[721] = 'ヘイズ';
      $description[731] = '砂、ほこり旋回する';
      $description[741] = '霧';
      $description[751] = '砂';
      $description[761] = 'ほこり';
      $description[762] = '火山灰';
      $description[771] = 'スコール';
      $description[781] = '竜巻';
      $description[800] = '晴天';
      $description[801] = '薄い雲';
      $description[802] = '雲';
      $description[803] = '曇りがち';
      $description[804] = '厚い雲';
      $description[900] = '竜巻';
      $description[901] = '熱帯低気圧';
      $description[902] = 'ハリケーン';
      $description[903] = '寒い';
      $description[904] = '暑い';
      $description[905] = '風が強い';
      $description[906] = '雹';
      $description[951] = '落ち着いた';
      $description[952] = 'そよ風';
      $description[953] = 'そよ風';
      $description[954] = '中風';
      $description[955] = '新鮮な風';
      $description[956] = '強い風';
      $description[957] = '高風、近くの暴風';
      $description[958] = 'ガール';
      $description[959] = '深刻な暴風';
      $description[960] = '嵐';
      $description[961] = '暴風雨';
      $description[962] = 'ハリケーン';

      if(isset($description[$id])){
        return $description[$id];
      }

      return '';
    }

  /**
   * 風向き計算
   *
   * @param $digree
   * @return mixed
   */
    public function getWindDigger($digree){
      $dname = ["北","北北東","北東", "東北東", "東", "東南東", "南東", "南南東", "南", "南南西", "南西", "西南西", "西", "西北西", "北西", "北北西", "北"];
      $dindex = round($digree / 22.5);

      return $dname[$dindex];
    }
}

BotController修正

今度はこのComponentを使えるようにしないとですね。

BotController.php
class BotController extends AppController
{
  public $components = [ "WeatherMap" ];

  // アクセストークン
  protected $ACCESS_TOKEN = 'developerの[メッセージ送受信設定]の[アクセストークン]';

componentsに"WeatherMap"を指定します。

BotController.php
    }elseif($type == "message"){
      // メッセージ
      $messageType = $event['message']['type'];
      if($messageType == 'text') {
        // 文言に「天気予報」が含まれていたら天気予報を返す
        if(strpos("天気予報",$event['message']['text']) !== false){
          $message_text = $this->WeatherMap->();
        }else{
          // text そのまま返す
          $message_text = $event['message']['text'];
        }
      }
    }

if(strpos("天気予報",$event['message']['text']) !== false){
このようにして、文言の中に「天気予報」が含まれていたら、天気を返します。
とはいえ、今回返しているのは現在の天気なわけですが…

まとめ

このようにして、Controller、Componentを作成して、BOTに天気を返させる処理ができました。
今回は現在の天気を返していますが、URLの「weather」を「forecast」にすれば、予報の処理も作成できます。
(返ってくる値が違うので、気をつけてください)

APIと連携したら色々と面白いBOTが作れそうだなぁーと言うのがこちらを作った際の感想でした。
でも、現在はPUSH機能を使ったBOTがかなり面白いので、そちらの処理も後々書きたいと思います。

この機能を使ったおしゃべりBOT 堕天使YOHANEを公開しています。
メインはおしゃべりなので、何か言うと返ってきます。
また、占いとか…現在の沼津の天気を教えてくれるそんなBOTです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away