안녕하세요! 실시간 데이터 시각화와 함께 IoT 대시보드를 만드는 튜토리얼에 오신 것을 환영합니다! 이 튜토리얼에서는 HTML5, CSS3, Bootstrap 4 및 JavaScript를 사용하여 실시간 온도 값을 표시하는 동적 대시보드를 만들어보겠습니다. 노드.js를 사용하여 센서 데이터를 모방하고 라이브 환경을 시뮬레이션할 것입니다. 프로젝트에 IoT를 통합하고자 하는 개발자이거나 실시간 데이터 시각화에 대해 궁금한 분들을 위해 이 튜토리얼이 한 단계씩 가이드해 드릴 것입니다. 완료하면 새로운 데이터가 들어올 때마다 업데이트되는 완전히 기능적인 온도 차트를 갖게 될 것입니다. 이제 시작하여 여러분의 IoT 프로젝트를 현실로 만들어봅시다!
뒤에 나온 Markdown 표식을 이해하고 계시나요?
Backend code to mock sensor data
한 줄 씩 코드를 이해해 볼까요?
- WebSocket 모듈을 가져오기
const WebSocket = require('ws');
이 코드는 ws 모듈을 가져오는 역할을 합니다. ws는 Node.js용 인기 있는 WebSocket 라이브러리입니다. WebSocket을 사용하면 서버와 클라이언트 간에 실시간 양방향 통신이 가능하며 단일, 오래 지속되는 연결을 통해 이루어집니다.
- WebSocket 서버 만들기
const server = new WebSocket.Server({ port: 8080 });
여기서는 포트 8080에서 수신 대기하는 새로운 WebSocket 서버 인스턴스가 생성됩니다. 이 서버는 클라이언트로부터 들어오는 WebSocket 연결을 수락할 것입니다.
- 클라이언트 연결 처리하기
server.on('connection', (socket) => {
console.log('Client connected');
이 부분은 웹소켓 서버에 클라이언트가 연결될 때 트리거되는 connection 이벤트를 위한 이벤트 리스너를 설정합니다. 연결이 성립되면 서버는 "Client connected"를 콘솔에 로깅합니다.
- 실시간 온도 데이터 전송
const sendTemperatureData = () => {
const temperature = (Math.random() * 10 + 20).toFixed(2); // 20에서 30 사이의 더미 온도
const timeStamp = (new Date()).getTime();
const data = JSON.stringify({ temperature, timeStamp });
- 이 함수인 sendTemperatureData는 연결된 클라이언트에 온도 데이터를 생성하고 전송하는 역할을 합니다.
- Math.random()을 사용하여 20도부터 30도 사이의 임의의 온도가 생성되며, .toFixed(2)를 사용하여 결과가 소수점 둘째 자리까지 포맷됩니다.
- 현재 시간을 밀리초로 나타내는 new Date().getTime()을 사용하여 타임스탬프가 생성됩니다 (Unix epoch인 1970년 1월 1일부터의 시간).
- 그런 다음 온도와 타임스탬프는 JSON.stringify를 사용하여 JSON 문자열로 패키징됩니다.
socket.send(data);
온도와 타임스탬프가 포함된 JSON 문자열은 socket.send를 사용하여 클라이언트로 전송됩니다.
setTimeout(sendTemperatureData, 2000);
};
setTimeout
은 실시간 데이터 스트림을 시뮬레이션하기 위해 sendTemperatureData 함수를 매 2초마다 호출하는 데 사용됩니다.
- 초기 데이터 전송
sendTemperatureData();
이 줄은 클라이언트가 연결된 후 즉시 sendTemperatureData를 처음 호출합니다. setTimeout 루프로 인해 이 함수는 매 2초마다 계속 호출됩니다.
- 클라이언트 연결 해제 처리
socket.on('close', () => {
console.log('클라이언트가 연결을 해제했습니다');
});
close 이벤트를 처리하기 위한 이벤트 리스너가 설정되어 있습니다. 이 이벤트는 클라이언트가 웹소켓 서버와의 연결을 해제할 때 발생합니다. 이때 콘솔에 "클라이언트가 연결을 해제했습니다"가 로그로 출력됩니다.
- 웹소켓 서버 시작
console.log('웹소켓 서버가 ws://localhost:8080 주소에서 실행 중입니다.');
마지막으로, 이 라인은 웹소켓 서버가 작동 중이며 클라이언트가 연결할 수 있는 URL(ws://localhost:8080)을 특정하는 메시지를 기록합니다.
이 코드는 간단한 웹소켓 서버를 설정하여, 매 2초마다 연결된 클라이언트에게 랜덤 온도 데이터와 타임스탬프를 스트리밍합니다. 또한 연결 및 연결 해제 이벤트를 로깅합니다.
실시간 데이터 시각화를 위한 프론트엔드 코드입니다.
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IoT 대시보드</title>
<!-- Highcharts 라이브러리 포함 -->
<script src="https://code.highcharts.com/highcharts.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"></script>
<script src="script.js" defer></script>
</head>
<body>
<nav class="navbar navbar-expand-sm bg-dark navbar-dark">
<ul class="navbar-nav">
<li class="nav-item active">
<a class="nav-link" href="#">IoT 대시보드</a>
</li>
</ul>
</nav>
<div class="row mt-4 p-4">
<div class="col">
<div id="accordion">
<div class="card rounded-0">
<div class="card-header bg-info card rounded-0">
<a class="card-link text-white" data-toggle="collapse" href="#collapseOne">
센서 1의 온도
</a>
</div>
<div id="collapseOne" class="collapse show" data-parent="#accordion">
<div class="card-body">
<div id="temperatureChart"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
</script>
</body>
</html>
// script.js
// Highcharts 차트 초기화
const chart = Highcharts.chart('temperatureChart', {
chart: {
type: 'line',
events: {
load: function() {
this.series[0].setData([]);
}
}
},
title: {
text: ''
},
xAxis: {
type: 'datetime'
},
yAxis: {
title: {
text: '온도 (°C)'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
series: [{
name: '온도',
data: []
}]
});
// 로컬 WebSocket 서버에 연결
const socket = new WebSocket('ws://localhost:8080');
socket.onopen = function(event) {
console.log('WebSocket 서버에 연결되었습니다');
};
socket.onmessage = function(event) {
const sensorData = JSON.parse(event.data);
const series = chart.series[0];
const x = sensorData.timeStamp;
const y = parseFloat(sensorData.temperature);
series.addPoint([x, y]);
};
socket.onerror = function(error) {
console.error('WebSocket 오류 발생:', error);
};
socket.onclose = function(event) {
console.log('WebSocket 연결이 닫혔습니다');
};
- Highcharts 차트 초기화하기
const chart = Highcharts.chart('temperatureChart', {
chart: {
type: 'line',
events: {
load: function() {
this.series[0].setData([]);
}
}
},
title: {
text: ''
},
xAxis: {
type: 'datetime'
},
yAxis: {
title: {
text: 'Temperature (°C)'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
series: [{
name: 'Temperature',
data: []
}]
});
- const chart = Highcharts.chart(
temperatureChart
, ' ... '): 이 줄은 새로운 Highcharts 차트를 초기화하고 그것을 chart 변수에 할당합니다. 차트는 temperatureChart라는 ID를 가진 HTML 요소에 렌더링됩니다. - chart: ' type:
line
': 차트 유형을 선 그래프로 지정하며, 시간에 따른 지속적인 데이터를 표시하는 데 적합합니다. (ex: 온도 측정값) - events: ' load: function() ' ... ' ': 로드 이벤트에 대한 이벤트 리스너를 정의하고, 차트가 완전히 로드되면 트리거됩니다. 해당 코드는 이 경우 첫 번째 시리즈의 초기 데이터를 지우도록 설정되어 있습니다: this.series[0].setData([]);.
- title: ' text: `` ': 여기서 차트 제목을 정의하는 부분이지만, 이 예시에서는 비워두었습니다.
- xAxis: ' type:
datetime
': x-축이 시간 기반 데이터를 표시하도록 구성되어 있어, 시간에 따른 온도 측정값을 그래프로 표시할 때 중요합니다. - yAxis: ' title: ' text:
Temperature (°C)
', plotLines: [' value: 0, width: 1, color:#808080
'] ': - y-축은 "Temperature (°C)"로 레이블이 지정됩니다.
- 너비가 1픽셀이고 회색(#808080)인 y = 0에 플롯 라인이 추가됩니다. 일반적으로 중요한 값이나 임계값을 나타내는 데 사용되지만, 여기에서는 기준선으로만 사용됩니다.
- series: [' name:
Temperature
, data: [] ']: 차트의 데이터 시리즈를 정의합니다. 시리즈는 "Temperature"로 이름이 지정되며 빈 데이터 배열로 시작됩니다. 데이터가 수신되면 이 시리즈에 추가될 것입니다.
- WebSocket 서버에 연결하기
const socket = new WebSocket('ws://localhost:8080');
이 코드는 ws://localhost:8080으로 로컬에서 실행 중인 서버에 WebSocket 연결을 설정합니다. 이 연결을 통해 서버에서 클라이언트로 실시간 데이터를 스트리밍할 수 있습니다.
- WebSocket 이벤트 처리
연결이 열리면
socket.onopen = function(event) {
console.log('웹소켓 서버에 연결되었습니다');
};
socket.onopen: 이 이벤트 핸들러는 WebSocket 연결이 성공적으로 열릴 때 트리거됩니다. 콘솔에 "웹소켓 서버에 연결되었습니다"를 기록합니다.
메시지 수신
socket.onmessage = function(event) {
const sensorData = JSON.parse(event.data);
const series = chart.series[0];
const x = sensorData.timeStamp;
const y = parseFloat(sensorData.temperature);
series.addPoint([x, y]);
};
socket.onmessage: 이벤트 핸들러는 WebSocket 서버로부터 메시지를 수신했을 때 트리거됩니다.
- const sensorData = JSON.parse(event.data);: 수신된 JSON 데이터를 JavaScript 객체(sensorData)로 파싱하여 온도 데이터와 타임스탬프가 포함되어 있습니다.
- const series = chart.series[0];: 차트 내 첫 번째(유일한) 데이터 시리즈를 참조합니다.
- const x = sensorData.timeStamp;: 수신된 데이터에서 타임스탬프를 추출하여 x-좌표로 사용합니다.
- const y = parseFloat(sensorData.temperature);: 온도 값을 부동 소수점 숫자로 변환하여 y-좌표로 사용합니다.
- series.addPoint([x, y]);: 새로운 데이터 포인트 [x, y]를 차트에 추가하여 실시간으로 라인 그래프를 업데이트합니다.
오류 처리
socket.onerror = function(error) {
console.error('WebSocket error:', error);
};
socket.onerror: WebSocket 연결 중 오류가 발생하면이 이벤트 핸들러가 트리거됩니다. 오류는 콘솔에 "WebSocket error:" 메시지와 함께 기록됩니다.
연결 닫힘
socket.onclose = function(event) {
console.log('WebSocket connection closed');
};
socket.onclose: WebSocket 연결이 클라이언트 또는 서버에 의해 닫힐 때 트리거되는 이벤트 핸들러입니다. 콘솔에 "WebSocket connection closed"를 기록합니다.
이 코드는 Highcharts와 웹 소켓을 사용하여 실시간 온도 모니터링 시스템을 설정합니다. 차트는 시간이 지남에 따른 온도 데이터를 표시하도록 초기화되며, 웹 소켓 연결이 설정되어 실시간 업데이트를 받습니다. 새로운 온도 측정값이 수신되면 차트에 추가되어 계속해서 업데이트되는 시각화를 제공합니다. 코드에는 기본 오류 처리가 포함되어 있으며 연결 상태를 추적하기 위해 콘솔에 로그 메시지가 기록됩니다.