Makato-kanのアイコン画像
Makato-kan 2022年10月10日作成 (2022年11月19日更新)
製作品 製作品 閲覧数 5216
Makato-kan 2022年10月10日作成 (2022年11月19日更新) 製作品 製作品 閲覧数 5216

M5StickCとM5Stackを使い、ESP-NOWとMQTTで温湿度データをラズパイに送った

M5StickCとM5Stackを使い、ESP-NOWとMQTTで温湿度データをラズパイに送った

初めに:

インターネット環境がなくてもデータ受け取れないかと探していると、
ESP-NOWというインターネット環境を使わないデータ送受信できる仕組みが
ある事わかったので、M5StickとM5StickCを使って試してみました。

ついでにM5StickにSPI接続のethernetをつけてイーサネット経由でMQTTを使って
ラズベリーパイにデータ送信するようにしました。

部品表:

M5Stick(elchika様からの頂き物でした。)
ENC28J60を使ったSPI接続のイーサネットアダプタ (Aliexpressで購入しました。)

M5stickC(elchika様からの頂き物でした。)
DHT11 (Aliexpressで購入しました。)

配線表:

M5STICKにENC28J60のイーサネットアダプタをつけます。
※他VCC3.3VとGND必要です。

SPI名称 M5側 イーサネット側
SCK 18 SCK
MISO 19 SO
MOSI 23 SI
CS 26 CS

M5StickCは VCC3.3V DHT11をデータ線G26で接続します。
※プルアップ抵抗はプログラムでプルアップするようにしたので、不要です。

ESP-NOW特徴:

ESP32やESP8266で使えるIOTに便利な通信方式 
双方向や一対多、多対一などいろいろな組み合わせ可能
詳細は以下のURLに詳しい記事ありました。
Getting Started with ESP-NOW (ESP32 with Arduino IDE)
Getting Started with ESP-NOW (ESP8266 NodeMCU with Arduino IDE)
以下のプログラムで多対一の通信で複数のセンサーからでデータを受信しています。
大事な事は3つ
 ESP32とESP8266ではインクルードするライブラリ違う事
 親機と子機でデータの形を同じにする事
 親機のMACアドレスを調べる事です。

プログラム:

M5STACKのMACアドレスを調べる

// Complete Instructions to Get and Change ESP MAC Address: https://RandomNerdTutorials.com/get-change-esp32-esp8266-mac-address-arduino/ #include "WiFi.h" void setup(){ Serial.begin(115200); WiFi.mode(WIFI_MODE_STA); Serial.println(WiFi.macAddress()); } void loop(){ }

M5STICK
キャプションを入力できます

#include <EthernetENC.h> //"ライブラリを管理"でENC28J60を検索して"EthernetENC"をインストールします。 #include <M5Stack.h> #include <PubSubClient.h>//"ライブラリを管理"でPubSubClientを検索して"PubSubClient"をインストールします。 #include <esp_now.h> #include <WiFi.h> #define DISP_BRIGHTNESS_MIN 8 //LCD画面の輝度は8以下にするとほぼ見えない Max255 uint8_t disp_brightness = DISP_BRIGHTNESS_MIN; /*Ref https://randomnerdtutorials.com/esp-now-esp32-arduino-ide/ *Ref https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html *Ref https://espressif.github.io/esp-protocols/mdns/en/index.html *ESP32にENC28J60イーサネットアダプタをSPI接続で取り付け、ESP-NOWでWiFi経由データ受信 *MQTTでイーサネット経由データ送信するプログラム */ //ENC28J60 #define USE_THIS_SS_PIN 26 //SS = CS #define MODULE "ENC28J60" byte mac[] = { 0x**, 0xA** 0x**, 0x**, 0x**, 0x** }; //ENC28J60に割り当てるMACアドレスを書いてね //ENC28J60 //MQTT const char* mqttServer = "192.168.0.***"; // Broker address指定してね const int mqtt_port = 1883; const char* mqttUserName = **i"; // name→設定した名前に書き換える const char* mqttPass = "***"; // pass→設定されたmqttパスに書き換える const char* clientID= "M5Stack-ENC28J60"; #define dht11_topic "sensor/dht11-110" //MQTT //ESP-NOW esp_now_peer_info_t slave; typedef struct struct_message { char a[32]; // float b; //温度 float c; //湿度 } struct_message; struct_message myData; //ESP-NOW //MQTTのコールバック void callback(char* topic, byte* payload, unsigned int length) { } //イーサネット指定した EthernetClient ethClient; PubSubClient client(mqttServer, mqtt_port, callback, ethClient); // callback function that will be executed when data is received //ESP-NOWでデータ受信した時の動作 void OnDataRecv(const uint8_t *mac_addr, const uint8_t *incomingData, int data_len) { char macStr[18]; snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); memcpy(&myData, incomingData, sizeof(myData)); String data = ""+String(macStr)+","+String(myData.b)+","+String(myData.c); delay(10); Serial.println(data); delay(10); client.publish(dht11_topic, data.c_str(), false); //M5にも表示する M5.Lcd.fillScreen(BLACK); M5.Lcd.setCursor(10, 10); M5.Lcd.println(macStr); M5.Lcd.setCursor(10, 30); M5.Lcd.print("Temp: "); M5.Lcd.println(myData.b); M5.Lcd.setCursor(10, 50); M5.Lcd.print("Humi: "); M5.Lcd.printf("%.1f", myData.c); M5.Lcd.println(" % "); } void setup() { M5.begin(); M5.Lcd.setBrightness(disp_brightness); M5.Lcd.fillScreen(BLACK); M5.Lcd.setRotation(1); M5.Lcd.setTextSize(2); M5.Lcd.setCursor(10, 10); M5.Lcd.print("ESP-NOW Test\n"); WiFi.mode(WIFI_STA); WiFi.disconnect(); delay(10); //init ENC28J60 Ethernet.init(USE_THIS_SS_PIN); Ethernet.begin(mac); Serial.print(F("Connected! IP address: ")); Serial.println(Ethernet.localIP()); delay(10); client.setServer(mqttServer, mqtt_port); client.setCallback(callback); delay(10); //init ESP-NOW if (esp_now_init() != ESP_OK) { Serial.println("Error initializing ESP-NOW"); return; } // Once ESPNow is successfully Init, we will register for recv CB to // get recv packer info esp_now_register_recv_cb(OnDataRecv); } void reconnect() { while (!client.connected()) { Serial.println("Attempting MQTT connection..."); if (client.connect(clientID,mqttUserName,mqttPass)) { Serial.println("connected..."); } else { Serial.print("failed, rc= "); // http://pubsubclient.knolleary.net/api.html#state に state 一覧が書いてある Serial.print(client.state()); Serial.println(" try again in 5 seconds"); delay(5000); } } } void loop() { if (!client.connected()) { reconnect(); } if(!client.loop()) { client.connect(clientID,mqttUserName,mqttPass); } delay(5000); }

