MKR GSM 1400과 아두이노 클라우드, 구글 시트로 구현하는 실시간 IoT 압력 모니터링
프로젝트 개요
원격지 산업 설비의 압력을 저비용으로 모니터링하기 위해, 아두이노 우노(센서 수집) → MKR GSM 1400(셀룰러 통신) → 아두이노 IoT 클라우드 → 웹훅 → 구글 시트(데이터 파싱/알림) 파이프라인을 구축했습니다. 배터리 구동 가능하며, 압력 임계값 초과 시 즉시 알림, 정기 리포팅, 원격 조회(디맨드 폴링) 기능을 모두 제공합니다.
시스템 아키텍처 및 데이터 흐름
- Step 1: 압력 트랜스듀서 → 아두이노 우노 - 0~150 psi 아날로그 신호를 우노가 읽어 psi로 변환
- Step 2: 우노 → MKR GSM 1400 (시리얼) - RX/TX 크로스 연결, 공통 그라운드. 3가지 전송 트리거:
- 정기 전송: 30분마다
- 임계값 알림: 20 psi 미만 또는 40 psi 초과 2분 지속 시
- 원격 조회: MKR GSM의 A3 핀 High → 우노 A1 핀 High → 즉시 전송
- Step 3: MKR GSM 1400 → 아두이노 클라우드 (셀룰러) - Serial1 사용(하드웨어 시리얼). 클라우드 변수 2개:
dataStringCloud: 모든 데이터 패키지(파싱 편의성 위해 단일 문자열)
pinCloud: 클라우드에서 MKR 제어용(1=로컬 LED, 2=원격 조회 트리거)
- Step 4: 아두이노 클라우드 → 구글 시트 (웹훅) - 구글 앱스 스크립트
doPost(e)로 JSON 수신, 'RawData' 시트에 기록
- Step 5: 구글 시트에서 데이터 파싱 - 'Data' 시트에서 수식으로 개별 필드 추출, 고유 레코드만 표시
- Step 6: 구글 시트에서 이메일 알림 발송 -
sendEmail() 함수를 분 단위 트리거로 실행. 임계값 알림, 통신 두절/복구 알림 발송
하드웨어 구성 (BOM)
| 부품 | 수량 | 비고 |
| 아두이노 MKR GSM 1400 | 1 | 셀룰러 통신, 아두이노 클라우드 연동 |
| 아두이노 우노 | 1 | 센서 인터페이스, 아날로그-디지털 변환 |
| 압력 트랜스듀서 (0-150 psi) | 1 | 아날로그 출력, A2 핀 연결 |
| DHT22 온습도 센서 | 1 | 디지털 11번 핀 |
| DS3231 RTC 모듈 | 1 | I2C, 정확한 타임스탬프용 |
| 로직 레벨 컨버터 (BSS138, 4채널) | 1 | MKR(3.3V) ↔ 우노(5V) I2C/시리얼 레벨 변환 |
| 3.7V LiPo 배터리 (2000mAh+) | 2 | 각 보드 독립 전원 |
| 스텝업 컨버터, 브레드보드, LED/저항 키트 | 각 1 | 전원 승압, 프로토타이핑용 |
전력 및 통신 성능
- 배터리 수명: 약 24시간 (디스플레이, DHT22, RTC 제거 시 대폭 연장 가능)
- 데이터 사용량: 약 0.7 MB/일 (전송 주기/페이로드 크기 조정으로 최적화 가능)
- 총 제작비: 약 $241 (MKR GSM 1400 $70, 우노 $22, 배터리 $30, 디스플레이 $29, 케이스 $22, 센서류 $34, 기타 $25)
핵심 소스 코드
1. 아두이노 우노 스케치 (InstrumentReader)
// 주요 라이브러리: DS3231, DHT, U8glib(OLED 디스플레이용)
#include
#include
#include
#include
#include "U8glib.h"
#define DHTPIN 11
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
RTClib RTC;
U8GLIB_SH1106_128X64 u8g(3, 4, 6, 7); // CLK, MOSI, CS, DC
const int ledPin = 9; // 전송 표시 LED
const int ledPin2 = 8; // 강제 전송 표시 LED
const int buttonPin = A1; // 강제 전송 트리거 입력 (MKR A3 또는 푸시버튼)
int transmitFrequency = 30; // 분 단위 정기 전송 주기
float lowTrigger = 20.0, highTrigger = 40.0;
float dtLastTriggerLimit = 2.0; // 분 단위 임계값 지속 시간
void setup() {
Serial.begin(9600);
Wire.begin(); dht.begin();
pinMode(ledPin, OUTPUT); pinMode(ledPin2, OUTPUT); pinMode(buttonPin, INPUT);
u8g.setRot180();
}
void loop() {
delay(5000);
DateTime now = RTC.now();
float pressure = getPressure(); // 아날로그 읽기 → 선형 변환
int buttonState = digitalRead(buttonPin);
if (buttonState) { digitalWrite(ledPin2, HIGH); delay(30000); } else digitalWrite(ledPin2, LOW);
// 정기 전송 조건
bool transmitIndicator = (now.minute() % transmitFrequency == 0 && now.minute() != pTransmitMinute);
// 임계값 알림 조건
bool triggerStatus = (pressure <= lowTrigger || pressure >= highTrigger);
// ... 지속 시간 카운팅 로직 생략 ...
// 데이터 문자열 구성: <인덱스,알림플래그,지속시간,버튼,월,일,년,시,분,초,습도,온도,압력>
String dataString = "<" + String(i) + "," + alertFlag + "," + duration + "," + buttonState + ", " +
now.month() + "," + now.day() + "," + now.year() + ", " +
now.hour() + "," + now.minute() + "," + now.second() + ", " +
humidity + "," + tempF + "," + pressure + ">";
if (transmitIndicator || triggerPushAlert || buttonState) {
Serial.println(dataString); // MKR GSM으로 전송
flashLED(10, 500);
}
// OLED 디스플레이 업데이트, 인덱스 증가 등 생략
i++;
}
float getPressure() {
int sensorVal = analogRead(A2);
float voltage = sensorVal * 5.0 / 1023.0;
// 0 psi = 0.4889V, 150 psi = 4.5V 선형 보간
float m = 150.0 / (4.5 - 0.4889);
float b = 150.0 - m * 4.5;
return m * voltage + b;
}
2. MKR GSM 1400 스케치 (CommunicationsDevice)
원문에 코드 본문이 생략되어 있으나, 핵심은 Serial1로 우노 데이터 수신 → 아두이노 클라우드 라이브러리로 dataStringCloud, pinCloud 변수 동기화 → pinCloud 값에 따라 A1/A3 핀 제어(원격 조회 트리거) 로직으로 구성됩니다.
3. 구글 앱스 스크립트 (GoogleSheetsScript.js)
// doPost: 아두이노 클라우드 웹훅 수신 → RawData 시트 기록
function doPost(e) {
var cloudData = JSON.parse(e.postData.contents);
var values = cloudData.values; // [{name, value, updated_at}, ...]
var timestamp = values[0].updated_at;
var date = new Date(Date.parse(timestamp));
if (date.getYear() > 2018) { // 중복/지연 메시지 필터링
// 헤더 행 동적 생성 (신규 속성 자동 추가)
// 최대 행 수(MAX_ROWS=1440) 초과 시 최하행 삭제 후 새 행 삽입
// 타임스탬프 + 각 속성 값 기록 (불리언 → 0/1 변환, 빈 값은 '-' 채움)
}
}
// sendEmail: 분 단위 트리거로 실행, 알림 조건 판단 후 메일 발송
function sendEmail() {
var email = sd.getRange("V3").getValue();
var pressure = sd.getRange("K3").getValue();
var lastUpdate = sd.getRange("A3").getValue();
var triggerMonitor = sd.getRange("M3").getValue(); // -1: 임계값 이탈, 1: 정상 복구
var dtLastDeviceUpdate = sd.getRange("S3").getValue(); // 분 단위 최종 업데이트 경과
if (triggerMonitor == -1 && alertCount <= 4) { /* 이탈 알림 메일 */ }
if (triggerMonitor == 1 && alertCount <= 4) { /* 복구 알림 메일 */ }
if (emailSentNoUpdate == 0 && dtLastDeviceUpdate > 60) { /* 통신 두절 알림 */ }
if (emailSentNoUpdate == 1 && dtLastDeviceUpdate < 60) { /* 통신 복구 알림 */ }
}
웹훅 설정 절차 (구글 시트 → 아두이노 클라우드)
- 구글 시트 생성 → 도구 → 스크립트 편집기
doPost 함수 작성 후 게시 → 웹 앱으로 배포
- 설정: 실행 계정: 나, 액세스 권한: 누구나(익명 포함), 버전: 새로 만들기
- 생성된 현재 웹 앱 URL 복사
- 아두이노 IoT 클라우드 → Things → Webhooks → Add Webhook → URL 붙여넣기
회로도

구글 시트 템플릿 (참고용)
공개 시트 링크 - RawData, Data, References 시트 구성, 조건부 서식으로 색상 구분
결론 및 개선 방향
- 저비용 셀룰러 IoT 게이트웨이 패턴 검증 완료
- 배터리 수명 연장: 디스플레이 제거, 비필수 센서(DHT22, RTC) 제외, 딥슬립 모드 적용
- 데이터 절약: 압력만 전송, 전송 주기 1시간으로 늘리기
- 내구성: 방수 케이스, 커넥터 방수 처리, 감압 밸브 장착
- 보안: MKR GSM 1400 내장 보안 엘리먼트(ATECC508A) 활용, 클라우드 인증서 기반 TLS