자바스크립트를 사용하도록 작성된 웹페이지를 사용하여 아두이노에 연결된 LED를 제어하는 테스트를 진행해봤습니다.
2024. 12. 26 최초작성
1. 다음 포스트대로 진행하여 아두이노에서 와이파이 모듈을 사용하는 코드를 업로드하고 테스트를 해둡니다.
Arduino UNO에서 ESP8266 WiFi 모듈을 사용하는 방법
https://webnautes.tistory.com/2071
2. 다음 포스트대로 진행하여 윈도우상에서 자바스크립트 개발 환경을 구축합니다.
Visual Studio Code 사용하는 JavaScript 개발 환경 만들기
https://webnautes.tistory.com/2123
3. Visual Studio Code에서 새로운 폴더를 생성하고 다음 2개의 파일을 생성합니다.
index.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>LED 제어</title> <style> body { font-family: 'Malgun Gothic', '맑은 고딕', sans-serif; max-width: 800px; margin: 20px auto; padding: 0 20px; } .button-container { margin: 20px 0; } button { padding: 10px 20px; margin-right: 10px; border: none; border-radius: 5px; cursor: pointer; font-weight: bold; font-family: 'Malgun Gothic', '맑은 고딕', sans-serif; } #ledOn { background-color: #4CAF50; color: white; } #ledOff { background-color: #f44336; color: white; } #ledStatus { background-color: #2196F3; color: white; } #messageLog { height: 300px; border: 1px solid #ccc; padding: 10px; overflow-y: auto; background-color: #f9f9f9; font-family: 'Malgun Gothic', '맑은 고딕', sans-serif; } .status { margin-bottom: 10px; padding: 10px; background-color: #e7e7e7; border-radius: 5px; } </style> </head> <body> <h1>LED 제어 인터페이스</h1> <div class="status" id="connectionStatus">연결 상태: 연결 중...</div> <div class="button-container"> <button id="ledOn">LED 켜기</button> <button id="ledOff">LED 끄기</button> <button id="ledStatus">LED 상태</button> </div> <div id="messageLog"></div> <script> const ws = new WebSocket('ws://localhost:3000'); const messageLog = document.getElementById('messageLog'); const connectionStatus = document.getElementById('connectionStatus'); function addMessage(message) { const div = document.createElement('div'); div.textContent = `${new Date().toLocaleTimeString()} - ${message}`; messageLog.appendChild(div); messageLog.scrollTop = messageLog.scrollHeight; } ws.onopen = () => { connectionStatus.textContent = '연결 상태: 연결됨'; connectionStatus.style.backgroundColor = '#4CAF50'; connectionStatus.style.color = 'white'; addMessage('서버에 연결되었습니다.'); }; ws.onclose = () => { connectionStatus.textContent = '연결 상태: 연결 끊김'; connectionStatus.style.backgroundColor = '#f44336'; connectionStatus.style.color = 'white'; addMessage('서버와의 연결이 종료되었습니다.'); }; ws.onmessage = (event) => { addMessage(`수신: ${event.data}`); }; document.getElementById('ledOn').onclick = () => { ws.send('1'); addMessage('송신: LED 켜기 (1)'); }; document.getElementById('ledOff').onclick = () => { ws.send('2'); addMessage('송신: LED 끄기 (2)'); }; document.getElementById('ledStatus').onclick = () => { ws.send('s'); addMessage('송신: LED 상태 확인 (s)'); }; </script> </body> </html> |
server.js
아두이노에서 포트번호 23을 다른 것으로 바꾸었다면 여기에서도 변경해야 합니다.
// server.js // # 필요한 패키지 설치 // npm init -y // npm install ws // # server.js와 index.html 파일을 같은 디렉토리에 저장 // # 서버 실행 // node server.js // server.js const WebSocket = require('ws'); const net = require('net'); const http = require('http'); const fs = require('fs'); const path = require('path'); let webSocketClients = new Set(); let currentTcpSocket = null; let lastArduinoMessage = null; // 마지막으로 받은 메시지 저장 // TCP 서버 설정 const tcpServer = net.createServer((socket) => { console.log('TCP 클라이언트(아두이노) 연결됨'); currentTcpSocket = socket; socket.setKeepAlive(true, 1000); socket.setNoDelay(true); socket.setTimeout(0); socket.on('data', (data) => { try { const message = data.toString().trim(); console.log('아두이노로부터 수신:', message); lastArduinoMessage = message; // 메시지 저장 // 연결된 모든 웹소켓 클라이언트에게 전송 webSocketClients.forEach((client) => { if (client.readyState === WebSocket.OPEN) { client.send(message); } }); } catch (err) { console.log('데이터 처리 중 에러:', err); } }); socket.on('close', (hadError) => { console.log('아두이노 연결 종료' + (hadError ? ' (에러 발생)' : '')); if (currentTcpSocket === socket) { currentTcpSocket = null; } webSocketClients.forEach((client) => { if (client.readyState === WebSocket.OPEN) { client.send('아두이노 연결이 종료되었습니다.'); } }); }); socket.on('error', (err) => { if (err.code === 'ECONNRESET') { console.log('아두이노와의 연결이 재설정되었습니다.'); } else { console.log('TCP 소켓 에러:', err.message); } if (currentTcpSocket === socket) { currentTcpSocket = null; } }); webSocketClients.forEach((client) => { client.tcpSocket = socket; if (client.readyState === WebSocket.OPEN) { client.send('아두이노가 연결되었습니다.'); } }); }); // HTTP 서버 설정 const server = http.createServer((req, res) => { if (req.url === '/') { fs.readFile(path.join(__dirname, 'index.html'), (err, data) => { if (err) { res.writeHead(500); return res.end('Error loading index.html'); } res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(data); }); } }); // WebSocket 서버 설정 const wss = new WebSocket.Server({ server }); wss.on('connection', (ws) => { console.log('웹소켓 클라이언트 연결됨'); webSocketClients.add(ws); // 현재 아두이노 연결 상태와 마지막 메시지 전송 if (currentTcpSocket) { ws.send('아두이노가 연결되어 있습니다.'); ws.tcpSocket = currentTcpSocket; if (lastArduinoMessage) { ws.send(lastArduinoMessage); // 마지막 메시지 전송 } } else { ws.send('아두이노가 연결되어 있지 않습니다.'); } ws.on('message', (message) => { try { const command = message.toString().trim(); console.log('웹소켓으로부터 수신:', command); if (currentTcpSocket && currentTcpSocket.writable) { currentTcpSocket.write(command + '\n'); } else { ws.send('아두이노가 연결되어 있지 않아 명령을 전송할 수 없습니다.'); } } catch (err) { console.log('메시지 전송 중 에러:', err); ws.send('메시지 전송 중 에러가 발생했습니다.'); } }); ws.on('close', () => { console.log('웹소켓 클라이언트 연결 종료'); webSocketClients.delete(ws); }); ws.on('error', (err) => { console.log('웹소켓 에러:', err); webSocketClients.delete(ws); }); }); // TCP 서버 시작 (23번 포트) tcpServer.listen(23, '0.0.0.0', () => { console.log('TCP 서버가 모든 인터페이스의 23번 포트에서 대기 중입니다'); console.log('서버 IP 주소들:'); const { networkInterfaces } = require('os'); const nets = networkInterfaces(); for (const name of Object.keys(nets)) { for (const net of nets[name]) { if (net.family === 'IPv4' && !net.internal) { console.log(` - ${name}: ${net.address}`); } } } }); // HTTP/WebSocket 서버 시작 const PORT = 3000; server.listen(PORT, () => { console.log(`웹 서버가 http://localhost:${PORT} 에서 실행 중입니다`); }); // 프로세스 종료 시 정리 process.on('SIGINT', () => { console.log('서버를 종료합니다...'); if (currentTcpSocket) { currentTcpSocket.end(); } wss.clients.forEach((client) => { client.close(); }); tcpServer.close(() => { server.close(() => { process.exit(0); }); }); }); |
4. Visual Studio Code의 터미널에서 다음 명령을 차례로 실행합니다. 처음 2줄은 초기화와 필요한 모듈 설치라 최초 실행시에만 하면 됩니다. 3번째 줄 명령을 사용하여 자바스크립트 코드를 실행합니다.
npm init -y
npm install ws
node server.js
다음처럼 대기상태가 됩니다. Ctrl 누른채 마우스로 http://localhost:3000 부분을 클릭합니다.
6. 웹브라우저에 다음과 같은 화면이 보입니다.
7. 아두이노 IDE의 메뉴에서 툴 > 시리얼 모니터를 선택하고 잠시 기다리면 다음처럼 보입니다.
8. Visual Studio Code의 터미널창에서 아두이노에서 수신된 메시지가 보입니다.
9. 앞에서 열어놓았던 웹페이지를 보면 다음처럼 아두이노와 연결되었고 수신받은 메시지가 보입니다.
10. LED 켜기, LED 끄기, LED 상태 버튼을 클릭하면 아두이노의 LED가 제어되고 상태도 알 수 있습니다.
아래 창에 결과가 보입니다.
'Arduino Uno > WIFI(ESP8266)' 카테고리의 다른 글
Arduino UNO에서 ESP8266 WiFi 모듈을 사용하는 방법 (0) | 2024.12.25 |
---|---|
Android 앱에서 ESP8266 WiFi 모듈을 연결한 Arduino Uno 제어하기 (0) | 2023.10.18 |
Arduino Uno에서 ESP8266을 이용하여 MYSQL에 온도값(DB18B20) 넣기 (252) | 2018.10.17 |