mametarou963
2021年09月20日作成 (2021年12月07日更新)
製作品 3885
ワイヤレス・wifi環境不要で部屋4点の環境情報表示器をつくる2
背景
以前、elchikaで「ワイヤレス・wifi環境不要で部屋4点の環境情報表示器をつくる」を投稿しました。
その際に表示器であるモニターユニットと環境情報を取得するセンサーユニットの通信はUDPのブロードキャストにて実装していました。
しかし、各ユニットのデバイスはESP32を採用していることと、ESP32間の無線ローカル通信はESP-NOWで実装すれば、簡単かつ省電力であるということを教えていただき、再実装したくなったので、別記事にてまとめようと考えました。
部品/構成/機能/動作する様子
「ワイヤレス・wifi環境不要で部屋4点の環境情報表示器をつくる」と同様です。
前回のプロダクトの問題点と改善内容
- 前回の「ワイヤレス・wifi環境不要で部屋4点の環境情報表示器をつくる」では、親機であるモニターユニットが電源OFF→ONすると、子機であるセンサーユニットを再起動しないと値が取得でいないようになっていました。(※子機起動時にwifi接続を実施するため)ESP-NOWではそれがないため、任意のタイミングで親機が再起動しても表示が継続されるようになりました。
- (おそらく)若干省電力されて?います
- ESP-NOWについてはLang-ship様のM5StickCでESP-NOW その1を参考にさせていただきました。
プログラム
モニターユニット
#include "M5Stack.h"
#include <esp_now.h>
#include "WiFi.h"
esp_now_peer_info_t slave;
//device
#define DEVICE_NUMBER_MIN 1
#define DEVICE_NUMBER_MAX 4
struct deviceInfo
{
double tmp;
double humi;
double pressure;
int tvoc;
int eco2;
};
struct deviceInfo devInfo[DEVICE_NUMBER_MAX] = {0};
// esp-now 受信コールバック
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, 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]);
Serial.printf("Last Packet Recv from: %s\n", macStr);
int deviceNumber = data[0];
double tempValue = (double)data[1] + ((double)data[2] * 0.01);
double humiValue = (double)data[3] + ((double)data[4] * 0.01);
double pressureValue = ((double)data[5] * 100) + (double)data[6] + ((double)data[7] * 0.01);
int tvocValue = (data[8] * 100) + data[9];
int eco2Value = (data[10] * 100) + data[11];
Serial.printf("DvNo:%d ",deviceNumber);
Serial.printf("Temp:%2.2lfC ", tempValue);
Serial.printf("Humi:%2.2lf%% ", humiValue);
Serial.printf("pressure:%4.2lfPa ", pressureValue);
Serial.printf("TVOC:%4dppb ", tvocValue);
Serial.printf("eCO2:%4dppm\n", eco2Value);
// 画面表示用/データ送信用のデータ更新
if((deviceNumber >= DEVICE_NUMBER_MIN) && (deviceNumber <= DEVICE_NUMBER_MAX)){
devInfo[deviceNumber-1].tmp = tempValue;
devInfo[deviceNumber-1].humi = humiValue;
devInfo[deviceNumber-1].pressure = pressureValue;
devInfo[deviceNumber-1].tvoc = tvocValue;
devInfo[deviceNumber-1].eco2 = eco2Value;
}
}
void setup()
{
// serial
Serial.begin(115200);
// M5Stack
M5.begin();
M5.Lcd.setTextSize(2);
// ESP-NOW初期化
WiFi.mode(WIFI_STA);
WiFi.disconnect();
if (esp_now_init() == ESP_OK) {
Serial.println("ESPNow Init Success");
M5.Lcd.print("ESPNow Init Success\n");
} else {
Serial.println("ESPNow Init Failed");
M5.Lcd.print("ESPNow Init Failed\n");
ESP.restart();
}
// マルチキャスト用Slave登録
memset(&slave, 0, sizeof(slave));
for (int i = 0; i < 6; ++i) {
slave.peer_addr[i] = (uint8_t)0xff;
}
esp_err_t addStatus = esp_now_add_peer(&slave);
if (addStatus == ESP_OK) {
// Pair success
Serial.println("Pair success");
}
// ESP-NOWコールバック登録
esp_now_register_recv_cb(OnDataRecv);
}
void loop()
{
M5.update();
M5.Lcd.setCursor(0, 0);
{
int i = 0;
for(i = 0;i < DEVICE_NUMBER_MAX;i=i+2)
{
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.printf("DvNo| %d | %d\n",i+1,i+2);
M5.Lcd.printf("----+---------+-----------\n");
M5.Lcd.printf("Temp| %02.2fC | %02.2fC\n",devInfo[i].tmp,devInfo[i+1].tmp);
M5.Lcd.printf("Humi| %02.2f%% | %02.2f%%\n",devInfo[i].humi,devInfo[i+1].humi);
M5.Lcd.printf("TVOC| %4dppb| %4dppb\n", devInfo[i].tvoc,devInfo[i+1].tvoc);
M5.Lcd.printf("eCO2| %4dppm| %4dppb\n", devInfo[i].eco2,devInfo[i+1].eco2);
M5.Lcd.printf("\n");
}
}
delay(5000);
}
センサーユニット
#include "EEPROM.h"
#include <esp_now.h>
#include "WiFi.h"
#include "M5StickC.h"
#include "Adafruit_BMP280.h"
#include "Adafruit_SHT31.h"
#include "Adafruit_SGP30.h"
esp_now_peer_info_t slave;
// EEPROM
#define EEPROM_SIZE 64
#define DEVICE_NUMBER_ADDRESS 1
// device
int deviceNumber = 1;
#define DEVICE_NUMBER_MIN 1
#define DEVICE_NUMBER_MAX 4
// ENV 2
Adafruit_SHT31 sht3x = Adafruit_SHT31(&Wire);
Adafruit_BMP280 bme = Adafruit_BMP280(&Wire);
// SGP30
Adafruit_SGP30 sgp;
void readDeviceNumber()
{
deviceNumber = EEPROM.readInt(DEVICE_NUMBER_ADDRESS);
if((deviceNumber < DEVICE_NUMBER_MIN) || (deviceNumber > DEVICE_NUMBER_MAX))
{
deviceNumber = DEVICE_NUMBER_MIN;
}
}
void countUpDeviceNumber()
{
deviceNumber = deviceNumber + 1;
if(deviceNumber > DEVICE_NUMBER_MAX)
{
deviceNumber = DEVICE_NUMBER_MIN;
}
EEPROM.writeInt(DEVICE_NUMBER_ADDRESS, deviceNumber);
EEPROM.commit();
}
// esp-now 送信コールバック
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
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]);
Serial.print("Last Packet Sent to: ");
Serial.println(macStr);
Serial.print("Last Packet Send Status: ");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
void setup()
{
// シリアルの初期設定
Serial.begin(115200);
// EEPROMの初期化
if (!EEPROM.begin(EEPROM_SIZE))
{
Serial.println("Failed to initialise EEPROM");
Serial.println("Restarting...");
delay(1000);
ESP.restart();
}
// m5stickcの初期設定
M5.begin();
M5.Lcd.setRotation(3);
M5.Lcd.setTextSize(2);
Wire.begin(32, 33);
// deviceNumberの読み出し
readDeviceNumber();
// ENV2 の初期設定
while (!bme.begin(0x76)) {
Serial.println("Could not find a valid BMP280 sensor, check wiring!");
M5.Lcd.println("Could not find a valid BMP280 sensor.");
}
while (!sht3x.begin(0x44)) {
Serial.println("Could not find a valid SHT3X sensor, check wiring!");
M5.Lcd.println("Could not find a valid SHT3X sensor.");
}
// SGP30の初期設定
while(! sgp.begin()){
Serial.println("Could not find a valid SGP30 sensor, check wiring!");
M5.Lcd.println("Could not find a valid SGP30 sensor.");
}
// ESP-NOW初期化
WiFi.mode(WIFI_STA);
WiFi.disconnect();
if (esp_now_init() == ESP_OK) {
Serial.println("ESPNow Init Success");
M5.Lcd.print("ESPNow Init Success\n");
} else {
Serial.println("ESPNow Init Failed");
M5.Lcd.print("ESPNow Init Failed\n");
ESP.restart();
}
// マルチキャスト用Slave登録
memset(&slave, 0, sizeof(slave));
for (int i = 0; i < 6; ++i) {
slave.peer_addr[i] = (uint8_t)0xff;
}
esp_err_t addStatus = esp_now_add_peer(&slave);
if (addStatus == ESP_OK) {
// Pair success
Serial.println("Pair success");
}
// ESP-NOWコールバック登録
esp_now_register_send_cb(OnDataSent);
M5.Lcd.fillScreen(BLACK);
}
void loop()
{
M5.update();
// 各値の取得
float tmp = sht3x.readTemperature();
float hum = sht3x.readHumidity();
float pressure = ( bme.readPressure() / 100);
sgp.IAQmeasure();
// 表示の更新
Serial.printf("Temperatura: %2.2f*C Humedad: %0.2f%% Pressure: %0.2fhPa Tvoc:%dppb eCo2:%dppm \r\n", tmp, hum, pressure,sgp.TVOC,sgp.eCO2);
M5.Lcd.setCursor(0, 0);
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.printf("DvNo:%d\n",deviceNumber);
M5.Lcd.printf("Temp:%2.2fC\n", tmp);
M5.Lcd.printf("Humi:%2.2f%%\n", hum);
M5.Lcd.printf("TVOC:%4dppb\n", sgp.TVOC);
M5.Lcd.printf("eCO2:%4dppm\n", sgp.eCO2);
uint8_t tmpUpper = (uint8_t)tmp;
uint8_t tmpLower = (uint8_t)((tmp - (float)tmpUpper) * 100);
uint8_t humUpper = (uint8_t)hum;
uint8_t humLower = (uint8_t)((hum - (float)humUpper) * 100);
uint8_t pressureUpper1 = (uint8_t)(((int)pressure) / 100);
uint8_t pressureUpper2 = (uint8_t)(((int)pressure) % 100);
uint8_t pressureLower = (uint8_t)((pressure - (int)pressure) * 100);
uint8_t tvocUpper = (uint8_t)(sgp.TVOC / 100);
uint8_t tvocLower = (uint8_t)(sgp.TVOC % 100);
uint8_t eco2Upper = (uint8_t)(sgp.eCO2 / 100);
uint8_t eco2Lower = (uint8_t)(sgp.eCO2 % 100);
uint8_t data[12] = {
deviceNumber,
tmpUpper,
tmpLower,
humUpper,
humLower,
pressureUpper1,
pressureUpper2,
pressureLower,
tvocUpper,
tvocLower,
eco2Upper,
eco2Lower,
};
esp_err_t result = esp_now_send(slave.peer_addr, data, sizeof(data));
// ボタンを押された場合はDeviceNumberを変更
if(M5.BtnB.wasPressed()){
Serial.println("ButtonB pressed");
countUpDeviceNumber();
}
delay(1000);
}
3
投稿者の人気記事
-
mametarou963
さんが
2021/09/20
に
編集
をしました。
(メッセージ: 初版)
-
mametarou963
さんが
2021/09/20
に
編集
をしました。
(メッセージ: トップ絵差し替えました)
-
mametarou963
さんが
2021/12/07
に
編集
をしました。
ログインしてコメントを投稿する