0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

OpenHardTerraceAdvent Calendar 2023

Day 15

ESP32 から Google Sheet に放射線量をアップ(放射線測定マップの作成 Ⅴ)

Last updated at Posted at 2023-12-17

「安価な中華ガイガーカウンターをIoT化(放射線測定マップの作成 Ⅰ)」
https://qiita.com/nanbuwks/items/7ee0bf85be3ff3730405

では、測定値をスマホで閲覧したりガイガーカウンターを WiFi に接続したりして、最後に以下のように記しました。

ここから先

サーバにデータを保管したりするのは上記のプログラムを元にがんばってみよう!

「ここから先」をやってみます。

Google Spreadsheet にテンプレートを作ってみました。

image.png

この、テンプレートをコピーします。
image.png

名前を自分のわかりやすい名前にして、「コピーを作成」します。
image.png

「data」シートに入っているサンプルデータを消します。
1〜9行目の間には何を書いても構いません。
ここに写真や説明などを入力しておきましょう。

image.png

テンプレートには、「説明」「data」「changelog」のシートがあります。
「説明」、「cgabgelog」 シートは間違い防止の為削除しておくのがいいでしょう。

また、「data」シートはIDを 0 に設定しています。コピーや新規作成したシートだと IDが 別の値になってしまいますので、0 の ID のシートをそのままお使いください。
シートIDは、シートを表示したときの URL の末尾に gid= の形で表示されます。

image.png

スクリプトを設定する

URL の、この部分がシートのIDになります。これをコピーします。

image.png

Apps Script を開きます。

image.png

設定されているスクリプトは以下の通りです。

function doGet(e) {
    let id = '  -- please replace your sheet ID -- ';
    let sheetName = 'data'
    var result;
    // e.parameter from GET request
    if (e.parameter == undefined) {
        result = 'Parameter undefined';
    } else {
        var sheet = SpreadsheetApp.openById(id).getSheetByName(sheetName);
        const testRange = sheet.getRange("C11:D11");
        var onedata = [];
        testRange.insertCells(SpreadsheetApp.Dimension.ROWS);
        onedata[0] = new Date();
        onedata[1] = e.parameter.value;
        sheet.getRange(11,3).setValue(onedata[0]);
        sheet.getRange(11,4).setValue(onedata[1]);
    }
    return ContentService.createTextOutput('saved');   
}

ここの ' -- please replace your sheet ID -- ' を コピーしたIDに入れ替えます。

image.png

image.png

「デプロイ」-「新しいデプロイ」して

image.png

種類を「ウェブアプリ」とします。説明は適当に。

image.png
実行ユーザーは自分として、

image.png

アクセスできるユーザを「全員」として「デプロイ」します。

image.png

「アクセスを承認」

image.png

URLを知っている人は無条件でスクリプトを実行できる危険性があるので、この後に出るURLは自分だけが知るようにしないといけません。「Advanced」を押して許可をします。

image.png
「Allow」
image.png

image.png

この、スクリプト実行 URL をコピーしておきます。
image.png

スクリプトを試しに実行する

先程のURLが、例えば https://script.google.com/macros/s/hogehogefugafuga/exec
とすると、後ろに ?value=222 を追加して
https://script.google.com/macros/s/hogehogefugafuga/exec?value=222 をブラウザで開きます。

C11 に実行日時、D11 に222と入力されます。

image.png

トラブルシューティング

以下のようになったときは、スクリプトのファンクション名が doGet になっていないので直します。
image.png

ESP32 からデータを投げる

先の内容を少し変更して、このようにしました。

#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <HTTPClient.h>
#include <SPIFFS.h>
#include <FS.h>

const int WiFiSetPin = 16; // GPIO16  push with boot : AP mode on
const char* settings = "/wifi_settings.txt";
// AP mode WiFi Setting
const char* defaultWifiMode = "APMode";
const char* defaultSsid = "ORION";
const char* defaultEssKey = "11111111";
String wifiMode;
String ssid;
String essKey;
String channel;
String AppScriptURL=" -- Please replace your script URL --";
char *sensorModeStr;
int WiFiSet = 0;  // 0 ... normal operation / 1 ... WiFi Setting Mode
int count;
int beforecpm,cpm;
float microSvph;

