Lambdaカクテル

Common Lispを書くMT-03ライダー(初心者)です

Raspberry PiとGROVE水分センサとPoEで観葉植物の土を監視するマシーン作った

ついに念願の観葉植物監視環境ができたので報告する.

f:id:Windymelt:20190312214907j:plain
動いている様子

f:id:Windymelt:20190312222607p:plain
Mackerelのダッシュボードにはこう写る

f:id:Windymelt:20190312223310j:plain
観葉植物くん

できること

このラズパイを使うと観葉植物の土壌の水分が監視され,水分量がMackerelに投稿される.水分量が一定量を切るとアラートがSlackやDiscordに流れ,水やりをするタイミングを逃さない.

f:id:Windymelt:20190312223616p:plain
アラート発報の様子

動機

観葉植物名人みたいな人は土に指をつっこんで「そろそろ水やりが必要」みたいなことをやっている印象だけれど,俺には無理だし完全に忘れてしまう. 実際観葉植物が枯れかけたり水のやりすぎで腐りかけたりしたので,定量的な評価ソリューションが求められたのである.

構成

Raspbetty Pi B+(Ethernetが刺さればなんでもいいと思うけどEthernetはPoEのオマケなので最悪なくてもいい)

最近は3B+というモデルがあるのでこれでいいんじゃないでしょうか(適当)

GROVEの水分センサ

水分に応じた抵抗値を出力するセンサ.土壌にも使えるのでこれを土に突き刺して使う.

www.switch-science.com

GrovePi+

GROVEをラズパイに突き刺すための部品.ラズパイからはI2Cデバイスとして認識されるので,SDKを経由してひっぱたくとセンサの値が取れる.

www.switch-science.com

俺のは2+だけど,今主流っぽいRaspberry Pi 3+に刺さるかはわからないがたぶん刺さる(適当)

PoEスプリッタ

電力供給にUSB充電器とケーブルを使っていたが,たいした消費電力でもないのにコンセントをまるまる1つ使うし,めちゃくちゃ邪魔で困った. とはいえポータブルバッテリでは充電し直すのが面倒だ.絶対に忘れそう. まあどこのご家庭にもPoEスイッチングハブがあると思うので,これを使って給電することにした. このキカイはPoEでやってくる48Vの電力をラズパイ用の5Vに落として,マイクロUSBに変換してくれる.

巷には簡易的に任意の電圧をLANケーブルに通せるパーツもあるようだが,PoEは電圧も規定しているはずなので正確にはPoEではない.それはただのLANケーブルに電流を流してそれを取り出すだけのパーツ. 何も考えずにPoEスイッチと普通の分離ケーブルを併用してしまうと,ラズパイに48Vがかかって昇天してしまうこと間違いなし.

PoEってなに??

Power over Ethernetの略.通信と電源のために2つもケーブル用意するのダルいから,LANケーブルで電力を供給しちゃおうぜ!という規格. 監視カメラや業務用の無線LANアクセスポイントなどに採用されていることが多い.ケーブルが1つですむというメリットの反面,機器が高価になりがちなデメリットがある.

PoEインジェクタと呼ばれる装置を使うと,PoE規格に沿った電力を供給することができ,PoE対応機器を動かすことができる. PoEスプリッタと呼ばれる装置を使うと,PoE規格に沿った電力を受電してDC端子やUSB端子に変換することができ,PoEに対応していない機器をPoEの電源で動かせるようになる. 高価なスプリッタは電圧を選択できるといった機能を持つが,今回は5V固定の安物を使っている.

長いLANケーブル

48Vもかかるので電圧降下なんかへっちゃらさ!どうせ5Vしか要らないのだ.

PoEスイッチングハブ

同僚とメルカリで購入したGEPoEL2P-ESW10Gというやつが家に転がっていたが,ただのバカハブとしてしか使っていないので可哀想,さっそく使ってあげよう.

ちなみにこのハブ,PoEのみならずVLANやらスパニングツリーやら,当職にはほぼ無縁の機能がたくさん付いており,丁寧なことにWebから設定ができる.最高だな.

