메인 콘텐츠로 건너뛰기

5장 ESP32 WiFi 네트워크 연결 기초와 실습 예제

로버트
로버트
조회수 6

생성형 AI 도구를 활용하여 작성 및 편집된 노트입니다.

다시 보는 ESP32

개요

ESP32는 WiFi와 블루투스를 내장한 마이크로컨트롤러로, 저렴한 가격에 네트워크 기능을 손쉽게 활용할 수 있어 IoT 프로젝트에서 많이 사용됩니다. 특히 Arduino IDE에서 제공하는 WiFi.h 라이브러리를 사용하면, 복잡한 네트워크 프로토콜을 직접 다루지 않고도 몇 줄의 코드만으로 무선 네트워크에 연결할 수 있습니다.

Generated Image

이 노트에서는 ESP32의 기본적인 WiFi 동작 모드를 이해하고, 실제로 코드를 작성해 네트워크에 연결해 보는 실습 중심으로 내용을 정리합니다. 암호가 있는 AP, 오픈 네트워크(암호 없음) 연결, 네트워크 정보 조회, 연결 상태 확인과 디버깅, 간단한 재시작(타임아웃) 처리까지 한 번에 정리할 수 있도록 구성했습니다.


ESP32의 두 가지 WiFi 모드: STATION 모드와 AP 모드

ESP32는 크게 두 가지 WiFi 모드를 지원합니다: STATION 모드(WIFI_STA)와 AP 모드(WIFI_AP)입니다. 기본값은 STATION 모드입니다.

STATION 모드는 ESP32가 집이나 회사에서 사용하는 일반 WiFi 라우터(무선 공유기)에 접속하는 "클라이언트"처럼 동작하는 방식입니다. 이 모드에서 ESP32는 노트북이나 스마트폰과 마찬가지로 라우터에 연결되고, 라우터가 인터넷에 연결되어 있다면 ESP32도 인터넷에 접근할 수 있습니다. 이후 ESP32는 외부 서버에 데이터를 보내거나, 반대로 ESP32 안에 웹 서버를 띄워 같은 네트워크의 다른 기기에서 접근하도록 할 수 있습니다.

AP(Access Point) 모드는 ESP32가 자체적으로 하나의 WiFi 네트워크(소프트 AP)를 만들어 다른 기기들이 ESP32에 직접 접속하도록 하는 방식입니다. 이때 ESP32는 라우터 같은 역할을 하며, 보통 인터넷에는 연결되지 않습니다. 주변 스마트폰이나 노트북이 ESP32가 만든 WiFi SSID에 직접 접속하게 됩니다. 다만 이 모드는 ESP32가 라우터 기능을 흉내 내야 하기 때문에 계산량과 전력 소모가 더 크고, 발열과 지연 시간, 대역폭 면에서 일반 라우터보다 비효율적일 수 있습니다.

실제 프로젝트에서는 대부분 STATION 모드를 사용합니다. 예를 들어 센서 데이터를 클라우드 서버로 보내거나, 집 안의 홈 오토메이션 서버와 통신하려면 라우터를 통해 인터넷에 접속해야 하므로 STATION 모드가 적합합니다. AP 모드는 주로 초기 설정 단계에서 "설정용 WiFi"를 열고, 사용자에게 SSID/패스워드를 입력받을 때 일시적으로 사용하거나, 외부 인터넷 없이 독립된 폐쇄형 네트워크를 만들 때 활용합니다.


WiFi.h 라이브러리 기본 구조 이해하기

ESP32를 Arduino IDE에서 사용할 때는 WiFi.h 라이브러리를 포함해 네트워크 기능을 제어합니다. 기본적인 연결 흐름은 대부분 다음 순서를 따릅니다.

  1. #include <WiFi.h>로 라이브러리 포함

  2. 접속할 AP의 SSID, 비밀번호를 전역 변수로 선언

  3. setup()에서 WiFi.mode()로 모드 설정(필수는 아니지만 명시하면 좋음)

  4. WiFi.begin(ssid, password)로 연결 시도

  5. WiFi.status()를 반복 확인하며 연결 완료를 기다림

  6. 연결되면 WiFi.localIP() 등으로 IP 정보 출력

아래는 암호가 있는 WiFi AP에 연결하는 가장 기본적인 구조입니다.

#include <WiFi.h>

// 접속할 WiFi 정보
const char* ssid     = "yourNetworkName";
const char* password = "yourNetworkPassword";

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

  // 1. STATION 모드 명시 (생략해도 기본값이지만, 코드 가독성을 위해 넣는 것을 권장)
  WiFi.mode(WIFI_STA);

  // 2. WiFi 연결 시작
  WiFi.begin(ssid, password);

  Serial.println("\nConnecting");

  // 3. 연결 완료될 때까지 상태를 계속 확인
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(100);
  }

  // 4. 연결 성공 후 로컬 IP 출력
  Serial.println("\nConnected to the WiFi network");
  Serial.print("Local ESP32 IP: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  // 이 예제에서는 반복 동작 없음
}

