快速攻略ESP8266NodeMCU(基于Arduino IDE)(下)
本文最后更新于129 天前,其中的信息可能已经过时,如有错误请发送邮件到canke137@foxmail.com

前情回顾

书接上回,我们掌握了ESP8266NodeMCU的基本功能后,终于开始学习ESP8266最强大的WiFi功能了。ESP8266的WiFi功能强大且易于使用,是物联网和智能设备项目的热门选择。

上回链接:快速攻略ESP8266NodeMCU(基于Arduino IDE)(上)

没有看上回的小伙伴也莫慌,如果只是需要ESP8266做WiFi模块使用,那么单看本文就行。

Wi-Fi

要使用ESP8266的WiFi功能需要先包含#include<ESP8266WiFi.h>

ESP8266WiFi库的函数很多,我这里只会挑一些常用的讲。

设置网络模式

WiFi.mode(WiFiMode_t mode);

设置 ESP8266 的 WiFi 模式。参数mode是一个 WiFiMode_t 类型的枚举值,用于设定ESP8266的工作模式。WiFiMode_t 枚举定义了以下几种模式:

  • WIFI_OFF:关闭 Wi-Fi 功能。
  • WIFI_STA:设置为客户端模式,用于连接到其他接入点。
  • WIFI_AP:设置为接入点模式,允许其他设备连接到 ESP8266。
  • WIFI_AP_STA:同时设置为接入点模式和客户端模式。
WiFi.softAP(ssid, password);
WiFi.softAPConfig(ip, gateway, subnet);

 这两个函数在设置 ESP8266 作为软接入点时使用,用于设置 ESP8266软接入点(通俗说就是热点)的名称和密码,以及IP 地址、网关地址和子网掩码。

初始化和配置

WiFi.begin(ssid, password);

启动与指定WiFi网络连接。和多数功能一样.begin都是启动函数,参数ssid是指定WiFi网络的名称,password则是指定网络的密码。

WiFi.disconnect();

断开当前连接的WiFi网络。这个函数没有参数和返回值,通常在你需要断开当前网络并连接另一个网络时使用。

WiFi.status();

获取当前WiFi连接的状态。这个函数会返回一个wl_status_t 类型的值,该值代表了当前WiFi的状态。wl_status_t 枚举定义了以下几种状态:

  • WL_NO_SHIELD: 没有检测到 WiFi模块。
  • WL_IDLE_STATUS: WiFi模块处于空闲状态。
  • WL_NO_SSID_AVAIL: 扫描不到指定的 SSID。
  • WL_SCAN_COMPLETED: 扫描完成。
  • WL_CONNECTED: 已连接到一个接入点。
  • WL_CONNECT_FAILED: 连接失败。
  • WL_CONNECTION_LOST: 连接丢失。
  • WL_DISCONNECTED: 未连接到接入点。
WiFi.setAutoReconnect(boolean autoReconnect)

设置是否自动重新连接到WiFi网络。参数autoReconnect设置是否启用重新连接,可输入以下关键词:

  • true:启用自动重新连接。如果ESP8266失去了与WiFi网络的连接,它将自动尝试重新连接到之前配置的网络。
  • false:禁用自动重新连接。如果ESP8266失去了与WiFi网络的连接,它不会自动尝试重新连接。

获取网络信息

WiFi.SSID();
WiFi.localIP();
WiFi.gatewayIP();
WiFi.subnetMask();

这几个函数都是用于返回设备当前网络信息。从上到下依次是返回当前连接网络的名称,返回设备当前的IP地址,返回网络的网关IP地址,返回网络的子网掩码。

连接网络

现在我们来写连接WiFi并返回网络状态的函数。

#include<ESP8266WiFi.h> 

const char* WIFISSID ="OPPOFindX3"; //WiFi名称
const char* PASSWORO ="55555555";   //WiFi密码
uint8_t wifi_flag=0;

void setup() {
  Serial.begin(115200);
  //设置为客户端模式
  WiFi.mode(WIFI_STA);
  //连接Wifi
  WiFi.begin(WIFISSID, PASSWORO);
  //等待连接
  while(WiFi.status() != WL_CONNECTED){
      delay(500);
      Serial.print(".");
  }
  //打印WiFi信息
  Serial.println("Connected to Wi-Fi");
  Serial.print("Wi-Fi Name: ");
  Serial.println(WiFi.SSID());
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  //启用自动重连
  WiFi.setAutoReconnect(true);
}

