#★使えなくなりました★
一般データ保護規則(GDPR)の関係でYahoo!のサービスが欧州から繋がらなくなりました。
GASから気象情報APIを叩くと「欧州からは使えねーよ」と403エラーが出るように…。
エラー出ない時もあるので、多分GASの接続元が欧州じゃない時もあるのかな?
接続元のリージョンを指定出来れば良いのですが…。そんなのあるのかな。
#作ったきっかけ
リアルタイムに「今から雨降るよ!!」って通知してくれるbotが欲しくて作りました。
前日や当日に一日の天気を通知するbotはちょこちょこあるんですが、リアルタイムに監視するbotがなかったので。
#まぁスマホアプリとかで簡単に実現出来ますけど
社内でGoogle Chatを活用して紙やメールを減らしていきましょうって流れがあり、
Google Chatを定期的に見る仕組みを用意したかったので…。
他にも社食のメニューをお知らせするbotとかもあります。
#ざっくりとした仕組み
気象情報APIはYahoo!のを使いました。
Yahoo! Open Local Platform(YOLP) 気象情報API
https://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/weather.html
気象情報APIから予報を取得
↓
スプレッドーシートに書き出す
↓
前回と今回の取得時の観測値に変化があったら
「雨がやみました/降り始めました」と通知
↓
現在の観測値と15分後の天気を比べて差があったら
「雨がやみそうです/降り始めそうです」と通知
↓
メッセージと一緒に雨雲レーダーの画像チャットにポスト
↓
15分毎にループする
#気象情報APIの使い方
APIを使うためにはアプリケーションIDを取得する必要があります。
https://e.developer.yahoo.co.jp/register
アプリケーションの種類はサーバーサイドで良いっぽい。
天気を知りたい場所の緯度、経度、取得したアプリケーションIDを以下のように記述して使います。
https://map.yahooapis.jp/weather/V1/place?coordinates=<経度>,<緯度>&appid=<アプリケーションID>
#スプレッドシート
こんな感じにしてます。
実行時刻と観測時刻を見比べて貰ったら分かると思いますが、結構ラグがあります。
☆残念なお知らせ☆
【重要】YOLP Web APIにおける一部API・SDK 提供終了のお知らせ
雨雲レーダーのAPIは2020/10/31で提供終了になるそうです。代替サービスあるんか…?
終了しちゃったらImageなしで通知するしかないですね。
#コード
//YOLPのapiを叩くのに必要なパラメータ
let appId = "<取得したAPIのAPP ID>";
let lon = "139.7649361"; //経度
let lat = "35.6812362"; //緯度
let interval = 5; //予報の間隔(分)
let apiUrl = "https://map.yahooapis.jp/weather/V1/place?coordinates=" + lon + "," + lat + "&output=json&appid=" + appId + "&interval=" + interval;
//Google ChatのWebhook
let webhookUrl = 'https://chat.googleapis.com/v1/spaces/~';
//スプシとシートの設定
let spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
let sheet = SpreadsheetApp.getActiveSheet();
function getJson() {
//お天気api叩く
let response = UrlFetchApp.fetch(apiUrl);
//let response = spreadSheet.getSheetByName('シート3').getRange('A1').getValue();
let date = '';
let rainfall = '';
let previouszObservation = sheet.getRange(3,3).getValue(); //前回天気を確認した時の雨量
let currentObservation = '';
let after15minForecast = '';
let minDiff = '';
let now = new Date();
let str = '';
//現時刻を書き込み
sheet.getRange(1,2).setValue(Utilities.formatDate( now, 'Asia/Tokyo', 'HH:mm'));
Logger.log(response.getContentText());
//JOSNオブジェクトに変換
let json=JSON.parse(response.getContentText());
//観測結果と5分毎の予報を取得(13回)
for(let i=0;i<=12;i++){
//JSONから日時を取得
date = json['Feature'][0]['Property']['WeatherList']['Weather'][i]['Date'];
//'yyyy/MM/dd hh:mm'に変換
date = date.slice(0,4)+'/'+date.slice(4,6)+'/'+date.slice(6,8)+' '+date.slice(8,10)+':'+date.slice(-2);
//雨量を取得
rainfall = json['Feature'][0]['Property']['WeatherList']['Weather'][i]['Rainfall'];
//type = json['Feature'][0]['Property']['WeatherList']['Weather'][i]['Type'];
//日時と雨量を書き出す
sheet.getRange(i+3,2).setValue(date);
sheet.getRange(i+3,3).setValue(rainfall);
}
//現在の観測雨量
currentObservation = sheet.getRange(3,3).getValue();
//観測時刻から25分後の予測雨量
//apiを叩くと約10分前の観測と予報が得られるので、api叩いた時刻の15分後の予報が知りたい時はJSONから25分後のデータを取る
after15minForecast = sheet.getRange(8,3).getValue();
//観測から25分後の時刻と、スクリプト実行時刻との時間差を計算
minDiff = String(Math.round((sheet.getRange(8,2).getValue() - now)/60000)); //単純に引き算するとミリ秒で出て来るので60000で割ると分になる
//雨の観測結果の変化チェック
if(previouszObservation!=currentObservation){ //前回の雨量と現在の雨量が一致しない時
if(currentObservation==0){ //現在の雨量が0なら
str += '雨がやみました。';
}else if(previouszObservation==0) { //前回の雨量が0なら
str += '雨が降り始めました。';
}
}
//約15分後の予報チェック
//現在の雨量と15分後の雨量の差異で判断
if(currentObservation==0){
if(after15minForecast>0){
if(str!=''){
str += '<br>';
}
str += '約' + minDiff + '分後に雨が降り始めるようです。'
}
}else {
if(after15minForecast==0){
if(str!=''){
str += '<br>';
}
str += '約' + minDiff + '分後に雨がやむようです。'
}
}
Logger.log(str);
Logger.log('前回の観測値:'+ previouszObservation);
Logger.log('今回の観測値:'+ currentObservation);
Logger.log('15分後の予報:'+ after15minForecast);
//通知内容があればGoogle Chatにpost
if(str!=''){
let payload = {
"cards": [
{
"sections": [
{
"widgets": [
{
"textParagraph": {
"text": str
}
},
{
"image": { "imageUrl": "https://map.yahooapis.jp/map/V1/static?appid="+ appId + "&lat=" + lat + "&lon=" + lon + "&z=11&width=300&height=200&pointer=on&overlay=type:rainfall|date:"+Utilities.formatDate( now, 'Asia/Tokyo', 'yyyyMMddHHmm') }
},
{
"buttons": [
{
"textButton": {
"text": "雨雲レーダーを見る",
"onClick": {
"openLink": {
"url": "https://weather.yahoo.co.jp/weather/zoomradar/?lat=" + lat + "&lon="+ lon + "&z=12"
}
}
}
}
]
}
]
}
]
}
]
};
let options = {
"method" : "POST",
"contentType" : 'application/json; charset=utf-8',
"payload" : JSON.stringify(payload)
};
//Google Chatにポスト
let dayOfWeek = now.getDay();
let hour = now.getHours();
//土日じゃない&7時~21時の時チャットに通知
if(dayOfWeek != 0 && dayOfWeek != 6){
if(hour>6 && hour<22){
UrlFetchApp.fetch(webhookUrl, options);
}
}
}
}
職場にいない時に通知されるのも邪魔なので、土日と夜間/早朝は通知しないようにしています。
#作ってみて
天気予報の精度に因るところもあるんですけど、結構「降りそう」って通知があっても降らなかったりとか外れる事も多いです。笑
あと、Google Chatのカード形式メッセージを初めて使ってみました。
見た目がシュッとするので良い感じですね。(もうちょっと自由度欲しいけど)