이 프로젝트는 MKR1000으로 데이터를 처리하고 와이파이를 통해 클라우드의 구글 시트로 전송합니다. 신용카드 등록이나 독점적인 블랙박스 API 없이도 구현 가능합니다. 예제로는 저렴하고 널리 쓰이는 DHT11 환경 센서를 사용하지만, 포함된 아두이노 코드를 수정하면 어떤 센서나 기기든 쉽게 적용할 수 있습니다. 이 프로젝트는 제 관련 프로젝트인 Thingspeak.com으로 DHT11 데이터를 업로드해 그래프로 시각화하는 것과 쉽게 결합할 수 있습니다.
전체 4부 중 1부입니다. 1부에서는 구글 앱 스크립트 코드를 사용해 직접 구글 시트를 설정하고 와이파이 데이터를 수신하도록 구성합니다.
1부: 구글 시트 생성 및 배포
1. 구글 계정이 없다면 무료로 가입하세요.
2. 구글 계정으로 로그인해 새 "구글 시트"를 만드세요. 이 스프레드시트가 DHT 센서 값으로 와이파이를 통해 채워집니다. 이때 스프레드시트 URL 키를 복사해 저장해야 합니다. 이 키는 새 스프레드시트 URL에서 "/d/"와 "/edit" 사이에 있는 문자열입니다(파란 원 참조).
3. 스프레드시트 이름을 "환경 데이터" 같은 걸로 짓고, 이제 구글 앱 스크립트(자바스크립트와 유사)를 만들어 데이터를 처리하고 스프레드시트를 올바르게 채우게 합니다. 스크립트 에디터로 이동하려면:
도구 → 스크립트 에디터
이제 구글 스크립트 에디터 페이지에 있습니다. G스크립트 이름을 "내 환경 G스크립트"처럼 창의적으로 지으세요. 스크립트 에디터 페이지에서 해야 할 일이 네 가지 남았습니다.
A) 포함된 구글 스크립트 코드를 에디터에 복사-붙여넣기
B) 2단계에서 저장한 스프레드시트 URL 키를 구글 스크립트 코드의 올바른 줄(따옴표 사이)에 붙여넣기:
var id = ' '; // 스프레드시트 ID
C) 스크립트 저장: 파일 → 모두 저장
D) 웹 앱으로 배포: 게시 → 웹 앱으로 배포…
4. 마지막 단계로 웹 배포 매개변수를 구성합니다. 네 필드를 정확히 설정해야 스프레드시트가 제대로 작동합니다.
필드 1) 방금 생성된 "현재 웹 앱 URL:"을 복사해 저장하세요. 나중에 PushingBox에서 API 구성할 때 필요합니다.
필드 2) 각 반복마다 프로젝트 버전을 "새 버전"으로 저장하세요. 스크립트 수정 시 새 버전을 만들지 않으면 웹에서 수정이 반영되지 않습니다. 직관적이지 않고 놓치기 쉽지만 현재 구글 시스템이 이렇게 되어 있습니다.
필드 3) "앱 실행 계정:"을 "나(내 Gmail)"로 설정.
필드 4) "앱에 액세스할 수 있는 사용자: "을 "익명 사용자 포함 모두"로 설정.
2부: PushingBox 구성
Pushingbox.com은 우리 DHT 데이터가 구글 시트에서 처리될 수 있게 해주는 간단하고 무료한 API 미들맨 역할을 합니다. PushingBox API 중개자가 필요한 이유는 HTTP로 전송된 데이터를 구글이 요구하는 HTTPS 암호화 데이터로 변환하기 위함입니다. 비자명한 암호화 알고리즘으로 표준 요구사항을 만족시키려 시도할 수도 있지만, PushingBox를 쓰는 게 더 쉽고 하루 1,000회 요청까지 무료입니다. 게다가 매개변수는 입력할 수 있지만 커스터마이징 제약이 있고 실제 작동 방식을 알 수 없는 "블랙박스" API도 피할 수 있습니다. PushingBox 설정 단계:
Gmail로 PushingBox 계정 생성
상단의 "My Services" 클릭
"My Services"에서 "Add a service" 박스의 "Add a service" 클릭
서비스 목록 마지막 항목인 "CustomURL, Set your own service!" 선택
열린 박스에 세 항목 입력 후 제출:
CustomURL 구성 이름:
Root URL:이 URL은 https://script.google.com... 로 시작하며, 1부에서 저장한 구글 스크립트 주소입니다.
Method:
서비스 제출 후 시나리오 생성. 페이지 상단 "My Scenarios" 선택.
"Create a scenario or add a device" 박스에 적절한 시나리오 이름 입력 후 오른쪽 "add" 버튼 클릭.
"Add an action for your scenario" 요청 시, 이전 단계에서 만든 서비스 이름 옆의 "Add an action to this service" 버튼 선택. 이렇게 새 시나리오가 새 서비스에 할당됩니다.
데이터 박스가 열리며 "Get" 또는 "Post" 방식 요청(우리는 Get 방식 사용, 직관에 반하는 듯하지만). 구글 앱 스크립트의 변수명을 아두이노 스케치의 변수명과 연결하기 위해 PushingBox API에서 이름을 올바르게 포맷해야 합니다. 다음 문자열을 복사-붙여넣기 하세요:
"DeviceID" 문자열을 꼭 복사해두세요. 다음 단계의 사전 테스트와 4부의 아두이노 스케치에서 필요합니다.
3. API 테스트
하드웨어 부분으로 넘어가기 전에 지금까지 한 작업이 올바른지 테스트해보는 게 좋습니다. 하드웨어까지 완료하면 오류 원인 추적이 더 어려워질 수 있습니다. 다행히 간단한 테스트 방법이 있습니다. 웹 브라우저 주소창에 하드코딩된 가짜 데이터를 직접 입력해 구글 시트가 올바르게 업데이트되는지 확인하면 됩니다. 브라우저 주소창에 복사-붙여넣기 할 예시:
원하면 다른 값으로 새 가짜 데이터를 다시 입력해 후속 행을 채울 수도 있습니다. 단, PushingBox에서 하루 1,000회 요청 제한이 있으니 너무 많이 하진 마세요! 이 절차로 스프레드시트가 업데이트되지 않으면 1~3부를 검토해 오류를 찾은 후 4부를 시도하세요.
4부
브라우저에서 하드코딩된 가짜 데이터를 구글 시트로 푸시하는 게 확인되었다면, 이제 MKR1000을 프로그래밍해 DHT 데이터를 PushingBox를 거쳐 와이파이로 구글 시트에 전송하는 단계로 넘어갑니다. 포함된 아두이노 스케치를 MKR1000에 업로드해 실행하기 전에 다음 세 단계를 완료해야 합니다.
하드웨어
1. MKR1000과 DHT 배선: MKR1000을 쓰면 간단합니다. DHT에 5볼트로 전원 공급을 권장합니다. MKR1000의 5V 핀으로 가능합니다. DHT가 3.3V로도 작동한다고 하지만 저전압에서 신뢰할 만한 읽기값을 얻진 못했습니다. DHT 데이터를 MKR1000으로 입력할 핀은 여러 개 쓸 수 있지만, 제 스케치에서는 핀 5를 사용하며 이는 보드 상단의 핀 D5에 매핑됩니다.
소프트웨어 (1)
2. 아두이노 IDE를 MKR1000과 작동하도록 설정하는 몇 단계가 있습니다. 두 라이브러리 다운로드와 아두이노 IDE(1.6.4 이상)에서 올바른 MKR1000 보드 패키지 설정(도구 → 보드 → 보드 매니저)이 필요합니다. 이미 필요한 소프트웨어를 모두 설치한 분도 많겠지만, 아닌 분들을 위해 필요한 라이브러리와 MKR1000 보드 지원 패키지 링크를 아래에 적습니다. 저는 최신 MKR1000 보드 패키지가 제대로 작동하지 않아 이전 버전을 써야 했습니다. 이 글을 읽을 땐 문제가 해결됐길 바랍니다.
https://www.arduino.cc/en/Reference/WiFi101
스케치에 필요한 두 라이브러리:
https://github.com/arduino-libraries/WiFi101
https://learn.adafruit.com/dht
소프트웨어 (2)
3. 이제 프로젝트 마지막 단계입니다. 포함된 아두이노 스케치를 복사-붙여넣기 하고 자신의 기기에 맞게 커스터마이징한 후 MKR1000에 업로드하세요. 스케치는 9600 보드레이트로 시리얼 출력을 중계해 와이파이로 전송되는 데이터를 모니터링할 수 있습니다. 아두이노 스케치에서 반드시 커스터마이징해야 할 세 필드:
A) 와이파이 이름 (SSID)
B) 와이파이 비밀번호
C) PushingBox Device ID (devid)
이게 전부입니다! 모든 게 올바르게 완료되면 출력이 아래 그림처럼 나올 겁니다:
이 프로젝트의 기반이 된 소프트웨어 구성요소 대부분을 만드신 모든 분들께 감사드립니다. 코드 주석에 이름을 적어 적절히 출처를 밝혔습니다. 이 프로젝트의 어떤 부분이든 자유롭게 사용해 여러분만의 매직을 만드세요.
-SDB
코드
MKR1000 → PushingBox → 구글 시트 (DHT 사용)
이 아두이노 스케치는 와이파이로 데이터를 PushingBox에 밀어 암호화한 뒤 구글 시트에 기록합니다.
//-----------------------------------------------
// 이 스케치는 Adafruit DHT 센서와 tdicola의 dht.h 라이브러리 결합
// https://learn.adafruit.com/dht/overview
// https://gist.github.com/teos0009/acad7d1e54b97f4b2a88
// 다른 작성자 아두이노 및 관련 구글 스크립트:
// Aditya Riska Putra
// Ahmed Reza Rafsanzani
// Ryan Eko Saputro
// 참고:
// https://jarkomdityaz.appspot.com/
// ELINS UGM
// Hackster.io 프로젝트용으로 MKR1000에 맞게 수정
// by Stephen Borsay (Portland, OR, USA)
// 아두이노는 HTTPS를 못하므로 PushingBox API(HTTP 사용)로
// 구글 스크립트(HTTPS 사용) 실행. 대안으로 Ivan의 SecureWifi 암호화 사용 가능
#include
#include "DHT.h"
#define DHTPIN 5 // 연결된 핀, 끝에서 5번째 핀이 핀 1
// 사용하는 DHT 센서 타입 주석 해제!
#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT21 // DHT 21
//#define DHTTYPE DHT22 // DHT 22
DHT dht(DHTPIN, DHTTYPE);
const char WEBSITE[] = "api.pushingbox.com"; // PushingBox API 서버
const String devid = "YOUR_DEVICEID"; // 우리 시나리오용 PushingBox Device ID
const char* MY_SSID = "YOUR SSID";
const char* MY_PWD = "YOUR WiFi PASSWORD";
int status = WL_IDLE_STATUS;
// DNS 사용 안 하고 스케치 크기 줄이려면 서버 이름 대신 숫자 IP 사용:
// IPAddress server(74,125,232,128); // Google 숫자 IP (DNS 불필요)
void setup() {
Serial.begin(9600);
while (!Serial) { ; } // 네이티브 USB 포트만 필요
if (WiFi.status() == WL_NO_SHIELD) {
Serial.println("WiFi shield not present");
while (true); // 중단
}
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(MY_SSID);
status = WiFi.begin(MY_SSID, MY_PWD); // WPA/WPA2 네트워크 연결. 오픈/WEP면 이 줄 변경
delay(10000); // 연결 대기 10초
}
Serial.println("Connected to wifi");
printWifiStatus();
}
void loop() {
delay(10000); // 측정 간격
int humidityData = dht.readHumidity();
int celData = dht.readTemperature(); // 섭씨 (기본)
int fehrData = dht.readTemperature(true); // 화씨 (isFahrenheit = true)
if (isnan(humidityData) || isnan(celData) || isnan(fehrData)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
int hifData = dht.computeHeatIndex(fehrData, humidityData); // 화씨 열지수 (기본)
int hicData = dht.computeHeatIndex(celData, humidityData, false); // 섭씨 열지수
Serial.print("Humidity: "); Serial.print(humidityData); Serial.print(" %\t");
Serial.print("Temperature: "); Serial.print(celData); Serial.print(" *C ");
Serial.print(fehrData); Serial.print(" *F\t");
Serial.print("Heat index: "); Serial.print(hicData); Serial.print(" *C ");
Serial.print(hifData); Serial.println(" *F\n");
Serial.println("\nSending Data to Server...");
WiFiClient client;
if (client.connect(WEBSITE, 80)) {
client.print("GET /pushingbox?devid=" + devid + "&humidityData=" + (String)humidityData + "&celData=" + (String)celData + "&fehrData=" + (String)fehrData + "&hicData=" + (String)hicData + "&hifData=" + (String)hifData);
client.println(" HTTP/1.1");
client.print("Host: "); client.println(WEBSITE);
client.println("User-Agent: MKR1000/1.0");
client.println(); // ESP8266과 달리 연결 닫지 않음
Serial.println("\nData Sent");
}
}
void printWifiStatus() {
Serial.print("SSID: "); Serial.println(WiFi.SSID());
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: "); Serial.println(ip);
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):"); Serial.print(rssi); Serial.println(" dBm");
}
HTTPS 형식으로 무선 데이터 수신하는 구글 스크립트
구글 시트의 스크립트 에디터에 붙여넣으세요. 암호화/보안 인증서 HTTPS 형식이어야 하므로 PushingBox를 사용합니다.
//-----------------------------------------------
// 원래 Mogsdad@Stackoverflow 게시
// jarkomdityaz.appspot.com용으로 수정
// Hackster.io용으로 Stephen Borsay 수정
//-----------------------------------------------
/* GET 요청 쿼리: https://script.google.com/macros/s//exec?celData=data_here
----------------------------------------------------------------------
GScript, PushingBox, 아두이노/ESP8266 변수 순서:
humidityData celData fehrData hicData hifData
---------------------------------------------------- */
function doGet(e) {
Logger.log(JSON.stringify(e)); // 매개변수 확인
var result = 'Ok'; // 성공 가정
if (e.parameter == undefined) {
result = 'No Parameters';
} else {
var id = ''; // docs.google.com/spreadsheetURL/d
var sheet = SpreadsheetApp.openById(id).getActiveSheet();
var newRow = sheet.getLastRow() + 1;
var rowData = [];
rowData[0] = new Date(); // A열에 타임스탬프
for (var param in e.parameter) {
Logger.log('In for loop, param='+param);
var value = stripQuotes(e.parameter[param]);
switch (param) {
case 'humidityData': rowData[1] = value; break; // B열
case 'celData': rowData[2] = value; break;
case 'fehrData': rowData[3] = value; break;
case 'hicData': rowData[4] = value; break;
case 'hifData': rowData[5] = value; break;
default: result = "unsupported parameter";
}
}
Logger.log(JSON.stringify(rowData));
var newRange = sheet.getRange(newRow, 1, 1, rowData.length);
newRange.setValues([rowData]);
}
return ContentService.createTextOutput(result);
}
function stripQuotes(value) {
return value.replace(/^["']|["']$/g, "");
}
PushingBox URL 문자열 (HTTPS 접착제용)
아두이노/MKR1000에서 전송되는 변수명을 구글 시트의 정확한 같은 이름과 연결하는 문자열입니다. PushingBox를 보안 지원 중개자로 RESTfully 사용.