本文作者:淡

安信可ESP32-Blinker-APP自动浇花

5个月前 ( 12-22 ) 338 抢沙发
安信可ESP32-Blinker-APP自动浇花摘要: 因临近春节回老家,无人照顾养的茉莉花,借鉴别人的思路新手照搬例程点灯APP自动浇花,分享出来希望大佬优化。代码杂乱不足之处嘴下留情app截图Arduino代码#define&nbs...

因临近春节回老家,无人照顾养的茉莉花,借鉴别人的思路新手照搬例程点灯APP自动浇花,分享出来希望大佬优化。代码杂乱不足之处嘴下留情


app截图

110116odxxkg1uhmmdh1ap.png

Arduino代码

#define BLINKER_WIFI
#include <ArduinoJson.h>//此库需要放在Blinker.h库前不然会出现编译错误
#include <Blinker.h>
#include <DHT.h>
#define JDQ 12 //继电器信号引脚
#define TR 35 //土壤传感器信号引脚
#define DHTPIN 25 //温湿度传感器信号引脚
#define DHTTYPE DHT11 //温湿度传感器类型
#define ran "SliderKey"

DHT dht(DHTPIN, DHTTYPE);


char auth[] = ".................";


/*********************************************************************************************************
  新建数据类型组件对象,作用:将数据传输到手机blinker app

*********************************************************************************************************/
BlinkerNumber TRZ("TRZ"); //blinker-app创建名为TRZ的数据模块显示土壤值
BlinkerNumber HUMI("humi");//blinker-app创建名为humi的数据模块显示湿度值
BlinkerNumber TEMP("temp");//blinker-app创建名为temp的数据模块显示温度值
BlinkerNumber RSS("rssi");//blinker-app创建名为huashi的数据模块显示华式温度
BlinkerNumber LU("ludian");//blinker-app创建名为ludian的数据模块显示露点值
BlinkerNumber HUMISJ("humi9");//blinker-app创建名为humi9的图表显示湿度历史数据
BlinkerNumber TEMPSJ("temp9");//blinker-app创建名为temp9的图标显示温度历史数据
BlinkerNumber TRZSJ("TRZ9");//blinker-app创建名为TRZ9的图标显示土壤值历史数据
BlinkerNumber CI("ci");
BlinkerSlider Slider1("ran");
BlinkerButton Button1("zhaoming");
BlinkerButton Button2("jiaoshui");
BlinkerText TURANG("turang");
BlinkerText BENG("beng");
BlinkerText YUNHANG("yunhang");
BlinkerText CITY("city");
BlinkerText WURAN("wuran");
BlinkerText PM("pm");
BlinkerText BTQX("btqx");
BlinkerText WSQX("wsqx");
BlinkerText BTWD("btwd");
BlinkerText WSWD("wswd");
BlinkerText BTFX("btfx");

/*********************************************************************************************************变量*********************************************************************************************************/
//天气
String city1, level1, pm251, forecasts_0_date1, forecasts_0_week1, forecasts_0_dayweather1, forecasts_0_nightweather1, forecasts_0_daytemp1, forecasts_0_nighttemp1, forecasts_0_daywind1, forecasts_0_nightwind1, forecasts_0_daypower1, forecasts_0_nightpower1;//天气及空气质量
int a3 = 0; //用于间隔更新天气
bool first_label = false; //开机标签,开机第一时间更新天气信息

//土壤值读取
uint16_t LeiJi[20];//存储土壤累计读取数值
uint16_t TRzhi;//土壤值
uint16_t Amin = 60700; //土壤最小校准值
uint16_t Amax = 24200; //土壤最大校准值

//空气温湿度
float  n1 = 0.0, n2 = 0.0,  t = 0, h = 0, rssi = 0;
double humi_read = 0, temp_read = 0, huashi_read = 0, ludian_read = 0, ci_read = 0;

//判断是否浇花
String turang_read, beng_read, T, B;
int ci = 0, zhi = 40;

//配网设置
int count = 0;     //时间计数
bool WIFI_Status = true;   //WIFI状态标志位

