Arduino Uno R4 WiFiとGROVEでクラウド温度計を作る
前回の記事で、Arduino Uno R4 WiFiを使ってHTTPSなサイトに簡単に接続できることを確認しました。
次は、温度センサーで取得した値をさくらのレンタルサーバ上の自身のHTTPSサイトにデータ送信します。
温度センサの値をディスプレイに表示して送信するスケッチ
Arduino Unoにコネクタ接続するだけで使えるSeed Studio製 GROVEのセンサーを使用しています。
必要な機材
温度センサーからの値を5秒毎に取得しつつ1分毎に保存して、5回分のデータが溜まったらHTTPSなサイトにGETパラメータで送信しています。つまり5分毎にHTTPSアクセスが発生します。
#include "DHT.h"
#include "TM1637.h"
#include "WiFiS3.h"
#include "WiFiSSLClient.h"
#include "arduino_secrets.h"
#define DHTPIN 2 //D2 温湿度計
#define DHTTYPE DHT11
#define CLK 5 //D5 ディスプレイ
#define DIO 6
DHT dht(DHTPIN , DHTTYPE);
TM1637 tm1637(CLK , DIO);
//---------------------
// *温度・湿度
//---------------------
float temperature = 0;
float temperature_display = 0;
float humidity = 0;
//---------------------
// *データ送信
//---------------------
unsigned long time_check;
unsigned long time_now;
int data_count = 0;
float temperature_ary[5];
float humidity_ary[5];
//---------------------
// *Wi-Fi接続
//---------------------
char wifi_ssid[] = SECRET_WIFI_SSID;
char wifi_pass[] = SECRET_WIFI_PASS;
char server_host[] = SERVER_HOST;
///=======================================================================
// +setup
///=======================================================================
void setup() {
//---Serialポートを開く
Serial.begin(115200);
//---シリアルモニタの準備を待つ
while (!Serial) {
;
}
//---ディスプレイ初期化
tm1637.init();
//---温度計初期化
dht.begin();
//---ディスプレイ輝度(普通)
tm1637.set(BRIGHT_TYPICAL);
//---開始時の時刻を記録
time_check = millis();
//---5秒待つ
delay(5000);
//---------------------------------------------
// *Wi-Fi接続を実行
//---------------------------------------------
Serial.println("Waiting to come online");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
//---接続
WiFi.begin(wifi_ssid , wifi_pass);
//---10秒待つ
delay(10000);
}
Serial.println(" >>> online");
}
///=======================================================================
// +loop
///=======================================================================
void loop() {
humidity = dht.readHumidity();
temperature = dht.readTemperature();
//---エラー時
if(isnan(temperature) || isnan(humidity)){
Serial.println("Failed to read from DHT");
//---ディスプレイの消灯
tm1637.clearDisplay();
//---正常時
} else{
//---数値に変換するので10倍する
temperature_display = temperature * 10;
//---ディスプレイに表示
tm1637.displayNum(temperature_display);
Serial.print("温度: ");
Serial.print(temperature);
Serial.print("℃\t");
Serial.print("湿度: ");
Serial.print(humidity);
Serial.print("% ");
Serial.println("[" + (String)data_count + "]");
//---現在時間
time_now = millis();
//---------------------------------------------
// *1分ごとに温湿度を配列に記録する
//---------------------------------------------
if((time_now - time_check) > (1000 * 60)){
Serial.println(" >> save");
//---配列に追加
temperature_ary[data_count] = temperature;
humidity_ary[data_count] = humidity;
//---タイマーリセット
time_check = time_now;
//---件数加算
data_count++;
//---------------------------------------------
// *5分ごとにデータを送信する
//---------------------------------------------
if(data_count >= 5){
Serial.println(" >>>> send");
//---Webサーバにデータ送信
SendData();
//---カウントリセット
data_count = 0;
}
}
}
//---5秒ごとに実行
delay(5000);
}
////===========================================================================================
// *Webサーバにデータ送信
////===========================================================================================
void SendData() {
//---------------------------------------------
// *GETパラメータを生成
//---------------------------------------------
String send_data = "";
for (int i = 0; i <= 4; i++){
if(i != 0){
send_data += "&";
}
send_data += "t" + (String)i + "=" + (String)temperature_ary[i] + "&" + "h" + (String)i + "=" + (String)humidity_ary[i];
//---配列の初期化
temperature_ary[i] = 0;
humidity_ary[i] = 0;
}
//---------------------------------------------
// *HTTP接続を実行
//---------------------------------------------
Serial.println("Starting connection to server");
String http_params = "GET /" + (String)SERVER_PATH + "?type=" + (String)SERVER_TYPE + "&" + send_data + " HTTP/1.1";
String http_host = "Host: " + (String)server_host;
Serial.println(http_params);
Serial.println(http_host);
WiFiSSLClient client;
//---HTTPSで接続(SSL)
if (client.connect(server_host , 443)) {
Serial.println(" >>> connected");
//---HTTPリクエスト部分
client.println(http_params);
client.println(http_host);
client.println("User-Agent: OndoToWifi");
client.println("Connection: close");
client.println();
unsigned long timeout = millis();
//---タイムアウトで接続を閉じる
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println("--- client timeout");
client.stop();
}
}
} else{
Serial.println("--- connection failed");
}
//---接続を閉じる
if (client.connected()) {
Serial.println("disconnecting from server.");
client.stop();
}
}
#define SECRET_WIFI_SSID "あなたのSSID"
#define SECRET_WIFI_PASS "あなたのパスワード"
#define SERVER_TYPE "適当な名前"
#define SERVER_HOST "www.example.jp"
#define SERVER_PATH "ondo_to_wifi/index.php"
サーバ上で受け取るパラメータ例
https://www.example.jp/ondo_to_wifi/index.php?type=hoge&t0=24.60&h0=52.00&t1=24.50&h1=52.00&t2=24.60&h2=52.00&t3=24.60&h3=51.00&t4=24.70&h4=51.00
- typeはデバイスを識別する為の任意の名前
- t0からt4までに過去5分の温度
- h0からh4までに過去5分の湿度
パラメータの解析方法
例えばPHPであれば、以下の構文で簡単に取得できます。
if(!empty($_GET["type"])){
for ($i = 0; $i <= 4; $i++){
$temperature_ary[$i] = $_GET["t{$i}"];
$humidity_ary[$i] = $_GET["h{$i}"];
}
}
}
受け取ったデータを何に使う?
以前記事にもしていますが、スマホでも簡単に温度計のデータを見ることが出来るように、サーバー上で受け取ったデータを加工した後にSlackにデータを送信しています。
以下Slackにデータ送信している部分の過去記事
まとめ
以前使っていたsakura.ioに比べてシールドの数が1枚減ったのとLTEアンテナが不要になったので、かなりシンプルな見た目になりました。またWi-Fiなので通信費用も0円。
市販品で似たような製品も発売されていますが、自分で作るメリットは柔軟性にあります。温度が何度以上になったらアラートメールを送信するとかを自身で柔軟に設定出来るのは便利です!