ESP8266配置MQTT的相关函数

**

ESP8266配置MQTT的相关函数

1. 连接wifi

1.1 有账号密码的网络连接

//ssid、password为手动输入的WiFi账号、密码
#include <ESP8266WiFi.h>
const char* ssid = "........";//wifi账号
const char* password = "........";//wifi秘密
void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
//也可先配置网络,station的固定IP地址staticIP、网关地址gateway、子网掩码地址subnet。
//如:IPAddress staticIP(192,168,1,22);
//IPAddress gateway(192,168,1,9);
//IPAddress subnet(255,255,255,0);
//WiFi.config(staticIP,gateway,subnet);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
//改变随机数生成器的种子,有参数则生成相同的随机数
  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

1.2 Samrtconfig配置WiFi

当不知道wifi账号密码或者不方便重新烧录程序时使用Samrtconfig配置WiFi,IOS连接wifi后采用Esptouch app输入密码使esp8266连接WiFi

#include <ESP8266WiFi.h>
void smartConfig()
{
  WiFi.mode(WIFI_STA);
  Serial.println("\r\nWait for Smartconfig");
  delay(2000);
  // 等待配网
  WiFi.beginSmartConfig();
 
 while (1)
  {
    Serial.print(".");
    delay(500);
    if (WiFi.smartConfigDone())
    {
      Serial.println("SmartConfig Success");
      Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
      Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());
      WiFi.setAutoConnect(true);  // 设置自动连接
      break;
    }
  } 
  
  Serial.println("");
  Serial.println("WiFi connected");  
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

1.3 断电重连并智能配网(Smartconfig)


#include <ESP8266WiFi.h>
 
bool autoConfig()
{
  WiFi.begin();
  for (int i = 0; i < 20; i++)
  {
    int wstatus = WiFi.status();
    if (wstatus == WL_CONNECTED)
    {
      Serial.println("AutoConfig Success");
      Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
      Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());
      WiFi.printDiag(Serial);
      return true;
      //break;
    }
    else
    {
      Serial.print("AutoConfig Waiting......");
      Serial.println(wstatus);
      delay(1000);
    }
  }
  Serial.println("AutoConfig Faild!" );
  return false;
  //WiFi.printDiag(Serial);
}
void smartConfig()
{
  WiFi.mode(WIFI_STA);
  Serial.println("\r\nWait for Smartconfig");
  WiFi.beginSmartConfig();
  while (1)
  {
    Serial.print(".");
    if (WiFi.smartConfigDone())
    {
      Serial.println("SmartConfig Success");
      Serial.printf("SSID:%s\r\n", WiFi.SSID().c_str());
      Serial.printf("PSW:%s\r\n", WiFi.psk().c_str());
      WiFi.setAutoConnect(true);  // 设置自动连接
      break;
    }
    delay(1000); // 这个地方一定要加延时,否则极易崩溃重启
  }
}
 
void setup()
{
  Serial.begin(115200);
 
  if (!autoConfig())
  {
    Serial.println("Start module");
    smartConfig();
  }
}
 
void loop()
{
  delay(1000);
  Serial.println("loop");
}

1.4 web配网

通过先配置esp8266为AP模式建立一个开放网络,其他设备连接wifi后,网页进入设置的固定IP(IPAddress local_IP(192,168,4,1))页面,输入wif账号和密码,esp8266在转换为STA模式自动连接wifi。

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

#define DEBUG

#ifdef DEBUG
  //以下三个定义为调试定义
  #define DebugBegin(baud_rate)    Serial.begin(baud_rate)
  #define DebugPrintln(message)    Serial.println(message)
  #define DebugPrint(message)    Serial.print(message)
#else
  //以下三个定义为调试定义
  #define DebugBegin(baud_rate)
  #define DebugPrintln(message)
  #define DebugPrint(message)
#endif  

const char* ap_ssid = "esp_webconfig";
const char* ap_password = "";//开放式网络

