ESP8266 과 TM1637 으로 인터넷 시계 만들기
원래는 다이소에서 판매하는 5000원짜리 시계 뜯어서 만드려고 했는데, 시계를 뜯어보니, 자체 MCU를 통해 제어를 하고 있어 TM1637 로 구현하고 나중에 케이스를 만드는게 나을 것 같아서 아래와 같이 구현(chatGPT)했다.
- 30분마다 NTP 가져오기
- WIFI가 끊기더라도 RTC 유지
- WIFI가 끊기면 1분에 한 번씩 재접속 시도
- 버튼을 3초 누르면, AP 설정 모드 (88:88 표시)
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <TM1637Display.h>
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
#define CLK D5 // TM1637 CLK
#define DIO D6 // TM1637 DIO
#define CONFIG_BUTTON_PIN D7 // 설정 진입 버튼
TM1637Display display(CLK, DIO);
// 시간 관련 변수
time_t currentEpochTime = 0;
unsigned long lastNtpMillis = 0;
unsigned long checkTermMillis = 1800000UL; // 30분마다 NTP 다시 받아옴 // Wi-Fi 재접속 관련
unsigned long lastWiFiReconnectAttempt = 0;
const unsigned long wifiReconnectInterval = 60000; // 1분
// 버튼 관련
unsigned long buttonPressedTime = 0;
bool buttonWasHeld = false;
const unsigned long CONFIG_HOLD_TIME = 3000; // 3초
bool isInConfigMode = false;
const char* ntpServer = "pool.ntp.org";
const int timeZone = 9; // 한국은 +09:00
WiFiUDP udp;
unsigned int localPort = 2390;
void setup() {
Serial.begin(115200);
display.setBrightness(0x0f);
display.showNumberDecEx(0, 0b11100000, true); // 00:00 표시
pinMode(CONFIG_BUTTON_PIN, INPUT);
WiFiManager wm;
if (!wm.autoConnect("ESPClockAP")) {
Serial.println("WiFi 연결 실패");
} else {
Serial.println("WiFi 연결됨: " + WiFi.SSID());
}
connectNTP();
}
void connectNTP() {
Serial.println("NTP 시간 동기화 시도");
udp.begin(localPort);
sendNTPpacket(ntpServer);
delay(1000);
if (udp.parsePacket()) {
byte packetBuffer[48];
udp.read(packetBuffer, 48);
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
unsigned long secsSince1900 = highWord << 16 | lowWord;
currentEpochTime = secsSince1900 - 2208988800UL + timeZone * 3600;
lastNtpMillis = millis();
Serial.println("NTP 동기화 완료: " + String(currentEpochTime));
} else {
Serial.println("NTP 응답 없음");
}
}
void sendNTPpacket(const char* address) {
byte packetBuffer[48] = { 0 };
packetBuffer[0] = 0b11100011;
packetBuffer[1] = 0;
packetBuffer[2] = 6;
packetBuffer[3] = 0xEC;
udp.beginPacket(address, 123);
udp.write(packetBuffer, 48);
udp.endPacket();
}
void enterConfigPortal() {
isInConfigMode = true;
display.clear();
display.showNumberDecEx(8888, 0b11100000, true); // 88:88 표시
WiFiManager wm;
wm.setConfigPortalTimeout(180); // 3분 제한
// 스마트폰으로 WifiClock/8888 로 접속해서 WiFi SID 설정
bool res = wm.startConfigPortal("WiFiClock", "8888");
if (res) {
Serial.println("WiFi 설정 완료!");
} else {
Serial.println("설정 시간 초과");
}
delay(1000);
ESP.restart();
}
void loop() {
static int prevMinute = -1;
static unsigned long lastNtpCheck = 0;
unsigned long nowMillis = millis();
if (isInConfigMode) return;
// 1. 버튼 3초 이상 누르면 설정 모드 진입
int buttonState = digitalRead(CONFIG_BUTTON_PIN);
if (buttonState == HIGH) {
if (buttonPressedTime == 0) {
buttonPressedTime = nowMillis;
} else if (!buttonWasHeld && nowMillis - buttonPressedTime >= CONFIG_HOLD_TIME) {
buttonWasHeld = true;
Serial.println("버튼 3초 이상 눌림 - 설정 모드 진입");
enterConfigPortal();
}
} else {
buttonPressedTime = 0;
buttonWasHeld = false;
}
// 2. WiFi 끊긴 경우 1분마다 재접속
if (WiFi.status() != WL_CONNECTED && nowMillis - lastWiFiReconnectAttempt >= wifiReconnectInterval) {
lastWiFiReconnectAttempt = nowMillis;
WiFi.reconnect();
Serial.println("WiFi 재접속 시도");
}
// 3. 30분마다 NTP 재동기화
if (nowMillis - lastNtpCheck >= checkTermMillis) {
lastNtpCheck = nowMillis;
connectNTP();
}
// 4. 소프트 RTC 기반으로 시간 표시
time_t now = currentEpochTime + (nowMillis - lastNtpMillis) / 1000;
int hours = (now % 86400L) / 3600;
int minutes = (now % 3600) / 60;
if (minutes != prevMinute) {
prevMinute = minutes;
int displayTime = hours * 100 + minutes;
display.showNumberDecEx(displayTime, 0b11100000, true); // ':' on
Serial.printf("Time: %02d:%02d\n", hours, minutes);
}
delay(100);
}
댓글
댓글 쓰기