만들기
아두이노로 광 센서를 만들어 내 정원에 연결하기
Arduino UNO R4 WiFi에 SEN0644 조도 센서를 붙여 lux를 PPFD로 환산하고, 5분 평균을 Open API로 전송하는 광 센서 노드를 만드는 방법입니다.
식물이 실제로 받는 빛이 얼마나 되는지는 눈으로 가늠하기 어렵습니다. 창가가 밝아 보여도 바깥의 10분의 1도 안 되는 경우가 흔합니다. 이 글에서는 Arduino UNO R4 WiFi에 RS485 조도 센서를 붙여 **광량(PPFD)**을 5분마다 전송하는 센서 노드를 만듭니다.
완성하면 앱의 센서 관리 화면에 광량 센서가 나타나고, 구역과 식물에 연결해 다른 센서와 똑같이 쓸 수 있습니다. 하루 총 광량(DLI)은 장치가 아니라 서버가 받은 값으로 계산하므로, 보드는 PPFD만 꾸준히 보내면 됩니다.
온습도·토양수분 노드를 먼저 보고 싶다면 아두이노로 만든 센서를 내 정원에 연결하기를 참고하세요. 설정 방식과 서명 규칙은 두 프로젝트가 같습니다.
이 글에서 쓰는 코드 전체는 GitHub에 공개되어 있습니다 — four-seasons-of-mygarden/sensors의
arduino-r4-wifi-light폴더입니다.
준비물
| 부품 | 설명 |
|---|---|
| Arduino UNO R4 WiFi | Wi-Fi와 12×8 LED 매트릭스가 내장된 보드입니다. |
| DFRobot SEN0644 | RS485로 통신하는 조도 센서입니다. |
| DFRobot DFR0845 | RS485 신호를 보드가 읽는 UART로 바꿔 주는 어댑터입니다. |
| 누름 버튼 | 설정 화면을 다시 열 때 씁니다. 없어도 동작합니다. |
| 점퍼선, USB-C 케이블 | 데이터 전송이 되는 케이블이어야 합니다. |
조도 센서를 RS485 제품으로 고른 이유는 실외에 오래 두기 위해서입니다. 아날로그 조도 센서는 선이 길어지면 값이 흔들리는데, RS485는 CRC로 검증되는 디지털 통신이라 배선이 길어도 값이 그대로 옵니다. 창밖이나 온실처럼 보드에서 떨어진 자리에 센서만 내놓을 수 있습니다.
1. 회로 연결
센서와 보드 사이에 어댑터가 하나 낍니다. 센서는 RS485로 말하고 보드는 UART로 듣습니다.
SEN0644 → DFR0845
| SEN0644 선 색상 | DFR0845 RS485 |
|---|---|
| 빨강 (VCC) | 12V |
| 파랑 (GND) | GND |
| 노랑 (485-A) | A |
| 초록 (485-B) | B |
센서 전원은 12V입니다. 보드의 5V에 물리면 동작하지 않습니다. 어댑터의 12V 단자를 쓰세요.
DFR0845 → UNO R4 WiFi
| DFR0845 UART | UNO R4 WiFi |
|---|---|
| T | D1 (TX) |
| R | D0 (RX) |
| + | 5V |
| - | GND |
D0·D1은 보드의 Serial1입니다. USB로 연결되는 시리얼 모니터는 별개의 Serial이라 이 선을 꽂아 둔 채로 업로드하고 로그를 볼 수 있습니다.
설정 버튼
평소에는 열려 있고 누르면 연결되는 누름 버튼을 D3과 GND 사이에 연결합니다. 내부 풀업을 쓰므로 저항은 필요 없습니다. 핀 번호는 include/config.h에서 바꿀 수 있습니다.
2. 프로젝트 준비
VS Code에 PlatformIO IDE 확장을 설치하고 sensors 저장소를 내려받아 arduino-r4-wifi-light 폴더를 엽니다. 필요한 라이브러리는 platformio.ini에 정의되어 있어 처음 빌드할 때 자동으로 받습니다.
lib_deps =
arduino-libraries/ArduinoHttpClient @ ^0.6.1
arduino-libraries/Arduino_CloudUtils @ ^1.2.1
bblanchon/ArduinoJson @ ^7.4.2
ricmoo/QRCode @ 0.0.1
토양수분 노드와 달리 센서 라이브러리가 없습니다. SEN0644는 Modbus RTU 요청을 직접 만들어 읽기 때문입니다.
3. API 키 발급과 설정
앱에서 키를 먼저 발급받습니다.
MY → 설정 → 센서 관리 → 오른쪽 위 + 버튼 → OpenAPI
Key 이름을 입력하고 저장하면 Access Key와 Secret Key가 발급됩니다. Secret Key는 이때 한 번만 제공되니 CSV 파일을 꼭 저장해 두세요. 자세한 절차는 나만의 센서 데이터를 Open API로 전송하기에 정리되어 있습니다.
include/config.example.h를 include/config.h로 복사하고 값을 채웁니다.
constexpr char SETUP_AP_PASSWORD[] = "설정용_AP_비밀번호"; // 8~63자
constexpr char DEVICE_NAME[] = "베란다 창가";
constexpr char API_KEY[] = "발급받은_Access_Key";
constexpr char API_SECRET[] = "발급받은_Secret_Key";
config.h는 .gitignore에 들어 있습니다. Wi-Fi 정보와 광원 프로필은 여기 넣지 않습니다. 다음 단계에서 웹페이지로 고르면 EEPROM에 저장됩니다.
4. 업로드하고 Wi-Fi 설정하기
보드를 USB로 연결하고 PlatformIO의 Upload를 실행합니다.
pio run --target upload
pio device monitor
업로드가 끝나면 LED 매트릭스에 AP가 표시됩니다. 설정용 Wi-Fi가 열렸다는 뜻입니다.
- 휴대폰에서
LightSensor-XXXXXXWi-Fi에 연결합니다. 비밀번호는config.h에 넣은 값입니다. - 브라우저에서
http://192.168.4.1을 엽니다. - 공유기 SSID와 비밀번호를 입력하고 저장합니다.
휴대폰이 “인터넷에 연결되어 있지 않음”이라고 표시해도 연결을 유지해야 합니다. 설정 AP에는 인터넷이 없는 것이 정상입니다.
저장하면 AP가 닫히고 보드가 입력한 공유기에 연결됩니다. 이후에는 같은 Wi-Fi에서 http://lightsensor-xxxxxx.local/로 설정 페이지를 다시 열 수 있습니다. 설정 페이지 맨 위에 이 주소와 QR 코드가 함께 표시되니, 스캔해서 즐겨찾기에 넣어 두면 다음에 찾기 쉽습니다.
설정 AP는 다음 네 경우에 열립니다.
- 처음 실행했을 때
- 새 펌웨어를 업로드한 뒤
- 저장된 공유기에 60초 동안 연결하지 못했을 때
- D3 버튼을 3초 이상 눌렀을 때 (부팅 중 누르고 있어도 열립니다)
5. 광원 프로필 고르기
여기가 이 프로젝트의 핵심입니다.
센서가 읽는 값은 lux입니다. lux는 사람 눈이 느끼는 밝기라서 초록빛에 크게 반응하고 붉은빛·푸른빛에는 둔합니다. 반면 식물이 광합성에 쓰는 빛은 PPFD(μmol/m²/s), 즉 광합성에 쓰이는 파장대의 광자 개수입니다. 사람 눈의 감도와 식물의 감도가 다르기 때문에 같은 lux라도 광원이 다르면 PPFD가 다릅니다.
그래서 설정 페이지에서 쓰고 있는 광원을 고르면, 그에 맞는 환산계수로 PPFD를 계산합니다.
| 광원 프로필 | PPFD/lux |
|---|---|
| 자연광 | 0.0185 |
| 백색 LED 2700~4000K | 0.0175 |
| 백색 LED 5000~6500K | 0.0145 |
| 형광등 / 메탈할라이드 | 0.0138 |
| HPS 나트륨등 | 0.0122 |
| 사용자 보정 | 0.001~0.100 사이의 직접 입력값 |
같은 10,000 lux라도 자연광이면 185, HPS 나트륨등이면 122가 됩니다. 30% 넘게 차이 납니다.
설정 페이지에는 현재 조도와 계산된 PPFD가 1초마다 갱신되어 표시되므로, 프로필을 바꿔 가며 값이 어떻게 달라지는지 바로 볼 수 있습니다.
혼합광은 계수 하나로 정확히 나눌 수 없습니다. 창으로 햇빛이 들어오는데 식물등도 켜 두는 자리라면 어떤 프로필을 골라도 오차가 남습니다. PAR 센서를 빌릴 수 있다면 같은 자리에서 동시에 재고
PPFD ÷ lux를 계산해 사용자 보정에 넣는 편이 가장 정확합니다.
프로필을 바꾸면 진행 중이던 5분 집계가 초기화됩니다. 계수가 다른 표본이 한 평균에 섞이지 않도록 한 것입니다.
6. 전송이 동작하는 방식
센서는 1초마다 읽고, 5분치를 모아 평균 하나를 보냅니다.
시간가중 평균을 씁니다
단순히 표본을 더해서 개수로 나누지 않습니다. 표본과 표본 사이의 시간을 반영한 평균을 구합니다.
표본 간격이 고르면 → 산술평균과 같은 값
API 전송으로 한 구간이 길어지면 → 그 구간이 그만큼 큰 비중을 차지
전송이나 통신 지연으로 측정 간격이 늘어나는 일이 실제로 생기는데, 산술평균을 쓰면 오래 유지된 밝기가 짧게 스친 밝기와 같은 무게로 들어갑니다. 빛은 하루 총량으로 쓰는 값이라 이 차이가 누적됩니다.
전송에 실패하면 집계 구간을 버리지 않고 그대로 둔 채 30초마다 재시도합니다. 성공했을 때만 다음 구간을 새로 시작합니다.
전송 형식
const SensorReading readings[] = {
{"ppfd", "09", String(averagePpfd, 2)},
};
const bool sent = sendSensorReadings(readings, 1);
| field_nm | category | 단위 |
|---|---|---|
ppfd |
09 |
μmol/m²/s |
DLI(하루 총 광량)는 보드에서 계산하지 않습니다. 서버가 받은 PPFD와 측정 시각으로 적분합니다. 보드가 재부팅되거나 잠시 꺼져 있어도 그날의 누적값이 날아가지 않습니다.
서명 규칙과 타임스탬프 처리는 온습도·토양수분 노드와 같습니다. 요청마다 메서드 + 경로 + 타임스탬프 + Access Key를 Secret Key로 HMAC-SHA256 서명하고, date는 한국 시간이 아닌 UTC로 보냅니다.
7. 동작 확인하기
시리얼 모니터(115200 baud)에서 측정과 전송을 볼 수 있습니다.
[SEN0644] 12450.000 lux, PPFD: 230.33 umol/m^2/s, profile: 자연광
[Aggregate] samples: 298, duration: 301 s, average PPFD: 228.71 umol/m^2/s
[API] HTTP status: 200
LED 매트릭스는 세 화면이 2초 간격으로 돌아갑니다.
| 화면 | 표시 |
|---|---|
| 광량 | 230 — 현재 PPFD를 반올림한 정수 |
| Wi-Fi | 안테나 모양, 끊기면 사선 |
| 전송 결과 | 화살표 옆에 체크(성공) 또는 X(실패) |
아직 값을 못 읽었으면 ---로 표시됩니다. 매트릭스가 세 자리까지만 그릴 수 있어 999를 넘는 값은 999로 잘려 보입니다. 한여름 직사광은 2000을 넘기므로 화면이 999에 붙어 있어도 전송되는 값은 정상입니다.
200이 확인되면 앱의 센서 관리 화면에 발급한 키 아래로 광량 센서가 나타납니다. 설치한 구역을 지정하고 식물과 연결하면 식물 상세 화면에서 값을 볼 수 있습니다.
자주 막히는 곳
response timeout이 반복됩니다
센서에서 응답이 아예 오지 않는 상태입니다. 순서대로 확인하세요.
- 센서 전원 — SEN0644는 12V입니다. 5V로는 동작하지 않습니다.
- A와 B — RS485는 두 선이 바뀌면 통신이 되지 않습니다. 노랑이 A, 초록이 B입니다.
- T와 R — 어댑터의 T는 D1, R은 D0입니다.
CRC mismatch가 나옵니다
응답은 오는데 내용이 깨지는 상태입니다. 접촉 불량이나 선이 너무 길어 생기는 노이즈가 흔한 원인입니다. 결선을 다시 조이고, 전원선과 통신선을 나란히 길게 묶어 두었다면 떼어 보세요.
값이 실제보다 너무 높거나 낮습니다
광원 프로필을 확인하세요. 식물등 아래인데 자연광으로 두었다면 30% 가까이 높게 나옵니다. 센서 위에 유리나 필름이 있는지도 함께 보세요.
401이 나옵니다
시각을 먼저 의심하세요. 서명은 서버 시각과 5분 이내여야 통과합니다. 키를 붙여 넣을 때 앞뒤 공백이나 CSV의 따옴표가 섞여 들어가는 경우도 흔합니다.
저장한 Wi-Fi 정보가 사라집니다
Upload를 실행하면 EEPROM의 Wi-Fi 정보와 광원 프로필이 초기화됩니다. 새 펌웨어를 올리면 설정 AP부터 다시 시작합니다. RESET 버튼이나 전원 재연결로는 지워지지 않습니다.
더 해볼 것
지금은 전송에 실패한 구간을 재시도하다가 결국 못 보내면 버립니다. Wi-Fi가 오래 끊기는 자리라면 EEPROM이나 SD 카드에 쌓아 두었다가 나중에 올리는 편이 낫습니다.
이 센서는 한 자리의 빛만 잽니다. 같은 방이어도 창에서 1m만 멀어지면 광량이 크게 떨어지므로, 화분이 여럿이라면 자리마다 하나씩 두거나, 하나를 옮겨 가며 며칠씩 재 보는 것도 방법입니다.