WebServer server(80);

void handleRoot(){
  char temp[500];
  snprintf ( temp, 500,
"<html>\
<head>\
<title>Geiger Demo</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<h1> %f uSv/h (%d cpm )</h1>\
<br>%d :geiger count in %d sec.\
<hr> \
<a href=\"\/wifiInput\">wifi settings</a> \
</body>\
</html>",microSvph,cpm,count,millis()/1000);
  server.send ( 200, "text/html", temp );
}

void wifiInput() {
  String html = "";
  html += "<h1>WiFi Settings</h1>";
  html += "<form method='post' action='/wifiSet'>";
  html += "  <br>";
  html += "  <input type='text' name='essid' >ESSID<br>";
  html += "  <input type='text' name='key' >KEY(pass)<br>";
  html += "  <br>";
  html += "  <input type='submit'><br>";
  html += "</form>";
  server.send(200, "text/html", html);
}

void wifiSet() {
  String wifiMode = "clientMode";
  String setSsid = server.arg("essid");
  String setKey = server.arg("key");
  String setChannel = server.arg("0");

  File f = SPIFFS.open(settings, "w");
  f.println(wifiMode);
  f.println(setSsid);
  f.println(setKey);
  f.println(channel);
  f.close();

  String html = "";
  html += "<h1>WiFi Settings</h1>";
  html += "ESSID:" + setSsid + "<br>";
  html += "key(pass):" + setKey + "<br>";
  html += "<hr>";
  html += "<h1>Please Reset!</h1>";

  server.send(200, "text/html", html);
}

void handleNotFound(){
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  server.send(404, "text/plain", message);
}
void googleSheet(){
    HTTPClient http;
    String URL = AppScriptURL;
    URL += "?";
    URL += "value=";
    URL += microSvph;

    Serial.println("HTTP access to:");
    Serial.println(URL);
    http.begin(URL);
    int httpCode = http.GET();
    if(httpCode > 0) {
        Serial.println(httpCode);
        if(httpCode == HTTP_CODE_OK) {
            String payload = http.getString();
            Serial.println(payload);
        }
    } else {
        Serial.println(http.errorToString(httpCode).c_str());
    }

}

void setup(void){

  pinMode(27, INPUT);
    
  Serial.begin(115200);
  Serial.println("");
  Serial.println("ESXAR Program Start");
  delay(1000);
  pinMode ( WiFiSetPin, INPUT_PULLUP );
  WiFiSet=digitalRead(WiFiSetPin);
//   init filesystem
  bool res = SPIFFS.begin(true); // FORMAT_SPIFFS_IF_FAILED
  if (!res) {
      Serial.println("SPIFFS.begin fail");
  }
  // check port
  int i;
  delay(1000);
  // settings read
  if ((1 ==digitalRead(WiFiSetPin)) && (1 ==WiFiSet)){
    WiFiSet=1; // boot on default  
  } else {
    WiFiSet=0;
  }
  // set file read
  File fp = SPIFFS.open(settings, "r");
  if (!fp) {
      Serial.println("open error");
  }
  wifiMode = fp.readStringUntil('\n'); // always "clientMode"
  ssid = fp.readStringUntil('\n');
  essKey = fp.readStringUntil('\n');
  channel = fp.readStringUntil('\n');  // no use
  Serial.print("wifiMode:");
  Serial.println(wifiMode);
  Serial.print("ssid:");
  Serial.println(ssid);
  Serial.print("essKey:");
  Serial.println(essKey);
  fp.close();
  wifiMode.trim();
  ssid.trim();
  essKey.trim();
  channel.trim();
  if ( 0 == wifiMode.compareTo("clientMode") ){
  } else if ( 0 == wifiMode.compareTo("APMode") ) {
  } else {
       Serial.print("SPIFFS data seems clash. Default load...");
       wifiMode=defaultWifiMode;
       ssid=defaultSsid;
       essKey=defaultEssKey;
       File f = SPIFFS.open(settings, "w");
       f.println(wifiMode);
       f.println(ssid);
       f.println(essKey);
       f.close();
  }
  if ( 0 == WiFiSet ) { 
    Serial.println("WiFiMode is ON");
    //----------WiFi access point---------
    Serial.println();
    Serial.print("Configuring access point...");
  /* You can remove the password parameter if you want the AP to be open. */
    if ( 0 == wifiMode.compareTo("APMode") ){
      WiFi.softAP(ssid.c_str(), essKey.c_str());
      IPAddress myIP = WiFi.softAPIP();
      Serial.print("AP IP address: ");
      Serial.println(myIP);
    }
    //----- WiFi client --------------
    if ( 0 == wifiMode.compareTo("clientMode") ){
      WiFi.begin(ssid.c_str(), essKey.c_str());
      Serial.println("");
    // Wait for connection
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      Serial.println("");
      Serial.print("Connected to ");
      Serial.println(ssid);
      Serial.print("IP address: ");
      Serial.println(WiFi.localIP());
    }
  }
  if (1 == WiFiSet) { 
    Serial.println("WiFiMode default boot");
    //----------WiFi access point---------
    Serial.println();
    Serial.print("Configuring access point...");
  /* You can remove the password parameter if you want the AP to be open. */
    WiFi.softAP(defaultSsid, defaultEssKey);
    IPAddress myIP = WiFi.softAPIP();
    Serial.print("AP IP address: ");
    Serial.println(myIP);
  }
  server.on("/",     handleRoot);
  server.on("/wifiInput",  wifiInput);
  server.on("/wifiSet", wifiSet);
  server.onNotFound(handleNotFound);
  server.begin();
  Serial.println("HTTP server started");  
}




