PR

《卒FIT》ポータブル電源自動充電システム – GoogleAppScript(GAS) プログラムの定期実行編

住宅関連
記事内に広告が含まれています。

前回は、ポータブル電源自動充電システムのパススルー問題とその解決方法について記載しました。

これまでの記事で、自動で余剰電力(本来売電するはずだった電気)のみをポータブル電源に充電するプログラムは組み上げることが出来るはずです。

ただ、ポータブル電源自動充電システム として常時稼働させるためには、プログラムを定期的に起動させてあげる必要があります。

今回はGAS(Google Apps Script)を利用して、プログラムを定期的に実行する方法を解説します。

ちなみにポータブル電源自動充電システムのシステム構成とメリット・デメリットについては、以下の記事で紹介しています。

  • 本記事を参考に同等の機能を実現しようとする場合、どのような不具合が発生しようとも責任は負えません。
  • あくまで自己責任の範囲で作業してください。

Google Apps Script の トリガー

Google Apps Script(GAS)には、任意のタイミングでプログラムを起動させる機能として「トリガー」があります。

簡易的な定期実行であれば、このトリガーを設定するだけで実現が可能です。

以下のタイミングでプログラムを実行させるように設定することができます。

スプレッドシートから
  • 起動時
  • 編集時
  • 変更時
  • フォーム送信時
時間主導型
特定の日時
  • YYYY-MM-DD HH:MM
分ベースのタイマー
  • 1分おき
  • 5分おき
  • 10分おき
  • 15分おき
  • 30分おき
時間ベースのタイマー
  • 1時間おき
  • 2時間おき
  • 4時間おき
  • 6時間おき
  • 8時間おき
  • 12時間おき
日付ベースのタイマー
  • 午前0時~1時
  • 午前1時~2時
  • 午前2時~3時
  •  …
  • 午後9時~10時
  • 午後10時~11時
  • 午後11時~午前0時
週ベースのタイマー
  • 毎週月曜日のX時~Y時
  • 毎週火曜日のX時~Y時
  • 毎週水曜日のX時~Y時
  • 毎週木曜日のX時~Y時
  • 毎週金曜日のX時~Y時
  • 毎週土曜日のX時~Y時
  • 毎週日曜日のX時~Y時
月ベースのタイマー
  • 1日のX時~Y時
  • 2日のX時~Y時
  • 3日のX時~Y時
  •  …
  • 30日のX時~Y時
  • 31日のX時~Y時
カレンダーから
  • カレンダー更新済み

トリガーの作成

トリガーはGoogle Apps Scriptの画面上から簡単に設定することが可能です。
以下の画像では1分ごとに動くトリガーを設定しています。

これだけで、ポータブル電源自動充電システムのプログラムを1分に1回、定期的に動かすことが出来ます。

トリガーのデメリット

上記の通り、とても簡単に設定できるGASのトリガー機能ですが、デメリットもあります。
それは1分より短い間隔では起動できない点になります。

これをデメリットと考えるかどうかは人それぞれですが、本ブログで紹介しているポータブル電源自動充電システムを考えた時にはもう少し短い間隔で動かせると嬉しいです。

ソーラーパネルの発電量を気にしている方であればわかると思いますが、たった1分の間でも発電する量は結構変動します。

空を流れる雲の動きに合わせて発電量は随時変わります。
それに加え、家庭で使用する電力量も随時変わりますので、私自身がポータブル電源自動充電システムを運用している感覚からして、1分ごとの判断では若干遅いと思っていました。

プログラムの起動間隔が長くなると、その分余剰電力量の判断に遅れが出ます。
たった1分の間ですが、本来であれば充電できるのに売電してしまったり、すでに曇っていて余剰電力がないのに充電を続けてしまったりすることになります。

Google Apps Scriptでプログラムを1分より短い間隔で起動する方法

ではGASを利用して1分より短い間隔でプログラムを動作させるためにはどうすれば良いのか?ですが、一定期間で定期的に動作させるためにはトリガーを利用するのは必須だと思います。

注目した点の1つ目は、トリガー自体は複数設定することが可能というところです。
(1分おきに動作するトリガーを2つとか3つとか作ることが出来ます)

2つ目は、GAS(Google Apps Script)には処理を一定期間待機させるスリープのメソッドが用意されていることです。

上記の2つを組み合わせることで、実現が可能です。

例えば、プログラムを1分間に2回動作させたいとします(つまり30秒おき)
この場合は、1分おきに動作するトリガーを2つ定義します。

1つ目のトリガーは、起動した時間の次のXX分00秒までスリープして、XX分00秒になったら本来行いたい処理を実行します。
(例えば 12時01分10秒 にトリガー起動されたプログラムは、12時02分00秒までスリープしてから処理を開始します)

2つ目のトリガーは、起動した時間の次のXX分30秒までスリープして、XX分30秒になったら本来行いたい処理を実行します。
(例えば 12時01分10秒 にトリガー起動されたプログラムは、12時01分30秒までスリープしてから処理を開始します)

上記の例では、12時01分30秒 と 12時02分00秒 に本来行いたい処理が実行されます。
これがトリガーで繰り返されることで『30秒おき』が実現できます。

