【GAS】天気予報をslackに通知する

どんな感じのものかは↓のtweetのスレッドを見てもらえばイメージできると思う。

季節の変わり目ということもあり、日々の気温が気になる。

そうだ、slackに天気や気温を日々通知するようにしよう!と思い立ち、いくつかのサイトを見ながら天気予報をslackに通知するようにしてみた。

// 今日の天気をslackに通知
function weatherForecastToday() {
  var dateType = 0;
  weatherForecast(dateType);
}

// 明日の天気をslackに通知
function weatherForecastTomorrow() {
  var dateType = 1;
  weatherForecast(dateType);
}

function weatherForecast(dateType) {

  var response = UrlFetchApp.fetch("http://weather.livedoor.com/forecast/webservice/json/v1?city=130010"); //URL+cityID
  var json = JSON.parse(response.getContentText());

  var publicTime = json.publicTime //発表時間

  // dateTypeに応じて、今日か明日の天気予報データを取得する
  if(dateType === 0) {
    var forecastData = json.forecasts[0];
  }else{
    var forecastData = json.forecasts[1]; 
  }  
  var date = forecastData.date; // 予報の日付
  var telop = telopMessage(forecastData.telop); //天気(例: 晴れ)

  //気温: 取れないときがあるので制御する
  if(forecastData.temperature.min !== null) {
    var tempMin = forecastData.temperature.min.celsius; // 最低気温
  } else {
    var tempMin = "- "
  }

  if(forecastData.temperature.max !== null) {
    var tempMax = forecastData.temperature.max.celsius; // 最高気温
  } else {
    var tempMax = "- "
  }
  
  if(dateType === 0){
    var dateMessage = ":red_circle: 今日の天気\n"
  }else{
    var dateMessage = ":large_blue_circle: 明日の天気\n"
  }

  // メッセージ文を作成してslackに送信
  var messageBody =  dateMessage + date + "の天気: " + telop + "\n最低気温: " + tempMin + "℃" + " 最高気温: " + tempMax + "℃" + "\n\n発表時間:" + publicTime;
  sendSlackMessage(messageBody);
}

//天気の文字列を見て、絵文字を追加する
function telopMessage(telop) {
  switch (telop) {
    case "晴時々曇":
      return telop = ":sunny:→:cloud: " + telop;
      break;
    case "曇り":
      return telop = ":cloud: " + telop;
      break;
    case "曇時々雨":
      return telop = ":cloud:→:rain_cloud: " + telop;
      break;
    case "晴れ":
      return telop = ":sunny: " + telop;
      break;
    default:
      return telop;
  }
}

function sendSlackMessage(message) {

  var postUrl = 'https://hooks.slack.com/***********'; 
  // postUrl の設定はここを参照した https://qiita.com/chihiro/items/c7b11abc78f5d806c3a8
  var username = '天気bot';  // 通知時に表示されるユーザー名
  var icon = ':mostly_sunny:';  // 通知時に表示されるアイコン
  var jsonData =
  {
     "username" : username,
     "icon_emoji": icon,
     "text" : message
  };
  var payload = JSON.stringify(jsonData);
  var options =
  {
    "method" : "post",
    "contentType" : "application/json",
    "payload" : payload
  };
  UrlFetchApp.fetch(postUrl, options);
}


最初は 今日の天気を通知する関数と、明日の天気を通知する関数のそれぞれでほぼ同じコードを書いていたのでどちらからも利用できるように別の関数に切り出すなどにチャレンジしてみた。

あとは
– 今日の天気を起床する時間帯に通知
– 明日の天気を就寝前の時間帯に通知
するようにトリガーで設定した。

これで前日との気温差に敏感になって、服装選びも失敗しにくいはずだ。

スプレッドシートに特定の文字列が出現したらSlackに通知するGoogleAppScript

