編集履歴一覧に戻る
Makato-kanのアイコン画像

Makato-kan が 2021年05月31日22時10分52秒 に編集

コメント無し

本文の変更

## はじめに:  前回作成した [お礼 いただいたM5StickCを使って二酸化炭素濃度測定](https://elchika.com/article/77f5ef6a-063a-4ac3-bd5a-50bc7f2488c7/)に M5ボタンを押した時WiFi接続しMQTTパブリッシュ機能を 使ってデータ送信するようにしました。 ## MQTT:   詳しいことはMQTTWikiにお任せしてデータを送信する事。そのデータを受信する事を決めたものらしいです。   ラズベリーパイをMQTTブローカーにして無線LAN親機経由でデータを受信しています。   M5StickCはラズベリーパイのMQTTブローカーにデータを送信して役目が終了です。   データ受信はラズベリーパイでMQTTサブスクライバーを起動して受信の都度データをファイルに追記するように  しています。ちなみに受信時に時刻情報を追加しているのでM5StickCに時刻情報なくても大丈夫です

-

 作ったデータはカンマ区切りデータなので エクセルでグラフ化してもよいし グーグルチャートでグラフ化も  できました。

+

  作ったデータはカンマ区切りデータなので エクセルでグラフ化してもよいし  グーグルチャートでグラフ化もできました。

 恐れ入りますがMQTTのセットアップについては後日記載したいと思います。  因みにラズベリーパイを無線LAN親機にしてDHCPのサービスをすれば無線LAN親機なくても データ受信できましたがラズベリーパイのアンテナが貧弱なのか距離を伸ばす事できなかったのでデータ受信は 無線LAN親機にやらせています。 ## ハードウェア: M5StickCにSGP30とDHT11を接続しています。接続は前の記事をご参考ください。 ## プログラム: 通常setup()に含まれるWiFi接続してIPアドレス取得する所はloop()の中で実施しています。 これはWiFi親機のない場所で起動した場合IPアドレス取得エラーになってしまい先に 進まなくなるのでボタンを押したらIPアドレス取得してデータ送信するようにしています。 よってWiFi親機の範囲外でボタン押した時にはLED点灯したままになります。   またシリアル出力のなるべくデータ以外のものは送信しないようにしたので トラブル解決したい場合はコメントを外してシリアル出力したものをみると良いです。 ```arduino:M5StickC+SGP30+DHT11接続し、画面表示とシリアル出力とMQTT送信する #include <M5StickC.h> #include <WiFi.h> #include <PubSubClient.h> #include <Wire.h> #include "Adafruit_SGP30.h" #include "DHT.h" #define DHTPIN 26 #define DHTTYPE DHT11 // DHT 11 DHT dht(DHTPIN, DHTTYPE); #define DISP_BRIGHTNESS_MIN 9 uint8_t disp_brightness = DISP_BRIGHTNESS_MIN; Adafruit_SGP30 sgp; uint32_t getAbsoluteHumidity(float temperature, float humidity) { //approximation formula from Sensirion SGP30 Driver Integration chapter 3.15 const float absoluteHumidity = 216.7f * ((humidity / 100.0f) * 6.112f * exp((17.62f * temperature) / (243.12f + temperature)) / (273.15f + temperature)); // [g/m^3] const uint32_t absoluteHumidityScaled = static_cast<uint32_t>(1000.0f * absoluteHumidity); // [mg/m^3] return absoluteHumidityScaled; } #define inPin 37 // WiFi 設定 const char wifi_ssid[] = "WiFiSSID"; // yourssid→使うWiFiのSSIDに書き換える const char wifi_password[] = "WiFipassword"; // yourwifissid→使うWiFiのパスワードに書き換える //MQTT設定 const char mqtt_server[] = "192.168.10.xxx"; //MQTTのサーバーIPアドレス const int mqtt_port = 1883; const char mqttUserName[] = "name"; // name→設定した名前に書き換える const char mqttPass[] = "Password"; // pass→設定されたmqttパスに書き換える const char clientID[] = "ESP32Client"; #define dht11_topic "sensor/dht11-12" WiFiClient wifiClient; PubSubClient mqttClient(wifiClient); void setup() { pinMode(inPin, INPUT); pinMode(GPIO_NUM_10, OUTPUT); delay(10); digitalWrite(GPIO_NUM_10, HIGH); M5.Axp.ScreenBreath(disp_brightness); M5.begin(); M5.Lcd.setRotation(1); M5.Lcd.setTextFont(2); M5.Lcd.setTextColor(TFT_WHITE,TFT_BLACK); M5.Lcd.fillScreen(BLACK); while (!Serial) { delay(10); } // Wait for serial console to open! Serial.println("SGP30 test"); Wire.begin(32, 33);//I2C dht.begin(); if (! sgp.begin()){ Serial.println("Sensor not found :("); while (1); } Serial.print("Found SGP30 serial #"); Serial.print(sgp.serialnumber[0], HEX); Serial.print(sgp.serialnumber[1], HEX); Serial.println(sgp.serialnumber[2], HEX); M5.Lcd.fillScreen(WHITE); delay(500); M5.Lcd.fillScreen(BLACK); delay(500); } void setup_wifi() { delay(10); Serial.print("Connecting to "); Serial.println(wifi_ssid); WiFi.begin(wifi_ssid, wifi_password); delay(100); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.println("Connecting to WiFi.."); } Serial.println(WiFi.localIP()); } void mqtt_reConnect() { while (!mqttClient.connected()) { // Serial.println("Attempting MQTT connection...");トラブルあったらコメント外す // MQTT broker に接続する if (mqttClient.connect(clientID,mqttUserName,mqttPass)) { // Serial.print("Connected with Client ID: "); トラブルあったらコメント外す // Serial.print(clientID); // Serial.print(", Username: "); // Serial.print(mqttUserName); // Serial.print(" , Passwword: "); // Serial.println(mqttPass); } else { Serial.print("failed, rc= "); // http://pubsubclient.knolleary.net/api.html#state に state 一覧が書いてある Serial.print(mqttClient.state()); Serial.println(" try again in 5 seconds"); delay(5000); } } } int counter = 0; //シリアル送信用 int counter1 = 0; //ベースライン値送信用 int counter2 = 0; //画面表示用 void loop() { float h = dht.readHumidity(); // Read temperature as Celsius (false) float t = dht.readTemperature(); String datath = ""+String(t)+" "+String(h); sgp.setHumidity(getAbsoluteHumidity(t, h)); if (! sgp.IAQmeasure()) { Serial.println("Measurement failed"); return; } //シリアル送信は6秒に一回にした counter++; if (counter == 6) { counter = 0; Serial.print(datath); Serial.print(" ");Serial.print(sgp.TVOC); Serial.print(" "); Serial.println(sgp.eCO2); } if (! sgp.IAQmeasureRaw()) { Serial.println("Raw Measurement failed"); return; } delay(500); //トラブル解析用にベースラインの値をシリアル出力できるようにしてあるが使っていない counter1++; if (counter1 == 60) { counter1 = 0; uint16_t TVOC_base, eCO2_base; if (! sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) { Serial.println("Failed to get baseline readings"); return; } // Serial.print("****Baseline values: eCO2: 0x"); Serial.print(eCO2_base, HEX); トラブルあったらコメント外す // Serial.print(" & TVOC: 0x"); Serial.println(TVOC_base, HEX); } //M5ボタンを押したらWifi接続してMQTTデータ転送する // デジタルピン#37が'LOW'ボタンを押された時 //Serial.println(digitalRead(inPin)); if (digitalRead(inPin) == LOW) { digitalWrite(GPIO_NUM_10, LOW); setup_wifi(); mqttClient.setServer(mqtt_server, mqtt_port); delay(100); if (!mqttClient.connected()) { mqtt_reConnect(); } delay(10); if(!mqttClient.loop()) { delay(10); mqttClient.connect(clientID); } String datathTC = ""+String(t)+","+String(h)+","+String(sgp.TVOC)+","+String(sgp.eCO2); delay(100); mqttClient.publish(dht11_topic, datathTC.c_str(), false); digitalWrite(GPIO_NUM_10, HIGH); } //M5stick OLED に TVOC eCO2 温度 湿度を表示する 表示画面は少し暗くしている //データの更新は2秒に一回にするためカウンタを使った counter2++; if (counter2 == 2) { counter2 = 0; M5.Axp.ScreenBreath(disp_brightness); M5.Lcd.fillScreen(BLACK); String str = " " + (String)sgp.TVOC + " [ppb] "; M5.Lcd.drawRightString(str,250,0,2); M5.Lcd.setCursor(0, 0, 2); M5.Lcd.println(" TVOC"); str = " " + (String)sgp.eCO2 + " [ppm] "; M5.Lcd.drawRightString(str,250,16,2); M5.Lcd.setCursor(0, 16, 2); M5.Lcd.println(" eCO2"); M5.Lcd.setCursor(0, 32, 2); M5.Lcd.println(" Temp"); str = " " + (String)t + " [C] "; M5.Lcd.drawRightString(str,250,16+16,2); M5.Lcd.setCursor(0, 32+16, 2); M5.Lcd.println(" Humi"); str = " " + (String)h + " [%] "; M5.Lcd.drawRightString(str,250,16+16+16,2); } delay(500); } ``` ## 使い方:  起動すると画面に温度・湿度・eCO2・TVOCを表示します。 M5ボタンを押すとLEDが点灯してIPアドレス取得とデータ送信を行い、 成功すればLED消灯します。 ## シリアルコンソール出力: M5StickC initializing...OK SGP30 test Found SGP30 serial #01668588 26.30 57.00 0 400 26.30 55.00 1 405 Connecting to aterm-57f693-g Connecting to WiFi.. Connecting to WiFi.. Connecting to WiFi.. Connecting to WiFi.. Connecting to WiFi.. 192.168.10.114 ※途中でM5ボタンを押したのでWifi接続のメッセージが入っています。 ※ArduinoIDEのシリアルプロットを使えばグラフにしてくれます。 ## MQTTデータ受信 ラズベリーパイで設定が終えてMQTTサブスクライバーコマンドでデータを受信する場合のコマンド mosquitto_sub -h raspberrypi3B.local -u USERNAME -p PASSWORD -t sensor/dht11-12 -F '@Y,@m,@d,"@H:@M",%p' 以下が受信例です。  ※時刻に””がついているのはグーグルチャートでチャート化する時:のせいで エラーになったのでつけています。 2021,05,31,"06:53",22.80,58.00,4,412 2021,05,31,"20:14",24.80,56.00,23,400 2021,05,31,"20:34",24.90,57.00,255,542 2021,05,31,"21:41",26.30,54.00,0,407 ## 最後に:  GPSをつけてMQTT送信するデータに位置情報をつければ測定場所を地図にプロットできるかなあ  とは言っても使うのはビルの室内とかですから、GPS信号受信できるのか?。。。