산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

부품 및 소모품

부품 수량
아두이노 UNO 1
Espressif ESP8266 ESP-01 1
DHT22 온습도 센서 1
DS18B20 1-Wire 디지털 온도 센서 (토양용) 1
LDR - 조도 의존 저항 1
2채널 DC 5V 릴레이 모듈 1

앱 및 온라인 서비스

프로젝트 개요

목표는 로컬 유닛에서 정보를 수집해 인터넷으로 전송하는 것입니다. 지구 반대편의 사용자가 이 정보를 보고 원격 명령을 액추에이터로 보내는 구조입니다. 어떤 센서나 액추에이터든 적용 가능합니다.

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

내 IoT 작업의 대부분은 NodeMCU와 최근에는 ESP32를 사용했지만, 몇 년 전 아두이노 UNO와 ESP8266-01로 IoT를 처음 배우던 시절을 잊지 않고, 이제는 더 많은 경험을 바탕으로 다시 이 훌륭한 기기들을 탐구해보려 합니다. ThingSpeak.com 웹 서비스를 이용해 클라우드에 연결하고, MIT App Inventor로 개발한 안드로이드 앱으로 원격 제어도 구현합니다.

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

우리 IoT 프로젝트의 "중심"은 ThingSpeak.com입니다. 로컬 유닛(UNO/ESP-01)은 센서와 액추에이터 상태에서 데이터를 수집해 전송하며, ThingSpeak.com의 특정 상태 채널(Status Channel)에 "기록"합니다. 로컬 유닛은 인터넷에서 데이터를 수신해 특정 액추에이터 채널(Actuator Channels)에서 "읽기"도 합니다.

안드로이드 앱도 ThingSpeak.com 상태 채널에서 데이터를 읽어 사용자에게 표시합니다. 사용자는 이 상태 정보를 바탕으로 액추에이터에 명령을 보내 ThingSpeak 액추에이터 채널에 기록합니다 (위 블록 다이어그램의 데이터 흐름 참조).

1단계: 소개

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

일반적인 센서를 사용해 여러 데이터를 수집하고 클라우드로 전송해 인터넷 어디에서든 볼 수 있게 합니다. 데이터 처리는 ThingSpeak.com(오픈 IoT 플랫폼) 서비스를 이용해 수집, 분석, 조치합니다.

센서로 수집할 데이터:

액추에이터 2개:

액추에이터 상태(ON/OFF)도 클라우드로 전송됩니다. 예를 들어 농장의 데이터를 수집해 클라우드로 보내고, 사용자는 다음 기준으로 판단해 원격 제어합니다.

원격 제어를 위해 안드로이드 앱을 사용합니다.

2단계: BoM - 자재 명세서

주요 구성품 링크와 대략적인 가격(USD)은 참고용입니다.

3단계: 하드웨어 구성

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

프로젝트 하드웨어를 조립합니다. 이상적으로는 파트별로 설치하고 테스트하는 것이 좋습니다. 제안 순서:

  1. 모든 센서 로컬 설치 및 테스트
  2. ESP-01 설치 및 설정 (BareMinimum)
  3. ESP-01 최종 구성으로 변경 및 테스트
  4. ThingSpeak 상태 채널 설정
  5. 아두이노에 ThingSpeak 코드 설치 및 클라우드 센서 상태 확인
  6. 상태/메시지 표시용 안드로이드 앱 1차 개발
  7. 액추에이터(LED, 릴레이) 설치
  8. ThingSpeak 액추에이터 채널 설정
  9. 액추에이터 포함 아두이노 코드 설치 및 테스트
  10. 최종 안드로이드 앱 버전 개발

4단계: 센서 연결

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

센서를 제대로 읽으려면 IDE에 라이브러리가 설치되어 있어야 합니다. 초기 설정 예시:

// DS18B20
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 5 // DS18B20 on pin D5
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
int soilTemp = 0;

// DHT
#include "DHT.h"
#include <stdlib.h>
int pinoDHT = 11;
int tipoDHT = DHT22;
DHT dht(pinoDHT, tipoDHT);
int airTemp = 0, airHum = 0;

