arduino uno 与 esp01s 利用mqtt网页控制led、舵机、风扇、喷灌器,做一个简单的基于arduino的温室智能系统

问题遇到的现象和发生背景

1、wifi模块有时候会检测不到
2、arduino想要发送温湿度、co2浓度、光照强度、土壤湿度等其他数据 上传不了那么多,串口会显示乱码然后不发生数据消息到mqtt
3、用node-red制作了一个网页端 用来控制led、舵机、风扇、加水机,但是每次控制加水机的时候,按钮按完发送消息,加水机打开后mqtt就会断开重连不上(电池拿掉只控制继电器的话是正常的,电池装了后控制后就会不能继续运行),其他的控制暂时没出现问题
4、有环境变化自动控制,但是网页端控制希望在因为环境变化的时候风扇开启,但是我可以用网页端关掉正在运行风扇(没思路)

全部代码
#include <dht11.h>
#include "SGP30.h"
#include "WiFiEspAT.h"
#include "SoftwareSerial.h"
#include <LiquidCrystal.h>
SoftwareSerial Serial1(0,6);    // RX, TX
#include <PubSubClient.h>         // MQTT通信使用的库


unsigned long previousMillis = 0;

const long interval = 2000; 


int ledpin=10;//定义数字10 接口
const int snpin=A0;//室内光敏电阻
const int swpin=A1;//室外光敏电阻
int fsPin = 8;//继电器引脚
int djPin = 7;    //定义舵机接口数字接口7 也就是舵机的橙色信号线。
int sensorPin = A2;    // 设置模拟口A2土壤湿度传感器
int pgjPin = 13;      // 设置继电器控制引脚为13
int sensorValue = 0;  // 存放模拟信号量的变量

int state=LOW;
int ddkg=0;
int fskg=2;
int pgkg=4;
int jlkg=6;


char ssid[] = "kk01";    // your network SSID (name)
char pass[] = "kk011209..";        // your network password
int status = WL_IDLE_STATUS;     // the Wifi radio's status
    
long lastMsg = 0;
char msg[50];

int value=0;
WiFiClient client;

PubSubClient pubSubClient(client); 
char server[] = "broker-cn.emqx.io";

int port = 1883;


//char topic[] = "fjjxu/13/303/temp15";
char topic[] = "fjjxu/13/303/light15";

int count = 0;
int countPub = 0;

dht11 DHT11;
#define DHT11PIN 9 //定义温湿度针脚号为9号引脚




const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);



SGP mySGP30;

u16 CO2Data,TVOCData;//定义CO2浓度变量与TVOC浓度变量
u32 sgp30_dat;

void servopulse(int angle)//定义一个脉冲函数,这个函数的频率是50hz的,20000us=20ms=1/50hz

{
  
  for(int i=0;i<100;i++){
  int pulsewidth=(angle*11)+500;  //将角度转化为500-2480的脉宽值
  digitalWrite(djPin,HIGH);    //将舵机接口电平至高,反过来也是可以的
  delayMicroseconds(pulsewidth);  //延时脉宽值的微秒数
  digitalWrite(djPin,LOW);     //将舵机接口电平至低
  delayMicroseconds(20000-pulsewidth);}
}


void callback(char* topic, byte* payload, unsigned int length) {  //回调函数
  count++;
 // char str[length]={0};
  Serial.print(count );
  Serial.print(" - Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    //str[i] = (char)payload[i]; 
    Serial.print((char)payload[i]);
  }
  Serial.println();//
//char a=str[0];
//String c =(String)str;
//String b=c.substring(1,4);
//int j = atoi(b.c_str());
// int n=atoi(&a);

  if((char)payload[0]=='0')//电灯
   {  ddkg=0;}  
   else if((char)payload[0]=='1')
   { ddkg=1;}
  else if((char)payload[0]=='2')//风扇
   {  fskg=2; }
  else if((char)payload[0]=='3')
   {  fskg=3; }
  else if((char)payload[0]=='4')//喷灌机
   {  pgkg=4; }
  else if((char)payload[0]=='5')
   {  pgkg=5; }
  else if((char)payload[0]=='6')//卷帘机
   {  jlkg=6; }
  else if((char)payload[0]=='7')
   {  jlkg=7; }
   
    Serial.println((char)payload[0]);
 
}


