地震情報を取得してSlackに通知したかったので、自分用にやったことをまとめました。
main.gs
/*
東京で震度5弱以上の地震が確認された場合に安否確認を行うシステムです。
*/
// Slackのトークン
const TOKEN = PropertiesService.getScriptProperties().getProperty('TOKEN');
// 地震情報のURL
const URL = PropertiesService.getScriptProperties().getProperty('URL');
const date = new Date();
// 震度5弱
const judgeLevel = 10;
// 投稿するチャンネル
const channelId = "#accall";
// エラー報告用チャンネル
const errorChannel = "#accfree";
// Main関数
async function main(){
// 地震情報を取得する
let info = await getInfo();
// 地震情報が発信対象か判定
let [time,maxElm,isSend] = judgeSend(info);
// 地震情報からメッセージを作成
if(isSend){
// Googleフォームを作成
let formUrl = createForm();
// 送信メッセージの作成
let message = createMessage([time,maxElm],formUrl);
// Slackにメッセージを送信
sendMessage(message);
console.log("【正常終了】地震情報あり");
}else{
console.log("【正常終了】地震情報なし");
};
}
// 地震情報を取得
async function getInfo(){
let result = new Array();
let data = new Array();
try{
let res = await UrlFetchApp.fetch(URL).getContentText('UTF-8');
let json = JSON.parse(res);
let date = json['Head']['ReportDateTime'];
while(date.includes('-')){
date = date.replace('-','/');
}
date = new Date(date);
result.push(date);
json['Body']['Intensity']['Observation']['Pref'].forEach(elm =>{
let obj = new earthquakeInfoModel(changeLevel(elm['MaxInt']),elm['Name']);
data.push(obj);
});
result.push(data);
}catch(err){
sendErr(err);
deleteTrigger();
writeLog(err);
}
return result;
};
// 地震情報から過去5分以内、かつ関東の情報、かつ震度が5弱以上のものがあるかどうかを判定
function judgeSend(info){
// 5分をミリ秒に変換
const fiveMins = 5 * 60 * 1000;
const KANTO = ["東京都","埼玉県","神奈川県","千葉県","群馬県","茨城県","栃木県"];
let maxElm = new earthquakeInfoModel(0,null,null);
let isSend = false;
let result = new Array();
let time = null;
try{
time = Utilities.formatDate(info[0], 'Asia/Tokyo', 'yyyy-MM-dd HH:mm:ss');
info[1].forEach(elm=>{
if((date - fiveMins) < info[0]){
if(KANTO.includes(elm.place)){
if(elm.level >= judgeLevel){
if(maxElm.level < elm.level){
maxElm = elm;
isSend = true;
};
};
};
};
});
}catch(err){
sendErr(err);
deleteTrigger();
writeLog(err);
}
return [time,maxElm,isSend];
}
// 地震情報からメッセージを生成
function createMessage([time,maxElm],formUrl){
let notifyEveryone = "<!everyone>\n"
let message = notifyEveryone.concat(PropertiesService.getScriptProperties().getProperty('MESSAGE').concat("\n",formUrl));
while(message.includes('</br>')){
message = message.replace('</br>', '\n');
}
return message.replace("<time>",time).replace("<place>",maxElm.place).replace("<level>",convertScale(maxElm.level));
}
// Googleフォームの生成
function createForm(){
const folderName = "安否確認";
let targetFolder;
let title = "【安否確認】"+ date.toLocaleString('ja-JP');
let desc = "安否確認用フォームです。 \n24時間以内に回答してください。";
let question1 = "社員番号";
let question2 = "氏名";
let question3 = "被害状況"
let question3Ans= ["無事","被害あり"];
let question4 = "現在地";
let question5 = "伝達事項";
try{
// フォームの作成
let form = FormApp.create(title);
form.setTitle(title);
form.setDescription(desc);
form.addTextItem().setTitle(question1).setRequired(false);
form.addTextItem().setTitle(question2).setRequired(true);
form.addMultipleChoiceItem().setTitle(question3).setChoiceValues(question3Ans).setRequired(true);
form.addTextItem().setTitle(question4);
form.addTextItem().setTitle(question5);
// 作成したフォームを「安否確認」フォルダに移動
let formId = DriveApp.getFileById(form.getId());
let folderIter = DriveApp.getRootFolder().getFoldersByName(folderName);
if(folderIter.hasNext()){
targetFolder = folderIter.next();
}else{
targetFolder = DriveApp.getRootFolder().createFolder(folderName);
}
targetFolder.addFile(formId);
DriveApp.getRootFolder().removeFile(formId);
return form.shortenFormUrl(form.getPublishedUrl());
}catch(err){
sendErr(err);
deleteTrigger();
writeLog(err);
}
}
// Slackにメッセージを送信
function sendMessage(message){
// ライブラリから導入したSlackAppを定義し、トークンを設定する
let slackApp = SlackApp.create(TOKEN);
try{
// SlackAppオブジェクトのpostMessageメソッドでボット投稿を行う
slackApp.postMessage(channelId, message);
}catch(err){
sendErr(err);
deleteTrigger();
writeLog(err);
}
}
// 受信した震度を数値に置き換える(比較するため)
function changeLevel(level){
switch(level){
case "1":
return 10;
case "2":
return 20;
case "3":
return 30;
case "4":
return 40;
case "5-":
return 45;
case "5+":
return 50;
case "6-":
return 55;
case "6+":
return 60;
case "7":
return 70;
default:
return 999;
}
}
//震度を日本語表記に変換する
function convertScale(num){
switch(num){
case 10:
return "震度1";
case 20:
return "震度2";
case 30:
return "震度3";
case 40:
return "震度4";
case 45:
return "震度5弱";
case 50:
return "震度5強";
case 55:
return "震度6弱";
case 60:
return "震度6強";
case 70:
return "震度7";
default:
return "震度不明";
}
}
// Slackにエラーメッセージを送信
function sendErr(err){
// ライブラリから導入したSlackAppを定義し、トークンを設定する
let slackApp = SlackApp.create(TOKEN);
// 報告用エラーメッセージ
let message = "エラーが発生しました。\n".concat(err);
try{
// SlackAppオブジェクトのpostMessageメソッドでボット投稿を行う
slackApp.postMessage(errorChannel, message);
}catch(err){
sendErr(err);
deleteTrigger();
writeLog(err);
}
}
// エラー発生時にトリガーをすべて削除する
function deleteTrigger(){
let triggers = ScriptApp.getProjectTriggers();
writeLog("%s件のトリガーをすべて削除します。",triggers.length);
triggers.forEach(trg=>{
ScriptApp.deleteTrigger(trg);
});
}
// ログを出力する
function writeLog(log){
const sheetId = "1yrQDPyR9klug5p_oEsO71W8F77F_JgnVvfZP7SUp2wc";
let sheetName = "log_sheet"; // SpreadSheetName
// スプレットシートにログ出力
var MySheet = SpreadsheetApp.openById(sheetId);
MySheet.getSheetByName(sheetName).appendRow(
[new Date(), 'Log出力:',log]
);
}
earthquakeInfoModel.gs
/*
地震情報のModel
*/
class earthquakeInfoModel{
constructor(level,place,time){
this.level = level;
this.place = place;
this,time = time;
}
get getLevel(){
return this.level;
}
set setLevel(level){
this.level = level;
}
get getPlace(){
return this.place;
}
set setPlace(place){
this.place = place;
}
get getTime(){
return this.time;
}
set setTime(time){
this.time = time;
}
}
Crieitは個人で開発中です。
興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!