M5StickCで二酸化炭素と温度・湿度の測定値をMQTT送信します。
はじめに:
前回作成した お礼 いただいたM5StickCを使って二酸化炭素濃度測定にM5ボタンを押した時WiFi接続しMQTTパブリッシュ機能を使ってデータ送信するようにしました。
2022-10-27編集:
ラズベリーパイにMQTTの設定をして、データを受信する記事を作成しましたので、
併せて見ていただけると良いです。
ラズベリーパイにMQTTブローカーの設定して pub/subを試してみる
2022-4-5編集:
MQTTブローカーのホスト名解決できるようにプログラム修正しました。
ちょっと変かもしれません。わかる方いらっしゃればご指摘いただけると助かります。
2021-7-9編集:
このプログラムでは常時WiFiを使用していないのです。
WiFi.mode(WIFI_OFF);というものがありWiFiの消費電流を少なくする効果あるそうなので
それを起動時とWiFi通信実施後に組み込んでみました。
また、バッテリーの電圧値を取得できたのでそれも組み込んでみました
さらにCPU速度を通常の半分に設定変更しました。
他に、状態表示の出力はコメントしてありますので、エラー解析必要になったらコメント外して使います。
MQTT:
詳しいことはMQTTWikiにお任せして,MQTTとはデータを送信する事。そのデータを受信する事を決めたものらしいです。
そこで,ラズベリーパイをMQTTブローカーにして無線LAN親機経由でデータを受信しています。
M5StickCはラズベリーパイのMQTTブローカーにデータを送信して役目が終了です。
データ受信はラズベリーパイでMQTTサブスクライバーを起動して受信の都度データをファイルに追記するようにしています。
ちなみに受信時に時刻情報を追加しているのでM5StickCに時刻情報なくても大丈夫です。
作ったデータはカンマ区切りデータなので エクセルでグラフ化してもよいしグーグルチャートでグラフ化もできました。
恐れ入りますがMQTTのセットアップについては後日記載したいと思います。
試しにラズベリーパイを無線LAN親機にしてDHCPのサービスをすれば無線LAN親機なくてもデータ受信できましたがラズベリーパイのアンテナが貧弱なのか距離を伸ばす事できなかったのでデータ受信は無線LAN親機経由でやらせています。
ハードウェア:
M5StickCにSGP30とDHT11を接続しています。接続は前の記事 お礼 いただいたM5StickCを使って二酸化炭素濃度測定をご参考ください。
プログラム:
起動すると画面に測定値を表示します。
WIFI親機無い場所でも表示だけは出来るようボタンを押すとWiFi接続して、MQTTで測定値を送信します。
M5StickC+SGP30+DHT11接続し、画面表示とシリアル出力とMQTT送信する
#include <M5StickC.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <ESPmDNS.h>//Add2022-4-5
#include <Wire.h>
#include "Adafruit_SGP30.h"
#include "DHT.h"
#define DHTPIN 26
#define DHTTYPE DHT11 // DHT11
double vbat = 0.0;
DHT dht(DHTPIN, DHTTYPE);
#define DISP_BRIGHTNESS_MIN 9 //LCD画面の輝度は8以下にするとほぼ見えない
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 //M5ボタンでMQTT送信する
//#define GPIO10 MQTT送信時LEDを点灯する
// WiFi 設定
const char wifi_ssid[] = "yourssid"; // yourssid→使うWiFiのSSIDに書き換える
const char wifi_password[] = "yourwifissid"; // yourwifissid→使うWiFiのパスワードに書き換える
//MQTT設定
const char mqtt_server_host[] ="raspi-master"; //Add2022-4-5
IPAddress mqtt_server; //Add2022-4-5
const int mqtt_port = 1883;
const char mqttUserName[] = "name"; // name→設定した名前に書き換える
const char mqttPass[] = "pass"; // pass→設定されたmqttパスに書き換える
const char clientID[] = "M5StickC-1";
#define dht11_topic "sensor/dht11-12"
WiFiClient espClient;
PubSubClient mqttClient(espClient);
void setup() {
WiFi.disconnect();
delay(1);
WiFi.mode(WIFI_OFF);
// WiFi.forceSleepBegin();
delay(1);
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(3);
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 SGP30
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);
//CPU速度の設定 80以下にするとDHT11センサーデータ取得失敗するかもnanになるかも
setCpuFrequencyMhz(160);
}
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);
//mdns_init();
// Serial.println("Connecting to WiFi..");
}
// Serial.println(WiFi.localIP());
mdns_init(); //Add2022-4-5
mqtt_server = MDNS.queryHost(mqtt_server_host); //Add2022-4-5
delay(10); //Add 2022-4-5
}
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 vbat = M5.Axp.GetVbatData() * 1.1 / 1000;
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;
}
//シリアル送信は10秒に一回にした
counter++;
if (counter == 30) {
counter = 0;
Serial.print(datath);
Serial.print(" ");Serial.print(sgp.TVOC);
Serial.print(" "); Serial.print(sgp.eCO2);
Serial.print(" "); Serial.println(vbat);
}
if (! sgp.IAQmeasureRaw()) {
Serial.println("Raw Measurement failed");
return;
}
delay(50);
//トラブル解析用にベースラインの値をシリアル出力できるようにしてあるが使っていない
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(20);
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)+","+String(vbat);
delay(10);
mqttClient.publish(dht11_topic, datathTC.c_str(), false);
delay(10);
digitalWrite(GPIO_NUM_10, HIGH);
WiFi.disconnect();
delay(1);
WiFi.mode(WIFI_OFF);
delay(1);
}
//M5stick OLED に TVOC eCO2 温度 湿度を表示する 表示画面は少し暗くしている
//データの更新は2.5秒位に一回にするためカウンタを使った
counter2++;
if (counter2 == 8) {
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);
M5.Lcd.setCursor(0, 32+16+16, 2);
M5.Lcd.println(" Volt");
str = " " + (String)vbat + " [V] ";
M5.Lcd.drawRightString(str,250,16+16+16+16,2);
}
delay(300);
}
使い方:
起動すると画面に温度・湿度・eCO2・TVOCを表示します。
M5ボタンを押すとLEDが点灯してIPアドレス取得とデータ送信を行い、成功すればLED消灯します。
シリアルコンソール出力例:
M5StickC initializing...OK
SGP30 test
Found SGP30 serial #01668xxx
25.80 76.00 7 400 4.16
25.90 76.00 11 400 4.16
26.00 76.00 6 400 4.16
25.80 75.00 5 400 4.16
26.00 76.00 2 400 4.16
※ArduinoIDEのシリアルプロットを使えばグラフにしてくれます。
※Gnuplotを使ってもグラフになります。
※エクセルでもグラフにできます。
MQTTデータ受信コマンドと受信例:
ラズベリーパイは設定が終えて,MQTTサブスクライバーコマンドでデータを受信する場合のコマンド例
mosquitto_sub -h 192.168.10.yyy -u USERNAME -p PASSWORD -t sensor/dht11-12 -F '@Y,@m,@d,"@H:@M",%p'
以下が受信例です。
※時刻に””がついているのはグーグルチャートでグラフ化する時:のせいでエラーになったのでつけています。
2021,07,09,"07:03",24.20,83.00,50,500,3.83
2021,07,09,"19:30",24.10,79.00,222,593,3.88
2021,07,09,"22:59",25.50,77.00,22,426,4.16
2021,07,09,"23:01",25.30,77.00,9,412,4.16
ラズベリーパイにMQTTをインストールする:
ラズベリーパイのコマンドラインで以下のコマンドを実行して インストールします。
ログイン名パスワード設定 などが必要ですがすっかり忘れているので思い出したら編集します。
sudo apt install mosquitto
sudo apt install mosquitto-clients
最後に:
DHT11はVCCとデータ線の間に10kΩ抵抗を入れて,VCCは3.3Vを使っています データ線は26番のピンに接続しております。
投稿者の人気記事
-
Makato-kan
さんが
2021/05/31
に
編集
をしました。
(メッセージ: 初版)
-
Makato-kan
さんが
2021/05/31
に
編集
をしました。
-
Makato-kan
さんが
2021/05/31
に
編集
をしました。
-
Makato-kan
さんが
2021/06/02
に
編集
をしました。
-
Makato-kan
さんが
2021/06/02
に
編集
をしました。
-
Makato-kan
さんが
2021/06/03
に
編集
をしました。
-
Makato-kan
さんが
2021/06/03
に
編集
をしました。
-
Makato-kan
さんが
2021/06/13
に
編集
をしました。
-
Makato-kan
さんが
2021/06/23
に
編集
をしました。
-
Makato-kan
さんが
2021/07/09
に
編集
をしました。
-
Makato-kan
さんが
2021/07/09
に
編集
をしました。
(メッセージ: プログラムのバージョンアップ)
-
Makato-kan
さんが
2021/07/09
に
編集
をしました。
-
Makato-kan
さんが
2021/07/23
に
編集
をしました。
-
Makato-kan
さんが
2021/07/24
に
編集
をしました。
-
Makato-kan
さんが
2021/12/07
に
編集
をしました。
-
Makato-kan
さんが
2022/04/03
に
編集
をしました。
(メッセージ: 文章の手直し)
-
Makato-kan
さんが
2022/04/05
に
編集
をしました。
(メッセージ: プログラム修正した)
-
Makato-kan
さんが
2022/04/05
に
編集
をしました。
(メッセージ: プログラム修正)
-
Makato-kan
さんが
2022/04/05
に
編集
をしました。
(メッセージ: プログラム修正)
-
Makato-kan
さんが
2022/04/05
に
編集
をしました。
(メッセージ: 表題変更)
-
Makato-kan
さんが
2022/10/27
に
編集
をしました。
(メッセージ: リンクの情報を入れました。)
ログインしてコメントを投稿する