여러 슬라이더가 있는 ESP32 웹 서버(WebSocket): LED 밝기 제어(PWM)
이 튜토리얼에서는 여러 슬라이더가 있는 웹 페이지를 표시하는 ESP32 웹 서버를 만드는 방법을 보여줍니다. 슬라이더는 다양한 PWM 채널의 듀티 사이클을 제어하여 여러 LED의 밝기를 제어합니다. LED 대신 이 프로젝트를 사용하여 PWM 신호가 필요한 DC 모터나 다른 액추에이터를 제어할 수 있습니다. 클라이언트와 ESP32 간의 통신은 WebSocket 프로토콜을 사용하여 이루어집니다. 또한 변경 사항이 있을 때마다 모든 클라이언트가 슬라이더 값을 동시에 업데이트합니다.
여러 슬라이더가 있는 ESP32 웹 서버 WebSocket: LED 밝기 제어 PWM
이 튜토리얼에 제시된 코드를 수정하여 프로젝트에 슬라이더를 추가하여 임계값이나 코드에서 사용해야 하는 다른 값을 설정할 수도 있습니다.
이 프로젝트의 경우 ESP32 보드는 Arduino 코어를 사용하여 프로그래밍됩니다. Arduino IDE, PlatformIO가 있는 VS Code 또는 다른 적합한 IDE를 사용할 수 있습니다.
이 프로젝트의 작동 방식을 더 잘 이해하려면 다음 튜토리얼을 살펴보는 것이 좋습니다.
Arduino IDE를 사용한 ESP32 PWM(아날로그 출력)
ESP32 WebSocket 서버: 제어 출력(Arduino IDE)
슬라이더가 있는 ESP32 웹 서버: LED 밝기 제어(PWM)*
* 이 프로젝트는 하나의 슬라이더로 웹 서버를 만드는 방법을 보여주지만 HTTP 요청을 사용합니다. 이 튜토리얼에서는 WebSocket 프로토콜을 사용합니다.
ESP8266 NodeMCU 보드에 대한 유사한 튜토리얼이 있습니다.
여러 슬라이더가 있는 ESP8266 NodeMCU 웹 서버(WebSocket): LED 밝기 제어(PWM)
프로젝트 개요
다음 이미지는 이 프로젝트를 위해 만들 웹 페이지를 보여줍니다.
ESP32 웹 서버 WebSocket 프로젝트 개요 슬라이더 PWM
- 웹 페이지에는 세 장의 카드가 있습니다.
- 각 카드에는 카드 제목(페이더 1, 페이더 2, 페이더 3)을 표시하는 단락이 있습니다.
- 각 카드에는 해당 LED의 밝기를 설정하기 위해 이동할 수 있는 범위 슬라이더가 있습니다.
- 각 카드에서 다른 문단은 현재 LED 밝기(백분율)를 표시합니다.
- 슬라이더에 대한 새 위치를 설정하면 모든 클라이언트가 업데이트됩니다(여러 웹 브라우저 탭(또는 여러 장치)을 연 경우 변경 사항이 있을 때마다 거의 동시에 업데이트됨).
작동 원리?
- ESP는 세 개의 슬라이더가 있는 웹 페이지를 표시하는 웹 서버를 호스팅합니다.
- 슬라이더에 대한 새 위치를 설정하면 클라이언트가 WebSocket 프로토콜을 통해 슬라이더 번호와 슬라이더 값을 서버로 전송합니다. 예를 들어, 슬라이더 번호 3을 위치 번호 40으로 설정하면 이 메시지 3s40을 서버로 전송합니다.
ESP32 웹 서버 여러 슬라이더 작동 원리
- 서버(ESP)는 슬라이더 번호와 해당 값을 수신하고 이에 따라 PWM 듀티 사이클을 조정합니다. 또한 다른 모든 클라이언트에 새 현재 슬라이더 값을 알립니다. 이를 통해 모든 클라이언트를 거의 즉시 업데이트할 수 있습니다.
ESP32 슬라이더 웹 서버 WebSocket 업데이트 클라이언트
- ESP32는 LED 밝기를 제어하기 위해 해당 듀티 사이클과 함께 PWM 신호를 출력합니다. 듀티 사이클이 0%이면 LED가 완전히 꺼지고, 듀티 사이클이 50%이면 LED가 반쯤 켜지고, 듀티 사이클이 100%이면 LED가 켜진다는 것을 의미합니다.
ESP32 밝기 듀티 사이클 웹 서버 PWM 예제
새로운 웹 브라우저 창을 열 때마다(새로운 클라이언트가 연결할 때) getValues라는 메시지와 함께 ESP32(WebSocket 프로토콜을 통해)로 메시지를 보냅니다. ESP32가 이 메시지를 받으면 현재 슬라이더 값을 보냅니다. 이렇게 하면 새 탭을 열 때마다 항상 현재 값과 업데이트된 값이 표시됩니다.
ESP32 여러 슬라이더 웹 서버 새 클라이언트 업데이트 값
필수 조건
이 튜토리얼을 진행하기 전에 다음 모든 필수 조건을 확인하세요.
1) 필요한 부품
이 프로젝트를 따르려면 다음이 필요합니다.
ESP32 보드 - ESP32 개발 보드 리뷰 및 비교 읽기
3x LED
3x 220Ohm 저항기
브레드보드
점퍼 와이어
이 프로젝트를 테스트하는 데 3개의 LED가 필요하지 않습니다. 직렬 모니터에서 결과를 보거나 작동에 PWM 신호가 필요한 다른 액추에이터를 사용하면 됩니다.
이전 링크를 사용하거나 MakerAdvisor.com/tools로 바로 이동하여 프로젝트에 필요한 모든 부품을 최상의 가격으로 찾을 수 있습니다!
2) Arduino IDE 및 ESP32 보드 애드온
Arduino IDE를 사용하여 ESP32를 프로그래밍합니다. 따라서 ESP32 애드온이 설치되어 있어야 합니다. 아직 하지 않았다면 다음 튜토리얼을 따르세요.
Arduino IDE에 ESP32 보드 설치(Windows, Mac OS X, Linux)
PlatformIO 확장과 함께 VS Code를 사용하려면 대신 다음 튜토리얼을 따라 ESP32를 프로그래밍하는 방법을 알아보세요.
ESP32 및 ESP8266을 위한 VS Code 및 PlatformIO IDE 시작하기(Windows, Mac OS X, Linux Ubuntu)
3) 파일 시스템 업로더 플러그인
이 프로젝트를 ESP32 플래시 메모리(LittleFS)에 빌드하는 데 필요한 HTML, CSS 및 JavaScript 파일을 업로드하려면 Arduino IDE용 플러그인인 LittleFS 파일 시스템 업로더를 사용합니다. 아직 하지 않았다면 다음 튜토리얼을 따라 파일 시스템 업로더 플러그인을 설치하세요.
Arduino IDE 2: ESP32 LittleFS 업로더 설치(파일 시스템에 파일 업로드)
PlatformIO 확장 기능이 있는 VS Code를 사용하는 경우 다음 튜토리얼을 읽고 파일 시스템에 파일을 업로드하는 방법을 알아보세요.
VS Code 및 PlatformIO가 있는 ESP32: LittleFS 파일 시스템에 파일 업로드
4) 라이브러리
이 프로젝트를 빌드하려면 다음 라이브러리를 설치해야 합니다.
- Arduino_JSON 라이브러리 by Arduino 버전 0.1.0(Arduino 라이브러리 관리자)
- ESPAsyncWebServer(.zip 폴더)
- AsyncTCP(.zip 폴더)
Arduino 라이브러리 관리자를 사용하여 첫 번째 라이브러리를 설치할 수 있습니다. 스케치 > 라이브러리 포함 > 라이브러리 관리로 이동하여 라이브러리 이름을 검색합니다.
ESPAsyncWebServer 및 AsynTCP 라이브러리는 Arduino 라이브러리 관리자를 통해 설치할 수 없으므로 라이브러리 파일을 Arduino 설치 라이브러리 폴더에 복사해야 합니다. 또는 Arduino IDE에서 Sketch>Include Library>Add .zip Library로 이동하여 방금 다운로드한 라이브러리를 선택할 수 있습니다.
라이브러리 설치(VS Code + PlatformIO)
PlatformIO를 사용하여 ESP32를 프로그래밍하는 경우 다음 줄을 platformio.ini 파일에 추가하여 라이브러리를 포함하고 기본 파일 시스템을 LittleFS로 설정해야 합니다(또한 직렬 모니터 속도를 115200으로 변경):
회로도
ESP32에 세 개의 LED를 연결합니다. GPIO 12, 13, 14를 사용합니다. 다른 적합한 GPIO를 사용할 수 있습니다.
세 개의 LED에 연결된 ESP32 회로도 배선 회로
추천 자료: ESP32 핀아웃 참조: 어떤 GPIO 핀을 사용해야 합니까?
파일 구성
프로젝트를 구성하고 이해하기 쉽게 하기 위해 웹 서버를 빌드하는 네 개의 파일을 만듭니다.
웹 서버를 처리하는 Arduino 스케치;
- index.html: 웹 페이지의 내용을 정의합니다.
- sytle.css: 웹 페이지의 스타일을 지정합니다.
- script.js: 웹 페이지의 동작을 프로그래밍합니다. 슬라이더를 움직일 때 발생하는 일을 처리하고, WebSocket 프로토콜을 통해 수신된 메시지를 보내고 받고 해석합니다.
파일 구성 arduino sketch index html style css script js
HTML, CSS, JavaScript 파일은 이전 다이어그램에 표시된 대로 Arduino sketch 폴더 내의 data라는 폴더에 저장해야 합니다. 이러한 파일을 ESP32 파일 시스템(LittleFS)에 업로드합니다.
아래 모든 프로젝트 파일을 다운로드할 수 있습니다.
HTML 파일
다음을 index.html 파일에 복사합니다.
<!DOCTYPE html>
<html>
<head>
<title>ESP IOT DASHBOARD</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/png" href="favicon.png">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="topnav">
<h1>Multiple Sliders</h1>
</div>
<div class="content">
<div class="card-grid">
<div class="card">
<p class="card-title">Fader 1</p>
<p class="switch">
<input type="range" onchange="updateSliderPWM(this)" id="slider1" min="0" max="100" step="1" value ="0" class="slider">
</p>
<p class="state">Brightness: <span id="sliderValue1"></span> %</p>
</div>
<div class="card">
<p class="card-title"> Fader 2</p>
<p class="switch">
<input type="range" onchange="updateSliderPWM(this)" id="slider2" min="0" max="100" step="1" value ="0" class="slider">
</p>
<p class="state">Brightness: <span id="sliderValue2"></span> %</p>
</div>
<div class="card">
<p class="card-title"> Fader 3</p>
<p class="switch">
<input type="range" onchange="updateSliderPWM(this)" id="slider3" min="0" max="100" step="1" value ="0" class="slider">
</p>
<p class="state">Brightness: <span id="sliderValue3"></span> %</p>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
HTML 파일에서 가장 관련성이 높은 부분을 간단히 살펴보겠습니다.
슬라이더 만들기
다음 태그는 첫 번째 슬라이더(페이더 1)에 대한 카드를 생성합니다.
<div class="card">
<p class="card-title">Fader 1</p>
<p class="switch">
<input type="range" onchange="updateSliderPWM(this)" id="slider1" min="0" max="100" step="1" value ="0" class="slider">
</p>
<p class="state">Brightness: <span id="sliderValue1"></span> %</p>
</div>
첫 번째 단락에는 카드의 제목이 표시됩니다(Fader 1). 텍스트를 원하는 대로 변경할 수 있습니다.
<p class="card-title">Fader 1</p>
HTML에서 슬라이더를 만들려면 Input 태그를 사용합니다. input 태그는 사용자가 데이터를 입력할 수 있는 필드를 지정합니다.
다양한 입력 유형이 있습니다. 슬라이더를 정의하려면 범위 값과 함께 type 속성을 사용합니다. 슬라이더에서는 min 및 max 속성(이 경우 각각 0과 100)을 사용하여 최소 및 최대 범위를 정의해야 합니다.
다음과 같은 다른 속성도 정의해야 합니다.
- step 속성은 유효한 숫자 사이의 간격을 지정합니다. 우리의 경우 1로 설정합니다.
- 슬라이더에 스타일을 지정하는 클래스(class="slider")
- JavaScript를 사용하여 슬라이더 값을 조작할 수 있도록 하는 id(id="slider1")
- 슬라이더의 새 위치를 설정할 때 함수를 호출하는 onchange 속성(updateSliderPWM(this)). 이 함수(JavaScript 파일에 정의됨)는 WebSocket 프로토콜을 통해 현재 슬라이더 값을 클라이언트로 전송합니다. this 키워드는 HTML 슬라이더 요소를 참조합니다.
슬라이더는 switch 클래스 이름이 있는 문단 안에 있습니다. 따라서 실제로 슬라이더를 만드는 태그는 다음과 같습니다.
<p class="switch">
<input type="range" onchange="updateSliderPWM(this)" id="slider1" min="0" max="100" step="1" value ="0" class="slider">
</p>
마지막으로, 태그가 있는 문단이 있는데, 이를 통해 해당 문단에 현재 슬라이더 값을 삽입할 수 있습니다. 이를 위해 해당 문단의 id(id="sliderValue1")를 참조합니다.
<p class="state">Brightness: <span id="sliderValue1"></span> %</p>
더 많은 슬라이더 만들기
더 많은 슬라이더를 만들려면 전체 카드를 만드는 모든 HTML 태그를 복사해야 합니다. 그러나 먼저 각 슬라이더와 슬라이더 값에 대해 고유한 id가 필요하다는 점을 고려해야 합니다. 우리의 경우, 다음 id를 가진 세 개의 슬라이더가 있습니다: slider1, slider2, slider3, 그리고 다음 id를 가진 슬라이더 값에 대한 세 개의 플레이스홀더: sliderValue1, sliderValue2, sliderValue3.
예를 들어, 슬라이더 번호 2에 대한 카드는 다음과 같습니다.
<div class="card">
<p class="card-title"> Fader 2</p>
<p class="switch">
<input type="range" onchange="updateSliderPWM(this)" id="slider2" min="0" max="100" step="1" value ="0" class="slider">
</p>
<p class="state">Brightness: <span id="sliderValue2"></span> %</p>
</div>
CSS 파일
다음을 style.css 파일에 복사합니다.
/* Complete project details: https://randomnerdtutorials.com/esp32-web-server-websocket-sliders/ */
html {
font-family: Arial, Helvetica, sans-serif;
display: inline-block;
text-align: center;
}
h1 {
font-size: 1.8rem;
color: white;
}
p {
font-size: 1.4rem;
}
.topnav {
overflow: hidden;
background-color: #0A1128;
}
body {
margin: 0;
}
.content {
padding: 30px;
}
.card-grid {
max-width: 700px;
margin: 0 auto;
display: grid;
grid-gap: 2rem;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.card {
background-color: white;
box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
}
.card-title {
font-size: 1.2rem;
font-weight: bold;
color: #034078
}
.state {
font-size: 1.2rem;
color:#1282A2;
}
.slider {
-webkit-appearance: none;
margin: 0 auto;
width: 100%;
height: 15px;
border-radius: 10px;
background: #FFD65C;
outline: none;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 30px;
height: 30px;
border-radius: 50%;
background: #034078;
cursor: pointer;
}
.slider::-moz-range-thumb {
width: 30px;
height: 30px;
border-radius: 50% ;
background: #034078;
cursor: pointer;
}
.switch {
padding-left: 5%;
padding-right: 5%;
}
슬라이더를 스타일링하는 관련 CSS 파일 부분을 간단히 살펴보겠습니다. 이 예에서는 appearance 속성에 공급업체 접두사를 사용해야 합니다.
/* Complete project details: https://randomnerdtutorials.com/esp32-web-server-websocket-sliders/ */
html {
font-family: Arial, Helvetica, sans-serif;
display: inline-block;
text-align: center;
}
h1 {
font-size: 1.8rem;
color: white;
}
p {
font-size: 1.4rem;
}
.topnav {
overflow: hidden;
background-color: #0A1128;
}
body {
margin: 0;
}
.content {
padding: 30px;
}
.card-grid {
max-width: 700px;
margin: 0 auto;
display: grid;
grid-gap: 2rem;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.card {
background-color: white;
box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
}
.card-title {
font-size: 1.2rem;
font-weight: bold;
color: #034078
}
.state {
font-size: 1.2rem;
color:#1282A2;
}
.slider {
-webkit-appearance: none;
margin: 0 auto;
width: 100%;
height: 15px;
border-radius: 10px;
background: #FFD65C;
outline: none;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 30px;
height: 30px;
border-radius: 50%;
background: #034078;
cursor: pointer;
}
.slider::-moz-range-thumb {
width: 30px;
height: 30px;
border-radius: 50% ;
background: #034078;
cursor: pointer;
}
.switch {
padding-left: 5%;
padding-right: 5%;
}
Vendor Prefixes 공급업체 접두사
공급업체 접두사를 사용하면 브라우저가 완전히 지원되기 전에 새로운 CSS 기능을 지원할 수 있습니다. 가장 일반적으로 사용되는 브라우저는 다음 접두사를 사용합니다.
- -webkit- Chrome, Safari, newer versions of Opera, almost all iOS browsers,
- -moz- Firefox,
- -o- Old versions of Opera,
- -ms- Microsoft Edge and Internet Explorer.
공급업체 접두사는 일시적입니다. 사용하는 브라우저에서 속성을 완전히 지원하면 필요하지 않습니다. 다음 참조를 사용하여 사용 중인 속성에 접두사가 필요한지 확인할 수 있습니다. shouldiprefix.com
.slider 선택기(슬라이더 자체의 스타일을 지정)를 살펴보겠습니다.
.slider {
-webkit-appearance: none;
margin: 0 auto;
width: 100%;
height: 15px;
border-radius: 10px;
background: #FFD65C;outline: none;
}
-webkit-appearance를 none으로 설정하면 Google Chrome, Safari 및 Android 브라우저에서 슬라이더에 적용된 기본 CSS 스타일이 재정의됩니다.
-webkit-appearance: none;
margin을 0 auto로 설정하면 슬라이더가 부모 컨테이너 내부에 정렬됩니다.
margin: 0 auto;
슬라이더의 너비는 100%로 설정되고 높이는 15px로 설정됩니다. border-radius는 10px로 설정됩니다.
margin: 0 auto;
width: 100%;
height: 15px;
border-radius: 10px;
슬라이더의 배경색을 설정하고 윤곽선을 none으로 설정합니다.
background: #FFD65C;
outline: none;
그런 다음 슬라이더 핸들을 포맷합니다. Chrome, Opera, Safari 및 Edge 웹 브라우저의 경우 -webkit-을 사용하고 Firefox의 경우 -moz-를 사용합니다.
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 30px;
height: 30px;
border-radius: 50%;
background: #034078;
cursor: pointer;
}
.slider::-moz-range-thumb {
width: 30px;
height: 30px;
border-radius: 50% ;
background: #034078;
cursor: pointer;
}
-webkit-appearance 및 appearance 속성을 none으로 설정하여 기본 속성을 재정의합니다.
-webkit-appearance: none;
appearance: none;
핸들러의 특정 너비, 높이 및 border-radius를 설정합니다. 동일한 너비와 높이를 border-radius를 50%로 설정하면 원이 생성됩니다.
width: 30px;
height: 30px;
border-radius: 50%;
그런 다음 배경색을 설정하고 커서를 포인터로 설정합니다.
background: #034078;
cursor: pointer;
슬라이더 속성을 자유롭게 조정하여 다른 모습을 만들어 보세요.
JavaScript 파일
다음을 script.js 파일에 복사합니다.
// Complete project details: https://randomnerdtutorials.com/esp32-web-server-websocket-sliders/
var gateway = `ws://${window.location.hostname}/ws`;
var websocket;
window.addEventListener('load', onload);
function onload(event) {
initWebSocket();
}
function getValues(){
websocket.send("getValues");
}
function initWebSocket() {
console.log('Trying to open a WebSocket connection…');
websocket = new WebSocket(gateway);
websocket.onopen = onOpen;
websocket.onclose = onClose;
websocket.onmessage = onMessage;
}
function onOpen(event) {
console.log('Connection opened');
getValues();
}
function onClose(event) {
console.log('Connection closed');
setTimeout(initWebSocket, 2000);
}
function updateSliderPWM(element) {
var sliderNumber = element.id.charAt(element.id.length-1);
var sliderValue = document.getElementById(element.id).value;
document.getElementById("sliderValue"+sliderNumber).innerHTML = sliderValue;
console.log(sliderValue);
websocket.send(sliderNumber+"s"+sliderValue.toString());
}
function onMessage(event) {
console.log(event.data);
var myObj = JSON.parse(event.data);
var keys = Object.keys(myObj);
for (var i = 0; i < keys.length; i++){
var key = keys[i];
document.getElementById(key).innerHTML = myObj[key];
document.getElementById("slider"+ (i+1).toString()).value = myObj[key];
}
}
이 코드가 수행하는 작업 목록은 다음과 같습니다.
- 서버와의 WebSocket 연결을 초기화합니다.
- 현재 슬라이더 값을 가져오기 위해 서버에 메시지를 보냅니다.
- 응답을 사용하여 웹 페이지의 슬라이더 값을 업데이트합니다.
- WebSocket 프로토콜을 통해 데이터 교환을 처리합니다.
이 JavaScript 코드를 살펴보고 작동 방식을 살펴보겠습니다.
게이트웨이는 WebSocket 인터페이스의 진입점입니다. window.location.hostname은 현재 페이지 주소(웹 서버 IP 주소)를 가져옵니다.
var gateway = ws://${window.location.hostname}/ws;
websocket이라는 새 전역 변수를 만듭니다.
var websocket;
웹 페이지가 로드될 때 onload 함수를 호출하는 이벤트 리스너를 추가합니다.
window.addEventListener('load', onload);
onload() 함수는 initWebSocket() 함수를 호출하여 서버와의 WebSocket 연결을 초기화합니다.
function onload(event) {
initWebSocket();
}
initWebSocket() 함수는 이전에 정의한 게이트웨이에서 WebSocket 연결을 초기화합니다. 또한 WebSocket 연결이 열리거나 닫히거나 메시지를 받을 때를 위한 여러 콜백 함수를 할당합니다.
function initWebSocket() {
console.log('Trying to open a WebSocket connection…');
websocket = new WebSocket(gateway);
websocket.onopen = onOpen;
websocket.onclose = onClose;
websocket.onmessage = onMessage;
}
websocket 연결이 열리면 getValues 함수를 호출합니다.
function onOpen(event) {
console.log('Connection opened');
getValues();
}
getValues() 함수는 모든 슬라이더의 현재 값을 가져오기 위해 getValues라는 메시지를 서버로 보냅니다. 그런 다음 서버 측(ESP32)에서 해당 메시지를 수신하면 어떤 일이 발생하는지 처리해야 합니다.
function getStates(){
websocket.send("getValues");
}
onMessage() 함수에서 웹소켓 프로토콜을 통해 수신된 메시지를 처리합니다.
function onMessage(event) {
console.log(event.data);
var myObj = JSON.parse(event.data);
var keys = Object.keys(myObj);
for (var i = 0; i < keys.length; i++){
var key = keys[i];
document.getElementById(key).innerHTML = myObj[key];
document.getElementById("slider"+ (i+1).toString()).value = myObj[key];
}
}
서버는 JSON 형식으로 상태를 전송합니다. 예:
{
sliderValue1 : 20;
sliderValue2: 50;
sliderValue3: 0;
}
onMessage() 함수는 모든 값을 살펴보고 HTML 페이지의 해당 위치에 배치합니다.
updateSliderPWM() 함수는 슬라이더를 움직일 때 실행됩니다.
function updateSliderPWM(element) {
var sliderNumber = element.id.charAt(element.id.length-1);
var sliderValue = document.getElementById(element.id).value;
document.getElementById("sliderValue"+sliderNumber).innerHTML = sliderValue;
console.log(sliderValue);
websocket.send(sliderNumber+"s"+sliderValue.toString());
}
이 함수는 슬라이더에서 값을 가져와 해당 문단을 올바른 값으로 업데이트합니다. 이 함수는 또한 ESP32가 LED 밝기를 업데이트하도록 서버에 메시지를 보냅니다.
websocket.send(sliderNumber+"s"+sliderValue.toString());
메시지는 다음 형식으로 전송됩니다.
- slidernumbersslidervalue
예를 들어, 슬라이더 번호 3을 위치 40으로 이동하면 다음 메시지가 전송됩니다.
3s40
Arduino Sketch
PlatformIO를 사용하는 경우 다음 코드를 Arduino IDE 또는 main.cpp 파일에 복사합니다.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp32-web-server-websocket-sliders/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "LittleFS.h"
#include <Arduino_JSON.h>
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_SSID";
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Create a WebSocket object
AsyncWebSocket ws("/ws");
// Set LED GPIO
const int ledPin1 = 12;
const int ledPin2 = 13;
const int ledPin3 = 14;
String message = "";
String sliderValue1 = "0";
String sliderValue2 = "0";
String sliderValue3 = "0";
int dutyCycle1;
int dutyCycle2;
int dutyCycle3;
// setting PWM properties
const int freq = 5000;
const int ledChannel1 = 0;
const int ledChannel2 = 1;
const int ledChannel3 = 2;
const int resolution = 8;
//Json Variable to Hold Slider Values
JSONVar sliderValues;
//Get Slider Values
String getSliderValues(){
sliderValues["sliderValue1"] = String(sliderValue1);
sliderValues["sliderValue2"] = String(sliderValue2);
sliderValues["sliderValue3"] = String(sliderValue3);
String jsonString = JSON.stringify(sliderValues);
return jsonString;
}
// Initialize LittleFS
void initFS() {
if (!LittleFS.begin()) {
Serial.println("An error has occurred while mounting LittleFS");
}
else{
Serial.println("LittleFS mounted successfully");
}
}
// Initialize WiFi
void initWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
void notifyClients(String sliderValues) {
ws.textAll(sliderValues);
}
void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
AwsFrameInfo *info = (AwsFrameInfo*)arg;
if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
data[len] = 0;
message = (char*)data;
if (message.indexOf("1s") >= 0) {
sliderValue1 = message.substring(2);
dutyCycle1 = map(sliderValue1.toInt(), 0, 100, 0, 255);
Serial.println(dutyCycle1);
Serial.print(getSliderValues());
notifyClients(getSliderValues());
}
if (message.indexOf("2s") >= 0) {
sliderValue2 = message.substring(2);
dutyCycle2 = map(sliderValue2.toInt(), 0, 100, 0, 255);
Serial.println(dutyCycle2);
Serial.print(getSliderValues());
notifyClients(getSliderValues());
}
if (message.indexOf("3s") >= 0) {
sliderValue3 = message.substring(2);
dutyCycle3 = map(sliderValue3.toInt(), 0, 100, 0, 255);
Serial.println(dutyCycle3);
Serial.print(getSliderValues());
notifyClients(getSliderValues());
}
if (strcmp((char*)data, "getValues") == 0) {
notifyClients(getSliderValues());
}
}
}
void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
switch (type) {
case WS_EVT_CONNECT:
Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
break;
case WS_EVT_DISCONNECT:
Serial.printf("WebSocket client #%u disconnected\n", client->id());
break;
case WS_EVT_DATA:
handleWebSocketMessage(arg, data, len);
break;
case WS_EVT_PONG:
case WS_EVT_ERROR:
break;
}
}
void initWebSocket() {
ws.onEvent(onEvent);
server.addHandler(&ws);
}
void setup() {
Serial.begin(115200);
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
pinMode(ledPin3, OUTPUT);
initFS();
initWiFi();
// Set up LEDC pins
ledcAttachChannel(ledPin1, freq, resolution, ledChannel1);
ledcAttachChannel(ledPin2, freq, resolution, ledChannel2);
ledcAttachChannel(ledPin3, freq, resolution, ledChannel3);
initWebSocket();
// Web Server Root URL
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/index.html", "text/html");
});
server.serveStatic("/", LittleFS, "/");
// Start server
server.begin();
}
void loop() {
ledcWrite(ledPin1, dutyCycle1);
ledcWrite(ledPin2, dutyCycle2);
ledcWrite(ledPin3, dutyCycle3);
ws.cleanupClients();
}
코드 작동 방식
이 프로젝트의 관련 부분을 간단히 살펴보겠습니다. 코드 작동 방식을 더 잘 이해하려면 ESP32를 사용한 WebSocket 프로토콜에 대한 이 튜토리얼과 ESP32를 사용한 PWM에 대한 이 튜토리얼을 따르는 것이 좋습니다.
다음 변수에 네트워크 자격 증명을 삽입하여 ESP32를 로컬 네트워크에 연결합니다.
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
getSliderValues() 함수는 현재 슬라이더 값으로 JSON 문자열을 만듭니다.
String getSliderValues(){
sliderValues["sliderValue1"] = String(sliderValue1);
sliderValues["sliderValue2"] = String(sliderValue2);
sliderValues["sliderValue3"] = String(sliderValue3);
String jsonString = JSON.stringify(sliderValues);
return jsonString;
}
notifyClients() 함수는 모든 클라이언트에 현재 슬라이더 값으로 알립니다. 이 함수를 호출하면 슬라이더에 대한 새 위치를 설정할 때마다 모든 클라이언트의 변경 사항을 알릴 수 있습니다.
void notifyClients(String sliderValues) {
ws.textAll(sliderValues);
}
이름에서 알 수 있듯이 handleWebSocketMessage()는 서버가 WebSocket 프로토콜을 통해 클라이언트로부터 메시지를 수신할 때 발생하는 일을 처리합니다. JavaScript 파일에서 서버가 getValues 메시지 또는 슬라이더 번호와 슬라이더 값이 포함된 메시지를 수신할 수 있음을 확인했습니다.
getValues 메시지를 수신하면 현재 슬라이더 값을 보냅니다.
if (strcmp((char*)data, "getValues") == 0) {
notifyClients(getSliderValues());
}
다른 메시지를 수신하면 메시지에 해당하는 슬라이더를 확인하고 해당 듀티 사이클 값을 업데이트합니다. 마지막으로 모든 클라이언트에게 변경 사항이 발생했음을 알립니다. 슬라이더 1의 예는 다음과 같습니다.
if (message.indexOf("1s") >= 0) {
sliderValue1 = message.substring(2);
dutyCycle1 = map(sliderValue1.toInt(), 0, 100, 0, 255);
Serial.println(dutyCycle1);
Serial.print(getSliderValues());
notifyClients(getSliderValues());
}
loop()에서 PWM 채널의 듀티 사이클을 업데이트하여 LED의 밝기를 조정합니다.
void loop() {
ledcWrite(ledPin1, dutyCycle1);
ledcWrite(ledPin2, dutyCycle2);
ledcWrite(ledPin3, dutyCycle3);
ws.cleanupClients();
}
코드 및 파일 업로드
네트워크 자격 증명을 삽입한 후 코드를 저장합니다. 스케치 > 스케치 폴더 표시로 이동하여 data라는 폴더를 만듭니다.
Arduino IDE 스케치 폴더를 열어 data 폴더를 만듭니다.
해당 폴더 안에 HTML, CSS 및 JavaScript 파일을 저장해야 합니다.
그런 다음 코드를 ESP32 보드에 업로드합니다. 올바른 보드와 COM 포트를 선택했는지 확인합니다. 또한 네트워크 자격 증명을 추가했는지 확인합니다.
Arduino IDE 2 업로드 버튼
코드를 업로드한 후 파일을 파일 시스템에 업로드해야 합니다.
Windows에서는 [Ctrl] + [Shift] + [P]를 누르고 MacOS에서는 [⌘] + [Shift] + [P]를 눌러 명령 팔레트를 엽니다. Upload LittleFS to Pico/ESP8266/ESP32 명령을 검색하여 클릭합니다.
이 옵션이 없는 경우 파일 시스템 업로더 플러그인을 설치하지 않았기 때문입니다. 이 튜토리얼을 확인하세요.
ESP32 스케치 데이터 업로드 LittleFS Arduino IDE
중요: 파일 시스템에 업로드하기 전에 직렬 모니터가 닫혔는지 확인하세요. 그렇지 않으면 업로드가 실패합니다.
모든 것이 성공적으로 업로드되면 115200의 전송 속도로 직렬 모니터를 엽니다. ESP32 EN/RST 버튼을 누르면 ESP32 IP 주소가 인쇄됩니다.
데모
로컬 네트워크에서 브라우저를 열고 ESP32 IP 주소를 붙여넣습니다. LED의 밝기를 제어하기 위해 웹 서버 페이지에 액세스할 수 있습니다.
ESP32 웹 서버 데모 WebSocket 여러 슬라이더가 LED 밝기 PWM 제어
슬라이더를 이동하여 LED의 밝기를 제어합니다.
ESP32 여러 슬라이더 웹 서버 Webscocket Arduino
여러 탭을 열거나 다른 장치를 사용하여 웹 서버에 연결하면 슬라이더 값이 변경될 때마다 거의 즉시 업데이트되는 것을 알 수 있습니다.
비디오 데모를 볼 수 있습니다.
마무리
이 튜토리얼에서는 ESP32로 여러 슬라이더가 있는 웹 페이지를 제공하는 웹 서버를 만드는 방법을 배웠습니다. 슬라이더를 사용하면 ESP32에 연결된 LED의 밝기를 제어할 수 있습니다. 또한 WebSocket 프로토콜을 사용하여 ESP32와 클라이언트 간에 통신했습니다.
이 튜토리얼에서 많은 것을 배웠기를 바랍니다. 이 튜토리얼을 성공적으로 따라하고 프로젝트를 작동시켰는지 아래의 댓글에서 알려주세요.
ESP32로 웹 서버를 구축하는 방법에 대해 자세히 알아보려면 전자책을 살펴보는 것이 좋습니다.
ESP32 및 ESP8266으로 웹 서버 구축 전자책
다음 리소스를 통해 ESP32에 대해 자세히 알아보세요.
Arduino IDE로 ESP32 배우기(전자책 + 비디오 과정)
추가 ESP32 튜토리얼 및 프로젝트…
읽어주셔서 감사합니다. 배움을 멈추지 마세요. 또한 절대 포기하지 마세요.
'ESP32' 카테고리의 다른 글
ESP32 의 참조 링크 (2) | 2025.01.17 |
---|---|
ESP32 아두이노 IDE 에서 사용하기 (0) | 2025.01.17 |
Relay Web Server (1) | 2025.01.17 |
PWM32 비동기 웹 서버 ESPAsyncWebServer 라이브러리 (1) | 2025.01.17 |
ESP32 슬라이더가 있는 웹 서버: LED 밝기 제어(PWM) (0) | 2025.01.15 |
ESP32 이벤트 사용 Web Server(센서값 자동 업데이트) (0) | 2025.01.14 |
HTTP POST Web APIs, ThingSpeak 및 IFTTT.com (0) | 2025.01.14 |
ESP32 Bluetooth Classic과 Arduino IDE (1) | 2025.01.14 |
더욱 좋은 정보를 제공하겠습니다.~ ^^