水位 シリアル通信かBLE

$ sudo hcitool lescan LE Scan ... EF:FC:25:C5:D2:4A (unknown) 38:34:DB:5D:05:6D (unknown) 38:63:4B:18:FE:64 (unknown) 84:0D:8E:06:65:8E (unknown) 84:0D:8E:06:65:8E Long name works now 03:4B:A5:0B:C5:9D (unknown) 4C:65:A8:D0:8E:1C (unknown) 栽培ガジェット

RETENTION POLICYラズパイとESP32とシリアル通信でラズパイから制御します。

ESP32はWifi通信すると使えなくなるPINが出てくるので・・ラズパイのUSBにESP32を接続してシリアル通信で直接水位データを取得していきます。

BLEで取得

RaspberryPi から ESP32 のデータを BLE で読み出す - Qiita
ゴール、目的我が家は断熱性能が結構高くて、油断して外に出るとめっちゃ寒かったなんてことがあり、家の中から外の気温を知る手段が欲しくなった。けど、それっぽい製品はそれなりのお値段なので、前に買って放…
$ sudo hcitool lescan LE Scan ... EF:FC:25:C5:D2:4A (unknown) 38:34:DB:5D:05:6D (unknown) 38:63:4B:18:FE:64 (unknown) 84:0D:8E:06:65:8E (unknown) 84:0D:8E:06:65:8E Long name works now 03:4B:A5:0B:C5:9D (unknown) 4C:65:A8:D0:8E:1C (unknown)

ESP32のBluetooth MACアドレスを調べる

$ sudo hcitool lescan
LE Scan ...
EF:FC:25:C5:D2:4A (unknown)
38:34:DB:5D:05:6D (unknown)
38:63:4B:18:FE:64 (unknown)
84:0D:8E:06:65:8E (unknown)
84:0D:8E:06:65:8E Long name works now
03:4B:A5:0B:C5:9D (unknown)
4C:65:A8:D0:8E:1C (unknown)

84:0D:8E:06:65:8EがESP32のMACアドレス。

接続してみる

$ gatttool -b 84:0D:8E:06:65:8E -I
[84:0D:8E:06:65:8E][LE]> connect
Attempting to connect to 84:0D:8E:06:65:8E
Connection successful
[84:0D:8E:06:65:8E][LE]>
(gatttool:32098): GLib-WARNING **: Invalid file descriptor.#これが出たら再度connectする。
[84:0D:8E:06:65:8E][LE]> characteristics
handle: 0x0002, char properties: 0x20, char value handle: 0x0003, uuid: 00002a05-0000-1000-8000-00805f9b34fb
handle: 0x0015, char properties: 0x02, char value handle: 0x0016, uuid: 00002a00-0000-1000-8000-00805f9b34fb
handle: 0x0017, char properties: 0x02, char value handle: 0x0018, uuid: 00002a01-0000-1000-8000-00805f9b34fb
handle: 0x0019, char properties: 0x02, char value handle: 0x001a, uuid: 00002aa6-0000-1000-8000-00805f9b34fb
handle: 0x0029, char properties: 0x3a, char value handle: 0x002a, uuid: beb5483e-36e1-4688-b7f5-ea07361b26a8


[84:0D:8E:06:65:8E][LE]> char-read-hnd 0x002a
Characteristic value/descriptor: 3c 11 00 00
$ sudo apt-get install bluez-hcidump

配線

  • + : 3.3V
  • – : GND
  • S : GPIO36

水位センサー 簡単なスケッチ

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

void loop() {
  int sensorValue;
  sensorValue = analogRead(36);
  Serial.print("sensor = ");
  Serial.println(sensorValue);
  delay(3000);
}

水位が変わってきたら1秒毎にInfluxDBに送る。

水位が変わらない場合は3分おき程度で送る。

だいたい1200弱くらいから水が入っているのを感知していて2300くらいで満タン近くになるのでアラートになったほうがよさそう

InfluxDBのデータを間引く

1秒おきに水位データをInfluxDBにアップしているので、そのうちラズパイのMicroSDカードが満タンになって動かなくなりそうなので、30分おきの水位データを保存してから1秒おきの水位データは一日で破棄してみる。

https://docs.influxdata.com/influxdb/v1/guides/downsample_and_retain/

なので過去の不要なデータを間引きする。

RETENTION POLICY(RP)を作成する

InfluxDBのデータをどのくらい保存しておくかのRETENTION POLICYを作成していきましょう。

