-3-はえらく短くなってしまったが、他にネタを思いついたので続く。

時計で1日に一回しか同期しないので、無線関係は完全に切って、消費電力を下げておくと良さそう。
Bluetoothは使っていないので完全にオフにするとして、WiFiは設定のときと、1日一回の時刻同期の時だけ動作させるようにしておきたい。とりあえず、Arduinoからの制御はある程度できそうだ。
WiFiの停止はこんな感じ。
#include <WiFi.h>
void setup() {
// もしつながっていたら切断
WiFi.disconnect(true); // true で保存済みの設定も消す
// モードを NULL (OFF) に
WiFi.mode(WIFI_OFF); // または WiFi.mode(WIFI_MODE_NULL);
}
Bluetoothの停止はこんな感じ。
#include <WiFi.h>
extern "C" {
#include "esp_bt.h"
}
void setup() {
esp_bluedroid_disable();
esp_bt_controller_disable();
}
以下の方針でAIにスケッチを書きなおしてもらう。
- 共通関数 wifiOff() を用意(必ず WiFi を切って WIFI_OFF)
- NTP 用の一時接続関数 wifiReconnectForNtp() を用意
- autoConnect() / startConfigPortal() 失敗時も必ず wifiOff() 呼び出し
- 15:48 の再同期でも成功 / 失敗に関係なく最後に WiFi を OFF
まぁ、いきなりうまくはできないよね... 動かない。
初回、WiFiセット直後に時刻同期をするときにうまく動作せずsync表示で停止している。
修正させる。 が、明後日の提案をしてきたので、軌道を修正する。 WiFiのオン・オフを独立の関数化して、初回やリセット後にはこの関数でオンにして、時刻同期後にオフにするように指示する。また、日次の時刻同期は別の関数にして、その中でオン・時刻同期・オフを行うように指示する。
こんな方針を出してきた。
- wifiOn() / wifiOff() を用意
- 初回/リセット後は wifiOn() → WiFiManager → synctime() → wifiOff()
- 日次同期は dailySyncIfNeeded() という別関数内でwifiOn() → WiFi.begin() → synctime() → wifiOff()
#include <WiFi.h>
#define WM_STRINGS_FILE "wm_strings_ja.h"
#include <WiFiManager.h> // tzapu WiFiManager
#include <TM1637Display.h>
#include "time.h"
/* ESP32-DevKitC
const int button = 4;
const int CLK = 32;
const int DIO = 33; */
// NodeMCU-32S
const int button = 27;
const int CLK = 25;
const int DIO = 26;
TM1637Display display(CLK, DIO);
WiFiManager wm;
// NTP
const char* ntpServer = "ntp.jst.mfeed.ad.jp";
const long gmtOffset_sec = 9 * 3600L;
const int daylightOffset_sec = 0;
// 7セグ用メッセージパターン
const uint8_t SEG_PUSH[] = {
SEG_A | SEG_B | SEG_F | SEG_E | SEG_G, // P
SEG_B | SEG_C | SEG_D | SEG_E | SEG_F, // U
SEG_A | SEG_C | SEG_D | SEG_F | SEG_G, // S
SEG_B | SEG_C | SEG_F | SEG_E | SEG_G, // H
};
const uint8_t SEG_CONN[] = {
SEG_D | SEG_E | SEG_G, // c
SEG_C | SEG_D | SEG_E | SEG_G, // o
SEG_C | SEG_E | SEG_G, // n
SEG_C | SEG_E | SEG_G, // n
};
const uint8_t SEG_BAR[] = {
SEG_G, SEG_G, SEG_G, SEG_G // ----
};
const uint8_t SEG_SYNC[] = {
SEG_A | SEG_C | SEG_D | SEG_F | SEG_G, // S
SEG_B | SEG_C | SEG_D | SEG_F | SEG_G, // y
SEG_C | SEG_E | SEG_G, // n
SEG_D | SEG_E | SEG_G, // c
};
const uint8_t SEG_ERR[] = {
SEG_D, // _
SEG_A | SEG_D | SEG_E | SEG_F | SEG_G, // E
SEG_E | SEG_G, // r
SEG_E | SEG_G, // r
};
// 長押ししきい値(ループ内 delay(10) と合わせて約2秒)
const int BUTTON_LONGPRESS_COUNT = 200;
int btnCounter = BUTTON_LONGPRESS_COUNT;
// ===== WiFi ON/OFF 共通関数 =====
void wifiOn() {
Serial.println("[wifiOn] WiFi.mode(WIFI_STA)");
WiFi.mode(WIFI_STA);
}
void wifiOff() {
Serial.println("[wifiOff] WiFi.disconnect + WIFI_OFF");
WiFi.disconnect(true); // 保存済み設定は保持したまま切断
WiFi.mode(WIFI_OFF);
}
// NTP 同期(WiFi 接続済み前提・ON/OFFは触らない)
void synctime() {
Serial.println("[synctime] start");
display.setSegments(SEG_SYNC);
Serial.print("[synctime] using NTP server: ");
Serial.println(ntpServer);
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
delay(1000);
struct tm timeinfo;
if (getLocalTime(&timeinfo)) {
Serial.printf("[synctime] synced: %04d-%02d-%02d %02d:%02d:%02d\n",
timeinfo.tm_year + 1900,
timeinfo.tm_mon + 1,
timeinfo.tm_mday,
timeinfo.tm_hour,
timeinfo.tm_min,
timeinfo.tm_sec);
} else {
Serial.println("[synctime] getLocalTime FAILED");
display.setSegments(SEG_ERR);
}
}
// 時刻表示(コロン点滅)
// → 日次の再同期判定はここから分離して別関数にする
void printTime() {
static bool flashPhase = false; // 2回に1回フラッシュするためのフラグ
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("[printTime] getLocalTime FAILED");
display.setSegments(SEG_ERR);
return;
}
char hourmin[5];
sprintf(hourmin, "%02d%02d", timeinfo.tm_hour, timeinfo.tm_min);
int hm = atoi(hourmin);
// コロン位置を変えて点滅っぽく
flashPhase = !flashPhase;
if (flashPhase) {
display.showNumberDecEx(hm, (0x80 >> 0), true);
delay(100);
display.showNumberDecEx(hm, (0x80 >> 1), true);
} else {
display.showNumberDecEx(hm, (0x80 >> 0), true);
delay(100);
}
}
// 日次の時刻同期(15:48:00)
// この中で WiFi オン・接続・同期・オフを完結させる
void dailySyncIfNeeded() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("[dailySyncIfNeeded] getLocalTime FAILED");
return;
}
char hourminsec[7];
sprintf(hourminsec, "%02d%02d%02d",
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
if (atoi(hourminsec) == 154800) {
Serial.println("[dailySyncIfNeeded] 15:48:00 reached, resync NTP");
display.setSegments(SEG_SYNC);
// WiFi オン(STA モード)
wifiOn();
// 保存済みの設定で接続
WiFi.begin(); // WiFiManager が保存した設定を利用
int retry = 0;
while (WiFi.status() != WL_CONNECTED && retry < 60) {
delay(500);
retry++;
Serial.printf("[dailySyncIfNeeded] reconnecting WiFi... retry=%d status=%d\n",
retry, WiFi.status());
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("[dailySyncIfNeeded] WiFi reconnected, call synctime()");
synctime();
} else {
Serial.println("[dailySyncIfNeeded] WiFi reconnect FAILED");
display.setSegments(SEG_ERR);
}
// 同期の成否にかかわらずここでオフ
wifiOff();
}
}
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println();
Serial.println("==== ESP32 Clock with WiFiManager / TM1637 ====");
Serial.print("WM_LANGUAGE = ");
Serial.println(FPSTR(WM_LANGUAGE));
pinMode(button, INPUT_PULLUP);
display.clear();
display.setBrightness(0);
display.showNumberDec(0, true);
// WiFiManager のデバッグ出力もシリアルに出す(デフォルト true だが明示)
wm.setDebugOutput(true);
// ポータル待ち中の表示
display.setSegments(SEG_BAR);
Serial.println("[setup] WiFiManager autoConnect(\"ClockConfig\")");
// 初回:WiFi ON → WiFiManager → NTP 同期 → OFF
wifiOn();
bool res = wm.autoConnect("ClockConfig");
delay(100);
if (!res) {
Serial.println("[setup] WiFiManager autoConnect FAILED");
display.setSegments(SEG_ERR);
wifiOff(); // 失敗時も OFF に戻す
return;
}
Serial.println("[setup] WiFiManager autoConnect OK");
Serial.print("[setup] Connected SSID: ");
Serial.println(WiFi.SSID());
Serial.print("[setup] IP address: ");
Serial.println(WiFi.localIP());
// WiFi 接続成功
display.setSegments(SEG_CONN);
delay(1000);
// WiFi はすでに繋がっているので、そのまま時刻同期だけ
synctime();
// 同期後は WiFi を OFF
wifiOff();
}
void loop() {
int flag = digitalRead(button);
if (flag == HIGH) {
// ボタンが押されていないとき → 普通の時計表示
btnCounter = BUTTON_LONGPRESS_COUNT; // カウンタをリセット
delay(400);
printTime();
dailySyncIfNeeded(); // 日次同期チェック
} else {
// ボタン押下中:カウントダウン表示
if (btnCounter > 0) {
btnCounter--;
display.showNumberDec(btnCounter, true);
delay(10);
// カウントダウン完了 → 長押しと判定して WiFi 設定リセット&ポータル
if (btnCounter == 0) {
Serial.println("[loop] long press detected, reset WiFi settings");
// WiFi情報リセット
wm.resetSettings();
// 長押し中表示
display.setSegments(SEG_PUSH);
delay(1000);
display.setSegments(SEG_BAR);
// リセット後も:WiFi ON → ConfigPortal → NTP → OFF
wifiOn();
Serial.println("[loop] WiFiManager startConfigPortal(\"ClockConfig\")");
bool res = wm.startConfigPortal("ClockConfig");
if (res) {
Serial.println("[loop] WiFiManager startConfigPortal OK");
Serial.print("[loop] Connected SSID: ");
Serial.println(WiFi.SSID());
Serial.print("[loop] IP address: ");
Serial.println(WiFi.localIP());
display.setSegments(SEG_CONN);
synctime();
} else {
Serial.println("[loop] WiFiManager startConfigPortal FAILED");
display.setSegments(SEG_ERR);
}
// 終了後は必ず OFF
wifiOff();
// 終了後は次にボタンを離したときにリセットされる
}
}
}
}
そういえば、この実装になってから、「conn」表示が一瞬で見えていないな... わりとconn好きなんだけど。手動で1秒待ち入れた。
これで問題なさそうだけど、電力消費はどうかな?
前に、簡単に測るやつ買っておいたような。100均で買ったmicroBの変換もあったな。

測ってみたけど、あまりかかってない感じねw こんな安いシンプルなのじゃ計れないレベルの500mA以下だw もっと細かく測れる機材もあったのだけど、埋もれて出てこないw


これで終わりかな。
前の実装で、もう連続何年かわからないくらい動いている時計が2台あるのだけど、今年になって、たまにLEDの輝度ムラが出てきたり、なんか時刻同期に失敗したり、明らかにハングして停止していることが何回かあった。さすがにいろいろ経年劣化するのだろうな。そのうち、そっちもファームを焼いたり、7セグの交換とかしてみるかな。
パーツは同時期のものなのだけど、今回焼いたものは、LEDもくっきりとしているのでいい感じだ。
オリジナル投稿: NTP時刻同期時計再び -4-|kinneko|pixivFANBOX
https://www.fanbox.cc/@kinneko/posts/10930601