// LDR (조도)
#define ldrPIN 1
int light = 0;

// 토양 습도
#define soilHumPIN 0
int soilHum = 0;

Setup과 Loop 작성:

void setup() {
  Serial.begin(9600);
  DS18B20.begin();
  dht.begin();
}
void loop() {
  readSensors();
  displaySensors();
  delay(10000);
}

센서 읽기 및 표시 함수:

/********* 센서 값 읽기 *************/
void readSensors(void) {
  airTemp = dht.readTemperature();
  airHum = dht.readHumidity();
  DS18B20.requestTemperatures();
  soilTemp = DS18B20.getTempCByIndex(0);
  soilHum = map(analogRead(soilHumPIN), 1023, 0, 0, 100);
  light = map(analogRead(ldrPIN), 1023, 0, 0, 100);
}

/********* 센서 값 표시 *************/
void displaySensors(void) {
  Serial.print("airTemp (oC): "); Serial.println(airTemp);
  Serial.print("airHum (%): "); Serial.println(airHum);
  Serial.print("soilTemp (oC): "); Serial.println(soilTemp);
  Serial.print("soilHum (%): "); Serial.println(soilHum);
  Serial.print("light (%): "); Serial.println(light);
  Serial.println("");
}
아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

코드 다운로드: GitHub - Sensors_Test.ino

5단계: ESP8266-01 초기 설정

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

ESP-01은 시리얼 브리지로 사용되며 "AT 명령어"로 프로그래밍합니다. 먼저 ESP-01의 보드레이트 통신 속도가 올바른지 확인합니다. 여기서는 9,600 baud를 사용합니다. 보통 공장 출하 시 115,200 baud로 설정되어 있어 변경해야 합니다.

  1. ESP-01을 위와 같이 연결합니다.
  2. 아두이노를 컴퓨터에 연결하고 IDE에서 File > Examples > 01.Basics > BareMinimum 예제를 로드합니다. 이는 아두이노와 ESP 간 시리얼 통신 충돌을 방지하기 위한 빈 코드입니다.
  3. IDE 시리얼 모니터를 열고 속도를 115,200 baud로 변경한 후 "AT" 명령어를 보냅니다. ESP-01이 "OK"를 반환해야 합니다.
  4. 보드레이트 변경: AT+CIOBAUD=9600 또는 AT+UART_DEF=9600,8,1,0,0 (영구 변경)
  5. 시리얼 모니터 속도를 9600 baud로 변경하고 AT 명령어로 테스트합니다.
  6. 스테이션 모드(클라이언트)로 설정: AT+CWMODE=1
  7. WiFi 네트워크 연결: AT+CWJAP="네트워크명","비밀번호"
  8. 연결 성공 시: WIFI CONNECTED / WIFI GOT IP
  9. IP 확인: AT+CIFSR

6단계: ESP-01 테스트

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

ESP-01 설정이 완료되면 최종 회로에 설치합니다. 배선을 아래와 같이 변경합니다.

간단한 테스트 코드로 ESP-01이 올바르게 설치되었는지 확인합니다.

#include <SoftwareSerial.h>
SoftwareSerial esp8266(6,7); //Rx => Pin 6; TX => Pin7
#define speed8266 9600
void setup() {
  esp8266.begin(speed8266);
  Serial.begin(speed8266);
  Serial.println("ESP8266 Setup test - use AT commands");
}
void loop() {
  while(esp8266.available()) Serial.write(esp8266.read());
  while(Serial.available()) esp8266.write(Serial.read());
}

시리얼 모니터에서 AT 명령어 테스트:

* AT      =====> ESP8266 returns OK
* AT+RST  =====> ESP8266 restart and returns OK
* AT+GMR  =====> ESP8266 returns AT Version; SDK version; id; OK
* AT+CWMODE? => ESP8266 returns mode type
* AT+CWLAP ===> ESP8266 returns close access points
* AT+CIFSR ===> ESP8266 returns assigned IP

코드 다운로드: GitHub - ESP_AT_Config.ino

리셋 시마다 자동으로 WiFi에 연결하려면 setup() 끝에 connectWiFi() 호출을 추가하세요.

7단계: 센서와 ESP-01 연결

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

