M5Stamp Picoでできること 〜畑の「環境情報採取装置」をつくる

これまで、畑に「ソーラー発電システム」や「モバイルWi-Fiルータ」、「M5Camera」などのIoTデバイスを設置して、畑の写真を定期的にWebサーバに送信したりと、いろいろな実験をしてきました。

また、それらの実験と並行して、ソーラー発電システムの構成をシンプルにして、できるだけ安価になるようにしたり(記事は こちら)、設置の容易化のために、ソーラーパネルの取り付け方法を簡略化したり(記事は こちら)と、いろいろな検討も行ってきました。

このように、これまでも屋外でのIoT運用について、いろいろと試してはきましたが、これまで実施してきたのはいずれも、画像データをサーバに送信するなど、割とふざけた内容のものばかりでした。
今回は、これまでの検討結果を踏まえて、より実用的なIoTシステムをつくってみたいと思います。

具体的には、「畑の環境情報を採取する」ためのIoTシステムをつくります。
一定期間毎に、畑の「温度」「湿度」などの情報を採取し、Webサーバに送信したり、場合によってはメール通知したりするものです。

私が家庭菜園で楽しんでいるのは「露地栽培」ですので、たとえこのような情報が得られても、対策として実際にできることは限られますが、もしも「ハウス栽培」なら、温度が低すぎる時のみ暖房をつけたり、逆に温度が高ければ側面ビニールを巻き上げたり、土が乾いていたら水やりをしたりと、ハウス内の状況に応じて実施する作業がたくさんあると思いますので、このようなIoTシステムがあれば、作業の効率化に大いに役立つのではないかと思います。

具体的な仕様は、以下のような感じにしようと思います。

  • 農業に役立ちそうな環境情報はいろいろありますが、今回は「気温」「湿度」「土中温度」「土中水分量」を採取することとします。手持ちのセンサで対応できるのが理由です。
  • マイコンデバイスとしては「M5Stamp Pico」を使います。これまでの調査で、ディープスリープありの間欠動作であれば、非常に低電力で動かせる見込みが得られている(記事は こちら)のが理由です。上記4つのセンサを、ひとつのM5Stamp Picoにつなぎ、1台で全てのデータを採取します。
  • マイコンやセンサへの電源供給には、「工作用の小型ソーラーパネル」+「単三型ニッケル水素電池4本」を使います。こちら の記事では「2Wソーラーパネル2枚」+「単三型ニッケル水素電池4本」で「M5Camera」を常時稼働させていますが、「M5Stamp Pico」は「M5Camera」よりも大幅に低電力なので、この構成に対して、パネルを1枚に減らします。
  • 防水ボックスの上部に、ひさしを兼ねてソーラーパネルを取り付けます(記事は こちら)。電池やマイコンを全て防水ボックスの中に入れることで、全てが一体化され、設置作業が容易になります。



特にソーラーパネルや電源周りに関して、私はこの分野の専門家ではなく、ネットや書籍で調べた情報に基づいて検討・実施しています。
正常動作や安全性などは保証できませんので、本記事を参考にされる場合は自己責任にてお願いいたします。

「気温」「湿度」の採取には、M5Stack社の「ENV IIユニット」を使います。I2Cで温度と湿度を採取できます(このセンサでは、その他に「気圧」情報も採取できますが、気圧は農業にそれほど関連しなさそうなので、今回は採取しません)。
「ENV IIユニット」の使い方については こちら をご参照ください。


「土中温度」の採取には、「DS18B20」という防水型の温度センサを使います。「1-Wire」という通信規格で温度を採取できます。今回は、上記「ENV IIユニット」と本センサの採取データの差異を確認するため、本センサをふたつ使い、「土中温度」だけでなく「気温」も採取しようと思います(つまり「気温」は「ENV IIユニット」と「DS18B20」の両方で採取します)。
「DS18B20」の使い方については こちら をご参照ください。


「土中水分量」の採取には、アマゾンで購入した「静電容量型土壌水分センサ」を使います。
水分量をアナログ値で採取できます。水分量が「高い」とアナログ出力端子の電圧が「低く」、「低い」と電圧が「高く」なります。
「静電容量型土壌水分センサ」の使い方については こちら をご参照ください。


なお、本来ならば、知りたいのは「体積含水率(=水の体積/土の体積)」のような値ですが、本センサで得られるのは電圧値であり、「高い」「低い」の関係も「体積含水率」とは逆になっています。
また、センサで採取した「電圧値」を「体積含水率」に変換する式を求めるには、実際にセンサを設置する場所の土を使って「校正」を行わなければならないようです。
今回は、土が乾いているかどうかの相対的な状況が分かればいいので、精度は全く気にしないのですが、計算式を使って数値を変換できることだけは確認しておきたいので、同じセンサをつかって校正を行った方のブログ記事(こちら)を参照させていただき、この記事に記載の数値をそのまま使って計算式をつくることにしました。

なお、この土壌水分センサは基板がむき出しです。そのため今回は「UVレジン」をつかって基板部分を封止しておきました。

スケッチは、以下のような感じになります。

#include <WiFi.h>
#include <Wire.h>
#include "SHT3X.h"
#include <OneWire.h>
#include <DallasTemperature.h>

#define sensorVdd 25

SHT3X sht30;
OneWire oneWire(19); // oneWire bus
DallasTemperature sensors(&oneWire);