ソフトウェア

センサから値を取り出してMackerelに投稿するためにちょっとしたプログラミングが必要だ. プログラムは以下の構成になっている.

  • センサからデータ取得する部
  • Mackerelに投稿する部

センサからデータ取得する部

GrovePi+にはオープンソースなSDKが付属していて,これをいじれば動かすことができる. C++やRuby,Pythonなど主流な言語はカバーしているが,この手の工作でよく使われるPythonには嫌な思い出しかない*1ので,最近流行りのGolangを選択した.

まずこのライブラリをインストールしておこう.

go get github.com/JGrotex/GrovePi/Software/Go/grovepi

そんで,次のようなコードを書いた.アナログポートA0からデータを取り出して表示するだけの簡素なコードだ.

package main

import (
        "github.com/JGrotex/GrovePi/Software/Go/grovepi"

        "fmt"
)

func runDirt() string {
        var g grovepi.GrovePi
        g = *grovepi.InitGrovePi(0x04) // GrovePi+はI2Cアドレス0x04で動作する
        defer g.CloseDevice()

        i, err := g.AnalogRead(grovepi.A0) //A0ポートからセンサの値を読む

        if err != nil {
                panic(err)
        }

        fmt.Printf("%d\n", i) // 表示する

        return "done"
}

func main() {
        runDirt()
}

これをビルドして$PATHの通った~/bin/に配置する.

$ go build grovepi_dirt.go
$ mv grovepi_dirt ~/bin/

動作は以下のとおり.

$ grovepi_dirt 
297

Mackerelに投稿する部

あとはこのデータをMackerelのサービスメトリクスとして定期的に投稿する. ここは馴染みのCommon LispでRoswellスクリプトとして実装した. 今回はコマンドライン引数で数値を受け取ることにする.

#!/bin/sh
#|-*- mode:lisp -*-|#
#|
exec ros -Q -- $0 "$@"
|#
(progn ;;init forms
  (ros:ensure-asdf)
  #+quicklisp (ql:quickload '(:jsown :local-time :dexador) :silent t)
  )

(defpackage :ros.script.post-humidity.3760098712
  (:use :cl))
(in-package :ros.script.post-humidity.3760098712)

(defparameter *mackerel-api-key* "ほげほげ")

(defmethod to-mackerel-time ((time local-time:timestamp))
  (local-time:timestamp-to-unix time))

(defun build-service-metrics-object (metric-name metric-time metric-val)
  (list (list
         :obj
         (cons "name" metric-name)
         (cons "time" (to-mackerel-time metric-time))
         (cons "value" metric-val))))

(defun post-service-metrics (service-name metric-name metric-time metric-val)
  (dex:post (format nil "https://mackerel.io/api/v0/services/~A/tsdb" service-name)
            :headers `(("x-api-key" . ,*mackerel-api-key*)
                       ("content-type" . "application/json"))
            :content (jsown:to-json (build-service-metrics-object metric-name metric-time metric-val))))

(defun main (&rest argv)
  (declare (ignorable argv))
  (post-service-metrics "bacuralis" "soil.humidity" (local-time:now) (parse-integer (car argv))))
;;; vim: set ft=lisp lisp:

これもビルドして$PATHが通った~/bin/に配置する.

$ ros build post-humidity.ros
$ mv post-humidity ~/bin/

これをcronで叩くようにすれば完成.今回は30分に1回投稿してもらう.crontab -eを使って以下の通り記載した.

*/30 * * * * bash -c '~/bin/post-humidity `~/bin/grovepi_dirt`'

まとめ

こうして我が家の観葉植物の安全は守られたのであった.

☆くれぐれも感電・漏電には気を付けましょう!

おまけ

f:id:Windymelt:20190312224018p:plain
植物監視のために3ワット使っています

PoEスイッチのWebインターフェイスに電力表示もついていておもしろい

参考文献

qiita.com

センサの値の目安はこのサイトを参考にしました.ありがとうございます.

*1:env系ツールの混沌とpipがうまく動かなかった思い出がある