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

허브 박스 에코 시스템

구성품 및 소모품

Amazon Alexa 에코 닷
× 1
Arduino UNO
× 1
Espressif ESP8266 ESP-01
× 1
Arduino Proto Shield
× 1
Arduino 4 릴레이 실드
× 1
아쿠아 펌프
× 2
식물 성장 램프
× 1
220V DC 전원 어댑터
× 1
12V DC 전원 어댑터
× 1
USB 전원 플러그 + 케이블
× 1
에어 호스
× 1
점퍼 와이어(일반)
× 1

앱 및 온라인 서비스

Arduino IDE
Amazon Alexa Alexa 기술 키트
Amazon Web Services AWS Lambda
php 웹 서버

이 프로젝트 정보

내 식물은 항상 너무 많거나 적은 물에 시달리고 있고 나는 내 접시에 많은 허브를 넣는 것을 좋아하기 때문에 맞춤형 관개 시스템을 만들기로 결정했습니다. 내 허브 상자는 구성 가능해야 하며 자동 또는 수동으로 작동해야 합니다. 따라서 웹사이트에 대한 인터페이스는 설정을 가능하게 하고 좋은 차트에 습도를 표시하기 위해 존재합니다. 마지막 단계는 음성 제어를 통합하여 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(독일어)

<울>
  • 유용한 도우미 클래스(하지만 너무 많은 메모리를 사용함):라이브러리:WiFiEsp
  • <울>
  • 메모리 검사 도구:라이브러리:MemoryFree
  • 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 옵션 ={ 호스트:'', 경로:'', 포트:443, 메서드:'POST', 헤더:{ '콘텐츠 유형':'응용 프로그램/json' , '콘텐츠 길이':postData.length, } }; // 요청 설정 var postRequest =https.request(options, function(res) { res.setEncoding('utf8'); res.on('data', function (chunk) { console.log('Response:' + 청크); // console.log(청크); callback(null, JSON.parse(chunk)); }); }); // 데이터 게시 postRequest.write(postData); postRequest.end();};

    내 기술로 사용한 의도 발췌:

    <울>
  • ReadHumidityIntent 내 식물은 어떻습니까
  • <울>
  • ReadHumidityIntent 내 {plantName} 상태
  • <울>
  • IrrigatePlantIntent 내 식물에 관개
  • <울>
  • IrrigatePlantIntent 내 {plantName}을(를) {durationSeconds}초 동안 관개합니다.
  • <울>
  • SwitchIntent 램프 {switchState} 전환
  • <울>
  • ReadIrrigateIntent 물이 필요한 식물
  • <울>
  • ReadLastIrrigationIntent 내 {plantName}의 마지막 관개는 언제였습니까?
  • 마지막으로 독일어와 영어 사용을 위한 로케일 지원을 추가했습니다.

    결과

    결과적으로, 나는 슈퍼마켓 허브 화분을 넣을 나무 상자를 가지고 있으며, 토양에 물 튜브와 수분 센서를 가져오고 외부 물 탱크에 튜브를 가져갑니다. Alexa 통합으로 다음 문장을 말할 수 있습니다.

    <울>
  • "Alexa, 허브 상자에 내 식물이 어떤지 물어보세요 " - 응답:"공장 1은 괜찮고, 공장 2는 건조하고, ..."
  • <울>
  • "Alexa, 약초 상자에 내 바질을 5초 동안 관개하도록 지시 " - 응답:"5초 동안 바질 관수"
  • <울>
  • "Alexa, 어떤 식물에 관개가 필요한지 허브 상자에 물어보세요. " - 응답:"공장 1은 건조, 공장 3은 건조, ..."
  • <울>
  • "Alexa, 허브 상자에 마지막 관개가 언제였는지 물어보세요 나의 바질 " - 응답:"바질의 마지막 관개는 36시간 전이었습니다."
  • <울>
  • "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.mp4

    Alexa에게 식물 성장 램프를 켜달라고 요청:

    <비디오 너비="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:

    계획된 기능

    다음 기능은 아직 구현되지 않았지만 향후 계획됩니다.

    <울>
  • Arduino 소스 코드의 절전 모드
  • <울>
  • 무선 통신(2,4GHz)이 있는 외부 Arduino Nanos를 추가하여 집안의 다른 식물의 수분 측정(상자는 WiFi의 허브임) - 배터리만 사용
  • <울>
  • 친구(그리고 관심 있는 사람이라면?!)를 위해 허브 상자의 여러 인스턴스에 대한 API 확장
  • <울>
  • 웹사이트 또는 Alexa가 없는 상자에 관개 및 램프 전환 버튼 추가
  • <울>
  • Alexa 이미지(스킬 응답의 카드)
  • 2018년 3월 23일 업데이트

    두 가지 새로운 의도를 추가했습니다. 그 중 하나는 습도를 기록하는 외부 Adruino Nano의 계획된 기능에 중요합니다.

    <울>
  • 건조한 식물
  • <울>
  • 마지막 관개 시기
  • <섹션 클래스="섹션 컨테이너 섹션 축소 가능" id="코드">

    코드

    <울>
  • EcoActionBuffer.h
  • EcoActionBuffer.cpp
  • 공장.cpp
  • 공장.h
  • WhiteWalnut.ino
  • WhiteWalnutApi.cpp
  • WhiteWalnutApi.h
  • EcoActionBuffer.hArduino
    #ifndef ECOACTIONBUFFER_H#define ECOACTIONBUFFER_H#include "Arduino.h#include "StensTimer.h"구조 EcoActionBuffer :public IStensTimerListener { long entryNo; 인트 액션; 인트 핀; 장기간; 무효 timerCallback(타이머* 타이머); 무효 switchPin(int 핀, 부울 값); 무효 readStack(); 무효 프로세스(); 무효 toSerial(); 무효 리셋();};#endif
    EcoActionBuffer.cpp아두이노
    #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();}
    Plant.cppArduino
    #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();}
    Plant.hArduino
    #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
    WhiteWalnut.ino아두이노
    #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(); 부서지다; }}
    WhiteWalnutApi.cpp아두이노
    WiFi 및 API 설정을 추가해야 합니다.
    #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;}
    WhiteWalnutApi.hArduino
    #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

    회로도

    Chart about the communication and interfaces All implemented intents you can ask Alexa, including the response.
    (multilingual) If you are interested in the entrance step of your alexa json parsing.

    제조공정

    1. 웹 운영 DMX 컨트롤러
    2. Arduino 스파이봇
    3. Arduino 알람 시스템:SERENA
    4. Arduino + ESP Weather Box
    5. 지하실/크롤 공간 환기 시스템
    6. Arduino 및 Google 스프레드시트 기반 출석 시스템
    7. BLUE_P:무선 Arduino 프로그래밍 실드
    8. Arduino 기반 충돌 감지 경고 시스템
    9. Arduino Nano용 TFT Shield - 시작
    10. Arduino Shield NCS314 NIXIE 튜브 시계 IN-14