Makato-kan が 2022年10月10日12時28分53秒 に編集
初版
タイトルの変更
M5Stick-CとM5STICK使い、ESP-NOWとMQTTで温湿度データをラズパイに送った
タグの変更
M5StickC
M5Stack
ESP-NOW
MQTT
ENC28J60
ethernet
DHT11
メイン画像の変更
記事種類の変更
製作品
本文の変更
## 初めに: インターネット環境がなくてもデータ受け取れないかと探していると、 ESP-NOWというインターネット環境を使わないデータ送受信できる仕組みが ある事わかったので、M5StickとM5StickCを使って試してみました。 ついでにM5StickにSPI接続のethernetをつけてイーサネット経由でMQTTを使って ラズベリーパイにデータ送信するようにしました。 ## 部品表: M5Stick(elchika様からの頂き物でした。) ENC28J60を使ったSPI接続のイーサネットアダプタ (Aliexpressで購入しました。) M5stickC(elchika様からの頂き物でした。) DHT11 (Aliexpressで購入しました。) 10kΩ抵抗 (DHT11のプルアップ用) ## 配線表: M5STICKにENC28J60のイーサネットアダプタをつけます。 ※他VCC3.3VとGND必要です。 |SPI名称 | M5側| イーサネット側 | |:---|:---:|:---| | SCK | 18 | SCK | | MISO | 19 | SO | | MOSI | 23 | SI | | CS | 26 | CS | M5StickCは VCC3.3V DHT11をデータ線G26で接続し10kΩの抵抗でプルアップしています。 ## ESP-NOW特徴: ESP32やESP8266で使えるIOTに便利な通信方式 双方向や一対多、多対一などいろいろな組み合わせ可能 詳細は以下のURLに詳しい記事ありました。 [Getting Started with ESP-NOW (ESP32 with Arduino IDE)](https://randomnerdtutorials.com/esp-now-esp32-arduino-ide/) [Getting Started with ESP-NOW (ESP8266 NodeMCU with Arduino IDE)](https://randomnerdtutorials.com/esp-now-esp8266-nodemcu-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 ![キャプションを入力できます](https://camo.elchika.com/1f26546214576a93b778b3fccfcf4edd9e800cc5/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f66373831653764372d303336352d343131662d613663362d3663623238333931346464342f63336361643365322d636234632d346563642d626132362d366433336261633631393535/) ``` #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 ![キャプションを入力できます](https://camo.elchika.com/744eda47a7e2721966b6ed79ac1d65dcd5b09d14/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f66373831653764372d303336352d343131662d613663362d3663623238333931346464342f33363632366237382d326666322d343431332d393234332d316462623834366366653030/) ``` #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(); dht.begin(); M5.Lcd.fillScreen(BLACK); M5.Lcd.setTextColor(GREEN); M5.Lcd.setTextSize(2); pinMode(DHTPIN, INPUT_PULLUP); // 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 ``` ## 謝辞: elchika様に投稿があった[ワイヤレス・wifi環境不要で部屋4点の環境情報表示器をつくる2](https://elchika.com/article/748b00ae-c320-406c-9bc6-8566090b882e/)に触発されてこのシステムを考えてみました。