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

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をくっつけています。
ログインしてコメントを投稿する