見出し画像

Google Apps Scriptで予定と天気を教えるbotを作る

どうも、フルトしろ。です。

現代社会を生きるみなさん、仕事や知り合いとの約束に行きたいイベント、毎日予定がてんこ盛りですよね。
天気予報を見たり提出する書類の確認など、必要な情報もたくさんです。
これらを人力でチェックしきるのには少し骨が折れます。

というわけで、朝にそういう情報を教えてくれるLINEのbotを作りましょう。

作りたいもの

  • Googleカレンダーを参照し今日の予定を羅列して教えてくれる

  • 天気予報を取得し教えてくれる

  • アラームも兼ねて朝の5~6時くらいに送信してくれる

こんな感じのを作ります。

カレンダーの情報を取得する

Google Apps ScriptはGoogleカレンダーの操作に対応しているので、APIの操作などめんどくさそうなことは特にないです。
普通のコードを書くような感覚でカレンダーの操作が可能になっています。

function GetEventsFunction() {
  const myCalendar = CalendarApp.getCalendarById("見せられないよ@gmail.com")
  const today = new Date;
  const myEvents = myCalendar.getEventsForDay(today);
  if(myEvents[0] === undefined){
    console.log("予定はないよ")
  } else {
    for (let i = 0;i < myEvents.length;i++){
      console.log(myEvents[i].getTitle())
    }
  }

とりあえず書いたコードがこちらです。ひとつずつ解説します。

const myCalendar = CalendarApp.getCalendarById("見せられないよ@gmail.com")

getCalendarByIdという関数でカレンダーの情報をまず取得します。
この時引数として必要な情報はカレンダーのIDです。
一応Googleカレンダーから確認することはできますが、だいたい自分のメールアドレスになってます。

もちろん僕のメアドが本当に「見せられないよ」である訳ではないです。

const today = new Date;
const myEvents = myCalendar.getEventsForDay(today);

today変数にDateオブジェクトをインスタンス化して代入します。
Dateオブジェクトは名前の通り日付や時刻が記録されており、インスタンス化した時点ではその日の情報が入っています。

カレンダーのgetEventsForDay関数は日付を引数として渡すことでその日のイベントが配列で帰ってきます。
今回のコードでは先ほど定義したtodayを引数にしているので、コードを実行した日のイベントたちが帰ってくる訳です。

  if(myEvents[0] === undefined){
    console.log("予定はないよ")
  } else {
    for (let i = 0;i < myEvents.length;i++){
      console.log(myEvents[i].getTitle())
    }
  }

ここで条件分岐を挟みます。
もし予定がなかった場合、配列は当たり前ですが未定義となるので、もし配列の一番最初が未定義であれば「予定はないよ」と返すようにしました。

予定があるならfor文でひとつづつチェックします。
getTitle関数でイベントのタイトルを抽出することができるので、それを使って全てのイベントの名前を並べてもらいましょう。

試しにカレンダーの今日の日付に3つほど予定を入れて実行してみます。

ちゃんと取得することができました。順番が逆転しているのは少し気になりますが…

一応予定がない場合もテストしましょう。


しっかり予定はないよと返ってきました。これで十分でしょう。
この関数たちはGetEventsFunctionとして残しておきます。
console.logを後々returnに書き換えて、使い回せるようにしましょう。

天気予報を取得する

天気予報はGoogle Apps Scriptだけではキツそうです。そのため今回は外部APIを使って対処しようと思います。
今回はこちらのAPIを利用して実装していきます。

新しくGetWeatherFunctionを作り、UrlFetchAppでAPIを叩いてみます。

function GetWeatherFunction(){
  const API_Data = UrlFetchApp.fetch("https://weather.tsukumijima.net/api/forecast/city/130010").getContentText();
  console.log(API_Data);
}

返ってきたJsonはこちらです。

{
    "publicTime": "2022-12-18T11:00:00+09:00",
    "publicTimeFormatted": "2022/12/18 11:00:00",
    "publishingOffice": "気象庁",
    "title": "東京都 東京 の天気",
    "link": "https://www.jma.go.jp/bosai/forecast/#area_type=offices&area_code=130000",
    "description": {
        "publicTime": "2022-12-18T10:44:00+09:00",
        "publicTimeFormatted": "2022/12/18 10:44:00",
        "headlineText": "",
        "bodyText": " 日本付近は冬型の気圧配置となっています。\n\n 東京地方は、晴れています。\n\n 18日は、冬型の気圧配置となりますが、湿った空気の影響を受けるため、晴れ時々曇りとなるでしょう。\n\n 19日は、冬型の気圧配置が続く見込みです。このため、晴れで夕方から夜のはじめ頃は曇りとなるでしょう。\n\n【関東甲信地方】\n 関東甲信地方は、晴れや曇りで、雨や雪の降っている所があります。\n\n 18日は、冬型の気圧配置となりますが、湿った空気の影響を受ける所がある見込みです。このため、晴れや曇りで、雨や雪の降る所があるでしょう。\n\n 19日は、冬型の気圧配置が続く見込みです。このため、晴れや曇りで、長野県や関東地方北部では雪の降る所があるでしょう。\n\n 関東地方と伊豆諸島の海上では、18日から19日にかけてしけとなり、19日はうねりを伴うでしょう。船舶は高波に注意してください。",
        "text": " 日本付近は冬型の気圧配置となっています。\n\n 東京地方は、晴れています。\n\n 18日は、冬型の気圧配置となりますが、湿った空気の影響を受けるため、晴れ時々曇りとなるでしょう。\n\n 19日は、冬型の気圧配置が続く見込みです。このため、晴れで夕方から夜のはじめ頃は曇りとなるでしょう。\n\n【関東甲信地方】\n 関東甲信地方は、晴れや曇りで、雨や雪の降っている所があります。\n\n 18日は、冬型の気圧配置となりますが、湿った空気の影響を受ける所がある見込みです。このため、晴れや曇りで、雨や雪の降る所があるでしょう。\n\n 19日は、冬型の気圧配置が続く見込みです。このため、晴れや曇りで、長野県や関東地方北部では雪の降る所があるでしょう。\n\n 関東地方と伊豆諸島の海上では、18日から19日にかけてしけとなり、19日はうねりを伴うでしょう。船舶は高波に注意してください。"
    },
    "forecasts": [
        {
            "date": "2022-12-18",
            "dateLabel": "今日",
            "telop": "晴時々曇",
            "detail": {
                "weather": "晴れ 時々 くもり",
                "wind": "南西の風 後 北西の風 23区西部 では 南西の風 やや強く",
                "wave": "1.5メートル"
            },
            "temperature": {
                "min": {
                    "celsius": null,
                    "fahrenheit": null
                },
                "max": {
                    "celsius": "11",
                    "fahrenheit": "51.8"
                }
            },
            "chanceOfRain": {
                "T00_06": "--%",
                "T06_12": "--%",
                "T12_18": "10%",
                "T18_24": "0%"
            },
            "image": {
                "title": "晴時々曇",
                "url": "https://www.jma.go.jp/bosai/forecast/img/101.svg",
                "width": 80,
                "height": 60
            }
        },
        {
            "date": "2022-12-19",
            "dateLabel": "明日",
            "telop": "晴れ",
            "detail": {
                "weather": "晴れ 夕方 から 夜のはじめ頃 くもり",
                "wind": "南西の風 後 北西の風 23区西部 では はじめ 南西の風 やや強く",
                "wave": "1メートル 後 0.5メートル"
            },
            "temperature": {
                "min": {
                    "celsius": "1",
                    "fahrenheit": "33.8"
                },
                "max": {
                    "celsius": "11",
                    "fahrenheit": "51.8"
                }
            },
            "chanceOfRain": {
                "T00_06": "0%",
                "T06_12": "0%",
                "T12_18": "0%",
                "T18_24": "0%"
            },
            "image": {
                "title": "晴れ",
                "url": "https://www.jma.go.jp/bosai/forecast/img/100.svg",
                "width": 80,
                "height": 60
            }
        },
        {
            "date": "2022-12-20",
            "dateLabel": "明後日",
            "telop": "晴時々曇",
            "detail": {
                "weather": "晴れ 時々 くもり",
                "wind": "北の風",
                "wave": "0.5メートル"
            },
            "temperature": {
                "min": {
                    "celsius": "2",
                    "fahrenheit": "35.6"
                },
                "max": {
                    "celsius": "11",
                    "fahrenheit": "51.8"
                }
            },
            "chanceOfRain": {
                "T00_06": "10%",
                "T06_12": "10%",
                "T12_18": "10%",
                "T18_24": "10%"
            },
            "image": {
                "title": "晴時々曇",
                "url": "https://www.jma.go.jp/bosai/forecast/img/101.svg",
                "width": 80,
                "height": 60
            }
        }
    ],
    "location": {
        "area": "関東",
        "prefecture": "東京都",
        "district": "東京地方",
        "city": "東京"
    },
    "copyright": {
        "title": "(C) 天気予報 API(livedoor 天気互換)",
        "link": "https://weather.tsukumijima.net/",
        "image": {
            "title": "天気予報 API(livedoor 天気互換)",
            "link": "https://weather.tsukumijima.net/",
            "url": "https://weather.tsukumijima.net/logo.png",
            "width": 120,
            "height": 120
        },
        "provider": [
            {
                "link": "https://www.jma.go.jp/jma/",
                "name": "気象庁 Japan Meteorological Agency",
                "note": "気象庁 HP にて配信されている天気予報を JSON データへ編集しています。"
            }
        ]
    }
}

想像以上にたくさんの情報が入っていて驚きました。これだけでお天気アプリ作れそうですね。

さて、このJsonから情報を上手いこと抜き出して利用していきたいので、まずJSON.parseで上手いことしてあげます。
先ほど書いたコードを少しいじりましょう。

const API_Data = JSON.parse(UrlFetchApp.fetch("https://weather.tsukumijima.net/api/forecast/city/130010").getContentText());

こうしてあげることで、Jsonの内容が配列として代入されました。
今回使いたいと思っているデータは、予報日、天気、天気概況文、最高気温なので、これらのデータを抜き取ります。
抜き取ったデータたちは、後々返り値を渡すことを考えてまた別の配列に代入しましょう。

let WeatherData = [];
{
  WeatherData[0] = API_Data["forecasts"][0]["date"] //予報日
  WeatherData[1] = API_Data["forecasts"][0]["telop"] //天気
  WeatherData[2] = API_Data["description"]["bodyText"] //天気概況文
  WeatherData[3] = API_Data["forecasts"][0]["temperature"]["max"]["celsius"] //最高気温
}
console.log(WeatherData);

このようになりました。API_Dataに入った情報をWeatherData配列に代入しています。
現時点ではデバッグログで表示させていますが、将来的にはWeatherDataを返り値として返せばいいだけです。

さて、実行してみましょう。実行結果、つまりWeatherDataの中身は以下のようになりました。

[ '2022-12-18','晴時々曇',' (概況文は長いので省略)','11' ]

大丈夫そうですね。
天気の取得も以上で終わります。

送信する文章を作ろう

さて、カレンダーの情報も天気予報の情報も取得できたところで、送信するための元となる文章を生成する関数を作ります。

とりあえず新しくMakeMessageFunction関数を作り、MadeMessage変数を宣言します

function MakeMessageFunction(){
  let MadeMessage;
}

さて、コードを描き進める前に、まず送るメッセージの元を考えましょう

おはようございます。今日は{日付}、天気は{天気}、最高気温は{気温}となっています。
 
◎今日の予定
・{予定}
 
◎天気概況文
{概況文}

メッセージのイメージ

こんなもんでしょう。続いてこのメッセージを組み上げる関数を作ります。
最初に先ほど書いた二つの関数の最後をconsole.logからreturnへ書き換え

  if(myEvents[0] === undefined){
    return ["特になし"];
  } else {
    let ReturnData = [];
    for (let i = 0;i < myEvents.length;i++){
      ReturnData[i] = myEvents[i].getTitle();
    }
    return ReturnData;
  }

このif文はすこしややこしくなりましたが、要するに
予定なし→"特になし"
予定あり→予定のタイトルを並べた配列 を返すようにしました
"特になし"も配列に統一することでコードを書きやすくします

return WeatherData;

これはそのまんまです。天気の情報4つが入った配列を返してます。

さて、MakeMessageFunctionに戻って、二つの関数の返り値を保存する変数を宣言しておきます

  let TodayEvents = GetEventsFunction();
  let TodayWeather = GetWeatherFunction();

続いて、新しくTodayEventsList変数を宣言し、TodayEventsの配列を参照して箇条書きの文字列を生成&代入します

  let TodayEventsList = "";
  for(let i = 0;i < TodayEvents.length;i++){
    TodayEventsList += "・" + TodayEvents[i] + "\n"
  }

例えばTodayEventsの中身が[test1,test2,test3]であれば
TodayEventsListはString型で「・test1\n・test2\n・test3\n」という形になります

あとはこれらの変数をうまく結合してMadeMessage変数に代入するだけです

  MadeMessage = "おはようございます。今日は" + TodayWeather[0] + "、天気は" + TodayWeather[1] + "、最高気温は" + TodayWeather[3] + "度です。\n\n◎今日の予定\n" + TodayEventsList + "\n◎天気概要文\n" + TodayWeather[2]

クソ長1行ができたところで、文章の生成も終わりです。
console.logでMadeMessageを表示してみると以下のようになります

おはようございます。今日は2022-12-18、天気は晴時々曇、最高気温は11度です。

◎今日の予定
・特になし

◎天気概要文
 (概況文は長いので省略)

また、試しにGetEventsFunctionのgetEventsForDayの引数を2022/12/25、つまり今月のクリスマスにしてみました。

おはようございます。今日は2022-12-18、天気は晴時々曇、最高気温は11度です。

◎今日の予定
・クリスマス、死せ。

◎天気概要文
 (概況文は長いので省略)

ちゃんとクリスマスの予定が表示されました。大丈夫そうですね。

LINEのbotを作ろう

LINEのbotを作るにはLINE Messaging APIという仕組みを利用します
少しややこしいので、今回はこの記事を参考にします。

まずLINE Developersに登録し、チャネルを作成

友達追加とアクセストークン発行など、もろもろの設定を行います。

続いて、テキストを送信する関数を作りましょう。ここではSendMessageFunctionとします

function SendMessageFunction(){
  const token = "アクセストークン";

  const payload = {
    to: 'ユーザーID',
    messages: [
      { type: 'text', text: "Hello, World" }
    ]
  };

  const params = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      Authorization: 'Bearer ' + token
    },
    payload: JSON.stringify(payload)
  };

  UrlFetchApp.fetch("https://api.line.me/v2/bot/message/push", params);
}