void loop() {
  //持续检查连接状态
  switch(WiFi.status()){
    case WL_CONNECTED://已连接网络
    if(wifi_flag == 1){
      Serial.println("Connected to Wi-Fi");
      Serial.print("Wi-Fi Name: ");
      Serial.println(WiFi.SSID());
      Serial.print("IP address: ");
      Serial.println(WiFi.localIP());
      wifi_flag=0;
    }
      break; 
    case WL_DISCONNECTED://未连接网络
    if(wifi_flag == 0){
       wifi_flag=1;
       Serial.println("wifi Disconnected");
    }
      break;
  }
}

这里我连接的是我手机开的热点,特意关了一下热点,连接和重连都是没问题的。

MQTT

既然我们已经让ESP8266连上网络了,ESP8266的学习也将步入尾声。

要想将ESP8266应用与物联网中我们还需要掌握通讯协议,MQTT是一种轻量级的消息传输协议,专为带宽有限和不稳定的网络环境设计。它广泛应用于物联网领域,用于连接远程设备,实现数据传输。

环境配置

ESP8266有相应的MQTT协议的库PubSubClient,可以在Arduino的官方网站上去下载。

链接:PubSubClient库下载

下载2.8.0版本,下载完成后再去Arduino IDE中安装。

添加库之后需要等一会加载。

加载完成后我们在程序中包含PubSubClient库再编译下,测试是否装好。

初始化

#include<ESP8266WiFi.h> 
#include<PubSubClient.h>

WiFiClient espClient;
PubSubClient client(espClient);

要使用PubSubClient库需要同时包含WiFi库。

首先创建一个WiFiClient 类型,再创建PubSubClient类型来使用WiFiClient 类型。

设置服务器

client.setServer(IPAddress ip, uint16_t port);
client.setServer(const char* domain, uint16_t port);

设置MQTT服务器地址和端口号。这个函数有两种形式,可以使用IP地址或者域名来访问服务器。参数ip为服务器的 IP 地址,可以是IPv4地址,domain是服务器域名,port是服务器端口号。

连接服务器

client.connect(const char* id);

连接MQTT 服务器。这个函数有几种形式,这个是无身份验证连接服务器。参数id是设置客户端唯一标识符。

client.connect(const char* client_id, const char* username, const char* password);

带用户名和密码的连接。和上个函数差不多,只是多了设置用户名和服务器密码的参数。

断开连接

client.disconnect();

断开与MQTT服务器的连接。这个函数一般用在需要重新配置连接参数是使用。

发布主题消息

client.publish(const char* topic, const char* payload);

发布消息到 MQTT 服务器上的特定主题。这个函数也有几种形式,这个是向指定主题发布消息。参数topic是要发布消息的主题(字符串),payload是要发布的内容。

client.publish(const char* topic, const char* payload, boolean retained);

发布保留消息到主题。和上个函数差不多,不过多了一个参数retained。retained是一个布尔值,用于指定消息是否为保留消息。如果设置为true,那么新的订阅者订阅该主题时会立即收到保留消息。

如果想要取消保留消息,需要发布一个消息为空的保留消息如:client.publish("topic","",true);

订阅主题

client.subscribe(const char* topic);

订阅MQTT服务器上的主题。参数topic是要订阅的主题字符串。

订阅回调函数

client.setCallback(Callback);

客户端接收到来自订阅主题的消息时,回调函数就会被调用。

要使用这个函数需要定义一个回调函数,且必须要符合以下原型:

void callback(char* topic, byte* payload, unsigned int length);
  • topic: 接收到消息的主题字符串。
  • payload: 接收到的消息内容,以字节数组形式。
  • length: 接收到的消息长度。

消息循环

在完成前面一系列配置后,我们还需要保持设备和服务器之间的联系。

我们需要定时的向服务器发送一个心跳信号,告诉服务器我们还没寄寄。这里我们可以设置这个心跳信号的时间。

client.setKeepAlive(tim);

如果没有设置间隔时间的话默认会是15秒,当超过间隔时间内没发送心跳信号,服务器就会认为设备寄了。在 PubSubClient 库中,心跳信号的管理是自动的。需要调用下函数:

client.loop();