M5StickC
プルアップ抵抗は、プログラムでプルアップしたので不要です。

#include <M5StickC.h> #include <esp_now.h> #include <WiFi.h> #include "DHT.h" #define DHTPIN 26 #define DHTTYPE DHT11 DHT dht(DHTPIN, DHTTYPE); /*DHT11のデータをESP-NOWで、M5Stackに送信します。 * 送信間隔はカウンタで決めています。 *データの形は受送信一致するよう設定します。 * *受信機のMACアドレス */ uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //調べた親機のMACアドレス入れてね // Structure example to send data // Must match the receiver structure typedef struct struct_message { char a[32]; float b; //温度 float c; //湿度 } struct_message; // Create a struct_message called myData struct_message myData; esp_now_peer_info_t peerInfo; // callback when data is sent void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { Serial.print("\r\nLast Packet Send Status:\t"); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail"); } void setup() { M5.begin(); pinMode(DHTPIN, INPUT_PULLUP);//DHT11をプルアップします。 dht.begin(); M5.Lcd.fillScreen(BLACK); M5.Lcd.setTextColor(GREEN); M5.Lcd.setTextSize(2); // Set device as a Wi-Fi Station WiFi.mode(WIFI_STA); WiFi.disconnect(); // Init ESP-NOW if (esp_now_init() != ESP_OK) { Serial.println("Error initializing ESP-NOW"); return; } // Once ESPNow is successfully Init, we will register for Send CB to // get the status of Trasnmitted packet esp_now_register_send_cb(OnDataSent); // Register peer memcpy(peerInfo.peer_addr, broadcastAddress, 6); peerInfo.channel = 0; peerInfo.encrypt = false; // Add peer if (esp_now_add_peer(&peerInfo) != ESP_OK){ Serial.println("Failed to add peer"); return; } } int counter = 0; //ESP-NOW送信用 void loop() { M5.update(); float h = dht.readHumidity(); // Read temperature as Celsius (false) float t = dht.readTemperature(); // Check if any reads failed and exit early (to try again). if (isnan(h) || isnan(t)) { Serial.println("Failed to read from DHT sensor!"); return; } M5.Lcd.fillScreen(BLACK); M5.Lcd.setCursor(10, 15); M5.Lcd.printf("%.2f", dht.readTemperature()); M5.Lcd.setCursor(10, 45); M5.Lcd.printf("%.1f", dht.readHumidity()); counter++; if (counter == 36) { //3分に一回送信ESP-NOWで送信する counter = 0; // Set values to send strcpy(myData.a, "Temp and Humi"); myData.b = t; myData.c = h; // Send message via ESP-NOW esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData)); if (result == ESP_OK) { Serial.println("Sent with success"); } else { Serial.println("Error sending the data"); } } delay(3000); }

表示例:

MQTTサブスクライバーを設定すると、MACアドレスと温湿度データを受信します
-Fオプションで時刻を指定してデータ受信時刻も取得します
 コマンド例

mosquitto_sub -h raspi-master.local -u ユーザー名 -P パスワード -t sensor/dht11-110 -F @Y,@m,@d,"@H:@M",%p

2022-10-11追記
 ラズベリーパイにMQTTの設定する記事を書いておりました。
ラズベリーパイにMQTTブローカーの設定して pub/subを試してみる。
こちらも使っていただけると幸いです。

謝辞:

elchika様に投稿があったワイヤレス・wifi環境不要で部屋4点の環境情報表示器をつくる2に触発されてこのシステムを考えてみました。

1
Makato-kanのアイコン画像
屋外で温度湿度を測定し記録するので、壊れやすいと思い大量にDHT11とESP-WROOM-02を購入したのですが思いのほか壊れなかったので、何にでもDHT11をくっつけています。
ログインしてコメントを投稿する