/********************************************************************************************************* Esptouch配网*********************************************************************************************************/
void blinkerConnect()  //网络链接
{
  WiFi.begin();//没有这行命令ESP32断电重启不会自动连接WIFI
  BLINKER_LOG("\r\n正在连接WIFI...");
  while (WiFi.status() != WL_CONNECTED) //判断是否连接WIFI成功
  {
    if (WIFI_Status)
    {
      BLINKER_LOG("WIFI连接中");
      digitalWrite(LED_BUILTIN, HIGH);
      delay(500);
      digitalWrite(LED_BUILTIN, LOW);
      delay(500);
      count++;
      if (count >= 30) //5s
      {
        WIFI_Status = false;
        BLINKER_LOG("WiFi连接失败,请用ESPtouch进行配网");
      }
    }
    else
    {
      smartConfig();
    }
  }
  BLINKER_LOG("连接成功IP地址为:", WiFi.localIP());
}

void smartConfig()//ESPtouch配网
{
  WiFi.mode(WIFI_STA);//设置STA模式
  BLINKER_LOG("\r\nWait for Smartconfig...");
  WiFi.beginSmartConfig();//开始SmartConfig,等待手机端发出用户名和密码
  while (1)
  {
    BLINKER_LOG("等待配网中");
    digitalWrite(LED_BUILTIN, HIGH); //指示灯闪烁
    delay(1000);
    digitalWrite(LED_BUILTIN, LOW); //指示灯闪烁
    delay(1000);
    if (WiFi.smartConfigDone()) //配网成功,接收到SSID和密码
    {

      BLINKER_LOG("配网成功");
      BLINKER_LOG("SSID:", WiFi.SSID().c_str());
      BLINKER_LOG("PSK:", WiFi.psk().c_str());
      break;
    }
  }
}

/********************************************************************************************************* 土壤值读取*********************************************************************************************************/

void turang()//土壤值读取
{
  uint8_t i;
  for (i = 0; i < 20; i++) { //连续取采集多个样本,缺点AD读取会有延迟
    LeiJi[i] = analogRead(TR); //读取土壤湿度传感器的值
    Blinker.delay(100);
  }
  TRzhi = 0; //平均所有值
  for (i = 0; i < 20; i++) {
    TRzhi += LeiJi[i];
  }
  //Serial.println(TRzhi);//串口输出土壤值
  TRzhi = map(TRzhi, Amin, Amax, 0, 100); //校准值转换成0-100
  TRzhi = constrain(TRzhi, 0, 100); //将传感器值的范围限制在0到100之间
  Blinker.delay(1000);
}

/*********************************************************************************************************室内温度值读取*********************************************************************************************************/

// 快速计算露点,速度是5倍dewPoint()
double dewPointFast(double celsius, double humidity)
{
  double a = 17.271;
  double b = 237.7;
  double temp = (a * celsius) / (b + celsius) + log(humidity / 100);
  double Td = (b * temp) / (a - temp);
  return Td;
}

void wenshidu()  //空气温湿度值读取
{
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  float hic = dht.computeHeatIndex(t, h, false);
  float n2 = (((9.0 / 5.0) * t + 32.0));//摄氏温度转为华式温度
  float n1 = dewPointFast(dht.readTemperature(), dht.readHumidity());//计算露点
  humi_read = h;//湿度值
  temp_read = t;//温度值
  huashi_read = n2;//华式温度
  ludian_read = n1;//露点值
  rssi = (WiFi.RSSI());//WIFI信号强度
  Blinker.delay(1000);
}

/*********************************************************************************************************判断是否浇水*********************************************************************************************************/
void slider1_callback(int32_t value)//读取设定自动浇水阈值,初始值为40
{
  BLINKER_LOG("get slider value: ", value);
  zhi = value;
}

