
こんにちは、原田です。
あ、待ってください。ブラウザを閉じないで。電波系の話題ではありません。
今回は観葉植物をモニタリングする仕組みをさっとつくり、さらにユーザ体験を上げるための応用まで行います。
TL;DR ※まとめです
- Wio Node, Grove土壌水分センサで観葉植物の土の乾き具合をノンプラグラミングで取得できるようにした
- 乾き具合の検知までに留め、水やり制御は敢えて行わなかった
- 乾き具合を毎朝Google Homeに発話させ、観葉植物の家電化に成功した
はじめに
妻が数日前に観葉植物の取扱に困っていました。
「観葉植物にいつ水を上げればいいのかわからない」
話を聞いてみると、うちには観葉植物があるのですが、どうも水分のコントロールが難しい種であることがわかりました。
毎朝水を上げるのは上げすぎになり、寒暖の差の激しい屋外には置けない。
水を上げた日をメモしておけばいいけどそれも面倒、なんとかならないの?ドラえもん!
もうーしょうがいないなぁのび太くんはー
てっててー「Wio NodeとGrove土壌水分センサー」!
用意した機材
すみません普通に説明します。

・Grove 土壌水分センサ(画像右上)
734円(スイッチサイエンス)
・Wio Node(画像右下)
Arduinoのマイコンです
ノンプログラミングでセンサーに繋げられる
1231円(スイッチサイエンス)
Wio NodeはArduinoマイコンの一種で、ESP-WROOM-02のチップが搭載されています。要はwifiに繋がります。Grove形式のセンサーも2個まで取り付けられる代物です。
スマフォ(Andoroid/iOSともOK)からセンサーのセットアップができ、クラウドからセンサーを操作するエンドポイントが無料で使えます。それでいて本体価格1200円ほどと,ランニングコストなしと大変お安いです。
※ Groveの形式にコネクタが合っていたとしてもすべてのセンサが対応しているわけではありません。3.3VのGroveセンサーのみ標準で使用可能です。ただしGeneral Input/Outputの項目を選べばマニュアル操作することも可能です。
Grove土壌水分センサは、そのものズバリ土の中の水分を測定してくれるものです。端子間の電気伝導度(要は抵抗値)を読み取り、その値から水分量を測定しています。
Groveとはコネクタの形式の一種であり、基本的に線をつなげるだけでセンサーを扱えるようになるものです。
スイッチサイエンスや秋葉原の千石通商などで入手できると思われます。
使い方
使い方は簡単です。
1. Wio Nodeに土壌水分センサを繋げます。配線はこれだけ。ソフトウェアエンジニアにやさしいですね。
2. Wio Nodeに電源を供給します。microUSBを挿すだけで電源が入ります。消費電力はせいぜい0.6Wです。
![]() |
![]() |
3. スマフォのアプリからWio Nodeをネットワークに接続します。自宅のwifiに参加させましょう。
4. Wio Nodeの右側に土壌水分センサが付いていることをアプリから設定します。一覧から選択するだけです。
5. Update Firmwareをします。
6. 成功した後、View APIを開きます。
こうすると、なんと外部から接続可能なAPIが発行されます。View APIを押して確認してください。
Test RequestのところのGETボタンを押すか、https://us.wio—access_token=★ の部分にブラウザからアクセス(HTTP GET)すると、センサーの値が取得できます。
通常Arduinoのマイコンを制御する場合、Arduino IDEの導入といくつかのコーディングが必要になります。
今回手動で同じことをしようとするならば、wifi接続、センサーからのデータ取得、センサーデータを外部に送信などでしょうか。これをC/C++などで実装するわけです。これがちょっと面倒ですよね。
このあたりをより楽にしてくれるのがWio Nodeの仕組みです。
ユーザはただ無線の設定とセンサーのセットアップを行えばよいだけ。気軽ですね。

