2022年6月6日月曜日

【GAS】2週間気温予報のデータをグラフ化して LINE で画像メッセージとして配信する

最近の天気は寒暖差が激しすぎて訳が分からないですね。

気象庁から提供されている2週間気温予報のデータを視覚的に一目で把握できるようにするため、スプレッドシートでグラフ化 → 画像メッセージとして LINE で配信する GAS(Google Apps Script)を作ってみました。


▼ スプレッドシートの準備

2週間気温予報のデータの入力、及びグラフ作成のためのスプレッドシートを準備します。

グラフの見出し用にB1からM1に順に「平均気温(予報)」「最高気温(予報)」「最低気温(予報)」「平均気温(平年値)」「最高気温(平年値)」「最低気温(平年値)」「平均気温(過去10年)」「最高気温(過去10年)」「最低気温(過去10年)」「平均気温(昨年)」「最高気温(昨年)」「最低気温(昨年)」と入力しておきます。

予報、平年値、過去10年、昨年についてそれぞれ平均気温、最高気温、最低気温なので計12列になります。


▼ スクリプトの作成

まずは2週間気温予報のデータの取得、グラフの作成・保存、LINEへのグラフ画像URLの受け渡し、グラフの削除(ゴミ箱移動)を行うためのスクリプトです。

今回はとりあえず予報についてのみ簡単な折れ線グラフを作成、配信するようになっています。

2週間気温予報のデータの取得には自作の Web API を利用しています。

function getTwoweekData() {
  const spreadsheet = SpreadsheetApp.openById("スプレッドシート ID");
  const twSheet = spreadsheet.getSheetByName("twoweek");

  //JSON データの取得
  let point = "地域(地点)番号";
  let url = "https://weather-nkkmd.herokuapp.com/twoweek?point=";
  url = url + point;
  let response = "";
  try {
    response = UrlFetchApp.fetch(url);
  } catch(e) {
    return response;
  }
  let data = JSON.parse(response.getContentText());

  //スプレッドシートに初期日と予報期間を入力
  let date = new Date([data["date"][0]]);
  let fcDate = new Date(date.setDate(date.getDate() + 2));
  let period = [];
  for(i = 0; i < 13; i++) {    
    period.push([Utilities.formatDate(fcDate, "JST", "MM/dd")]);
    fcDate = new Date(fcDate.setDate(fcDate.getDate() + 1));
  }
  twSheet.getRange(2, 1, 13, 1).setValues(period);

  //スプレッドシートに気温を入力
  let keys = Object.keys(data); 
  let twoweek = [];
  let temp = [];
  for(let x = 0; x < 13; x++) {
    for(let y = 1; y < 5; y++) {
      temp.push([data[keys[y]]["ave" + String(x)][0]]);
      temp.push([data[keys[y]]["hi" + String(x)][0]]);
      temp.push([data[keys[y]]["low" + String(x)][0]]);
    }
    twoweek.push(temp);
    temp = [];
  }
  twSheet.getRange(2, 2, 13, 12).setValues(twoweek);

  //折れ線グラフを作成
  const range = twSheet.getRange(1, 1, 14, 4);
  let chart = twSheet.newChart()
                .addRange(range)
                .asLineChart()
                .setNumHeaders(1)
                .setPosition(16,2,0,0)
                .setOption("title", "2週間気温予報")
                .build();
  twSheet.insertChart(chart);

  //折れ線グラフをドライブに保存
  let graph = twSheet.getCharts();
  let graphImg = graph[0].getBlob();
  let folder = DriveApp.getFolderById("フォルダ ID");
  let file = folder.createFile(graphImg.setName("graph"));
  file.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);

  //LINE 配信
  push(file.getDownloadUrl());

  //折れ線グラフの削除
  twSheet.removeChart(graph[0]);
  folder.getFilesByName("graph").next().setTrashed(true);
}

2行目の「スプレッドシート ID」、6行目の「地域(地点)番号」、56行目の「フォルダ ID」を記載します。フォルダはグラフ画像を一時的に保存する場所になります(LINE 配信後にゴミ箱に入ります)。

また、シート名は「twoweek」、作成するグラフ名は「graph」としています(適宜変更してください)。


つぎに LINE で画像メッセージをプッシュ通知で配信するためのスクリプトです。

const ACCESS_TOKEN = "チャンネルアクセストークン";

const PUSH = "https://api.line.me/v2/bot/message/push";

function push(img) {
  let postData = {
    "to" : "LINE ユーザー ID",
    "messages" : [
      {
        "type" : "image",
        "originalContentUrl" : img,
        "previewImageUrl" : img
      }
    ]
  };
  
  // リクエストヘッダ
  const headers = {
    "Content-Type" : "application/json; charset=UTF-8",
    "Authorization" : "Bearer " + ACCESS_TOKEN
  };
  
  // POSTオプション作成
  const options = {
    "method" : "POST",
    "headers" : headers,
    "payload" : JSON.stringify(postData)
  };

  return UrlFetchApp.fetch(PUSH, options);
}

1行目の「チャンネルアクセストークン」、7行目の「LINE ユーザー ID」を記載します。

LINE のユーザー ID は LINE ID とは異なります。不明な場合はこちら↓を参考に取得してください。



ということで、ひとまず完成です。


▼ 送ってみる


getTwoweekData 関数を実行することで、こんな感じで画像メッセージが配信されます。

今日とても寒いですが、一応今後上がっていく予報ですね。よかった……。

あとは、平年値との差なんかも分かるようにしたいですね。

トリガー設定をして、毎朝送られてくるようにしようかと思います。


***

LINE で画像メッセージをおくるためには JPG もしくは PNG ファイルの URL を指定しなければならないのですが、Google ドライブ内の画像ファイルから LINE で送信可能な URL をどう取得すればいいの分からず迷宮に入り込みました。

getUrl() ではだめ。結局、getDownloadUrl() でいけました。取得できる URL は JPG や PNG の拡張子付きではないのですが、なぜか大丈夫です。

自動でグラフ化からの画像メッセージはけっこう便利そうなので、覚えておくといろいろ使いどころがありそうです。





・関連投稿
【GAS】気象庁 API から取得した天気予報を LINE にプッシュ通知する

2週間気温予報のデータを取得するWeb APIを作りました。



Twitter(@nkkmd)日々更新中です。