esp8266使用Arduino编程实现自动浇水、OTA升级功能

17 篇文章 2 订阅
10 篇文章 4 订阅

创作前情:

上海疫情已有一段时间,从三月初算起来已过了一个多月,当时用了泡沫箱种了些小香葱,这几天把它搬到了室外阳台,由于浇水不方便,想着做一个自动浇水的设备。

实现目的:

  1. 可以远程控制浇水
  2. 可以实时查看湿度
  3. 可以根据湿度设定自动校准
  4. 太阳能供电
  5. 远程升级(摆脱TTL束缚)

所用材料:

  1. 温湿度模块(之前淘宝买的垃圾佬光合未来温湿度计)
  2. 主控 esp8266,选他主要是比较熟悉(其实是相对简单了,手上也有不少)
  3. 水泵以及水管,这些之前也是淘宝垃圾佬买的
  4. 太阳能板,同样垃圾佬的必备吧 

设计步骤:

远程控制以及数据查看,采用点灯平台,接入简单,有完善的文档以及例子可以参考,温湿度数据通过光合未来的设备,通过ESPNOW传给主控esp8266,测量设备设定休眠半小时,醒来一分钟,每十秒传送一次数据,晚上十点到次日六点每两个小时醒来一次,实测充电一次可以使用一周的时间。主控esp8266通过收到的数据来决定是否需要浇水,

这里介绍下espnow,感觉听有意思的,这里是接受端的代码

//接收
#include <ESP8266WiFi.h>
#include <espnow.h>
//接收数据保存的结构体和发送方一致
typedef struct struct_message
{
    int id;
    char ip[32];
    int b;
    float c;
    String d;
    bool e;
    float rx_bat;
    float rx_temp;
    float rx_humi;
} struct_message;

//创建结构体变量
/*******新加 20220411 多版子*************/
struct_message myData;
struct_message board1; //用于储存开发版1的值
struct_message board2;
struct_message board3;
struct_message Shuju[3] = {board1, board2, board3}; //创建一个包含所有结构数组方便电泳读写数据
/*******新加 20220411 多版子*************/
//创建一个回调函数作为接收数据后的串口显示
void OnDataRecv(uint8_t *mac_addr, uint8_t *incomingData, uint8_t len)
{
    /*******新加 20220411 多版子*************/
    char macStr[18]; //定义字符串数组
    Serial.print("收到数据包来自: ");
    snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); //获取板子地址
    Serial.println(macStr);
    /*******新加 20220411 多版子*************/
    memcpy(&myData, incomingData, sizeof(myData));
    // Serial.print("Bytes received: ");
//    Serial.print("数据包大小: ");
//    Serial.println(len);
//    Serial.print("来自开发版: ");
//    Serial.println(myData.id);
    //  Serial.print("Char: ");
//    Serial.print("IP 地址: ");
//    Serial.println(myData.ip);
//    Serial.print("电量百分比: ");
//    Serial.print(myData.b);
//    Serial.println(" %");
    //  Serial.print("Float: ");
    //  Serial.println(myData.c);
    //  Serial.print("String: ");
    //  Serial.println(myData.d);
    //  Serial.print("Bool: ");
    //  Serial.println(myData.e);
//    Serial.print("电池电压: ");
//    Serial.println(myData.rx_bat);
//    Serial.print("温度: ");
//    Serial.println(myData.rx_temp);
//    Serial.print("湿度: ");
//    Serial.println(myData.rx_humi);
//    Serial.print("********************************************************");
    Serial.println();
    if (myData.id == 10)
    {
        rx_read.humi_one_read = myData.rx_humi;
        rx_read.temp_one_read = myData.rx_temp;
        rx_read.bat_one_read = myData.rx_bat;
    }
}

void esp_now_setup()
{
    //初始化窗口
    // Serial.begin(115200);
    Serial.println();
    Serial.print("ESP8266 Board MAC Address: ");
    Serial.println(WiFi.macAddress());
    //设置ESP8266模式
    WiFi.mode(WIFI_STA);

    //初始化 ESP-NOW
    if (esp_now_init() != 0)
    {
        Serial.println("初始化 ESP-NOW 出错");
        return;
    }
    //设置ESP8266角色:
    esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
    //先前创建的功能 测试ESP-NOW通信
    esp_now_register_recv_cb(OnDataRecv);
}

void esp_now_loop()
{
}

这里是发射端的代码

