-
-
Save rin-ofumi/2441540d6d8fc6e85f02d3b286b538ce to your computer and use it in GitHub Desktop.
ATOMS3用 Wi-SUN HATモニター子機プログラム
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// M5Stack社のATOMS3をWi-SUN HAT用ESPNOW受信モニタ子機にするサンプルプログラム | |
// 2023.01.05 @rin_ofumi | |
// | |
// ESPNOWコードは「Lang-Ship」さんのESPNOWサンプルスケッチを参考にしています。 | |
// https://lang-ship.com/blog/work/m5stickc-esp-now-1/ | |
// | |
// ESPNOW受信データの処理は「がじぇっとろぐ」さんを参考にしてます。 | |
// https://b.okadajp.org/2020/05/08/pinku-ji-xiao7seguledshirudoni/ | |
// | |
// PlatformIO IDE用のテンプレートは「さいとてつや」さんのを使っています。 | |
// https://github.com/3110/m5stack-platformio-boilerplate-code | |
// | |
// 別途、下記のライブラリが必要となります。 | |
// M5Unified (テスト時のVerは0.1.1) | |
#include <M5Unified.h> | |
#include <WiFi.h> | |
#include <esp_now.h> | |
WiFiClient client; | |
esp_now_peer_info_t slave; | |
// ユーザー毎のカスタマイズ項目(ここから ↓) | |
// YOUR-SSID と YOUR-PASSWORD をご自身のWiFi環境に合わせて修正して下さい。 | |
const char* ssid = "YOUR-SSID"; // WiFiのSSID | |
const char* password = "YOUR-PASSWORD"; // WiFiのパスワード | |
const int npd_threshold = 2000; // 電力使い過ぎ警告(赤文字)の閾値(単位[W]) | |
unsigned long disp_timeout = 30000; // ESPNOW受信タイムアウトリミット(単位[ms])超えると非表示になります。 | |
// ユーザー毎のカスタマイズ項目(ここまで ↑) | |
// 以下、プログラム内で使用するグローバル変数 | |
const char* npd_unit = "W"; // 瞬時電力の単位文字列[w] | |
int d_size_x; // LCDサイズ | |
int d_size_y; // LCDサイズ | |
const float f_size_x = 0.5; // 値のフォントXサイズ倍率 | |
const float f_size_y = 0.7; // 値のフォントYサイズ倍率 | |
const float f_u_size_x = 0.5; // 単位のフォントXサイズ倍率 | |
const float f_u_size_y = 0.6; // 単位のフォントYサイズ倍率 | |
const float f_s_size_x = 0.3; // ステータスアイコンのフォントXサイズ倍率 | |
const float f_s_size_y = 0.4; // ステータスアイコンのフォントYサイズ倍率 | |
boolean disp_update = false; // true = 画面更新有り | |
boolean disp_off = false; // 受信タイムアウト非表示フラグ(false:表示、true:非表示) | |
int disp_r = 0; // 画面回転(0 to 3)"0"がUSBコネクタが下にある向き | |
class Recv_data { // ESPNOW受信データの格納用クラス定義 | |
public: | |
unsigned long recv_Time; // 受信時刻キャッシュ(単位[ms]) | |
String unit_Type; // 機器種別(NPDの英数3文字) | |
String val_Data; // 受信データ | |
}; | |
Recv_data r_d; // 受信データクラス宣言 | |
// 送信コールバック関数 | |
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("ESPNOW Sent to: "); | |
Serial.println(macStr); | |
Serial.print("ESPNOW Send Status: "); | |
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" | |
: "Delivery Fail"); | |
} | |
// 受信コールバック関数 | |
void OnDataRecv(const uint8_t* mac_addr, const uint8_t* data, int data_len) { | |
Serial.print(">>>Free Heap Size = "); | |
Serial.println(esp_get_free_heap_size()); | |
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("> ESPNOW Recv MAC Addr = %s\n", macStr); | |
Serial.printf("> ESPNOW Recv Data(%d byte)\n", data_len); | |
char* dataStr; | |
dataStr = (char*)malloc(data_len + 1); | |
memcpy(dataStr, data, data_len); | |
dataStr[data_len] = 0; | |
// 受信データ解析 | |
// UIFlowから受信した先頭10バイトの謎データは捨てる | |
String data_s = String(dataStr + 10); | |
Serial.printf("> Recv Data String = [%s]\n", data_s); | |
// 残りデータの先頭3バイトにWi-SUN HATからの瞬間電力値のヘッダー[NPD]が含まれてるか確認 | |
r_d.unit_Type = data_s.substring(0, 3); | |
if (r_d.unit_Type == "NPD") { | |
Serial.printf("-> r_d.unit_Type = %s\n", r_d.unit_Type); | |
r_d.val_Data = data_s.substring(4); | |
Serial.printf("-> r_d.val_Data = %s\n", r_d.val_Data); | |
// 「受信時刻(ms)」をキャッシュに格納し、LCD更新フラグをtrueに | |
r_d.recv_Time = millis(); // タイマーリセット | |
Serial.printf("-> ESPNOW recv time = %d(ms)\n", r_d.recv_Time); | |
disp_off = false; // ”LCD表示”に | |
disp_update = true; // ”画面更新有り”に | |
} | |
free(dataStr); | |
Serial.print(">>>Free Heap Size = "); | |
Serial.println(esp_get_free_heap_size()); | |
Serial.print("\n"); | |
} | |
// 画面描画関数 | |
void draw_lcd() { | |
uint16_t val_color = WHITE; // 値・単位のフォントカラー | |
uint16_t back_color = BLACK; // 画面背景色 | |
M5.Display.startWrite(); | |
// 画面回転 | |
M5.Display.setRotation(disp_r); | |
// 通信タイムアウト時の黒画処理 | |
if (disp_off) { // タイムアウト時は値が黒文字(非表示) | |
val_color = BLACK; | |
back_color = BLACK; | |
} | |
// ESPNOWで受信したデータ種別確認 | |
String val_buf = r_d.val_Data; | |
String unit_buf; | |
if (r_d.unit_Type == "NPD") { // NPD(Wi-SUN HATからの電力値受信)なら | |
unit_buf = npd_unit; | |
if (val_buf.toInt() >= npd_threshold) { // 電力使い過ぎ閾値超えの場合は | |
val_color = BLACK; | |
back_color = RED; | |
} else { | |
val_color = WHITE; | |
back_color = BLACK; | |
} | |
} | |
// 背景色描画 | |
M5.Display.fillScreen(back_color); | |
// 値の描画 | |
M5.Display.setTextColor(val_color, back_color); | |
M5.Display.setFont(&fonts::Font8); | |
M5.Display.setTextSize(f_size_x, f_size_y); | |
M5.Display.setTextDatum( | |
textdatum_t::middle_center); // 真ん中寄せ、中央原点 | |
M5.Display.drawString(val_buf, (int)(d_size_x / 2), (int)(d_size_y / 2)); | |
// 単位の描画 | |
M5.Display.setFont(&fonts::FreeSansBold24pt7b); | |
M5.Display.setTextSize(f_u_size_x, f_u_size_y); | |
M5.Display.setTextDatum(textdatum_t::bottom_right); // 右寄せ、下原点 | |
M5.Display.drawString(unit_buf, (int)(d_size_x - 8), (int)(d_size_y - 3)); | |
M5.Display.endWrite(); | |
disp_update = false; // 画面更新フラグをクリア | |
} | |
void setup() { | |
Serial.begin(115200); | |
auto cfg = M5.config(); | |
cfg.clear_display = true; // 起動時に画面クリア | |
M5.begin(cfg); | |
M5.Display.setTextSize(1.5); // 老眼にはキツいので文字サイズは1.5倍 | |
M5.Display.setBrightness(128); // LCD輝度を半分に | |
d_size_x = M5.Display.height(); | |
d_size_y = M5.Display.width(); | |
Serial.printf("height=%d width=%d\n", d_size_x, d_size_y); | |
M5.Display.fillScreen(BLACK); | |
M5.Display.setRotation(disp_r); | |
M5.Display.print("Wi-SUN HAT ESPNOW monitor\n"); | |
Serial.print("Wi-SUN HAT ESPNOW monitor\n"); | |
// 変数群初期化 | |
r_d.unit_Type = ""; | |
r_d.val_Data = ""; | |
WiFi.begin(ssid, password); // Wi-Fi に接続 | |
while (WiFi.status() != WL_CONNECTED) { // Wi-Fi 接続待ち | |
delay(500); | |
M5.Display.print("."); | |
} | |
M5.Display.print("WiFi connected\r\nIP address: "); | |
M5.Display.println(WiFi.localIP()); | |
// ESP-NOW初期化 | |
// WiFi.mode(WIFI_STA); //送信しないなら不要みたい | |
WiFi.disconnect(); | |
if (esp_now_init() == ESP_OK) { | |
Serial.println("ESPNow Init Success"); | |
M5.Display.println("ESPNow Init Success"); | |
} else { | |
Serial.println("ESPNow Init Failed"); | |
M5.Display.println("ESPNow Init Failed"); | |
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); //送信しないなら不要みたい | |
esp_now_register_recv_cb(OnDataRecv); | |
} | |
void loop() { | |
M5.update(); | |
// 一定時間指定モードのデータを受信してなければ値を非表示にする | |
if ((millis() - r_d.recv_Time) >= disp_timeout) { | |
if (disp_off == false) { | |
disp_off = true; | |
disp_update = true; | |
draw_lcd(); | |
Serial.print("ESPNOW timeout! disp_off!\n"); | |
} | |
} | |
// ボタンBを押したら画面回転 | |
if (M5.BtnA.wasPressed()) { | |
if (disp_r < 3) { | |
disp_r = disp_r + 1; | |
} else { | |
disp_r = 0; | |
} | |
disp_update = true; | |
draw_lcd(); | |
Serial.print("disp_rotate!\n"); | |
} | |
// 画面更新有りなら描画処理へ | |
if (disp_update == true) { | |
draw_lcd(); | |
} | |
delay(1); | |
} |
Author
rin-ofumi
commented
Jan 6, 2023
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment