メロンを自動栽培していたら、水を補充するタイミングがつかめないので水位監視装置をつくった件

[前回の記事（毎日の水やりが面倒なので、メロンを自動栽培した件）](https://qiita.com/spadr/items/a7f3a8d2c594cefc4cba)では、M5StickCとWatering Unit, Django REST frameworkを使って、自動水やり機を作りました。
装置おかげで、楽ちんにメロンを育てることができました。

ところがあまり横着しすぎるのも良くないようで、
特に栽培の後半になると、装置の水源であるバケツへ水補充を忘れてしまうことがよくありました。

そこで今回はM5StackのTOF Unitを使って水位監視装置をつくります。
そんなところで、今回も「やる夫と学ぶ〇〇」のスタイルで、なろう系気味に記事を書いていきます。
![mizuyari.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348993/5f3f8e71-6e7b-a46b-e84e-8587b14e80e7.jpeg)
![mizu.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348993/00712037-6068-cbc8-2439-b74d17fde2d4.jpeg)
![s-0013_06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348993/2d2716ab-af1b-bf41-4367-12bfe014a936.jpeg)

## 近所で噂になるやらない夫
```
　　　 ∧,,∧　 ∧,,∧
　∧ (´・ω・) (・ω・｀) ∧∧　　　　やる夫さん家のメロン見た？
(　´・ω)　Ｕ) ( つと ﾉ(ω・｀ )　　　お家でメロンなんて出来っこ無いと思ってたけど、
｜　Ｕ (　　´・) (・｀　　)　と ﾉ　　ちゃんと収穫できたっていうじゃない？！
　ｕ-ｕ （l 　　 ) (　　　ﾉu-ｕ
　　　　 'ｕ-ｕ'.　`ｕ-u' 


　　　 ∧,,∧　 ∧,,∧
　∧ (´・ω・) (・ω・｀) ∧∧　　　　見た見た！
(　´・ω)　Ｕ) ( つと ﾉ(ω・｀ )　　　おもちゃみたいな機械が動いてたから気になったのよ
｜　Ｕ (　　´・) (・｀　　)　と ﾉ　　やる夫さんに聞いたら、やらない夫さんが作った水やり機だって
　ｕ-ｕ （l 　　 ) (　　　ﾉu-ｕ　　　やらない夫さんエンジニアだったのよ
　　　　 'ｕ-ｕ'.　`ｕ-u' 


　　　 ∧,,∧　 ∧,,∧
　∧ (´・ω・) (・ω・｀) ∧∧　　　　
(　´・ω)　Ｕ) ( つと ﾉ(ω・｀ )　　　中学校でプログラミングが必修化するっていうじゃない？
｜　Ｕ (　　´・) (・｀　　)　と ﾉ　　あの機械、うちのチビたちにも丁度いいかもしれないわね
　ｕ-ｕ （l 　　 ) (　　　ﾉu-ｕ
　　　　 'ｕ-ｕ'.　`ｕ-u' 
```

## メロンを美味しく頂いたやる夫
```
　 　 　　　＿＿＿_　　
　 　　　／　　　　　＼ 　 
　　　／ 　 　 　 　　　＼　　　　メロンうまかったお
　 ／　　⌒ 　　　 ⌒　　 ＼ 　　　来年は増産して、ご近所さんにおすそ分けしてもいいお！！
　 | 　:::（__人__）:::  　|
　 ＼ 　　 　 　　　 　 　／ 

　 　 　　　＿＿＿_　　
　　　　／　　 　 　　＼ 　　　
　 　／　　─　 　 ─　　　＼ 　　　でも今年は、バケツに水を補給し忘れたり、
　／ 　　 （●） 　（●） 　　＼ 　　朝には水が半分残っていても昼過ぎには空になっていたり
　|　 　　　（__人__）　 　   |　　　なかなか、水を補給するタイミングがつかめなかったんだお
　 ＼　　  　｀ ⌒´ 　     ,／　　　　


　 　 　　　＿＿＿_　　
　 　　　／　　 　 　＼ 　　　　　　
　　　／　 _ノ 　ヽ､_　 ＼ 　　　　このまま増産したら、さらに渇水させてしまうお……
　 ／ oﾟ(（●）) (（●）)ﾟo ＼ 　　　夏場に枯らしてしまったらご近所さんの目が痛いお
　|　　　　 （__人__）　　  |　　 　
　 ＼　　 　 ｀ ⌒´ 　 　 ／　　

```

## 近所のやらない夫がやってきた
```
　　 ／￣￣＼
　／　　 _ノ　　＼
　|　　　 （ ●）（●）　　常識的に考えて……心配しすぎだろ
.　|　　　　 （__人__）　まあ一応、距離センサを使って水位監視すればいいだろ
　 |　　　　　｀ ⌒´ﾉ　　
.　 |　　　　　　 　 }
.　 ヽ　　　　　 　 }
　　 ヽ　　　　　ノ　　　　　　　　＼
　　　/　　　 く　　＼　　　　　　　 ＼
　　　|　　　　 ＼ 　 ＼ 　 　　　　　　＼
　 　 |　　　　|ヽ、二⌒)､　 　 　　　　　 ＼