将这个函数放在主循环中使用时,客户端在设定心跳信号时间内没有发送任何消息,PubSubClient 库会自动发送一个 PINGREQ 消息。如果在设定心跳信号时间内客户端没有从服务器接收到任何消息,它也会发送 PINGREQ。如果服务器在一定时间内没有响应 PINGRESP,客户端将断开连接。

检查连接状态

client.connected();

返回设备与服务器连接状态。可以在主循环中使用此函数来实时检查与服务器的连接状态。

MQTT发送/接收消息

好了我们已经基本掌握了PubSubClient 库的使用了,下面我们来编写代码。

#include<ESP8266WiFi.h> 
#include<PubSubClient.h>
#include <Ticker.h>
// WiFi设置
const char* WIFISSID ="name";
const char* PASSWORO ="passworo";
uint8_t wifi_flag=0;
// MQTT服务器设置
const char* mqtt_server = "xx.xx.xx.xx";
const int mqtt_port = 1883;
const char* mqtt_id = "esp-01";
WiFiClient espClient;
PubSubClient client(espClient);
Ticker tim0;
void setup_wifi(){
  WiFi.mode(WIFI_STA);//设置为客户端模式
  //连接Wifi
  WiFi.begin(WIFISSID, PASSWORO);
  while(WiFi.status() != WL_CONNECTED){
      delay(500);
      Serial.print(".");
  }
  Serial.println("Connected to Wi-Fi");
  Serial.println(WiFi.SSID());
  //启用自动重连
  WiFi.setAutoReconnect(true);
}
void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect(mqtt_id)) {
      Serial.println("connected");
      // 订阅主题
      client.subscribe("topic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}
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();
}
void Issued(){
  client.publish("test","Hello!MQTT");
}
void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
  client.setKeepAlive(15);
  tim0.attach_ms(1000, Issued);
}
void loop() {
  //持续检查连接状态
  switch(WiFi.status()){
    case WL_CONNECTED:
      if(wifi_flag == 1){
        Serial.println("Connected to Wi-Fi");
        Serial.println(WiFi.SSID());
        wifi_flag=0;
      }
      if(!client.connected()){//检查与服务器连接状态
        reconnect();
      }
      client.loop();
      break; 
    case WL_DISCONNECTED:
      if(wifi_flag == 0){
         wifi_flag=1;
        Serial.println("wifi Disconnected");
      }
      break;
  }
}

这里我写了一个向主题test定时发送消息,同时接收topic主题发送的消息并将其输出到串口的程序。

OK,这里使用MQTTX软件来验证下。软件地址:MQTTX下载

可以看到,test主题确实收到来自ESP8266发布的消息。现在我们在topic主题发送消息。

OK,ESP8266也是接收到了topic主题发布的消息。

这里我使用的MQTT服务器是我自己搭建的,后续我会出一期关于MQTT服务器的文章。

使用MQTT点灯

好了,行至此处ESP8266已经可以说通关了,此时应当不忘初心,继续向点灯大师的方向前进。下面让我们使用MQTT服务器实现远程点灯。

在点灯之前,我们还需要了解一下MQTT常用的数据格式Json。

JSON数据格式

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。JSON 是基于 JavaScript 语言的一个子集,但它独立于语言,使用文本格式来存储和表示数据。

以下是一个简单 JSON 对象的示例:

{
  "name": "Van Darkholme",
  "age": 30,
  "DATA": [11, 45, 14]
}

一个 JSON 对象以 { 开始,并以 } 结束,它包含键值对,键是字符串,值可以是字符串、数字、数组、布尔值、null 或者另一个 JSON 对象。

ArduinoJson库

在了解JSON格式后,我们需要使用ESP8266去解析它。

在Arduino IDE中有专门解析JSON数据的库ArduinoJson。下载地址:ArduinoJson库

添加库又是熟悉的配方,熟悉的味道ヽ( ̄▽ ̄)ノ

初始化

#include<ArduinoJson.h>
DynamicJsonDocument doc(1024);

和前面的库差不多,先添加库文件然后创建JsonDocument对象。

解析数据

使用ArduinoJson库可以非常简单的解析JSON数据,下面举一个解析数据的例子。