ほぼコピペです。ドキュメント読むの面倒くさかったし。
要するに、必要なJsonのデータを作ってAPIに渡してるだけです。
7行目の"Hello, World"が送信するテキストの内容です
実行してみると、LINEにハローワールドが届きます

ちゃんと送信できました。
あとはテキストの内容を引数で指定できるようにして、SendMessageFunctionを他の場所から呼び出すだけです。

function SendMessageFunction(SendText){
  const token = "アクセストークン";

  const payload = {
    to: 'ユーザーID',
    messages: [
      { type: 'text', text: SendText }
    ]
  };

  const params = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      Authorization: 'Bearer ' + token
    },
    payload: JSON.stringify(payload)
  };

  UrlFetchApp.fetch("https://api.line.me/v2/bot/message/push", params);
}

こんな感じ。あとはMakeMessageFunctionの最後にこの関数を呼び出すコードを書いてプログラムは終了になります。

今回のプログラムコードの全文は以下の通りです。

function MakeMessageFunction(){
  let MadeMessage;
  let TodayEvents = GetEventsFunction();
  let TodayWeather = GetWeatherFunction();

  let TodayEventsList = "";
  for(let i = 0;i < TodayEvents.length;i++){
    TodayEventsList += "・" + TodayEvents[i] + "\n"
  }

  MadeMessage = "おはようございます。今日は" + TodayWeather[0] + "、天気は" + TodayWeather[1] + "、最高気温は" + TodayWeather[3] + "度です。\n\n◎今日の予定\n" + TodayEventsList + "\n◎天気概要文\n" + TodayWeather[2]
  
  SendMessageFunction(MadeMessage);
}

