/*Google AdSense自動広告*/

2019年7月14日日曜日

GAS(Google Apps Script)で定期的なタスクをGoogleカレンダーに登録する~車のメンテナンス通知などに利用できます

我が家の車も12万キロを超えて、不具合は出ていませんが、メンテナンスが重要になってきました。オイル交換は早め早めに、車検時にはオーバーホール・部品交換を積極的にお願いしています。目指せ25万キロ!

とはいえ、インターバルの大きいメンテナンスは忘れがちです。スマホアプリでも作ってみようかと思いましたが、データはどこに保存する?機種変したら消える?PCやタブレットでも見るには?と考えるとハードルが高い…ということで、Googleスプレッドシートにリストを作って、実行するとGoogleカレンダーに一括登録してくれるスクリプトを組みました。

CalendarAppの操作、カレンダーの追加・削除、定期イベントの作成方法について解説するので、参考になさってください。














スクリプトのコード


 function putMyTaskToCalendar() {
 
///// SheetWrapper Class ver.1.0 without tableTopRowShift Light/////  
  // sheetId:スプレッドシートのURLからIdを指定
  // sheetName:スプレッドシートのシート名
  var SheetWrapper = function(sheetId, sheetName){
    this.sheet = SpreadsheetApp.openById(sheetId).getSheetByName(sheetName);
    var values = this.sheet.getDataRange().getValues();
   
    this.currentY = 1; // 行方向ポインタ
    this.maxX = values[0].length;
    this.maxY = values.length;
   
    // 列項目名->列毎データの連想配列を作成
    this.columns = {};
    for(var c = 0; c < this.maxX; c++){
     
      var item = values[0][c]; // 列項目名
      this.columns[item] = [c + 1]; // 先頭に列番号を格納
     
      for(var r = 1; r < this.maxY; r++){
        this.columns[item].push(values[r][c]);
      }      
    }
  };
 
  // 表操作関数    
  SheetWrapper.prototype = {
   
    getByItem : function(itemName){
      return this.columns[itemName][this.currentY];
    },
       
    moveNext : function(){this.currentY++;},
   
    EOF : function(){
      return this.currentY >= this.maxY;
    }
  };
///////////////////////////////////////////////////////////////////
 
  /// MAIN ///
  const THIS_CALENDAR_NAME = 'myTaskByGAS';
  const SHEET_ID = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
  var taskSheet = new SheetWrapper(SHEET_ID, 'MAIN');
 
  // delete and create calender
  var calendars = CalendarApp.getCalendarsByName(THIS_CALENDAR_NAME);
  if(calendars.length > 0){
    calendars[0].deleteCalendar();
  }
  
  var calendar = CalendarApp.createCalendar(THIS_CALENDAR_NAME);
 
  // create events
  while(!taskSheet.EOF()){
   
    var title = taskSheet.getByItem('作業内容');
    var startDate = new Date(taskSheet.getByItem('開始日'));
    var endDate = new Date(taskSheet.getByItem('終了日'));
    var interval = taskSheet.getByItem('頻度(値)');    
    var recurrence;
   
    switch(taskSheet.getByItem('頻度(単位)')) {
      case '日':
        recurrence = CalendarApp.newRecurrence().addDailyRule()
        .interval(interval)
        .until(endDate);
        break;
        
      case '週':
        recurrence = CalendarApp.newRecurrence().addWeeklyRule()
        .interval(interval)
        .until(endDate);
        break;
        
      case '月':
        recurrence = CalendarApp.newRecurrence().addMonthlyRule()
        .interval(interval)
        .until(endDate);
        break;
        
      case '年':
        recurrence = CalendarApp.newRecurrence().addYearlyRule()
        .interval(interval)
        .until(endDate);
        break;
        
    }
     
    calendar.createAllDayEventSeries(title, startDate, recurrence);
   
    taskSheet.moveNext();
  }
}


スクリプトの解説


SheetWrapper Class


以前作成した(リンク)、スプレッドシートを配列に格納し、列名検索やmoveNextで回せるクラスです。もうね、これは何列目とか、配列のインデックスだから0から始まるとか、覚えてられない年頃なのです(笑)。

setValue等は使わないので、省きました。クラス(function)を共有するにはライブラリ化という手もありますが、ちょこちょこといじるので、それぞれのFunction内に書く形にしています。