デフォルトのRETENTION POLICYはautogenで保存期間が無制限になっているのでデータがディスク容量を消費していきますので一定期間ごとにデータを削除するためにRetention Policyを設定します。

ChronographでRETENTION POLICYを作成

Chronographをラズパイにインストールしている場合はWebページからRETENTION POLICYを作成しましょう。もしまだChronographをインストールしていない方はラズパイのシェルで以下のようにすればインストールできます。

$ sudo apt-get install chronograf

Chronographのアドレスは「http://localhost:8888/か、SSHで他のPCからアクセスする場合は「http://192.168.xx.xx:8888/」と、IPアドレスを指定してアクセスします。

左メニューの王冠アイコン > Databasesをクリックして、RETENTION POLICYを追加するデータベースの「+ Add Retention Policy」をクリックする。

InfluxDB Policy

以下のように設定してみました。

  • Retention Policy:1day(ポリシー名)
  • Duration:24h(有効期間、無制限はINF)
  • Replication Factor:1(クラスターの複製数)
InfluxDB Policy

influxコマンドでリテンションポリシーを作成

リテンションポリシー(RETENTION POLICY)は以下のようにinfluxコマンドからDBがに入っても作成できます。

$ influx
> CREATE RETENTION POLICY "2day" ON "sensor" DURATION 2d REPLICATION 1

上記の3箇所を変更してお好みのポリシーを作れます。

  • ポリシー名:2day
  • データベース:sensor
  • 有効期間:2d(2日間)

1日でデータを削除と、2日で削除するリテンションポリシーを作って以下のようになりました。

InfluxDB Policy

リテンションポリシーの適用

リテンションポリシーはデータを登録するときにしか設定できないようです。特に指定しない時はDefalutのAutogen(無制限)のRetention Policyを使用するのでデータは削除されることはありません。

上の作成したリテンションポリシーを使って1日や2日で削除したい場合は以下のようにデータを入れるときに設定するか、次にあげるContinuous Queryを使用してデータを間引くこともできます。

作成したリテンションポリシーはInfluxDBにデータをインサートするときに使う。以下のように「retentionPolicy=2day」を追加する。

$ influx
> use sensor
> INSERT table1,place=room,host=espd32,retentionPolicy=2day,type=12 temp=17.025213452336,humi=56.0211211356

こうすることで、インサートしたデータの有効期限が2日になって2日後に削除される。

Continuous Query 作成

続いてContinuous Queryを作成していきます。こちらは1秒置きの水位データを間引いて30分置きにして保存します。

CREATE CONTINUOUS QUERY "CONTINUOUSクエリー名" ON "デーベース" BEGIN
  SELECT * 
  INTO "リテンションポリシー名"."新しいMEASUREMENT名"
  FROM "既存のMEASUREMENT名"
  GROUP BY time(30m)
END
$influx
> use sensor
> CREATE CONTINUOUS QUERY "cq30m" ON "sensor" BEGIN SELECT mean("wlevel") AS "wlevel" INTO "autogen"."water_level_past"  FROM "water"  GROUP BY time(30m) END

11/17 サブのラズパイ3B+2で以下のようなエラーになる?

$ vim syslog

Nov 17 06:25:42 Raspi3B2 influxd[435]: ts=2019-11-16T21:25:42.254134Z lvl=info msg="Error executing query" log_id=0J8Ws~aW000 service=continuous_querier query="CREATE CONTINUOUS QUERY cq30m ON sensor BEGIN SELECT * INTO sensor.autogen.water_level_past FROM sensor.autogen.water GROUP BY time(30m) END" error="continuous queries must be aggregate queries"
Nov 17 06:25:42 Raspi3B2 python[342]: display_power=0
Nov 17 06:25:42 Raspi3B2 python[342]: display_power=0
Nov 17 06:25:42 Raspi3B2 python[342]: display_power=0
Nov 17 06:25:42 Raspi3B2 python[342]: display_power=0
Nov 17 06:25:42 Raspi3B2 python[342]: display_power=0
Nov 17 06:25:42 Raspi3B2 python[342]: display_power=0
Nov 17 06:25:42 Raspi3B2 python[342]: display_power=0
Nov 17 06:25:43 Raspi3B2 python[342]: display_power=0
Nov 17 06:25:43 Raspi3B2 python[342]: display_power=0
Nov 17 06:25:43 Raspi3B2 python[342]: display_power=0
Nov 17 06:25:43 Raspi3B2 influxd[435]: ts=2019-11-16T21:25:43.256145Z lvl=info msg="Error executing query" log_id=0J8Ws~aW000 service=continuous_querier query="CREATE CONTINUOUS QUERY cq30m ON sensor BEGIN SELECT * INTO sensor.autogen.water_level_past FROM sensor.autogen.water GROUP BY time(30m) END" error="continuous queries must be aggregate queries"