char sta_ssid[32] = {0};
char sta_password[64] = {0};
//网页界面配置
const char* webpage_html = "\
<!DOCTYPE html>\r\n\
<html lang='en'>\r\n\
<head>\r\n\
  <meta charset='UTF-8'>\r\n\
  <title>Document</title>\r\n\
</head>\r\n\
<body>\r\n\
  <form name='input' action='/' method='POST'>\r\n\
        wifi名称: <br>\r\n\
        <input type='text' name='ssid'><br>\r\n\
        wifi密码:<br>\r\n\
        <input type='text' name='password'><br>\r\n\
        <input type='submit' value='保存'>\r\n\
    </form>\r\n\
</body>\r\n\
</html>\r\n\
";

//esp_webconfig wifi的信息
IPAddress local_IP(192,168,4,1);//IP地址
IPAddress gateway(192,168,4,1);//网关地址
IPAddress subnet(255,255,255,0);//子网掩码地址
//函数声明
void initApConfig();
void initWebServer();
void connectToWifi();
void handleRootPost();
void handleRoot();
void handleNotFound();

ESP8266WebServer server(80);
//除去用于DEBUG的打印命令,setup函数里主要有 initApConfig(); initWebServer();两个初始化函数
void setup(void) {
  DebugBegin(115200);
  DebugPrintln("");
  DebugPrint("connect ap: ");
  DebugPrintln(ap_ssid);

  initApConfig();

  DebugPrint("IP address: ");
  DebugPrintln(WiFi.softAPIP());

  initWebServer();

  DebugPrintln("HTTP server started");

  Serial.printf("Ready! Open http://%s in your browser\n",
  WiFi.softAPIP().toString().c_str());
}
/**
 * 初始化AP配置
 */
void initApConfig(){
  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(local_IP, gateway, subnet);
  WiFi.softAP(ap_ssid, ap_password);
}

/**
 * 初始化webserver配置
 */
void initWebServer(){
  server.on("/", HTTP_GET, handleRoot);
  server.on("/", HTTP_POST, handleRootPost);
  server.onNotFound(handleNotFound);

  server.begin();   
}

/**
 * 连接到WiFi,在web smartconfig配网中被放在web响应回调函数中。
 */
void connectToWifi(){
  DebugPrintln("connectToWifi");
  WiFi.disconnect();
  WiFi.mode(WIFI_STA);
  WiFi.begin(sta_ssid, sta_password);

  int cnt = 0;
  while (WiFi.status() != WL_CONNECTED) {
          delay(500);
          cnt++;
          Serial.print(".");
          if(cnt>=40){
            cnt = 0;
            //重启系统
            DebugPrintln("\r\nRestart now!");
            ESP.restart();
          }
  }
  DebugPrintln("connectToWifi Success!");
}

/**
 * 处理web post请求
 */
void handleRootPost() {
  DebugPrintln("handleRootPost");
  if (server.hasArg("ssid")) {
    DebugPrint("got ssid:");
    strcpy(sta_ssid, server.arg("ssid").c_str());
    DebugPrintln(sta_ssid);
  } else {
    DebugPrintln("error, not found ssid");
    server.send(200, "text/html", "<meta charset='UTF-8'>error, not found ssid");
    return;
  }

  if (server.hasArg("password")) {
    DebugPrint("got password:");
    strcpy(sta_password, server.arg("password").c_str());
    DebugPrintln(sta_password);
  } else {
    DebugPrintln("error, not found password");
    server.send(200, "text/html", "<meta charset='UTF-8'>error, not found password");
    return;
  }

  server.send(200, "text/html", "<meta charset='UTF-8'>保存成功");
  delay(2000);
  //连接wifi
  connectToWifi();
}

/**
 * 处理web get请求
 */
void handleRoot() {
  DebugPrintln("handleRoot");
  server.send(200, "text/html", webpage_html);
}

void handleNotFound() {
  String message = "File Not Found\n\n";
  server.send(404, "text/plain", message);
}

void loop(void) {
/**
必须在loop循环中使用,检查有没有客户端设备通过网络向ESP8266网络服务器发送请求。
每一次handleClient`函数被调用时,ESP8266网络服务器都会检查一下是否有客户端发送HTTP请求。
loop函数里有类似delay一类的函数延迟程序运行,那么就一定要注意了。
如果handleClient函数长时间得不到调用,ESP8266网络服务器会因为无法经常检查HTTP客户端请求而导致服务器响应*变慢,严重的情况下,会导致服务器工作不稳定。
*/
server.handleClient();}

