13주차_참고 : ESP32 OLED WiFi 공공데이터 API를 연계하는 코드의 상세 설명 - dhryu60/SmartDevice_2025-1 GitHub Wiki

1. 라이브러리 포함

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <WiFi.h>
#include <time.h>
#include "images.h"
  • Wire: I2C 통신을 지원.
  • Adafruit_GFX, Adafruit_SSD1306: OLED 디스플레이 제어 라이브러리.
  • WiFi: ESP32의 Wi-Fi 연결을 위해 포함.
  • time.h: 시간 관련 기능 제공.
  • images.h: 등급별 이미지 데이터를 포함한 헤더 파일.

2. WiFi 및 API 관련 설정

const char* ssid = "Your_SSID";
const char* password = "Your_Password";
const int httpPort = 80;
const char* apiKey = "...";  // 공공데이터 API 인증키
const char* version = "&ver=1.3";
const char* server = "apis.data.go.kr";
const char* stationName = "과천동";
const char* returnType = "xml";
const char* numOfRows = "1";
const char* pageNo = "1";
const char* dataTerm = "DAILY";
WiFiClient client;
  • Wi-Fi 연결 정보와 API 요청 파라미터를 정의.
  • WiFiClient client: HTTP 요청 및 응답 처리를 위해 생성.

3. OLED 디스플레이 설정

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
  • OLED 디스플레이의 크기와 주소를 설정하고 display 객체 생성.

4. setup() 함수

void setup() {
  Serial.begin(115200);
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  display.display();
  delay(2000);
  • 시리얼 모니터 시작, OLED 초기화 및 Adafruit 로고 화면 표시.
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("\nConnecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(1000);
  }
  Serial.println("\nWiFi is connected");
  • Wi-Fi 연결을 시도하고 연결될 때까지 대기.
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.setTextColor(WHITE);
  display.drawBitmap(0, 0, VeryGood, 32, 32, 1);
  display.display();
}
  • OLED 화면 초기화 및 VeryGood 아이콘 출력.

5. loop() 함수

void loop() {
  String dateNtime, pm10Val, pm10Grade, tmp_str;
  static int IntervalReq = 1800;  // 30분 간격 요청
  • 변수 초기화 및 30분마다 요청하도록 카운터 설정.
  if (IntervalReq++ > 1800) {
    IntervalReq = 0;
    Requesthttp();  // 데이터 요청
  }
  delay(50);
  • 50ms 지연 후, Wi-Fi 클라이언트 응답 대기.
  while (client.available()) {
    String line = client.readStringUntil('\n');
    Serial.println(line);
  • 수신한 응답 라인을 한 줄씩 읽어 출력.
    i = line.indexOf("</dataTime>");
    if (i > 0) {
      tmp_str = "<dataTime>";
      dateNtime = line.substring(line.indexOf(tmp_str) + tmp_str.length(), i);
      Serial.println(dateNtime);
    }
  • <dataTime> 태그에서 측정 일시 추출.
    i = line.indexOf("</pm10Value>");
    if (i > 0) {
      tmp_str = "<pm10Value>";
      pm10Val = line.substring(line.indexOf(tmp_str) + tmp_str.length(), i);
      Serial.println(pm10Val);
    }
  • <pm10Value> 태그에서 미세먼지 농도 추출.
    i = line.indexOf("</pm10Grade>");
    if (i > 0) {
      tmp_str = "<pm10Grade>";
      pm10Grade = line.substring(line.indexOf(tmp_str) + tmp_str.length(), i);
      Serial.println(pm10Grade);
      client.stop();
      display.clearDisplay();
      displayIcon(atoi(pm10Grade.c_str()));  // 등급별 아이콘 표시
      displayString(dateNtime, pm10Val);     // 날짜 및 농도 표시
      display.display();
      break;
    }
  }
  delay(1000);
}
  • <pm10Grade> 태그에서 등급을 추출하여 OLED에 아이콘과 텍스트로 표시.

6. Requesthttp() 함수

void Requesthttp() {
  if (client.connect(server, httpPort)) {
    Serial.println("\nSuccessed connection, and request http protocol");
    client.print(String("Get /B552584/ArpltnInforInqireSvc"));
    client.print(String("/getMsrstnAcctoRltmMesureDnsty?serviceKey=") + apiKey);
    client.print(String("&returnType=") + returnType);
    client.print(String("&numOfRows=") + numOfRows);
    client.print(String("&pageNo=") + pageNo);
    client.print(String("&stationName=") + urlencode(stationName));
    client.print(String("&dataTerm=") + dataTerm);
    client.print(version);
    client.print(" HTTP/1.1\r\n");
    client.print("Host: " + String(server) + "\r\n");
    client.print("Connection: close\r\n\r\n");
  } else {
    Serial.println("\nfailed connection");
  }
}
  • Wi-Fi를 통해 공공데이터 API 서버에 연결하고 HTTP GET 요청을 전송.

7. displayString() 함수

void displayString(String dnt, String pmval) {
  display.setCursor(50, 3);
  display.println(dnt.substring(0, 10));  // 날짜
  display.setCursor(50, 13);
  display.println(dnt.substring(11));     // 시간
  display.setCursor(50, 23);
  display.print(pmval);
  display.println(" ug/m^3");             // 미세먼지 농도
}
  • 날짜, 시간, 미세먼지 농도를 OLED에 출력.

8. displayIcon() 함수

void displayIcon(int grade) {
  switch (grade) {
    case 1: display.drawBitmap(0, 0, VeryGood, 32, 32, 1); break;
    case 2: display.drawBitmap(0, 0, Good, 32, 32, 1); break;
    case 3: display.drawBitmap(0, 0, Bad, 32, 32, 1); break;
    case 4: display.drawBitmap(0, 0, VeryBad, 32, 32, 1); break;
  }
}
  • 미세먼지 등급(1~4)에 따라 대응하는 아이콘을 OLED에 출력.

9. urlencode() 함수

String urlencode(String str) {
  String encodedString = "";
  for (int i = 0; i < str.length(); i++) {
    char c = str.charAt(i);
    if (c == ' ') encodedString += '+';
    else if (isalnum(c)) encodedString += c;
    else {
      char code1 = (c & 0xf) + '0'; if ((c & 0xf) > 9) code1 = (c & 0xf) - 10 + 'A';
      char code0 = (c >> 4) & 0xf; code0 = (code0 > 9) ? code0 - 10 + 'A' : code0 + '0';
      encodedString += '%'; encodedString += code0; encodedString += code1;
    }
  }
  return encodedString;
}
  • URL에 한글 등 특수문자가 포함될 경우 % 인코딩을 적용하는 함수.

요약

  • ESP32 + OLED + Wi-Fi + 공공데이터 API 연계를 통해 실시간으로 미세먼지 상태를 표시한다.
  • 30분마다 데이터를 요청하고, <dataTime>, <pm10Value>, <pm10Grade>를 파싱한다.
  • 등급별 아이콘과 수치를 OLED에 출력한다.

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