Arduino Google Apps Script Google Workspace (G Suite) Javascript プログラミング 工作 電子工作

ソーラー充電ランタンの電池寿命を測るためにESP32にCdsセンサを繋いで明るさをGoogleスプレッドシートに記録した

いい感じのソーラー充電ランタンをもらった

ちょっと前に友人からソーラー充電ランタンをもらいました。

 

ビニールでできた円筒形ボディの片面にソーラーパネルとLEDが付いています。

 

普段は空気を抜いておけばコンパクトに収納でき、使う時は空気を膨らませればランタンとして使えます。

 

構造的には防水っぽいし、軽くてコンパクトでなかなかいい感じです。

実際、結構な人気商品だそうです。

 

Cds+マイコンで明るさが持続する時間を測る

非常灯となると、やっぱり気になるのは一回の充電でどれくらいの時間点灯するかです。

自分の目でじっと見ているのほどヒマでもないのでマイコンに計測してもらうことにしました。

明るさの測定にはCdsセンサを使いました。明るさによって抵抗値が変わるセンサです。

 

昔のカメラの露出計はこれを使ったものが多かったですね。

手持ちがなかったので「GL5528」という製品を買いました。

アマゾンで翌日配送の10個入りパックがあったのでそれにしました。

電子部品がちょっと欲しいときは、ロットが多すぎたり、送料がやたら高かったりして難しいですね。

もっとも都心の公共交通機関は結構料金が高いので、時間ロスも考えれば1000円くらいの送料を払っても自分でアキバに行くより安かったりします。

あと私の場合、ド近眼と老眼のセットでパーツ屋に行くと目がしんどいんですよね(苦笑)。

 

Cdsは明るいと抵抗値が下がるセンサ

Cdsセンサは明るいと抵抗値が下がり、暗いと抵抗値が上がります。

抵抗系のセンサはテスタで簡単に実験できていいですね。

手で覆うと18MΩ、ライトを当てると0.6KΩとなりました。

実際に使う時は電源とGNDの間にCdsセンサを入れて電圧を取り出します。

Cdsセンサだけだと抵抗値が大きく下がったときに大きな電流が流れる可能性があるので、普通の抵抗を直列に入れます。

今回は適当に10KΩの抵抗を入れました。

 

CdsをGND側に配置する方が多い気がしますが、VCC側においた方が明るいほど電圧が高くなるので分かりやすいと思いました。

ブレットボードだと使いにくいのでユニバーサル基板で組んでコネクタを付けました。

 

ESP32でCdsのデータを測定する

マイコンはESP32を使いました。以下の記事にも書きましたが標準でWifiを装備していて、アナログ入力が3.3V対応なので採用しました。

ESP32(Developer Board)のarduino設定とLチカ&デジタル入力

マイコンボードESP32 Developper Moduleのarduino IDEインストールとLチカ、スイッチ入力テストの記録です

続きを見る

 

図のような感じでセンサボードとESP32の3.3V出力とGND、入力ピン(IO34)を接続します。

 

EPS32にはピンがたくさんありますが、とりあえずIO34は入力専用でアナログ入力対応なので無難な選択みたいです。

ひとまずセンサからのデータをシリアルモニタ(シリアルプロッタ)に書き出してテストしました。

const int inputPin = 34;

void setup() {
  Serial.begin(115200);
  delay(1000);
}

void loop() {
  int inputValue = analogRead(inputPin);
  Serial.println(inputValue);
  delay(200);
}

 

 

Cdsを手で隠したりライトを近づけるとデータが変化したので、無事にセンサのデータが取れているようです。

 

今回は明るさの絶対値は必要ないのでこのデータをそのまま記録します。

ちなみにESP32のADCは入力電圧に対してリニアな値が得られるわけではないそうです。

なので絶対値が必要な場合にはプログラムを工夫する必要がありますね。

 

ESP32でGoogle App ScriptのWebアプリにPOSTするための変更

あとは測定したデータをGoogle Apps ScriptのWebアプリにPOSTしてスプレッドシートに記録してもらいます。

やることはESP8266の電源電圧を記録したときと同じです。

電池駆動したESP8266(ESPr Developer)の3.3vピンの電圧をHTTPSRedirectを使って1分ごとにGoogle Spread Sheetに書き込んだ話

ESP8266を電池で動かしたときに、3.3V端子が何ボルトまで下がったら止まるのか、それはだいたい何時間後なのかを知るために、3.3V端子の電圧をGoogleスプレッドシートに記録してみました。GoogleスプレッドシートへのアクセスにはHTTPSRedirectというライブラリを使用しました

続きを見る

 

プログラムも流用しますが、ESP32からGASのWebアプリにアクセスするためには使用するライブラリの変更とHTTPSRedirectライブラリのソースコード改変が必要です。

使用するライブラリは #include <ESP8266WiFi.h> を #include <WiFi.h> に変えるだけです。

もうひとつは、HTTPSRedirectライブラリのソース「HTTPSRedirect.cpp」にある以下の記述のコメントアウトを外します。

// stop(); // may not be required

つまり、

ESP8266:コメントアウトしたまま
ESP32:コメントアウトを外す

 

HTTPSRedirect.cppのパスは、

スケッチの保存場所/libraries/HTTPSRedirect/HTTPSRedirect.cpp

です。(Macの場合)

スケッチの保存場所はarduino IDEの環境設定で「スケッチブックの保存場所」を見ると分かります。デフォルトは「書類」フォルダだと思います。

 

ちなみにstop();がコメントアウトされたままでEPS32上で動かすと、最初に一回GASにアクセスしたっきり戻ってきません。

