【基于Arduino IDE平台开发ESP8266连接巴法云】

简介: 【基于Arduino IDE平台开发ESP8266连接巴法云】

关于巴法云

专注于开源,智造,创新,分享。关注硬件与创新,突破技术极限,面向未来,我们是认真的。

崇尚开源,发掘未知。 ————巴法科技


1. 简介

ESP8266-NodeMCU的环境配置已经在一篇文章有所交代,接下让我们开启巴法云的物联网开发吧!😀😀😀

设计目标

实现esp8266自动配网;

实现ESP8266通过TCP协议连接巴法云的TCP创客云,串口发送指令控制LED的亮灭;

实现ESP8266通过MQTT协议连接巴法云的MQTT设备云;串口发送指令控制LED的亮灭,还实现DHT11温湿度数据的获取,并将数据上发巴法云平台,在线显示数据;

实现巴法云平台对ESP8266的OTA指令升级,基于前面两个实验。

2. 实验准备

本次需要做三个实验,分别是TCP点灯实验,MQTT发送温湿度和OTA指令升级,准备工作包括硬件💡💡💡和软件💻💻💻两部分。


2.1 硬件

你要实现巴法云的三个实验,你需要准备以下材料✨✨✨


  1. ESP8266-NodeMCU单片机(外加安卓数据线);
  2. DHT11温湿度传感器;
  3. 三根母母杜邦线;

硬件连接:ESP8266-NodeMCU硬件连接非常简单,只需将DHT11数据线接入D6引脚就好,这套连线三个实验都通用,具体接线如下🎀🎀🎀

ESP8266-NodeMCU -----> USB
VCC -----> 3.3V 
GND -----> GND
out -----> D2

1.png

2.2 软件

  1. Arduino IED 1.8.5以上(越高越好);
  2. 浏览器登录巴法云平台

3.png

3. 实验步骤

首先搭建巴法云平台,创建的产品相关主题,检测相关数据流,上传固件和发送指令,以便后期程序端口接入开发。👩👩👩

3.1 TCP点灯实验

  1. 登录巴法云物联网平台,选择控制台,点击TCP创客云,然后新建light002主题,那么巴法云TCP就配置好了🎈

4.png

  1. 程序设计,程序有四部分bemfa02、TCP 、motion和update,其中:🎈🎈
文件名 功能
bemfa02 程序初始化调用和主程序调用;
TCP 发送数据到TCP服务器,初始化wifi连接,初始化和服务器建立连接;
motion 检查数据,发送心跳,检查WiFi;
update 固件升级函数。

bemfa02.ino

/*
 * 智能语言控制控制,支持天猫、小爱、小度、google Assistent同时控制
 * Time:20211127
 * Author: 2345VOR
 * 项目实例:发送on、off的指令开关灯
 * 参考文献:https://bbs.bemfa.com/84/last
 */
#include <ESP8266WiFi.h>
#include <ESP8266httpUpdate.h>
#define server_ip "bemfa.com" //巴法云服务器地址默认即可
#define server_port "8344" //服务器端口,tcp创客云端口8344
//********************需要修改的部分*******************//
#define wifi_name  "J09 502"     //WIFI名称,区分大小写,不要写错
#define wifi_password   "qwertyuiop111"  //WIFI密码
String UID = "e8882ae28d5bde39766c330ea913fd46";  //用户私钥,可在控制台获取,修改为自己的UID
String TOPIC = "light002";         //主题名字,可在控制台新建
const int LED_Pin = D4;              //单片机LED引脚值,D2是NodeMcu引脚命名方式,其他esp8266型号将D2改为自己的引脚                         
String upUrl = "http://bin.bemfa.com/b/3BcZTg4ODJhZTI4ZDViZGUzOTc2NmMzMzBlYTkxM2ZkNDY=light002.bin";//固件链接,在巴法云控制台复制、粘贴到这里即可
//**************************************************//
//最大字节数
#define MAX_PACKETSIZE 512
//设置心跳值30s
#define KEEPALIVEATIME 30*1000
//tcp客户端相关初始化,默认即可
WiFiClient TCPclient;
String TcpClient_Buff = "";//初始化字符串,用于接收服务器发来的数据
unsigned int TcpClient_BuffIndex = 0;
unsigned long TcpClient_preTick = 0;
unsigned long preHeartTick = 0;//心跳
unsigned long preTCPStartTick = 0;//连接
bool preTCPConnected = false;
//相关函数初始化
//连接WIFI
void doWiFiTick();
void startSTA();
//TCP初始化连接
void doTCPClientTick();
void startTCPClient();
void sendtoTCPServer(String p);
//led控制函数,具体函数内容见下方
#define turnOnLed() digitalWrite(LED_Pin,LOW);
#define turnOffLed() digitalWrite(LED_Pin,HIGH);
// 初始化,相当于main 函数
void setup() {
  Serial.begin(115200);
  pinMode(LED_Pin,OUTPUT);
  digitalWrite(LED_Pin,HIGH);
  Serial.println("Beginning...");
}
//循环
void loop() {
  doWiFiTick();
  doTCPClientTick();
}

