ESP8266 物联网设备的自动网络配置





5.00/5 (7投票s)
关于自动配置 ESP8266 物联网设备的指南和源代码
引言
最近,我制作了一个设备,需要放在树林中间的一个小棚子里,用于报告传感器读数。由于它与世隔绝,设备不适合有用户界面,甚至连按钮都不需要。它需要向任何监听的机器广播传感器读数,并且需要在已知地址提供一个小网站。在创建这个设备的过程中,我编写了一些代码,用于自动配置ESP8266并在网络上发布。本文旨在解释这个过程,并提供代码以供您在自己的物联网项目中实现。虽然它专为ESP8266设计,但这些概念可以移植到其他平台。它应该适用于任何ESP8266模块,甚至是ESP-01。
必备组件
- 本文假设您已经熟悉ESP8266的编程。
- 本文假设您正在使用Arduino IDE。
- 本文假设IDE已配置为编程基于ESP8266的模块。
概念化这个混乱的局面
我们的第一个任务是连接到WiFi。我们将从内部闪存中读取一个配置文件。其中将包含一个SSID和网络密码。
如果我们在过程中超时,我们将开始监听WPS信号。如果超时,我们将再次尝试连接到WiFi,该过程将重复进行。
如果成功使用了WPS,我们将SSID和网络密码写入闪存并重置设备。否则,我们将继续。
最后,我们将使用多播DNS (mDNS) 来发布我们的设备,以便其他人可以使用众所周知的本地域名找到它。
如果我们需要推送数据,理想情况下,我们将使用UDP多播,以便任何设备都可以在众所周知的本地多播地址上监听。UDP通常是传输传感器读数的理想选择。否则,如果设备要监听,它可以这样做,并且其他设备可以使用其众所周知的域名找到它。
编写这个混乱的程序
请务必将您的ESP8266模块设置为编程模式。我没有对这段代码进行分解,因为我想保持它易于复制和粘贴,而且在其中包含一堆函数原型会破坏它。我可能会在某个时候将其制作成一个库。
首先,我们将介绍我们的包含和全局变量
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <EEPROM.h>
//
// Your includes follow
//
// BEGIN only needed if using UDP:
#include <WiFiUdp.h>
WiFiUDP Udp;
#define UDPPORT 11011
#define UDPMULTICASTIP IPAddress(239,0,0,10)
// END only needed if using UDP
#define HOSTNAME "test"
char cfgssid[256];
char cfgpassword[256];
//
// Your globals follow
//
上面有三个必要的头文件。之后,您可以插入您自己的包含文件。然后,我们有一个可选的UDP部分。只有在使用UDP时才需要它。
之后,我们定义了将要发布的hostname,并且我们有SSID和网络密码的缓冲区。
setup()
方法非常复杂。您可能需要为自己的代码分解它。我们将分部分介绍它
void setup() {
// Initialize the serial port
Serial.begin(115200);
// commit 512 bytes of ESP8266 flash
// this step actually loads the content (512 bytes) of flash into
// a 512-byte-array cache in RAM
EEPROM.begin(512);
int i = 0;
// Read the settings
for(i = 0;i<256;++i) {
cfgssid[i]=EEPROM.read(i);
if(!cfgssid[i])
break;
}
cfgssid[i]=0;
i=0;
for(i = 0;i<256;++i) {
cfgpassword[i]=(char)EEPROM.read(i+256);
if(!cfgpassword[i])
break;
}
cfgpassword[i]=0;
...
上面,我们初始化EEPROM库并分配512字节的存储空间。然后,我们读取我们的SSID - 一个小于256个字符的字符串。接下来,我们在偏移量256处读取我们的密码,但其他方面几乎相同。
现在进入WiFi处理,这有点复杂
// Initialize the WiFi and connect
WiFi.mode(WIFI_STA);
bool done = false;
while (!done) {
// Connect to Wi-Fi
WiFi.begin(cfgssid, cfgpassword);
Serial.print("Connecting to WiFi");
// try this for 10 seconds, then check for WPS
for (int i = 0; i < 20 && WL_CONNECTED != WiFi.status(); ++i) {
Serial.print(".");
delay(500);
}
Serial.println("");
// If we're not connected, wait for a WPS signal
if (WL_CONNECTED != WiFi.status()) {
Serial.print("Connection to ");
Serial.print(cfgssid);
Serial.println(" failed. Entering auto-config mode");
Serial.println("Press the WPS button on your router");
bool ret = WiFi.beginWPSConfig();
if (ret) {
String newSSID = WiFi.SSID();
if (0 < newSSID.length()) {
Serial.println("Auto-configuration successful. Saving.");
strcpy(cfgssid, newSSID.c_str());
strcpy(cfgpassword, WiFi.psk().c_str());
int c = strlen(cfgssid);
for(int i = 0;i<c;++i)
EEPROM.write(i,cfgssid[i]);
EEPROM.write(c,0);
c = strlen(cfgpassword);
for(int i = 0;i<c;++i)
EEPROM.write(i+256,cfgpassword[i]);
EEPROM.write(c+256,0);
EEPROM.end();
Serial.println("Restarting...");
ESP.restart();
} else {
ret = false;
}
}
} else
done = true;
// if we didn't get connected, loop
}
// Display the status
Serial.println("");
Serial.print("Connected to ");
Serial.println(WiFi.SSID());
Serial.print("Host name: ");
Serial.print(HOSTNAME);
Serial.println(".local");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
...
这个逻辑有点笨拙。我们要做的第一件事是连接。如果我们在10秒内无法连接,我们开始寻找来自路由器的WPS信号。如果超时,我们会回到尝试连接,并且循环重复。如果我们设法通过WPS连接,那么我们将新的SSID和密码写入闪存并重新启动设备。重新启动比尝试让WiFi设备重新连接更可靠。
现在一个简单但重要的步骤
// start the multicast DNS publishing
if (MDNS.begin(HOSTNAME)) {
Serial.println("MDNS responder started");
}
...
上面,我们使用我们的主机名初始化mDNS响应器。它的工作方式是,如果 HOSTNAME
是 "test",那么域名将是 "test.local"。
只有在使用UDP时才需要执行以下操作。之后是您自己的设置代码。
// initialize the UDP
// only needed if using UDP:
Udp.begin(UDPPORT);
//
// Your setup code follows
//
...
最后,我们进入我们的 loop()
方法。首先,如果我们的WiFi连接断开,我们尝试重新连接,如果无法重新连接,我们将重新启动。我们还会通过调用 MDNS.update() 定期刷新我们的mDNS注册。该代码下方的所有内容都是可选的,并作为示例提供,每四分之一秒多播一次 "Hello World!"
void loop() {
// reconnect to the WiFi if we
// got disconnected
if (WL_CONNECTED != WiFi.status()) {
// Connect to Wi-Fi
WiFi.begin(cfgssid, cfgpassword);
Serial.print("Connecting to WiFi");
for (int i = 0; i < 20 && WiFi.status() != WL_CONNECTED; ++i) {
Serial.print(".");
delay(500);
}
if (WL_CONNECTED != WiFi.status()) {
Serial.println("Could not reconnect. Restarting.");
ESP.restart();
}
}
// update the DNS information
MDNS.update();
// BEGIN only applicable if using UDP:
Udp.beginPacketMulticast(UDPMULTICASTIP, UDPPORT, WiFi.localIP());
Udp.print("Hello World!");
Udp.endPacket();
// END only applicable if using UDP
//
// Your code goes here
//
// we only want to do this every
// quarter second for the example
delay(250);
}
关注点
ESP-01 模块非常便宜,我遇到过一些闪存无法正常工作的问题。
历史
- 2020年11月5日 - 初始提交