//发送
#include <ESP8266WiFi.h>
//#include <WiFi.h>
//#include <esp_now.h>
#include <espnow.h>
char ownmacStr[18];//定义字符串数组
/******************ESP NOW *******************************/
//接收方MAC地址 根据自己的板子修改 CC:50:E3:08:E5:A9   60:01:94:52:DE:03   BC:DD:C2:4F:4E:E4  5C:CF:7F:9B:22:8F 5C:CF:7F:99:B8:57

//uint8_t broadcastAddress[] = {0xBC, 0xDD, 0xC2, 0x4F, 0x4E, 0xE4};
//uint8_t broadcastAddress[] = {0x5C, 0xCF, 0x7F, 0x9B, 0x22, 0x8F};
uint8_t broadcastAddress[] = {0x5C, 0xCF, 0x7F, 0x99, 0xB8, 0x57};
//发送数据的结构体
typedef struct struct_message {
  int id;
  char ip[32];
  int b;
  float c;
  String d;
  bool e;
  float f;
  float g;
  float h;
} struct_message;

//创建一个新的类型变量
struct_message myData;
//esp_now_peer_info_t peerInfo;//创建对等接口 add 20220411
/******************ESP NOW *******************************/
//这是一个回调函数,将在发送消息时执行。
//在这种情况下,无论是否成功发送该消息,都会简单地打印出来
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {
  //Serial.print("\r\n最后一个数据表发送状态: \t");
  if (sendStatus == 0) {
   // Serial.println("发送成功");
  }
  else {
    //Serial.println("发送失败");
  }
}

void esp_now_setup() {
  //初始化串行监视器以进行调试
  //Serial.begin(115200);

  //将设备设置为Wi-Fi站点
  WiFi.mode(WIFI_STA);
  Serial.print("ESP8266 Board MAC Address: ");
  Serial.println(WiFi.macAddress());
  //立即初始化ESP
  if (esp_now_init() != 0) {
    Serial.println("初始化 ESP-NOW 出错");
    return;
  }
  //设置ESP8266角色  ESP_NOW_ROLE_CONTROLLER, ESP_NOW_ROLE_SLAVE,
  //ESP_NOW_ROLE_COMBO, ESP_NOW_ROLE_MAX。
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  //先前创建的功能。
  esp_now_register_send_cb(OnDataSent);//成功初始化,注册发送包,获取已发送状态

  //与另一个ESP-NOW设备配对以发送数据
  esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);
}

void esp_now_loop() {
  //配置要发送的值
  myData.id = 0;//自定义开发版id
  //strcpy(myData.a, "THIS IS A CHAR");
  strcpy(myData.ip, WiFi.localIP().toString().c_str());
  //myData.b = random(1,20); //随机数
  myData.b = bat_num;
  myData.c = 1.2;
  //myData.d = "Hello";
  myData.d = ip.c_str();
  myData.e = false;

  myData.f = bat_read;
  myData.g = temp_read;
  myData.h = humi_read;
  //发送消息
  esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
  //延时两秒
  //delay(2000);
}

由于自己做的esp8266板子没有放置自动下载电路,所以决定加入arduino ota功能,板子上有物理按键,当检测到有按键按下时,执行ota程序,等待新的固件上传,再次按下按键则取消ota,因板子放在室外,不可能每次下载都跑到室外去按下按键,所以在blinker里也定义一个按键,用来控制是否出于ota升级状态。

ota实现的部分

#include <Arduino.h>
#include <WiFiManager.h>
#include <ArduinoOTA.h>
#include <ESP8266WiFi.h>
#include <Ticker.h>
//#define OTA_KEY_PIN  4