TCP.ino

/*
  *发送数据到TCP服务器
 */
void sendtoTCPServer(String p){
  if (!TCPclient.connected()) 
  {
    Serial.println("Client is not readly");
    return;
  }
  TCPclient.print(p);
}
/*
  *初始化wifi连接
*/
void startSTA(){
  WiFi.disconnect();
  WiFi.mode(WIFI_STA);
  WiFi.begin(wifi_name, wifi_password);
}
/*
  *初始化和服务器建立连接 :style="value.online?'订阅设备在线':'无订阅设备'"  color:#9A9A9A;
*/
void startTCPClient(){
  if(TCPclient.connect(server_ip, atoi(server_port))){
    Serial.print("\nConnected to server:");
    Serial.printf("%s:%d\r\n",server_ip,atoi(server_port));
    String tcpTemp="";  //初始化字符串
    tcpTemp = "cmd=1&uid="+UID+"&topic="+TOPIC+"\r\n"; //构建订阅指令
    sendtoTCPServer(tcpTemp); //发送订阅指令
    tcpTemp="";//清空
    /*
     //如果需要订阅多个主题,可再次发送订阅指令
      tcpTemp = "cmd=1&uid="+UID+"&topic="+主题2+"\r\n"; //构建订阅指令
      sendtoTCPServer(tcpTemp); //发送订阅指令
      tcpTemp="";//清空
     */
    preTCPConnected = true;
    preHeartTick = millis();
    TCPclient.setNoDelay(true);
  }
  else{
    Serial.print("Failed connected to server:");
    Serial.println(server_ip);
    TCPclient.stop();
    preTCPConnected = false;
  }
  preTCPStartTick = millis();
}

motion.ino