void loop() {
   int check=digitalRead(27);
   int beforemillis=millis();
   int counter=0;
   int timecounter=millis()-beforemillis;
   while ( 60000 > (millis()-beforemillis) ){
     int check=digitalRead(27);
     if ( 0 == check ) {
       count=count+1;
       cpm=cpm+1;
       Serial.println(count);
       delayMicroseconds(200);
      }
   }
   
   beforemillis=millis();
   beforecpm=cpm;
   microSvph = cpm / 150.0;
   Serial.print("count:");
   Serial.print(count);
   Serial.print("cpm:");
   Serial.print(cpm);
   Serial.print("microSvph:");
   Serial.print(microSvph);
   cpm=0;
   googleSheet();
   // Handle incoming connections 
   server.handleClient();
   
}

1分ごとに登録できました!

image.png

登録間隔の変更

Google Sheet に登録されたデータは最新100値をグラフ化し、マッピングに使用します。なので登録間隔は数時間に一度ぐらいがいいかな? 例えば2時間に1回、(100計測=200時間=8.3日分)にする場合は、

   while ( 60000 > (millis()-beforemillis) ){

   while ( 60000*60*2 > (millis()-beforemillis) ){

とします。

マッピングに登録

「Cloudcande」という名前で uMap 上に測定マップを作っています。上記で設定したものをマップ上にグラフ図示する場合は、こちらの Issue に登録してください。
https://github.com/nanbuwks/GeigerMap/issues/1

image.png

登録方法

Google Sheet の 「共有」を押して、「リンクを知っている全員」が「閲覧者」となるようにして「リンクをコピー」します。

image.png

その URL を Issue に貼ると、レポジトリの Author が追加していきます。

image.png

おまけ

以下は ESSID と ESSKEY をスケッチに直接書くやり方です。

const char* defaultSsid = "ORION";
const char* defaultEssKey = "11111111";

の箇所を書き換えてください。


#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <HTTPClient.h>
#include <SPIFFS.h>
#include <FS.h>

const int WiFiSetPin = 16; // GPIO16  push with boot : AP mode on
const char* settings = "/wifi_settings.txt";
// AP mode WiFi Setting
// const char* defaultWifiMode = "APMode";
const char* defaultSsid = "ORION";
const char* defaultEssKey = "11111111";
String wifiMode;
String ssid;
String essKey;
String channel;
String AppScriptURL=" -- Please replace your script URL --";
char *sensorModeStr;
int WiFiSet = 0;  // 0 ... normal operation / 1 ... WiFi Setting Mode
int count;
int beforecpm,cpm;
float microSvph;

WebServer server(80);

void handleRoot(){
  char temp[500];
  snprintf ( temp, 500,
"<html>\
<head>\
<title>Geiger Demo</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<h1> %f uSv/h (%d cpm )</h1>\
<br>%d :geiger count in %d sec.\
<hr> \
<a href=\"\/wifiInput\">wifi settings</a> \
</body>\
</html>",microSvph,cpm,count,millis()/1000);
  server.send ( 200, "text/html", temp );
}

void wifiInput() {
  String html = "";
  html += "<h1>WiFi Settings</h1>";
  html += "<form method='post' action='/wifiSet'>";
  html += "  <br>";
  html += "  <input type='text' name='essid' >ESSID<br>";
  html += "  <input type='text' name='key' >KEY(pass)<br>";
  html += "  <br>";
  html += "  <input type='submit'><br>";
  html += "</form>";
  server.send(200, "text/html", html);
}

void wifiSet() {
  String wifiMode = "clientMode";
  String setSsid = server.arg("essid");
  String setKey = server.arg("key");
  String setChannel = server.arg("0");

  File f = SPIFFS.open(settings, "w");
  f.println(wifiMode);
  f.println(setSsid);
  f.println(setKey);
  f.println(channel);
  f.close();

  String html = "";
  html += "<h1>WiFi Settings</h1>";
  html += "ESSID:" + setSsid + "<br>";
  html += "key(pass):" + setKey + "<br>";
  html += "<hr>";
  html += "<h1>Please Reset!</h1>";

  server.send(200, "text/html", html);
}

void handleNotFound(){
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  server.send(404, "text/plain", message);
}
void googleSheet(){
    HTTPClient http;
    String URL = AppScriptURL;
    URL += "?";
    URL += "value=";
    URL += microSvph;

    Serial.println("HTTP access to:");
    Serial.println(URL);
    http.begin(URL);
    int httpCode = http.GET();
    if(httpCode > 0) {
        Serial.println(httpCode);
        if(httpCode == HTTP_CODE_OK) {
            String payload = http.getString();
            Serial.println(payload);
        }
    } else {
        Serial.println(http.errorToString(httpCode).c_str());
    }

}

void setup(void){

  pinMode(27, INPUT);
    
  Serial.begin(115200);
  Serial.println("");
  Serial.println("ESXAR Program Start");
  delay(1000);

  
  
  ssid=defaultSsid;
  essKey=defaultEssKey;
  Serial.print("ssid:");
  Serial.println(ssid);
  Serial.print("essKey:");
  Serial.println(essKey);
// WiFi client mode
  WiFi.begin(ssid.c_str(), essKey.c_str());
      Serial.println("");
// Wait for connection
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
      Serial.println("");
      Serial.print("Connected to ");
      Serial.println(ssid);
      Serial.print("IP address: ");
      Serial.println(WiFi.localIP());
    }
  }

  server.on("/",     handleRoot);
  server.on("/wifiInput",  wifiInput);
  server.on("/wifiSet", wifiSet);
  server.onNotFound(handleNotFound);
  server.begin();
  Serial.println("HTTP server started");  
}




void loop() {
   int check=digitalRead(27);
   int beforemillis=millis();
   int counter=0;
   int timecounter=millis()-beforemillis;
   while ( 60000 > (millis()-beforemillis) ){
     int check=digitalRead(27);
     if ( 0 == check ) {
       count=count+1;
       cpm=cpm+1;
       Serial.println(count);
       delayMicroseconds(200);
      }
   }
   
   beforemillis=millis();
   beforecpm=cpm;
   microSvph = cpm / 150.0;
   Serial.print("count:");
   Serial.print(count);
   Serial.print("cpm:");
   Serial.print(cpm);
   Serial.print("microSvph:");
   Serial.print(microSvph);
   cpm=0;
   googleSheet();
   // Handle incoming connections 
   server.handleClient();
   
}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?