모든 센서와 ESP-01이 테스트 완료되면 인터넷으로 데이터 전송을 위해 통합합니다.

8단계: ThingSpeak 설정

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

ThingSpeak 계정이 없다면 회원가입 후 새 채널을 생성합니다. 2개 액추에이터, 5개 센서, 1개 예비 필드 구성:

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

채널 생성 후 Write/Read API Key를 메모해둡니다.

9단계: 상태 데이터를 클라우드로 전송

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

로컬 센서 데이터를 ThingSpeak에 WRITE합니다. GET 문자열 전송을 3단계로 수행:

  1. 시작 명령: AT+CIPSTART="TCP","184.106.153.149",80
  2. 명령 길이: AT+CIPSEND=116
  3. GET 문자열: GET /update?api_key=YOUR_WRITE_KEY&field1=pump&field2=lamp&field3=airTemp&field4=airHum&field5=soilTemp&field6=soilHum&field7=light&field8=spare

전체 코드는 GitHub - SendingStatusTS_EXT.ino에서 다운로드 가능합니다.

10단계: 안드로이드 앱 1부 - 상태 모니터링

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

MIT App Inventor로 사용자 인터페이스와 블록을 설계합니다. 2초마다(Clock1) "readArduino" 프로시저를 호출해 ThingSpeak 상태 채널을 READ하고 각 필드 값을 전역 변수에 저장해 라벨에 표시합니다. 액추에이터 상태 0/1을 OFF/ON으로 변환해 표시합니다. JSON 파싱으로 각 필드 값을 추출합니다. 토양 센서 상태 분석해 온도 10°C 미만 또는 습도 60% 미만 시 경고 메시지 표시(1초마다 색상 토글로 깜빡임).

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기
아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기
아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

앱 코드 다운로드: GitHub - ArduFarmBot_Status_App_EXT.aia

11단계: 액추에이터(LED, 릴레이) 설치

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

펌프와 램프를 원격 제어하기 위해 릴레이 모듈(옵토커플러, 로우 레벨 트리거)을 사용합니다. 별도 5V 전원으로 릴레이를 구동해 아두이노 핀에 전류 부담을 주지 않습니다. 릴레이 GND는 아두이노 GND와 연결하지 않아 노이즈 유입을 방지합니다.

12단계: ThingSpeak 액추에이터 채널 설정

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

상태 채널과 마찬가지로 액추에이터별 채널 2개 생성 (Field 1만 사용):

13단계: 액추에이터 포함 아두이노 코드 설치 및 테스트

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

이제 ThingSpeak에서 READ해 명령을 수신합니다. 10초 간격으로 액추에이터 채널에서 Field 1의 최신 값을 읽습니다. GET 명령: GET /channels/375598/fields/1/last. 응답에서 '1' 또는 '0'을 파싱해 액추에이터 제어. 핵심 함수는 readThingSpeak(String channelID)입니다. 전체 코드: GitHub - ReadingCommandTS_EXT.ino

14단계: 액추에이터에 명령 전송 (브라우저 테스트)

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

최종 앱 개발 전 브라우저로 테스트 가능:

15단계: 안드로이드 앱 완성

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

액추에이터 채널에 WRITE하는 기능 추가. 각 액추에이터마다 ON/OFF 버튼 쌍을 두고, 버튼 눌림 시 텍스트 색상 변경(ON=파란색, OFF=빨간색). 블록 프로그래밍으로 구현. 앱 테스트 후 시리얼 모니터로 ESP-01과 ThingSpeak 간 통신 확인.

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기
아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

완성 앱 코드: GitHub - ArduFarmBot_V1_EXT.aia

16단계: 전체 통합

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

이제 지속적으로 ThingSpeak를 읽고 쓰는 통합 코드가 필요합니다. ESP-01 동결 방지를 위해 읽기/쓰기 전 AT 명령어로 상태 확인 후 미응답 시 하드웨어 리셋 수행. 최종 통합 코드: GitHub - ArduFarmBot_Light_EXT.ino

17단계: 결론

아두이노 UNO, ESP-01, ThingSpeak, MIT App Inventor로 간단한 IoT 프로젝트 구축하기