/*
  *检查数据,发送心跳
*/
void doTCPClientTick(){
 //检查是否断开,断开后重连
   if(WiFi.status() != WL_CONNECTED) return;
  if (!TCPclient.connected()) {//断开重连
  if(preTCPConnected == true){
    preTCPConnected = false;
    preTCPStartTick = millis();
    Serial.println();
    Serial.println("TCP Client disconnected.");
    TCPclient.stop();
  }
  else if(millis() - preTCPStartTick > 1*1000)//重新连接
    startTCPClient();
  }
  else
  {
    if (TCPclient.available()) {//收数据
      char c =TCPclient.read();
      TcpClient_Buff +=c;
      TcpClient_BuffIndex++;
      TcpClient_preTick = millis();
      if(TcpClient_BuffIndex>=MAX_PACKETSIZE - 1){
        TcpClient_BuffIndex = MAX_PACKETSIZE-2;
        TcpClient_preTick = TcpClient_preTick - 200;
      }
      preHeartTick = millis();
    }
    if(millis() - preHeartTick >= KEEPALIVEATIME){//保持心跳
      preHeartTick = millis();
      Serial.println("--Keep alive:");
      sendtoTCPServer("ping\r\n"); //发送心跳,指令需\r\n结尾,详见接入文档介绍
    }
  }
  if((TcpClient_Buff.length() >= 1) && (millis() - TcpClient_preTick>=200))
  {
    TCPclient.flush();
    Serial.print("Rev string: ");
    TcpClient_Buff.trim(); //去掉首位空格
    Serial.println(TcpClient_Buff); //打印接收到的消息
    String getTopic = "";
    String getMsg = "";
    if(TcpClient_Buff.length() > 15){//注意TcpClient_Buff只是个字符串,在上面开头做了初始化 String TcpClient_Buff = "";
          //此时会收到推送的指令,指令大概为 cmd=2&uid=xxx&topic=light002&msg=off
          int topicIndex = TcpClient_Buff.indexOf("&topic=")+7; //c语言字符串查找,查找&topic=位置,并移动7位,不懂的可百度c语言字符串查找
          int msgIndex = TcpClient_Buff.indexOf("&msg=");//c语言字符串查找,查找&msg=位置
          getTopic = TcpClient_Buff.substring(topicIndex,msgIndex);//c语言字符串截取,截取到topic,不懂的可百度c语言字符串截取
          getMsg = TcpClient_Buff.substring(msgIndex+5);//c语言字符串截取,截取到消息
          Serial.print("topic:------");
          Serial.println(getTopic); //打印截取到的主题值
          Serial.print("msg:--------");
          Serial.println(getMsg);   //打印截取到的消息值
   }
   if(getMsg  == "on"){       //如果收到指令on==打开灯
     turnOnLed();
   }else if(getMsg == "off"){ //如果收到指令off==关闭灯
      turnOffLed();
    }else if(getMsg == "update"){  //如果收到指令update
      updateBin();//执行升级函数
    }
   TcpClient_Buff="";
   TcpClient_BuffIndex = 0;
  }
}
/**************************************************************************
                                 WIFI
***************************************************************************/
/*
  WiFiTick
  检查是否需要初始化WiFi
  检查WiFi是否连接上,若连接成功启动TCP Client
  控制指示灯
*/
void doWiFiTick(){
  static bool startSTAFlag = false;
  static bool taskStarted = false;
  static uint32_t lastWiFiCheckTick = 0;
  if (!startSTAFlag) {
    startSTAFlag = true;
    startSTA();
  }
  //未连接1s重连
  if ( WiFi.status() != WL_CONNECTED ) {
    if (millis() - lastWiFiCheckTick > 1000) {
      lastWiFiCheckTick = millis();
    }
  }
  //连接成功建立
  else {
    if (taskStarted == false) {
      taskStarted = true;
      Serial.print("\r\nGet IP Address: ");
      Serial.println(WiFi.localIP());
      startTCPClient();
    }
  }
}

update.ino

/**
 * 固件升级函数
 * 在需要升级的地方,加上这个函数即可,例如setup中加的updateBin(); 
 * 原理:通过http请求获取远程固件,实现升级
 */
void updateBin(){
  Serial.println("start update");    
  WiFiClient UpdateClient;
  t_httpUpdate_return ret = ESPhttpUpdate.update(UpdateClient, upUrl);
  switch(ret) {
    case HTTP_UPDATE_FAILED:      //当升级失败
        Serial.println("[update] Update failed.");
        break;
    case HTTP_UPDATE_NO_UPDATES:  //当无升级
        Serial.println("[update] Update no Update.");
        break;
    case HTTP_UPDATE_OK:         //当升级成功
        Serial.println("[update] Update ok.");
        break;
  }
}

修改bemfa02主程序对应wifi和巴法云参数,upUrl参数可以暂时不修改,实验三再修改🎈🎈🎈

5.png编译程序,然后上传esp8266,观察esp8266和巴法云TCP控制台🎈🎈🎈🎈

6.png

  1. 实验效果:在订阅的“light002”主题下,发送on或者off,可见esp8266板载灯分别会亮灭。🎈🎈🎈🎈🎈

