스마트디바이스실습 ‐ 7주차 - jiho0419/SmartDevice_2025-1 GitHub Wiki

1️⃣ IP (Internet Protocol)

*️⃣ 정의

💠 서로 다른 네트워크 상의 컴퓨터들이 서로 데이터를 주고받기 위한 규칙을 말한다
💠 목적으로는 데이터를 원하는 목적지까지 정확하게 전달하거나 인터넷이나 사설 네트워크 모두에서 기본적으로 사용하기 위함이다

*️⃣ 작동 방식

💠 데이터를 보낼 때, 큰 데이터를 작은 패킷(Packet) 으로 쪼갬
💠 각각의 패킷에는 보내는 사람의 IP 주소와 받는 사람의 IP 주소 가 적혀 있음
💠 패킷들은 독립적으로 네트워크를 통해 이동하고, 도착지에서 다시 조립되어 원래 데이터로 복원된다

*️⃣ IP 주소

💠 IPv4

🔸 32비트 주소 (4개의 8비트 숫자)
🔸 예시: 192.168.0.1
🔸 숫자 범위: 0~255 (각 자리)
🔸 한계: 약 42억 개 → 인터넷 사용자가 많아지면서 주소가 부족해졌음

💠 IPv6

🔸 128비트 주소
🔸 예시: 2001:0db8:85a3:0000:0000:8a2e:0370:7334
🔸 훨씬 더 많은 기기(2^128개!)를 지원할 수 있음

*️⃣ 종류

💠 공인 IP (Public IP)

🔸 인터넷에 직접 연결된 기기에 부여되는 고유한 IP 주소
🔸 예: 여러분의 집 인터넷 공유기 외부 IP

💠 사설 IP (Private IP)

🔸 내부 네트워크(회사, 집)에서만 사용되는 IP.
🔸 예: 공유기 내부에 연결된 휴대폰, 노트북 등

*️⃣ 프로토콜 특성

💠 비연결형(Connectionless)

🔸 통신을 시작하기 전에 상대와 미리 연결하지 않음 (그냥 패킷을 보냄)

💠 비신뢰성(Unreliable)

🔸 패킷이 손실되거나 순서가 뒤바뀔 수도 있음
🔸 따라서, 정확성이 필요한 경우 TCP 같은 다른 프로토콜이 보완해줌

💠 최선 노력형(Best Effort)

🔸 최선을 다해 패킷을 전달하지만, 성공을 보장하지는 않음

2️⃣ 실습

*️⃣ DHT11 온습도 제어

💠 DHT11 센서를 ESP32에 연결하여 실시간 온도 및 습도 데이터를 측정하는 실습 진행


💠 회로 연결


💠 코드

#include <DHT.h>

#define DHTPIN 18          // DHT11 센서에 연결된 핀 번호

// 사용 중인 센서 유형으로 변경하세요. DHT11, DHT22, DHT21
#define DHTTYPE DHT11     // DHT 센서 유형

DHT dht(DHTPIN, DHTTYPE);

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

void loop() {
  delay(2000);  // 2초마다 센서 값을 읽습니다.

  // 온도 및 습도 값 읽기
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();

  // 센서 값 출력
  Serial.print("온도: ");
  Serial.print(temperature);
  Serial.print(" °C, 습도: ");
  Serial.print(humidity);
  Serial.println(" %");
}


💠 실행 방법

🔸라이브러리 매니저에서 DHT sensor library by Adafruit를 설치


🔸 위 코드를 입력 후 업로드
🔸 현재 온도와 습도를 알 수 있음 (온도: 25 / 습도는 55.70~56.00)

*️⃣ 텍스트 기반 웹서버 온습도 표시

💠 웹 브라우저로 접속 시 HTML 없이 순수 텍스트만 출력하는 실습 진행


💠 코드

#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>

// Wi-Fi 정보 입력
const char* ssid = "wifi-SSID";             // 연결할 Wi-Fi의 SSID를 입력합니다.
const char* password = "wifi-Password";     // Wi-Fi의 비밀번호를 입력합니다.

// DHT 센서 설정
#define DHTPIN 18
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

// 웹서버 객체 생성
AsyncWebServer server(80);

// 온도 읽기 함수
String readDHTTemperature() {
  float t = dht.readTemperature();
  if (isnan(t)) {
    Serial.println("온도 읽기 실패");
    return "--";
  } else {
    Serial.print("온도: ");
    Serial.println(t);
    return String(t);
  }
}

