どっかの元高専生の技術備忘録

10割自分の備忘録用のブログ。

月齢と天気を朝晩にLINEへ通知するBOTをGASで作ってみる

やりたいこと

当日の月齢と当日の天気を朝8:00に送信して、
明日の月齢tと明日の天気を夜20:00に送信するLINE BOTを作ってみる。
LINE Notifyでもできそうだけど、今回はLINE Messaging APIを使って作ってみたい。

目次

LINE公式アカウントの作成

LINE Developersにアクセスしてアカウントを作成します。

ログインできたら、Create New Providerをクリックして新しいプロバイダーを作成します。

そうしたら、Create New ChannelからMessaging APIを選択して新しいチャンネルを作っていきます。
ここで、Botの名前やアイコン、アカウントのカテゴリーなどを設定していきます。

作成できたら、Bot informationのところにある友達追加用のQRコードから追加しておきましょう。

GASの方でスクリプトを書くときに以下の2点が必要になるので、控えておきましょう。

  • Your user ID
  • Channel access token

Channel access tokenは初期状態では発行されていないので、Messaging APIタブから発行しておきましょう。

グループLINEにBotを追加する場合

作成したBotをグループLINEに追加する場合は、LINE Official Account featuresのところにある、Allow bot to join group chatsを有効化しておいてください。

なお、グループに追加するのは後述するグループIDを取得する準備ができてからするようにしてください。

GASの作成

Google Apps Script にアクセスし、以下のコードをコピペしてください。
なお、月齢の計算には福原直人さんのスクリプトを使用させていただきました。
また、気象庁からの情報取得には@takatama(高玉 広和)さんのライブラリを使用させていただきました。

const TOKEN = "";
const DESTID = "";
const URL = "https://api.line.me/v2/bot/message/push";
const AREACODE = "130000";

function getNewMoon(julian) {
  /*
    新月日計算
    引数   julian  ユリウス通日
    戻り値  与えられたユリウス通日に対する直前の新月日(ユリウス日)
  */

  var k     = Math.floor((julian - 2451550.09765) / 29.530589);
  var t     = k / 1236.85;
  var nmoon = 2451550.09765
             + 29.530589  * k
             +  0.0001337 * t * t
             -  0.40720   * Math.sin((201.5643 + 385.8169 * k) * 0.017453292519943)
             +  0.17241   * Math.sin((2.5534 +  29.1054 * k) * 0.017453292519943);
  return (nmoon);         // julian - nmoonが現在時刻の月齢

}

function getJulian(date) {
  /*
    ユリウス通日計算
    引数  時刻(Dateオブジェクト)
    戻り値 ユリウス通日(浮動小数点数)
  */

  return date.getTime() / 86400000.0+2440587.5;

}

function maeZero(num){
  /*
      0,1,2,3 ... を 00,01,02,03 ... に。
    (変な関数名だ)
  */

  if (num < 10){
    return '0' + num;
  } else {
    return num;
  }

}

function getMoonPhase(day) {
  /*
    月齢計算
    引数  知りたい月齢の日(str)
    戻り値  月齢(float)
  */
  if (day == "today"){
    var calcDate = new Date();
  } else if (day == "nextday"){
    var nowDate = new Date();
    var calcDate = new Date(nowDate.setDate(nowDate.getDate() + 1));
  } else {
    console.log("Something went to wrong.");
    return 1;
  }

  julian = getJulian(calcDate);

  var year    = calcDate.getYear();
  if(year < 2000){
    year += 1900;
  }

  var nmoon = getNewMoon(julian);
  // getNewMoonは新月直前の日を与えるとうまく計算できないのでその対処
  // (一日前の日付で再計算してみる)
  if (nmoon > julian) {
    nmoon = getNewMoon(julian - 1.0);
  }

  var age = julian - nmoon; // julian - nmoonが現在時刻の月齢
  var age = age.toFixed(2); // 2桁に丸める
  console.log(age);
  return age;
}

function getForecast(time) {
  if (time == "morning") {
    // 当日の天気予報を返す
    console.log("Hi, Good morning.");
    var weather = WeatherForecast.fetchForecast(AREACODE);
    var today_forecast = weather["areas"][0]["threeDays"][0];
    console.log(weather);
    return today_forecast;
  } else if (time == "evening") {
    // 明日の天気予報を返す
    console.log("Good evening.");
    var weather = WeatherForecast.fetchForecast(AREACODE);
    var nextday_forecast = weather["areas"][0]["threeDays"][1];
    console.log(weather);
    return nextday_forecast;
  } else {
    console.log("Something went to wrong.");
    return 1;
  }
}

