「安価な中華ガイガーカウンターをIoT化(放射線測定マップの作成 Ⅰ)」
https://qiita.com/nanbuwks/items/7ee0bf85be3ff3730405
では、測定値をスマホで閲覧したりガイガーカウンターを WiFi に接続したりして、最後に以下のように記しました。
ここから先
サーバにデータを保管したりするのは上記のプログラムを元にがんばってみよう!
「ここから先」をやってみます。
Google Spreadsheet にテンプレートを作ってみました。
名前を自分のわかりやすい名前にして、「コピーを作成」します。
「data」シートに入っているサンプルデータを消します。
1〜9行目の間には何を書いても構いません。
ここに写真や説明などを入力しておきましょう。
テンプレートには、「説明」「data」「changelog」のシートがあります。
「説明」、「cgabgelog」 シートは間違い防止の為削除しておくのがいいでしょう。
スクリプトを設定する
URL の、この部分がシートのIDになります。これをコピーします。
Apps Script を開きます。
設定されているスクリプトは以下の通りです。
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に入れ替えます。
「デプロイ」-「新しいデプロイ」して
種類を「ウェブアプリ」とします。説明は適当に。
アクセスできるユーザを「全員」として「デプロイ」します。
「アクセスを承認」
URLを知っている人は無条件でスクリプトを実行できる危険性があるので、この後に出るURLは自分だけが知るようにしないといけません。「Advanced」を押して許可をします。
スクリプトを試しに実行する
先程のURLが、例えば https://script.google.com/macros/s/hogehogefugafuga/exec
とすると、後ろに ?value=222
を追加して
https://script.google.com/macros/s/hogehogefugafuga/exec?value=222
をブラウザで開きます。
C11 に実行日時、D11 に222
と入力されます。
トラブルシューティング
以下のようになったときは、スクリプトのファンクション名が doGet になっていないので直します。
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分ごとに登録できました!
登録間隔の変更
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
登録方法
Google Sheet の 「共有」を押して、「リンクを知っている全員」が「閲覧者」となるようにして「リンクをコピー」します。
その URL を Issue に貼ると、レポジトリの Author が追加していきます。
おまけ
以下は 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();
}