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초마다 업데이트
}