やらない夫は二流SIに勤めるエンジニアであり、
やる夫とは職場も職種も違うが、昔からの友人であり、今でも時々夕食を共にする仲である。
腐れ縁とも言える。
```

```
　 　 　　　＿＿＿_
　 　　　／⌒　　⌒　 ＼
　　　／（ ●） 　（●）   ＼
　 ／:::::⌒（__人__）⌒::::＼ 　　やらない夫、いいところに来たお！
　 |　　　　　|r┬-|　　　　　|　　　その距離センサってやつを使えばいいのかお？
　 ＼ 　　 　 `ー'´ 　 　 ／　　　　いろいろ教えてほしいお！



　　 ／￣￣＼
　／　　 _ノ　　＼
　|　　　 （ ●）（●）
.　|　　　　 （__人__）　　チッ、しょうがないな幼馴染のよしみで教えてやるよ･･･
　 |　　　　　｀ ⌒´ﾉ　　　それと必要なもの揃えるから、3000円くれ。
.　 |　　　　　　 　 }
.　 ヽ　　　　　 　 }
　　 ヽ　　　　　ノ　　　　　　　　＼
　　　/　　　 く　　＼　　　　　　　 ＼
　　　|　　　　 ＼ 　 ＼ 　 　　　　　　＼
　 　 |　　　　|ヽ、二⌒)､　 　 　　　　　 ＼
```


## 数日後...

```
お荷物のお届けですにゃ
　　|＼＿／|
　　|―　―|
　　∧_∧_ノ_＿＿／/
　 (･ω･`)　　　　/
　 O旦⊂|　 ＿　　ヽ
　 ＯＯノ_／｣/_／＼｣
```
・M5StickC & TOF Unit
![s-IMG20211006191243.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348993/7568be0f-c252-7fd0-feb3-4ed886ab6071.jpeg)



```
　　 ／￣￣＼
　／　　 _ノ　　＼ 　　　　　無事届いたな
　|　　　 （ ●）（●） 　　　 これのほかにもモバイルバッテリが必要だが流石に持っているよな
.　|　　　　 （__人__）　　　
　 |　　　　　｀ ⌒´ﾉ　　　　 
.　 |　　　　　　 　 }. 　 　 　 
.　 ヽ　　　　　 　 } 　　　　　
　　 ヽ　　　　　ノ　　　　　　　　＼ 
　　　/　　　 く　　＼　　　　　　　 ＼
　　　|　　　　 ＼ 　 ＼ 　 　　　　　　＼
　 　 |　　　　|ヽ、二⌒)､　 　 　　　　　 ＼

　 　　　＿＿＿_　　　　　
　　　／　　 　 　＼　　　　　
　 ／　　─　 　 ─    ＼　　　　
／ 　　 （●） 　（●）   ＼　　　もってるお！
|　 　　 　 （__人__）　 |　　　それにしても、こんなので水位がちゃんとはかれるのかお！？
/　　　　 ∩ノ ⊃　　／ 　　　   
(　 ＼　／ ＿ノ　|　 |　　　　　
.＼　“　　／＿＿|　 | 　
　　＼ ／＿＿＿ ／



　　 ／￣￣＼
　／　　 _ノ　　＼ 　　　　　
　|　　　 （ ●）（●） 　　　　ああ、問題ない
.　|　　　　 （__人__）　　 　最大で2mまで測れるぞ
　 |　　　　　｀ ⌒´ﾉ　　　 　
.　 |　　　　　　 　 }. 　 　 　 
.　 ヽ　　　　　 　 } 　　　　　
　　 ヽ　　　　　ノ　　　　　　　　＼ 
　　　/　　　 く　　＼　　　　　　　 ＼
　　　|　　　　 ＼ 　 ＼ 　 　　　　　　＼
　 　 |　　　　|ヽ、二⌒)､　 　 　　　　　 ＼
　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　
```

## サンプルコードで動作確認
https://github.com/m5stack/M5Stack/blob/master/examples/Unit/ToF_VL53L0X/ToF_VL53L0X.ino

```

　　　　　　　　　　　　　　　　　　＿＿＿
　　　　　　　　　　　　　　　　／　　　　　＼
　　　　　　　　　　　　　　 ／　　 ＼ ,　, ／＼　　　
　　　　　　　　　　　　　／　 　 （●）　 （●） ＼　 　
　　　　　　　　　　　 　 |　　 u. 　 （__人__）　　　| 　　 　　._＿＿＿＿＿＿＿＿＿_
　　　　　　　　　　 　 　 ＼　 　 　 ` ⌒ ´　　,／ｶﾞﾁｬ　　| |　　　　　　　　　　　　　|
　　　　　　　　　　　　 　 /⌒ヽ　 　ー‐ 　　 ｨヽ　ｶﾞﾁｬ　.| |　　　　　　　　　　　　　|
　　　　　　　　　　　　 　 |　　|　　　　 　 　 　|　＼ ｶﾞﾁｬ.| |　　　　　　　　　　　　　|
　　　　　　　　　　ﾀﾝ.　　|　　|　　 　 　 i i| 　i＼,,c｀ヽ彡.| |　　　　　　　　　　　　　|
　　　　　　　　　.　　ﾀﾝ　|　⌒￣￣r～ﾉｿｨ" | 　inﾙｿノﾉ|_|_＿＿＿＿_＿＿＿＿_|
　　　　　　　　　　|＼￣￣　ー─‐─ｏｰ"o￣￣~´￣￣　　　　 ＿|_|＿_|＿

　 　　　＿＿＿_　　
　　　／　　 　 　＼
　 ／　　─　 　 ─　　＼　
／ 　　 （●） 　（●）　 ＼　一応動いたけど、これじゃ流行りのスマートな農業とは程遠いお
|　 　　 　 （__人__）　 |　　また今度やらない夫に聞いてみるお
/　　　　 ∩ノ ⊃　　　／
(　 ＼　／ ＿ノ　|　 |
.＼　“　　／＿＿|　 | 　
　　＼ ／＿＿＿ ／
```

## 再びやらない夫がやってきた
```
　 　　　／　　 　 　＼ 　　　　　　
　　　／　 _ノ 　ヽ､_　 ＼ 　　　　やらない夫、水位をクラウドから確認するのはいいんだお
　 ／ oﾟ(（●）) (（●）)ﾟo ＼ 　　　ただ、バケツを目視で確認し忘れてしまうぐらいだから
　 |　　　　 （__人__）　　|　　  　　わざわざブラウザ画面から水位を確認するわけないんだお
　 ＼　　 　 ｀ ⌒´ 　 　 ／　　　　　　



　　 ／￣￣＼
　／　　 _ノ　　＼
　|　　　 （ ●）（●）
.　|　　　　 （__人__）　常識的に考えて……そうだよな
　 |　　　　　｀ ⌒´ﾉ　　　じゃあ、水位の表示用にもう一台M5StickCを使って、
.　 |　　　　　　 　 }　　　それをリビングか玄関に置いとけばいいだろ
.　 ヽ　　　　　 　 }
　　 ヽ　　　　　ノ　　　　　　　　＼
　　　/　　　 く　　＼　　　　　　　 ＼
　　　|　　　　 ＼ 　 ＼ 　 　　　　　　＼
　 　 |　　　　|ヽ、二⌒)､　 　 　　　　　 ＼


　 　 　　　＿＿＿_
　 　　　／⌒　　⌒　 ＼
　　　／（ ●） 　（●）   ＼
　 ／:::::⌒（__人__）⌒::::＼ 　　やらない夫、それだお！
　 |　　　　　|r┬-|　　　　　|　　　出先でLINEに通知されても忘れるから、アナログな方法がいいお
　 ＼ 　　 　 `ー'´ 　 　 ／　　　　
```

## Canaspadサンプルコードをもとに自分で書いてみるやる夫
https://github.com/spadr/Canaspad_ESP32_Library/blob/ver2/examples/M5StickC/Canaspad_TOF/Canaspad_TOF.ino

```