SheetWrapperの初期設定


SheetWrapperは、IDとシート名で初期設定を行います。IDはブラウザでスプレッドシートのURLを見て、
https://docs.google.com/spreadsheets/d/xxxxxx/edit#gid=0
xxxxxxの部分をコピペします。


CalendarApp.getCalendarsByName(), deleteCalendar(), createCalendar()


Googleカレンダーは、Gmailに紐づいたマイカレンダーに、「日本の祝日」「誕生日」などの予定を重ねて表示できます。デフォルトのマイカレンダーは、getDefaultCalendar()で取得できますが、ここにイベントを追加すると、後で消す時に面倒なので、新しいカレンダーを作成することにしました。表示するには、アプリやブラウザの設定でチェックを付けます。

カレンダーにはユニークな名前を付けます。本来、カレンダーの名前はユニークである必要が無く、IDがユニークであればいいため、getCalendarsByName()はカレンダーを配列として返します。しかし、IDは確認が面倒で使い辛いため、「他で使わなそうな名前」をユニークな値として使うことにします。また、そのカレンダーを削除してから新たに追加することで、リストを空にすると予定を全消去できるようにしました。

※自分以外のカレンダー(他人や、別のGmailアドレス)に追加・削除はできない仕様です


SheepWrapperの行毎処理


スプレッドシートをSheetWrapperに入れてしまえば、最終行などの判定不要で、whileとmoveNextで1行ずつ処理できます。
while(!taskSheet.EOF()){
  //処理
  taskSheet.moveNext();
}


recurrenceの作成


recurrenceは繰り返すを表すオブジェクトです。この後でイベントを作成しますが、その引数に使用します。CalendarApp.newRecurrence()で作成し、ピリオドで繋いで下記オプションを加えていきます。

  • addDailyRule() (Weekly, Monthly, Yearly)
スプレッドシートで「日、週、月、年」と選ぶことができるようにしておき、switch文で関数を選びます(引数で指定出来たらswitch不要なのに…)。



  • interval(interval)
スプレッドシートで入力した数値をそのまま入れます。これで、「3週間に一回」「6ヵ月に一回」といった、頻度の指定が作成できます。



  • until(endDate)
エンドレスなイベントで無い限り、どこかで止めなければいけません。endDateはここで指定しますが、startDateはイベント作成関数の引数であることに注意です(1時間くらい探してしまった…)。車のメンテナンスに使うならば、startDateは今日でなく、前回交換日となります。



createAllDayEventSeries(title, startDate, recurrence)


引数の準備はできているので、実行すれば定期的なイベントがカレンダーに追加されます。こちらは終日イベントですが、時間指定するcreateEventSeries()もあります。今回は時間が重要でないので、前者を使いました。また、引数にoptionsオブジェクトを加えると、場所などの詳細情報を登録できます。



シート作成のTips~データの入力規制&図形にスクリプトを登録


データの入力規制


頻度の単位については、switch文で分岐しているので、想定外の値を入力されると動作しません。そこで、「日、週、月、年」のみ入力できるよう、データの入力規制を追加します。











  1. 入力規制を追加したい範囲を選択
  2. メニュー データ → データの入力規制
  3. リストを直接指定
  4. コンマ「,」区切りで値を入力 


図形にスクリプトを登録する


スクリプトの実行は、コード入力画面からもできますが、普段使うには面倒です。
そこで、スプレッドシートの図形にスクリプトを割り当てます。これはExcelにもある機能ですね。





図形を作成した後、右上の「...(縦)」ボタンを押し、スクリプトを割り当てをクリックします。ここで、function名(function xxxxxxxxxxxxx()の部分)をコピペで入力します。選択できないのが面倒な仕様ですが。



まとめと展望


プラグなどは、距離数に応じて交換となりますが(でも車の一生に2回程度だろう)、この表では指定できません。年間走行距離を入力し、おおよその期間を計算できれば、インターバルを計算できるでしょう。


先にも書きましたが、スクリプト毎、用途毎にカレンダーを作成し、重ねて表示する仕様をおすすめします。プログラムのミスで大量の予定を作ってしまうと、悲惨なことになりますので。

0 件のコメント:

コメントを投稿