sakura.ioとArduinoとGROVEでクラウド温度計を作る(1)

離れた場所の温度(エアコンの動作状況)を監視して、異常時には通知したいという依頼がありました。

具体的にはペットの見守り用です。もしも飼い主の不在時にエアコンが止まってしまったら?真夏だと大切なペットが熱中症で死んでしまうかもしれない。

解決する為に、LTEで単独通信できてネットワークの設定が不要な、さくらインターネットsakura.ioと安価なArduinoを使ってクラウド温度計を作りました。


システムの仕様

  • 温度センサーで1分毎に温度と湿度を計測
  • 5分毎にまとめてsakura.ioでクラウドに送信する
  • 同時にslackの通常チャンネルに温度データを自動投稿する
  • 温度データが設定値を超えたら緊急用のslackチャンネルに投稿する
  • sakura.ioイベントアラート機能を利用して動作状況を監視する
  • 温度計がオフラインになれば緊急用のslackチャンネルに投稿する

※停電時などは、温度センサーを搭載したデバイスが動作しないのでsakura.ioのイベントアラート機能を使ってデバイスの動作状況を監視します。

※slackの通常時のチャンネルは、過去の温度データがすべて投稿されているので現在の温度等の確認が行えます。また通常チャンネルの通知はOFFにしておきます。

※slackの緊急時のチャンネルには、温度が閾値を超えた場合と停電やデバイスの故障などで温度データが取得出来ない場合に投稿します。通知音は大きな音のものに変更しておきます。


必要な機材

  1. Arduino Uno
  2. GROVE ベースシールド
  3. GROVE 7セグメント4桁ディスプレイ
  4. GROVE デジタル温度・湿度センサ
  5. sakura.io さくらの通信モジュール(LTE)
  6. sakura.io シールド for Arduino
  7. ACアダプター 9V/1.3A 

GROVEシステムを利用しているので、ハンダ付けなどの加工は不要です。下から[Arduino][GROVEベースシールド][sakura.ioシールド]の順番ではめ込むだけで組み立ては完了します。

※機材の購入費として2万円弱必要ですが、sakura.ioの通信費用は月10,000回以内の通信であれば月額60円です。24時間連続稼働するとして5分毎の通信であれば基本料金内で収まります。


温度センサーから取得したデータをディスプレイに表示しながら5分毎にsakura.ioに送信するArduinoスケッチ

デジタル温度・湿度センサは[D2]に接続します。
7セグメント4桁ディスプレイは[D5]に接続します。

#include "DHT.h"
#include "TM1637.h"
#include "SakuraIO.h"

#define DHTPIN 2
#define DHTTYPE DHT11

#define CLK 5
#define DIO 6

DHT dht(DHTPIN , DHTTYPE);
TM1637 tm1637(CLK , DIO);
SakuraIO_I2C sakuraio;

//---温度計の更新間隔(60秒)
const uint32_t UPDATE_TIME = 60;

//---温度の値
int8_t temperature = 0;

//---湿度の値
int8_t humidity = 0;

//---キューに追加した時間
uint32_t queued_time = 0;

//---Unixtime
uint32_t unixtime = 0;

///=======================================================================
//   +setup
///=======================================================================

void setup() {

	//---Serialポートを開く
	Serial.begin(9600);

	//---ディスプレイ初期化
	tm1637.init();

	//---温度計初期化
	dht.begin();

	//---ディスプレイ輝度(普通)
	tm1637.set(BRIGHT_TYPICAL);

	//---------------------------------------------
	//   +sakura.ioがオンラインになるまで待つ
	//---------------------------------------------

	Serial.println(F("Waiting to come online"));

	for(;;){
		if((sakuraio.getConnectionStatus() & 0x80) == 0x80) break;
		Serial.print(F("."));
		delay(1000);
	}

	Serial.println("");
}

///=======================================================================
//   +loop
///=======================================================================