スプレッドシートで試算などを行っているときに、「いつの間にか数式が壊れてることに気づかずそのまま作業を進めてしまい死…」みたいなことがあるので、防止する仕組みを作ってみることにした。

仕組み

  1. 検算用のセルを用意しておき、数値が合わないときは特定の文字列を出すようにしておく
    • このセルとこのセルの数値は必ず一致するという部分に =if(A1=B1,"OK","NG【要確認】") を仕込んでおく
  2. 特定文字列(ここではNG【要確認】)がスプレッドシート内にあるということは、何かしら問題が起きているということなので、Slackで自分宛てにmentionする
    • 手動で実行だと実行すること自体を忘れてしまうので、GASのトリガーでn分おきにスクリプトを実行する設定をしておくことで自動化する

特定文字列をチェックするスクリプト

function checkCell() {
  // スプレッドシートを指定
  var spreadshseet = SpreadsheetApp.openById('***********')
  var numSheets    = spreadshseet.getNumSheets();

  //チェックする文字列を定義
  var reg = "NG【要確認】";

  loop:
  for(var sheetNo = 0; sheetNo <= numSheets-1; sheetNo++) {
    SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[sheetNo];
    var sheetName = SpreadsheetApp.getActiveSpreadsheet().getSheets()[sheetNo].getSheetName();
    var range = sheet.getDataRange();
    var values = range.getValues();

    for (var i = 0; i < values.length; i++) {
      var row = "";
      for (var j = 0; j < values[i].length; j++) {      
        if (values[i][j]) {    
          row = row + values[i][j];
          if (row.match(new RegExp(reg))) {
            var messageBody = "<@U8LPZ1BBP>" + sheetName + "シートの" + i + "行目でセルの差異チェックがNGになってるよ";
            sendSlackMessage(messageBody);
            break loop;
          }
        }
      }
    }
  }
}

function sendSlackMessage(message) {
  var postUrl = 'https://hooks.slack.com/services/******';
  var username = 'bot';  
  var icon = ':hatching_chick:';  
  var jsonData =
  {
     "username" : username,
     "icon_emoji": icon,
     "text" : message
  };
  var payload = JSON.stringify(jsonData);
  var options =
  {
    "method" : "post",
    "contentType" : "application/json",
    "payload" : payload
  };
  UrlFetchApp.fetch(postUrl, options);
}

スクリプトのトリガーを設定する

これで10分おきにチェックするようになり、特定文字列を発見したら、Slackに通知してくれるようになった。

GASとSlackの連動は便利だなあ。

参考にしたサイト

【Googleスプレッドシート】GoogleAppScript (GAS)で参照元のセルにジャンプするショートカットを実現する

Googleスプレッドシートよりエクセルのほうが最高!と思うシーンは僕にとっては1つしかなくて

  • セルの参照元に command + { でジャンプできること

である。

参照元のセルにジャンプしたい、というのはこういうとき

予算管理をエクセルファイルでやってる都合上、参照元のセルにジャンプするショートカットには大変お世話になっていて、Googleスプレッドシートで同等の機能がないことに絶望していた。

ショートカットがないと何が辛いって、参照元のセル位置を見て忘れないように脳内に一時的に情報を保持しつつ目的のセルにたどり着かないといけないことだ。ましてや参照元が別のシートだったりすると発狂しそうだ。

2つのことを同時にやれるほど僕は器用にできてないので、GoogleAppScript を書いてみたら思いの外あっさり実現できた。

function JumpToDefinition() {

  // 現在のスプレッドシートを取得
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  // 現在のシートを取得
  var sheet = spreadsheet.getActiveSheet();
  // 参照元のセルの位置を取得する
  var value = sheet.getCurrentCell().getFormula().replace("=","");
  //該当のセルに移動する
  var objRange = sheet.getRange(value);
  objRange.activate();
}

GoogleAppScript自体はじめてつかったのだけど、見よう見まねで書いてみたらなんとかなるものだなあ。便利便利。