// 습도 읽기 함수
String readDHTHumidity() {
  float h = dht.readHumidity();
  if (isnan(h)) {
    Serial.println("습도 읽기 실패");
    return "--";
  } else {
    Serial.print("습도: ");
    Serial.println(h);
    return String(h);
  }
}

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

  // Wi-Fi 연결
  Serial.print("Wi-Fi 연결 중: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("\nWi-Fi 연결됨. IP 주소:");
  Serial.println(WiFi.localIP());

  // 루트 페이지: 텍스트로 온습도 정보 출력
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    String msg = "=== ESP32 온습도 정보 ===\n";
    msg += "온도: " + readDHTTemperature() + " °C\n";
    msg += "습도: " + readDHTHumidity() + " %\n";
    msg += "\n개별 확인: /temperature 또는 /humidity";
    request->send(200, "text/plain; charset=utf-8", msg);
  });

  // 온도 전용 요청 처리
  server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain; charset=utf-8", readDHTTemperature());
  });

  // 습도 전용 요청 처리
  server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain; charset=utf-8", readDHTHumidity());
  });

  server.begin();
}

void loop() {
  // 비동기 웹서버: loop 비워둠
}

💠 실습 결과

🔸시리얼 모니터에서 해당 IP를 확인 (192.168.198.66)
🔸텍스트로 현재의 온도와 습도가 표시됨 (온도: 24.10 / 습도: 56.60)

*️⃣ HTML,CSS 적용 웹서버 온습도 표시

💠 HTML과 CSS를 사용하여 DHT11 센서의 온도와 습도를 표시하는 웹 서버 실습 진행


💠 코드

#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>

// Wi-Fi 정보 입력
const char* ssid = "wifi-SSID";             // 연결할 Wi-Fi의 SSID를 입력합니다.
const char* password = "wifi-Password";     // Wi-Fi의 비밀번호를 입력합니다.

// DHT 센서 설정
#define DHTPIN 18
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

// 웹서버 객체 생성
AsyncWebServer server(80);

// 온도 읽기 함수
String readDHTTemperature() {
  float t = dht.readTemperature();
  if (isnan(t)) {
    Serial.println("온도 읽기 실패");
    return "--";
  } else {
    Serial.print("온도: ");
    Serial.println(t);
    return String(t);
  }
}

// 습도 읽기 함수
String readDHTHumidity() {
  float h = dht.readHumidity();
  if (isnan(h)) {
    Serial.println("습도 읽기 실패");
    return "--";
  } else {
    Serial.print("습도: ");
    Serial.println(h);
    return String(h);
  }
}

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

  // Wi-Fi 연결
  Serial.print("Wi-Fi 연결 중: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("\nWi-Fi 연결됨. IP 주소:");
  Serial.println(WiFi.localIP());

  // 루트 페이지: 텍스트로 온습도 정보 출력
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    String msg = "=== ESP32 온습도 정보 ===\n";
    msg += "온도: " + readDHTTemperature() + " °C\n";
    msg += "습도: " + readDHTHumidity() + " %\n";
    msg += "\n개별 확인: /temperature 또는 /humidity";
    request->send(200, "text/plain; charset=utf-8", msg);
  });

  // 온도 전용 요청 처리
  server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain; charset=utf-8", readDHTTemperature());
  });

  // 습도 전용 요청 처리
  server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain; charset=utf-8", readDHTHumidity());
  });

  server.begin();
}

void loop() {
  // 비동기 웹서버: loop 비워둠
}

💠 실습 결과

🔸시리얼 모니터에서 해당 IP를 확인 (192.168.198.66)
🔸HTML,CSS 변경된 웹서버로 현재의 온도와 습도가 표시됨 (온도: 23.80 / 습도: 54.20)

*️⃣ Ngrok을 활용한 외부 접속 웹 서버

💠 Ngrok을 이용하여 외부에서도 접속할 수 있는 웹 서버를 구축 실습 진행


💠 코드

#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>

// Wi-Fi 정보 입력
const char* ssid = "wifi-SSID";             // 연결할 Wi-Fi의 SSID를 입력합니다.
const char* password = "wifi-Password";     // Wi-Fi의 비밀번호를 입력합니다.

#define DHTPIN 18     // DHT 센서에 연결된 디지털 핀

// 사용 중인 센서 유형으로 변경하세요. DHT11, DHT22, DHT21
#define DHTTYPE    DHT11     // 
// 온습도 센서 객체 생성
DHT dht(DHTPIN, DHTTYPE);

// 80번 포트에서 AsyncWebServer 객체 생성
AsyncWebServer server(80);