void loop() {

	//---------------------------------------------
	//   +温度・湿度取得
	//---------------------------------------------

	float sensor_h = dht.readHumidity();
	float sensor_t = dht.readTemperature();

	//---エラー時
	if(isnan(sensor_t) || isnan(sensor_h)){

		Serial.println(F("Failed to read from DHT"));

		//---ディスプレイの消灯
		tm1637.clearDisplay();

		//---正常時
	}else{

		//---数値の温度に変換
		temperature = (int)sensor_t;
		humidity = (int)sensor_h;

		//---ディスプレイに表示
		tm1637.displayNum(temperature);

		//---------------------------------------------
		//   +sakura.ioがオンラインの時
		//---------------------------------------------

		if((sakuraio.getConnectionStatus() & 0x80) == 0x80){

			//---Unixtime
			uint32_t unixtime = (uint32_t)(sakuraio.getUnixtime()/1000UL);

			//---------------------
			//   +キューに追加
			//---------------------

			//---60秒間隔で温度・湿度をキューに追加する
			if(!queued_time || (unixtime - queued_time) >= UPDATE_TIME){

				//---キューに追加した時間
				queued_time = unixtime;

				Serial.print(F(" unixtime=")); Serial.println(unixtime);

				Serial.print(F(" 温度:")); Serial.print(temperature); Serial.print(F("℃"));
				Serial.print(F(" 湿度:")); Serial.print(humidity); Serial.println(F("% "));

				//---Queueに追加する
				EnQueue(temperature, humidity);
			}

			//---------------------------------------------
			//   +sakura.ioがオフラインの時
			//---------------------------------------------

		}else{

			Serial.println(F("sakura.io OFFLINE"));
		}
	}

	//---------------------
	//   +1秒ごとに実行
	//---------------------

	delay(1000);
}

///=======================================================================
//   +Queueに追加する
///=======================================================================
void EnQueue(int32_t p_sensor_t , int32_t p_sensor_h) {

	uint8_t ret;

	//---温度
	ret = sakuraio.enqueueTx((uint8_t)0, (int32_t)p_sensor_t);
	Serial.print(F(" Enqueue0=")); Serial.print(ret);

	//---湿度
	ret = sakuraio.enqueueTx((uint8_t)1, (int32_t)p_sensor_h);
	Serial.print(F(" Enqueue1=")); Serial.println(ret);

	//---------------------------------------------
	//   +sakura.ioに送信する
	//---------------------------------------------

	uint8_t avail;
	uint8_t queued;

	sakuraio.getTxQueueLength(&avail, &queued);

	Serial.print(F(" Tx Available=")); Serial.print(avail);
	Serial.print(F(" Queued=")); Serial.println(queued);

	//---30個以上でクリア
	if(queued >= 30){

		ret = sakuraio.clearTx();
		Serial.print(F(" Clear=")); Serial.println(ret);

		//---10個以上で送信
	}else if(queued >= 10){

		ret = sakuraio.send();
		Serial.print(F(" Send=")); Serial.println(ret);
	}
	
	Serial.println(F("-------------------------"));
}

温度センサーとディスプレイ表示については、以下の記事の応用編なので基本的な設定についてはそちらの内容をご確認ください。

sakura.ioの基本的な設定と動作については、公式ドキュメントおよび以下の記事を参考にしてください。


実行結果をシリアルモニタで確認

1分毎に温度と湿度が表示され5分毎に「send=1」で送信されていれば成功です。


実行結果をWebSocket で確認

sakura.ioのコンソールより連携サービスでWebSocketを追加すると通信状態を確認できます。

詳細表示モードで確認すると5分毎に温度・湿度のデータが送られているのが分かります。

※計測した温度が一定にならなかったりディスプレイ表示が異常な場合には、GROVEベースシールドに3.3Vと5Vの切替スイッチがありますので、5V側に切り替わっているか確認してください。3.3Vでは正しく動作しません。


完成後の外観

温度センサーとディスプレイは、Grove Wrapperに収納し本体部分は、共立エレショップのさくらの通信モジュール アクリルベースにスペーサーを追加して収納しています。

次回sakura.ioで受け取ったデータをslackに自動投稿する部分を掲載します。