このコメントを外す方法はどこかのサイトで知ったのですが参照元を忘れてしまいました。失敬。

あとは測定対象を電源電圧からGPIO34に変更しただけです。

 

ソースコード

ESP32とGAS、両方のソースを載せておきます。GASの方はESP8266と完全に同一です。私は汎用の記録場所として使い回しています。

EPS32側のプログラム。使う時にはWifiのSSIDとPassword、GASのIDを設定する必要があります。

#include <WiFi.h>
#include "HTTPSRedirect.h"
//EPS32で使う時には、ライブラリのHTTPSRedirec.cppの"stop();//may not be required" を活かす

const char* ssid = "******Wifi SSID*******";
const char* password = "******Wifi Password";
const char *GScriptId = "*******Google Apps ScriptのID*******;

const char* host = "script.google.com";
const int httpsPort = 443;

const int inputPin = 34;

String url = String("/macros/s/") + GScriptId + "/exec";

//payload_baseはJSONデータとしてコマンドとシート名、値を送るためのURLの前半部分
//ここではappentRowだけだが、サーバースクリプトでコマンドに応じた処理を作っておくと色んなコマンドが使える

String payload_base =  "{\"command\": \"appendRow\", \
                    \"sheet_name\": \"Sheet1\", \
                    \"values\": ";

//paload_baseと送る値を合体するための変数
String payload = "";

HTTPSRedirect* client = nullptr;

void setup() {
  Serial.begin(115200);
  Serial.flush();
  Serial.println("************** ESP32 to Google SS Starting up! ***************");

  Serial.println();
  Serial.print("Connecting to wifi: ");
  Serial.println(ssid);
  Serial.flush();

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}


void loop() {
  static int error_count = 0;
  bool flag = false;// connection success or fail

  client = new HTTPSRedirect(httpsPort);
  client->setInsecure();
  client->setPrintResponseBody(true);
  client->setContentTypeHeader("application/json");

  Serial.print("Connecting to ");
  Serial.println(host);

  // Try to connect for a maximum of 5 times
  for (int i = 0; i < 5; i++) {
    int retval = client->connect(host, httpsPort);
    if (retval == 1) {
      flag = true;
      break;
    }
    else
      Serial.println("Connection failed. Retrying...");
  }

  if (!flag) {
    delete client;
    Serial.print("Could not connect to server: ");
    Serial.println(host);
    Serial.println("GO TO SLEEP.....");
    ESP.deepSleep( 0 );
    delay( 1000 );
  }

  Serial.print("Successfully Connected to ");
  Serial.println(host);

  //**** read analog pin and send data to Google SpreadSheet ****
  Serial.println("POST append data to spreadsheet:");

  int inputValue = analogRead(inputPin);

  Serial.println( "AnalogPin " + String(inputPin) + ":" + String(inputValue));

  payload = payload_base + "\"" +  inputValue +  "\"}";

  // to send multiple values, separate with "," like this. Server side can handle array, so no neet to change GAS script.
  //複数の値を渡すときはこんな感じでカンマで区切る。サーバーサイドスクリプトは配列対応なのでデータ数が増えても変更不要
  //payload = payload_base + "\"" + inputPin + "," + data1 + "," + data2 + "\"}";

  if (client->POST(url, host, payload)) {
    Serial.println("Success! send data");
  }
  else {
    error_count++;
    Serial.print("Error!");
    Serial.println(error_count);
  }

  if (error_count > 3) {
    Serial.println("Halting processor...");
    delete client;
    client = nullptr;
    Serial.flush();
    ESP.deepSleep(0);
  }

  delete client;

  delay(60000*10);//interval of posting
}

GASのスクリプト。スプレッドシートに付属のスクリプトとして設定します。

//自分のスプレッドシート情報を取得
var SS = SpreadsheetApp.getActiveSpreadsheet();
var SHEET = SS.getSheets()[0];
var str = "";

function doPost(e) {
  var parsedData;
  var result = {};
  
  try { 
    parsedData = JSON.parse(e.postData.contents);
  } 
  catch(f){
    return ContentService.createTextOutput("Error in parsing request body: " + f.message);
  }
   
  if (parsedData !== undefined){    
    switch (parsedData.command) {
      case "appendRow":
         var dataArr = parsedData.values.split(",");
         var now = Utilities.formatDate(new Date(), "JST", "yyyy/MM/dd HH:mm:ss");
         dataArr.unshift(now);         
         SHEET.appendRow(dataArr);
      
         str = "Success(appendRow)";
         SpreadsheetApp.flush();
         break;     
      }
    
    return ContentService.createTextOutput(str);
  } 
  
  else{
    return ContentService.createTextOutput("Error! Request body empty or in incorrect format.");
  }
  
}



 

実用点灯時間は3時間くらい?

測定では適当に作った暗箱にセンサとランタンを入れて測りました。

 

もちろんランタンには数時間、太陽光を当てて充電しておきました。充電インジケーターなどはないのでどこまで充電されているのかは分かりません。

結果は図のような感じ。実用的な明るさを維持できるのはだいたい3時間くらい。一応ついている時間を含めて4時間といったところでしょうか。

もっと日に当てれば時間が伸びるのかなぁ。

 

これひとつあれば安心というよりも、電池式のライトと併用して電池の消耗を減らすという使い方が良いのではないかと思いました。

あと、灯りがつかないような時は、暗くなったらさっさと寝る朝方にシフトするべきですね。

-Arduino, Google Apps Script, Google Workspace (G Suite), Javascript, プログラミング, 工作, 電子工作