3.2 MQTT发送温湿度

  1. 登录巴法云物联网平台,选择控制台,点击MQTT设备云,然后新建led002控制端和temp004状态端主题,那么巴法云MQTT设备云就配置好了🎈

image.png

  1. 程序设计,程序有四部分dht11_led_OTA1.0、OTA(update)PubSubClient.cpp和PubSubClient.h,其中:🎈🎈
文件名 功能
dht11_led_OTA1.0 程序初始化调用和主程序调用,自动连接目标wifi,重新连接,led002的回调函数处理;
OTA(update) 固件升级函数。

dht11_led_OTA1.0.ino

/*
  Time:20211127
  Author: 2345VOR
  项目示例:通过MQTT协议发送on或off控制开关,温湿度上传巴法云
  参考文献:https://www.cnblogs.com/bemfa/p/14590133.html
*/
#include <ESP8266WiFi.h>//默认,加载WIFI头文件
#include "PubSubClient.h"//默认,加载MQTT库文件
#include <ESP8266httpUpdate.h>//自动升级库 https://bbs.bemfa.com/84
#include <SimpleDHT.h>//dht11库文件
String upUrl = "http://bin.bemfa.com/b/1BcZTg4ODJhZTI4ZDViZGUzOTc2NmMzMzBlYTkxM2ZkNDY=led002.bin";
const char* ssid = "J09 502";                  //修改,修改为你的路由的WIFI名字
const char* password = "qwertyuiop111";           //修改为你的WIFI密码
const char* mqtt_server = "bemfa.com";       //默认,MQTT服务器地址
const int mqtt_server_port = 9501;          //默认,MQTT服务器端口
#define ID_MQTT  "e8882ae28d5bde39766c330ea913fd46"   //mqtt客户端ID,修改为你的开发者密钥
const char*  topic = "led002";                       //Led主题名字,可在巴法云控制台自行创建,名称随意
const char * dhttopic = "temp004";                 //温湿度主题名字,可在巴法云mqtt控制台创建
int pinDHT11 = D2;                         //dht11传感器引脚输入
int B_led = D4;                           //控制的led引脚
long timeval = 3 * 1000;                  //上传的传感器时间间隔,默认3秒
#define ledstatus !digitalRead(B_led);//led状态默认0
long lastMsg = 0;//时间戳
SimpleDHT11 dht11(pinDHT11);//dht11初始化
WiFiClient espClient;
PubSubClient client(espClient);//mqtt初始化
//灯光函数及引脚定义
#define turnOnLed() digitalWrite(B_led, LOW);
#define turnOffLed() digitalWrite(B_led, HIGH);
//自动连接目标wifi
void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}
//重新连接
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(ID_MQTT)) {//连接mqtt
      Serial.println("connected");
      client.subscribe(topic);//修改,修改为你的主题
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}
void setup() {
  pinMode(B_led, OUTPUT);
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, mqtt_server_port);
  client.setCallback(callback);
  digitalWrite(B_led, HIGH);
}
void loop() {
  if (!client.connected()) {//判断mqtt是否连接
    reconnect();
  }
  client.loop();//mqtt客户端
  long now = millis();//获取当前时间戳
  if (now - lastMsg > timeval) {//如果达到3s,进行数据上传
    lastMsg = now;
    // read without samples.
    byte temperature = 0;
    byte humidity = 0;
    int err = SimpleDHTErrSuccess;
    if ((err = dht11.read(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
      Serial.print("Read DHT11 failed, err="); Serial.println(err); delay(1000);
      return;
    }
    String  msg = "#" + (String)temperature + "#" + (String)humidity + "#" + ledstatus; //数据封装#温度#湿度#开关状态#
    client.publish(dhttopic, msg.c_str());//数据上传
  }
}
//topic = "led002"的回调函数处理
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  String Mqtt_Buff = "";
  for (int i = 0; i < length; i++) {
    Mqtt_Buff += (char)payload[i];
  }
  Serial.print(Mqtt_Buff);
  Serial.println();
  // Switch on the LED if an 1 was received as first character
  if (Mqtt_Buff == "on") {//如果接收字符on,亮灯
    turnOnLed();//开灯函数
  } else if (Mqtt_Buff == "off") {//如果接收字符off,亮灯
    turnOffLed();//关灯函数
  }else if (Mqtt_Buff == "update") {//如果接收字符off,亮灯  
    client.disconnect();     //关闭mqtt
    delay(100);
    updateBin();             //开始升级
  }
  Mqtt_Buff = "";
}

OTA(update).ino

/**
 * 固件升级函数
 * 在需要升级的地方,加上这个函数即可,例如setup中加的updateBin(); 
 * 原理:通过http请求获取远程固件,实现升级
 */
void updateBin(){
  Serial.println("start update");    
  WiFiClient UpdateClient;
  t_httpUpdate_return ret = ESPhttpUpdate.update(UpdateClient, upUrl);
  switch(ret) {
    case HTTP_UPDATE_FAILED:      //当升级失败
        Serial.println("[update] Update failed.");
        break;
    case HTTP_UPDATE_NO_UPDATES:  //当无升级
        Serial.println("[update] Update no Update.");
        break;
    case HTTP_UPDATE_OK:         //当升级成功
        Serial.println("[update] Update ok.");
        break;
  }
}

PubSubClient.cpp

PubSubClient.h

(略)

修改dht11_led_OTA1.0主程序对应wifi和巴法云参数,upUrl参数可以暂时不修改,实验三再修改🎈🎈🎈

image.png

编译程序,然后上传esp8266,观察esp8266和巴法云MQTT控制台🎈🎈🎈🎈

9.png

  1. 实验效果:在订阅的“led002”主题下,发送on或者off,可见esp8266板载灯分别会亮灭;然后点击temp004主题的更多设置,。🎈🎈🎈🎈🎈

11.png

3.3 OTA指令升级

  • OTA升级控制图
    将刚刚两组实验联系起来,实现远程升级固件,通俗讲就是当你配置好实验一,在lighr002输入update指令就可以远程升级到实验二,反而言之也可以。🤩🤩🤩
  • 1.png
  • 关于上文实验一中的upUrl填写,先生成要升级(实验二)的bin文件,导入到TCP创客云的light002的OTA固件;关于上文实验二中的upUrl填写,先生成要升级(实验一)的bin文件,导入到MQTT设备云的led002的OTA固件,把生成的固件地址复制到对应的实验一的upUrl位置(地址不会变,固件会自动迭代更新)
  • 2.png
  • 3.png
  • image.png
  • OTA配置好后,重新下载实验一的代码,然后再TCP创客云的light002主题测试on、off和update指令,输入update就会自动升级到实验二代码,可以到MQTT设备云的led002主题下,测试on、off和update指令,这就是实验一和实验二的梦幻操作!😁😀😂实验一效果如下:
  • image.png

4. 总结

  • 期待大家可以消化代码并且半天实现OTA升级**本文是一个难度中等的物联网项目,实现E实现esp8266自动配网;TCP协议连接巴法云的TCP创客云,串口发送指令控制LED的亮灭;实现ESP8266通过MQTT协议连接巴法云的MQTT设备云;串口发送指令控制LED的亮灭,还实现DHT11温湿度数据的获取,并将数据上发巴法云平台,在线显示数据;实现巴法云平台对ESP8266的OTA指令升级,基于前面两个实验** 😁😁😁
  • 在以后的博文中我们将学会用ESP8266做常用的物联网开发,从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力。
相关实践学习
钉钉群中如何接收IoT温控器数据告警通知
本实验主要介绍如何将温控器设备以MQTT协议接入IoT物联网平台,通过云产品流转到函数计算FC,调用钉钉群机器人API,实时推送温湿度消息到钉钉群。
阿里云AIoT物联网开发实战
本课程将由物联网专家带你熟悉阿里云AIoT物联网领域全套云产品,7天轻松搭建基于Arduino的端到端物联网场景应用。 开始学习前,请先开通下方两个云产品,让学习更流畅: IoT物联网平台:https://iot.console.aliyun.com/ LinkWAN物联网络管理平台:https://linkwan.console.aliyun.com/service-open
目录
相关文章
|
监控 IDE 开发工具
【esp32c3配置arduino IDE教程】
设计用户操作界面,该设备具备简单易用的操作界面,外加显示屏SSD1306和旋转编码器进行显示和控制,用户后期可进行二次开发WiFi或蓝牙连接电脑或手机监控。
1211 0
|
6月前
|
网络协议 IDE 网络安全
GoLand远程开发IDE:使用SSH远程连接服务器进行云端编程
GoLand远程开发IDE:使用SSH远程连接服务器进行云端编程
720 0
|
IDE Go 开发工具
Go开发IDE全览:GoLand vs VSCode全面解析
Go开发IDE全览:GoLand vs VSCode全面解析
507 0
|
24天前
|
IDE 开发工具 C++
AvaloniaUI项目离线开发全攻略:IDE安装、模板应用与NuGet私有化部署一站式解决
本文详细介绍了在离线环境中开发Avalonia UI项目的完整解决方案,包括Visual Studio 2022和JetBrains Rider的离线安装、Avalonia UI模板的配置、私有NuGet服务的部署与使用,以及NuGet包的制作和上传。通过这些步骤,您可以在网络受限或完全离线的环境中顺利进行Avalonia UI项目的开发。
AvaloniaUI项目离线开发全攻略:IDE安装、模板应用与NuGet私有化部署一站式解决
|
1月前
|
IDE 网络安全 开发工具
IDE之vscode:连接远程服务器代码(亲测OK),与pycharm链接服务器做对比(亲自使用过了),打开文件夹后切换文件夹。
本文介绍了如何使用VS Code通过Remote-SSH插件连接远程服务器进行代码开发,并与PyCharm进行了对比。作者认为VS Code在连接和配置多个服务器时更为简单,推荐使用VS Code。文章详细说明了VS Code的安装、远程插件安装、SSH配置文件编写、服务器连接以及如何在连接后切换文件夹。此外,还提供了使用密钥进行免密登录的方法和解决权限问题的步骤。
357 0
IDE之vscode:连接远程服务器代码(亲测OK),与pycharm链接服务器做对比(亲自使用过了),打开文件夹后切换文件夹。
|
1月前
|
IDE 网络安全 开发工具
IDE之pycharm:专业版本连接远程服务器代码,并配置远程python环境解释器(亲测OK)。
本文介绍了如何在PyCharm专业版中连接远程服务器并配置远程Python环境解释器,以便在服务器上运行代码。
287 0
IDE之pycharm:专业版本连接远程服务器代码,并配置远程python环境解释器(亲测OK)。
|
30天前
|
机器学习/深度学习 存储 监控
AllData数据中台核心菜单五:实时开发IDE
杭州奥零数据科技有限公司成立于2023年,专注于数据中台业务,维护开源项目AllData并提供商业版解决方案。AllData提供数据集成、存储、开发、治理及BI展示等一站式服务,支持AI大模型应用,助力企业高效利用数据价值。
|
6月前
|
IDE 测试技术 项目管理
集成开发环境(IDE)的使用:提升Visual Basic开发效率的工具和技巧
【4月更文挑战第27天】本文探讨了如何使用Visual Basic IDE提升开发效率,包括理解IDE组件、利用代码编辑器的智能功能、通过界面设计器设计GUI、使用调试和测试工具、有效管理项目与版本控制、掌握快捷键和宏、定制IDE以及利用学习资源。通过充分利用这些工具和技巧,开发者能更快地编写高质量代码,高效管理项目,从而提升整体开发效率。随着IDE的持续发展,开发者应不断学习新特性以适应进步。
155 1
|
3月前
|
IDE 开发工具 Python
新一代数据科学ide平台DataSpell提前发行版体验
新一代数据科学ide平台DataSpell提前发行版体验