3. Wi-Fi联网基础:ESP32连接路由器,获取IP地址,实现基础TCP通信

好,咱们进入实战环节了。前面两章我们把硬件搭好、开发环境配通,现在该让灯“上网”了。这一章的核心就三件事:连上Wi-Fi、拿到IP、用TCP说上话。

说实话,我最早做物联网项目时,觉得联网不就是调个库函数嘛。结果第一次在现场部署,20个设备死活连不上公司路由器……后来才发现是Wi-Fi信道和DHCP租期的问题。嗯,这些坑咱们今天一并填上。

3.1 ESP32的Wi-Fi工作模式

ESP32的Wi-Fi模块挺灵活,支持三种模式:

模式 角色 典型场景
Station (STA) 客户端 连接家中路由器,上网
Access Point (AP) 热点 手机直连ESP32,做配置
STA + AP 双模式 一边上网,一边提供配置页面

咱们做灯光系统,设备肯定要连家里的路由器。所以今天只用Station模式。AP模式后面讲配网时会用到,先不急。

我的习惯:开发阶段我会把ESP32设为STA+AP双模式。STA连路由器调试,AP留着万一Wi-Fi密码错了,还能连上去看日志。不过产品发布时一定要关掉AP,省电也安全。

3.2 连接Wi-Fi路由器

代码其实不长。但你别小看这几行,我见过有人在这上面折腾一整天。

#include <WiFi.h>

const char* ssid = "你的WiFi名称";
const char* password = "你的WiFi密码";

void setup() {
  Serial.begin(115200);
  
  WiFi.begin(ssid, password);
  Serial.print("正在连接Wi-Fi");
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("\n连接成功!");
  Serial.print("IP地址: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  // 后面再填内容
}

这段代码一跑,串口监视器里就会看到一连串的点在跳动。直到打印出IP地址,说明连上了。

注意:while循环里是阻塞等待。如果Wi-Fi死活连不上,程序就卡死在这里。我曾经有个项目,客户现场的路由器5G频段和2.4G频段共用一个SSID,ESP32只支持2.4G,结果连了5分钟没连上。后来我加了个超时机制,连不上就重启或进入配网模式。

3.3 获取IP地址——DHCP的秘密

连上路由器后,ESP32会自动通过DHCP拿到IP地址。你什么都不用做,WiFi.localIP()就能拿到。

但这里有个坑:IP地址可能会变

为什么?因为DHCP分配的IP是有租期的。默认一般是24小时。租期到了,设备如果还连着,通常会续租同一个IP。但如果设备重启了、或者网络断了重连,路由器可能给你一个新IP。

这对灯光系统来说很要命。你想想看,手机App里存的是旧IP,设备IP变了,App就找不到灯了。

解决办法有三种:

  1. 路由器设置静态DHCP——在路由器后台,把ESP32的MAC地址绑定一个固定IP。这是最推荐的做法。
  2. 代码里设置静态IP——绕过DHCP,直接写死IP。但要注意IP不能和别的设备冲突。
  3. 用mDNS或广播发现——不依赖IP,通过设备名称找。这个后面章节会讲。

静态IP配置示例:

IPAddress local_IP(192, 168, 1, 100);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

if (!WiFi.config(local_IP, gateway, subnet)) {
  Serial.println("静态IP配置失败");
}
WiFi.begin(ssid, password);

我个人习惯是开发阶段用DHCP,部署时用静态IP或路由器绑定。这样调试方便,上线稳定。

3.4 基础TCP通信——让灯听你的话

有了IP地址,设备就在网络里有了“门牌号”。接下来要做的,就是在这个门牌号上开一个“窗口”,让别人能往里递纸条。

这个“窗口”就是TCP Server。手机或电脑作为客户端,连上这个Server,发送指令来控制灯光。

#include <WiFi.h>

WiFiServer server(8888);  // 端口号,随便选,别用已知端口就行

void setup() {
  Serial.begin(115200);
  WiFi.begin("你的WiFi", "你的密码");
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  
  server.begin();
  Serial.println("TCP服务器已启动,端口: 8888");
  Serial.print("设备IP: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  WiFiClient client = server.available();
  
  if (client) {
    Serial.println("有客户端连接了");
    
    while (client.connected()) {
      if (client.available()) {
        String cmd = client.readStringUntil('\n');
        cmd.trim();
        
        Serial.print("收到指令: ");
        Serial.println(cmd);
        
        // 解析指令,控制灯光
        if (cmd == "ON") {
          // 开灯代码
          client.println("灯已打开");
        } else if (cmd == "OFF") {
          // 关灯代码
          client.println("灯已关闭");
        } else {
          client.println("未知指令");
        }
      }
    }
    
    client.stop();
    Serial.println("客户端断开");
  }
}

这段代码启动了一个TCP Server,监听8888端口。手机用TCP调试工具连上来,发"ON"就开灯,发"OFF"就关灯。

避坑指南:我曾经犯过一个错——在loop里用delay()。你想想看,如果程序在delay的时候,客户端发来指令,ESP32是收不到的。所以后来我改用millis()非阻塞定时,或者把指令解析放在中断里。这个后面讲灯光控制时会详细说。

3.5 测试TCP通信

怎么测试?你不需要写一个App。手机上下载一个“TCP调试助手”或者“网络调试助手”就行。

测试步骤:

  1. ESP32上电,串口打印出IP地址,比如192.168.1.100
  2. 手机连同一个Wi-Fi(必须在同一个局域网)
  3. 打开TCP调试助手,选择TCP Client模式
  4. 输入IP: 192.168.1.100,端口: 8888
  5. 点击连接,发送"ON"
  6. 看串口是否打印"收到指令: ON"

如果连不上,先ping一下ESP32的IP。ping不通说明网络没通,检查Wi-Fi连接。ping通了连不上,检查防火墙或者端口号是否被占用。

3.6 本章小结

这一章我们做了三件事:

  • ESP32以Station模式连上Wi-Fi
  • 通过DHCP或静态配置拿到IP地址
  • 启动TCP Server,实现基础的指令收发

说白了,现在你的灯已经“上网”了。虽然还只是最原始的TCP通信,但这是后面所有场景联动的基础。下一章我们会把TCP指令和PWM调光结合起来,让灯真正听话地亮起来、暗下去。

嗯,先别急着往下走。我建议你把今天的代码跑通,用手机发几条指令试试。那种“自己写的代码控制了一盏灯”的感觉,真的很爽。