なにがやりたいのか
簡単にいうと
Arduino Unoで室内の温度と湿度を測ってそれをブラウザ上で表示させたい。
とりあえずブラウザ上で表示させるのはNode.js
かなんかに任せるとして、
今回は**DHTセンサーなるものを使ってArduinoで回路を組み、計測した温度と湿度をJSON形式で送ろうとおもう。**
DHTセンサーにはメジャーなものとしてDHT11
とDHT22
があるようですが、
今回は精度がDHT11
より高い**DHT22
**を使用します。Amazonで750円ぐらいで売っているのでよかったら試してみてください。
JSONデータを送る方法はシリアル通信にします。
ほんとうはシリアル通信じゃなくてHTTPあたりで通信したいけどEthernetシールド付きのArduinoの購入は
現在諸事情によりお金がなく、お値段的に憚れるので今回はシリアル通信で我慢する。
というより純正品に関しては日本のスイッチサイエンス社はもう販売していない?
HTTP通信についてはお金に余裕ができたら試してみようとおもいます。
Arduinoで使用するライブラリ
-
DHT-sensor-library
- 簡単にDHTから値を読み取ることができるようになる。
- Adafruit Unified Sensor Libraryをインクルードしないとダメとあるが多分今回使う部分の程度なら必要なさそう。
-
ArduinoJson
- JSONのシリアライズに使用する。
- 2019/01/21の時点ではバージョン6はベータ版なので注意。
回路を組む
以下の画像がわかりやすいと思います。
ブレッドボード図はこちら
画像元のURL
Arduinoのコードを書く
# include <ArduinoJson.h>
# include <DHT.h>
constexpr uint8_t dhtPin = 2; // DHTセンサーが刺さっているピン
constexpr uint8_t dhtType = DHT22; // 今回使うのはDHT22
DHT dht{dhtPin, dhtType};
void setup() {
Serial.begin(9600);
dht.begin();
}
void loop() {
// 10秒待機(DHT22は最低でも2秒は遅延させたい)
delay(10000);
// JsonObjectの生成。
StaticJsonBuffer<200> jsonBuffer;
auto& root = jsonBuffer.createObject();
// 読み取った温度をJsonObjectにセットする。
const auto temperature = dht.readTemperature();
if (isnan(temperature)) {
setError(root, "Error reading temperature!");
}
else {
root["temperature"] = temperature;
}
// 読み取った湿度をJsonObjectにセットする。
const auto humidity = dht.readHumidity();
if (isnan(humidity)) {
setError(root, "Error reading humidity!");
}
else {
root["humidity"] = humidity;
}
// Jsonのシリアライズ。
root.printTo(Serial);
Serial.print("\n"); // 改行文字をデリミタとして使う。
}
{"temperature":20.6,"humidity":54.4}
簡単な解説
# include <ArduinoJson.h>
# include <DHT.h>
constexpr uint8_t dhtPin = 2; // DHTセンサーが刺さっているピン
constexpr uint8_t dhtType = DHT22; // 今回使うのはDHT22
DHT dht{dhtPin, dhtType};
constexpr uint8_t dhtType = DHT22;
とありますが、DHT22
はDHT.h
に定義されています。
C++11以降のC++にあまり馴染みがない方なら**constexpr
**ってなんやねん!って思ったかもしれません。
この部分に関してはconst
とあまり変わらないので気にする必要はなさそうです。
**constexpr
**に対してまともに解説するとそれだけで長い記事になるほど奥が深いので気になった方はぜひ調べてみてください。
DHT dht{dhtPin, dhtType}
ではDHTのコンストラクタを呼び出しています。
ArduinoでC++11以降の記述ができるんだと知り、ビビってしまったためここでもC++11の記法を使っています。
void setup() {
Serial.begin(9600);
dht.begin();
}
シリアル通信のデータ転送レートの指定とDHTのセットアップをしています。
DHT::begin()
の中身はメンバ変数とピンモードの初期化となっているようです。(2019/1/21時点)
ちなみにArduinoではSetup()
は電源を入れたときやリセットしたときに、一度だけ呼ばれる関数となっています。
void loop() {
// 10秒待機(DHT22は最低でも2秒は遅延させたい)
delay(10000);
Arduinoではloop()
はSetup()
のあとに繰り返し呼ばれます。
とりあえず10秒間隔でシリアル通信を行うことにしました。
// JsonObjectの生成。
StaticJsonBuffer<200> jsonBuffer;
auto& root = jsonBuffer.createObject();
StaticJsonBuffer
はメモリプールで、StaticJsonBuffer<200> jsonBuffer
では200bytesのメモリを確保しています。
ちなみにおもいっきりStackにのっているのでHeapから確保したい場合はDynamicJsonBuffer
を使えばいいそうです。
また、auto& root = jsonBuffer.createObject();
でさきほどのjsonBuffer
からJsonObject
への参照を得ていますが、この参照の寿命はjsonBufferがスコープから抜けるまでのようです。
なので今回で言えばloop()
内では参照可能ということになります。
// 読み取った温度をJsonObjectにセットする。
const auto temperature = dht.readTemperature();
if (isnan(temperature)) {
setError(root, "Error reading temperature!");
}
else {
root["temperature"] = temperature;
}
DHT::readTemperature()
でセンサーが計測した温度を受け取ることができます。
失敗した場合はNAN
が返ってきます。
ここではNAN
を捉えたらsetError()
でroot
にerror関連の値をセットしています。error値のセット方法は人によって実装方法がいろいろあると思うので実装は載せていません。
返り値がNAN
ではなかった場合、JsonObject
のroot
にkey=temperature
,value=読み取った温度
を追加しています。
例えば、読み取った温度が25.5°Cだった場合は{"temperature"=25.5}
のような感じになります。
湿度も同じことやっているので省略。
// Jsonのシリアライズ。
root.printTo(Serial);
Serial.print("\n"); // 改行文字をデリミタとして使う。
}
JsonObject::printTo()
の引数はJsonの書き込み先を指定します。今回はシリアル通信を行いたいのでSerial
を指定します。
データを受信する際に改行文字あったほうが楽そうだったので今回は改行文字もシリアルポートへ出力しています。
つぎにやること
TypeScript
+ Node.js
でJSONデータを受け取ってブラウザで表示させるところまでは記事にしたい。
本当はそれも含めた記事にしたかったのですが、そろそろ真面目に就職活動を行おうと思うので、ちょっと後回しになってしまう形に。
キチンと書き終えるのがいつになるのかわからなかったのでとりあえず一区切りとしてここでいったん投稿することにします。