Skip to content

Instantly share code, notes, and snippets.

@ksasao
Created November 25, 2025 00:09
Show Gist options
  • Select an option

  • Save ksasao/b60d1b2ded8d88e286cd82535c525361 to your computer and use it in GitHub Desktop.

Select an option

Save ksasao/b60d1b2ded8d88e286cd82535c525361 to your computer and use it in GitHub Desktop.
M5StickC Plus2でモバイルバッテリー/ポータブル電源の電源制御。タイマーでオンオフします。ロードスイッチXC8114AA01PR-G を利用し5V, 3A 程度がコントロールできます。https://x.com/ksasao/status/1991507033775042855
#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