　　　　　　　　　　　　　　　　　　＿＿＿
　　　　　　　　　　　　　　　　／　　　　　＼
　　　　　　　　　　　　　　 ／　　 ＼ ,　, ／＼　　　
　　　　　　　　　　　　　／　 　 （●）　 （●） ＼　 　
　　　　　　　　　　　 　 |　　 u. 　 （__人__）　　　| 　　 　　._＿＿＿＿＿＿＿＿＿_
　　　　　　　　　　 　 　 ＼　 　 　 ` ⌒ ´　　,／ｶﾞﾁｬ　　| |　　　　　　　　　　　　　|
　　　　　　　　　　　　 　 /⌒ヽ　 　ー‐ 　　 ｨヽ　ｶﾞﾁｬ　.| |　　　　　　　　　　　　　|
　　　　　　　　　　　　 　 |　　|　　　　 　 　 　|　＼ ｶﾞﾁｬ.| |　　　　　　　　　　　　　|
　　　　　　　　　　ﾀﾝ.　　|　　|　　 　 　 i i| 　i＼,,c｀ヽ彡.| |　　　　　　　　　　　　　|
　　　　　　　　　.　　ﾀﾝ　|　⌒￣￣r～ﾉｿｨ" | 　inﾙｿノﾉ|_|_＿＿＿＿_＿＿＿＿_|
　　　　　　　　　　|＼￣￣　ー─‐─ｏｰ"o￣￣~´￣￣　　　　 ＿|_|＿_|＿

　 　 　　　＿＿＿_
　 　　　／⌒　　⌒　 ＼
　　　／（ ●） 　（●）   ＼
　 ／:::::⌒（__人__）⌒::::＼ 　　コード書けるようになってきたお！
　 |　　　　　|r┬-|　　　　　|　　　IoT完全に理解したんだお！
　 ＼ 　　 　 `ー'´ 　 　 ／　　　　
```


![img808.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348993/043513f4-843c-80ca-07c2-f6f6b5eca868.jpeg)


## 距離センサ側コード
```cpp
#include <M5StickC.h>
#include <Canaspad.h>
#include "VL53L0X.h"

const char  ssid[]       = "WiFi_ssid";
const char  password[]   = "WiFi_pass";
const char* api_username = "user@mail.com";
const char* api_password = "password";

unsigned long interval = 60*30;//Seconds(s)

Canaspad api;
VL53L0X tof;

String sensor_distance;

float distance = 0.0;


void setup() {
  M5.begin();
  
  Serial.begin(115200);

  //Connecting to the API
  if(not api.begin(ssid, password, 9, api_username, api_password)){
    Serial.println("Failed to connect API!");
    Serial.println(api.httpCode);
    while(1){}
  }
  Serial.println("API connection succeeded.");
  
  //Getting a uuid
  sensor_distance   = api.set("TOF",  "distance", "number", 10, true);

  //Initializing the sensor
  tof.setAddress(0x29);
  tof.setTimeout(500);
  if (!tof.init()) {
    Serial.println("Failed to connect sensor!");
    while(1){}
  }
  tof.startContinuous();
}

