Node-RED 실습 A: 가상 센서(온도/진동/전류) 데이터 만들기 (Inject→Function→Debug)
한눈에 보는 요약
이 실습의 목표는 Node-RED 코어 노드만으로 “1초마다 온도값을 생성”하고, 현실적인 센서 특성(노이즈, 추세 변화, 간헐적 이상치)을 포함한 메시지를 만드는 것입니다.
핵심은 Function 노드에서 상태를 저장/갱신(flow.get/set)하여 랜덤워크(서서히 변하는 추세)를 구현하고, 작은 노이즈와 낮은 확률의 스파이크를 추가해 데이터 품질을 현실에 가깝게 만드는 데 있습니다.
또한 msg.payload를 JSON 형태로 표준화하면, 이후 진동/전류 센서 확장, 저장/시각화/알림 연동, 다중 센서 관리에 유리합니다.
목차
- 1. 실습 목표와 구성 노드
- 2. 랜덤워크·노이즈·스파이크 모델링 이해
- 3. Function 노드 코드 구현(상태 저장 포함)
- 4. msg.payload 설계: 숫자 vs JSON
- 5. 파라미터 튜닝 가이드(추천 범위 표)
- 6. 따라하기: Inject→Function→Debug 구성 절차
- 7. 자주 겪는 문제와 해결 팁
핵심 포인트
- Inject 노드의 repeat(1초)로 일정 주기 이벤트를 만들고, Function 노드에서 센서 값을 생성합니다.
- 랜덤워크는 “이전 값 + 작은 변화” 형태로 추세를 만들며, flow 컨텍스트에 값을 저장해야 자연스럽게 이어집니다.
- 노이즈는 미세한 흔들림을, 스파이크는 간헐적 이상치(갑작스런 튐)를 모사합니다(확률 기반).
- msg.payload를 JSON으로 표준화하면 타임스탬프/센서ID/다중 채널(진동, 전류) 확장이 쉬워집니다.
- 범위 제한(클램프)은 데이터가 비현실적으로 폭주하는 것을 막는 안전장치입니다.
상세 설명
1. 실습 목표와 구성 노드
실습 A는 “가상 센서(온도/진동/전류) 데이터”를 생성하는 가장 기본적인 패턴을 다룹니다. 실제 센서를 붙이기 전, 대시보드/저장소/알림 로직이 정상 동작하는지 검증하기 위해 가상 데이터를 많이 사용합니다.
구성은 매우 단순합니다. Inject(repeat: 1 second) → Function(센서 생성) → Debug의 3개 노드만으로 코어 기능을 구현합니다.
inject 노드를 드래그해서 플로우에 가져가면 timestamp로 이름이 변경됩니다.2. 랜덤워크·노이즈·스파이크 모델링 이해
현실의 센서 데이터는 단순히 “랜덤 숫자”가 아니라, 보통 다음 3가지 특징을 동시에 가집니다.
- 추세(랜덤워크): 온도가 서서히 오르거나 내리는 것처럼 이전 값에서 조금씩 이동합니다.
- 미세 노이즈: 측정 오차나 환경 변화로 인해 작은 폭으로 흔들립니다.
- 간헐적 이상치(스파이크): 순간적인 전기적 노이즈/충격/통신 오류 등으로 값이 갑자기 튀는 현상이 드물게 발생합니다.
이 실습에서는 랜덤워크와 노이즈를 매 주기마다 누적하고, 2% 확률로 스파이크를 추가해 “정상 데이터 속에 섞인 이상치” 시나리오를 만듭니다.
3. Function 노드 코드 구현(상태 저장 포함)
아래 코드는 “가상 온도 센서: 랜덤워크 + 노이즈 + 스파이크”를 구현한 예시입니다. 핵심은 flow.get("temp")로 이전 값을 가져오고, 계산 후 flow.set("temp", t)로 다시 저장하는 구조입니다.
// 가상 온도 센서: 랜덤워크 + 노이즈 + 스파이크
let t = flow.get("temp") ?? 23.0;
// 랜덤워크(서서히 변함)
t += (Math.random() - 0.5) * 0.2; // -0.1 ~ +0.1
// 미세 노이즈
t += (Math.random() - 0.5) * 0.05; // -0.025 ~ +0.025
// 2% 확률로 스파이크(이상치)
if (Math.random() < 0.02) {
t += (Math.random() < 0.5 ? -1 : 1) * (2 + Math.random() * 3); // ±(2~5)
}
// 범위 제한
t = Math.max(10, Math.min(45, t));
flow.set("temp", t);
// 출력
msg.payload = {
ts: Date.now(),
temp: Number(t.toFixed(2)),
sensor: "TEMP_001"
};
return msg;
운영 관점에서 중요한 포인트는 3가지입니다. 첫째, 랜덤워크와 노이즈는 매번 누적되므로 장시간 실행 시 값이 경계 밖으로 튈 수 있어 범위 제한이 필요합니다. 둘째, 스파이크 확률(예: 0.02)은 테스트 목적에 따라 조절해야 하며 너무 높으면 “정상 패턴”을 보기 어렵습니다. 셋째, payload를 JSON으로 표준화하면 후속 단계(저장, 알림, 이상탐지)에서 파싱/필터링이 쉬워집니다.
function 1 노드를 더블클릭하면 Edit function node 창이 열립니다.4. msg.payload 설계: 숫자 vs JSON
msg.payload는 “숫자 하나”로도 동작합니다. 예를 들어 msg.payload = Number(t.toFixed(2));처럼 만들면 Debug에서 간단히 확인하기 좋습니다.
다만 실무에서는 JSON 형태가 유리합니다. 이유는 다음과 같습니다.
- 타임스탬프(ts) 포함으로 저장 시계열 데이터 정합성이 좋아집니다.
- sensor ID로 다중 센서(예: TEMP_001, VIB_001, CUR_001)를 구분할 수 있습니다.
- 추후 진동(vib), 전류(cur) 등을 한 메시지에 추가하거나, 센서별 토픽 분기에도 유리합니다.
파라미터 튜닝 가이드(추천 범위 표)
아래 표는 실습에서 주로 조절하는 파라미터와 추천 범위를 정리한 것입니다. 목적(정상 시각화, 이상치 테스트, 알림 검증)에 따라 값을 바꾸어 보시면 학습 효과가 큽니다.
| 항목 | 코드 위치/의미 | 추천 범위 | 값을 키우면 | 값을 줄이면 |
|---|---|---|---|---|
| 랜덤워크 폭 | (Math.random()-0.5)*0.2 | 0.1 ~ 0.6 | 추세 변화가 빨라짐 | 완만한 드리프트 |
| 노이즈 폭 | (Math.random()-0.5)*0.05 | 0.02 ~ 0.2 | 잔떨림이 커짐 | 곡선이 매끈해짐 |
| 스파이크 확률 | Math.random() < 0.02 | 0.005 ~ 0.05 | 이상치가 자주 발생 | 이상치가 드묾 |
| 스파이크 크기 | ±(2~5) | ±(1~10) | 알림/탐지 테스트에 유리 | 미세 이상치 테스트 |
| 값 범위 제한 | 10 ~ 45 클램프 | 센서 사양 기반 | 현실적 범위 유지 | 폭주 가능(비권장) |
따라하기
자주 겪는 문제와 해결 팁
값이 매번 23 근처로 “초기화”되는 것처럼 보입니다.
flow 컨텍스트가 유지되지 않는 경우(예: 노드/플로우 재배포, 컨텍스트 설정 문제)일 수 있습니다. 먼저 배포 후 일정 시간 연속으로 값이 이어지는지 확인하고, Function 노드가 실제로 flow.set을 수행하는지 Debug로 점검합니다.
스파이크가 너무 자주(또는 너무 드물게) 나옵니다.
Math.random() < 0.02의 값을 조정해 확률을 변경하십시오. 알림 검증이 목적이면 0.03~0.05로 높여 빠르게 재현하고, 정상 추세 시각화가 목적이면 0.005~0.01로 낮추는 편이 좋습니다.
데이터가 상한/하한에 붙어서 움직입니다.
랜덤워크 폭이 너무 크거나 범위 제한이 너무 좁을 때 발생합니다. 랜덤워크 계수를 낮추거나(예: 0.2→0.1), 범위를 센서 사양에 맞게 조금 넓히는 방법이 있습니다.
추가로 생각해볼 점
이상치(스파이크)를 “단발”이 아니라 “연속(예: 5초간 과열)” 형태로 모델링하면 경보 로직(지속 시간 조건) 테스트에 더 유리합니다.
센서가 여러 개일 때는 sensor ID뿐 아니라 “라인/설비/위치” 메타데이터를 payload에 넣어두면 운영 단계에서 필터링과 집계가 쉬워집니다.
Debug 확인이 끝나면, 다음 단계로는 차트(대시보드) 시각화, DB 적재, 임계치 알림(이메일/슬랙/웹훅) 순서로 확장하는 것을 권장합니다.





0 댓글