void connectToInternet() {
 
  Serial1.begin(9600);
  WiFi.init(Serial1);

  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("【ERROR】WiFi shield not present");
   
    while (true);
  }

  while ( status != WL_CONNECTED) {
    Serial.print("【INFO】Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
  
    status = WiFi.begin(ssid, pass);
  }
 
  Serial.println("【INFO】Connection Successful");

}



void setup()
{
pinMode(ledpin,OUTPUT);//定义小灯接口为输出接口
pinMode(fsPin, OUTPUT);  //继电器输出模式
pinMode(djPin, OUTPUT); //设定舵机接口为输出接口
pinMode(pgjPin, OUTPUT);  //设置对应的引脚为输出
  lcd.begin(16, 2);

  Serial.begin(9600);
 connectToInternet();

 pubSubClient.setServer(server, port);
 pubSubClient.setCallback(callback);
 
  reconnect();
  
mySGP30.SGP30_Init();
  mySGP30.SGP30_Write(0x20,0x08);
  sgp30_dat = mySGP30.SGP30_Read();//读取SGP30的值
  CO2Data = (sgp30_dat & 0xffff0000) >> 16;
  TVOCData = sgp30_dat & 0x0000ffff; 
  //SGP30模块开机需要一定时间初始化,在初始化阶段读取的CO2浓度为400ppm,TVOC为0ppd且恒定不变,因此上电后每隔一段时间读取一次
  //SGP30模块的值,如果CO2浓度为400ppm,TVOC为0ppd,发送“正在检测中...”,直到SGP30模块初始化完成。
  //初始化完成后刚开始读出数据会波动比较大,属于正常现象,一段时间后会逐渐趋于稳定。
  //气体类传感器比较容易受环境影响,测量数据出现波动是正常的,可自行添加滤波函数。
  while(CO2Data == 400 && TVOCData == 0)
  {
    mySGP30.SGP30_Write(0x20,0x08);
    sgp30_dat = mySGP30.SGP30_Read();//读取SGP30的值
    CO2Data = (sgp30_dat & 0xffff0000) >> 16;//取出CO2浓度值
    TVOCData = sgp30_dat & 0x0000ffff;       //取出TVOC值
    Serial.println("正在检测中...");
    delay(500);
  }
}


