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

Arduino教程传送门

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

  • 1. 简介
  • 2. 实验准备
    • 2.1 硬件
    • 2.2 软件
  • 3. 实验步骤
    • 3.1 TCP点灯实验
    • 3.2 MQTT发送温湿度
    • 3.3 OTA指令升级
  • 4. 总结

关于巴法云
专注于开源,智造,创新,分享。关注硬件与创新,突破技术极限,面向未来,我们是认真的。
崇尚开源,发掘未知。 ————巴法科技

1. 简介

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

设计目标

  1. 实现esp8266自动配网
  2. 实现ESP8266通过TCP协议连接巴法云的TCP创客云,串口发送指令控制LED的亮灭;
  3. 实现ESP8266通过MQTT协议连接巴法云的MQTT设备云;串口发送指令控制LED的亮灭,还实现DHT11温湿度数据的获取,并将数据上发巴法云平台,在线显示数据;
  4. 实现巴法云平台对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

【基于Arduino IDE平台开发ESP8266连接巴法云】_第1张图片

2.2 软件

  1. Arduino IED 1.8.5以上(越高越好);
  2. 浏览器登录巴法云平台。
    【基于Arduino IDE平台开发ESP8266连接巴法云】_第2张图片

3. 实验步骤

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

3.1 TCP点灯实验

  1. 登录巴法云物联网平台,选择控制台,点击TCP创客云,然后新建light002主题,那么巴法云TCP就配置好了
    【基于Arduino IDE平台开发ESP8266连接巴法云】_第3张图片
  2. 程序设计,程序有四部分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 
#include 

#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;
  }
}
  1. 修改bemfa02主程序对应wifi和巴法云参数,upUrl参数可以暂时不修改,实验三再修改
    【基于Arduino IDE平台开发ESP8266连接巴法云】_第4张图片

  2. 编译程序,然后上传esp8266,观察esp8266和巴法云TCP控制台
    【基于Arduino IDE平台开发ESP8266连接巴法云】_第5张图片

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

3.2 MQTT发送温湿度

  1. 登录巴法云物联网平台,选择控制台,点击MQTT设备云,然后新建led002控制端和temp004状态端主题,那么巴法云MQTT设备云就配置好了
    【基于Arduino IDE平台开发ESP8266连接巴法云】_第6张图片

  2. 程序设计,程序有四部分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 //默认,加载WIFI头文件
#include "PubSubClient.h"//默认,加载MQTT库文件
#include //自动升级库 https://bbs.bemfa.com/84
#include //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
(略)

  1. 修改dht11_led_OTA1.0主程序对应wifi和巴法云参数,upUrl参数可以暂时不修改,实验三再修改
    【基于Arduino IDE平台开发ESP8266连接巴法云】_第7张图片

  2. 编译程序,然后上传esp8266,观察esp8266和巴法云MQTT控制台
    【基于Arduino IDE平台开发ESP8266连接巴法云】_第8张图片

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

【基于Arduino IDE平台开发ESP8266连接巴法云】_第9张图片
实验效果如GIF

3.3 OTA指令升级

  • OTA升级控制图
    将刚刚两组实验联系起来,实现远程升级固件,通俗讲就是当你配置好实验一,在lighr002输入update指令就可以远程升级到实验二,反而言之也可以。
    【基于Arduino IDE平台开发ESP8266连接巴法云】_第10张图片
  1. 关于上文实验一中的upUrl填写,先生成要升级(实验二)的bin文件,导入到TCP创客云的light002的OTA固件;关于上文实验二中的upUrl填写,先生成要升级(实验一)的bin文件,导入到MQTT设备云的led002的OTA固件,把生成的固件地址复制到对应的实验一的upUrl位置(地址不会变,固件会自动迭代更新)
    【基于Arduino IDE平台开发ESP8266连接巴法云】_第11张图片

【基于Arduino IDE平台开发ESP8266连接巴法云】_第12张图片
【基于Arduino IDE平台开发ESP8266连接巴法云】_第13张图片
OTA配置好后,重新下载实验一的代码,然后再TCP创客云的light002主题测试on、off和update指令,输入update就会自动升级到实验二代码,可以到MQTT设备云的led002主题下,测试on、off和update指令,这就是实验一和实验二的梦幻操作!实验一效果如下:
【基于Arduino IDE平台开发ESP8266连接巴法云】_第14张图片

4. 总结

  • 期待大家可以消化代码并且半天实现OTA升级**本文是一个难度中等的物联网项目,实现E实现esp8266自动配网;TCP协议连接巴法云的TCP创客云,串口发送指令控制LED的亮灭;实现ESP8266通过MQTT协议连接巴法云的MQTT设备云;串口发送指令控制LED的亮灭,还实现DHT11温湿度数据的获取,并将数据上发巴法云平台,在线显示数据;实现巴法云平台对ESP8266的OTA指令升级,基于前面两个实验**
  • 在以后的博文中我们将学会用ESP8266做常用的物联网开发,从而实现对外部世界进行感知,充分认识这个有机与无机的环境,科学地合理地进行创作和发挥效益,然后为人类社会发展贡献一点微薄之力
  • 参考链接:
    第一个链接十分有用,主要参考代码,期待大家都可以实现!
  • esp8266 OTA远程无线升级
  • (开源)微信小程序+mqtt+esp8266,温湿度实时显示
  • 利用天猫精灵控制ESP8266(NodeMCU开发板)arduino ide开发

你可能感兴趣的:(arduino学习,物联网,巴法云,MQTT,TCP,ESP8266)