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(){
}
#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);
}
#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に触発されてこのシステムを考えてみました。
投稿者の人気記事
-
Makato-kan
さんが
2022/10/10
に
編集
をしました。
(メッセージ: 初版)
-
Makato-kan
さんが
2022/10/11
に
編集
をしました。
-
Makato-kan
さんが
2022/10/18
に
編集
をしました。
(メッセージ: プログラムプルアップして抵抗を抜いた)
-
Makato-kan
さんが
2022/11/05
に
編集
をしました。
(メッセージ: コメント追加)
-
Makato-kan
さんが
2022/11/19
に
編集
をしました。
(メッセージ: 表題表記ミス修正)
ログインしてコメントを投稿する