7주차 ‐ DHT11 센서를 이용한 온습도 측정 및 웹 서버를 통한 데이터 출력 - boguuu/SmartDevice_2025-1 GitHub Wiki

1. DHT11 온/습도 제어하기


실습을 위한 준비물

  • ESP32 개발 보드
  • ESP32 확장 실드
  • DHT11 온습도 센서 모듈
  • DHT Sensor Library by Adafruit (라이브러리 매니저에서 설치)
  • ESPAsyncWebServer 및 Async TCP 라이브러리

회로연결


image

실습 코드


#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(" %");
}

코드설명


🔧 1. 라이브러리 포함

#include <DHT.h>
  • DHT.h는 DHT 시리즈 센서(DHT11, DHT22 등)를 쉽게 사용할 수 있게 해주는 라이브러리
  • 이 라이브러리를 사용하면 복잡한 신호 처리 없이 간단하게 온습도 값을 읽을 수 있음

📌 2. 핀 및 센서 유형 설정

#define DHTPIN 18
#define DHTTYPE DHT11
  • DHTPIN은 센서가 연결된 디지털 핀 번호입니다. 여기서는 핀 18을 사용
  • DHTTYPE은 사용 중인 센서의 종류를 정의합니다. 이 코드에서는 DHT11을 사용

🧠 3. DHT 객체 생성

DHT dht(DHTPIN, DHTTYPE);
  • 위에서 설정한 핀 번호와 센서 타입으로 dht라는 센서 객체를 생성
  • 이 객체를 통해 센서 데이터를 읽음

⚙️ 4. setup() 함수

void setup() {
  Serial.begin(115200);
  dht.begin();
}
  • Serial.begin(115200)시리얼 통신을 115200 보드레이트로 시작 (속도 조절 가능)
  • dht.begin()센서를 초기화.

🔁 5. loop() 함수

void loop() {
  delay(2000);
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();

  Serial.print("온도: ");
  Serial.print(temperature);
  Serial.print(" °C, 습도: ");
  Serial.print(humidity);
  Serial.println(" %");
}
  • delay(2000) : 2초 대기 후 센서 값을 읽음. (너무 자주 읽으면 오류 발생 가능)
  • readTemperature() : 온도 값을 °C로 읽음
  • readHumidity() : 상대 습도 값을 %로 읽음
  • Serial.print/println : 값을 시리얼 모니터에 출력

동작 요약


  • 아두이노가 켜지면 센서를 초기화하고, 2초마다 온도와 습도를 측정해 시리얼 모니터로 전송
  • 시리얼 모니터(115200bps)에서 실시간으로 측정값을 확인 가능
  • DHT11 센서는 온도(050°C, ±2°C), 습도(2090% RH, ±5% RH) 범위 내에서 동작

실행방법


1.핵심 라이브러리 설치


1

2. 코드 업로드


2

3. 실행결과 확인


3

4

💡 시리얼 모니터에 온도와 습도가 잘 뜨는 것을 확인

2. DHT11 온습도 표시 웹 서버


실습코드


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

// 실습 환경의 WIFI아이디와 비밀번호로 수정하세요.
const char* ssid = "YourSSID"; // 연결할 Wi-Fi의 SSID를 입력합니다.
const char* password = "YourPassword"; // 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(){

}

코드설명


🔧 1. 필요한 라이브러리

#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
  • WiFi.h: ESP32의 Wi-Fi 기능 사용
  • AsyncTCP.h / ESPAsyncWebServer.h: 비동기 웹 서버 구동용 (빠르고 반응성 좋음)
  • DHT.h: DHT11 센서 제어용 라이브러리

📶 2. Wi-Fi 정보 설정

const char* ssid = "YourSSID";
const char* password = "YourPassword";
  • Wi-Fi 이름(SSID)과 비밀번호를 입력해서 ESP32가 인터넷에 연결되게 함

🌡️ 3. 센서 핀 및 객체 정의

#define DHTPIN 18
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
  • 18번 디지털 핀에 연결된 DHT11 센서 사용 설정

🌐 4. 웹서버 객체 생성

AsyncWebServer server(80);
  • *80번 포트(HTTP 기본 포트)**로 웹 서버 실행