void loop()
{
  if (pubSubClient.connected()) //如果没有成功连接服务器
  {
     pubSubClient.loop();//保持客户端心跳
    }
  else{
   reconnect();//尝试连接
  }
 
  
  lcd.clear();
  lcd.setCursor(0, 1);
 
  Serial.println("\n");
 
  DHT11.read(DHT11PIN);

 float tem=(float)DHT11.temperature;        //将温度值赋值给tem
 float hum=(float)DHT11.humidity; 
 int t=tem;
  int g=analogRead(swpin);

  g=map(g,0,1023,100,0);
  //float gg=analogRead(snpin);
  int c = CO2Data;
  c=map(c,0,1023,0,100);
  
  int tr = analogRead(sensorPin);
int  r=map(tr,0,1023,100,0);
  
 char b[50]="";
String date="{\"t\":"+String(t)+",\"c\":"+String(c)+",\"r\":"+String(r)+",\"g\":"+String(g)+"}";

 strcpy(b,date.c_str());//转格式字符数组  不能接收字符串


 
  Serial.print("Humidity (%): ");
  Serial.println(hum);
 
  Serial.print("Temperature (oC): ");
  Serial.println(tem);

    lcd.clear();//清屏,光标回到左上角
      lcd.print("Hum:");//共12个字符
      lcd.setCursor(4,0);//光标定位到上面字符的后面,即第1行第13列
      lcd.print(hum,1);//显示采集到湿度值,保留小数点后1位
      lcd.print("%");
      lcd.setCursor(0,1);//光标定位到第1列第2行
      lcd.print("Tem:");//8个字符
      lcd.setCursor(4,1);//光标定位到第9列第2行
      lcd.print(tem,1);//显示采集到温度值,保留小数点后1位
      lcd.print("C");
       lcd.setCursor(9,0);//光标定位到第1列第2行
   lcd.print("Tu:");
       lcd.setCursor(12,0);//光标定位到第1列第2行
       lcd.print(sensorValue);
       
   lcd.setCursor(9,1);//光标定位到第9列第2行
   lcd.print("CO2:");
       lcd.setCursor(13,1);//光标定位到第1列第2行
       lcd.print(CO2Data,DEC);
     
     
  if (tem >22)        //如果温度大于22摄氏度
    {
      digitalWrite(fsPin, LOW);        //继电器开,风扇开
      Serial.println(" OPEN!");
    } else
    {  
      if(fskg==2){ digitalWrite(fsPin,HIGH);
      Serial.println("CLOSE!");}
  else{ digitalWrite(fsPin, LOW); 
    Serial.println("OPEN!");
  }
   
      
    }
 

//灯
int snguangmin=analogRead(snpin);   //读入光敏电阻产生的模拟信号(范围:0~1023)
  Serial.print("snvalue= ");
  Serial.print(snguangmin);
 // snguangmin=map(snguangmin,0,1023,0,255);  //map函数 将0~1023范围映射到255~0
  //这里反着写255,0;因为想实现随着光强增加LED变亮
  //analogWrite(ledpin,snguangmin);    //让13号引脚发出PWM波


if(snguangmin>500)
{ 
       digitalWrite(ledpin,HIGH);
  
  }
  else{
   if (ddkg==0){
           digitalWrite(ledpin,LOW);}
           else{
           digitalWrite(ledpin,HIGH);}
  

    }


//喷灌机
sensorValue = analogRead(sensorPin);
  
  if(sensorValue<900)//当读取的值小于700时,启动
  {
   digitalWrite(pgjPin, HIGH);
  }else
  {
        if(pgkg==4){ digitalWrite(pgjPin, LOW);}
  else{ digitalWrite(pgjPin, HIGH);}
   
  }
   Serial.print("turang= ");
  Serial.println(sensorValue);



 //舵机
 int swguangmin=analogRead(swpin); 
 Serial.print("swvalue= ");
  Serial.println(swguangmin);
if(swguangmin>500)
{
  servopulse(0);
 
  }else
  {
       if(jlkg==6){ servopulse(180);}
  else{ servopulse(0);}
    
    }


//CO2检测
  mySGP30.SGP30_Write(0x20,0x08);
  sgp30_dat = mySGP30.SGP30_Read();//读取SGP30的值
  CO2Data = (sgp30_dat & 0xffff0000) >> 16;//取出CO2浓度值
  TVOCData = sgp30_dat & 0x0000ffff;       //取出TVOC值
  Serial.print("CO2:");
  Serial.print(CO2Data);
  Serial.println("ppm");

 long now = millis();
  if (now - lastMsg > 2000) {
    lastMsg = now;
    ++value;
    
    snprintf (msg,75, b, value);
  
    Serial.print("Publish message: ");
    
    Serial.println(msg);
    
     pubSubClient.publish("fjjxu/13/303/date15", msg);
  
  }

delay(2000);
}


void reconnect() {

  while (!pubSubClient.connected()) {
    Serial.println("【INFO】 Retry  connect  MQTT  ...");
  
    String clientId = "Arduinoskw66-";
    clientId += String(random(0xffff), HEX);   //产生随机的ClientID
   
 
    if (pubSubClient.connect(clientId.c_str())) {
      Serial.println("connected");
  
     
      pubSubClient.subscribe(topic);   //订阅主题
 
      Serial.print("【INFO】 Successfully Subscribed to MQTT Topic:");
      Serial.println(topic);     
    } else {
      Serial.print("【ERR】 failed, rc=");
      Serial.print(pubSubClient.state());
      Serial.println(" try again in 5 seconds");
    
      delay(5000);
    }
  }
}

运行结果及详细报错内容

主要问题是加水机通电后,用网页端控制开关喷灌机,会断开连不上mqtt,单纯控制继电器是没问题的

我的思路和尝试过的方法

因为不会做,所以我对于网页端控制arduino我的思路就是利用按钮的开关发送0或者1或者其他数字消息到mqtt主题,然后arduino里收到消息做出反应

我想要达到的结果

1、喷灌机通电后网页端也可以流畅的控制他的开关
2、例:当温度大于22度的时候,风扇会开启,但是我要通过网页控制他关闭,不管环境怎么样(led、舵机、加水机也想这样,不管环境怎么样,网页要他开就开要关就关)希望给出代码 我想不出来
(希望可以帮我出个主意,改一下代码,我很多都不懂所以只能凭感觉做成这样)

根据所提供的信息,这里可以看到几个不同的问题,每个问题都有自己特定的现象和背景,可以分开解决。

