在这个项目中,我们将使用物联网构建一个智能农业系统。该项目的目的是帮助农民获取实时数据(温度、湿度、土壤水分、土壤温度),以进行有效的环境监测,从而使他们能够提高产品的整体产量和质量。这种使用由 NodeMCU 驱动的物联网系统的智能农业由 DHT11 传感器、湿度传感器、DS18B20 传感器探头、LDR、水泵和 12V LED 灯条组成。当基于物联网的农业监测系统启动时,它会检查土壤湿度、温度、湿度和土壤温度。然后它将这些数据发送到物联网云进行实时监控。如果土壤湿度低于一定水平,它会自动启动水泵。我们之前建自动植物灌溉系统 在移动设备上发送警报但不监控其他参数。除此之外, 雨水报警 和 土壤湿度检测电路 也有助于构建智能农业监测系统。
智慧农业系统所需组件
硬件
NodeMCU ESP8266
土壤湿度传感器
DHT11 传感器
DS18B20 防水温度传感器探头
LDR
潜水迷你水泵
12V LED灯条
7805稳压器
2×TIP122晶体管
电阻器(4.7K、10K)
电容器(0.1µF、10µF)
在线服务
Adafruit IO
智慧农业系统电路图
智能农业系统的完整示意图如下:
这个电路并不难。这里我们使用了4个传感器,即DHT11,DS18B20传感器探头,LDR和土壤湿度传感器,一个12V LED灯条,12V水泵,7805稳压器,以及两个TP122晶体管来控制LED灯条和水泵。7805 用于从 12V 适配器获得稳压 5V,DHT11 传感器用于获取温度和湿度读数。DS18B20传感器探头用于获取土壤温度,土壤湿度传感器用于读取土壤湿度,以便自动打开/关闭水泵。
Adafruit IO 设置
Adafruit IO 是一个开放数据平台,可让您聚合、可视化和分析云上的实时数据。使用 Adafruit IO,您可以通过 Internet 上传、显示和监控您的数据,并使您的项目支持物联网。您可以使用 Adafruit IO 在互联网上控制电机、读取传感器数据并制作酷炫的 IoT 应用程序。
要使用 Adafruit IO,首先,您必须在 Adafruit IO 上创建一个帐户。为此,请访问 Adafruit IO 网站并单击屏幕右上角的“免费入门”。
完成帐户创建过程后,登录您的帐户并单击右上角的“查看 AIO Key”以获取您的帐户用户名和 AIO 密钥。
当您“AIO 密钥”时,将d出一个窗口,其中包含您的 Adafruit IO AIO 密钥和用户名。复制此密钥和用户名。您稍后将在代码中使用它。
现在,在此之后,您需要创建一个提要。要创建提要,请单击“提要”。然后单击“ *** 作”,您将看到一些选项,从中单击“创建新提要”。
之后,将打开一个新窗口,您需要在其中输入提要的名称和描述。书写描述是可选的。
点击“创建”;在此之后,您将被重定向到新创建的提要。
对于这个项目,我们总共为水泵、LED 灯条、湿度数据、温度、湿度、天气数据和土壤温度创建了 8 个源。按照与上述相同的过程创建其余的提要。
创建提要后,现在我们将创建一个 Adafruit IO 仪表板,以在单个页面上显示所有这些提要。为此,首先创建一个仪表板,然后在该仪表板中添加所有这些提要。
要创建仪表板,请单击仪表板选项,然后单击“ *** 作”,然后单击“创建新仪表板”。
在下一个窗口中,输入仪表板的名称,然后单击“创建”。
创建仪表板后,现在我们将块添加到仪表板。要添加块,请单击右上角的“齿轮”,然后单击“创建新块”。
首先,我们将添加两个切换按钮块来手动打开/关闭 LED 灯条和水泵,然后添加四个滑块来显示温度、湿度、土壤温度和水分值,最后,两个图表块来显示最近 30 天的水分和土壤温度数据。要在仪表板上添加按钮,请单击 Toggle 块。
在下一个窗口中,它将要求您选择提要,因此单击 LED 提要。
在此之后,按照相同的过程添加其余的块。添加所有块后,我的仪表板如下所示:
您可以通过单击设置按钮来编辑仪表板。
获取 OpenWeatherMap API
如前所述,我们还将在 Adafruit IO 仪表板上显示天气预报,为此,我们将使用OpenWeatherMap API 请求所选位置的当天天气预报。OpenWeatherMap 提供了高度可识别的天气产品,使处理天气数据变得更加容易。可以通过遵循行业标准并与不同类型的企业系统兼容的快速、可靠的 API 访问这些数据。OpenWeatherMap 提供付费和免费计划,在这个项目中,我们将使用它的免费计划来获取天气预报数据。
现在要获取 API 密钥,必须在他们的平台上注册,所以首先创建一个帐户,一旦您的帐户被创建,您将被重定向到仪表板,如下所示。从那里单击您的姓名,然后单击“我的 API 密钥”,您将看到一个唯一的 API 密钥以从站点中提取信息。
现在我们将使用 5 天/3 小时的预测数据 API。此 API 包含间隔 3 小时的天气预报数据,并且预报数据以 JSON 或 XML 格式提供。要获取您选择的位置的天气数据,请输入以下 URL,将大括号中的部分替换为城市和您的唯一 API 密钥:
api.openweathermap.org/data/2.5/forecast?q={城市名称}&appid={API 密钥}
例如,我们的 API URL 将是:
api.openweathermap.org/data/2.5/forecast?q=斋浦尔&appid=e8b22b36da932dce8f31ec9be9cb68a3
将此 URL 粘贴到浏览器的搜索栏中,它应该会为您提供一堆与您当地的天气预报信息相对应的信息。
现在我们有了 JSON 数据,下一步将生成代码,通过它我们可以读取 JSON 数据并根据需要对其进行表述。为此,请转到ArduinoJson 助手并在第一步中选择处理器类型、模式和输入类型。
然后在下一部分中,粘贴 JSON 数据。
然后在最后一步,您将获得读取天气预报数据的代码。我们不会使用助手生成的完整代码。
智能农业系统编程NodeMCU
基于物联网的农业监测系统的完整代码在文档末尾给出。在这里,我们将解释代码的一些重要部分。该代码使用DallasTemperature、OneWire、 Adafruit_MQTT、 ArduinoJson和DHT.h库。Adafruit_MQTT.h和DHT11.h可以从给定的链接下载,其余的库可以直接从 Arduino IDE 库管理器下载。
将库安装到 Arduino IDE 后,通过包含所需的库文件来启动代码。
#include#include <达拉斯温度.h> #include #include "DHT.h" #include "Adafruit_MQTT.h" #include "Adafruit_MQTT_Client.h" #include
然后输入您从 Adafruit IO 服务器复制的 Wi-Fi 和 Adafruit IO 凭据。这些将包括 MQTT 服务器、端口号、用户名和 AIO 密钥。
const char *ssid = "Wi-Fi 名称"; const char *pass = "Wi-Fi 密码"; #define MQTT_SERV "io.adafruit.com" #define MQTT_PORT 1883 #define MQTT_NAME "Adafruit IO 用户名" #define MQTT_PASS "AIO 密钥"
然后设置用于存储传感器数据和控制 LED 和水泵的 Adafruit IO 馈送。在我的例子中,我定义了四个馈送来存储不同的传感器数据,即:土壤温度、温度、湿度和湿度,一个用于显示天气数据的馈送和两个用于控制 LED 灯条和水泵的馈送。
Adafruit_MQTT_Client mqtt(&client, MQTT_SERV, MQTT_PORT, MQTT_NAME, MQTT_PASS); Adafruit_MQTT_Publish Moisture = Adafruit_MQTT_Publish(&mqtt,MQTT_NAME "/f/Moisture"); Adafruit_MQTT_Publish 温度 = Adafruit_MQTT_Publish(&mqtt,MQTT_NAME "/f/Temperature"); Adafruit_MQTT_Publish Humidity = Adafruit_MQTT_Publish(&mqtt,MQTT_NAME "/f/Humidity"); Adafruit_MQTT_Publish SoilTemp = Adafruit_MQTT_Publish(&mqtt,MQTT_NAME "/f/SoilTemp"); Adafruit_MQTT_Subscribe LED = Adafruit_MQTT_Subscribe(&mqtt, MQTT_NAME "/f/LED"); Adafruit_MQTT_Subscribe Pump = Adafruit_MQTT_Subscribe(&mqtt, MQTT_NAME "/f/Pump");
现在在setup()函数中,以 9600 的波特率初始化串行监视器以进行调试。同时使用begin()函数初始化 DHT 传感器和 DS18B20 传感器。
无效设置() { 序列号.开始(9600); 延迟(10); dht.begin(); 传感器.开始(); ……………….. }
现在是void loop()。这是执行所有任务的地方。因此,在这个循环中,首先我们将从 OpenWeatherMap API 获取天气预报数据,然后我们将读取传感器数据,最后一步,我们将在 Adafruit IO 仪表板上发布所有这些数据。
阅读天气预报:
要从 OpenWeatherMap API 读取天气预报数据,我们将使用我们使用 ArduinoJson 助手生成的代码片段。在 void 循环中,我们只会在特定时间间隔后调用 API,以免超出每日限制。
if (millis() - lastConnectionTime > posTInterval) { // 注意建立连接的时间: 最后连接时间 = 毫秒(); makehttpRequest(); }
读取传感器数据:
现在获取天气数据后,接下来我们将读取所有传感器数据。这里我们使用 DHT11、DS18B20、LDR 和土壤湿度传感器。LDR 和土壤湿度传感器数据将用于自动化 LED 灯条和水泵。所以首先我们将读取 LDR 状态,如果 LDR 读数小于 200,则 LED 将自动打开。同样,如果土壤水分百分比小于 35,则水泵将打开。
int ldrStatus = 模拟读取(ldrPin); 如果(ldrStatus <= 200){ 数字写入(ledPin,高); } 别的 { 数字写入(ledPin,低);} 湿度百分比 = ( 100.00 - ( (analogRead(moisturePin) / 1023.00) * 100.00 ) ); 如果(水分百分比 < 35){ 数字写入(motorPin,高); } 温度 = dht.readTemperature(); 湿度 = dht.readHumidity(); 传感器.requestTemperatures(); 土壤温度 = 传感器.getTempCByIndex(0);
在 Adafruit IO 上发布数据:
现在我们已经收集了所有数据,是时候在 Adafruit IO 仪表板上发布这些数据了,以便我们可以从任何地方对其进行监控。在这里,我们会将不同的传感器数据发布到各自的提要中。
if (currentTime - previousTime >= 间隔) { if (! Moisture.publish(moisturePercentage)) 如果(!温度。发布(温度)) 如果(!湿度。发布(湿度)) if (!SoilTemp.publish(soiltemp)) 如果(!WeatherData.publish(图标)) }
用于智能农业系统的 3D 打印外壳
由于这个项目将用于农业应用,我决定 3D 打印一个外壳。我用游标测量了装置的尺寸来设计外壳。完成后,我的设计看起来像这样:
对设计满意后,我将其导出为 STL 文件,根据打印机设置对其进行切片,最后打印出来。STL 文件也可以从 Thingiverse 下载,您可以使用它打印自己的外壳。
打印完成后,我继续将项目设置组装在一个永久外壳中以备将来使用。完成连接后,我将电路组装到我的外壳中,一切都非常合适,如下所示:
测试智能农业系统
为了测试这个项目,我在塑料托盘中发了一些种子,如下图所示:
我将硬件盒安装在托盘旁边,将水泵连接到水瓶,并连接电源。完成后,它开始监测不同的参数,如土壤湿度、土壤温度等。所有这些读数都将发布在 Adafruit IO 仪表板上。
#include
#include
#include
#include "DHT.h"
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"
#include
const char *ssid = "银河-M20"; // 输入您的 WiFi 名称
const char *pass = "ac312124"; // 输入您的 WiFi 密码
WiFiClient 客户端;
#define MQTT_SERV "io.adafruit.com"
#define MQTT_PORT 1883
#define MQTT_NAME "aschoudhary" // 你的 Adafruit IO 用户
名 #define MQTT_PASS "1ac95cb8580b4271bbb6d9f75d0668f1" // Adafruit IO AIO key
const char server[] = "api.openweathermap.org ";
字符串 apiKey = "e8b22b36da932dce8f31ec9be9cb68a3";
字符串文本;
const char* icon="";
int jsonend = 0;
布尔 startJson = 假;
int 状态 = WL_IDLE_STATUS;
#define JSON_BUFF_DIMENSION 2500
unsigned long lastConnecTIonTIme = 10 * 60 * 1000; // 上次连接服务器的时间,以毫秒为单位
const unsigned long postInterval = 10 * 60 * 1000; // 发布间隔 10 分钟(10L * 1000L;测试延迟 10 秒)
const int ldrPin = D1;
常量 int ledPin = D0;
常量int湿气Pin = A0;// 湿度传感器引脚
const int motorPin = D8;
漂浮水分百分比;//湿度读数
int温度,湿度,土壤温度;
#define ONE_WIRE_BUS 4 //nodemcu 的 D2 引脚
#define DHTTYPE DHT11 //DHT 11
#define dht_dpin D4
DHT dht(dht_dpin, DHTTYPE);
单线单线(ONE_WIRE_BUS);
达拉斯温度传感器(&oneWire);
const unsigned long 间隔 = 50000;
unsigned long previousTime = 0;
//设置您要发布到
Adafruit_MQTT_Client mqtt(&client, MQTT_SERV, MQTT_PORT, MQTT_NAME, MQTT_PASS);
Adafruit_MQTT_Publish Moisture = Adafruit_MQTT_Publish(&mqtt,MQTT_NAME "/f/Moisture"); // Moisture 是将发布数据的源名称
Adafruit_MQTT_Publish Temperature = Adafruit_MQTT_Publish(&mqtt,MQTT_NAME "/f/Temperature");
Adafruit_MQTT_Publish Humidity = Adafruit_MQTT_Publish(&mqtt,MQTT_NAME "/f/Humidity");
Adafruit_MQTT_Publish SoilTemp = Adafruit_MQTT_Publish(&mqtt,MQTT_NAME "/f/SoilTemp");
Adafruit_MQTT_Publish WeatherData = Adafruit_MQTT_Publish(&mqtt,MQTT_NAME "/f/WeatherData");
//设置您订阅的订阅
源 Adafruit_MQTT_Subscribe LED = Adafruit_MQTT_Subscribe(&mqtt, MQTT_NAME "/f/LED");
Adafruit_MQTT_Subscribe Pump = Adafruit_MQTT_Subscribe(&mqtt, MQTT_NAME "/f/Pump");
无效设置()
{
序列.开始(9600);
延迟(10);
dht.begin();
传感器.开始();
mqtt.subscribe(&LED);
mqtt.subscribe(&Pump);
pinMode(ledPin,输出);
pinMode(ldrPin,输入);
数字写入(motorPin,低);// 最初保持电机关闭 digitalWrite
(ledPin, HIGH);
text.reserve(JSON_BUFF_DIMENSION);
Serial.println("正在连接");
序列号.println(ssid);
WiFi.开始(ssid,通过);
而(WiFi.status()!= WL_CONNECTED)
{
延迟(500);
Serial.print("."); // 打印...直到没有连接
}
Serial.println("");
Serial.println("WiFi 连接");
}
void loop()
{
unsigned long currentTime = millis();
MQTT_connect();
if (millis() - lastConnectionTime >
// 注意建立连接的时间:
lastConnectionTime = millis();
makehttpRequest();
}
//}
int ldrStatus = analogRead(ldrPin);
if (ldrStatus <= 200) {
digitalWrite(ledPin, HIGH);
Serial.print("天黑了,打开 LED :");
Serial.println(ldrStatus);
}
else {
digitalWrite(ledPin, LOW);
Serial.print("它很亮,关闭 LED :");
Serial.println(ldrStatus);
}
湿度百分比 = ( 100.00 - ( (analogRead(moisturePin) / 1023.00) * 100.00 ) );
Serial.print("土壤水分=");
序列号.print(moisturePercentage);
序列号.println("%");
if (moisturePercentage < 35) {
digitalWrite(motorPin, HIGH); // 调整电机
}
if (moisturePercentage > 38) {
digitalWrite(motorPin, LOW); // 关闭电机
}
temperature = dht.readTemperature();
湿度 = dht.readHumidity();
//Serial.print("温度:");
//Serial.print(温度);
//Serial.println();
//Serial.print("湿度:");
//Serial.print(湿度);
//Serial.println();
传感器.requestTemperatures();
土壤温度 = 传感器.getTempCByIndex(0);
// Serial.println("土壤温度:");
// Serial.println(soiltemp);
if (currentTime - previousTime >= Interval) {
if (!Moisture.publish(moisturePercentage)) //此条件用于在 adafruit IO 上发布变量 (moisturePercentage)。根据你的改变变量。
{
}
if (!Temperature.publish(temperature))
{
}
if (!Humidity.publish(humanity))
{
//delay(30000);
}
if (!SoilTemp.publish(soiltemp))
{
}
if (!WeatherData.publish(icon))
{
}
以前的时间 = 当前时间;
}
Adafruit_MQTT_Subscribe * 订阅;
while ((subscription = mqtt.readSubscription(5000))) //在控制某些东西或从 Adafruit IO 获取数据之前不要使用这个。
{
if (subscription == &LED)
{
//将新值打印到串口监视器
Serial.println((char*) LED.lastread);
if (!strcmp((char*) LED.lastread, "OFF"))
{
digitalWrite(ledPin, LOW);
}
if (!strcmp((char*) LED.lastread, "ON"))
{
digitalWrite(ledPin, HIGH);
}
}
if (subscription == &Pump)
{
//将新值打印到串口监视器
Serial.println((char*) Pump.lastread);
if (!strcmp((char*) Pump.lastread, "OFF"))
{
digitalWrite(motorPin, HIGH);
}
if (!strcmp((char*) Pump.lastread, "ON"))
{
digitalWrite(motorPin, LOW);
}
}
}
延迟(9000);
// client.publish(WeatherData, icon)
}
void MQTT_connect()
{
int8_t ret;
// 如果已经连接则停止。
if (mqtt.connected())
{
返回;
}
uint8_t 重试次数 = 3;
while ((ret = mqtt.connect()) != 0) // connect 将返回 0 连接
{
mqtt.disconnect();
延迟(5000);// 等待 5 秒
重试--;
if (retries == 0)
{
// 基本上死了,等待 WDT 重置我
while (1);
}
}
}
void makehttpRequest() {
// 在发送新请求之前关闭任何连接以允许客户端与服务器建立连接
client.stop();
// 如果连接成功:
if (client.connect(server, 80)) {
client.println("GET /data/2.5/forecast?q=" + nameOfCity + "&APPID=" + apiKey + "&mode=json&units=metric&cnt=2 HTTP/1.1");
client.println("主机:api.openweathermap.org");
client.println("用户代理:ArduinoWiFi/1.1");
client.println("连接:关闭");
客户端.println();
无符号长超时=毫秒();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println(">>> Client Timeout !");
客户端.stop();
返回;
}
}
字符 c = 0;
while (client.available()) {
c = client.
// 由于 json 包含相同数量的打开和关闭大括号,这意味着我们可以通过计算
打开和关闭出现次数来确定何时完全接收到 json,//
Serial.print(c);
if (c == '{') {
startJson = true; // 设置 startJson true 表示 json 消息已经开始
jsonend++;
}
if (c == '}') {
jsonend--;
}
if (startJson == true) {
text += c;
}
// 如果 jsonend = 0 那么我们收到了相同数量的花括号
if (jsonend == 0 && startJson == true) {
parseJson(text.c_str()); // 在 parseJson 函数中解析 c 字符串文本
text = ""; // 下次清空字符串
startJson = false; // 将 startJson 设置为 false,表示新消息尚未开始
}
}
}
else {
// 如果没有建立连接:
Serial.println("connection failed");
返回;
}
}
//解析从OWM接收的json数据
void parseJson(const char * jsonString) {
//StaticJsonBuffer<4000> jsonBuffer;
const size_t bufferSize = 2*JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(2) + 4*JSON_OBJECT_SIZE(1) + 3*JSON_OBJECT_SIZE(2) + 3*JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + 2*JSON_OBJECT_SIZE(7) + 2 *JSON_OBJECT_SIZE(8) + 720;
DynamicJsonBuffer jsonBuffer(bufferSize);
// DynamicJsonDocument(bufferSize);
// 在 JSON 树中查找
字段 JsonObject& root = jsonBuffer.parseObject(jsonString);
if (!root.success()) {
Serial.println("parseObject() failed");
返回;
}
JsonArray& list = root["list"];
JsonObject& nowT = list[0];
JsonObject& 稍后 = 列表 [1];
JsonObject& tommorow = list[2];
// 字符串条件 = list.weather.main;
// 包括温度和湿度,供那些可能想破解它的人使用
String city = root["city"]["name"];
字符串 weatherNow = nowT["天气"][0]["描述"];
String weatherLater = later["weather"][0]["description"];
String list12 = later["weather"][0]["list"];
序列号.println(list12);
Serial.println(weatherLater);
if(weatherLater == "几朵云"){
icon = "几朵云";
序列号.print(icon);
}
else if(weatherLater == "rain"){
icon = "Rain";
序列号.print(icon);
}
else if(weatherLater == "破云"
){ icon = "破云";
序列号.print(icon);
}
否则{
图标=“晴天”;
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)