아두이노 우노와 ESP8266-01로 IoT 세상을 탐구할 여지가 여전히 많습니다. 새로운 튜토리얼로 다시 찾아뵙겠습니다! 이 프로젝트가 전자공학, 로봇공학, IoT의 흥미로운 세계에서 길을 찾는 분들께 도움이 되길 바랍니다.

업데이트된 파일은 GitHub - ArduFarmBot_Light에서 확인하세요. 더 많은 프로젝트는 MJRoBot.org 블로그를 방문하세요. 남반구에서 인사를 전하며, 다음 튜토리얼에서 뵙겠습니다! 감사합니다, Marcelo

코드 스니펫

코드 스니펫 #1 - 센서 초기화

// DS18B20
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 5
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
int soilTemp = 0;

// DHT
#include "DHT.h"
#include <stdlib.h>
int pinoDHT = 11;
int tipoDHT = DHT22;
DHT dht(pinoDHT, tipoDHT);
int airTemp = 0, airHum = 0;

// LDR (조도)
#define ldrPIN 1
int light = 0;

// 토양 습도
#define soilHumPIN 0
int soilHum = 0;

코드 스니펫 #2 - 기본 루프

void setup() {
  Serial.begin(9600);
  DS18B20.begin();
  dht.begin();
}
void loop() {
  readSensors();
  displaySensors();
  delay(10000);
}

코드 스니펫 #3 - 센서 읽기/표시 함수

/********* Read Sensors value *************/
void readSensors(void) {
  airTemp = dht.readTemperature();
  airHum = dht.readHumidity();
  DS18B20.requestTemperatures();
  soilTemp = DS18B20.getTempCByIndex(0);
  soilHum = map(analogRead(soilHumPIN), 1023, 0, 0, 100);
  light = map(analogRead(ldrPIN), 1023, 0, 0, 100);
}

/********* Display Sensors value *************/
void displaySensors(void) {
  Serial.print("airTemp (oC): "); Serial.println(airTemp);
  Serial.print("airHum (%): "); Serial.println(airHum);
  Serial.print("soilTemp (oC): "); Serial.println(soilTemp);
  Serial.print("soilHum (%): "); Serial.println(soilHum);
  Serial.print("light (%): "); Serial.println(light);
  Serial.println("");
}

코드 스니펫 #11 - ESP-01 AT 테스트

#include <SoftwareSerial.h>
SoftwareSerial esp8266(6,7);
#define speed8266 9600
void setup() {
  esp8266.begin(speed8266);
  Serial.begin(speed8266);
  Serial.println("ESP8266 Setup test - use AT commands");
}
void loop() {
  while(esp8266.available()) Serial.write(esp8266.read());
  while(Serial.available()) esp8266.write(Serial.read());
}

코드 스니펫 #12 - AT 명령어 응답

* AT      =====> ESP8266 returns OK
* AT+RST  =====> ESP8266 restart and returns OK
* AT+GMR  =====> ESP8266 returns AT Version; SDK version; id; OK
* AT+CWMODE? => ESP8266 returns mode type
* AT+CWLAP ===> ESP8266 returns close access points
* AT+CIFSR ===> ESP8266 returns assigned IP

코드 스니펫 #16 - 상태 데이터 전송 전체 코드

// Thingspeak
String statusChWriteKey = "6SRPQQKIE6AJVQE6"; // Status Channel id: 385184
#include <SoftwareSerial.h>
SoftwareSerial EspSerial(6, 7); // Rx, Tx
#define HARDWARE_RESET 8
// DS18B20
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 5
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
int soilTemp = 0;
// DHT
#include "DHT.h"
#include <stdlib.h>
int pinoDHT = 11;
int tipoDHT = DHT22;
DHT dht(pinoDHT, tipoDHT);
int airTemp = 0, airHum = 0;
// LDR (조도)
#define ldrPIN 1
int light = 0;
// 토양 습도
#define soilHumPIN 0
int soilHum = 0;
// 타이머 변수
long writeTimingSeconds = 17;
long startWriteTiming = 0, elapsedWriteTime = 0;
// 액추에이터 변수
boolean pump = 0, lamp = 0;
int spare = 0;
boolean error;