🌈 5. 온도/습도 측정 함수

String readDHTTemperature()
String readDHTHumidity()
  • readTemperature()readHumidity() 로 측정
  • 오류 발생 시 "--" 반환
  • 정상값이면 문자열로 반환 (String(t))

🖥️ 6. HTML 웹페이지 정의

const char index_html[] PROGMEM = R"rawliteral(
  ... HTML, CSS, JS 포함된 코드 ...
)rawliteral";
  • 웹 페이지 UI 정의
  • 아이콘(fontawesome 사용), 디자인 CSS 포함
  • %TEMPERATURE%, %HUMIDITY% 부분은 센서 값으로 대체됨

🔄 7. 자바스크립트로 실시간 업데이트

setInterval(function() {
  var xhttp = new XMLHttpRequest();
  xhttp.open("GET", "/temperature", true);
  xhttp.send();
}, 2000);
  • 2초마다 서버에 GET 요청을 보내서
  • 새로운 온도/습도 값을 가져와 화면에 표시

🔁 8. 플레이스홀더 값 대체

String processor(const String& var)
  • %TEMPERATURE% 또는 %HUMIDITY% 문자열을 실제 측정값으로 바꿔주는 함수

⚙️ 9. setup() 함수

void setup() {
  ...
}
  • 시리얼 시작
  • DHT 센서 초기화
  • Wi-Fi 연결 (연결될 때까지 대기)
  • 서버 라우팅 설정:
    • /: HTML 페이지 전송
    • /temperature: 온도 문자열 전송
    • /humidity: 습도 문자열 전송
  • 서버 시작

동작 요약


  1. ESP32가 부팅 → Wi-Fi 연결 → 웹서버 실행
  2. PC/스마트폰에서 ESP32의 IP로 접속
  3. 웹페이지에서 2초마다 센서값을 자동으로 새로고침하여 실시간 표시

실행방법


1. 코드 업로드


5

2. 시리얼 모니터를 통해 ip주소 확인


6

3. ip주소로 이동후 결과 확인


7

8

3. Ngrok을 활용한 외부 접속 웹 서버


Ngrok설치


9

💡 가입 후 Terminal 를 이용하거나 Download를 눌러 다운로드를 진행

다운로드 후 실행


10

인증키 값 확인 후 적용


11

💡 사이트에서 인증키 값을 확인

12

💡 ngrok config add-authtoken 인증키값

웹서버를 외부로 호스팅


13

14

💡 ngrok tcp 서버IP:서버포트를 Terminal창에서 실행

웹서버 실행 및 적용 확인


15

💡 주소의 첫tcp를 http로 변경하여 주소창 입력

사설 IP 영역에서 서버 운영


사설 IP 구현의 주된4가지 방법


번호 방법 설명
1 포트 포워딩 공유기 설정에서 외부에서 특정 포트로 들어온 요청을 사설 IP의 서버로 전달
2 DDNS + 포트 포워딩 유동 공인 IP를 도메인 주소로 연결 + 포트 포워딩
3 VPN 서버 구성 외부에서 내부 네트워크에 안전하게 접속해서 마치 내부처럼 서버에 접근
4 터널링 서비스 (예: Ngrok) 별도 설정 없이 외부 접근 가능하게 해주는 클라우드 중계형 터널링 방식
💡

 Ngrok은 제4번, ‘터널링 서비스’에 해당

  • Ngrok은 로컬 서버가 사설 IP 영역에 있어도, 외부에서 접근할 수 있게 중간에 있는 Ngrok 서버가 중계 역할
  • 공유기 설정이나 포트 포워딩 없이도 동작!
  • 로컬에서 실행한 서버(localhost:포트번호)를 Ngrok이 외부 URL로 연결시켜 줌.

요약


구분 Ngrok
사설 IP에서 외부 접근 가능하게 해줌? ✅ 가능
공유기 설정(포트포워딩) 필요? ❌ 불필요
외부 접근 주소 제공? ✅ 예 (예: https://abcd1234.ngrok.io)
속도, 연결 유지 💡 제한적 (무료 버전은 일정 시간 후 끊김 등 제약 있음)
⚠️ **GitHub.com Fallback** ⚠️