void gh() //读取的土壤值与设定的浇水阈值对比判断是否浇水
{
  if ((TRzhi < zhi) && (temp_read < 36) && (humi_read < 75)) { //如果读取土壤值小于自动浇水阈值且温度小于36度湿度低于75%则给继电器高电平信号打开水泵浇水
    digitalWrite(JDQ, HIGH); //给继电器输出高电平打开水泵
    Blinker.println("土壤干旱,需要浇水");
    ci++;
    T = "土壤干旱";
    B = "水泵打开";
    Blinker.delay(3000);
  }

  else if ((TRzhi > zhi) && (humi_read < 75)) { //如果读取土壤值大于设定浇水阈值且湿度小于75%则给继电器低电平信号关闭水泵
    digitalWrite(JDQ, LOW); //关闭LED灯
    Blinker.println("土壤潮湿,不需要浇水");
    T = "土壤湿润";
    B = "水泵关闭";
    Blinker.delay(3000);
  }

  else if (t > 36)//如果读取温度值大于36℃则给继电器低电平信号关闭水泵
  {
    digitalWrite(JDQ, LOW);
    Blinker.println("温度过高,不适宜浇水");
    T = "温度过高不适宜浇水";
    B = "水泵关闭";
    Blinker.delay(3000);
  }

  else if (humi_read > 75)//如果读取湿度值大于75%则给继电器低电平信号关闭水泵
  {
    digitalWrite(JDQ, LOW);
    Blinker.println("空气湿度高,可能会下雨!");
    T = "空气湿度高可能会下雨";
    B = "水泵关闭";
    Blinker.delay(3000);
  }
}

/*********************************************************************************************************记录历史数据*********************************************************************************************************/
void dataStorage()//记录历史数据
{
  Blinker.dataStorage("humi9", humi_read);
  Blinker.dataStorage("temp9", temp_read);
  Blinker.dataStorage("TRZ9", TRzhi);
}

void printlf() //打印调试信息
{
  BLINKER_LOG("空气湿度:", humi_read, " %");
  BLINKER_LOG("摄氏温度: ", temp_read, " *C");
  BLINKER_LOG("华氏温度: ", huashi_read, " °F");
  BLINKER_LOG("露点: ", ludian_read, " Td");
  BLINKER_LOG("土壤湿度: ", TRzhi, " %");
  BLINKER_LOG("浇水阈值: ", zhi, " %");
  BLINKER_LOG("自动浇水次数:", ci, " 次");
  BLINKER_LOG("当前土壤状态:", T, "");
  BLINKER_LOG("当前水泵状态:", B, "");
  BLINKER_LOG("当前WIFI信号强度:", rssi, "db");
}

/********************************************************************************************************* 手动浇水*********************************************************************************************************/

void button2_callback(const String & state)//手动浇水
{
  BLINKER_LOG("get button state: ", state);
  if (state == "on")
  {
    digitalWrite(JDQ, HIGH);
    // 反馈开关状态
    Button2.print("on");
    B = "开始手动浇水";
  }  if (state == "off") //按照例程else if无法关闭
  {
    digitalWrite(JDQ, LOW);
    // 反馈开关状态
    Button2.print("off");
    B = "停止手动浇水";
  }
  Blinker.delay(300);
}

void button1_callback(const String & state) //原计划设置光照补偿(无用改为系统指示灯开关)
{
  BLINKER_LOG("get button state: ", state);
  if (state == "on") {
    digitalWrite(LED_BUILTIN, HIGH);
    // 反馈开关状态
    Button1.print("on");
    BENG.print("系统指示灯开启");
  } if (state == "off") {
    digitalWrite(LED_BUILTIN, LOW);
    // 反馈开关状态
    Button1.print("off");
    BENG.print("系统指示灯关闭");
  }
  Blinker.delay(300);
}

/*********************************************************************************************************系统运行时间*********************************************************************************************************/

String rts()
{
  int rt = Blinker.runTime();
  int r, e, f, s;
  String fh;
  Blinker.delay(100);
  if (rt >= 86400) //天数
  { r = rt / 86400;
    e = rt / 3600 - r * 24;
    f = rt / 60 - r * 1440 - e * 60;
    s = rt - r * 86400 - e * 3600 - f * 60;
  }
  else if (rt >= 3600)
  { r = 0;
    e = rt / 3600;
    f = rt / 60 - e * 60;
    s = rt - e * 3600 - f * 60;
  }
  else
  { r = 0;
    e = 0;
    f = rt / 60;
    s = rt - f * 60;
  }


  if (f == 0 & e == 0 & r == 0)
  {
    fh = String("") + s + "秒";
  }
  else if (r == 0 & e == 0 )
  {
    fh = String("") + f + "分" + s + "秒";
  }
  else if (r == 0)
  {
    fh = String("") + e + "小时" + f + "分" + s + "秒";
  }
  else
  {
    fh = String("") + r + "天" + e + "小时" + f + "分" + s + "秒";
  }

  return (fh);
}

