天気予報で今日が何度かを見ても「で、昨日より暑いの?寒いの?」となるので、差分を取って GAS で Slack に通知することにした。
やりたいこと
- 今日の 12:00 頃の気温と前日の 12:00 頃の気温の差分が知りたい
- 12:00 頃はごはんを食べた後のお散歩で一番外に出る可能性が高いから
- 気温差分の通知は朝欲しい
- 着替える前に知りたいから
- 前日の気温は実績値でほしい
OpenWeatherMap の Free plan で事足りそうなのでこれを使うことにした。
取得したい値
- 毎日 12:00 頃の現在の気象データ
- 翌日の気温差分を計算するときに前日の実績値として欲しいから
- Current weather data - OpenWeatherMap でとれる
- 差分計算のために Google Sheets に保存する
- 当日 12:00 頃の予報データ
- 朝 Slack で通知したいときにとってきたらよい
- 5 day weather forecast - OpenWeatherMap でとれる
OpenWeatherMap の使い方
OpenWeatherMap でアカウント登録して、API Key を作成して、取得したい地点の緯度経度が分かれば良い。緯度経度は自分で調べても良いが Geocoding API - OpenWeatherMap で調べることもできる。
秩父麦酒とイチローズモルトが好きなので、緯度経度は西武秩父駅にした。
curl "https://api.openweathermap.org/data/2.5/weather?lat=35.9899&lon=139.0833&units=metric&appid={API_KEY}"
{ "coord": { "lon": 139.0833, "lat": 35.9899 }, "weather": [ { "id": 800, "main": "Clear", "description": "clear sky", "icon": "01n" } ], "base": "stations", "main": { "temp": 1.17, "feels_like": -1.33, "temp_min": 0.86, "temp_max": 1.97, "pressure": 1026, "humidity": 38, "sea_level": 1026, "grnd_level": 996 }, "visibility": 10000, "wind": { "speed": 2.21, "deg": 254, "gust": 2.3 }, "clouds": { "all": 0 }, "dt": 1705414807, "sys": { "type": 2, "id": 73731, "country": "JP", "sunrise": 1705355605, "sunset": 1705391536 }, "timezone": 32400, "id": 1864637, "name": "Chichibu", "cod": 200 }
やったこと
// OpenWeatherMap の URL を生成する function buildUrl(apiName) { const apiKey = PropertiesService.getScriptProperties().getProperty('OWM_API_KEY') const lat = 35.9899 const lon = 139.0833 return `https://api.openweathermap.org/data/2.5/${apiName}?lat=${lat}&lon=${lon}&units=metric&appid=${apiKey}` } // OpenWeatherMap の API を叩いてレスポンスを JSON で返す function callApi(apiName) { const url = buildUrl(apiName) const response = UrlFetchApp.fetch(url) return JSON.parse(response) } // 今の気温 (実績値) をとってくる function fetchCurrentTemp() { const json = callApi("weather") return json["main"]["temp"] } // 気温を保存しているセルを取得する function getTempCell() { return SpreadsheetApp.getActiveSpreadsheet().getSheetByName("temp").getRange("A1") } // 今日の気温 (実績値) を保存する (cron で毎日 12:00 頃に実行する) function saveTodayTemp() { getTempCell().setValue(`${fetchCurrentTemp()}`) } // 前日の実績気温をとってくる function getYesterdayTemp() { return getTempCell().getValue() } // 当日 12:00 の予報の気温をとってくる function fetchTodayForecastTemp() { const json = callApi("forecast") const today = new Date() const year = today.getFullYear() const month = today.getMonth() + 1 const date = today.getDate() + 1 const forecastUtcTime = Date.parse(`${year}-${month}-${date} 03:00:00 GMT`) / 1000 const forecast = json["list"].find((item) => { return item["dt"] === forecastUtcTime }) return forecast["main"]["temp"] } // 通知するメッセージを生成する function buildMessage(todayForecastTemp, yesterdayTemp) { const tempDiff = Number.parseFloat(todayForecastTemp - yesterdayTemp).toFixed(1) const sign = (tempDiff > 0) ? '+' : '' return `今日は昨日と比べて ${sign}${tempDiff} 度だよ!` } // Slack に通知する function sendSlack(message) { const token = PropertiesService.getScriptProperties().getProperty('SLACK_TOKEN') UrlFetchApp.fetch("https://slack.com/api/chat.postMessage", { method: "POST", payload: { token: token, channel: "#general", text: message, username: "name", icon_url: "https://example.com/icon.png", } }) } // 気温差分を Slack に通知する (cron で毎日 08:00 頃に実行する) function reportTempDiff() { const todayForecastTemp = fetchTodayForecastTemp() const yesterdayTemp = getYesterdayTemp() sendSlack(buildMessage(todayForecastTemp, yesterdayTemp)) }
あとは saveTodayTemp
と reportTempDiff
をトリガーに登録しておわり。
OpenWeatherMap では体感温度の取得もできるので、もしかしたら体感温度のほうが良いかもしれない。そのうち考える。
なお、アプリの名前は天気予報ということでモネになりました。