Arduino Uno R4 WiFiとGROVEでクラウド温度計を作る

前回の記事で、Arduino Uno R4 WiFiを使ってHTTPSなサイトに簡単に接続できることを確認しました。

次は、温度センサーで取得した値をさくらのレンタルサーバ上の自身のHTTPSサイトにデータ送信します。


温度センサの値をディスプレイに表示して送信するスケッチ

Arduino Unoにコネクタ接続するだけで使えるSeed Studio製 GROVEのセンサーを使用しています。

必要な機材

  1. Arduino Uno R4 WiFi
  2. GROVE ベースシールド
  3. GROVE 7セグメント4桁ディスプレイ
  4. 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円。

市販品で似たような製品も発売されていますが、自分で作るメリットは柔軟性にあります。温度が何度以上になったらアラートメールを送信するとかを自身で柔軟に設定出来るのは便利です!