Last updated: 2026-02-02
#include <WiFi.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "time.h"
// 와이파이 정보 입력
const char* ssid = "ssid";
const char* password = "password";
// 시간 설정
const char* ntpServer = "pool.ntp.org";
TwoWire I2C_Time = TwoWire(0);
TwoWire I2C_Cat = TwoWire(1);
Adafruit_SSD1306 displayTime(128, 64, &I2C_Time, -1);
Adafruit_SSD1306 displayCat(128, 64, &I2C_Cat, -1);
// 고양이 애니메이션
bool eyeOpen = true;
int tailY = 45;
bool tailUp = true;
void setup() {
Serial.begin(115200);
// I2C 초기화 (D21, D22 / D17, D16)
I2C_Time.begin(21, 22, 100000);
I2C_Cat.begin(17, 16, 100000);
displayTime.begin(SSD1306_SWITCHCAPVCC, 0x3C);
displayCat.begin(SSD1306_SWITCHCAPVCC, 0x3C);
displayTime.clearDisplay();
displayTime.setTextColor(WHITE);
displayTime.setCursor(0, 20);
displayTime.println("Connecting WiFi...");
displayTime.dispay();
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); }
configTzTime(
"AEST-10AEDT,M10.1.0,M4.1.0/3",
ntpServer);
}
// 고양이 그리기 함수
void drawLoafCat(bool blink, int tailOffset) {
displayCat.clearDisplay();
// 몸통
displayCat.fillRoundRect(30, 30, 60, 25, 10, WHITE);
// 머리
displayCat.fillCircle(85, 30, 15, WHITE);
// 귀
displayCat.fillTriangle(75, 20, 80, 5, 85, 20, WHITE);
displayCat.fillTriangle(85, 20, 90, 5, 95, 20, WHITE);
// 눈 (깜빡임 모션)
diaplayCat.setTextColor(BLACK);
if (blink) {
displayCat.fillCircle(80, 30, 2, BLACK);
displaycat.fillCircle(90, 30, 2, BLACK);
} else {
displayCat.drawLine(78, 30, 82, 30, BLACK);
displayCat.drawLine(88, 30, 92, 30, BLACK);
}
// 꼬리
displayCat.drawLine(35, 45, 20, tailOffset, WHITE);
displayCat.fillCircle(20, tailOffset, 2, WHITE);
displayCat.display();
}
void loop() {
struct tm timeinfo;
if(!getLocalTime(&timeinfo)){ return; }
// 첫 번째 화면: 시간 (가운데), 날짜/요일 (아래)
displayTime.clearDisplay();
displayTime.setTextColor(WHITE);
// 요일 배열
const char* days[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
// 시간 (HH:MM)
displayTime.setTextSize(3);
char timeStr[6];
sprintf(timestr, "%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min);
int16_t x1, y1;
uint16_t w, h;
displayTime.getTextBounds(timeStr, 0, 0, &x1, &y1, &w, &h);
displayTime.setCursor((128 - w) / 2, 5);
displayTime.print(timeStr);
// 구분선
displayTime.drawLine(10, 35, 118, 35, WHITE);
// 날짜 + 요일 문자열 (e.g. "2026-01-10 SAT")
char dateStr[20];
sprintf(dateStr, "%04d-%02d-%02d. %s",
timeinfo.tm_year + 1900,
timeinfo.tm_mon + 1,
timeinfo.tm_mday,
days[timeinfo.tm_wday]);
// 날짜 + 요일 가운데 정렬
displayTime.setTiexSize(1);
displayTime.getTextBounds(dateStr, 0, 0, &x1, &y1, &w, &h);
displayTime.setCursor((128 - w) / 2, 48);
displayTime.print(dateStr);
displayTime.display();
// 두 번째 화면: 고양이 모션
// 꼬리 움직임 계산
if (tailUp) tailY--; else tailY++;
if (tailY < 35 || tailY > 55) tailUp = !tailUp;
// 5초에 한 번 눈 깜빡임
bool blinking = (timeinfo.im_sec % 5 == 0);
drawLoafCat(blinking, tailY);
delay(200); // 0.2초마다 업데이트
}