DeviceAddress temp3 = { 0x28, 0xA1, 0xE7, 0x06, 0x5F, 0x20, 0x01, 0x4C };
DeviceAddress temp5 = { 0x28, 0x2C, 0x24, 0x11, 0x5F, 0x20, 0x01, 0x3E };

float val0 = 0.0; // temperature of oneWire(temp3)
float val1 = 0.0; // temperature of ENV.II unit
float val2 = 0.0; // humidity of ENV.II unit
float val3 = 0.0; // temperature of oneWire(temp5)
float val4 = 0.0; // soil moisture

RTC_DATA_ATTR float val0_prev = 0.0; // previous value of val0
float th_val0 = 30.0; // threshold value of val0 for send mail

const char*  ssid      = "XXXXXXXX";
const char*  password  = "XXXXXXXX";

unsigned long interval = 600; // unit:sec

void setup() {
  Serial.begin(115200);
  pinMode(sensorVdd, OUTPUT);
  digitalWrite(sensorVdd, HIGH);
  delay(100);

  pinMode(36, INPUT); // capacitive soil moisture sensor
  Wire.begin(21, 22); // ENV.II unit
  sensors.begin();    // oneWire

  // WiFi Connect
  Serial.printf("Connecting to %s\n", ssid);
  WiFi.begin(ssid, password);
  while(WiFi.status()!=WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.printf("\nWiFi connected\n");

  // get data(ENV.II)
  if(sht30.get()==0) {
    val1 = sht30.cTemp;
    val2 = sht30.humidity;
  }
  // get data(oneWire)
  sensors.requestTemperatures();
  val0 = sensors.getTempC(temp3);
  val3 = sensors.getTempC(temp5);
  // get data(soil moisture)
  float x = analogRead(36) * 3.3 / 4096;
  float y = 1 / x;
  val4 = ( 4.0499 * y * y - 4.1973 * y + 1.1768 ) * 100;

  int flag_mail = 0;
  if(val0 >= th_val0 && val0_prev < th_val0) flag_mail = 1;
  val0_prev = val0;

  // send data
  if(!sendRequest(val0, val1, val2, val3, val4, flag_mail)) { // 測定値を送信する
    Serial.println("Failed to send request.");
  }
  Serial.printf("%.2f,%.2f,%.2f,%.2f,%.2f\n", val0, val1, val2, val3, val4);

  // WiFi Disconnect
  WiFi.disconnect(true);
  Serial.printf("WiFi disconnected\n");

  // Deep Sleep
  esp_sleep_enable_timer_wakeup(interval*1000*1000);
  esp_deep_sleep_start();
}

void loop() {}

boolean sendRequest(float val0, float val1, float val2, float val3, float val4, int mail_flag) {
  // 省略
}

ディープスリープ中は、センサにも電源供給したくないので、各センサに直接電源をつなぐことはせず、各センサの電源端子はM5Stamp Picoの「25番ピン」をつなぎます。
M5Stamp Picoは、起動するとすぐに「25番ピン」を「HIGH」にします。これで、M5Stamp Picoの起動中のみ、各センサに電源供給されるようになります。

「DS18B20」は、「1-Wire」という通信規格でデータ採取できますが、今回は「DS18B20」をふたつ使うので、あらかじめそれぞれのアドレスを調査しておき、そのアドレスを使ってデータ採取します。

M5Stamp Picoは、起動して「25番ピン」を「HIGH」にした後、Wi-Fiに接続し、その後「ENV IIユニットでデータ採取」「DS18B20でデータ採取」「土壌水分センサでデータ採取・変換」を行います。
また、「DS18B20(気温測定用)」の値が30°℃以上になった時、メール送信用フラグを「1」にします。
その後、全採取データおよびメール送信用フラグをWebサーバに送信、WI-Fiを切断し、10分間のディープスリープに移行します。

各パーツを、このように接続します。

今回は、ミニブレッドボードを使って接続したので、かなりぐちゃぐちゃになってしまいました。
ただ、回路図を見ても分かるとおり、センサや電池以外の部品はほとんどなく、配線ばかりですので、基板をきちんとすれば、かなりスッキリさせることができると思います。

こちら の記事で準備した、ソーラーパネル付きの防水ボックスに、M5Stamp Pico、ブレッドボード、電池などを詰め込みます。
ボックスから外に出ているのは、ソーラーパネルと各センサのみです。


実際に畑に設置するのに先立ち、まずは自宅ベランダのプランターに設置して、しばらく様子をみようと思います。
ボックス- センサ間の配線が短いので、かなり窮屈になってしまっています。畑に設置する際には、ケーブルを延長しようと思います。

「DS18B20(土中温度測定用)」と「土壌水分センサ」は、そのままプランターの土に差し込みます。

「ENV IIユニット」と「DS18B20(気温測定用)」は、プランター横の陰に置いておきます(直射日光が当たらないように、横に銀マットを立てかけておきます)。

設置してから5日ほど経過しました。今のところ、順調に稼働しています。

こんな感じで各データが採取できています。

なお、私がM5Stack、M5StickCの使い方を習得するのにあたっては、以下の書籍を参考にさせていただきました。


ごく基本的なところから、かなり複雑なスケッチや、ネットワーク接続など、比較的高度なものまで、つまづかずに読み進めていけるような構成になっており、大変わかりやすい本です。


このサイトで書いている、M5Stackシリーズ(M5Stack、M5StickCなど)に関するブログ記事を、「さとやまノート」という別のブログページに、あらためて整理してまとめました。

他のM5Stackシリーズの記事にも興味のある方は「さとやまノート」をご覧ください。