String json = "{\"name\":\"Van\",\"temper\":36.6}";
//分配解析文档内存
DynamicJsonDocument doc(1024);
// 解析 JSON 字符串
DeserializationError error = deserializeJson(doc, json);
// 检查解析是否成功
if (error) {
  return;
}
// 访问解析后的数据
const char* name= doc["name"];
double temper= doc["temper"];

deserializeJson函数会将JSON数据解析,然后放入我们创建的JsonDocument对象里,之后就可以直接访问。

转换数据

掌握了解析数据后我们就可以接受数据了,需要发送数据的话还需要将数据转换为JSON格式发送。下面举个栗子。

const char* name = "dio";
double temper = 114.514;
uint8_t led = 1;
DynamicJsonDocument doc(128); 
// 写入数据
doc["name"] = name;
doc["temper"] = temper;
doc["led"] = led;
//将JSON转换为字符串
String output;
serializeJson(doc, output);

将数据做成JSON格式很方便,这样就可以将数据转换成JSON格式的字符串了。

点灯

现在可以开始点灯了,下面编写代码。

#include<ESP8266WiFi.h> 
#include<PubSubClient.h>
#include<ArduinoJson.h>
#include <Ticker.h>
// WiFi设置
const char* WIFISSID ="SSID";
const char* PASSWORO ="passworo";
uint8_t wifi_flag=0;
// MQTT服务器设置
const char* mqtt_server = "xx.xx.xx.xx";
const int mqtt_port = 1883;
const char* mqtt_id = "esp-01";
WiFiClient espClient;
PubSubClient client(espClient);
DynamicJsonDocument doc(1024); 
Ticker tim0;
const char* name;
double temper;
uint8_t led;
void setup_wifi(){
  WiFi.mode(WIFI_STA);//设置为客户端模式
  //连接Wifi
  WiFi.begin(WIFISSID, PASSWORO);
  while(WiFi.status() != WL_CONNECTED){
      delay(500);
      Serial.print(".");
  }
  Serial.println("Connected to Wi-Fi");
  Serial.println(WiFi.SSID());
  //启用自动重连
  WiFi.setAutoReconnect(true);
}
void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect(mqtt_id)) {
      Serial.println("connected");
      // 订阅主题
      client.subscribe("topic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}
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();
  DeserializationError error = deserializeJson(doc, payload);
  if (error) {
    return;
  }
  name = doc["name"];
  temper = doc["temper"];
  led = doc["led"];
  Serial.printf("name=%s, temper=%f, led=%d\n",name,temper,led);
}
void Issued(){
  doc["name"] = name;
  doc["temper"] = temper;
  doc["led"] = led;
  String output;
  serializeJson(doc, output);
  client.publish("test",output.c_str());
}
void setup() {
  Serial.begin(115200);
  pinMode(12,OUTPUT);
  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);
  client.setKeepAlive(15);
  tim0.attach_ms(1000, Issued);

}
void loop() {
  //持续检查连接状态
  switch(WiFi.status()){
    case WL_CONNECTED:
      if(wifi_flag == 1){
        Serial.println("Connected to Wi-Fi");
        Serial.println(WiFi.SSID());
        wifi_flag=0;
      }
      if(!client.connected()){//检查与服务器连接状态
        reconnect();
      }
      client.loop();
      break; 
    case WL_DISCONNECTED:
      if(wifi_flag == 0){
         wifi_flag=1;
        Serial.println("wifi Disconnected");
      }
      break;
  }
  if(led){ //开关灯
    digitalWrite(12,1);
  }else{
    digitalWrite(12,0);
  }
}

这段代码实现了从MQTT服务器订阅的主题中获取消息,并且解析JSON格式数据,再将客户端的信息以JSON格式定时发送到test主题。使用了一个变量来控制灯的开关,当接收到led=1的消息时点亮灯,反之则关灯。

通过MQTTX验证一下,看来是没问题。

总结

能够坚持看到这里的朋友,恭喜你通关了ESP8266。根据现在掌握的知识,相信做一些简单的物联网项目也是没什么问题了,比如物联网小车,智能寝室门锁之类的项目。

关于MQTT服务器,我使用服务器的是利用阿里云的免费体验ECS服务器搭建的。之后我会出一期关于MQTT服务器的文章(我先自己玩明白捏)。

好了,快速攻略ESP8266NodeMCU(基于Arduino IDE)系列完结了。感谢各位阅读,下个系列再见。

文末附加内容

评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