실행하면 시리얼 모니터에 점들이 찍히다가, 연결에 성공하면 "Connected to the WiFi network"와 할당된 IP 주소가 출력됩니다.


비밀번호 있는 네트워크 연결 예제 (실습 중심)

암호가 있는 일반 가정용 WiFi에 연결하는 가장 실용적인 예제를 조금 더 "실습용"으로 풀어보면 다음과 같은 형태가 됩니다. 여기에 간단한 타임아웃 및 상태 메시지를 추가해 실습 시 불편함을 줄일 수 있습니다.

#include <WiFi.h>

const char* ssid     = "yourNetworkName";       // 공유기 SSID
const char* password = "yourNetworkPassword";   // 공유기 비밀번호

// 연결을 기다릴 최대 시간(초)
#define WIFI_CONNECT_TIMEOUT 15

void connectToWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  Serial.println("\n[WiFi] Connecting...");

  unsigned long start = millis();
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);

    if (millis() - start > WIFI_CONNECT_TIMEOUT * 1000) {
      Serial.println("\n[WiFi] Connection timeout!");
      return;
    }
  }

  Serial.println("\n[WiFi] Connected!");
  Serial.print("[WiFi] Local IP: ");
  Serial.println(WiFi.localIP());
}

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

  connectToWiFi();
}

void loop() {
  // 여기서부터는 WiFi가 연결되었다고 가정하고
  // 서버에 데이터를 보내거나, 웹 서버를 띄우는 코드를 추가할 수 있습니다.
}

실습 포인트:

  • SSID와 비밀번호를 자신의 공유기 정보로 꼭 수정해야 합니다.

  • 시리얼 모니터를 115200 baud로 설정해야 한글/영문 출력이 제대로 보입니다.

  • 비밀번호가 틀리거나 SSID가 잘못된 경우 타임아웃 후 "Connection timeout!" 메세지가 출력됩니다.

보안 관점에서, 코드 안에 SSID/비밀번호를 평문으로 두는 것은 좋지 않은 습관입니다. 실제 프로젝트에서는 별도의 헤더 파일이나 설정 파일에 분리하거나, 빌드 환경 변수 등을 사용하는 방식을 고려하는 것이 좋습니다.


오픈 네트워크(비밀번호 없음) 연결 예제

카페, 공공장소, 혹은 실습용으로 스마트폰 테더링을 "암호 없이" 열어둔 경우처럼 비밀번호가 없는 네트워크도 있습니다. 이때는 WiFi.begin() 호출에서 비밀번호를 생략할 수 있어 코드가 더 단순해집니다.

#include <WiFi.h>

const char* ssid = "openNetworkName";   // 비밀번호 없는 AP의 SSID

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

  WiFi.mode(WIFI_STA);

  // 비밀번호가 없는 경우 password 인자를 생략
  WiFi.begin(ssid);

  Serial.println("\nConnecting to open network");

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(100);
  }

  Serial.println("\nConnected to the open WiFi network");
  Serial.print("Local ESP32 IP: ");
  Serial.println(WiFi.localIP());
}

void loop() {
}

실습에서 가끔 실수하는 부분은, "비밀번호 없는 AP인데 습관적으로 WiFi.begin(ssid, password)를 쓰고, password를 빈 문자열 ""로 넣는 경우"입니다. 대체로 빈 문자열도 동작하지만, AP 설정에 따라 접속 실패할 수 있으므로 "정말 비밀번호가 없다면" 위처럼 WiFi.begin(ssid); 형태로 사용하는 것이 더 명확합니다.


네트워크 정보 조회: IP, RSSI, BSSID, 게이트웨이, 서브넷 마스크

WiFi에 연결된 후에는 ESP32와 네트워크 환경에 대한 다양한 정보를 WiFi 객체의 메서드를 통해 얻을 수 있습니다. 대표적인 것들은 다음과 같습니다.

  • WiFi.localIP() 라우터의 DHCP 서버가 ESP32에게 할당한 로컬 IP 주소입니다. 같은 네트워크의 다른 기기에서 ESP32에 접속할 때 사용하는 주소입니다.

  • WiFi.RSSI() 현재 연결된 WiFi 신호 강도(RSSI)를 dB 단위로 반환합니다. 값이 0에 가까울수록 강하고, -90dB처럼 절대값이 커질수록 신호가 약합니다.

  • WiFi.BSSIDstr() 현재 접속 중인 AP의 MAC 주소(BSSID)를 문자열 형태로 반환합니다.

  • WiFi.gatewayIP() 게이트웨이(보통 공유기)의 IP 주소입니다. 예: 192.168.0.1, 휴대폰 테더링에서는 종종 192.168.43.1 등.

  • WiFi.subnetMask() 서브넷 마스크 정보입니다. 가정용 네트워크에서는 255.255.255.0 형태가 일반적입니다.

