Arduinoで作るワイヤレス土壌湿度監視システム:センサー編

以前Raspberry Piで土壌湿度を計測して記録、通知をしてくれるシステムを作成したのですが、常に観葉植物が電源につながっているため配線が掃除の邪魔になったり、土壌水分センサーが錆びて計測結果がおかしくなったりと色々と問題点があり、最終的には物置に封印されてしまいました。
今回はこれらの問題を解決するため、Arduino Unoを使って電池で動く土壌湿度センサーを作成しようと思います。
センサーは金メッキされたものを使って様子をみてみます。

構成

Arduinoが取得したセンサー情報をWi-Fi経由でRaspberry Piに送り、それを受け取ったRaspberry Piがメールを配信したり、Firebaseにデータを格納したりする構成にします。
格納されたデータは、Ionicで作成したアプリで確認できるようにします。


1.Wi-Fiに接続する。

まずはArduinoにWi-Fiモジュールを接続し、WI-FI経由でデータを送れるようにします。
ググってみると色々な方法が存在しているようですが、下記記事を参考に実装してみました。

が、全くWi-Fiに繋がらない。
何度作り直しても、何度見返しても原因がわからず、そしてWi-Fiに繋がらない。
テスターを使ってみても問題なく全て通電しているし、プログラムも最小構成にしいるのに。。
電子回路初心者のソフトウェア出身エンジニアは、デバッグ、エラーログがないと何もできません。。

気を取り直してもう一度ググってみると、こんな記事が。
arduino wifiと温度センサを使い簡易的なグラフに出力してみた。(前編)

「Wi-Fiシールド」なるものがあり、これをArduinoに繋げるだけでWi-Fi接続ができるというじゃないか。

ということで、記事を参考にWi-FiシールドをArduinoに接続します。

ピンヘッダをWi-Fiシールドにはんだ付けして、それをArduinoにつけるだけ。簡単!

Arduinoに書き込むプログラムはほぼ記事のままでこんな感じになります。

#include <httpclient_esp8266_at.h>

#define SSID        "YourSSID"
#define PASSWORD    "YourPassword"

// Arduino UNO の場合は、例えばデジタル入出力の 2 番, 4 番ピンを利用して
// ESP-WROOM-02 とシリアル通信するように設定します。

const byte rxPin = 2; // Wire this to Tx Pin of ESP8266
const byte txPin = 4; // Wire this to Rx Pin of ESP8266
HttpClient_ESP8266_AT httpClient(rxPin, txPin);

void setup() {
    // HardwareSerial settings
    Serial.begin(115200);

    // Setup HttpClient_ESP8266_AT
    while(true) {
        if(httpClient.statusAT()) { Serial.println("AT status OK"); break; }
        else Serial.println("AT status NOT OK");
        delay(1000);
    }
    while(true) {
        if(httpClient.connectAP(SSID, PASSWORD)) { Serial.println("Successfully connected to an AP"); break; }
        else Serial.println("Failed to connected to an AP. retrying...");
        delay(1000);
    }
    while(true) {
        if(httpClient.statusWiFi()) { Serial.println("WiFi status OK"); break; }
        else Serial.println("WiFi status NOT OK");
        delay(1000);
    }
}

void loop() {
    while(true) {
        // Let's start HTTP POST request
        // 同じネットワーク上にポート3000で立てたローカルサーバにjson形式のデータを送ります。
        httpClient.post("192.168.xxx.xxx", "/hoge", "{\"value\":\"test\"}", "application/json", 3000);

        // レスポンス status code が 0 以上であればリクエスト成功です。
        //   -1: ノイズ等でシリアル通信ができず、そもそもデータ送信ができなかった。
        //    0: データ送信はできたが、受信データがノイズで壊れてしまっていた。
        //   else (>0): 受信データから正常に HTTP レスポンス status code が得られた。

        if(httpClient.responseStatusCode() >= 0) {
            // 本ページでは電圧レベルコンバータを用意していない想定のため、
            // 受信データが壊れている可能性が高く、したがって 200 が 100 になっていたりするため、
            // 値には興味をもたず、0 以上の値が得られることが重要であると考えてコーディングします。

            Serial.println("SUCCESS");
            break;
        }
        else {
            Serial.println("FAILURE, retrying...");
        }
    }
    delay(3000);
}

以下のように「WiFi status OK」と表示されれば無事Wi-Fi接続完了です。
(最初の数回は接続エラーが起きて焦った。。)
まだ送信先を作成していないので、post自体はエラーとなります。

2.センサーで受け取った値をサーバーへ送る。

今回はこのセンサーを使います。
Arduino用 土壌湿度センサー

使い方はこちらのドキュメントを参考にします。
https://www.dfrobot.com/wiki/index.php/Moisture_Sensor_(SKU:SEN0114)

センサーは下記のように接続します。

  • アナログアウトプット(青)→A0
  • GND(黒)→GDN
  • 電源(赤)→5V

プログラムは以下のように修正します。

#include <HttpClient_ESP8266_AT.h>

#define SSID        "YourSSID"
#define PASSWORD    "YourPassword"