/*********************************************************************************************************天气数据及空气数据读取*********************************************************************************************************/
void airData(const String & data) //空气质量
{
  BLINKER_LOG("air: ", data);
  const size_t capacity = JSON_OBJECT_SIZE(11) + 120;
  DynamicJsonDocument doc(capacity);
  DeserializationError error = deserializeJson(doc, data);
  if (error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.c_str());
    return;
  }
  const char* city = doc["city"]; 
  const char* updateTime = doc["updateTime"];
  const char* aqi = doc["aqi"]; 
  const char* level = doc["level"]; 
  const char* pm25 = doc["pm25"];
  const char* pm10 = doc["pm10"];
  const char* SO2 = doc["SO2"];
  const char* NO2 = doc["NO2"];
  const char* CO = doc["CO"];
  const char* O3 = doc["O3"];
  city1 = city;
  level1 = level;
  pm251 = pm25;


  BLINKER_LOG("城市:", city1);//1
  BLINKER_LOG("更新时间:", updateTime);
  BLINKER_LOG("aqi:", aqi);
  BLINKER_LOG("污染程度:", level1); //2
  BLINKER_LOG("pm25:", pm251);//3
  BLINKER_LOG("pm10:", pm10);
  BLINKER_LOG("SO2:", SO2);
  BLINKER_LOG("NO2:", NO2);
  BLINKER_LOG("CO:", CO);
  BLINKER_LOG("O3:", O3);
}

void weatherForecastData(const String & data)//天气
{
  BLINKER_LOG("weather: ", data);
  const size_t capacity = JSON_ARRAY_SIZE(4) + JSON_OBJECT_SIZE(4) + 4 * JSON_OBJECT_SIZE(10) + 650;
  DynamicJsonDocument doc(capacity);
  DeserializationError error = deserializeJson(doc, data);
  if (error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.c_str());
    return;
  }

  const char* city = doc["city"];
  const char* province = doc["province"];
  const char* updateTime = doc["updateTime"];

  JsonArray forecasts = doc["forecasts"];

  JsonObject forecasts_0 = forecasts[0];
  const char* forecasts_0_date = forecasts_0["date"]; 
  const char* forecasts_0_week = forecasts_0["week"];
  const char* forecasts_0_dayweather = forecasts_0["dayweather"];
  const char* forecasts_0_nightweather = forecasts_0["nightweather"];
  const char* forecasts_0_daytemp = forecasts_0["daytemp"];
  const char* forecasts_0_nighttemp = forecasts_0["nighttemp"];
  const char* forecasts_0_daywind = forecasts_0["daywind"];
  const char* forecasts_0_nightwind = forecasts_0["nightwind"];
  const char* forecasts_0_daypower = forecasts_0["daypower"];
  const char* forecasts_0_nightpower = forecasts_0["nightpower"];
  forecasts_0_dayweather1 = forecasts_0_dayweather;
  forecasts_0_nightweather1 = forecasts_0_nightweather;
  forecasts_0_daytemp1 = forecasts_0_daytemp;
  forecasts_0_nighttemp1 = forecasts_0_nighttemp;
  forecasts_0_daywind1 = forecasts_0_daywind;

  BLINKER_LOG("城市:", city);
  BLINKER_LOG("更新时间:", updateTime);
  BLINKER_LOG("时间:", forecasts_0_date);
  BLINKER_LOG("星期:", forecasts_0_week);
  BLINKER_LOG("白天天气现象:", forecasts_0_dayweather);//4
  BLINKER_LOG("晚上天气现象:", forecasts_0_nightweather);//5
  BLINKER_LOG("白天温度:", forecasts_0_daytemp);//6
  BLINKER_LOG("晚上温度:", forecasts_0_nighttemp);//7
  BLINKER_LOG("白天风向:", forecasts_0_daywind);//8
  BLINKER_LOG("晚上风向:", forecasts_0_nightwind);
  BLINKER_LOG("白天风力:", forecasts_0_daypower);
  BLINKER_LOG("晚上风力:", forecasts_0_nightpower);
}