// 闪烁时间间隔(秒)
const int blinkInterval = 2;
//bool led_on_flag = false;
Ticker ticker;
// 在Tinker对象控制下,此函数将会定时执行。
void tickerCount() {
  led_on_flag = true;
  //digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
// 设置wifi接入信息(请根据您的WiFi信息进行修改)
//const char* ssid = "taichimaker";
//const char* password = "12345678";
#if defined(ARDUINO_AVR_UNO) || defined (ARDUINO_AVR_NANO_EVERY)
void key_press()
{
  // include all buttons here to be checked
  // button.tick(); // just call tick() to check the state.
}
#elif defined(ESP8266)
ICACHE_RAM_ATTR void key_press()
{
  otaflag = !otaflag;
  if (otaflag)
    b1 = 1;
  else
    b1 = 0;
  ota_change_flag = true;
 // Serial.println("key press");
  // include all buttons here to be checked
  //button.tick(); // just call tick() to check the state.
}
#endif
void otasetup() {
  //Serial.begin(115200);
  // Serial.println("");
  pinMode(LED_BUILTIN, OUTPUT);
  ticker.attach(blinkInterval, tickerCount);  // 设置Ticker对象
  //connectWifi();
  // OTA设置并启动
  ArduinoOTA.setHostname("ESP8266");
  ArduinoOTA.setPassword("1234");
  ArduinoOTA.begin();
  Serial.println("OTA ready");

  pinMode(OTA_KEY_PIN, INPUT_PULLUP);
  attachInterrupt(OTA_KEY_PIN, key_press, FALLING );
//  Serial.println("ota int done ");
//  Serial.print("ota set pin = ");
//  Serial.println(OTA_KEY_PIN);
}
void otaconnectWifi() {
  //开始连接wifi
  //WiFi.begin(ssid, password);
  // Serial.begin(115200);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    //xianshi_wifi();
    Serial.print(".");
    if (!(WiFi.status() != WL_CONNECTED)) {
      break;
    } else {
      WiFiManager wifiManager;
      wifiManager.autoConnect("ESP8266");
    }
  }
  //Serial.println("");
 // Serial.print("ESP8266 Connected to ");
  //Serial.println(WiFi.SSID());              // WiFi名称
 // Serial.print("IP address:\t");
 // Serial.println(WiFi.localIP());           // IP
}
void otaloop() {
  ArduinoOTA.handle();
  Serial.println("OTA start");
  if (led_on_flag == true) {
    led_on_flag = false;
    ota_OLED();
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  }
  if (ota_change_flag == true) {
    ota_change_flag = false;
    u8g2.setContrast(100);
    u8g2.setPowerSave(0);
  }

}