// Arduino UNO の場合は、例えばデジタル入出力の 2 番, 4 番ピンを利用して
// ESP-WROOM-02 とシリアル通信するように設定します。

const byte rxPin = 2; // Wire this to Tx Pin of ESP8266
const byte txPin = 4; // Wire this to Rx Pin of ESP8266
HttpClient_ESP8266_AT httpClient(rxPin, txPin);

// ここから追加
int soilMoisture;
char trans[20];
// ここまで

void setup() {
    // HardwareSerial settings
    Serial.begin(115200);

    // Setup HttpClient_ESP8266_AT
    while(true) {
        if(httpClient.statusAT()) { Serial.println("AT status OK"); break; }
        else Serial.println("AT status NOT OK");
        delay(1000);
    }
    while(true) {
        if(httpClient.connectAP(SSID, PASSWORD)) { Serial.println("Successfully connected to an AP"); break; }
        else Serial.println("Failed to connected to an AP. retrying...");
        delay(1000);
    }
    while(true) {
        if(httpClient.statusWiFi()) { Serial.println("WiFi status OK"); break; }
        else Serial.println("WiFi status NOT OK");
        delay(1000);
    }
}

void loop() {
    while(true) {
        // ここから追加
        soilMoisture = analogRead(0);
        Serial.println(soilMoisture);

        char *json = &trans[0];
        sprintf(json, "{\"soilMoisture\":%d}", soilMoisture);
        // ここまで

        // Let's start HTTP POST request
        // ここを修正
        httpClient.post("192.168.xxx.xxx", "/soil-moisture", json, "application/json", 3000);

        // レスポンス status code が 0 以上であればリクエスト成功です。
        //   -1: ノイズ等でシリアル通信ができず、そもそもデータ送信ができなかった。
        //    0: データ送信はできたが、受信データがノイズで壊れてしまっていた。
        //   else (>0): 受信データから正常に HTTP レスポンス status code が得られた。

        if(httpClient.responseStatusCode() >= 0) {          
            // 本ページでは電圧レベルコンバータを用意していない想定のため、
            // 受信データが壊れている可能性が高く、したがって 200 が 100 になっていたりするため、
            // 値には興味をもたず、0 以上の値が得られることが重要であると考えてコーディングします。

            Serial.println("SUCCESS");
            break;
        }
        else {
            Serial.println("FAILURE, retrying...");
        }
    }
    delay(3000);
}

3.データをサーバで受け取る

データが受け取れることを確認したいだけなので、簡単なAPIサーバーを作成します。
今回はfastify(Node.js)で受け取った値を確認する処理を作成します。
fastifyでのAPIサーバーの作成方法は、こちらにまとめてあります。
FastifyをTypeScriptで利用する方法

// server.ts
import * as fastify from 'fastify'
import * as cors from 'cors'

const server = fastify();

class REST {
  constructor() {
    this.init();
  }

  init() {
    server.use(cors());
    server.post('/soil-moisture', this.postHelloHandler);

    server.listen(3000, err => {
      if (err) throw err;
      console.log(`server listening on ${server.server.address().port}`);
    });
  }
  postHelloHandler (req: any, reply: any) {
    console.log("POST success:)");
    console.log(req.body);

    reply.send();
  }

}

new REST();

実行結果です。
シリアルモニタから、無事Wi-Fi経由で値が送れていることが確認できます。

4.電池で動かす

最後はArduinoを電池につないで、完全なワイヤレス状態にします。
下記記事を参考に、昇圧型DC-DCコンバーターを使って単三電池2本でArduinoを動かします。
Arduinoを電池で動かす

結果、Arduinoの「L」とマークされたLEDが点滅しているだけで動かない。。
調べてみると、Arduinoは起動中に「L」とマークされたLEDが点滅するので、電圧不足で起動できないときは点滅したままになるのだとか。
Wi-Fiシールドを外すと動くので、おそらくWi-Fiモジュールの消費電力が大きいのでしょう。

とりあえず電池を2本から4本へ変更。
1.5 x 4 = 6Vで無事動きました。

サーバー側でも無事データを受け取れていることが確認できます。

これでWi-Fi、電源共にワイヤレス化された土壌湿度監視センサーの完成です。
次回はセンサーか送られてくる情報を受け取るサーバーをRaspberry Pi上に構築して、データの保存やメールの送信などを行えるようにします。
Arduinoで作るワイヤレス土壌湿度監視システム:Fastifyサーバー編


追記

現状だと、電池の減りが早く1日くらいしか持たなかったので、下記の記事を参考にスリープを実装しました。
【Arduino】sleepを利用して電力消費を抑えてみた

今回利用するWATCHDOGタイマは最長8秒しかスリープしませんが、指定の時間に到達するまでスリープを繰り返すことで8秒以上のスリープが実現できるようです。
それでもかなり消費電力を抑えられると思うので、この状態で使って様子を見てみようと思います。

The following two tabs change content below.
Akihiro Tanaka

Akihiro Tanaka

Engineer/UI Designer
UI設計を得意とするエンジニア。 現在はDApps開発しています。
好きな言語はTypeScript、好きなフレームワークはIonic、Angular。 趣味はハーレー、キャンプ、アンティーク。
WEB: http://tanakas.org/