아래 예제는 위의 정보를 한 번에 출력하는 코드입니다.

#include <WiFi.h>

const char* ssid     = "yourNetworkName";
const char* password = "yourNetworkPassword";

void printNetworkInfo() {
  if (WiFi.status() == WL_CONNECTED) {
    Serial.print("[*] Network information for ");
    Serial.println(ssid);

    Serial.println("[+] BSSID : " + WiFi.BSSIDstr());

    Serial.print("[+] Gateway IP : ");
    Serial.println(WiFi.gatewayIP());

    Serial.print("[+] Subnet Mask : ");
    Serial.println(WiFi.subnetMask());

    Serial.print("[+] RSSI : ");
    Serial.print(WiFi.RSSI());
    Serial.println(" dB");

    Serial.print("[+] ESP32 IP : ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("[!] Not connected to WiFi");
  }
}

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

  WiFi.begin(ssid, password);
  Serial.println("\nConnecting");

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(100);
  }

  Serial.println("\nConnected to the WiFi network");

  printNetworkInfo();
}

void loop() {
  // 필요하면 특정 주기마다 printNetworkInfo()를 호출해 상태를 갱신할 수 있습니다.
}

실습 팁:

  • 이 코드를 먼저 실행해서 자신의 공유기 게이트웨이 IP, 서브넷 마스크를 확인해 두면, 나중에 "정적 IP 설정"을 할 때 큰 도움이 됩니다.

  • RSSI 값을 이용해 ESP32를 들고 이동하면서 신호 강도를 측정하면, 라우터의 위치나 ESP32 설치 위치를 최적화하는 데 참고할 수 있습니다.


WiFi.status() 상태 코드와 의미

WiFi.status() 함수는 ESP32의 현재 WiFi 연결 상태를 나타내는 상수 값을 반환합니다. 이 값들을 잘 이해하면 "왜 연결이 안 되지?" 같은 문제를 디버깅하는 데 큰 도움이 됩니다.

대표적인 상태 값은 다음과 같습니다.

  • WL_IDLE_STATUS 아직 네트워크에 연결하기 전의 기본 상태입니다.

  • WL_SCAN_COMPLETED 주변 WiFi 네트워크 스캔이 완료된 상태입니다. 일반적인 연결 코드에서는 자주 직접 보게 되지는 않습니다.

  • WL_NO_SSID_AVAIL 지정한 SSID를 가진 네트워크를 찾을 수 없을 때 나타납니다. → SSID 오타, AP 전원 꺼짐, AP가 너무 멀어서 신호를 잡지 못하는 경우 등을 의심할 수 있습니다.

  • WL_CONNECT_FAILED 네트워크에 연결을 시도했지만 실패한 상태입니다. → 보통 잘못된 암호, 인증 방식 불일치 등을 먼저 의심해 볼 수 있습니다.

  • WL_CONNECTION_LOST 한 번 연결되었던 네트워크와의 연결이 끊어진 상태입니다. → AP 재부팅, 전파 간섭, ESP32 전원 문제 등 여러 원인이 있을 수 있습니다.

  • WL_CONNECTED 네트워크에 정상적으로 연결된 상태입니다.

  • WL_DISCONNECTED 네트워크에서 연결이 끊어졌거나 아직 연결되지 않은 상태를 의미합니다. 초기 상태나, 연결 시도 실패 이후 종종 보게 됩니다.


연결 상태 모니터링 예제 코드 (디버깅용)

연결 과정에서 WiFi.status() 값을 주기적으로 확인하고, 그에 해당하는 문자열을 출력하도록 하면 디버깅할 때 어떤 단계에서 문제가 생기는지 파악하기 쉽습니다.

#include <WiFi.h>

const char* ssid     = "yourNetworkName";
const char* password = "yourNetworkPassword";

