植物の水やりをIoTする その３：Raspberry piを用いての給水タイミング制御

前回：[植物の水やりをIoTする その２：モーター制御とトランジスタ](https://qiita.com/mashino-satoshi/items/583c4f95b23fa6fc5fc0)

# 誰が水やりを制御するべきか
前回と前々回で、水やりをするべきタイミングと、実際に水やりをする手段を獲得した。
これらを組み合わせることによって、ようやく適切なタイミングでの給水をすることができるようになる。
単純にArduinoのなかにそのプログラムを組み込んでしまえば、5Vの電源に繋ぐだけでスタンドアロン稼働させることができる。
それはそれで有用ではあるだろうが、今回はそれを少し拡張させてみたい。

# 命令通りに従わせる
Arduino君には手足になってもらうこととします。
水分量が何%であるかを獲得できても、何%になったら給水を行うかの判断を同時にやらなければならないわけではない。
値の獲得とその値を元に何を判断するかは、全く別問題である。
なので、Arduinoには「センサー値を送れと言われたら送り、給水しろと言われたら給水をする」という仕事のみを担当してもらうことにする。
前回、シリアル通信を通してArduinoとPCで文字列のやりとりを行った。
シリアル通信での文字のやり取りは一文字ずつであり、しかも今時のjsonなどといった形式の解析機能などArduinoは持っていないため、受け取る値は固定長形式とする。

Arduinoへ送る文字列のうち1文字目を命令とし、給水の場合にその後何秒間給水するかの数値を送る。

```c:autoWatering.ino
int SENSOR_PIN = A0;    // select the input pin for the potentiometer
int MOTER_PIN = 2;      // select the pin for the LED

int CMD_SENSOERING = 0;
int CMD_WATERING = 1;

void setup() {
  pinMode(MOTER_PIN, OUTPUT);
  Serial.begin(115200);
}

void loop() {
  // シリアル値が来たら実行する
  int Vib = Serial.available();
  if (Vib > 0) {
    String VibON;

    // 固定長で一文字目は命令とする
    int command = Serial.read() - 48;

    // 残りの文字があればモーター稼働時間
    for (int i = 0; i < Vib - 1; i++) {
      VibON += String(Serial.read() - 48);
    }
    Serial.read(); // 最後は改行文字

    if (command == CMD_SENSOERING) {
      int value = analogRead(SENSOR_PIN);
      int per = 100 - (value - 200) / 3;
      Serial.println(per);
      Serial.flush();

    } else if (command == CMD_WATERING) {
      int v = VibON.toInt();
      if (0 < v) {
        digitalWrite(MOTER_PIN, HIGH);
        delay(v);
        digitalWrite(MOTER_PIN, LOW);
      }
    }
  }
}
```

これで、Arduinoはただ命令を受け取ってその通りに処理を実行するだけの機械と化した。
なおセンサー値は実行のたびに多少の上下幅があったため、10回の平均値とした。

# Raspberry piで制御する
以下のようにラズパイとArduinoを接続する。
![IMG_0069-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235422/ac8e9437-a464-507d-728f-39911ed3cd50.jpeg)
具体的にラズパイの環境をどう構築したかに関しては、今回は割愛する。
ラズパイとはつまりはとても小さなコンピューターなので、最近のやつだとWifiやBluetoothを内蔵していたりと普通に使う分にはパソコンとなんら変わることがないためだ。
植物は室内栽培に適した観葉植物のスパティフィラム。
すでに我が家に来てから二週間が経過したが、順調に葉の数を増やしている。
一度も外に出したことはないが、たった７WのLEDでも十分な光量を確保できることが判明した。

さて、ラズパイから以下のpythonのコードを実行する。
こちらは給水用のコード。
一回実行すると3秒間の給水を行う。

```python:temporaryWatering.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import serial
#ser = serial.Serial('/dev/cu.usbmodem141101', 115200) # Mac用
ser = serial.Serial('/dev/ttyACM0', 115200) # ラズパイ用
ser.write(b"13000")
ser.close()
```

こちらはセンサー値取得。
一回実行すると、センサー値を返す。
センサー値は実行のたびに多少の上下幅があったため、10回の平均値とした。

```python:receiveMoisture.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import serial
import time
#ser = serial.Serial('/dev/cu.usbmodem141101', 115200) # Mac用
ser = serial.Serial('/dev/ttyACM0', 115200) # ラズパイ用
sensor_value = 0
for i in range(10):
    ser.write(b"0")
    a = ser.readline()
    while ser.in_waiting:
        a = a + ser.readline()
    sensor_value += int(a.split(b'\r')[0])
    time.sleep(1)
sensor_value //= 10
print(sensor_value)
ser.close()
```

これで、ラズパイからの制御をする準備が整った。
これらを組み合わせて、以下の通り完成となる。

```python:autoWatering.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
import serial
import pymysql.cursors

# 通信は都度開閉する
#ser = serial.Serial('/dev/cu.usbmodem141101', 115200) # Mac用
ser = serial.Serial('/dev/ttyACM0', 115200) # ラズパイ用
ser.write(b"0")
a = ser.readline()
while ser.in_waiting:
    a = a + ser.readline()
sensor_value = int(a.split(b'\r')[0])
print(sensor_value)

if (sensor_value < 90):
    ser.write(b"13000")
ser.close()

try:
    conn = pymysql.connect(
        user='root',
        host='localhost',
        port=3306,
        db='auto_watering'
    )
    c = conn.cursor()
    sql = 'INSERT INTO moisture_list (moisture) VALUES (%s);'
    c.execute(sql, (sensor_value))
    c.execute('commit')
except Exception as e:
    print(e)
```
これを一時間に一回のcronで叩くことにした。
# appendix
これで、ようやく自動給水システムが完成したことになる。
このままでもいいが、どうせラズパイにまで制御を拡張させたので、次はいよいよIoTの「I」の部分への拡張を試みたい。