M5Atomと土壌水分センサユニットで植木の水分を監視してBLEで送信する

M5Stack用のGrove接続する土壌水分センサユニット(Earth Sensor)をM5 Atom Liteに接続して、データをBLEでブロードキャストしてみました。
ついでにラズパイでBLEを受信してみました。

土壌水分センサユニット(Earth Sensor)

こちらのセンサーはアナログ出力を持っていますので、M5側もアナログ端子に接続する必要があります。
幸いM5 Atom LiteのGrove端子はアナログ入力に対応しているようなので、Groveで接続OKです。

M5Stack用土壌水分センサユニット – SwitchScience
https://www.switch-science.com/catalog/4049/

EARTH – 公式ページ
https://docs.m5stack.com/#/en/unit/earth

M5Atom プログラム

M5Stack用のサンプルを基にIOピンを analogRead(36) から M5Atom 用に anaogRead(32) へ変更します。
LCD表示も削除しています。

setAdvData() でBLEのadvertisement packet dataにTest Manufacturer の0xffffとしてanalogReadを2バイト、digitalReadを1バイトでセットしています。
10分間隔でBLEブロードキャストします。

GitHub – github.com/tyamazoe/EarthMonitor
https://github.com/tyamazoe/EarthMonitor

BLE Advertisement packet Manufacturer specific data

項目バイト
manufacture id 20xffff テスト用 manufacturer
device_id 2任意のID 例: 0x0101
analogRead_value 20x0000 – 0x0fff 水分センサアナログ値 0 – 4095
digitalRead_value 10x00 / 0x01 水分センサデジタル値 0/1
 
#include "M5Atom.h"
#include "BLEDevice.h"
#include "BLEUtils.h"
#include "BLEBeacon.h"
#include "esp_sleep.h"

#define GPIO_DEEP_SLEEP_DURATION     600  // sleep x seconds and then wake up

uint16_t analogRead_value = 0;
uint16_t digitalRead_value = 0;
uint16_t device_id = 0x0101;        // your any sensor device id

BLEAdvertising *pAdvertising;

void readEarthSensor() {
  analogRead_value = analogRead(32);
  digitalRead_value = digitalRead(26);
  Serial.printf("0x%04x, %d, %d\n", device_id, digitalRead_value, analogRead_value);
}

void setAdvData() {
  BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();

  oAdvertisementData.setFlags(0x06); // BR_EDR_NOT_SUPPORTED | LE General Discoverable Mode
  std::string strServiceData = "";
  strServiceData += (char)0x08;   // length
  strServiceData += (char)0xff;   // AD Type 0xFF: Manufacturer specific data
  strServiceData += (char)0xff;   // Test manufacture ID
  strServiceData += (char)0xff;   // Test manufacture ID
  strServiceData += (char)((device_id >> 8) & 0xff);
  strServiceData += (char)(device_id & 0xff);
  strServiceData += (char)((analogRead_value >> 8) & 0xff);
  strServiceData += (char)(analogRead_value & 0xff);
  strServiceData += (char)(digitalRead_value & 0xff);

  oAdvertisementData.addData(strServiceData);
  pAdvertising->setAdvertisementData(oAdvertisementData);
}

void setup() {
  M5.begin(true, false, true);
  delay(10);
  Serial.begin(115200);
  M5.dis.clear();
  pinMode(26, INPUT);
  Serial.println("\nEarth Test");

  // Create the BLE Device
  BLEDevice::init("Earth_Beacon");
  pAdvertising = BLEDevice::getAdvertising();

  // Read earth sensor value
  readEarthSensor();
  // set advertizing packet data
  setAdvData();

  // Start advertising
  pAdvertising->start();
  Serial.println("Advertizing started...");
  delay(1200);
  pAdvertising->stop();
  Serial.printf("enter deep sleep\n");
  esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
  Serial.printf("in deep sleep\n");
}

void loop() {
}

参考:M5Stack用サンプル EARTH.ino
https://github.com/m5stack/M5Stack/blob/master/examples/Unit/EARTH/EARTH.ino

ラズパイ用 BLE 受信 python プログラム

BLEライブラリに bluepy を使用しています。

# -*- coding: utf-8 -*-
from bluepy.btle import DefaultDelegate, Scanner, BTLEException
import sys
import struct
import time

class ScanDelegate(DefaultDelegate):
  def __init__(self):
    DefaultDelegate.__init__(self)

  def handleDiscovery(self, dev, isNewDev, isNewData):
    #print("addr: {0}, addrType: {1}, rssi: {2}".format(dev.addr, dev.addrType, dev.rssi))
    if isNewDev or isNewData:
      for (adtype, desc, value) in dev.getScanData():
        if desc == 'Manufacturer':
          #print(adtype, desc, value)
          if value[0:4] == 'ffff':
            #print("addr: {0}, addrType: {1}, rssi: {2}".format(dev.addr, dev.addrType, dev.rssi))
            self.parseManufacturerData(value[4:])

  def parseManufacturerData(self, data):
    (id, a_dat, d_dat) = struct.unpack('>HHb', bytes.fromhex(data[0:]))
    print("deviceId: 0x{0:04x}, analogRead: {1}, digitalRead: {2}".format(id, a_dat, d_dat))


if __name__ == "__main__":
  scanner = Scanner().withDelegate(ScanDelegate())
  while True:
    try:
      scanner.scan(3.0)
    except BTLEException:
      print(BLEException)

実行するとBLEで受信したデータのアナログ値とデジタル値を表示します。

pi@raspi:~/earth $ sudo python3 earth_scan.py
deviceId: 0x0101, analogRead: 4095, digitalRead: 1
deviceId: 0x0101, analogRead: 4095, digitalRead: 1
deviceId: 0x0101, analogRead: 4095, digitalRead: 1

モニタリングしてみる

鉢植えにセットしてみました。

ラズパイからambientに送信してみました。水をやった直後にアナログ値が 2000 程度に低下しています。
約2日間で 1000 上昇しているので、アナログセンサー値の最大値である 4095に向けて徐々に上昇しています。水分が減ってきていることが伺えます。

なお、最初に別の観葉植物で試したところ、土がふんわりした植木だったので、水はあっというまにしみこんで12時間ほどで水分を検知しなくなりました。

まとめ

無事に水分をモニタリングすることができました。
M5AtomはLCDが無いので、水分量でLEDの色点滅で水不足を知らせてもよいかもしれません。

電源を太陽光発電でまかなって、屋外に設置して太陽光発電ラズパイカメラと連携したいですね。これは次の課題。

コメントを残す

メールアドレスが公開されることはありません。

two × 2 =