void jggxtq() //时间段判断更新
{
  int8_t hour = Blinker.hour();//时
  int8_t min  = Blinker.minute();//分
  BLINKER_LOG("判断是否更新天气");
  if (hour == 8) {
    a3 = 8;
  }
  if (hour == 10) {
    a3 = 10;
  }
  if (hour == 14) {
    a3 = 14;
  }
  if (hour == 16) {
    a3 = 16;
  }
  if (hour == 18) {
    a3 = 18;
  }
  if (hour == 21) {
    a3 = 21;
  }
  if (hour == 20) {
    a3 = 20;
  }
  if (hour == 22) {
    a3 = 22;
  }
  if (hour == 23) {
    a3 = 23;
  }
  if (hour == a3) {
    if (min == 0) {
      BLINKER_LOG("开始更新天气");
      Blinker.weatherForecast();
      Blinker.air();
      Blinker.delay(4000);
    }
  }
}

/*********************************************************************************************************心跳发送数据到手机APP*********************************************************************************************************/

void heartbeat()//心跳 发送数据到手机APP
{
  HUMI.print(humi_read);//湿度
  TEMP.print(temp_read);//温度
  TRZ.print(TRzhi);//土壤值
  RSS.print(rssi);//华式温度值
  LU.print(ludian_read);//露点值
  CI.print(ci_read);//水泵浇水次数
  TURANG.print(T);//土壤状态
  BENG.print(B);//水泵状态
  YUNHANG.print(rts());//显示系统运行时间
  Slider1.print(zhi);//浇水阈值
  CITY.print(city1);//显示城市
  WURAN.print(level1);//显示污染程度
  PM.print(pm251);//显示PM值
  BTQX.print(forecasts_0_dayweather1);//白天天气气象
  WSQX.print(forecasts_0_nightweather1); //晚上天气气象
  BTWD.print(forecasts_0_daytemp1);//白天温度
  WSWD.print(forecasts_0_nighttemp1);//晚上温度
  BTFX.print(forecasts_0_daywind1);//白天风向
}



void setup()
{
  first_label = true;
  pinMode (JDQ, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  Serial.begin(115200);//打开串口波特率设置115200
  BLINKER_DEBUG.debugAll();//开启调试
  BLINKER_DEBUG.stream(Serial);
  Blinker.begin(auth, WiFi.SSID().c_str(), WiFi.psk().c_str()); //根据配网得到的WIFI信息和设备秘钥,连接到Blinker云
  blinkerConnect();//连接网络
  Blinker.attachHeartbeat(heartbeat);
  Blinker.attachDataStorage(dataStorage);//开启历史数据
  Blinker.attachAir(airData);//注册空气质量
  Blinker.attachWeatherForecast(weatherForecastData);//注册天气
  Slider1.attach(slider1_callback);
  Button1.attach(button1_callback);
  Button2.attach(button2_callback);
  dht.begin();

}

void loop()
{
  Blinker.run();
//通电更新天气及空气质量
  if ((first_label == true)) {
    if (Blinker.init())
    {
      Blinker.weatherForecast();
      Blinker.air();
      Blinker.delay(2000);
      first_label = false;
    }
  }
  turang();
  wenshidu();
  Blinker.delay(2000);
  gh();
  printlf();
  ci_read = ci;//浇水次数
  jggxtq();
}
文章版权及转载声明

作者:本文地址:https://www.jietn.com/blog/61.html发布于 5个月前 ( 12-22 )
文章转载或复制请以超链接形式并注明出处半星笔记

赞(0

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

阅读
分享

发表评论

快捷回复:

评论列表 (暂无评论,338人围观)参与讨论

还没有评论,来说两句吧...