// DHT 온도 읽기 함수
String readDHTTemperature() {
  // 센서 읽기는 최대 2초가 소요될 수 있습니다. (센서가 매우 느립니다.)
  // 기본값으로 섭씨로 온도 읽기
  float t = dht.readTemperature();
  // 화씨로 온도 읽으려면 매개 변수를 true로 설정
  //float t = dht.readTemperature(true);
  // 읽기 실패 시 조기에 종료하고 다시 시도합니다.
  if (isnan(t)) {
    Serial.println("DHT 센서에서 읽기 실패!");
    return "--";
  }
  else {
    Serial.println(t);
    return String(t);
  }
}

// DHT 습도 읽기 함수
String readDHTHumidity() {
  // 센서 읽기는 최대 2초가 소요될 수 있습니다. (센서가 매우 느립니다.)
  float h = dht.readHumidity();
  if (isnan(h)) {
    Serial.println("DHT 센서에서 읽기 실패!");
    return "--";
  }
  else {
    Serial.println(h);
    return String(h);
  }
}

// 인덱스 HTML 페이지
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" 
    href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" 
    integrity=
    "sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" 
    crossorigin="anonymous">
  <style>
    html {
      font-family: Arial;
      display: inline-block;
      margin: 0px auto;
      text-align: center;
    }
    h2 { font-size: 3.0rem; }
    p { font-size: 3.0rem; }
    .units { font-size: 1.2rem; }
    .dht-labels {
      font-size: 1.5rem;
      vertical-align: middle;
      padding-bottom: 15px;
    }
  </style>
</head>
<body>
  <h2>ESP32 DHT Server</h2>
  <p>
    <i class="fas fa-thermometer-half" style="color:#059e8a;"></i>
    <span class="dht-labels">온도</span>
    <span id="temperature">%TEMPERATURE%</span>
    <sup class="units">&deg;C</sup>
  </p>
  <p>
    <i class="fas fa-tint" style="color:#00add6;"></i>
    <span class="dht-labels">습도</span>
    <span id="humidity">%HUMIDITY%</span>
    <sup class="units">&percnt;</sup>
  </p>
</body>
<script>
setInterval(function() {
  // XMLHttpRequest 객체를 사용하여 "/temperature" 엔드포인트로 GET 요청을 전송
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      // 요청이 완료되고 성공적인 응답을 받았을 때, 온도 값을 업데이트합니다.
      document.getElementById("temperature").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "/temperature", true);
  xhttp.send();
}, 2000); // 2초 간격으로 업데이트합니다.

setInterval(function() {
  // XMLHttpRequest 객체를 사용하여 "/humidity" 엔드포인트로 GET 요청을 전송
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      // 요청이 완료되고 성공적인 응답을 받았을 때, 습도 값을 업데이트합니다.
      document.getElementById("humidity").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "/humidity", true);
  xhttp.send();
}, 2000); //2초 간격으로 업데이트합니다.
</script>
</html>
)rawliteral";

// 플레이스홀더를 DHT 값으로 대체하는 함수
String processor(const String& var){
  if(var == "TEMPERATURE"){
    return readDHTTemperature();
  }
  else if(var == "HUMIDITY"){
    return readDHTHumidity();
  }
    return String();
}

void setup(){
  // 디버깅용 시리얼 포트 설정
  Serial.begin(115200);

  dht.begin();

  // Wi-Fi 연결
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Wi-Fi에 연결 중...");
}

// ESP32 로컬 IP 주소 출력
Serial.println(WiFi.localIP());

// 루트(/) 웹 페이지 라우팅
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send_P(200, "text/html", index_html, processor);
});

// "/temperature" 엔드포인트에 대한 GET 요청 처리
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send_P(200, "text/plain", readDHTTemperature().c_str());
});

// "/humidity" 엔드포인트에 대한 GET 요청 처리
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send_P(200, "text/plain", readDHTHumidity().c_str());
});

// 서버 시작
server.begin();
}

void loop(){

}

💠 실행 방법

🔸 Ngrok 사이트 접속 https://ngrok.com/ 후 회원가입 진행
🔸 Ngrok 설치 (자신에 맞는 버전으로 다운 ) https://ngrok.com/download


🔸 https://dashboard.ngrok.com/get-started/your-authtoken 에서 자신의 토큰을 복사


🔸 Ngrok 을 킨 후 ngrok config add-authtoken 자신의 토큰 을 입력
🔸 위 코드를 업로드 후 시리얼 모니터에서 받은 IP를 확인 후 ngrok http 확인한IP:80을 입력
🔸 입력 후 나온 app으로 접속


🔸 app을 접속하면 현재 온도와 습도가 표시되어 외부에서 접속 가능함 (온도: 23.50 / 습도: 58.30)

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