Herb Box 生态系统
组件和用品
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
| × | 2 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
![]() |
| × | 1 |
应用和在线服务
![]() |
| |||
![]() |
| |||
![]() |
| |||
|
关于这个项目
由于我的植物总是受到过多或过少的水的影响,而且我喜欢在菜肴中加入大量草药,因此我决定创建一个定制的灌溉系统。我的草药盒应该是可配置的,可以自动或手动工作。因此,存在一个网站界面以启用设置并在漂亮的图表中显示湿度。最后一步是集成语音控制,向亚马逊 Alexa 询问湿度,打开/关闭植物生长灯,并在禁用自动化时启动灌溉。点击这里查看结果。
我从项目的技术部分开始,买了一个 Arduino。经过一些教程,我对软件和控制 Arduino 有了坚定的信念。我订购了一个 wifi 控制器、一些湿度传感器、泵、一个植物生长灯和额外的必需硬件(relais shield 将灯和泵的电路与 Arduino 分开,一些电线和山毛榉木用于框架)。本教程提供了结果的 Arduino 代码,以及如何在项目中使用组件的一些信息。不提供网站/api代码(除非要求非常高;))。
第一步:湿度传感器
第一个里程碑是用我的 Arduino 读取湿度。湿度传感器 YL-69 很容易与 Arduino 连接。您需要将 VCC 引脚连接到 Arduino 的 GPIO 引脚(在我的示例引脚 06 中)、接地和 A0 到模拟引脚(在我的示例引脚 A1 中)。
教程:土壤湿度传感器
byte vccPin =6;byte dataPin =A1;void setup() { pinMode(vccPin, OUTPUT);数字写入(vccPin,低); Serial.begin(9600); while (!Serial);}int readHumidity() { digitalWrite(vccPin, HIGH);延迟(500); // 你需要在测量前测试你预通电的时间 int value =analogRead(dataPin);数字写入(vccPin,低); return 1023 - value;}void loop() { Serial.print("HumidityLevel (0-1023):"); Serial.println(readHumidity());延迟(10000);}
第二步:泵和灯的继电器
下一个目标是安装一个继电器屏蔽(4 个继电器)来分隔灯、泵和 Arduino 的电路。 Arduino 以 5V 运行,泵使用 12V,植物生长灯使用 230V。屏蔽需要连接到 Arduino 上的 5V 和接地引脚。每个继电器还需要一个您选择的 GPIO 引脚来打开和关闭。最后,您可以在屏蔽上使用 VCC JC 到 VCC 的跳线,或者使用额外的电池(这会是最好的,但我的项目中还没有任何电池)。
重要的是要了解,我的屏蔽在引脚上以“低”开关“打开”。一旦我的引脚被定义为输出,它就会自动切换到活动状态。在代码中,如果您希望继电器关闭,您应该始终切换到 INPUT 和 LOW。默认情况下,Arduino 引脚为 INPUT 和低电平。
教程:中继盾
信息:为什么继电器 OUTPUT + LOW =Active?
byte pump1 =11;byte pump2 =10;void setup() { Serial.begin(9600);而(!串行); pinMode(泵1,输出); // 变量低/高 digitalWrite(pump2, LOW); // 变量输入/输出}void loop() { digitalWrite(pump1, HIGH); // pump1 停用 pinMode(pump2, INPUT); // pump2 停用延迟(1000);数字写入(泵 1,低); // pump1 激活 pinMode(pump2, OUTPUT); // pump2 激活延迟(1000);}
第三步:使用 ESP-01 的 WiFi
将 espressif ESP8266 ESP-01 连接到 Arduino for WiFi 是最困难的部分。我花了几个小时才让 wifi 在我的脚本中运行。
ESP 连接到:VCC =3.3V,GND =GND,CH_PD =3.3V,TX =引脚 02,RX =引脚 03。为了生产使用,你应该至少使用一个从 5V 到 3.3V 的电平转换器作为引脚02 和引脚 03,也是。就我而言,它运行良好。
与 Arduino 类似,ESP-01 是另一个微控制器。如果您希望两个控制器进行通信,则必须使用串行通信。 Arduino UNO 默认使用引脚 01 和 02 作为 RX 和 TX。但它们也用于 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 命令并查看结果。串口通讯容易出现故障,因此我将ESP使用的通讯波特率从115200降低到9600。
教程:ESP8266 + Arduino |教程:ESP8266通用(德语)
- 一个有用的辅助类(但使用了太多内存):库:WiFiEsp
- 内存检查工具:库:MemoryFree


该脚本使用 HTTP 1.0,因为对于 HTTP 1.1,字节是响应的一部分。重要的是要注意 AT+CIPSEND 之后要发送的命令的换行符。如果它们是错误的,您将收到一个字节发送错误。
#include SoftwareSerial espSerial(3,2); // RX, TXconst char* ssid ="";const char* pass ="";void setup() { Serial.begin(9600); espSerial.begin(9600);而(!串行); while(!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() { delay(2000;) espSerial.setTimeout(3000);而 (espSerial.available()) Serial.write(espSerial.read()); Serial.println(F("[ESP] 连接到 WiFi")); espSerial.println(F("AT+CIPSTATUS=2")); if (!espSerial.find("OK")) { espSerial.setTimeout(10000); Serial.println(F("[ESP] 重置模块")); espSerial.println(F("AT+RST")); if (!espSerial.find("ready")) { Serial.println(F("[ESP] 重置失败"));返回假; Serial.println(F("[ESP] 设置 CWMode")); 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(pass); espSerial.println ("\""); if (!espSerial.find("OK")) { Serial.println(F("[ESP] WiFi 连接失败"));返回假; espSerial.setTimeout(3000); Serial.println(F("[ESP] WiFi 已连接")); return true;}bool httpRequest(String server, String site) { String cmd =""; cmd +="GET " + 站点 + " HTTP/1.0\r\n"; cmd +="主机:" + 服务器 + "\r\n"; cmd +="连接:关闭"; int cmdLength =cmd.length() + 4; // Serial.println(cmd); espSerial.print(F("AT+CIPSTART=\"TCP\",\"")); espSerial.print(server); espSerial.println(F("\",80")); if (!espSerial.find("OK")) { Serial.println(F("[ESP] TCP 连接错误"));返回假; espSerial.print(F("AT+CIPSEND=")); espSerial.println(cmdLength); 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("Bytes not sent")); espSerial.print(F("AT+CIPCLOSE"));返回假; } 字符状态[32] ={0}; espSerial.readBytesUntil('\r', status, sizeof(status)); 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] Bytes not found"));返回; } // 跳过字节(对于 http 1.1)返回 true;i}
第四步:木箱
该框架计划存放超市的所有电子产品和三个药草罐。我测量了所有组件的尺寸并构建了位置。四个湿度传感器、两个泵、Arduino + 扩展板、一个 4x 继电器扩展板和一个 USB 插头以及一些电线需要装入盒子中。它由山毛榉木制成,使其坚固耐用,无需额外上釉。

在自制曲线锯台上用曲线锯锯出圆圈。植物支架用热胶粘在圆圈内。盒子的侧面用木胶(D3防水)粘合。除了电子,我没有在下面板固定旁边使用任何螺丝或钉子。



我把所有的电路、电线和水管放在盒子里,拉出传感器和额外水箱的管子。关闭盒子之前,我加了碟子,防止水淹在盒子里,保护电子设备。


第五步:网站 API
API 和网站基于 jQuery、Bootstrap、X-editable(用于内联 ajax 表单)和 Chart.js(用于湿度图表),用 php 编码。在网站上,您可以定义 Arduino 的设置(例如传感器引脚、湿度检查间隔、每株泵、泵 VCC 引脚、光 VCC 引脚)并找到当前湿度 + 图表。

配置由 JSON 提供给 Arduino。开始并在频繁的间隔后,药草框检查新设置。为了用 Arduino 解析 JSON,我使用了库 ArduinoJson。对于轮询间隔,我使用了 StensTimer。
库:ArduinoJson |图书馆:StensTimer
第六步:Alexa 集成
该网站提供了用于 Alexa 通信的 API。它用作接收 Alexa 请求 JSON 并将其转换为 Arduino 使用的自定义 JSON(例如,开灯、灌溉植物 1 等)的集线器。 Arduino 轮询新动作并执行它们。

因为语音请求不仅仅是开/关,所以我实施了 Alexa Skill 而没有 Alexa Smart Home。 AWS Lampda 将请求 JSON 转发到我的 API,后者解析意图。
var https =require('https');exports.handler =(event, context, callback) => { var postData =JSON.stringify(event); var options ={ host:'', path:'', port:443, method:'POST', headers:{ 'Content-Type':'application/json' , 'Content-Length':postData.length, } }; // 设置请求 var postRequest =https.request(options, function(res) { res.setEncoding('utf8'); res.on('data', function (chunk) { console.log('Response:' + chunk); // console.log(chunk); 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,告诉 Herb box 打开灯 “ - 响应:“打开植物生长灯”

向 Alexa 询问我的植物的湿度并随后对其进行灌溉(德语):
要求 Alexa 打开植物生长灯:
没有视频的 GIF 显示结果:


计划功能
以下功能尚未实现但计划在未来实现:
- Arduino 源代码的省电模式
- 添加具有无线通信 (2,4 GHz) 的外部 Arduino Nanos,用于测量屋内其他植物的水分(盒子是 WiFi 的集线器) - 仅使用电池
- 为多个药草盒实例扩展 API,为朋友(以及任何人,如果您感兴趣?!)
- 在没有网站或Alexa的盒子上添加一个按钮来灌溉和开关灯
- Alexa 图像(技能响应中的卡片)
23.03.2018 更新
我添加了两个新意图。其中之一对于仅记录湿度的外部 Adruino Nanos 的计划功能很重要。
- 哪些植物是干的
- 最后一次灌溉是什么时候
代码
- EcoActionBuffer.h
- EcoActionBuffer.cpp
- Plant.cpp
- Plant.h
- WhiteWalnut.ino
- WhiteWalnutApi.cpp
- WhiteWalnutApi.h
EcoActionBuffer.hArduino
#ifndef ECOACTIONBUFFER_H#define ECOACTIONBUFFER_H#include "Arduino.h"#include "StensTimer.h"struct EcoActionBuffer :public IStensTimerListener { long entryNo;行动;内部引脚;持续时间长; void timerCallback(Timer* timer); void switchPin(int pin, bool value);无效的读取堆栈();无效过程(); void toSerial(); void reset();};#endif
EcoActionBuffer.cppArduino
#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) { process(); // WhiteWalnutApi::updateActionOnStack(*this); // 为性能而停用 }}void EcoActionBuffer::process() { toSerial(); pinMode(pin, 输出);数字写入(引脚,高); switch (action) { case ACTION_ECOACTION_HIGH:switchPin(pin, true);休息; case ACTION_ECOACTION_LOW:switchPin(pin, false);休息; } if (duration !=0) { StensTimer::getInstance()->setTimer(this, -pin, duration); }}void EcoActionBuffer::timerCallback(Timer* timer) { switch (timer->getAction()) { case ACTION_ECOACTION_READ:readStack();休息; } if (timer->getAction() <0) { switchPin(abs(timer->getAction()), false); }}void EcoActionBuffer::switchPin(int pin, bool value) { switch (value) { case true:digitalWrite(pin, LOW);休息;情况为假:digitalWrite(pin, HIGH);休息; } WhiteWalnutApi::switchPin(pin, value);}void EcoActionBuffer::reset() { entryNo =0;动作 =0;引脚 =0;持续时间 =0;}void EcoActionBuffer::toSerial() { Serial.print(entryNo); Serial.print(F(" - 动作:")); Serial.print(action); Serial.print(F(", Pin:")); Serial.print(pin); Serial.print(F(", Duration:")); Serial.print(持续时间); Serial.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 (hydrityDataPin !=0) { Serial.print (代码); Serial.print(F(" - 检查湿度..."));数字写入(PIN_HUMIDITY_VCC,高);延迟(200); // TODO int 湿度 =1023 - 模拟读取(湿度数据引脚);数字写入(PIN_HUMIDITY_VCC,低); Serial.println(湿度); WhiteWalnutApi::sendHumidity(*this, 湿度);如果(湿度检查间隔==0)湿度检查间隔=60000; StensTimer::getInstance()->setTimer(this, ACTION_PLANT_CHECKHUMIDITY,hydrationCheckInterval); } else StensTimer::getInstance()->setTimer(this, ACTION_PLANT_CHECKHUMIDITY, 60000);}void Plant::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();休息; }}void Plant::toSerial() { Serial.print(code); Serial.print(F(" - DataPin:")); Serial.print(湿度数据Pin); Serial.print(F(", 间隔:"));串行打印(湿度检查间隔); Serial.println();}
Plant.hArduino
#ifndef PLANT_H#define PLANT_H#include "Arduino.h"#include "StensTimer.h"struct Plant :public IStensTimerListener { const char* code; int 湿度数据引脚;长湿度检查间隔;无效检查湿度(); void timerCallback(Timer* timer); void toSerial(); void updateApi();};#endif
WhiteWalnut.inoArduino
#include "EcoActionBuffer.h"#include "Plant.h"#include "StensTimer.h"#include "WhiteWalnutApi.h"struct TimerHelper :public IStensTimerListener { public:void updateApi(); void timerCallback(Timer* timer);};StensTimer* stensTimer;TimerHelper apiTimer;Plant leftPlant;Plant centerPlant;Plant rightPlant;Plant externalPlant;EcoActionBuffer actionBuffer;#define ACTION_PLANT_UPDATE 1#define ACTION_ECOACTION_READ 1void setup() { Serial.begin);而(!串行); stensTimer =StensTimer::getInstance(); leftPlant.code ="左"; centerPlant.code ="中心"; rightPlant.code ="正确"; externalPlant.code ="外部"; while(!WhiteWalnutApi::connectToWiFi()) delay(2000); WhiteWalnutApi::switchPin(0, false); 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();}void TimerHelper::timerCallback(Timer* timer){ switch (timer->getAction()) { case ACTION_PLANT_UPDATE:updateApi();休息; }}
WhiteWalnutApi.cppArduino
你需要添加你的 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 ="ready";char* findGT =">";char* findDP =":";char* findHD ="\r\n\r\n";char* findBT ="\r\n"; bool 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"));如果 (!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] 设置 CWMode")); 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(pass); 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(site)) connectToWiFi(); JsonObject&root =parseJson(); if (root.success()) { plant.hydrityDataPin =root["dataPin"].as ();植物湿度检查间隔 =atol(root["interval"].as ()); }}void WhiteWalnutApi::sendHumidity(Plant&plant, int 湿度) { String site =String(API_PLANT) + "?action=hydrity&code=" + String(plant.code) + "&humidity=" + String(humity);而 (!httpRequest(site)) connectToWiFi(); // TODO:REMOVE RETURN}void WhiteWalnutApi::sendHeartbeat(Plant&plant) { String site =String(API_PLANT) + "?action=heartbeat&code=" + String(plant.code); while (!httpRequest(site)) connectToWiFi();}void WhiteWalnutApi::receiveActionFromStack(EcoActionBuffer&actionBuffer) { while (!httpRequest(String(API_ACTION))) connectToWiFi(); JsonObject&root =parseJson(); if (root.success()) { actionBuffer.entryNo =atol(root["entryNo"].as ()); actionBuffer.action =root["actionEnum"].as (); actionBuffer.pin =root["pin"].as (); actionBuffer.duration =atol(root["value"].as ()); }}void WhiteWalnutApi::updateActionOnStack(EcoActionBuffer&actionBuffer) { String site =String(API_ACTION) + "?action=processed&entryNo=" + String(actionBuffer.entryNo); while (!httpRequest(site)) connectToWiFi();}void WhiteWalnutApi::switchPin(int pin, bool value) { String site =String(API_ACTION) + "?action=switch&pin=" + String(pin) + "&value=" + 字符串(值); while (!httpRequest(site)) connectToWiFi();}bool WhiteWalnutApi::httpRequest(String site) { // char* cmd; // sprintf(cmd, "GET %s HTTP/1.0\r\nHost:%s\r\nConnection:close", site, API_SERVER); /* 字符串 cmd =""; cmd +="GET " + 站点 + " HTTP/1.0\r\n"; cmd +="主机:" + String(API_SERVER) + "\r\n"; cmd +="连接:关闭"; int cmdLength =cmd.length() + 4; Serial.println(cmd); */ int cmdLength =44 + site.length() + strlen(API_SERVER); // Serial.print(F("[MEMORY] ")); // 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(cmdLength); // 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("Host:")); espSerial.print(API_SERVER); espSerial.print(F("\r\n")); espSerial.print(F("Connection:close\r\n")); espSerial.println(); // while (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
(multilingual)


制造工艺