function GetEventsFunction() {
  const myCalendar = CalendarApp.getCalendarById("メアド")
  const today = new Date;
  const myEvents = myCalendar.getEventsForDay(today);
  if(myEvents[0] === undefined){
    return ["特になし"];
  } else {
    let ReturnData = [];
    for (let i = 0;i < myEvents.length;i++){
      ReturnData[i] = myEvents[i].getTitle();
    }
    return ReturnData;
  }
}

function GetWeatherFunction(){
  const API_Data = JSON.parse(UrlFetchApp.fetch("https://weather.tsukumijima.net/api/forecast/city/130010").getContentText());

  let WeatherData = [];
  {
    WeatherData[0] = API_Data["forecasts"][0]["date"] //予報日
    WeatherData[1] = API_Data["forecasts"][0]["telop"] //天気
    WeatherData[2] = API_Data["description"]["bodyText"] //天気概況文
    WeatherData[3] = API_Data["forecasts"][0]["temperature"]["max"]["celsius"] //最高気温
  }
  return WeatherData;
}

function SendMessageFunction(SendText){
  const token = "アクセストークン";

  const payload = {
    to: 'ユーザーID',
    messages: [
      { type: 'text', text: SendText }
    ]
  };

  const params = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      Authorization: 'Bearer ' + token
    },
    payload: JSON.stringify(payload)
  };

  UrlFetchApp.fetch("https://api.line.me/v2/bot/message/push", params);
}

あとはMakeMessageFunctionをトリガーに設定して終わりです。

これで完成です。お疲れ様でした。

最後に

Google Apps ScriptはJavaScriptがベースの言語で、文法もほとんど一致しています。

私が初めて覚えたコードを書くプログラミング言語はJavaScriptです。
他の言語の会得には挫折してきましたが、この言語はシンプルなので入門としていいのではないかなと個人的には思います。
これを機に、皆さんもプログラマーデビューしてみてください。

この記事は有料区間が存在しない有料記事となっています。
お金を払っても読者様には何も起こりませんが、もしよければ投げ銭感覚でポチって頂けると幸いです。

それでは、最後までご精読ありがとうございました。

ここから先は

0字

¥ 200

この記事が気に入ったらサポートをしてみませんか?