function sendFigLINE(url){
  // LINEにメッセージを送信する関数
  UrlFetchApp.fetch(URL, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + TOKEN,
    },
    'method': 'POST',
    'payload': JSON.stringify({
      'to': DESTID,
      'messages':[{
        'type': 'image',
        'originalContentUrl': url ,
        'previewImageUrl': url ,
      }]
     })
   })
}

function sendMsgLINE(body) {
  // LINEに画像を送信
  UrlFetchApp.fetch(URL, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + TOKEN,
    },
    'method': 'POST',
    'payload': JSON.stringify({
      'to': DESTID,
      'messages':[{
        'type': 'text',
        'text': body ,
      }]
     })
   })
}

function createMorningReport() {
  var moonage = getMoonPhase("today")
  var forecast = getForecast("morning");
  console.log(moonage);
  console.log(forecast);

  // メッセージの作成
  var msg = ("【今日の天気】\n" +
  "\t天気概況: " + forecast["summary"] + "\n" +
  "\t最高気温: " + forecast["maxTemp"] + "℃\n" + 
  "\t最低気温: " + forecast["minTemp"] + "℃\n" +
  "【今日の月齢】\n" + 
  "\t" + moonage
  );
  console.log(msg);
  console.log(forecast["iconUrl"])
  sendMsgLINE(msg);
  sendFigLINE(forecast["iconUrl"]);

}

function createEveningReport() {
  var today_moonage = getMoonPhase("today");
  var nextday_moonage = getMoonPhase("nextday");
  var forecast = getForecast("evening");
  console.log(today_moonage);
  console.log(nextday_moonage);
  console.log(forecast);

  // メッセージの作成
  var msg = ("【明日の天気】\n" +
  "\t天気概況: " + forecast["summary"] + "\n" +
  "\t最高気温: " + forecast["maxTemp"] + "℃\n" + 
  "\t最低気温: " + forecast["minTemp"] + "℃\n" +
  "【今日の月齢】\n" + 
  "\t" + today_moonage + "\n" +
    "【明日の月齢】\n" + 
  "\t" + nextday_moonage
  );
  console.log(msg);
  console.log(forecast["iconUrl"])
  sendMsgLINE(msg);
  sendFigLINE(forecast["iconUrl"]);
}

なお、グループLINEにメッセージを送りたい人はDESTIDにUser IDではなくGroup IDを入力する必要があります。
この取得方法がめんどくさいので、後述します。

グループLINEにメッセージを送る方法

グループIDを取得するには、Webhookを受信するサーバーが必要になります。
自前で用意するのもありですが、めんどくさいのでGASとスプレッドシートを使ってグループIDを取得します。
まず、スプレッドシートを新規作成しExtensionからApps Scriptを選択してGASの画面に行きます。

そうしたら、以下のコードを貼り付けます。
なお、コードは三十路街道 ボンバィエ様のサイトにあるものを使わせていただきました。

cyuraharuto.com

function doPost(e){
 var json = JSON.parse(e.postData.contents);
 var UID = json.events[0].source.userId;
 var GID = json.events[0].source.groupId;
  
 var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
 sheet.getRange(1,1).setValue(GID);

}

貼り付けたら、これをWEBアプリとしてデプロイしていきます。
上の方にあるDeployからNew Deployを選択して、以下のように設定します。

デプロイできたら、URLが表示されるのでそれをコピーしてLINE DevelopersのWebhook URLに貼り付けます。

そうしたら、下にあるUse webhookを有効化します。ここまで出来たらBotをグループLINEに招待してください。
そうすると、先程のスプレッドシートのA1にグループIDが表示されています。これをDESTIDに入力してください。 完了したら、セキュリティのためにUse webhookを無効化し、スクリプトを削除しておいてください。

トリガーの設定

定期的に実行できるよう、トリガーの設定をしていきます。

朝用のトリガーには、実行する関数にcreateMorningReportを選択してください。

夜用のトリガーには、実行する関数にcreateEveningReportを選択してください。
これで、毎日朝晩に通知が飛んでくるようになります。

参考

https://news.local-group.jp/moonage/moonage.js.txt

qiita.com