Created
November 25, 2025 00:09
-
-
Save ksasao/b60d1b2ded8d88e286cd82535c525361 to your computer and use it in GitHub Desktop.
M5StickC Plus2でモバイルバッテリー/ポータブル電源の電源制御。タイマーでオンオフします。ロードスイッチXC8114AA01PR-G を利用し5V, 3A 程度がコントロールできます。https://x.com/ksasao/status/1991507033775042855
This file contains hidden or 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
| #include <M5Unified.h> | |
| #include <WiFi.h> | |
| #include <time.h> | |
| #include <sys/time.h> | |
| // ------------------------------------------------- | |
| // 設定エリア | |
| // ------------------------------------------------- | |
| const char* ssid = "YOUR-SSID"; // Wi-FiのSSID | |
| const char* password = "YOUR-PASSWORD"; // Wi-Fiのパスワード | |
| // ピン定義 | |
| const int pinG0 = 0; // メインの負荷 | |
| const int pinG26 = 26; // スリープさせないための負荷 | |
| // ------------------------------------------------- | |
| // 変数・オブジェクト定義 | |
| // ------------------------------------------------- | |
| M5Canvas canvas(&M5.Display); | |
| unsigned long lastScreenUpdate = 0; | |
| // 時刻をNTPサーバから取得 | |
| bool syncRtcFromNtp() | |
| { | |
| configTime(3600L * 9, 0, "ntp.nict.jp", "ntp.jst.mfeed.ad.jp"); | |
| // 起動ごとに時刻同期するために同期タイミングを一時的に変更 | |
| auto default_interval = sntp_get_sync_interval(); // ミリ秒単位 | |
| sntp_set_system_time(1, 0); // 1秒 | |
| // Set RTC | |
| struct tm timeInfo; | |
| if (getLocalTime(&timeInfo)) | |
| { | |
| M5.Rtc.setDateTime(timeInfo); | |
| } | |
| sntp_set_system_time(default_interval * 1000, 0); // 同期タイミングを戻す | |
| return true; | |
| } | |
| // WiFi 接続 | |
| bool connectWiFi() | |
| { | |
| Serial.println("[WiFi] Connecting..."); | |
| WiFi.mode(WIFI_STA); | |
| WiFi.begin(ssid, password); | |
| unsigned long start = millis(); | |
| const unsigned long timeoutMs = 5000; // 最大 5 秒待つ | |
| while (WiFi.status() != WL_CONNECTED && (millis() - start) < timeoutMs) { | |
| delay(500); | |
| Serial.print("."); | |
| } | |
| Serial.println(); | |
| if (WiFi.status() == WL_CONNECTED) { | |
| Serial.print("[WiFi] Connected. IP="); | |
| Serial.println(WiFi.localIP()); | |
| return true; | |
| } else { | |
| Serial.println("[WiFi] Connect FAILED."); | |
| return false; | |
| } | |
| } | |
| // WiFi を完全に OFF にする | |
| void turnOffWiFi() { | |
| Serial.println("[WiFi] Turning OFF..."); | |
| WiFi.disconnect(true, true); // AP情報も削除したい場合は第二引数 true | |
| WiFi.mode(WIFI_OFF); | |
| delay(100); | |
| } | |
| void drawScreen(bool isOn) { | |
| uint16_t bgColor = isOn ? TFT_GREEN : TFT_RED; | |
| uint16_t textColor = isOn ? TFT_BLACK : TFT_WHITE; | |
| canvas.fillScreen(bgColor); | |
| canvas.setTextColor(textColor); | |
| auto dt = M5.Rtc.getDateTime(); | |
| static const char* WEEKDAY_STR[] = { | |
| "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" | |
| }; | |
| int w = dt.date.weekDay; | |
| char dateStr[40]; | |
| snprintf(dateStr, sizeof(dateStr), | |
| "%04d-%02d-%02d (%s)", | |
| dt.date.year, | |
| dt.date.month, | |
| dt.date.date, | |
| (0 <= w && w < 7) ? WEEKDAY_STR[w] : "???"); | |
| char timeStr[10]; | |
| snprintf(timeStr, sizeof(timeStr), | |
| "%02d:%02d:%02d", | |
| dt.time.hours, | |
| dt.time.minutes, | |
| dt.time.seconds); | |
| canvas.setFont(&fonts::FreeSansBold9pt7b); | |
| canvas.drawString(dateStr, M5.Display.width() / 2, 30); | |
| canvas.setFont(&fonts::FreeSansBold18pt7b); | |
| canvas.drawString(timeStr, M5.Display.width() / 2, 70); | |
| canvas.setFont(&fonts::FreeSansBold24pt7b); | |
| if (isOn) { | |
| canvas.drawString("ON", M5.Display.width() / 2, 110); | |
| } else { | |
| canvas.drawString("OFF", M5.Display.width() / 2, 110); | |
| } | |
| canvas.pushSprite(0, 0); | |
| } | |
| void setup() { | |
| auto cfg = M5.config(); | |
| M5.begin(cfg); | |
| Serial.begin(115200); | |
| // ピン設定 | |
| pinMode(pinG0, OUTPUT); | |
| pinMode(pinG26, OUTPUT); | |
| // 画面設定 | |
| M5.Display.setRotation(3); | |
| canvas.createSprite(M5.Display.width(), M5.Display.height()); | |
| canvas.setTextDatum(middle_center); | |
| // ----------------------------------------------------------- | |
| // Wi-Fi接続 | |
| // ----------------------------------------------------------- | |
| M5.Display.fillScreen(TFT_BLACK); | |
| M5.Display.setTextColor(TFT_WHITE); | |
| M5.Display.setTextDatum(middle_center); | |
| M5.Display.setFont(&fonts::FreeSans9pt7b); | |
| M5.Display.drawString("Connecting WiFi...", M5.Display.width()/2, M5.Display.height()/2); | |
| bool wifiOk = connectWiFi(); | |
| if (wifiOk) { | |
| // WiFi がつながったときだけ NTP で同期して RTC 更新 | |
| M5.Display.fillScreen(TFT_GREEN); | |
| M5.Display.setTextColor(TFT_BLACK); | |
| M5.Display.drawString("NTP Synced!", M5.Display.width()/2, M5.Display.height()/2); | |
| syncRtcFromNtp(); | |
| } else { | |
| // WiFi がつながらない場合は、RTC に入っている時刻をそのまま使う | |
| M5.Display.fillScreen(TFT_ORANGE); | |
| M5.Display.setTextColor(TFT_BLACK); | |
| M5.Display.drawString("NTP Error", M5.Display.width()/2, M5.Display.height()/2); | |
| Serial.println("[TIME] Using RTC time as-is."); | |
| } | |
| // WiFi の成否にかかわらず、最後に必ず WiFi を OFF | |
| turnOffWiFi(); | |
| } | |
| void loop() { | |
| M5.update(); | |
| unsigned long currentMillis = millis(); | |
| // --- G0 メイン電源 --- | |
| bool g0_isOn = false; | |
| struct tm timeInfo; | |
| if (getLocalTime(&timeInfo)) { | |
| // 平日 8:00~19:00のみON | |
| bool isWeekday = (timeInfo.tm_wday >= 1 && timeInfo.tm_wday <= 5); // 日曜日:0 ~ 土曜日:6 | |
| bool isWorkingHour = (timeInfo.tm_hour >= 8 && timeInfo.tm_hour < 19); | |
| if (isWeekday && isWorkingHour) { | |
| g0_isOn = true; | |
| } | |
| } | |
| digitalWrite(pinG0, g0_isOn ? HIGH : LOW); | |
| // --- G26 スリープさせないための電力消費 --- | |
| // ポータブル電源 FLOUREONは周期的に電流が流れている | |
| // ことを監視する。そのタイミングで電流が流れている | |
| // 必要がある。 | |
| // メイン電源に負荷がぶら下がっていない場合には | |
| // 消費電力が減ってしまいバッテリー電源がスリープに | |
| // なるため今回は常にオン。 | |
| digitalWrite(pinG26, HIGH); | |
| // --- 画面更新 --- | |
| if (currentMillis - lastScreenUpdate >= 1000) { | |
| lastScreenUpdate = currentMillis; | |
| drawScreen(g0_isOn); | |
| } | |
| delay(100); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment