제조공정
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 2 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 |
| ||||
| ||||
| ||||
|
내 식물은 항상 너무 많거나 적은 물에 시달리고 있고 나는 내 접시에 많은 허브를 넣는 것을 좋아하기 때문에 맞춤형 관개 시스템을 만들기로 결정했습니다. 내 허브 상자는 구성 가능해야 하며 자동 또는 수동으로 작동해야 합니다. 따라서 웹사이트에 대한 인터페이스는 설정을 가능하게 하고 좋은 차트에 습도를 표시하기 위해 존재합니다. 마지막 단계는 음성 제어를 통합하여 Amazon Alexa에 습도를 요청하고, 식물 재배 램프를 켜고 끄며, 자동화가 비활성화된 경우 관개를 시작하는 것이었습니다. 결과를 찾으려면 여기를 클릭하십시오.
저는 프로젝트의 기술적인 부분부터 시작하여 Arduino를 구입했습니다. 몇 가지 튜토리얼 후에 나는 소프트웨어와 Arduino를 제어하는 데 확고했습니다. Wi-Fi 컨트롤러, 일부 수분 센서, 펌프, 식물 재배 램프 및 추가로 필요한 하드웨어(램프용 회로를 Arduino에서 분리하기 위한 릴레 실드, 프레임용 일부 와이어 및 너도밤나무)를 주문했습니다. 결과의 Arduino 코드는 프로젝트에서 구성 요소를 사용하는 방법에 대한 몇 가지 정보와 함께 이 튜토리얼에서 제공됩니다. 웹사이트/API 코드는 제공되지 않습니다(수요가 매우 높은 경우 제외;)).
1단계:수분 센서
첫 번째 이정표는 내 Arduino로 습도를 읽는 것이 었습니다. 수분센서 YL-69는 아두이노와 쉽게 연결할 수 있었습니다. VCC 핀을 Arduino의 GPIO 핀(예제 핀 06번)에 연결하고, 접지를 접지로, A0을 아날로그 핀(예제 핀 A1번)에 연결해야 합니다.
튜토리얼:토양 습도 센서
byte vccPin =6;byte dataPin =A1;void setup() { pinMode(vccPin, OUTPUT); digitalWrite(vccPin, LOW); Serial.begin(9600); 동안 (! 직렬);}int readHumidity() { digitalWrite(vccPin, HIGH); 지연(500); // 측정하기 전에 미리 전원을 얼마나 켜야 하는지 테스트해야 합니다. int value =analogRead(dataPin); digitalWrite(vccPin, LOW); 반환 1023 - 값;} 무효 루프() { Serial.print("습도 수준(0-1023):"); Serial.println(readHumidity()); 지연(10000);}
2단계:펌프 및 램프용 릴레이
다음 목표는 램프, 펌프 및 Arduino의 회로를 분리하기 위한 릴레이 쉴드(4개 릴레)를 설치하는 것이었습니다. Arduino는 5V로, 펌프는 12V, 식물 성장 램프는 230V를 사용합니다. 쉴드는 Arduino의 5V 및 접지 핀에 연결해야 합니다. 각 릴레이에는 켜고 끄기 위해 선택한 GPIO 핀이 추가로 필요합니다. 마지막으로 실드에서 VCC JC에서 VCC로의 점퍼를 사용하거나 추가 배터리를 사용할 수 있습니다(이것이 가장 좋지만 내 프로젝트에는 아직 배터리가 없습니다).
내 실드가 핀에서 "LOW"로 "켜짐"으로 전환된다는 점을 이해하는 것이 중요합니다. 내 핀이 OUTPUT으로 정의되자마자 자동으로 활성으로 전환됩니다. 코드에서 릴레이를 끄려면 항상 INPUT 및 LOW로 전환해야 합니다. 기본적으로 Arduino 핀은 INPUT 및 LOW입니다.
튜토리얼:릴레이 쉴드
정보:릴레이 OUTPUT + LOW =활성인 이유는 무엇입니까?
byte pump1 =11;byte pump2 =10;void setup() { Serial.begin(9600); 동안 (! 직렬); 핀모드(펌프1, 출력); // 낮은/높은 변형 digitalWrite(pump2, LOW); // 변종 입/출력} void loop() { digitalWrite(pump1, HIGH); // 펌프1 비활성화 pinMode(pump2, INPUT); // pump2 비활성화 지연(1000); 디지털 쓰기(펌프1, LOW); // 펌프1 활성화 pinMode(pump2, OUTPUT); // pump2 활성화 지연(1000);}
3단계:ESP-01이 있는 WiFi
espressif ESP8266 ESP-01을 WiFi용 Arduino에 연결하는 것이 가장 어려운 부분이었습니다. 내 스크립트에서 Wi-Fi를 실행하는 데 몇 시간이 걸렸습니다.
ESP는 VCC =3.3V, GND =GND, CH_PD =3.3V, TX =핀 02, RX =핀 03에 연결됩니다. 생산적인 사용을 위해서는 핀에 최소한 5V ~ 3.3V의 레벨 변환기를 사용해야 합니다. 02 및 핀 03도 마찬가지입니다. 제 경우에는 잘 작동했습니다.
Arduino와 유사하게 ESP-01은 또 다른 마이크로 컨트롤러입니다. 두 컨트롤러가 통신하도록 하려면 직렬 통신을 사용해야 합니다. Arduino UNO는 기본적으로 RX 및 TX에 핀 01 및 02를 사용합니다. 그러나 USB 디버깅에도 사용되므로 SoftwareSerial.h를 포함하고 사용자 정의 핀을 정의하는 것이 좋습니다.
#include SoftwareSerial espSerial(3,2); // RX, TXvoid setup() { Serial.begin(9600); espSerial.begin(115200); // AT+UART_DEF=9600,8,1,0,0 후 9600으로 전환 while (!Serial);}void loop() { if (espSerial.available()) { Serial.write(espSerial.read()); } if (Serial.available()) { espSerial.write(Serial.read()); }}
위의 스크립트를 실행하면 직렬 모니터에 AT-command를 입력하고 결과를 볼 수 있습니다. 직렬 통신은 실패하기 쉬우므로 ESP에서 사용하는 통신 전송 속도를 115200에서 9600으로 줄였습니다.
튜토리얼:ESP8266 + Arduino | 튜토리얼:일반 ESP8266(독일어)
<울>HTTP 1.1에서는 바이트가 응답의 일부이기 때문에 스크립트는 HTTP 1.0을 사용합니다. AT+CIPSEND 이후에 보낼 명령의 줄 바꿈에 주의하는 것이 중요합니다. 틀리면 바이트 전송 오류가 발생합니다.
#include SoftwareSerial espSerial(3,2); // RX, TXconst char* ssid ="";const char* pass ="";void setup() { Serial.begin(9600); espSerial.begin(9600); 동안(! 직렬); 동안(!connectToWiFi()); // 웹사이트 요청 및 결과 출력 if (httpRequest("my.server.com", "/site/subsite/index.php")) { while (espSerial.available()) { Serial.write(espSerial.read() ); } }}void loop() { // 계속해서 실행 if (espSerial.available()) { Serial.write(espSerial.read()); } if (Serial.available()) { espSerial.write(Serial.read()); }}bool connectToWiFi() { 지연(2000;) espSerial.setTimeout(3000); 동안 (espSerial.available()) Serial.write(espSerial.read()); Serial.println(F("[ESP] WiFi에 연결 중")); espSerial.println(F("AT+CIPSTATUS=2")); if (!espSerial.find("확인")) { espSerial.setTimeout(10000); Serial.println(F("[ESP] 리셋 모듈")); espSerial.println(F("AT+RST")); if (!espSerial.find("준비")) { Serial.println(F("[ESP] 재설정 실패")); 거짓을 반환합니다. } Serial.println(F("[ESP] CW 모드 설정")); espSerial.println(F("AT+CWMODE=1")); if (!espSerial.find("OK")) { Serial.println(F("[ESP] 모드 실패")); 거짓을 반환합니다. } Serial.println(F("[ESP] 라우터에 연결")); espSerial.print(F("AT+CWJAP=\"")), espSerial.print(ssid), espSerial.print(F("\",\"")), espSerial.print(패스), espSerial.println ("\""); if (!espSerial.find("OK")) { Serial.println(F("[ESP] WiFi 연결 실패")); 거짓을 반환합니다. } } espSerial.setTimeout(3000); Serial.println(F("[ESP] WiFi가 연결되었습니다.")); return true;}bool httpRequest(문자열 서버, 문자열 사이트) { 문자열 cmd =""; cmd +="GET " + 사이트 + " HTTP/1.0\r\n"; cmd +="호스트:" + 서버 + "\r\n"; cmd +="연결:닫기"; int cmdLength =cmd.length() + 4; // 직렬.println(cmd); espSerial.print(F("AT+CIPSTART=\"TCP\",\"")); espSerial.print(서버); espSerial.println(F("\",80")); if (!espSerial.find("OK")) { Serial.println(F("[ESP] TCP 연결 오류")); 거짓을 반환합니다. } espSerial.print(F("AT+CIPSEND=")); espSerial.println(cmd길이); if (!espSerial.find(findGT)) { Serial.println(F("[ESP] 상태 오류 보내기")); 거짓을 반환합니다. } espSerial.print(F("GET")); espSerial.print(사이트); espSerial.print(F(" HTTP/1.0\r\n")); espSerial.print(F("호스트:")); espSerial.print(서버); espSerial.print(F("\r\n")); espSerial.print(F("연결:닫기\r\n")); espSerial.println(); if (!espSerial.find(":")) { Serial.println(F("전송되지 않은 바이트")); espSerial.print(F("AT+CIPCLOSE")); 거짓을 반환합니다. } 문자 상태[32] ={0}; espSerial.readBytesUntil('\r', 상태, 크기(상태)); if (strcmp(status, "HTTP/1.1 200 OK") !=0) { Serial.print(F("[ESP] 예기치 않은 응답:")); Serial.println(상태); 거짓을 반환합니다. } if (!espSerial.find("\r\n\r\n")) { Serial.println(F("[ESP] 잘못된 응답")); 거짓을 반환합니다. } // HTTP 헤더 건너뛰기 // if (!espSerial.find(\r\n)) { Serial.println(F("[ESP] 바이트를 찾을 수 없음")); 반품; } // 바이트 건너뛰기(http 1.1의 경우) return true;i}
4단계:나무 상자
프레임은 슈퍼마켓에서 모든 전자 제품과 세 개의 허브 화분을 보관할 계획이었습니다. 나는 모든 구성 요소의 크기를 측정하고 위치를 구성했습니다. 4개의 수분 센서, 2개의 펌프, Arduino + 쉴드, 4x 릴레이 쉴드, USB 플러그 및 일부 전선이 상자에 맞아야 합니다. 너도밤나무로 제작하여 추가 유약을 바르지 않아도 튼튼하고 물방울이 잘 마르도록 했습니다.
원은 직접 만든 직쏘 테이블에 직쏘로 톱질했습니다. 식물 마운트는 뜨거운 접착제로 원 안에 붙어 있습니다. 상자의 측면은 목공풀(내수성을 위한 D3)으로 접착됩니다. 전자제품 외에 하부패널 고정 옆에 나사나 못을 사용하지 않았습니다.
그림> 그림>나는 모든 회로, 전선 및 물 튜브를 상자 안에 넣고 추가 물 탱크용 센서와 튜브를 꺼냈습니다. 상자를 닫기 전에 전자 제품을 보호하기 위해 상자 안에 물이 빠지지 않도록 접시를 추가했습니다.
5단계:웹사이트 API
API 및 웹사이트는 php로 코딩된 jQuery, Bootstrap, X-editable(인라인 ajax 형식용) 및 Chart.js(습도 차트용)를 기반으로 합니다. 웹사이트에서 Arduino에 대한 설정(예:센서 핀, 습도 확인 간격, 공장당 펌프, 펌프 VCC 핀, 조명 VCC 핀)을 정의하고 현재 습도 + 차트를 찾을 수 있습니다.
구성은 Arduino용 JSON에 의해 제공됩니다. 시작 후, 그리고 빈번한 간격으로 허브 상자는 새로운 설정을 확인합니다. Arduino로 JSON을 구문 분석하기 위해 ArduinoJson 라이브러리를 사용했습니다. 폴링 간격으로 StensTimer를 사용했습니다.
라이브러리:ArduinoJson | 라이브러리:StensTimer
6단계:Alexa 통합
웹사이트는 Alexa 통신을 위한 API를 제공합니다. Alexa에서 요청 JSON을 수신하고 Arduino에서 사용하는 사용자 지정 JSON으로 변환하는 허브 역할을 합니다(예:램프 켜기, 관개 플랜트 1, ...). Arduino는 새로운 작업을 폴링하고 실행합니다.
음성 요청은 단순한 켜기/끄기 이상이므로 Alexa Skill을 구현하고 Alexa Smart Home은 구현하지 않았습니다. AWS Lampda는 요청 JSON을 내 API로 전달하여 의도를 구문 분석합니다.
<사전><코드>var https =require('https');exports.handler =(이벤트, 컨텍스트, 콜백) => { var postData =JSON.stringify(이벤트); var 옵션 ={ 호스트:'내 기술로 사용한 의도 발췌:
<울>마지막으로 독일어와 영어 사용을 위한 로케일 지원을 추가했습니다.
결과
결과적으로, 나는 슈퍼마켓 허브 화분을 넣을 나무 상자를 가지고 있으며, 토양에 물 튜브와 수분 센서를 가져오고 외부 물 탱크에 튜브를 가져갑니다. Alexa 통합으로 다음 문장을 말할 수 있습니다.
<울>Alexa에 식물의 습도를 요청하고 나중에 관개(독일어):
<비디오 너비="100%" 높이="100%" preload="metadata" controls="controls"><소스 유형="비디오/mp4" src="http://www.waltswooddesign.com/wp-content /uploads/2018/02/Irrigate-Full.mp4" />http://www.waltswooddesign.com/wp-content/uploads/2018/02/Irrigate-Full.mp4Alexa에게 식물 성장 램프를 켜달라고 요청:
<비디오 너비="100%" 높이="100%" preload="metadata" controls="controls"><소스 유형="비디오/mp4" src="http://www.waltswooddesign.com/wp-content /uploads/2018/02/Lamp-Switch.mp4" />http://www.waltswooddesign.com/wp-content/uploads/2018/02/Lamp-Switch.mp4동영상 없이 결과를 보여주는 GIF:
계획된 기능
다음 기능은 아직 구현되지 않았지만 향후 계획됩니다.
<울>
2018년 3월 23일 업데이트
두 가지 새로운 의도를 추가했습니다. 그 중 하나는 습도를 기록하는 외부 Adruino Nano의 계획된 기능에 중요합니다.
<울>#ifndef ECOACTIONBUFFER_H#define ECOACTIONBUFFER_H#include "Arduino.h#include "StensTimer.h"구조 EcoActionBuffer :public IStensTimerListener { long entryNo; 인트 액션; 인트 핀; 장기간; 무효 timerCallback(타이머* 타이머); 무효 switchPin(int 핀, 부울 값); 무효 readStack(); 무효 프로세스(); 무효 toSerial(); 무효 리셋();};#endif
#include "EcoActionBuffer.h#include "StensTimer.h#include "WhiteWalnutApi.h#define ACTION_ECOACTION_READ 1#define ACTION_ECOACTION_HIGH 2#define ACTION_ECOACTION_LOW 3void EcoActionBuffer::readStack() { reset(); WhiteWalnutApi::receiveActionFromStack(* this); if (entryNo !=0) { 프로세스(); // WhiteWalnutApi::updateActionOnStack(*this); // 성능을 위해 비활성화됨 }}void EcoActionBuffer::process() { toSerial(); 핀모드(핀, 출력); 디지털 쓰기(핀, 높음); 스위치(액션) { case ACTION_ECOACTION_HIGH:switchPin(핀, 참); 부서지다; 경우 ACTION_ECOACTION_LOW:switchPin(핀, 거짓); 부서지다; } if (duration !=0) { StensTimer::getInstance()->setTimer(this, -pin, duration); }} 무효 EcoActionBuffer::timerCallback(타이머* 타이머) { 스위치(타이머->getAction()) { 케이스 ACTION_ECOACTION_READ:readStack(); 부서지다; } if (타이머->getAction() <0) { switchPin(abs(타이머->getAction()), 거짓); }} 무효 EcoActionBuffer::switchPin(int 핀, 부울 값) { 스위치(값) { 경우 true:digitalWrite(핀, LOW); 부서지다; 경우 false:digitalWrite(핀, HIGH); 부서지다; } WhiteWalnutApi::switchPin(핀, 값);} 무효 EcoActionBuffer::reset() { entryNo =0; 액션 =0; 핀 =0; 지속 시간 =0;} 무효 EcoActionBuffer::toSerial() { Serial.print(entryNo); Serial.print(F(" - 작업:")); Serial.print(액션); Serial.print(F(", 핀:")); Serial.print(핀); Serial.print(F(", 기간:")); Serial.print(지속시간); 직렬.println();}
#include "Plant.h#include "StensTimer.h#include "WhiteWalnutApi.h#define ACTION_PLANT_CHECKHUMIDITY 2#define PIN_HUMIDITY_VCC 12void Plant::checkHumidity() { if (humidityDataPin !=0) { Serial.print (암호); Serial.print(F(" - 습도 확인...")); 디지털 쓰기(PIN_HUMIDITY_VCC, HIGH); 지연(200); // TODO int 습도 =1023 - analogRead(humidityDataPin); 디지털 쓰기(PIN_HUMIDITY_VCC, LOW); Serial.println(습도); WhiteWalnutApi::sendHumidity(*이, 습도); if (humidityCheckInterval ==0) 습도CheckInterval =60000; StensTimer::getInstance()->setTimer(이, ACTION_PLANT_CHECKHUMIDITY, 습도체크간격); } else StensTimer::getInstance()->setTimer(this, ACTION_PLANT_CHECKHUMIDITY, 60000);}무효 플랜트::updateApi() { WhiteWalnutApi::updatePlant(*this); // WhiteWalnutApi::sendHeartbeat(*this); // 성능을 위해 비활성화 pinMode(PIN_HUMIDITY_VCC, OUTPUT); toSerial();}void Plant::timerCallback(Timer* timer) { switch (timer->getAction()) { case ACTION_PLANT_CHECKHUMIDITY:checkHumidity(); 부서지다; }}공장::toSerial() { Serial.print(코드); Serial.print(F(" - 데이터 핀:")); Serial.print(습도데이터핀); Serial.print(F(", 간격:")); Serial.print(humidityCheckInterval); 직렬.println();}
#ifndef PLANT_H#define PLANT_H#include "Arduino.h#include "StensTimer.h" struct Plant :public IStensTimerListener { const char* code; 정수 습도 데이터 핀; 긴 습도CheckInterval; 무효 checkHumidity(); 무효 timerCallback(타이머* 타이머); 무효 toSerial(); 무효 updateApi();};#endif
#include "EcoActionBuffer.h#include "Plant.h"#include "StensTimer.h#include "WhiteWalnutApi.h"구조 TimerHelper :public IStensTimerListener { public:void updateApi(); void timerCallback(Timer* 타이머);};StensTimer* stensTimer;TimerHelper apiTimer;Plant leftPlant;Plant centerPlant;Plant rightPlant;Plant externalPlant;EcoActionBuffer actionBuffer;#define ACTION_PLANT_UPDATE 1#define ACTION_PLANT_UPDATE 1#define ACTION_ECOACTION_READ 10void setup(); 동안 (! 직렬); stensTimer =StensTimer::getInstance(); leftPlant.code ="왼쪽"; centerPlant.code ="중앙"; rightPlant.code ="오른쪽"; externalPlant.code ="외부"; while(!WhiteWalnutApi::connectToWiFi()) 지연(2000); WhiteWalnutApi::switchPin(0, 거짓); apiTimer.updateApi(); leftPlant.checkHumidity(); centerPlant.checkHumidity(); rightPlant.checkHumidity(); externalPlant.checkHumidity(); actionBuffer.readStack(); StensTimer::getInstance()->setInterval(&apiTimer, ACTION_PLANT_UPDATE, 60000); StensTimer::getInstance()->setInterval(&actionBuffer, ACTION_ECOACTION_READ, 1000);}void loop() { stensTimer->run();}void TimerHelper::updateApi() { leftPlant.updateApi(); centerPlant.updateApi(); rightPlant.updateApi(); externalPlant.updateApi();} 무효 TimerHelper::timerCallback(Timer* 타이머){ switch (timer->getAction()) { case ACTION_PLANT_UPDATE:updateApi(); 부서지다; }}
#include "Arduino.h#include "ArduinoJson.h#include "EcoActionBuffer.h#include "MemoryFree.h#include "Plant.h#include " SoftwareSerial.h#include "WhiteWalnutApi.h"SoftwareSerial espSerial(3, 2);const char* ssid ="";const char* pass =" ";const char* API_SERVER =" ";const char* API_PLANT =" ";const char* API_ACTION =" ";char* findOK ="OK";char* findRY ="준비";char* findGT =">";char* findDP =":";char* findHD ="\r\n\r\n";char* findBT ="\r\n"; 부울 WhiteWalnutApi::connectToWiFi() { espSerial.begin(9600); espSerial.setTimeout(3000); 동안 (espSerial.available()) Serial.write(espSerial.read()); Serial.println(F("[ESP] WiFi에 연결 중")); espSerial.println(F("AT+CIPSTATUS=2")); if (!espSerial.find(findOK)) { espSerial.setTimeout(10000); Serial.println(F("[ESP] 리셋 모듈")); espSerial.println(F("AT+RST")); if (!espSerial.find(findRY)) { Serial.println(F("[ESP] 재설정 실패")); 거짓을 반환합니다. } Serial.println(F("[ESP] CW 모드 설정")); espSerial.println(F("AT+CWMODE=1")); if (!espSerial.find(findOK)) { Serial.println(F("[ESP] 모드 실패")); 거짓을 반환합니다. } Serial.println(F("[ESP] 라우터에 연결")); espSerial.print(F("AT+CWJAP=\"")), espSerial.print(ssid), espSerial.print(F("\",\"")), espSerial.print(패스), espSerial.println ("\""); if (!espSerial.find(findOK)) { Serial.println(F("[ESP] WiFi 연결 실패")); 거짓을 반환합니다. } } espSerial.setTimeout(3000); Serial.println(F("[ESP] WiFi가 연결되었습니다.")); return true;} void WhiteWalnutApi::updatePlant(Plant&plant) { String site =String(API_PLANT) + "?action=get&code=" + String(plant.code); 동안 (!httpRequest(사이트)) connectToWiFi(); JsonObject&루트 =parseJson(); if (root.success()) { plant.humidityDataPin =root["dataPin"].as (); plant.humidityCheckInterval =atol(root["간격"].as ()); }}void WhiteWalnutApi::sendHumidity(Plant&식물, int 습도) { String site =String(API_PLANT) + "?action=humidity&code=" + String(plant.code) + "&humidity=" + String(humidity); 동안 (!httpRequest(사이트)) connectToWiFi(); // TODO:REMOVE RETURN} void WhiteWalnutApi::sendHeartbeat(Plant&plant) { String site =String(API_PLANT) + "?action=heartbeat&code=" + String(plant.code); 동안 (!httpRequest(사이트)) connectToWiFi();} 무효 WhiteWalnutApi::receiveActionFromStack(EcoActionBuffer&actionBuffer) { 동안 (!httpRequest(String(API_ACTION))) connectToWiFi(); JsonObject&루트 =parseJson(); if (root.success()) { actionBuffer.entryNo =atol(root["entryNo"].as ()); actionBuffer.action =root["actionEnum"].as (); actionBuffer.pin =루트["핀"].as (); actionBuffer.duration =atol(루트["값"].as ()); }} 무효 WhiteWalnutApi::updateActionOnStack(EcoActionBuffer&actionBuffer) { 문자열 사이트 =String(API_ACTION) + "?action=processed&entryNo=" + String(actionBuffer.entryNo); while (!httpRequest(site)) connectToWiFi();}void WhiteWalnutApi::switchPin(int pin, bool 값) { String site =String(API_ACTION) + "?action=switch&pin=" + String(pin) + "&value=" + 문자열(값); while (!httpRequest(site)) connectToWiFi();}bool WhiteWalnutApi::httpRequest(문자열 사이트) { // char* cmd; // sprintf(cmd, "GET %s HTTP/1.0\r\n호스트:%s\r\n연결:닫기", 사이트, API_SERVER); /* 문자열 cmd =""; cmd +="GET " + 사이트 + " HTTP/1.0\r\n"; cmd +="호스트:" + 문자열(API_SERVER) + "\r\n"; cmd +="연결:닫기"; int cmdLength =cmd.length() + 4; 직렬.println(cmd); */ int cmdLength =44 + site.length() + strlen(API_SERVER); // Serial.print(F("[메모리] ")); // Serial.print(freeMemory()); // Serial.print(F(" - ")); // Serial.println(사이트); // -> 외부의 경우 785 espSerial.print(F("AT+CIPSTART=\"TCP\",\"")); espSerial.print(API_SERVER); espSerial.println(F("\",80") ); if (!espSerial.find(findOK)) { Serial.println(F("[ESP] TCP 연결 오류")); 거짓을 반환합니다. } espSerial.print(F("AT+CIPSEND=")); espSerial.println(cmd길이); // espSerial.println(strlen(cmd)); if (!espSerial.find(findGT)) { Serial.println(F("[ESP] 상태 오류 보내기")); 거짓을 반환합니다. } espSerial.print(F("GET")); espSerial.print(사이트); espSerial.print(F(" HTTP/1.0\r\n")); espSerial.print(F("호스트:")); espSerial.print(API_SERVER); espSerial.print(F("\r\n")); espSerial.print(F("연결:닫기\r\n")); espSerial.println(); // 동안 (espSerial.available()) Serial.println(espSerial.readString()); 반품; if (!espSerial.find(findDP)) { Serial.println(F("Bytes not sent")); espSerial.print(F("AT+CIPCLOSE")); 거짓을 반환합니다. } char status[32] ={0}; espSerial.readBytesUntil('\r', status, sizeof(status)); if (strcmp(status, "HTTP/1.1 200 OK") !=0) { Serial.print(F("[ESP] Unexpected response:")); Serial.println(status); 거짓을 반환합니다. } // Check HTTP status if (!espSerial.find(findHD)) { Serial.println(F("[ESP] Invalid response")); 거짓을 반환합니다. } // Skip HTTP headers // if (!espSerial.find(findBT)) { Serial.println(F("[ESP] Bytes not found")); 반품; } // skip bytes (for http 1.1) return true;}JsonObject&WhiteWalnutApi::parseJson() { const size_t capacity =JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60; DynamicJsonBuffer jsonBuffer(capacity); JsonObject&root =jsonBuffer.parseObject(espSerial); if (!root.success()) Serial.println(F("Parsing failed!")); return root;}
#ifndef WHITEWALNUTAPI_H#define WHITEWALNUTAPI_H#include "Arduino.h"#include "ArduinoJson.h"#include "EcoActionBuffer.h"#include "Plant.h"class WhiteWalnutApi { public:static bool connectToWiFi(); static void updatePlant(Plant&plant); static void sendHumidity(Plant&plant, int humidity); static void sendHeartbeat(Plant&plant); static void receiveActionFromStack(EcoActionBuffer&actionBuffer); static void updateActionOnStack(EcoActionBuffer&actionBuffer); static void switchPin(int pin, bool value); private:static bool httpRequest(String site); static JsonObject&parseJson();};#endif섹션>
제조공정
이 프로젝트에서는 Arduino 보안 및 경보 시스템을 만드는 방법을 배웁니다. 다음 비디오를 보거나 아래에 작성된 튜토리얼을 읽을 수 있습니다. 개요 알람은 A 버튼을 누른 후 10초 후에 활성화됩니다. 물체를 감지하기 위해 초음파 센서를 사용하고 알람이 무언가를 감지하면 부저가 소리를 내기 시작합니다. 알람을 중지하려면 4자리 비밀번호를 삽입해야 합니다. 사전 설정된 비밀번호는 1234이지만 변경할 수도 있습니다. B 버튼을 눌러 암호 변경 메뉴로 들어갑니다. 계속하려면 현재 암호를 입력해야 하고 새 4자리 암호를 입력
Arduino 오픈 소스 하드웨어 플랫폼에서 회로를 생성하려면 Arduino 실드를 사용해야 합니다. 프로젝트에서 하드웨어 및 회로 배선의 복잡성을 줄이는 데 도움이 됩니다. 이 기사에서는 Arduino Sheild가 무엇인지, 다양한 유형 및 설치 프로세스에 대해 알아봅니다. Arduino Shield란 무엇입니까? Arduino 실드는 추가 기능을 제공하기 위해 Arduino 보드에 부착되는 하드웨어 애드온 보드입니다. Bluetooth, 모터 드라이버 및 WiFi와 같은 기능을 사용하여 다양한 IoT 프로젝트를 만드는 데