WiFi模块有时候会检测不到
现象:WiFi模块无法正常连接网络,Arduino无法通过MQTT发送数据。
背景:可能是由于WiFi模块连接到的路由器不稳定,或者模块自身存在问题。
解决方案:

确认WiFi模块连接的路由器是否正常工作。
尝试重新连接WiFi模块,或者更换一个新的模块。
调整WiFi模块的天线,尽可能减少干扰和阻碍。
上传的数据太多,MQTT无法正常工作
现象:通过串口发送的数据出现乱码,并且MQTT无法正常工作。
背景:可能是由于上传的数据量太大,导致MQTT无法正常处理。
解决方案:

尝试通过分批发送的方式减少数据量,或者使用更高效的数据传输方式。
确认Arduino的串口波特率设置是否正确,或者尝试更换串口线缆或端口。
检查代码逻辑,确保MQTT发布消息的时机和方式正确。
控制喷灌机时MQTT会断开连接
现象:在控制喷灌机时,MQTT会断开连接。
背景:可能是由于继电器操作时电流波动导致的,也有可能是代码逻辑的问题。
解决方案:

确认继电器和其他电路元件的工作状态是否正常,检查是否存在电流波动等问题。
尝试通过更改代码逻辑、延迟操作等方式来解决问题。
如果有可能,可以使用其他的MQTT服务器进行测试,以确定问题是否出现在MQTT服务器本身。
网页端控制不能正常工作
现象:通过网页端控制时,风扇无法按照预期的方式工作。
背景:可能是由于代码逻辑的问题,或者是因为Arduino无法正确解析网页端发送的命令。
解决方案:

确认代码逻辑是否正确,或者尝试更改代码逻辑以适应新的要求。
确认Arduino是否能够正确解析网页端发送的命令,或者尝试更换Arduino板卡或使用其他的通信方式

以下答案基于ChatGPT与GISer Liu编写:

  1. WiFi模块有时候会检测不到:
    这可能是由于WiFi信号不稳定或者WiFi模块有故障导致的。你可以尝试重新设置WiFi模块或者更换一个新的WiFi模块,看看是否能够解决问题。另外,你可以使用一些WiFi信号稳定的地方来测试你的设备,例如在一个没有障碍物的区域测试。

  2. Arduino想要发送温湿度、CO2浓度、光照强度、土壤湿度等其他数据上传不了那么多,串口会显示乱码然后不发生数据消息到MQTT:
    你可以考虑将数据进行压缩或者使用更高效的传输协议,例如JSON或者二进制格式。另外,如果你的数据量太大,可以考虑使用其他的数据存储方式,例如使用SD卡来存储数据,然后在需要的时候读取数据并上传到MQTT。

  3. 每次控制喷灌机的时候,MQTT就会断开重连不上:
    这可能是由于喷灌机控制时电流过大导致的。你可以考虑使用一个外部的电源来为你的设备供电,或者使用一个电源开关来控制喷灌机的电流。另外,你可以在代码中添加一些延时来等待设备稳定后再进行下一步操作,以避免设备崩溃或者断开连接。

  4. 网页端控制希望在因为环境变化的时候风扇开启,但是我可以用网页端关掉正在运行风扇:
    你可以在代码中添加一些判断逻辑,例如检测风扇是否已经开启,如果已经开启则不再开启。另外,你可以考虑使用一个定时器来控制风扇的开启和关闭,以避免频繁的开关机对设备的寿命造成影响。

该回答引用ChatGPT
您可以使用Arduino Uno和ESP01s来构建一个基于MQTT的温室智能系统。首先,您需要将Arduino Uno和ESP01s连接到同一个网络,然后使用MQTT协议将Arduino Uno和ESP01s连接起来。接下来,您可以使用Arduino Uno来控制LED、舵机、风扇和喷灌器,并使用ESP01s来接收来自网页的控制信号,从而实现温室智能系统的控制。

(1) 这可能是由于WiFi模块连接的不稳定,也有可能是因为电源不稳定
(2) 可能是由于串口传输速率过低,数据量过大,建议调整串口波特率,或将数据转换成二进制编码后发送
(3) 可能是由于继电器的电压与节点MCU的工作电压不匹配,或者继电器电压过低
(4) 可能是由于代码逻辑错误,建议检查代码中的条件语句和控制逻辑是否正确