
현대 농업은 단순히 경험에 의존하는 것을 넘어 데이터 기반의 스마트팜으로 진화하고 있습니다. 아두이노에서 수집된 센서 데이터를 실시간으로 모니터링하고, 웹을 통해 원격으로 시설을 제어하는 시스템을 구축하는 방법을 소개합니다.
시스템 아키텍처 개요
전체 시스템은 하드웨어 제어, 데이터 처리, 사용자 인터페이스의 세 가지 계층으로 나뉩니다. 아두이노가 수집한 환경 정보는 API를 통해 서버로 전달되며, 사용자는 웹 대시보드를 통해 이를 확인하고 명령을 내릴 수 있습니다.
백엔드 구성: NestJS와 Prisma 및 MySQL
NestJS는 확장성 있는 서버 구축을 위해 선택되었습니다. Prisma ORM을 사용하여 MySQL 데이터베이스와 연동하며, 농장의 상태를 효율적으로 관리합니다.
- 데이터베이스 스키마 설계
- Prisma를 사용하여 온습도 기록, 급수 상태, 차폐막 개폐 여부 등을 저장할 테이블을 정의합니다.
model FarmStatus {
id Int @id @default(autoincrement())
temperature Float
humidity Float
waterLevel Float
shutterOpen Boolean @default(false)
createdAt DateTime @default(now())
}
- API 엔드포인트 구현
- 아두이노가 HTTP 요청을 통해 데이터를 전송할 수 있도록 POST 엔드포인트를 생성하고, 웹 프론트엔드에서 실시간 데이터를 조회할 수 있도록 GET 엔드포인트를 마련합니다.
프론트엔드 구현: NuxtJS 대시보드
NuxtJS는 사용자에게 직관적인 모니터링 환경을 제공합니다. SSR(Server Side Rendering) 기능을 활용해 초기 로딩 속도를 높이고, 반응형 UI를 통해 모바일에서도 농장 상태를 확인할 수 있습니다.
- 실시간 데이터 시각화: Chart.js 등을 활용하여 온습도 변화 추이를 그래프로 표시합니다.
- 제어 인터페이스: 토글 스위치나 버튼을 배치하여 급수 펌프 가동이나 차폐막 제어 명령을 서버로 전송합니다.
- CCTV 연동: WebRTC나 스트리밍 서버를 통해 농장 내부의 실시간 영상을 캔버스 요소에 렌더링합니다.
하드웨어 통신: 아두이노와 센서
아두이노는 현장의 물리적 접점 역할을 수행합니다.
- 센서 수집: DHT11(온습도), 토양 수분 센서 등을 연결하여 주기적으로 환경 데이터를 읽어들입니다.
- 액추에이터 제어: 서버로부터 받은 제어 신호에 따라 릴레이 모듈을 작동시켜 펌프나 모터를 구동합니다.
- 통신: ESP8266 또는 Ethernet 쉴드를 사용하여 NestJS 서버와 통신합니다.
주요 모니터링 및 제어 항목
| 항목 | 수집 및 제어 내용 | 활용 목적 |
| 온습도 | 센서 값 수집 | 작물 최적 생장 환경 유지 |
| 급수 | 펌프 On/Off 제어 | 수분 공급 자동화 |
| 차폐 | 모터 정역회전 제어 | 일조량 및 온도 조절 |
| CCTV | 영상 스트리밍 | 보안 및 원격 현장 확인 |
스마트팜 시스템은 구축 후에도 데이터가 쌓임에 따라 머신러닝을 도입하여 자동화 로직을 고도화할 수 있는 잠재력이 큽니다. NestJS의 안정적인 구조와 NuxtJS의 유연한 UI는 이러한 확장성에 최적화된 조합입니다.
아두이노에서 수집한 데이터를 NestJS 서버로 전송하고 이를 데이터베이스에 저장하는 핵심 구현 예시입니다.
아두이노: 데이터 전송 코드 (C++)
아두이노(ESP8266 또는 ESP32 기준)에서 센서 값을 읽어 JSON 형태로 NestJS API에 POST 요청을 보내는 과정입니다.
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const char* serverUrl = "http://your-server-ip:3000/farm/status";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
}
void loop() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin(serverUrl);
http.addHeader("Content-Type", "application/json");
StaticJsonDocument<200> doc;
doc["temperature"] = 25.5; // 센서 읽기 값 대체
doc["humidity"] = 60.2;
doc["waterLevel"] = 80.0;
doc["shutterOpen"] = false;
String requestBody;
serializeJson(doc, requestBody);
int httpResponseCode = http.POST(requestBody);
http.end();
}
delay(60000); // 1분 간격 전송
}
NestJS: 데이터 수신 및 저장 구현
아두이노가 보낸 데이터를 처리하기 위한 DTO 정의와 컨트롤러, 서비스 로직입니다.
- 데이터 전송 객체 (DTO) 정의
export class CreateFarmStatusDto {
temperature: number;
humidity: number;
waterLevel: number;
shutterOpen: boolean;
}
- 컨트롤러 및 서비스 로직
// farm.controller.ts
@Controller('farm')
export class FarmController {
constructor(private readonly farmService: FarmService) {}
@Post('status')
async updateStatus(@Body() createFarmStatusDto: CreateFarmStatusDto) {
return this.farmService.saveStatus(createFarmStatusDto);
}
}
// farm.service.ts
@Injectable()
export class FarmService {
constructor(private prisma: PrismaService) {}
async saveStatus(data: CreateFarmStatusDto) {
return this.prisma.farmStatus.create({
data: {
temperature: data.temperature,
humidity: data.humidity,
waterLevel: data.waterLevel,
shutterOpen: data.shutterOpen,
},
});
}
}
시스템 연동 시 주의사항
서버와 아두이노가 통신할 때 같은 네트워크에 있거나 서버가 외부 고정 IP를 가지고 있어야 합니다. 또한 MySQL에 데이터가 쌓임에 따라 인덱싱 전략을 세워 모니터링 속도를 유지하는 것이 중요합니다. NuxtJS 프론트엔드에서는 1초 또는 5초 단위로 API를 호출하거나 WebSocket을 통해 실시간 변화를 사용자에게 보여줄 수 있습니다.
NuxtJS(Vue3)와 Chart.js를 활용하여 스마트팜의 실시간 상태를 시각화하고 제어하는 대시보드 구현 예시입니다.
NuxtJS 스마트팜 실시간 대시보드 구현
NestJS API로부터 데이터를 받아 온습도 변화를 그래프로 보여주고, 시설 제어 버튼을 구성하는 핵심 코드입니다.
1. 차트 시각화 컴포넌트 vue-chartjs 라이브러리를 사용하여 온습도 데이터를 선형 그래프로 나타냅니다. props를 통해 서버에서 받아온 농장 데이터를 실시간으로 반영합니다.
<template>
<div>
<Line :data="chartData" :options="chartOptions" />
</div>
</template>
<script setup>
import { Line } from 'vue-chartjs'
import { Chart as ChartJS, Title, Tooltip, Legend, LineElement, CategoryScale, LinearScale, PointElement } from 'chart.js'
ChartJS.register(Title, Tooltip, Legend, LineElement, CategoryScale, LinearScale, PointElement)
const props = defineProps(['farmData'])
const chartData = computed(() => ({
labels: props.farmData.map(d => new Date(d.createdAt).toLocaleTimeString()),
datasets: [
{ label: '온도', data: props.farmData.map(d => d.temperature), borderColor: '#f87171' },
{ label: '습도', data: props.farmData.map(d => d.humidity), borderColor: '#60a5fa' }
]
}))
</script>
2. 메인 대시보드 페이지 5초 간격의 폴링(Polling) 방식을 통해 서버의 최신 데이터를 가져오고, 사용자의 버튼 클릭 이벤트를 서버로 전송하여 차폐막 등을 제어합니다.
<template>
<div class="dashboard-container">
<h1>농장 실시간 모니터링</h1>
<div class="grid-layout">
<div class="chart-card">
<h3>환경 데이터 변화 (온습도)</h3>
<FarmChart :farmData="statusHistory" />
</div>
<div class="control-card">
<h3>시설 제어 센터</h3>
<button @click="toggleShutter">
차폐막 {{ currentStatus.shutterOpen ? '닫기' : '열기' }}
</button>
<div class="info">
<p>급수 탱크 잔량: {{ currentStatus.waterLevel }}%</p>
</div>
</div>
</div>
</div>
</template>
<script setup>
const statusHistory = ref([])
const currentStatus = ref({})
// 서버 데이터 조회 (fetch)
const fetchStatus = async () => {
const { data } = await useFetch('http://your-nestjs-api/farm/history')
statusHistory.value = data.value
currentStatus.value = data.value[0] || {}
}
// 시설 제어 명령 전송
const toggleShutter = async () => {
await $fetch('http://your-nestjs-api/farm/control', {
method: 'POST',
body: { command: 'shutter', value: !currentStatus.value.shutterOpen }
})
}
// 라이프사이클 훅: 주기적 갱신 설정
onMounted(() => {
fetchStatus()
setInterval(fetchStatus, 5000)
})
</script>
NuxtJS 대시보드는 백엔드 API와의 연동을 통해 농장의 현재 상태를 시각적으로 보여주는 데 매우 효과적입니다. 특히 useFetch를 활용한 데이터 관리와 Chart.js를 통한 직관적인 데이터 제공은 관리자의 빠른 판단을 돕습니다.
'IT 개발,관리,연동,자동화' 카테고리의 다른 글
| 푸드 빌딩 프로젝트: 스마트 수직픽업 배달 클러스터 기획안 (1) | 2025.12.24 |
|---|---|
| 5성급 호텔을 위한 차세대 ERP 구축 가이드: 혁신과 품격의 완성 (1) | 2025.12.22 |
| 미래 농업의 시작, IoT 스마트팜 시스템 구축 가이드 (2) | 2025.12.22 |
| [Special Report] 물류 데이터의 심장: 보세화물 수입신고 시스템 구축을 위한 DB 모델링 (0) | 2025.12.20 |
| OpenSeaMap과 이시각화Leaflet/OpenLayers 조합으로 AIS 데시보드구현 (0) | 2025.12.19 |