void setup() {
  Serial.begin(9600);
  pinMode(HARDWARE_RESET, OUTPUT);
  digitalWrite(HARDWARE_RESET, HIGH);
  DS18B20.begin();
  dht.begin();
  EspSerial.begin(9600);
  EspHardwareReset();
  startWriteTiming = millis();
}

void loop() {
  start:
  error = 0;
  elapsedWriteTime = millis() - startWriteTiming;
  if (elapsedWriteTime > (writeTimingSeconds * 1000)) {
    readSensors();
    writeThingSpeak();
    startWriteTiming = millis();
  }
  if (error == 1) {
    Serial.println(" <<<< ERROR >>>>");
    delay(2000);
    goto start;
  }
}

// ... (이하 writeThingSpeak, EspHardwareReset, startThingSpeakCmd, sendThingSpeakGetCmd 함수 생략 - GitHub 참조)

코드 스니펫 #20 - 액추에이터 명령 수신 전체 코드

// Thingspeak
String canalID1 = "375598"; // Actuator1
String canalID2 = "375599"; // Actuator2
#include <SoftwareSerial.h>
SoftwareSerial EspSerial(6, 7);
#define HARDWARE_RESET 8
// 타이머 변수
long readTimingSeconds = 10;
long startReadTiming = 0, elapsedReadTime = 0;
// 릴레이
#define ACTUATOR1 10 // RED LED => Pump
#define ACTUATOR2 12 // GREEN LED => Lamp
boolean pump = 0, lamp = 0;
int spare = 0;
boolean error;

void setup() {
  Serial.begin(9600);
  pinMode(ACTUATOR1, OUTPUT);
  pinMode(ACTUATOR2, OUTPUT);
  pinMode(HARDWARE_RESET, OUTPUT);
  digitalWrite(ACTUATOR1, HIGH); // 릴레이 모듈은 LOW 액티브
  digitalWrite(ACTUATOR2, HIGH);
  digitalWrite(HARDWARE_RESET, HIGH);
  EspSerial.begin(9600);
  EspHardwareReset();
  startReadTiming = millis();
}

void loop() {
  start:
  error = 0;
  elapsedReadTime = millis() - startReadTiming;
  if (elapsedReadTime > (readTimingSeconds * 1000)) {
    int command = readThingSpeak(canalID1);
    if (command != 9) pump = command;
    delay(5000);
    command = readThingSpeak(canalID2);
    if (command != 9) lamp = command;
    takeActions();
    startReadTiming = millis();
  }
  if (error == 1) {
    Serial.println(" <<<< ERROR >>>>");
    delay(2000);
    goto start;
  }
}

// ... (이하 takeActions, readThingSpeak, EspHardwareReset, startThingSpeakCmd, sendThingSpeakGetCmd 함수 생략 - GitHub 참조)

GitHub 저장소

https://github.com/Mjrovai/ArduFarmBot_Light

회로도

전기 회로도

Fritzing 파일 다운로드

제조공정

  1. 라즈베리 파이 4B+ IoT 보드에서 병렬 C++17 SYCL 코드 빌드하기
  2. 아두이노와 MAX30100으로 만드는 실시간 IoT 심박수 모니터
  3. 아두이노 우노 와이파이 웹 서버: 브라우저로 LED 제어하기
  4. 아두이노 우노로 기초 계산기 만들기 - 쉬운 프로젝트
  5. 아두이노 우노와 ATtiny85로 만드는 휴대용 POV(잔상) 디스플레이
  6. 비접촉 체온 측정 게이트: 아두이노 MKR1000으로 구현하는 자동 발열 검사 시스템
  7. 아두이노 우노 & WiFi 실드로 웹에서 실시간 온도 모니터링 - 시리얼 통신 활용
  8. 아두이노 & ThingSpeak로 실시간 날씨 모니터링 IoT 구축
  9. 서미스터(NTC) 온도 센서 아두이노 활용 완전 정복 - 수식부터 구현까지
  10. 애저 IoT 기반 스마트 수영장 제어 시스템: 온도 모니터링 및 원격 제어