先日植物の水やりをサボってしまったせいで、書斎のシンボルツリーの葉っぱがほとんど全部落ちてしまいました。。大きめの木なので鉢も深く、水やりの頻度が難しいんです。。。LINEで水がなくなったことを伝えてくれたら嬉しいなと思い、作ってみました。
仕様:
- 5V電源で動くこと
- 水やりタイミングをLINEで通知を受け取れること
- なるだけシンプルなこと
- 複製が簡単なこと(半田付け最小)
使ったもの:
あまり時間をかけるのもなと思い、手軽にできる構成を考えてみました。使ったのは、下記だけです。
- M5Stamp C3U(マイコン) : https://amzn.to/4iICWlR
- 土壌センサー(adafruit stemma soil sensor) : https://amzn.to/4fpgBai
- ケーブル : https://amzn.to/3VLjA5J
- 回路保護のためのレジン(なんでもいいですが、自分はずっとこれを使っています。):https://amzn.to/4iUhA5p
- レジン硬化用のライト:https://amzn.to/49IvoeX
仕上がり:
結構シンプルにできました。最近の電子工作は楽ちんですね。電子工作というかほぼプログラミングでできてしまいます。
今回選定したセンサは静電容量式のセンサで、I2Cでその値を取得できるものを選定しました。土が乾くとセンサが感知する静電容量が下がり、事前に設定した閾値を下回ると通知がきます。通知が来たら水やりします。すると静電容量が上がり、潤ったことを通知してくれます。
またマイコンに搭載されたボタンを押すと、現在の静電容量をLINEしてくれるようにしています。状況によって乾燥・湿潤時の静電容量は変わるはずなので、プログラム修正用に確認できるようにした次第です。
作り方
下記ような手順で説明します。
- センサ配線
- LINE 設定
- プログラミング
1.センサ配線
下記の通り配線します。電源ラインとI2Cのラインで合計4本だけです。I2CのポートはデフォルトではGPIO8,9のようなのですが、GPIO9はマイコン基盤上に設置されているボタンに既に配線されていて、しかも今回はこのボタンも使用したいため、I2CはGPIO8とGPIO7にアサインしました。このケーブル (https://amzn.to/3VLjA5J)を使えば、半田付はマイコン側だけでいいので楽です。センサ側はJSTのPHコネクタが採用されていますが、個人で圧着機とコネクタを揃えるのは割に合わないので、ASSY化されたケーブルをおとなしく買いましょう。仕上がりも綺麗になります。
また、センサに乗っている回路の保護のため、回路部をUVレジンで保護しました。もろに水があたる部分ですから、何かしら保護しないと錆びて壊れてしまいます。
2.LINE設定
LINEの通知でよく使っていたLINE Notifyが2025年3月31日にサービス終了するとのことで、今回初めて「LINE Messaging API」を使用しました。
LINE Messaging API:https://developers.line.biz/ja/services/messaging-api/
設定の方法とTokenの取得はこちらのサイトがとても丁寧に書かれています。下記参考にしてください。
https://sample.msr-r.net/m5stack-line-messaging-api/
上記サイトに従いTokenをゲットできたら、メモっておきましょう。後ほどプログラムに書き込みます。
3.プログラミング
プログラムはArduino IDEで行っていきます。下記からダウンロードしてインストールしてください。
次に、M5StampをPCが読み込めるようにドライバをインストールします。
必要なものは揃ったので、Arduino IDEを立ち上げてM5Stamp C3U を接続します。ここでArduino IDEにM5Stamp C3Uを認識してもらうために、[tool > Board > Boards Maneger]で「ESP32」と検索してインストールします。
そうすると[Tool > Board > ESP32 ]からM5StampC3が出るようになりますので選択します。
今回のプログラムは下記になります。これを書き込めば動くはずです。
まず電源ONでWifiに無事接続されると、LINEに「Hello!」と通知が来ます。その後、マイコンのボタンを押してみてください。すると現在のセンサの測定値が、LINEで届きます。センサを鉢に刺した状態でボタンを押して、鉢が乾いている時と水をあげた後それぞれの測定値をメモります。自分の環境では、水をあげたあとで「1015」、乾燥状態で「900」ぐらいでしたので、プログラムの条件分岐の条件を、水あげ完了時の通知「1010」、乾燥時の通知「950」と設定しました。こちらの値は適宜ご自身の環境に合わせて設定してください。
#include <WiFiClientSecure.h>
#include <WiFi.h>
#include <Wire.h>
#include "Adafruit_seesaw.h"
#define BTN 9
Adafruit_seesaw sensor;
const char* ssid = "WifiのSSIDを入れる";
const char* password = "Wifiのパスワードを入れる";
const char* host = "api.line.me";
const char* token = "LINE Messaging APIのTokenを入れる";
bool moist_announcement = false;
bool dry_announcement = false;
boolean line_notify(String msg) {
WiFiClientSecure client;
client.setInsecure();
if(!client.connect(host, 443)) {
Serial.println("connect error!");
return false;
}
String query = String("{\"messages\":[{\"type\":\"text\",\"text\":\"") + msg + "\"}]}";
String request = String("")
+ "POST /v2/bot/message/broadcast HTTP/1.1\r\n"
+ "Host: " + host + "\r\n"
+ "Authorization: Bearer " + token + "\r\n"
+ "Content-Length: " + String(query.length()) + "\r\n"
+ "Content-Type: application/json\r\n\r\n"
+ query + "\r\n";
client.print(request);
return true;
}
void setup() {
pinMode(BTN, INPUT_PULLUP);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
line_notify("Hello!");
Serial.begin(115200);
Wire.begin(8, 7);
if (!sensor.begin(0x36)) {
Serial.println("ERROR! seesaw not found");
while(1) delay(1);
} else {
Serial.print("seesaw started! version: ");
Serial.println(sensor.getVersion(), HEX);
}
}
void loop() {
uint16_t cap = sensor.touchRead(0);
if(digitalRead(BTN) == LOW) {
String msg = "容量の値は " + String(cap) + " です。";
line_notify(msg);
}
if((cap>1010) && (moist_announcement==false)){
line_notify("潤いました!("+String(cap)+")");
moist_announcement = true;
dry_announcement = false;
}
if((cap<950) && (dry_announcement==false)){
line_notify("水をください!!("+ String(cap)+")");
moist_announcement = false;
dry_announcement = true;
}
delay(1000);
}
Comments