コジンテキネット

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円。

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