同じように『20秒おき』であればトリガーを3つ用意して、それぞれ以下の通りスリープすれば良いことになります。

  • トリガー①:次のXX分00秒までスリープ
  • トリガー②:次のXX分20秒までスリープ
  • トリガー③:次のXX分40秒までスリープ

トリガーはプログラムからも追加、削除が可能

トリガーは画面から作成するだけでなく、プログラムからも追加や削除が可能です。
上で紹介した『20秒おき』に起動するためのコードを実装したものが以下になります。

function createTrigger() {

  // 一旦トリガーを削除
  deleteTrigger("main1");
  deleteTrigger("main2");
  deleteTrigger("main3");

  // 1分間隔のトリガーを追加
  ScriptApp.newTrigger('main1').timeBased().everyMinutes(1).create();
  ScriptApp.newTrigger('main2').timeBased().everyMinutes(1).create();
  ScriptApp.newTrigger('main3').timeBased().everyMinutes(1).create();
}

main1、main2、main3 の 3つのメソッド(function)を用意し、それぞれ1分ごとのトリガーを設定しています。

トリガーから呼び出されるmain処理のコードは以下のようになっています。

/**
 * ① トリガーで起動されるmainメソッド
 */
function main1() {
  mainSub_(0);
}
function main2() {
  mainSub_(20);
}
function main3() {
  mainSub_(40);
}

/**
 * ② 各mainメソッドから起動されるsubメソッド
 */
function mainSub_(startSec) {

  if (startSec != null) {
    // ③ 実際に処理を実行する時間を計算
    let next = new Date();
    if (next.getSeconds < startSec) {
      // 0分後の指定秒
      next.setSeconds(startSec);
    } else {
      // 1分後の指定秒
      next.setMinutes(next.getMinutes() + 1);
      next.setSeconds(startSec);
    }

    // ④ 指定時間まで待機
    Utilities.sleep(next.getTime() - new Date().getTime());
  }

  // ⑤ ※実行したいメイン処理をこれ以降に記載してください。
}

コードの解説

コードの内容をそれぞれ解説していきます。

/**
 * ① トリガーで起動されるmainメソッド
 */
function main1() {
  mainSub_(0);
}
function main2() {
  mainSub_(20);
}
function main3() {
  mainSub_(40);
}

トリガーから呼び出される main1、main2、main3 の 3つのメソッドを定義しています。

実際に行いたい処理は mainSub_ という共通のメソッドを用意し、その mainSub_ の呼び出しを行っています。

mainSub_ に渡す引数は、実際の処理を動かす時間(次のXX分YY秒)の秒の部分になります

  • main1:次のXX分00秒までスリープしたいので、0を渡す。
  • main2:次のXX分20秒までスリープしたいので、20を渡す。
  • main3:次のXX分40秒までスリープしたいので、40を渡す。
/**
 * ② 各mainメソッドから起動されるsubメソッド
 */
function mainSub_(startSec) {
  …
}

実際に行いたい処理は mainSub_ という共通のメソッドを用意し、実装しています。

    // ③ 実際に処理を実行する時間を計算
    let next = new Date();
    if (next.getSeconds < startSec) {
      // 0分後の指定秒
      next.setSeconds(startSec);
    } else {
      // 1分後の指定秒
      next.setMinutes(next.getMinutes() + 1);
      next.setSeconds(startSec);
    }

③では実際に処理を実行する時間を計算しています。
 例えば 12時01分10秒 に main1 から起動された場合は、次の00秒として 12時02分00秒
 同様に 12時01分10秒 に main2 から起動された場合は、次の20秒として 12時01分20秒
 同じく 12時01分10秒 に main3 から起動された場合は、次の40秒として 12時01分40秒
となります。

    // ④ 指定時間まで待機
    Utilities.sleep(next.getTime() - new Date().getTime());

④は指定の時間まで処理をスリープ(一時停止)する部分になります。
③で計算した実際に処理を開始する時間 と 今の時間 との差分のぶんだけ処理をスリープさせています。

  // ⑤ ※実行したいメイン処理をこれ以降に記載してください。

④で指定の時間まで処理がスリープされ、そのスリープが解除されると後続の処理が実行されます。
⑤に本来実行したいメインの処理を記載すれば完成です。

実行結果

以下は、上記のコード(⑤の部分)で実際にメイン処理が動いた時間をスプレッドシートに出力したものになります。
実際に20秒間隔で動作できていることがわかると思います。

まとめ

お疲れ様でした。
これで定期的にポータブル電源自動充電システムのプログラムを動作させることが出来るようになりました。

正規の方法ではありませんが、GAS(Google Apps Script)を利用して、1分より短い間隔(30秒ごと や 20秒ごと)でプログラムを動作させ、充電の判断をより頻繁に行うことも可能になります。

自分で作ったプログラムが上手く動作して、毎日ポータブル電源が自動的に充電される様子を見るのは嬉しいものです。
これでより卒FITライフを満喫できますね。

  • 本記事を参考に同等の機能を実現しようとする場合、どのような不具合が発生しようとも責任は負えません。
  • あくまで自己責任の範囲で作業してください。
タイトルとURLをコピーしました