最終的な設定

sensor.waterに登録時に以下のようにretentionPolicyを指定してインサートする。

INSERT water,host=esp32-wlevel,retentionPolicy=1day,place=leaf-wl32 wlevel=1232

おなじMEASUREMENTに間引きしたデータをautogenリテンションポリシーで書き込んで古いデータを間引きした状態で使う。

1秒おきに保存するとInfluxDBが重くなってCPUを食い尽くすみたい。

なので、2時間でデータを削除するようにした。

INSERT water,host=esp32-wlevel,retentionPolicy=2hours,place=leaf-wl32 wlevel=1232

Grafanaで2秒間隔でリアルタイム表示

自動でポンプをオン・オフするようにしましたが、エラーが出ると水漏れしちゃうので、しばらくは手動で監視しておくためにGrafanaでリアルタイム表示させてみました。

本当は1秒間隔がよかったのですが、1秒おきに「N/A」表示になるので2秒間隔にしました。

Grafana
Grafana
Grafana
Grafana

Grafana6.2からはBar Guageが追加された

水位を表示させるにはピッタリなBar Guage↓が追加されたので早速アップグレードしてみた。この表示だと培養容器に水がどのくらいあるのかひと目で分かる。ただしアラートに機能が無い。

Bar Gauge

こちら↓にサンプル表示がありますので気になる方はチェックしてみてください。

Grafana

すでにGrafanaをインストールしてあっても以下の操作をすれば上書きされました。

$ wget https://dl.grafana.com/oss/release/grafana-rpi_6.2.5_armhf.deb
$ sudo dpkg -i grafana-rpi_6.2.5_armhf.deb
$ rm grafana-rpi_6.2.5_armhf.deb

アップグレードしたらブラウザをリロードして左下の「?」アイコンをマウスオーバーしたらGraganaのバージョンが確認できる。

https://play.grafana.org/d/vmie2cmWz/bar-gauge?orgId=1&refresh=10s

ESP32 水位計測してInfluxDBに送るスケッチ 6水槽分

/*  
 ラズパイにUSBで接続してWIFI通信する。
  int myPins[] = {2, 4, 12, 14, 15, 26, 27,13,25};//BT,Wifiを使うとこのPINは使えない
  23,22,1,3,21,19,18,5,17,16も使えない?Wifi+水位センサーでは無理っぽい。
  36,39,34,35,32,33
*/
#include <Wire.h>
#include <HTTPClient.h>

//Wi-Fi情報
#define WIFI_SSID "WIFIのSSISID"
#define WIFI_PASSWORD "WIFIのパスワード"

//InfluxDB
#define MEASUREMENT "water"
#define HOST "esp32-wlevel"
//rp=1hour 1時間でデータを削除するRetention Policyを作っておく
const char* influxUrl = "http://192.168.31.53:8086/write?db=sensor&rp=1hour";
const char* influxUser = "root";
const char* influxPassword = "gonet1600";

//水位を計測
//InfluxDB送信 ラズパイに接続
void postToInfluxDB() {
  int myPins[] = {36,39,34,35,32,33};//結局この6つのピンしか使えない!!
  int awlevel;
  Serial.println("+++++++++++++++++++++++++++++++++++");
  for(int i=0; i<6; i++){
     awlevel = analogRead(myPins[i]);
     Serial.print( myPins[i] );
     Serial.print("---");
     Serial.println(awlevel);

    String influxData = MEASUREMENT ",host=" HOST;
    influxData += ",place=leaf-wl";
    influxData += myPins[i];
    influxData += " wlevel=";
    influxData +=  awlevel;
    HTTPClient http;
    http.begin(influxUrl);
    http.addHeader("Content-Type", "application/x-www-form-urlencoded");
    http.setAuthorization(influxUser, influxPassword);
    int httpCode = http.POST(influxData);
    http.end();
    if (httpCode == HTTP_CODE_OK) {
      Serial.print( influxData + "-------NO \n");
    } else {
      Serial.print( influxData + "-------OK! \n");
    }
    delay(100);
  }
}

void setup() {
  Serial.begin(115200);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("connecting");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println();
  Serial.print("connected: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  postToInfluxDB();
  delay(1000);//1秒おきに送信
}

コメント