在这篇教程中,将探讨如何为位于森林中央的IoT设备编程,使其能够自动配置并将其传感器数据发布到网络上。这个设备由于其孤立的位置,不适合拥有用户界面,甚至不需要一个按钮。它需要广播传感器的读数给任何监听的设备,并且需要在已知地址上提供一个小型网站。在创建这个设备的过程中,编写了一些代码,用于自动配置ESP8266并将其发布到网络上。本文旨在解释这个过程,并为自己的IoT项目提供实现代码。虽然它是为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。 之后,定义了将发布的主机名,并且有缓冲区用于SSID和网络密码。
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;
// Initialize the WiFi and connect
WiFi.mode(WIFI_STA);
bool done = false;
while (!done) {
WiFi.begin(cfgssid, cfgpassword);
Serial.print("\nConnecting 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("\n");
// If we're not connected, wait for a WPS signal
if (WL_CONNECTED != WiFi.status()) {
Serial.print("\nConnection to ");
Serial.print(cfgssid);
Serial.println(" failed. Entering auto-config mode");
Serial.println("\nPress the WPS button on your router");
bool ret = WiFi.beginWPSConfig();
if (ret) {
String newSSID = WiFi.SSID();
if (0 < newSSID.length()) {
Serial.println("\nAuto-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("\nRestarting...");
ESP.restart();
}
else {
ret = false;
}
}
}
else
done = true;
// if we didn't get connected, loop
}
// Display the status
Serial.println("\n");
Serial.print("\nConnected to ");
Serial.println(WiFi.SSID());
Serial.print("Host name: ");
Serial.print(HOSTNAME);
Serial.println(".local");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// start the multicast DNS publishing
if (MDNS.begin(HOSTNAME)) {
Serial.println("\nMDNS responder started");
}
// initialize the UDP
// only needed if using UDP:
Udp.begin(UDPPORT);
// Your setup code follows
}
在上述代码中,初始化了EEPROM库,并分配了512字节的存储空间。然后,读取SSID - 一个少于256个字符的字符串。接下来,在偏移量256处读取密码,但其他方面几乎相同。
现在继续处理WiFi,这有点复杂:
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("\nConnecting to WiFi");
for (int i = 0; i < 20 && WiFi.status() != WL_CONNECTED; ++i) {
Serial.print(".");
delay(500);
}
if (WL_CONNECTED != WiFi.status()) {
Serial.println("\nCould 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("\nHello 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);
}
逻辑有点笨拙。首先尝试连接。如果在10秒内无法连接,就开始寻找路由器的WPS信号。如果这也超时,回到尝试连接,并且循环重复。如果设法通过WPS连接,那么将新的SSID和密码写入闪存并重新启动设备。重新启动比试图让WiFi设备重新连接更可靠。