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

UNO, ESP-01, ThingSpeak 및 MIT 앱 발명가로 IoT를 쉽게 만들 수 있습니다.

구성품 및 소모품

Arduino UNO
× 1
Espressif ESP8266 ESP-01
× 1
DHT22 온도 센서
× 1
DS18B20 토양에서 사용하기 위한 1-Wire 디지털 온도 센서
× 1
LDR - 광 종속 저항기
× 1
2채널 DC 5V 릴레이 모듈
× 1

앱 및 온라인 서비스

Arduino IDE
ThingSpeak API
MIT 앱 발명가

이 프로젝트 정보

우리의 목표는 기본적으로 지역 단위에서 정보를 수집하여 인터넷으로 보내는 것입니다. 이 정보를 보고 있는 지구상의 어느 곳에서든 사용자는 원격 명령을 이 로컬 장치에도 있는 액추에이터에 전송하여 결정을 내릴 것입니다. 모든 센서 또는 액추에이터를 사용할 수 있습니다.

IoT 분야에 대한 제 작업의 대부분은 NodeMCU와 최근에는 ESP32를 사용하는 것이었습니다. 하지만 몇 년 전 Arduino UNO와 오래되고 좋은 ESP8266-01을 사용하여 IoT를 배우기 시작한 초기 단계를 잊지 않는 것이 중요하다고 생각합니다.

그래서 저는 여기에서 (지금은 경험이 조금 더 쌓이면서) 그 당시로 돌아가서 ThingSpeak.com 웹 서비스를 사용하여 클라우드에 연결하고 멋진 장치를 다시 탐색하기로 결정했습니다. 또한 MIT AppInventor를 사용하여 개발한 Android 앱을 사용하여 원격으로 사물을 제어하는 ​​방법도 살펴보겠습니다.

"우리 IoT 프로젝트의 중심"은 ThingSpeak.com이 될 것입니다. 로컬 장치(UNO/ESP-01)는 센서 및 액추에이터 상태에서 데이터를 캡처하여 전송 합니다. 특정 ThingSpeak.com에 "쓰기" 상태 채널 . 지역 단위도 수신 인터넷의 데이터, 특정 ThingSpeak Actuator 채널에서 "읽기" .

Android 앱은 읽기도 됩니다. ThingSpeak.com 상태 채널의 데이터 및 사용자를 위해 이를 표시하는 단계를 포함합니다. 같은 방식으로 사용자는 해당 상태 정보를 기반으로 액츄에이터에 명령을 보낼 수 있습니다. 쓰기 ThingSpeak Actuator 채널에 있습니다(데이터 흐름을 더 잘 이해하려면 위의 블록 다이어그램 참조).

그래서, 우리는 무엇을 할 것인가? 다음 단계에 표시된 블록 다이어그램은 최종 프로젝트에 대한 개요를 제공합니다.

1단계:소개

우리 프로젝트는 공통 센서를 사용하여 여러 데이터를 캡처하여 모든 사람이 인터넷을 통해 볼 수 있는 클라우드로 보냅니다. 이러한 데이터를 처리하기 위해 당사는 해당 데이터를 수집, 분석 및 조치할 수 있는 개방형 IoT 플랫폼인 ThingSpeak.com에서 제공하는 서비스를 사용할 것입니다.

센서가 수집할 데이터

<울>
  • 기온 및 상대 습도
  • <울>
  • 토양 온도 및 습도
  • <울>
  • 광도
  • 프로젝트에는 2명의 액추에이터가 있습니다. :

    <울>
  • 전기 펌프
  • <울>
  • 전기 램프
  • 해당 액추에이터의 상태("ON/OFF")도 클라우드로 전송되어야 합니다.

    따라서 아이디어는 예를 들어 농장과 같은 센서에서 이러한 데이터를 캡처하여 클라우드로 보내는 것입니다. 이러한 데이터를 기반으로 사용자는 다음 진술을 기반으로 결정을 내려야 합니다.

    <울>
  • 토양 습도가 너무 낮으면 펌프를 켜십시오.
  • <울>
  • 토양 온도가 너무 낮으면 램프를 켭니다.
  • 액추에이터를 원격으로 명령하기 위해 Android 앱을 사용합니다.

    2단계:BoM - BOM

    여기에 나열된 가장 중요한 구성 요소 중 일부에는 링크와 USD의 표시 가격이 있습니다. 해당 링크는 정보용입니다.

    <울>
  • Arduino UNO(마이크로컨트롤러) - $10.00
  • <울>
  • ESP8266-01(통신 모듈) - $3.50
  • <울>
  • DHT22(공기 및 상대 습도 센서) - $9.00
  • <울>
  • DS18B20(토양용 1-Wire 디지털 온도 센서) - $6.00
  • <울>
  • YL-69 + LM393(토양 습도 센서) - $2.00
  • <울>
  • LDR(광도 센서) - $0.20
  • <울>
  • 2 x LED(빨간색 및 녹색)
  • <울>
  • 1 x 2 채널 DC 5V 릴레이 모듈(옵토커플러 로우 레벨 트리거 포함) - $7.00
  • <울>
  • 5V DC 펌프 - $3.00
  • <울>
  • 220V 램프
  • <울>
  • 2 x 330ohm 저항기(LED와 함께 사용)
  • <울>
  • 2 x 10K 옴 저항기(DHT22 및 LDR과 함께 사용)
  • <울>
  • 1 x 4K7 옴 저항(DS18B20과 함께 사용됨
  • <울>
  • 프로토보드
  • <울>
  • 점퍼
  • <울>
  • 릴레이용 외부 5V DC 전원
  • 3단계:하드웨어

    Project HW를 조립해 봅시다. 이상적인 것은 부품별로 프로젝트를 설치하고 테스트하는 것입니다. 제안 사항으로 다음 단계를 수행할 수 있습니다.

    <울>
  • 모든 센서를 로컬에 설치 및 테스트
  • <울>
  • ESP-01 설치 및 구성(최소)
  • <울>
  • 최종 구성을 위해 ESP-01 설치를 변경하고 테스트합니다.
  • <울>
  • ThingsPeak 상태 채널 구성
  • <울>
  • Arduino에 ThingsPeak 코드를 설치하고 클라우드에서 센서 상태 확인
  • <울>
  • 상태 및 메시지를 표시하는 Android 앱의 첫 번째 버전 개발
  • <울>
  • 액츄에이터(LED 및 릴레이) 설치
  • <울>
  • ThingSpeak Actuators 채널 구성
  • <울>
  • 액추에이터로 Arduino 코드 설치 및 테스트
  • <울>
  • 최종 Android 앱 버전 개발
  • 4단계:센서 연결

    센서를 제대로 읽으려면 IDE에 일부 라이브러리가 설치되어 있어야 합니다. 모든 라이브러리가 설치되어 있는지 확인하십시오. 초기 구성은 다음과 같아야 합니다.

    // DS18B20#include #include #define ONE_WIRE_BUS 5 // 핀 D5의 DS18B20 OneWire oneWire(ONE_WIRE_BUS);DallasTemperature DS18B20;0(&oneWire) //DHT#include "DHT.h#include int pinoDHT =11;int tipoDHT =DHT22;DHT dht(pinoDHT, tipoDHT); int airTemp =0;int airHum =0;// LDR(Light)#define ldrPIN 1int light =0;// 토양 습도#define 흙HumPIN 0int 흙Hum =0; 

    설정 및 루프에서 다음을 작성해 보겠습니다.

    <사전><코드> 무효 설정(){ Serial.begin(9600); DS18B20.begin(); dht.begin();} 무효 루프(){ readSensors(); 디스플레이 센서(); 지연(10000);}

    그리고 마지막으로 두 가지 특정 함수를 작성해 보겠습니다. 하나는 센서를 읽고 다른 하나는 직렬 모니터에 값을 표시하는 것입니다.

    /************ 센서 값 읽기 *************/void readSensors(void){ airTemp =dht.readTemperature(); airHum =dht.readHumidity(); DS18B20.requestTemperatures(); 토양 온도 =DS18B20.getTempCByIndex(0); // 센서 0은 섭씨 섭씨의 토양 온도를 캡처할 것입니다.oilHum =map(analogRead(soilHumPIN), 1023, 0, 0, 100); 빛 =지도(analogRead(ldrPIN), 1023, 0, 0, 100); //LDRDark:0 ==> light 100% }/************ 디스플레이 센서 값 *************/void displaySensors(void){ Serial.print(" 공기 온도(oC):"); Serial.println(공기 온도); Serial.print("에어흠(%):"); Serial.println(airHum); Serial.print("soilTemp(oC):"); Serial.println(토양 온도); Serial.print("soilHum(%):"); Serial.println(soilHum); Serial.print("빛(%):"); Serial.println(빛); Serial.println("");} 

    아래 시리얼 모니터 사진은 센서 값을 보여줍니다.

    내 GITHUB:Sens ors_Test.ino

    에서 코드를 다운로드할 수 있습니다.

    5단계:ESP8266-01 초기 구성

    ESP-01은 직렬 브리지로 사용됩니다. 즉, " AT 명령"을 사용하여 프로그래밍합니다. 첫 번째는 ESP-01이 올바른 전송 속도 통신 속도에 있는지 확인하는 것입니다. 우리의 경우 9,600 보오입니다. 일반적으로 ESP-01은 공장에서 115,200보드로 프로그래밍되어 있으며 9,600보드로 변경해야 합니다.

    먼저 위와 같이 ESP-01을 연결해야 합니다.

    그런 다음 Arduino를 컴퓨터에 연결하고 IDE를 열고 File> Examples> 01.Basics> BareMinimum에있는 예제를로드하십시오. 이것은 Arduino와 ESP 사이에 통신 충돌이 없도록 하기 위한 빈 코드입니다.

    Arduino가 직렬 통신(TX 및 RX)을 사용하지 않도록 ESP-01S에 연결하기 전에 이 코드를 Arduino로 전송했습니다. 이것은 ESP가 제대로 통신할 수 있도록 하는 데 중요합니다.

    IDE 직렬 모니터를 열고 속도를 115,200보드로 변경합니다. IDE 직렬 모니터에서 "AT" 명령을 보내기 시작합니다. ESP-01은 "OK"를 반환해야 합니다.

    다음으로 속도를 변경해 보겠습니다. 이를 위해 다음 명령을 사용할 수 있습니다.

    AT + CIOBAUD =9600 

    ESP-01은 공장 프로그래밍으로 돌아갈 수 있습니다(FW 버전 때문인지는 모르겠습니다). 적어도 제 경우에는 BaudRate를 결정적으로 변경하려면 다른 명령을 사용해야 했습니다.

    AT+ UART_DEF=,,,, 

    예:9600 보드 / 8 데이터 비트 / 1 정지 비트 및 패리티 및 흐름 제어 없음:

    AT + UART_DEF =9600,8,1,0,0 

    직렬 모니터 하단의 선택 상자에서 속도를 "9600 baud"로 변경하십시오. 통신 테스트:창 상단에서 AT를 입력하고 확인 응답을 확인합니다. 이제 스테이션 모드에서 모듈을 구성해야 합니다. 고객 역할 당신의 Wi-Fi 네트워크의. 다음 명령을 사용하십시오.

     AT + CWMODE =1 

    이제 모듈을 Wi-Fi 네트워크에 연결해야 합니다.

    이렇게 하려면 아래 명령을 사용하여 "network_name"을 Wi-Fi 네트워크 이름으로 바꾸고 "network_name"을 암호로 바꿉니다. 따옴표를 유지하십시오.

    AT + CWJAP ="네트워크 이름", "네트워크 이름"  

    아래 답변이 표시되면 연결이 올바르게 설정된 것입니다.

    WIFI 연결 WIFI GOT IP 

    IP를 찾으려면 다음 명령을 실행하십시오.

    AT + CIFSR  

    그리고 시리얼 모니터에 나타날 IP 주소를 기록해 두십시오. 나중에 필요할 수도 있습니다.

    6단계:ESP-01 테스트

    ESP-01을 구성했으면 최종 회로에 설치해야 합니다. 이를 위해 이전에 수행한 배선을 변경하고 ESP-01을 아래와 같이 UNO에 연결해야 합니다.

    <울>
  • ESP-01 RX(노란색) - UNO 핀 D7
  • <울>
  • ESP-01 TX(주황색) - UNO 핀 D6
  • <울>
  • ESP-01 Ch-Pd(갈색)에서 Vcc(3.3V)로
  • <울>
  • ESP-01 리셋(파란색)을 UNO 핀 D8로
  • <울>
  • ESP-01 Vcc(빨간색) ~ 3.3V
  • <울>
  • ESP-01 Gnd(검정색)에서 UNO GND로
  • ESP-01이 올바르게 설치되고 테스트되었는지 확인하기 위해 간단한 테스트를 해보자. 아래 코드를 입력하세요:

    #include  SoftwareSerial esp8266(6,7); //Rx ==> 핀 6; TX ==> Pin7 #define speed8266 9600 void setup() { esp8266.begin (speed8266); Serial.begin(speed8266); Serial.println("ESP8266 설정 테스트 - AT coomands 사용");}void loop() { while(esp8266.available()) { Serial.write(esp8266.read()); } 동안(Serial.available()) { esp8266.write(Serial.read()); }} 

    이제 몇 가지 AT 명령을 시도하고 직렬 모니터에서 결과를 확인하십시오.

    * AT =====> ESP8266은 OK*를 반환합니다. AT+RST =====> ESP8266은 다시 시작하고 OK*를 반환합니다. AT+GMR =====> ESP8266은 AT Version을 반환합니다. SDK 버전; ID; OK* AT+CWMODE? => ESP8266은 모드 유형*을 반환합니다. AT+CWLAP ===> ESP8266은 가까운 액세스 포인트를 반환합니다.* AT+CIFSR ===> ESP8266은 지정된 IP를 반환합니다. 

    코드는 내 GITHUB:ESP_AT_Config.ino

    에서 다운로드할 수 있습니다.

    재설정이 발생할 때마다(또는 Arduino가 꺼지거나 켜질 때마다) WiFi 네트워크에 연결하고 자격 증명을 입력하려면 connectWiFi() 호출을 추가하세요. 설정() 함수의 끝에서 함수:

    setup(){ ... connectWiFi(); } 

    connectWiFi() 함수는 메인 코드의 끝에 있어야 합니다. .ino:

    무효 connectWiFi(무효){ sendData("AT+RST\r\n", 2000, 0); // 재설정 sendData("AT+CWJAP=\"사용자 이름\",\"암호\"\r\n", 2000, 0); //네트워크 연결 지연(3000); sendData("AT+CWMODE=1\r\n", 1000, 0); sendData("AT+CIFSR\r\n", 1000, 0); // IP 주소 표시 Serial.println("8266 Connected");} 

    위의 함수는 다른 sendData(data)를 호출합니다. 코드에도 있어야 하는 함수:

    String sendData(문자열 명령, const int timeout, 부울 디버그){ 문자열 응답 =""; EspSerial.print(명령); 긴 int 시간 =millis(); while ( (time + timeout)> millis()) { while (EspSerial.available()) { // esp에는 데이터가 있으므로 출력을 직렬 창에 표시합니다. char c =EspSerial.read(); // 다음 문자를 읽습니다. 응답 +=c; } } if(디버그) { Serial.print(응답); } 반환 응답;}  

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

    모든 센서를 설치하고 테스트하고 ESP-01도 제대로 작동했으면 모두 함께 살펴보고 인터넷에 데이터를 보낼 준비를 합시다.

    8단계:The ThingSpeak

    우리 프로젝트의 가장 중요한 부분 중 하나는 수집된 데이터를 수집, 분석 및 실행할 수 있는 개방형 IoT 플랫폼인 ThingSpeak입니다. 아직 계정이 없다면 ThingSpeak 가입으로 이동하여 계정을 만드십시오.

    다음으로 2개의 액추에이터, 5개의 센서 및 예비 필드 상태가 있는 새 채널을 만듭니다.

    <울>
  • 필드 1:액추에이터 1
  • <울>
  • 필드 2:액추에이터 2
  • <울>
  • 필드 3:oC의 기온
  • <울>
  • 출원 4:대기 상대 습도(%)
  • <울>
  • 필드 5:oC의 토양 온도
  • <울>
  • 필드 6:토양 습도(%)
  • <울>
  • 필드 7:광도(%)
  • <울>
  • 필드 8:예비
  • 필드 8은 향후 확장 또는 디버그 목적으로 사용하기 위해 예비로 남게 됩니다. 예를 들어, ThingSpeak.com과 Arduino/ESP-01 핸드셰이크 중에 발생하는 각 통신 오류에 대한 "카운터"로 사용하겠습니다.

    채널을 만들면(이 경우 상태 채널이 됨) 아래와 같이 키를 기록해 두는 것이 중요합니다.

    9단계:클라우드에 상태 보내기

    이 시점에서 클라우드 서비스를 사용할 수 있고 센서가 로컬에서 데이터를 캡처합니다. 해당 값을 가져와 ThingSpeak.com으로 보내 보겠습니다. 우리는 ThingSpeak 채널에 쓸 것이고 이를 위해 GET 문자열을 보내야 할 것입니다. 우리는 3 부분으로 할 것입니다:

    "시작 cmd"를 보내드립니다:

    AT+CIPSTART="TCP","184.106.153.149",80 

    명령의 "길이" 다음:

    AT+CIPSEND=116 

    상태 채널의 해당 필드에 쓸 GET 문자열 자체:

    GET /update?api_key=YOUR_WRITE_KEY_HERE&field1=pump&fieldlamp=0&field3=airTemp&field4=airHum&field5=soilTemp&field6=soilHum&field7=light&field8=예비

    아래 코드는 우리를 위해 작업을 수행하고 위의 PrintScreen은 직렬 모니터에 결과를 보여줍니다:

    // Thingspeak 문자열 statusChWriteKey ="6SRPQQKIE6AJVQE6"; // 상태 채널 ID:385184#include SoftwareSerial EspSerial(6, 7); // 토양 수신, Tx#define HARDWARE_RESET 8// DS18B20#include #include #define ONE_WIRE_BUS 5 // 핀 D5의 DS18B20 OneWire oneWire(ONE_WIRE_BUS);DallasTemperature =0;//DHT#include "DHT.h#include int pinoDHT =11;int tipoDHT =DHT22;DHT dht(pinoDHT, tipoDHT); int airTemp =0;int airHum =0;// LDR(Light)#define ldrPIN 1int light =0;// 토양 습도#define 흙HumPIN 0int 흙Hum =0;// 타이머와 함께 사용할 변수 writeTimingSeconds =17; // ==> 데이터를 보낼 샘플 시간을 초 단위로 정의합니다.long startWriteTiming =0;long elapsedWriteTime =0;// Actuatorsboolean pump =0과 함께 사용할 변수; 부울 램프 =0; int 예비 =0; 부울 오류; 무효 setup(){ Serial.begin(9600); 핀모드(하드웨어_리셋,출력); 디지털 쓰기(하드웨어_리셋, 높음); DS18B20.begin(); dht.begin(); EspSerial.begin(9600); // Comunicacao com 모듈로 WiFi EspHardwareReset(); // 모듈로 WiFi 재설정 startWriteTiming =millis(); // "프로그램 시계" 시작}void loop(){ start://label error=0; 경과된WriteTime =millis()-startWriteTiming; if (elapsedWriteTime> (writeTimingSeconds*1000)) { readSensors(); writeThingSpeak(); startWriteTiming =밀리(); } if (error==1) //전송이 완료되지 않으면 재전송 { Serial.println(" <<<>>>"); 지연(2000); 고토 시작; //레이블 "시작"으로 이동 }}/********* 센서 값 읽기 *************/void readSensors(void){ airTemp =dht.readTemperature(); airHum =dht.readHumidity(); DS18B20.requestTemperatures(); 토양 온도 =DS18B20.getTempCByIndex(0); // 센서 0은 섭씨 온도에서 토양 온도를 캡처합니다. light =map(analogRead(ldrPIN), 1023, 0, 0, 100); //LDRDark:0 ==> 빛 100% 흙흠 =map(analogRead(soilHumPIN), 1023, 0, 0, 100); }/************ Conexao com TCP com Thingspeak *******/void writeThingSpeak(void){ startThingSpeakCmd(); // 문자열 준비 GET String getStr ="GET /update?api_key="; getStr +=statusChWriteKey; getStr +="&필드1="; getStr +=문자열(펌프); getStr +="&필드2="; getStr +=문자열(램프); getStr +="&field3="; getStr +=문자열(공기 온도); getStr +="&필드4="; getStr +=문자열(에어흠); getStr +="&필드5="; getStr +=문자열(토양 온도); getStr +="&필드6="; getStr +=String(soilHum); getStr +="&field7="; getStr +=문자열(빛); getStr +="&필드8="; getStr +=문자열(예비); getStr +="\r\n\r\n"; sendThingSpeakGetCmd(getStr); }/************ ESP 재설정 *************/void EspHardwareReset(void){ Serial.println("재설정 중......."); 디지털 쓰기(하드웨어_리셋, 낮음); 지연(500); 디지털 쓰기(하드웨어_리셋, 높음); delay(8000);// Tempo necessário para começar a ler Serial.println("RESET"); }/************ ThingSpeak*************/void startThingSpeakCmd(void){ EspSerial.flush();//limpa o buffer antes de começar a gravar 문자열 cmd ="AT+CIPSTART=\"TCP\",\""; cmd +="184.106.153.149"; // Endereco IP de api.thingspeak.com cmd +="\",80"; EspSerial.println(cmd); Serial.print("enviado ==> cmd 시작:"); 직렬.println(cmd); if(EspSerial.find("오류")) { Serial.println("AT+CIPSTART 오류"); 반품; }}/********* GET cmd를 ThingSpeak로 전송 *************/String sendThingSpeakGetCmd(String getStr){ String cmd ="AT+CIPSEND="; cmd +=문자열(getStr.length()); EspSerial.println(cmd); Serial.print("enviado ==> cmd 길이:"); 직렬.println(cmd); if(EspSerial.find((char *)">")) { EspSerial.print(getStr); Serial.print("enviado ==> getStr:"); 직렬.println(getStr); delay(500);//처리기의 템포 o GET, sem este delay apresenta busy no proximo comando String messageBody =""; while (EspSerial.available()) { 문자열 줄 =EspSerial.readStringUntil('\n'); if (line.length() ==1) { //실제 내용은 빈 줄(길이가 1) 이후에 시작됩니다. messageBody =EspSerial.readStringUntil('\n'); } } Serial.print("MessageBody 수신:"); Serial.println(messageBody); 반환 messageBody; } else { EspSerial.println("AT+CIPCLOSE"); // 경고 사용자 Serial.println("ESP8266 CIPSEND 오류:재전송"); //재전송... 예비 =예비 + 1; 오류=1; "오류"를 반환합니다. } }  

    코드는 내 GITHUB:SendingStatusTS_EXT.ino

    에서 다운로드할 수 있습니다.

    10단계:Android 앱 첫 번째 부분 - 상태 모니터링

    Android 앱의 첫 번째 부분을 만들어 보겠습니다.

    먼저 사용자 인터페이스를 디자인합니다. 위의 인쇄 화면은 주요 보이는 요소와 보이지 않는 요소를 보여줍니다. 그런 다음 블록을 설계해야 합니다(아래 숫자는 위 그림에 해당).

    2초마다(Clock1에 의해 정의됨) "readArduino"라는 프로시저를 호출합니다.

    <울>
  • 이러한 절차의 반환은 화면에 표시되어야 하는 각 상태 변수에 대한 값입니다.
  • <울>
  • 더 나은 이해를 위해 액추에이터 상태에서 "0"과 "1" 값을 "OFF" 및 "ON"으로 "변환"합니다.
  • <울>
  • 해당 값("상태")은 해당 "레이블"에 표시됩니다.
  • <울>
  • 상태 변수는 전역으로 선언되어야 합니다.
  • <울>
  • "readArduino" 절차는 실제로 ThingSpeak에서 상태 채널을 읽습니다. 따라서 Thingspeak에 보낼 URL을 정의해야 합니다. 이를 위해 3개의 전역 변수를 선언하고 결합하여 TS로 보낼 URL을 생성해야 합니다. "ArduFarmBotStatusCh"라는 웹 구성 요소로 GET을 보내야 합니다.
  • <울>
  • 이전 명령에서 가져온 텍스트는 JSon 형식으로 도착합니다. 이 텍스트는 각 필드를 읽고 해당 전역 변수에 저장하도록 처리해야 합니다.
  • <울>
  • 마지막으로 수행할 작업은 두 개의 토양 센서의 상태를 분석하는 "알람" 절차를 호출하는 것입니다. 온도가 너무 낮으면(이 경우 10oC) 메시지가 표시되어야 합니다. 습도가 60% 미만인 경우에도 동일합니다. 1초마다 실행되도록 프로그래밍된 다른 타이머(Clock2)를 정의했습니다. 이것은 메시지 텍스트의 색상(흰색에서 빨간색으로)을 "전환"하기 위한 것입니다. 이렇게 하면 메시지가 "깜박거립니다".
  • 위의 마지막 사진은 최종 앱이 작동하는 모습을 보여줍니다.

    앱 코드는 내 GITHUB:ArduFarmBot_Status_App_EXT.aia

    에서 다운로드할 수 있습니다.

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

    HW를 완성해 봅시다.

    이를 위해 Actuator를 설치해야 합니다. 기억하시겠지만 원격으로 펌프와 램프를 켜고 끄라는 명령을 받게 됩니다. Arduino 출력은 릴레이(및 LED)를 활성화하여 이러한 작업을 수행합니다.

    우리는 Optocoupler Low-Level Trigger가 있는 Relay 모듈을 사용할 것입니다. 또한 별도의 핀을 통해 5V를 공급하므로 입력 핀에 필요한 전류를 공급할 필요가 없습니다. 모듈은 우리를 위해 그것을 합니다.

    위의 그림은 액츄에이터가 어떻게 연결되어야 하는지 보여줍니다. Realy GND는 Arduino GND에 연결되어 있지 않습니다. 이렇게 하면 릴레이가 작동할 때 노이즈가 발생하지 않는 데 도움이 됩니다.

    단순화를 위해 다이어그램에서 센서를 꺼냈습니다. 그러나 이미 설치하고 테스트한 센서를 제거하지 않고 프로젝트에 액추에이터 회로를 추가할 수 있습니다.

    12단계:ThingSpeak 액추에이터 채널 구성

    상태에 대해 했던 것과 같은 방식으로 각 액추에이터에 대해 하나씩 2개의 새 채널을 생성합니다. 각각에서 채널 ID, 읽기 및 쓰기 키를 기록해 둡니다. 필드 1에만 작성합니다. 각 채널의 예를 들어 제 경우:

    채널 ID 375598 ==> LED 빨간색(펌프)

    <울>
  • 필드1 =0 ==> 펌프 끄기
  • <울>
  • 필드1 =1 ==> 펌프 켜짐
  • 채널 ID 375599 ==> LED 녹색(램프)

    <울>
  • 필드1 =0 ==> 램프 꺼짐
  • <울>
  • 필드1 =1 ==> 램프 켜짐
  • 13단계:액추에이터로 Arduino 코드 설치 및 테스트

    웹에 데이터를 보낼 때 우리가 한 일은 ThingSpeak 채널(채널 상태)에 WRITE하여 데이터를 "전송"(업로드)하는 것이었습니다. 이제 ThingSpeak 채널(액츄에이터 채널)에서 데이터를 "수신"(다운로드)해야 합니다.

    ThingSpeak 채널에서 읽을 것이며 이를 위해 GET 문자열을 보내야 합니다. 우리는 3 부분으로 할 것입니다:

    "시작 cmd"를 보내드립니다:

    AT+CIPSTART="TCP","184.106.153.149",80 

    명령의 "길이" 다음:

    AT+CIPSEND=36 

    그리고 각각의 액츄에이터 채널의 필드 1에서 읽는 GET 문자열 자체:

    GET /channels/375598/fields/1/last 

    10초 간격으로 ThingSpeak 채널에서 읽을 것입니다. 위의 GET 명령을 보낸 후 "LAST VALUE STORED ON FIELD 1"을 호출하는 응답의 특정 위치에 대해 "1" 또는 "0"이어야 하는 ThingSpeak의 응답을 받게 됩니다. 도착하면 무시해야 합니다.

    코드의 이 부분과 이전 부분(상태 데이터 보내기)의 주요 차이점은 다음과 같은 기능입니다.

    readThingSpeak(문자열 채널 ID) 

    아래 코드는 우리를 위해 작업을 수행하고 위의 PrintScreen은 직렬 모니터에 결과를 보여줍니다:

    // Thingspeak 문자열 canalID1 ="375598"; //Actuator1String canalID2 ="375599"; //액츄에이터2#include SoftwareSerial EspSerial(6, 7); // Rx, Tx#define HARDWARE_RESET 8// timerslong과 함께 사용할 변수 readTimingSeconds =10; // ==> 데이터 수신을 위한 샘플 시간(초) 정의long startReadTiming =0;long elapsedReadTime =0;//Relays#define ACTUATOR1 10 // RED LED ==> Pump#define ACTUATOR2 12 // GREEN LED ==> Lampboolean 펌프 =0; 부울 램프 =0; int 예비 =0; 부울 오류; 무효 setup(){ Serial.begin(9600); 핀모드(ACTUATOR1,OUTPUT); 핀모드(ACTUATOR2,OUTPUT); 핀모드(하드웨어_리셋,출력); 디지털 쓰기(ACTUATOR1, HIGH); // 모듈과 관련하여 LOW digitalWrite(ACTUATOR2, HIGH); // 모듈과 관련하여 LOW digitalWrite(HARDWARE_RESET, HIGH); EspSerial.begin(9600); // Comunicacao com 모듈로 WiFi EspHardwareReset(); // 모듈로 WiFi 재설정 startReadTiming =millis(); // "프로그램 시계" 시작}void loop(){ start://label error=0; elapsedReadTime =millis()-startReadTiming; if (elapsedReadTime> (readTimingSeconds*1000)) { int 명령 =readThingSpeak(canalID1); if (명령 !=9) 펌프 =명령; 지연(5000); 명령 =readThingSpeak(canalID2); if (명령 !=9) 램프 =명령; 테이크액션(); 읽기 시작 시간 =밀리(); } if (error==1) //전송이 완료되지 않으면 재전송 { Serial.println(" <<<>>>"); 지연(2000); 고토 시작; //레이블 "시작"으로 이동 }}/********* ThingSpeak 명령에 따라 작업 수행 *************/void takeActions(void){ Serial.print( "펌프:"); Serial.println(펌프); Serial.print("램프:"); Serial.println(램프); if (펌프 ==1) digitalWrite(ACTUATOR1, LOW); 그렇지 않으면 digitalWrite(ACTUATOR1, HIGH); if (램프 ==1) digitalWrite(ACTUATOR2, LOW); else digitalWrite(ACTUATOR2, HIGH);}/************ ThingSpeak에서 액추에이터 명령 읽기 *************/int readThingSpeak(String channelID){ startThingSpeakCmd(); 정수 명령; // 문자열 준비 GET String getStr ="GET /channels/"; getStr +=채널ID; getStr +="/필드/1/마지막"; getStr +="\r\n"; 문자열 messageDown =sendThingSpeakGetCmd(getStr); if (messageDown[5] ==49) { 명령 =messageDown[7]-48; Serial.print("명령 수신:"); Serial.println(명령어); } 그렇지 않으면 명령 =9; return command;}/********* ESP 재설정 *************/void EspHardwareReset(void){ Serial.println("재설정 중......." ); 디지털 쓰기(하드웨어_리셋, 낮음); 지연(500); 디지털 쓰기(하드웨어_리셋, 높음); delay(8000);// Tempo necessário para começar a ler Serial.println("RESET"); }/************ ThingSpeak*************/void startThingSpeakCmd(void){ EspSerial.flush();//limpa o buffer antes de começar a gravar 문자열 cmd ="AT+CIPSTART=\"TCP\",\""; cmd +="184.106.153.149"; // Endereco IP de api.thingspeak.com cmd +="\",80"; EspSerial.println(cmd); Serial.print("enviado ==> cmd 시작:"); 직렬.println(cmd); if(EspSerial.find("오류")) { Serial.println("AT+CIPSTART 오류"); 반품; }}/********* GET cmd를 ThingSpeak로 전송 *************/String sendThingSpeakGetCmd(String getStr){ String cmd ="AT+CIPSEND="; cmd +=문자열(getStr.length()); EspSerial.println(cmd); Serial.print("enviado ==> cmd 길이:"); 직렬.println(cmd); if(EspSerial.find((char *)">")) { EspSerial.print(getStr); Serial.print("enviado ==> getStr:"); 직렬.println(getStr); delay(500);//처리기의 템포 o GET, sem este delay apresenta busy no proximo comando String messageBody =""; while (EspSerial.available()) { 문자열 줄 =EspSerial.readStringUntil('\n'); if (line.length() ==1) { //actual content starts after empty line (that has length 1) messageBody =EspSerial.readStringUntil('\n'); } } Serial.print("MessageBody received:"); Serial.println(messageBody); return messageBody; } else { EspSerial.println("AT+CIPCLOSE"); // alert user Serial.println("ESP8266 CIPSEND ERROR:RESENDING"); //Resend... spare =spare + 1; error=1; return "error"; } } 

    The code can be downloaded from my GITHUB:ReadingCommandTS_EXT.ino

    Step 14:Sending Commands to Actuators

    At this point, we have the actuators channels configured on ThingSpeak and changing the value of Field 1 on each channel, we must see the actuators changing accordingly. On our final project we will do this task, using the Android App, but for testing proposes we can also do it using a normal browser. Let's do it.

    The commands are:

    Turn ON Pump (RED LED):

    https://api.thingspeak.com/update?api_key=ACT1_WRITE_KEY&field1=1 

    Turn OFF Pump (RED LED):

    https://api.thingspeak.com/update?api_key=ACT1_WRITE_KEY&field1=0 

    Turn ON Lamp (GREEN LED):

    https://api.thingspeak.com/update?api_key=ACT2_WRITE_KEY&field1=1 

    Turn OFF Lamp (GREEN LED):

    https://api.thingspeak.com/update?api_key=ACT2_WRITE_KEY&field1=0 

    Above you can see a print screen of a command to TurnOn the Pump sent from a browser and how it will appear at Serial Monitor. Obviously, the LED Red and relay will be also be turned on.

    Step 15:Completing the Android APP

    Let's complete the APP. Previously we have developed a simple App that gets the status from ThingSpeak (READ from Staus Channel). Now we must WRITE on Actuator channels, so those commands could be read by Arduino and act on Pump and Lamp accordingly.

    For a user to pass the commands to the App, we will use "buttons". A pair of buttons (ON and OFF) for each one of the Actuators.

    When a button is pressed, the color of its text changes.

    <울>
  • If ON ==> Blue
  • <울>
  • if OFF ==> Red
  • Above you can see the set of blocks for each one of the pairs of buttons.

    Test the App, sending commands to turn ON and OFF the actuators. Check on Serial Monitor, the messages exchanged between ESP-01 and ThingSpeak.

    The complete App code can be downloaded from my GITHUB:ArduFarmBot_V1_EXT.aia

    Step 16:Putting All Together

    완벽한! At this point, you have a full Android APP, a complete HW but you still do not have a code that will continuously read and write on ThingSpeak. Let's combine all that we have developed previously.

    On the final code, you will find additional portions to verify for example if the ESP-01 is not freezing. We will do it, sending an AT command to it before any read or write. As we saw at the very beginning of this tutorial, sending an AT command should return from ESP-01 an OK. If this does not happen, we will proceed with an HW reset, commanded by SW (as we do once during setup phase).

    The complete code for our project can be downloaded from my GITHUB:ArduFarmBot_Light_EXT.ino

    Step 17:Conclusion

    There is a lot to be explored in IoT arena with those great little devices, the Arduino Uno, and the ESP8266-01. We will return soon with new tutorials! Keep following MJRoBot tutorials!

    As always, I hope this project can help others find their way in the exciting world of electronics, robotics, and IoT!

    Please visit my GitHub for updated files:ArduFarmBot_Light

    For more projects, please visit my blog:MJRoBot.org

    Saludos from the south of the world!

    See you at my next tutorial!

    Thank you,

    Marcelo

    <섹션 클래스="섹션 컨테이너 섹션 축소 가능" id="코드">

    코드

    <울>
  • 코드 스니펫 #1
  • 코드 스니펫 #2
  • 코드 스니펫 #3
  • Code snippet #11
  • Code snippet #12
  • Code snippet #16
  • Code snippet #20
  • 코드 스니펫 #1일반 텍스트
    // DS18B20#include #include #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 int pinoDHT =11;int tipoDHT =DHT22;DHT dht(pinoDHT, tipoDHT); int airTemp =0;int airHum =0;// LDR (Light)#define ldrPIN 1int light =0;// Soil humidity#define soilHumPIN 0int soilHum =0;
    코드 스니펫 #2일반 텍스트
    void setup(){ Serial.begin(9600); DS18B20.begin(); dht.begin();}void loop(){ readSensors(); displaySensors(); delay (10000);}
    Code snippet #3Plain text
    /********* Read Sensors value *************/void readSensors(void){ airTemp =dht.readTemperature(); airHum =dht.readHumidity(); DS18B20.requestTemperatures(); soilTemp =DS18B20.getTempCByIndex(0); // Sensor 0 will capture Soil Temp in Celcius soilHum =map(analogRead(soilHumPIN), 1023, 0, 0, 100); light =map(analogRead(ldrPIN), 1023, 0, 0, 100); //LDRDark:0 ==> light 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 ("");}
    Code snippet #11Plain text
    #include  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 coomands");}void loop() { while(esp8266.available()) { Serial.write(esp8266.read()); } while(Serial.available()) { esp8266.write(Serial.read()); }}
    Code snippet #12Plain text
    * 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 returs close access points* AT+CIFSR ===> ESP8266 returs designided IP
    Code snippet #16Plain text
    // Thingspeak String statusChWriteKey ="6SRPQQKIE6AJVQE6"; // Status Channel id:385184#include SoftwareSerial EspSerial(6, 7); // Rx, Tx#define HARDWARE_RESET 8// DS18B20#include #include #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 int pinoDHT =11;int tipoDHT =DHT22;DHT dht(pinoDHT, tipoDHT); int airTemp =0;int airHum =0;// LDR (Light)#define ldrPIN 1int light =0;// Soil humidity#define soilHumPIN 0int soilHum =0;// Variables to be used with timerslong writeTimingSeconds =17; // ==> Define Sample time in seconds to send datalong startWriteTiming =0;long elapsedWriteTime =0;// Variables to be used with Actuatorsboolean pump =0; boolean 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); // Comunicacao com Modulo WiFi EspHardwareReset(); //Reset do Modulo WiFi startWriteTiming =millis(); // starting the "program clock"}void loop(){ start://label error=0; elapsedWriteTime =millis()-startWriteTiming; if (elapsedWriteTime> (writeTimingSeconds*1000)) { readSensors(); writeThingSpeak(); startWriteTiming =millis(); } if (error==1) //Resend if transmission is not completed { Serial.println(" <<<>>>"); delay (2000); goto start; //go to label "start" }}/********* Read Sensors value *************/void readSensors(void){ airTemp =dht.readTemperature(); airHum =dht.readHumidity(); DS18B20.requestTemperatures(); soilTemp =DS18B20.getTempCByIndex(0); // Sensor 0 will capture Soil Temp in Celcius light =map(analogRead(ldrPIN), 1023, 0, 0, 100); //LDRDark:0 ==> light 100% soilHum =map(analogRead(soilHumPIN), 1023, 0, 0, 100); }/********* Conexao com TCP com Thingspeak *******/void writeThingSpeak(void){ startThingSpeakCmd(); // preparacao da string GET String getStr ="GET /update?api_key="; getStr +=statusChWriteKey; getStr +="&field1="; getStr +=String(pump); getStr +="&field2="; getStr +=String(lamp); getStr +="&field3="; getStr +=String(airTemp); getStr +="&field4="; getStr +=String(airHum); getStr +="&field5="; getStr +=String(soilTemp); getStr +="&field6="; getStr +=String(soilHum); getStr +="&field7="; getStr +=String(light); getStr +="&field8="; getStr +=String(spare); getStr +="\r\n\r\n"; sendThingSpeakGetCmd(getStr); }/********* Reset ESP *************/void EspHardwareReset(void){ Serial.println("Reseting......."); digitalWrite(HARDWARE_RESET, LOW); 지연(500); digitalWrite(HARDWARE_RESET, HIGH); delay(8000);//Tempo necessário para começar a ler Serial.println("RESET"); }/********* Start communication with ThingSpeak*************/void startThingSpeakCmd(void){ EspSerial.flush();//limpa o buffer antes de começar a gravar String cmd ="AT+CIPSTART=\"TCP\",\""; cmd +="184.106.153.149"; // Endereco IP de api.thingspeak.com cmd +="\",80"; EspSerial.println(cmd); Serial.print("enviado ==> Start cmd:"); Serial.println(cmd); if(EspSerial.find("Error")) { Serial.println("AT+CIPSTART error"); return; }}/********* send a GET cmd to ThingSpeak *************/String sendThingSpeakGetCmd(String getStr){ String cmd ="AT+CIPSEND="; cmd +=String(getStr.length()); EspSerial.println(cmd); Serial.print("enviado ==> lenght cmd:"); Serial.println(cmd); if(EspSerial.find((char *)">")) { EspSerial.print(getStr); Serial.print("enviado ==> getStr:"); Serial.println(getStr); delay(500);//tempo para processar o GET, sem este delay apresenta busy no próximo comando String messageBody =""; while (EspSerial.available()) { String line =EspSerial.readStringUntil('\n'); if (line.length() ==1) { //actual content starts after empty line (that has length 1) messageBody =EspSerial.readStringUntil('\n'); } } Serial.print("MessageBody received:"); Serial.println(messageBody); return messageBody; } else { EspSerial.println("AT+CIPCLOSE"); // alert user Serial.println("ESP8266 CIPSEND ERROR:RESENDING"); //Resend... spare =spare + 1; error=1; return "error"; } }
    Code snippet #20Plain text
    // Thingspeak String canalID1 ="375598"; //Actuator1String canalID2 ="375599"; //Actuator2#include SoftwareSerial EspSerial(6, 7); // Rx, Tx#define HARDWARE_RESET 8// Variables to be used with timerslong readTimingSeconds =10; // ==> Define Sample time in seconds to receive datalong startReadTiming =0;long elapsedReadTime =0;//Relays#define ACTUATOR1 10 // RED LED ==> Pump#define ACTUATOR2 12 // GREEN LED ==> Lampboolean pump =0; boolean 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); //o módulo relé é ativo em LOW digitalWrite(ACTUATOR2, HIGH); //o módulo relé é ativo em LOW digitalWrite(HARDWARE_RESET, HIGH); EspSerial.begin(9600); // Comunicacao com Modulo WiFi EspHardwareReset(); //Reset do Modulo WiFi startReadTiming =millis(); // starting the "program clock"}void loop(){ start://label 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) //Resend if transmission is not completed { Serial.println(" <<<>>>"); delay (2000); goto start; //go to label "start" }}/********* Take actions based on ThingSpeak Commands *************/void takeActions(void){ Serial.print("Pump:"); Serial.println(pump); Serial.print("Lamp:"); Serial.println(lamp); if (pump ==1) digitalWrite(ACTUATOR1, LOW); else digitalWrite(ACTUATOR1, HIGH); if (lamp ==1) digitalWrite(ACTUATOR2, LOW); else digitalWrite(ACTUATOR2, HIGH);}/********* Read Actuators command from ThingSpeak *************/int readThingSpeak(String channelID){ startThingSpeakCmd(); int command; // preparacao da string GET String getStr ="GET /channels/"; getStr +=channelID; getStr +="/fields/1/last"; getStr +="\r\n"; String messageDown =sendThingSpeakGetCmd(getStr); if (messageDown[5] ==49) { command =messageDown[7]-48; Serial.print("Command received:"); Serial.println(command); } else command =9; return command;}/********* Reset ESP *************/void EspHardwareReset(void){ Serial.println("Reseting......."); digitalWrite(HARDWARE_RESET, LOW); 지연(500); digitalWrite(HARDWARE_RESET, HIGH); delay(8000);//Tempo necessário para começar a ler Serial.println("RESET"); }/********* Start communication with ThingSpeak*************/void startThingSpeakCmd(void){ EspSerial.flush();//limpa o buffer antes de começar a gravar String cmd ="AT+CIPSTART=\"TCP\",\""; cmd +="184.106.153.149"; // Endereco IP de api.thingspeak.com cmd +="\",80"; EspSerial.println(cmd); Serial.print("enviado ==> Start cmd:"); Serial.println(cmd); if(EspSerial.find("Error")) { Serial.println("AT+CIPSTART error"); return; }}/********* send a GET cmd to ThingSpeak *************/String sendThingSpeakGetCmd(String getStr){ String cmd ="AT+CIPSEND="; cmd +=String(getStr.length()); EspSerial.println(cmd); Serial.print("enviado ==> lenght cmd:"); Serial.println(cmd); if(EspSerial.find((char *)">")) { EspSerial.print(getStr); Serial.print("enviado ==> getStr:"); Serial.println(getStr); delay(500);//tempo para processar o GET, sem este delay apresenta busy no próximo comando String messageBody =""; while (EspSerial.available()) { String line =EspSerial.readStringUntil('\n'); if (line.length() ==1) { //actual content starts after empty line (that has length 1) messageBody =EspSerial.readStringUntil('\n'); } } Serial.print("MessageBody received:"); Serial.println(messageBody); return messageBody; } else { EspSerial.println("AT+CIPCLOSE"); // alert user Serial.println("ESP8266 CIPSEND ERROR:RESENDING"); //Resend... spare =spare + 1; error=1; return "error"; } }
    깃허브
    https://github.com/Mjrovai/ArduFarmBot_Light

    회로도

    Electrical diagram
    https://github.com/Mjrovai/ArduFarmBot_Light/blob/master/ArduFarmBot_Light/ArduFarmBot%20Light.fzz

    제조공정

    1. 손쉬운 Raspberry Pi 4B+ IoT 보드에서 병렬 컴퓨팅
    2. IoT를 사용한 심박수 모니터
    3. Arduino Uno WiFi를 사용하는 WebServerBlink
    4. 간단한 UNO 계산기
    5. 시력의 지속성
    6. 비접촉식 온도 모니터링 게이트
    7. Arduino - 직렬을 통해 웹에 온도 보내기
    8. ThingSpeak Arduino 기상 관측소
    9. 서미스터를 사용하는 것이 얼마나 쉬운가요?!
    10. Azure IoT 수영장