
做智能家居我绕了一大圈最后还是回到ESP32上。这块板子自带WiFi和BLE双核240MHz几十块钱GPIO多到用不完我这两年用它陆续折腾过温度采集、灯光控制、门磁报警、窗帘电机最后干脆把家里的杂牌设备统一到一套WiFiBLE联动方案里。这篇文章不按官方文档的口气写我直接把从选型、环境搭建、配网、传感器联动到App控制、调优避坑的完整经验摊开讲。ESP32做智能家居最大的优势不是单点控制某个设备而是用WiFi打通局域网和云端的数据通道用BLE处理近场低功耗的传感器节点两种协议互补之后网关、子设备、App三端就能串成一张网。想用一块板子入门智能家居的开发者或者被各种设备App不互通折腾到崩溃的家居爱好者都可以参考这套思路。1. 方案概览为什么选ESP32当智能家居中枢1.1 硬件底子一颗板子能扛多少活ESP32并不是唯一能用的物联网芯片但它的综合性价比确实很难替代。以经典的ESP32-WROOM-32模组为例双核Xtensa LX6跑到240MHz520KB SRAM4MB Flash还集成了2.4GHz WiFi和蓝牙含BLE与Classic。这个配置在智能家居场景里意味着什么简单说单颗芯片既能做需要计算能力的网关节点比如跑Web服务、MQTT客户端、规则引擎又能做低功耗的传感器终端比如深度睡眠、定时唤醒、BLE广播中间态还能同时处理WiFi连接和BLE通信这样的角色跨度在同类芯片里不多见。和几类常见方案对比会更直观。对比ESP8266ESP32多了双核和BLE跑复杂协议栈不卡顿串口和I2C外设也更丰富对比树莓派ESP32的成本和功耗低一个数量级不需要维护操作系统上电就能跑裸机或RTOS适合长期挂墙对比STM32ESP32直接集成WiFi和BLE协议栈省掉了外挂无线模块、AT指令调度的麻烦开发效率高太多。智能家居里最典型的分工是这样WiFi直连设备灯、插座、摄像头负责高带宽和远距离通信BLE节点门磁、温湿度计、按钮负责低功耗和快速唤醒ESP32作为中心节点兼网关把这两类设备的协议汇总后统一对外提供控制接口。我实际做下来的感受是这个组合天然匹配居家环境因为家里既有“需要频繁网络交互”的设备也有“纽扣电池供电、一两个月不换电池”的低功耗传感器两种需求用一块板子同时满足比组合多块不同芯片的方案省心得多。这里有一个常见误区有人觉得ESP32既然有WiFi为啥还要折腾BLE原因很简单不是所有传感器都需要WiFi。WiFi协议栈的功耗和连接开销摆在那里一个纽扣电池供电的门磁如果每秒连一次WiFi电池撑不过一周换成BLE广播加睡眠策略一颗CR2032用大半年很轻松。把两种协议放在同一个芯片上本质上是在功耗、带宽、开发成本和设备数量之间找平衡点这也是“一站式”三个字的核心含义。1.2 整体架构网关、子设备、App三端怎么串整套方案我建议按三级结构设计而不是把所有逻辑都塞进一块板子。第一级是感知层包含温湿度传感器、人体红外、门磁、光照度传感器等它们大多通过BLE广播上报必要时也可以用GPIO直连第二级是控制层也就是ESP32本身负责收集数据、执行联动规则、向外提供控制接口第三级是交互层包括手机App、内嵌Web页面、MQTT消息队列用于用户本地或远程查看和控制。数据流我用一个真实场景说明。假设客厅放了一个ESP32网关门口装着一个BLE门磁沙发旁有一个WiFi智能插座连着落地灯。晚上推门回家门磁检测到开门事件通过BLE广播发给客厅的ESP32ESP32判断当前时间在“夜间模式”区间内于是通过WiFi发送报文给智能插座落地灯自动点亮。整个链路从检测到执行大概几百毫秒全部在局域网内完成不经过云端外网断了也能正常工作。这就是把WiFi和BLE打通之后才有的体验如果门磁是WiFi设备电池扛不住天天开关门如果ESP32不支持BLE门磁事件就必须绕道网关再走WiFi延迟和失败率都会上升。架构设计上我强烈建议把“设备发现”和“设备控制”分离。BLE负责发现和配置WiFi负责控制和数据流。新设备入网时ESP32通过BLE扫描到新节点判断UUID和广播数据后完成配对之后记住该节点的地址与对应控制规则日常运行中BLE节点使用低功耗策略保持通信用户远程控制时通过App走WiFi访问ESP32再由ESP32决定是否通过BLE唤醒对应的近场设备。双协议配合使用而不是各管各的才叫真正的联动。1.3 开发框架选型Arduino、ESP-IDF、MicroPython怎么选很多新手一上来就纠结用什么环境我直接给结论如果目标是快速搭建功能原型和中小型智能家居项目用Arduino框架最省心如果准备做量产产品或者需要精细控制蓝牙协议栈、电源管理建议上ESP-IDF如果主要是验证逻辑和学Python可以用MicroPython但别指望它在复杂中断和高频无线收发的场景下表现很好。Arduino框架的优势是库生态成熟WiFi、BLE、WebServer、传感器驱动几乎都有现成库踩坑文档也最多。ESP-IDF是乐鑫官方框架FreeRTOS真正跑起来事件循环、看门狗、NVS存储等系统级能力完整但学习曲线明显陡峭内存分配、任务优先级这些概念需要时间啃。MicroPython适合做演示解释执行的开销和内存占用对复杂联动规则并不友好。我自己用的是Arduino框架因为至少一半精力要花在传感器接线和联动逻辑上框架越顺手越好。这套方案的代码量不大Arduino完全够用。如果你已经用ROS2做机器人或更复杂的自动化控制后期可以把ESP32作为下位机通过串口桥接出去但那是另一条线了智能家居主场景用Arduino起步最稳。2. 开发环境搭建与烧录配置2.1 Arduino IDE环境搭建与国内镜像源配置ESP32的Arduino开发包默认从GitHub下载国内网络经常下到一半断掉。解决方法是打开Arduino IDE的“首选项”在“附加开发板管理器网址”里填一个ESP32开发板包的索引地址再用国内镜像下载工具链。乐鑫官方维护的索引URL是https://espressif.github.io/arduino-esp32/package_esp32_index.json这个源本身能用于Arduino IDE的开发板管理器。具体操作流程打开Arduino IDE进入“文件 - 首选项 - 附加开发板管理器网址”粘贴JSON地址保存后在“工具 - 开发板 - 开发板管理器”里搜索esp32选择对应版本点击安装。安装完成后选择“ESP32 Dev Module”开发板即可。这里有几个细节值得注意。第一安装过程需要下载编译器、烧录工具、USB-UART驱动等多个组件总共几百MB耗时较长不要中途关掉IDE。第二如果安装完成后仍然找不到开发板多半是JSON地址没被正确写入检查一下URL末尾是否有空格或换行。第三版本装好后尽量不要反复切换因为不同版本间的API有差异切换会触发重新编译还可能引入兼容问题。我建议把开发板包版本固定下来。Arduino框架的API在不同版本间有变化比如BLE部分的include路径、WiFi事件回调写法升级后旧示例可能编不过。固定一个稳定版本比如2.0.x系列并且用Git管理代码出问题时可以快速对比差异。实际开发中“昨天还能编译今天突然报错”的情况大多数是开发板包自动更新引起的。2.2 烧录模式、接线和串口避坑ESP32的烧录方式和传统Arduino不完全一样。开发板一般通过USB转串口芯片CP2102或CH340连接电脑正常模式下上电后可以直接用“烧录”按钮下载程序不需要手动进入下载模式。但如果板子设计特殊或者之前的程序把UART0引脚占用就写不进去了。这时需要手动让芯片进入下载模式把GPIO0拉低按一下EN引脚复位松开EN后保持GPIO0低电平此时芯片进入下载模式串口工具里能看到ROM boot信息。大多数开发板已经集成BOOT和EN按钮所以实际操作就是按住BOOT按一下EN松开BOOT。接线方面最容易踩的坑是串口交叉。很多人以为“TXD接TXDRXD接RXD”实际必须是板子的TXD接外部串口的RXDRXD接TXD。如果用的是一体式开发板USB直接连电脑就不用管如果自己搭最小系统板或者用裸片外接USB转TTL工具务必检查交叉连接。另外ESP32的UART0默认日志输出在GPIO1/GPIO3烧录和调试都会用到如果不想让日志占用这两个脚可以用Serial.begin配置到其他UART口或者代码里重映射引脚。电平匹配也是容易忽略的问题。ESP32全部引脚都是3.3V逻辑很多旧版USB转TTL模块是5V电平直接接上去轻则通信异常重则烧坏GPIO。确认下载器输出3.3V或者带电平转换。供电也要注意ESP32在WiFi发送时的峰值电流能到300mA以上电脑USB口可能不够稳尤其是同时外接传感器时。建议用带单独供电的USB Hub或者给开发板接5V/2A电源适配器否则会出现“烧录一半失败、设备重启”的现象。2.3 串口日志与固件验证拿到新板子的第一件事不是写业务逻辑而是先用一个Blink灯例程验证烧录链路。跑一遍“ESP32 Dev Module”自带的Blink示例按下烧录按钮观察IDE底部日志正常情况下会显示连接芯片信息最后出现“Hash of data verified”。如果日志停在“Connecting....”基本可以确定是两处问题一是串口选错打开设备管理器确认端口号二是烧录时序问题手动进入下载模式再试。还有一个典型报错“A fatal error occurred: Failed to connect to ESP32: Invalid head of packet (0xXX)”。这通常是GPIO0没有拉低或者串口芯片驱动异常。排查时不要一上来就重装驱动先按BOOTEN手动进入下载模式如果仍然失败再用串口调试工具发几个字节测试芯片是否有回复。我的经验是80%的烧录失败是USB线质量太差导致的。很多USB线只能充电不能传数据传输中途掉包就会报超时换一根好点的数据线往往立刻解决。3. WiFi核心功能实现配网、组网与内嵌控制台3.1 配网方式SmartConfig、SoftAP、BLE配网怎么选智能家居设备第一次使用总要告诉它WiFi账号密码这个环节叫配网。ESP32支持三种主流方式各有适用场景。SmartConfig的原理是手机连上路由器后App把SSID和密码编码进UDP广播包发送出去ESP32处于混杂监听模式时抓包并解码整个过程不需要知道设备IP地址。但SmartConfig有个硬性限制手机和ESP32必须在同一个2.4GHz频段网络里如果手机连的是5GHz WiFiESP32收不到广播这点必须在App里做提示。SoftAP方式更传统ESP32先自己开一个热点手机连上这个热点后通过HTTP请求把WiFi凭据交给ESP32然后ESP32关闭热点去连接目标路由器。优点是不依赖路由器环境缺点是配网流程长用户要在两个WiFi之间切换体验稍差。BLE配网是我个人最推荐的方式。ESP32上电后先开启一个带特定Service UUID的BLE广播手机App扫描到设备后建立GATT连接通过特征值把WiFi的SSID和密码写入ESP32写入成功后ESP32自动切换为WiFi模式。整个过程不用切WiFi、不用输入IP体验最接近消费级智能家居产品。BLE配网还能顺便完成设备身份认证比如写入设备Token后续云端或App通信就能识别设备唯一身份。三种方式中BLE配网对用户最友好代码量也只多一点值得优先选。3.2 配网与重连机制的代码实现下面这段是基于Arduino框架的BLE配网核心逻辑用ESP32-BLE-Arduino库先初始化BLE定义一个Service里面放一个接收WiFi信息的Characteristic收到写入请求时解析JSON或简单字符串保存到NVS后尝试连接WiFi。#include BLEDevice.h #include BLEUtils.h #include BLEServer.h #include WiFi.h #include Preferences.h #define SERVICE_UUID 6E400001-B5A3-F393-E0A9-E50E24DCCA9E #define CHAR_UUID_WIFI 6E400002-B5A3-F393-E0A9-E50E24DCCA9E #define CHAR_UUID_STATUS 6E400003-B5A3-F393-E0A9-E50E24DCCA9E Preferences prefs; class WiFiCallbacks : public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string value pCharacteristic-getValue(); if (value.length() 0) { // JSON解析更稳妥简单示例用逗号分隔: ssid,password int comma value.find(,); String ssid value.substr(0, comma).c_str(); String pass value.substr(comma 1).c_str(); prefs.begin(wifi, false); prefs.putString(ssid, ssid); prefs.putString(pass, pass); prefs.end(); pCharacteristic-setValue(OK); pCharacteristic-notify(); WiFi.begin(ssid.c_str(), pass.c_str()); } } };写这段代码时要注意几点。保存凭据用PreferencesNVS而不是全局变量因为设备配网之后可能重启重启后凭据必须还在。解析字符串时一定要考虑特殊字符密码里如果包含逗号会导致分割错位实际项目里最好用ArduinoJson解析JSON消息。WiFi.begin()调用之后App端不要立刻断开BLE最好等ESP32先上报一个“配网成功”的状态特征值再断开连接不然用户会困惑“WiFi填对了App却显示失败”。状态特征值可以用notify方式推给手机也可以让App主动读取我一般把MAC地址和IP地址也放进特征值里配网后App读一次就知道设备IP后续直接跳到局域网控制页面。3.3 内嵌Web控制台让设备不带App也能用除了手机App我强烈建议在ESP32里内嵌一个Web控制页面这样只要浏览器就能控制设备不用给每个家人装App。ESP32作为Web Server资源完全足够AsyncWebServer库是首选它运行在异步TCP任务之上不会因为某个连接慢而阻塞其他请求。页面资源可以存到SPIFFS/LittleFS也可以直接编译进固件用PROGMEM存储。对小型控制面板来说直接内嵌HTML最简单避免分区配置出问题。我的通常做法是根路径“/”返回一个自适应手机屏幕的页面包含当前温湿度、灯光状态、历史曲线用轻量Canvas绘制以及控制按钮。按钮点击后通过fetch发送AJAX请求到/api/relay/on之类的接口后端解析请求后执行GPIO控制并返回JSON状态。这样整个控制链全程局域网内延迟几十毫秒断网也不影响。代码结构上WiFi连接成功后启动WebServer用一个全局结构体保存设备状态WebHandler和业务逻辑通过读写这个状态结构体通信避免一大堆全局变量互相打架。有一个安全提醒不要把携带密码的Web页面直接暴露到公网端口转发下。ESP32的TLS资源和处理能力对公网环境并不宽裕如果确实需要远程访问更稳妥的方式是通过MQTT桥接到云端或者接入Home Assistant由更成熟的平台做远程鉴权。本地方案做好就不缺啥了公网暴露只会引入风险。4. BLE蓝牙核心功能实现GATT服务与手机联动4.1 GATT服务结构怎么设计BLE通信不像串口那样直接传原始字节流它把数据组织成“服务-特征值”的层级结构。一个设备可以有一个或多个Service服务每个Service下包含若干Characteristic特征值每个特征值有对应的UUID、权限读/写/通知和值缓冲区。手机App连接ESP32时先通过UUID发现服务再根据特征值读写数据。设计GATT结构时我建议按功能模块拆开一个Service负责设备信息一个Service负责WiFi配网一个Service负责业务控制不要把所有特征值堆到同一个服务里。这样App端查找逻辑清晰后续扩展新功能也方便。以设备信息Service为例可以包含设备名称、固件版本、MAC地址三个特征值业务控制Service包含一个接收指令的写特征值和一个上报状态的通知特征值。通知特征值由ESP32主动推送给App适合实时状态变化比如温度告警、门磁触发。白名单和加密属于更进阶的玩法BLE协议栈支持配对绑定但家庭内部组网大部分情况用“无配对即可读写入需要简单校验”的模式就够。如果产品要走认证流程再考虑白名单和加密绑定。4.2 手机App端蓝牙控制现成调试工具和自研思路开发初期不需要急着写App先用现成的BLE调试工具把硬件功能跑通比如nRF Connect和LightBlue。这些工具可以扫描设备、查看Service和Characteristic、手动读写数据、开启通知基本能替代初期测试App。我的工作流是先用nRF Connect手动发一条测试指令确认ESP32返回符合预期再封装App端协议。这样定位问题最方便能区分是硬件端逻辑错还是App端收发错。自研App的技术栈很多Flutter的flutter_blue_plus、uni-app的BLE插件、Android原生BLE API都可以。我推荐Flutter一套代码覆盖Android和iOS蓝牙插件基于平台Channel调用原生能力封装比较完善。App端的关键点是权限处理Android 6以上需要动态申请位置权限蓝牙扫描被归类为位置相关权限Android 12以上要申请附近设备扫描/连接权限iOS要在Info.plist里声明蓝牙使用描述。忽略这些权限会在真机调试时遇到扫描始终为空但不报错的诡异情况实际上是系统静默拦截了权限。协议设计上我强烈建议所有BLE报文都带帧头、命令字、长度、数据、校验和。举个例子0xA5 0x01 0x04 0x01 0x00 0x00 0x00 0x10其中0xA5是帧头0x01是控制命令0x04是数据长度后面是具体参数最后是累加校验。BLE默认MTU一般是23字节ATT payload只有20字节数据多了就要分包或者先协商MTU。协商MTU很简单连接后用gatt.requestMtu(247)把MTU提到最大单包能携带的数据量就更大拆包逻辑更简单。实测下来MTU 247对传输传感器日志这类批量数据帮助很大。4.3 WiFi和BLE共存避免互相干扰的实操经验ESP32的WiFi和BLE共用2.4GHz频段和同一套射频前端同时开启时会有信道争用。理想情况下WiFi连接路由器的同时BLE还能保持广播和扫描但实际吞吐量和连接稳定性都会互相影响。我在项目中遇到过两类典型问题一是WiFi吞吐率下降明显二是BLE连接偶尔断开尤其是WiFi持续上传数据时更明显。解决思路主要有几个方向。第一个方向是合理分配BLE广播间隔。如果BLE节点本来就是低频上报比如30秒一次温度广播间隔可以拉长到100ms以上扫描窗口对应缩短把大部分射频时间让给WiFi。如果是手机实时控制连接间隔可以适当增大用延迟换吞吐。第二个方向是任务调度ESP32协议栈会自动协调射频时间但应用层最好不要同时做“大量WiFi HTTP请求高频BLE扫描”把扫描窗口安排在WiFi空闲时段。第三个方向是物理布局ESP32天线区域不要被金属外壳完全罩住天线下方不要铺地铜箔BLE模块和路由器天线尽量保持距离。这些细节看起来不起眼对稳定性影响却是立竿见影的。我第一次把开发板塞进金属接线盒后BLE遥控距离从10米直线掉到3米把外壳换成塑料或开孔才恢复正常。还可以利用ESP32的事件接口在代码层面掌握当前WiFi活动状态。部分SDK版本在menuconfig里提供WiFi/BLE共存配置项。Arduino框架默认参数够日常使用但如果项目对实时性要求很高转ESP-IDF做更细粒度的共存策略更彻底。我的经验是先保证BLE不频繁断连再优化吞吐因为智能家居的BLE数据量通常很小WiFi才是大流量通道。5. 实战温湿度采集、Web面板与设备联动5.1 传感器选型DHT11、DHT22、SHT30怎么选温湿度是智能家居最基础的传感器场景但型号选错会带来一连串问题。DHT11最便宜精度±2℃/±5%RH采样周期1秒适合只做粗略环境监测DHT22精度高一些价格十几块响应稍慢SHT30是I2C接口精度更高、稳定性更好读取时序不用自己抠价格二十几块我优先推荐它。DS18B20是纯温度传感器单总线协议多个传感器可以挂一条总线适合多点测温但没湿度功能。接线很简单SHT30的VCC接3.3VGND接GNDSCL接GPIO22SDA接GPIO21ESP32默认I2C引脚。注意I2C总线上拉电阻一般模块已经内置但如果自制传感器板需要外接4.7kΩ上拉到3.3V否则距离稍长时波形边沿不够陡通信容易出错。DHT系列是单总线数据脚接GPIO库内部处理时序不需要额外上拉也能工作。采集逻辑里最容易被忽略的是传感器上电稳定时间。传感器刚上电的几百毫秒内数据不稳定或者读不到。代码里最好初始化后等1秒再开始采样连续采样之间至少间隔2秒DHT系列尤其明显。很多“读不到数据”的报错并不是接线错而是采样间隔太小传感器来不及更新内部值。5.2 数据上报与本地联动规则数据采集到之后是走WiFi上报还是BLE本地通知取决于数据用途。如果数据只给本地联动用完全不需要上报云端ESP32直接判断温度值并控制继电器就行如果要做历史记录和远程查看可以通过WiFi把数据发给MQTT broker或Home Assistant。我建议把两件事解耦传感器每30秒采集一次数据先存到内存本地规则引擎立刻执行判断同时每5分钟批量上报一次到MQTT减少WiFi连接和功耗压力。本地联动规则实现上不需要引入复杂规则引擎一个状态机加定时器就够了。举一个实际例子温度高于28℃且持续30秒开启风扇低于26℃且持续60秒关闭风扇。持续确认的目的是避免传感器瞬时波动导致继电器频繁启停。代码实现用millis()记录状态变化时间而不是在loop里用delay否则整个系统会被阻塞。核心逻辑类似bool fanState false; unsigned long stableSince 0; float hysteresisHigh 28.0; float hysteresisLow 26.0; void checkClimate() { float t readTemp(); if (t hysteresisHigh !fanState) { if (stableSince 0) stableSince millis(); if (millis() - stableSince 30000) { digitalWrite(FAN_PIN, HIGH); fanState true; stableSince 0; } } else if (t hysteresisLow fanState) { if (stableSince 0) stableSince millis(); if (millis() - stableSince 60000) { digitalWrite(FAN_PIN, LOW); fanState false; stableSince 0; } } else { stableSince 0; } }这段逻辑用滞回比较替代单阈值比较避免设备在临界温度附近反复开关。滞回区间28℃/26℃预留了2℃差实际使用按场景调整。风扇驱动电路用继电器模块或MOS管ESP32 GPIO输出电流只有12mA左右不能直接驱动大电流风扇。继电器模块建议选带光耦隔离的低电平触发版本控制引脚接GPIO模块供电不要和传感器共用同一根细线。5.3 Web面板和设备联动的完整链路把前面几章串起来一条完整链路就出来了ESP32通过BLE连接近场的温湿度节点节点每30秒推送一次数据ESP32把数据写入状态结构体同时更新Web页面接口Web面板上的图表每隔几秒通过AJAX拉取最新温湿度本地规则引擎根据同一份数据决定继电器通断。所有环节都围绕ESP32一个中枢不需要额外云服务这就是“一站式”的真正体现。实际部署时建议先做最小闭环一块ESP32开发板、一个SHT30、一个继电器模块、一个风扇或灯泡。先把Web控制台和温度采集调通再把BLE节点接进来最后加联动规则。每加一块设备就验证一次不要一口气把所有传感器和规则都挂上否则出问题时无从排查。我见过太多人第一步就翻车就是设备堆太多日志刷屏根本分不清是哪路信号出错。Web面板部分可以继续扩展把ESP32当前联网状态、IP地址、固件版本、最近一次BLE节点心跳时间都显示出来。这些信息对调试很有帮助比如我可以在手机上直接看到“最后一个BLE节点5分钟没心跳了”然后判断是节点没电还是广播被卡住省得拿串口线到处跑。往后如果设备数量增多还可以在这个面板里加设备分组、定时策略、场景模式本质都是对状态结构体的增删改查扩展性很好。6. 常见问题排查与长期运行心得6.1 编译和烧录环节的常见问题速查现象可能原因解决办法烧录提示Failed to connectGPIO0未拉低或串口线不合格手动按BOOTEN进入下载模式换合格数据线编译报错library not found开发板包没装完整或依赖库未安装检查开发板管理器版本逐个安装缺失库上传成功但板子没反应供电不足导致反复重启换5V/2A电源检查电源线粗细串口日志乱码波特率不匹配确认Tools和Serial.begin参数一致常见115200烧录问题里还有一个隐藏坑某些ESP32开发板启动时GPIO12如果为高电平Flash会进入电压配置模式导致启动失败。设计或接线时要注意启动阶段GPIO12、GPIO0、GPIO2的电平状态。如果遇到“烧录成功但上电后无输出”先量这几个关键引脚的启动电平。6.2 WiFi连接和BLE扫描的疑难杂症WiFi方面最大的坑是频段。ESP32只支持2.4GHz WiFi手机如果连5GHz频段SmartConfig配网几乎必失败。App端要做好检测和引导或者直接用BLE配网绕开这个问题。另一个坑是路由器开启了“AP隔离”局域网内ESP32和手机互相不可见Web控制台打不开这时需要去路由器后台关掉AP隔离或开启“允许设备互通”。BLE扫描不到设备的原因比较多。常见的有设备已进入深度睡眠没在广播扫描窗口太短错过广播包Android 12以上没授予附近设备权限板载天线被金属件遮挡。排查顺序建议是先用nRF Connect手动扫描如果它也搜不到问题大概率在硬件层如果它能搜到但自己的App搜不到检查权限和扫描参数。BLE广播间隔如果被设置得很长比如2秒扫描设备需要持续扫描更久才能捕获测试时容易误判为“设备离线”。6.3 长期7x24小时运行稳定性经验智能家居设备一旦上线基本是7x24小时连续运行这和开发时跑几分钟验证完全是两回事。我总结了三个让ESP32长期稳定运行的心得。第一处理好内存泄漏和任务堆积。Arduino的loop里如果频繁创建String变量、分配堆内存运行一段时间后内存碎片化会出现莫名重启或功能失灵。建议用固定长度的char数组代替动态String定时任务里不要做重量级打印。我遇到过运行一个月后WiFi连不上的案例最后定位是某条日志打印每秒钟分配一次String内存碎片把WiFi缓冲区挤爆了。第二启用并正确处理看门狗。ESP32的Arduino框架默认启动任务看门狗某个任务卡在死循环超过阈值系统会自动重启。这是保护机制但为了减少无故重启代码里不要用阻塞式delay超过5秒改用异步定时器。对需要长时间等待的传感器读取比如DHT可以分多次等待不要一个delay阻塞整个系统。第三电源质量是硬指标。ESP32的信号发射峰值电流大电源模块纹波大或压降明显时轻则WiFi丢包重则系统频繁重启。实测下来用劣质USB电源做持续WiFi传输板子可能几分钟重启一次。建议选输出电流不低于1A的品牌电源并用尽量短的粗导线连接开发板。细线压降明显传输数据时一掉电压芯片就直接复位。另外外壳和通风不能忽略。ESP32不算太烫但在密闭箱体里持续运行温度可能升到60℃以上Flash擦写异常或WiFi射频性能下降都可能出现。我最后给网关外壳开了散热孔把天线区域镂空BLE遥控距离从3米恢复到10米效果立竿见影。6.4 最后分享一个实用经验补充一个我觉得很实用的小习惯每次发布固件前用标签纸记录“设备位置 固件版本 主要功能 升级时间”贴在设备外壳上。智能家居设备多起来之后哪个房间是哪一版固件、上次升级改了什么很容易忘记。调试时看一眼标签就能快速判断问题是不是“版本太旧导致协议不兼容”。这个习惯成本几乎为零但能省掉大量来回确认的时间。整套方案做下来我的体感是ESP32最大的价值在于把复杂留给了开发者、把简单留给了用户。芯片把WiFi和BLE整合在一起意味着你可以用一块板子承接网关、控制端、传感器节点三种角色联动逻辑不依赖云端断网也能本地工作。如果你想从零做一个自己说了算的智能家居而不是被各家App牵着走这个方向值得踏踏实实投入时间。