そしてこうなりました。
セットアップ含め、センサーデータの取得まで15分というところです。非常に楽ですね。
センサーを観葉植物の土に挿してURLにアクセスすると、でました180!土の中の水分量が取れました。これはかなり乾いている状態です。
(0-300 乾燥状態 300-700 湿った状態 700-950 ほぼ水没の状態)
水分量の検知だけで十分な場合はここまでで良いでしょう。
あとは気になったタイミングでhttpリクエストを送信したら良いだけです。
めでたくうちの観葉植物が「家電」になりました笑
応用開発
さて、センサー値は該当URLにアクセスすることで取得できるようになりましたので、ここからはPythonなども使って便利になるまで応用してみましょう。
若干蛇足感はありますが、やりたいのだから仕方ないです。
課題をこうしましょう。毎朝7時10分になると、土壌水分センサーの値をチェックします。
乾き具合によっては、家の中にあるGoogle Homeを用いて水やりを人に促す形とします。
乾いている場合 → 「おはようございます。植物です!水をください!」と話す
十分湿っている場合 → 「おはようございます。植物です!水は要らないです!」と話す
幸い、GoogleHomeに発話させるためのPythonライブラリである、pychromecastが存在しました。
どうやらmp3ファイルをローカルネットワーク上から閲覧できるようにしておけばよいとのこと。ふむ。戦略が決まりました。
今回はpipでインストールすべきライブラリは、venv, requests, pychromecast, flaskです。
対処概要は以下の通りです。
- 仮想python実行環境を作る
- 喋る内容を格納したmp3ファイルを用意する
- 喋る内容を格納したmp3ファイルを提供するwebサーバを用意する
- ラズパイから該当の時間でシェルスクリプトをcron実行してpythonファイルを実行する
- pythonファイル内でセンサー値取得とGoogle Homeへの発話を実行する
これで皆さんもご経験したことがあるであろう、「あれ?リモコンどこだっけーー??」事件を解決できますね!
やり方はこれに限らないと思います。
AWSを使えるならば、CloudWatch EventとLambdaというところですかね。
ただ、どうしてもホームネットワーク内での実施になるので、それだけのためにクラウドを使うのも変な感じです
(センサー値を得るために外部に問い合わせてるじゃないか?あーあー聞こえません)
では方法の詳細です。
仮想python実行環境を作る
今回は2つの環境を用意しましょう。
(環境名)flaskserver : Webサーバーflaskが動作する環境。
gTTS、音声ファイルもこちらに配置します。
(環境名)checkplant : 植物の水分を取得するアプリの配置環境
flaskserver環境ではflask, gTTS、checkplant環境ではrequests, pychromecastをインストールします。
もちろんこれから作成するものは非常に軽量で、ラズパイでも動作します。
そのため諸々考慮してラズパイで実施するのが良いでしょう。
cd /home/pi mkdir workspace_py python3 -m venv flaskserver python3 -m venv checkplant
喋る内容を格納したmp3ファイルを用意する
google homeはmp3ファイルを与えることでその内容を発話します。
テキスト内容をmp3にして保存する、というだけであれば、gTTS(google text to speech)を使いましょう。
flaskserverの方で作業をしましょう。
cd /home/pi/workspace_py source flaskserver/bin/activate // python実行環境がflaskserverに切り替わる cd flaskserver pip install flask, gTTS pip freeze // flask,gTTSのインストールをかくにん!よかった。する // フォルダを作成しておく mkdir files cd files // pythonコンソールからファイルを作成する。 python
以下の内容を打ち込みmp3を作成する
from gtts import gTTS
> tts = gTTS(‘おはようございます。植物です!水はいらないです’, ‘ja’)
> tts.save(‘checkplant_enoughwater.mp3’)
これだけでcheckplant_enoughwater.mp3ファイルが作成されます。機械音声で水は要らない旨を語るmp3ファイルになります。
これで「おはようございます。植物です!水をください」と「おはようございます。植物です!水はいらないです」を用意するわけです。
喋る内容を格納したmp3ファイルを提供するwebサーバを用意する
GoogleHome内にはデータを保存できないため、GoogleHomeからの問い合わせ先を用意しておく必要があります。
ここはPythonで軽量なWebサーバを立てておきましょう。Flaskが良いでしょう。
引き続きflaskserver環境です。
cd /home/pi/workspace_py/flaskserver/files touch mp3server.py
mp3server.pyを以下に修正する
import os from flask import Flask, make_response app = Flask(__name__) @app.route("/mp3/<string:file_name>", methods=['GET']) def getMP3File(file_name): response = make_response() if not os.path.exists(file_name): return response response.data = open(file_name, "rb").read() response.headers['Content-Disposition'] = 'attachment; filename=' + file_name response.mimetype = 'audio/mp3' return response if __name__ == '__main__': app.run(debug=False, host='0.0.0.0', port=8080)
該当するmp3ファイルがあった場合にそれを返しているだけです。
先程作成したmp3ファイルはflaskサーバの実行ファイルmp3server.pyと同一フォルダに格納しておきましょう。
また、常時問い合わせが可能なように、バックグラウンド実行しておきましょう。
※ nohupでログアウト後も動作させるようにします
nohup python mp3server.py > out.log &
ラズパイから該当の時間でシェルスクリプトをcron実行してpythonファイルを実行する
この点技術的な特徴は何もないので、かなり説明を割愛します。
crontab -e
10 7 * * * bash /home/pi/workspace_cron/checkplant/CheckPlant.sh
CheckPlant.sh
#!/bin/bash cd /home/pi/workspace_py/checkplant/bin source activate cd /home/pi/workspace_py/checkplant/files python ./main_pychromecast.py
※ venvを使っている関係でactivateを入れていますが、1つのpython環境であればshell実行でなくcronから直接python main_pychoromecast.pyで良いですね
pythonファイル内でセンサー値取得とGoogle Homeへの発話を実行する
いよいよ最後です。
先程のFlaskのものとはまた別の仮想python実行環境で作業を行います。
cd /home/pi/workspace_py source checkplant/bin/activate // checkplant環境に切り替わります。 cd checkplant pip install requests, pychromecast pip freeze // requests, pychromecastのインストールをかくにん!よかった。する mkdir files touch main_pychromecast.py
main_pychromecast.pyの内容を以下に修正する
acess_tokenはWio Nodeの設定部分で得られた値(★)を用います。
# coding: utf-8 import requests import pychromecast def check_water(): # http get to wio node (Get Moisture value.) url = 'https://us.wio.seeed.io/v1/node/GroveMoistureA0/moisture?access_token=XXXXXXXXXXXXXXXXX' res = requests.get(url) if not res.ok: print('get value not works. nothing to do.') return -1 return res.json()['moisture'] def send_to_chromecast(file_name, target_cast_ip, mp3server_ip_port): # mp3 file path.(hosted on raspberry pi) mp3_url = 'http://' + mp3server_ip_port + '/mp3/' + file_name cc = pychromecast.Chromecast(target_cast_ip) cc.wait() mc = cc.media_controller mc.play_media(mp3_url,'audio/mp3') return def main(): moisture = check_water() if moisture < 0: return if moisture < 700: file_name = 'checkplant_overwater.mp3' if moisture < 500: file_name = 'checkplant_enoughwater.mp3' if moisture < 300: file_name = 'checkplant_littlebitdry.mp3' if moisture < 150: file_name = 'checkplant_toodry.mp3' send_to_chromecast(file_name = file_name, target_cast_ip='GoogleHomeのIP', mp3server_ip_port='MP3サーバのIP:ポート番号') if __name__ == '__main__': main()
ふう。お疲れ様でした。
これでひとまず完了です。実行権限など気になる方はどうぞchmodをしてください。
これで、該当の時間になれば土壌水分センサの値を取得、土の湿り具合から水の要不要を音声で教えてくれます。
最後に
いかがでしょうか。色々行っているように見えて、実はセンサのによる検知しか行っていません。
しかしこれでも良いと私は考えます。というのも、以前私の主催しているTechAgitatorsの活動で話が上がったのですが、
世の中のIoTソリューションは、よく検知、制御、分析までを行うことがソリューションとして取り扱われがちです。
ですが、実はフィールドレベルでは検知だけでも十分なときがあるわけです。例えばこの例。
・遠方にある農地の乾き具合を見て、目の前の水門を開けるかどうか判断する
水門の開け締めにはかなり力が必要なのと、その動作に誤りがあると大変です。
これを無理に制御までIoTで自動化するとなると、誤動作時に作物に甚大な被害を及ぼす可能性があります。
その誤作動を防ぐために十分過ぎるテストを考慮することになるかもしれませんが、それを考慮するよりも「制御はやらない」「検知だけにする」とした方がどんなに提供までが早くなるし安くつくでしょうか?
それならば遠方の農地に土壌水分センサとそのセンサデータを送信するマイコンを用意したら終わりです。
顧客が本当に求めていたものをいつも提案できるようでありたいものですね。
ここまで読んでいただきありがとうございました。
オチ
ある朝、朝食を食べていると妻が言いました。
「今朝は観葉植物ちゃんが水要らないって言ってきたよ」
そうしたら私がドヤ顔で言うわけです。
「何言ってんだ、植物が喋るわけねえだろ」
おしまい。