14주차_참고 : 코드 설명 - dhryu60/SmartDevice_2025-1 GitHub Wiki


✅ 1. 라이브러리 및 전역 변수

#include <WiFi.h>
#include <HTTPClient.h>
  • WiFi.h: ESP32에서 Wi-Fi 기능 사용
  • HTTPClient.h: HTTP 요청(POST, GET 등)을 보내기 위한 라이브러리
const char *ssid = "Your_SSID";          // Wi-Fi 이름
const char *password = "Your_Password";  // Wi-Fi 비밀번호

const String rest_api_key = "REST API KEY"; 
String access_token = "Access token";
String refresh_token = "Refresh token";

#define MsgSendInterval 3600 // 60 * 60초 = 1시간
long timeout = 3600;         // loop()에서 시간 경과 측정을 위한 변수
int sensorValue = 0;
int sensorPin = 34;          // 아날로그 센서 핀 번호

✅ 2. setup(): 시스템 초기화

void setup() {
  Serial.begin(115200);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(1000);
  }

  Serial.print("\nConnected to WiFi : ");
  Serial.println(WiFi.localIP());
}
  • Wi-Fi 연결을 시도하고, 연결될 때까지 대기한다.
  • 연결 성공 시 로컬 IP를 출력한다.

✅ 3. loop(): 반복 실행

void loop() {
  if (timeout++ > MsgSendInterval) {
    if (isAccessTokenExpired() == true) {
      if (update_access_token() == false) {
        Serial.println("Access token update failed");
      }
    }
    sensorValue = analogRead(sensorPin);
    send_message();
    timeout = 0;
  }

  delay(1000);
}
  • 1초마다 timeout을 증가시킨다.

  • 1시간(3600초)마다 다음 작업 수행:

    • Access Token 만료 여부 확인
    • 만료 시 Refresh Token으로 재발급 시도
    • 센서값 읽고 메시지 전송

✅ 4. isAccessTokenExpired(): 토큰 만료 확인

bool isAccessTokenExpired() {
  HTTPClient http;
  bool returnVal = true;

  http.begin("https://kapi.kakao.com/v1/user/access_token_info");
  http.addHeader("Authorization", "Bearer " + access_token);
  int httpCode = http.GET();

  if (httpCode > 0 && httpCode == HTTP_CODE_OK) {
    String payload = http.getString();
    String expireT = extract_string(payload, "\"expires_in\":", ",");
    if (expireT.toInt() > 0) returnVal = false;
  }

  http.end();
  return returnVal;
}
  • 카카오 API로 현재 Access Token이 유효한지 확인한다.
  • JSON 응답에서 "expires_in" 값을 추출하여 0보다 크면 아직 유효하다고 판단한다.

✅ 5. send_message(): 센서값 전송

void send_message() {
  HTTPClient http;
  String url = "https://kapi.kakao.com/v2/api/talk/memo/default/send";

  http.begin(url);
  http.addHeader("Authorization", "Bearer " + access_token);
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");

  String data = String("template_object={") +
                "\"object_type\": \"text\"," +
                "\"text\": \"토양 센서 값 :" + String(sensorValue) + "\"," +
                "\"link\": {}}";

  http.POST(data);

  String response = http.getString();
  Serial.println(response);

  http.end();
}
  • 카카오톡 메시지를 전송하는 API 호출
  • 메시지 내용은 "토양 센서 값 : [숫자]"로 구성
  • 링크 항목이 비어 있어도 구조는 있어야 한다 ("link": {})

✅ 6. update_access_token(): 토큰 갱신

bool update_access_token() {
  HTTPClient http;
  bool retVal = false;
  String url = "https://kauth.kakao.com/oauth/token";

  http.begin(url);
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");

  String data = "grant_type=refresh_token&client_id=" + rest_api_key +
                "&refresh_token=" + refresh_token;

  int http_code = http.POST(data);
  String response = http.getString();
  access_token = extract_string(response, "{\"access_token\":\"", "\"");
  String new_refresh_token = extract_string(response, "\"refresh_token\":\"", "\"");

  if (new_refresh_token != "") {
    refresh_token = new_refresh_token;
  }

  retVal = true;
  http.end();
  return retVal;
}
  • 현재 보유 중인 Refresh Token으로 Access Token을 재발급받는다.
  • 응답에 새로운 Refresh Token이 포함되어 있다면 갱신한다.

✅ 7. extract_string(): 문자열 추출 유틸리티

String extract_string(String str, String start_string, String end_string) {
  int index1 = str.indexOf(start_string) + start_string.length();
  int index2 = str.indexOf(end_string, index1);
  String value = str.substring(index1, index2);
  return value;
}
  • 응답 본문 문자열에서 특정 구간의 텍스트를 추출하는 함수
  • 예: access_token 또는 expires_in 값을 JSON에서 따로 파싱 없이 문자열로 추출

✅ 전체 흐름 요약

  1. ESP32가 Wi-Fi에 연결된다.

  2. loop()에서 1시간마다:

    • 토큰 유효성 확인
    • 만료 시 새 토큰 갱신
    • 토양 센서값 읽기
    • 카카오톡 메시지 전송
  3. JSON 파싱은 사용하지 않고 extract_string()으로 단순 추출만 수행한다.


⚠️ **GitHub.com Fallback** ⚠️