void loop() {
  if (api.gettimestamp() % interval == 0){//interval
    Serial.println();
    Serial.println("---------------------------------------------");

    //Get the measured value
    distance = tof.readRangeContinuousMillimeters();
    
    Serial.printf("Distance: %2.2fmm\r\n", distance);

    //Add the measured values to JSON
    api.add(distance, sensor_distance);

    //Send JSON to API
    if (api.send()) { 
      Serial.print("Now : ");
      Serial.println(api.gettime());//current time
      }
    else {
      int err_num = api.httpCode;
      Serial.print("Error on HTTP request! HttpCode : ");
      Serial.println(err_num);
      }

    delay(10*1000);
  }
}
```

## リビングに設置した表示用コード
```cpp
#include <M5StickC.h>
#include "Canaspad.h"

#define TFT_GREY 0x5AEB

Canaspad api;

const char  ssid[]       = "WiFi_ssid";
const char  password[]   = "WiFi_pass";
const char* api_username = "user@mail.com";
const char* api_password = "password";

float max_distance    = 450.0;//Distance(mm)
float min_distance    = 30.0;  //Distance(mm)
float upper_threshold = 99.5; //Rest of water(%)
float lower_threshold = 40.0; //Rest of water(%)

String tft_title = "Rest of Water(%)";
unsigned long interval = 60*30;//Seconds(s)

String sensor_distance;
float res_distance, rest_of_water;


void setup() {
  M5.begin();
  M5.Lcd.setRotation(3);
  
  pinMode(GPIO_NUM_10, OUTPUT);
  digitalWrite(GPIO_NUM_10, HIGH);
  
  Serial.begin(115200);

  //Connecting to the API
  if(not api.begin(ssid, password, 9, api_username, api_password)){
    Serial.println("Failed to connect API!");
    Serial.println(api.httpCode);
    esp_restart();
  }
  Serial.println("API connection succeeded.");
  
  //Getting a uuid
  sensor_distance   = api.set("TOF",  "distance", "number", 10, true);
}

void loop() {
  if (api.gettimestamp() % interval == 0){//interval
    delay(10*1000);
    Serial.println();
    Serial.println("---------------------------------------------");
    
    //Getting values from API
    res_distance =  api.get(sensor_distance);

    Serial.printf("Distance: %2.2fmm(Received from the API)\r\n", res_distance);
    Serial.println("---------------------------------------------");

    //Calculating the water storage rate
    rest_of_water = 100 * (max_distance - res_distance) / (max_distance - min_distance);
    if (rest_of_water<= lower_threshold || upper_threshold <= rest_of_water){//Too much or too little water.
      digitalWrite(GPIO_NUM_10, LOW);
      TftShow(tft_title, rest_of_water);//Turn on
    }
    else{
      digitalWrite(GPIO_NUM_10, HIGH);
      TftOff ();//Turn off
    }
    delay(10*1000);
  }
  
  M5.update();
  if ( M5.BtnA.wasPressed() ) {
    TftShow(tft_title, rest_of_water);
  }
}

void TftShow (String title,float num) {
  M5.Axp.ScreenBreath(15);
  M5.Lcd.fillScreen(TFT_GREY);
  M5.Lcd.setCursor(0, 0, 2);
  M5.Lcd.setTextColor(TFT_WHITE,TFT_BLACK);  
  M5.Lcd.setTextSize(1);
  M5.Lcd.println(title);
  M5.Lcd.setTextColor(TFT_YELLOW); 
  M5.Lcd.setTextFont(6);
  M5.Lcd.println(String(num, 1));
  M5.Lcd.setTextColor(TFT_RED,TFT_BLACK);
  M5.Lcd.setTextFont(4);
  M5.Lcd.setTextColor(TFT_GREEN,TFT_BLACK);
  M5.Lcd.setTextFont(1);
  M5.Lcd.println(api.gettime());
}

void TftOff () {
  M5.Lcd.fillScreen(TFT_BLACK);
  M5.Axp.ScreenBreath(7);
}
```

## 実際に水位を監視してみるやる夫
![2021-10-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348993/85c5243e-c7eb-07d7-57d3-a5c512cc9837.png)

```
　 　 　　　＿＿＿_
　 　　　／⌒　　⌒　 ＼
　　　／（ ●） 　（●）   ＼
　 ／:::::⌒（__人__）⌒::::＼ 　　水が減っていく様子が記録されてるお
　 |　　　　　|r┬-|　　　　　|　　　これでちゃんと水の補充できるお！
　 ＼ 　　 　 `ー'´ 　 　 ／　　　　　

```