2. 配置MQTT服务

2.1 配置MQTT服务器和客户端

添加 PubSubClient.h 头文件,先配置客户端

/**
 * 配置客户端
 * @param client  client实例,比如  wificlient
 */
PubSubClient& PubSubClient::setClient(Client& client){
    this->_client = &client;
    return *this;
}

再配置MQTT服务器,服务器配置在setup函数中,服务参数有(数组)、(IPAddress)、(字符串),另一个参数为端口号

PubSubClient& PubSubClient::setServer(uint8_t * ip, uint16_t port)
PubSubClient& PubSubClient::setServer(IPAddress ip, uint16_t port)
PubSubClient& PubSubClient::setServer(const char * domain, uint16_t port)

服务器和客户端具体配置代码(部分)

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
//wifi配置信息、mqtt服务器信息
const char* ssid = "........";//wifi账号
const char* password = "........";//wifi秘密
const char* mqtt_server = "broker.mqtt-dashboard.com";//mqtt服务器
//配置客户端函数参数一般选择wificlient
WiFiClient espClient;
//定义PubSubClient为client, 之后的函数编写都用client.****()
PubSubClient client(espClient);
/*
相关的其他函数

*/
void setup() {
//MQTT服务器配置函数在setup内
client.setServer(mqtt_server, 1883);
}

2.2 MQTT连接

使用 client.connected(),可在setup内一次设置,但一般在loop中做一个连接并检测的作用,配合使用的还有 reconnect()函数(需要自己配置)

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // 建立一个随机的服务器IP
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
      // 连接后操作由具体而定,也可以做个重连标志位
      client.publish("outTopic", "hello world");
      client.subscribe("inTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void loop() {
  //重连机制
  if (!client.connected()) {
    reconnect();
  }
  //同 server.handleClient() 一样需要不断监听信息
  client.loop();
}

2.3 客户端订阅主题

使用 client.subscribe()函数,参数有(const char* topic)、(const char* topic, uint8_t qos)
qos为MQTT消息等级

  1. QoS 0:“最多一次”,消息发布完全依赖底层 TCP/IP 网络。分发的消息可能丢失或重复。例如,这个等级可用于环境传感器数据,单次的数据丢失没关系,因为不久后还会有第二次发送。
  2. QoS 1:“至少一次”,确保消息可以到达,但消息可能会重复。
  3. QoS 2:“只有一次”,确保消息只到达一次。例如,这个等级可用在一个计费系统中,这里如果消息重复或丢失会导致不正确的收费。
boolean PubSubClient::subscribe(const char* topic)
boolean PubSubClient::subscribe(const char* topic, uint8_t qos)
//例如
client.subscribe("inTopic");

2.3.1 订阅回调处理函数

先定义处理回调函数 client.setCallback() 参数为处理函数,放在setup函数内,处理函数单独定义

PubSubClient& PubSubClient::setCallback(MQTT_CALLBACK_SIGNATURE)
//例如
client.setCallback(callback);

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  // Switch on the LED if an 1 was received as first character
  if ((char)payload[0] == '1') {
    digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on (Note that LOW is the voltage level
    // but actually the LED is on; this is because
    // it is active low on the ESP-01)
  } else {
    digitalWrite(BUILTIN_LED, HIGH);  // Turn the LED off by making the voltage HIGH
  }
}

2.4 发布消息

由客户端向服务器对应主题发送消息,函数client.publish,参数主要为(主题,内容)、(主题、内容、内容长度)

boolean PubSubClient::publish(const char* topic, const char* payload)
boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength)
/* 发布对应主题消息
 * @param topic 主题
 * @param payload 有效负载(F(xxx))
 * @param retained 是否保持
 */
boolean PubSubClient::publish_P(const char* topic, const char* payload, boolean retained)
//例如 
client.publish("outTopic", msg);
  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值