String getWiFiStatusText(int status) {
  switch (status) {
    case WL_IDLE_STATUS:      return "WL_IDLE_STATUS";
    case WL_SCAN_COMPLETED:   return "WL_SCAN_COMPLETED";
    case WL_NO_SSID_AVAIL:    return "WL_NO_SSID_AVAIL";
    case WL_CONNECT_FAILED:   return "WL_CONNECT_FAILED";
    case WL_CONNECTION_LOST:  return "WL_CONNECTION_LOST";
    case WL_CONNECTED:        return "WL_CONNECTED";
    case WL_DISCONNECTED:     return "WL_DISCONNECTED";
    default:                  return "UNKNOWN_STATUS";
  }
}

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

  int status = WL_IDLE_STATUS;

  Serial.println("\nConnecting");
  Serial.println(getWiFiStatusText(status));

  WiFi.begin(ssid, password);

  // WL_CONNECTED가 될 때까지 상태 출력
  while (status != WL_CONNECTED) {
    delay(500);
    status = WiFi.status();
    Serial.println(getWiFiStatusText(status));
  }

  Serial.println("\nConnected to the WiFi network");
  Serial.print("Local ESP32 IP: ");
  Serial.println(WiFi.localIP());
}

void loop() {
}

이 코드를 사용하면 다음과 같은 시나리오를 쉽게 재현·관찰할 수 있습니다.

  • 성공적인 연결: WL_IDLE_STATUSWL_DISCONNECTEDWL_CONNECTED 등의 흐름 후 IP 출력

  • SSID를 찾을 수 없음: WL_NO_SSID_AVAIL이 반복 출력

  • 비밀번호 오류: WL_CONNECT_FAILED 또는 연결 실패 후 WL_DISCONNECTED 반복

실습할 때는 SSID를 일부러 틀리게 입력하거나, 비밀번호를 일부러 잘못 넣어보면서 상태 코드 변화가 어떻게 나타나는지 관찰해 보면 이해가 훨씬 잘 됩니다.


타임아웃 후 ESP32 자동 재시작 예제

실제 운용 환경에서는 "이상하게 오늘은 WiFi가 안 붙네?" 같은 상황이 발생할 수 있습니다. 이때 가장 단순하면서 강력한 해결책 중 하나는 "일정 시간 안에 연결이 안 되면 그냥 리셋(재부팅)한다"는 전략입니다.

아래 예제는 WiFi 연결을 시도하고, 일정 시간(예: 10초) 동안 WL_CONNECTED가 되지 않으면 ESP.restart()를 호출하여 ESP32를 다시 시작합니다.

#include <WiFi.h>

#define CONNECTION_TIMEOUT 10   // 초 단위

const char* ssid     = "yourNetworkName";
const char* password = "yourNetworkPassword";

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

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  Serial.println("\nConnecting");

  int timeout_counter = 0;

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(200);
    timeout_counter++;

    // CONNECTION_TIMEOUT 초가 지나면 재부팅
    if (timeout_counter >= CONNECTION_TIMEOUT * 5) {  // 200ms * 5 = 1초
      Serial.println("\n[WiFi] Failed to connect. Restarting ESP32...");
      ESP.restart();
    }
  }

  Serial.println("\nConnected to the WiFi network");
  Serial.print("Local ESP32 IP: ");
  Serial.println(WiFi.localIP());
}

void loop() {
}

재부팅 시 부트 메시지와 함께 다시 setup()이 실행되고, 동일한 로직으로 다시 연결을 시도하게 됩니다. 현장에서 장비를 직접 만지기 어려운 환경에서는 이런 자동 복구 로직이 매우 중요합니다.


정리 및 다음 단계 제안

이 노트에서는 ESP32의 WiFi 기능을 다루는 데 꼭 필요한 기초를 다음 순서로 정리했습니다.

  • ESP32의 WiFi 모드: STATION vs AP

  • WiFi.h를 이용한 암호 있는 AP 연결 기본 구조

  • 비밀번호 없는 오픈 네트워크 연결 코드

  • WiFi.localIP, WiFi.RSSI, WiFi.BSSIDstr, WiFi.gatewayIP, WiFi.subnetMask 등으로 네트워크 정보 조회

  • WiFi.status() 상태 코드별 의미와 디버깅 방법

  • 일정 시간 내 미연결 시 ESP 재시작 타임아웃 처리 예제

여기까지 익혔다면, 다음 단계로는 다음과 같은 실습을 시도해 보는 것을 추천합니다.

  • ESP32를 STATION 모드로 연결한 뒤 간단한 웹 서버를 띄워, 브라우저에서 ESP32 페이지 열어 보기

  • ESP32를 AP 모드로 설정해 스마트폰으로 직접 접속해 보기

  • WiFi.config()를 사용해 정적 IP를 설정하고, 항상 동일한 주소로 ESP32에 접속해 보기

이러한 확장을 통해 "WiFi 연결"을 하나의 도구로 삼아, 자신만의 IoT 서비스나 프로젝트를 구현하는 데 한 발 더 나아갈 수 있습니다.

이 노트는 요약·비평·학습 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.