本网页已闲置超过3分钟,按键盘任意键或点击空白处,即可回到网页

基于 AWS 的植物盒生态系统

发布时间:2021-12-17
分享到:

基于 AWS 的植物盒生态系统

发布时间:2021-12-17
分享到:

该盒子可以记录湿度、自动灌溉、打开植物生长灯并使用 Amazon Alexa 和 Arduino 语音控制一切。

由于我的植物总是受到过多或过少的水的影响,而且我喜欢在菜肴中加入大量草药,因此我决定创建一个定制的灌溉系统。我的草药盒应该是可配置的,可以自动或手动工作。因此,存在一个网站界面以启用设置并在漂亮的图表中显示湿度。最后一步是集成语音控制,向亚马逊 Alexa 询问湿度,打开/关闭植物生长灯,并在禁用自动化时启动灌溉。

第一步:湿度传感器
第一个里程碑是用我的 Arduino 读取湿度。湿度传感器 YL-69 很容易与 Arduino 连接。您需要将 VCC 引脚连接到 Arduino 的 GPIO 引脚(在我的示例引脚 06 中)、接地和 A0 到模拟引脚(在我的示例引脚 A1 中)。

第二步:泵和灯的继电器
下一个目标是安装一个继电器屏蔽(4 个继电器)来分隔灯、泵和 Arduino 的电路。Arduino 以 5V 运行,泵使用 12V,植物生长灯使用 230V。屏蔽需要连接到 Arduino 上的 5V 和接地引脚。每个继电器还需要一个您选择的 GPIO 引脚来打开和关闭。最后,您可以在屏蔽上使用 VCC JC 到 VCC 的跳线,或使用额外的电池(最好,但我的项目中还没有任何电池)。

重要的是要了解,我的屏蔽在引脚上以“低”开关“打开”。一旦我的引脚被定义为输出,它就会自动切换到活动状态。在代码中,如果您希望继电器关闭,您应该始终切换到 INPUT 和 LOW。默认情况下,Arduino 引脚为输入和低电平。

第三步:使用 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 并定义自定义引脚。

运行上面的脚本,您可以在串行监视器中输入 AT 命令并查看结果。串行通信容易出现故障,因此我将ESP使用的通信波特率从115200降低到9600。

该脚本使用 HTTP 1.0,因为对于 HTTP 1.1,字节是响应的一部分。重要的是要注意 AT+CIPSEND 之后要发送的命令的换行符。如果它们是错误的,您将收到一个字节发送错误。

#include <SoftwareSerial.h>
SoftwareSerial espSerial(3,2); // RX, TX
const char* ssid = "<YOUR-WIFI-SSID>";
const char* pass = "<YOUR-WIFI-PASSWORD>";
void setup() {
 Serial.begin(9600);
 espSerial.begin(9600);
 while(!Serial);
 while(!connectToWiFi());
 // request website and print result
 if (httpRequest("my.server.com", "/site/subsite/index.php")) {
   while (espSerial.available()) { Serial.write(espSerial.read()); }
 }
}
void loop() { // run over and over
 if (espSerial.available()) {
   Serial.write(espSerial.read());
 }
 if (Serial.available()) {
   espSerial.write(Serial.read());
 }
}
bool connectToWiFi() {
 delay(2000;)
 espSerial.setTimeout(3000);
 while (espSerial.available()) Serial.write(espSerial.read());
 Serial.println(F("[ESP] Connecting to WiFi"));
 espSerial.println(F("AT+CIPSTATUS=2"));
 if (!espSerial.find("OK")) {
   espSerial.setTimeout(10000);
   Serial.println(F("[ESP] Reset Module"));
   espSerial.println(F("AT+RST")); if (!espSerial.find("ready")) { Serial.println(F("[ESP] Reset failed")); return false; }
   Serial.println(F("[ESP] Set CWMode"));
   espSerial.println(F("AT+CWMODE=1")); if (!espSerial.find("OK")) { Serial.println(F("[ESP] Mode failed")); return false; }
   Serial.println(F("[ESP] Connect to Router"));
   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 connection failed")); return false; }
 }
 espSerial.setTimeout(3000);
 Serial.println(F("[ESP] WiFi is connected"));
 return true;
}
bool httpRequest(String server, String site) {
 String cmd = "";
 cmd += "GET " + site + " HTTP/1.0\r\n";
 cmd += "Host: " + server + "\r\n";
 cmd += "Connection: close";
 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 Connection Error")); return false; }
 espSerial.print(F("AT+CIPSEND="));
 espSerial.println(cmdLength);
 if (!espSerial.find(findGT)) { Serial.println(F("[ESP] Send State Error")); return false; }
 espSerial.print(F("GET "));
 espSerial.print(site);
 espSerial.print(F(" HTTP/1.0\r\n"));
 espSerial.print(F("Host: "));
 espSerial.print(server);
 espSerial.print(F("\r\n"));
 espSerial.print(F("Connection: close\r\n"));
 espSerial.println();
 if (!espSerial.find(":")) { Serial.println(F("Bytes not sent")); espSerial.print(F("AT+CIPCLOSE")); return false; }
 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); return false; }
 if (!espSerial.find("\r\n\r\n")) { Serial.println(F("[ESP] Invalid response")); return false; } // Skip HTTP headers
 // if (!espSerial.find(\r\n)) { Serial.println(F("[ESP] Bytes not found")); return; } // skip bytes (for http 1.1)
 return 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。

第六步: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: '<MY-SERVER>',
       path: '<MY-API-SITE>',
       port: 443,
       method: 'POST',
       headers: {
           'Content-Type': 'application/json',
           'Content-Length': postData.length,
       }
   };
   // set up the request
   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));
         });
   });
   // post the data
   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,告诉药草盒打开灯” - 回应:“打开植物生长灯”

计划功能
以下功能尚未实现,但计划在未来实现:

  • Arduino源代码的省电模式
  • 添加具有无线通信 (2,4 GHz) 的外部 Arduino Nanos,用于测量屋内其他植物的湿度(盒子是 WiFi 的集线器)-仅使用电池
  • 为多个药草盒实例扩展 API,为朋友(以及任何人,如果您感兴趣?!)
  • 在没有网站或Alexa的盒子上添加一个按钮来灌溉和开关灯
  • Alexa 图像(技能响应中的卡片)

如果您对此项目有任何想法、意见或问题,请在下方留言。

原文链接丨以上内容来源网络,如涉及侵权可联系删除。

加入微信技术交流群

技术交流,职业进阶

关注与非网服务号

获取电子工程师福利

加入电路城 QQ 交流群

与技术大牛交朋友

讨论