{¨config¨{¨headerColor¨¨transparent¨¨headerStyle¨¨dark¨¨background¨{¨img¨¨assets/img/bg/1.jpg¨}}¨dashboard¨|{¨type¨¨num¨¨t0¨¨室外湿度¨¨ico¨¨fal fa-humidity¨¨clr¨¨#6010E4¨¨min¨É¨max¨¢1c¨uni¨¨%RH¨¨bg¨É¨cols¨Ë¨rows¨Ë¨key¨¨humi¨´x´Ë´y´Ë¨speech¨|÷¨lstyle¨É}{ß9ßAßB¨室外温度¨ßD¨fal fa-thermometer-three-quarters¨ßF¨#076EEF¨ßHÉßI¤oßJ´℃´ßLÉßMËßNËßO¨temp¨´x´É´y´ËßQ|÷ßRɨrt¨«}{ß9¨cha¨ßLʨsty¨¨line¨ßFßU¨sty1¨ßZ¨clr1¨ßG¨sty2¨ßZ¨clr2¨¨#389BEE¨ßMÑßNÌßO´´´x´É´y´ÏßQ|÷ßRɨkey1¨ßPßBßS¨t1¨ßC¨key0¨ßV¨key2¨´´¨t2¨´´}{ß9ßAßB¨信号强度¨ßD¨fal fa-signal¨ßFßeßHÉßIº0ßJ¨db¨ßLÊßMËßNËßO¨num-xinhao¨´x´Ï´y´ËßQ|÷ßRÉ}{ß9¨tex¨ßB¨0.0.0.0¨ßg¨IP地址¨ßLÉßD´´ßMÍßNËßO¨tex-ip¨´x´Í´y´¤FßQ|÷ßRÌ}{ß9¨ran¨ßB¨屏幕亮度¨ßF¨#FBA613¨ßI¢47ßHÉßLÊßMÏßNÊßO¨SliderKey¨´x´É´y´¤DßQ|÷ßRÎ}{ß9ßAßB¨花盆湿度¨ßD¨fad fa-sprinkler¨ßFßußHÉßIº0ßJßKßLÉßMÍßNËßO¨humi_10¨´x´Í´y´ÉßQ|÷ßRË}{ß9ßoßB¨文本1¨ßg¨系统运行时间¨¨size¨´15´ßLÊßD¨fad fa-cogs¨ßMÍßNËßO¨tex-time¨´x´É´y´¤FßQ|÷ßRÌßFßu}{ß9¨btn¨ßD¨fal fa-power-off¨¨mode¨ÊßB¨屏幕开关¨ßg¨文本2¨ßLÊßMËßNËßO¨print¨´x´Í´y´ÍßQ|÷ßRÉßFßU}{ß9ß14ßD¨far fa-sync¨ß16ÉßB´刷新´ßgß18ßLÊßMËßNËßO¨reflash¨´x´Ï´y´ÍßQ|÷ßFßU}{ß9ßXßLÉßYßZßFßUßaßZßb¨#EA0909¨ßcßZßdßeßMÑßNÍßO´´´x´É´y´ÒßQ|÷ßh¨temp_10¨ßB¨花盆温度¨ßfßyßgßwßRÊßi¨bat_10¨ßj¨花盆电量¨}{ß9ßAßBß1EßD¨fal fa-question¨ßF¨#00A90C¨ßHÉßI¤eßJ´°C´ßLÉßMÍßNËßOß1D´x´É´y´ÉßQ|÷ßRË}{ß9ßsßB¨设定湿度¨ßFßußI¤eßH¤GßLÊßMÑßNÊßO¨Slidertem¨´x´É´y´¤HßQ|÷ßRÌ}{ß9ßAßB´电量´ßD¨far fa-charging-station¨ßFßeßHÉßIº0ßJ´%´ßLÉßMËßNËßOß1F´x´Ë´y´Í}{ß9ßsßB¨浇水时间¨ßFßeßI¤KßHÉßLÉßMÏßNÊßO¨water_time¨´x´É´y´¤EßRÎ}{ß9ß14ßDß15ß16ÊßBßzßgß18ßLÉßMËßNËßO¨water¨´x´Ï´y´¤DßRÉ}{ß9ß14ßDß15ß16ÊßB¨ota¨ßgß18ßLÉßMËßNËßOß1P´x´É´y´¤I}{ß9ß14ßDß15ß16ÊßB¨显示电量¨ßgß18ßLÉßMËßNËßO¨batdisplay¨´x´Í´y´¤I}{ß9ß14ßD¨fad fa-lightbulb-on¨ß16ÊßB¨led控制¨ßgß18ßLÉßMËßNËßO¨led¨´x´Ë´y´¤IßFßU}{ß9ß14ßDß15ß16ÊßB¨自动浇水¨ßgß18ßLÉßMËßNËßO¨auto¨´x´Ï´y´¤I}{ß9ßAßB´电量´ßD¨fas fa-blinds¨ßFßeßHÉßIº0ßJ´%´ßLÉßMËßNËßO¨bat_0¨´x´É´y´Í}÷¨actions¨|÷¨triggers¨|¦¨range¨¨source¨¨source_zh¨¨unit¨‡|¢-K¤o÷ßV´温度´´℃´|ɺ0÷ßP´湿度´´%´—÷ßW|÷}

主板上设定了一个0.96的oled,主要在浇水时显示浇水速度以及浇水时间,当浇水开始时自动打开屏幕,显示数据,浇水完成,则关闭屏幕,达到省电效果。

关于浇水程序,采用的是pwm的方式,控制功率管控制是否浇水以及浇水速度,这样可以有一个加速以及减速过程,

因为用了不少库,减少编程难度,但这样增加了代码占用空间大小,最后几乎用尽空间,做了不少删减,有能力还是自己写代码,库尽量少用。

最后发现可笑的是,我发现它是个废物,不实用,哈哈哈哈哈

  • 9
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
ESP8266是一款常用的Wi-Fi模块,用于实现物联网应用。在温湿度检测方面,可以通过连接DHT11传感器来获取当前环境的温度和湿度数据。引用中的代码片段展示了一个基于ESP8266和DHT11的WiFi数据采集模块,并使用WebSocket方式实现了传感器数据的实时显示。通过该代码,ESP8266可以将温湿度数据发送到服务器,并在网页上进行实时显示。 在代码中,首先创建了一个WebSocket服务器,并监听在8081端口上。当ESP8266连接到服务器后,可以发送温湿度数据。服务器会将数据广播给所有连接的客户端,并在网页上显示。同时,通过HTTP服务器在8080端口上提供一个简单的网页,用于展示实时数据。 至于后续的考虑,引用中提到了几个方面。首先是数据显示方面,目前只显示了温度,还可以进一步优化坐标轴等。其次是考虑加入数据库,可以存储采集到的信息,以便后续展示历史数据。最后是通信方式,可以考虑使用更专业的MQTT协议。在开展这些工作的过程中,可以学习到更多关于回调函数和事件驱动的知识。 总结来说,ESP8266可以通过连接DHT11传感器实现温湿度检测,并利用WebSocket方式将数据实时传输到服务器。在服务器上可以展示实时数据,并可以考虑进一步优化和扩展功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [使用ESP8266构建一个简单的温湿度在线监测装置](https://blog.csdn.net/gitdive/article/details/117636825)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值