ESP32 BLE接近检测:基于RSSI信号强度实现智能设备感知与自动化触发
1. 项目概述与核心价值
几年前,当我第一次尝试用ESP32做一个简单的门磁报警器时,我就在想,能不能把检测的对象从物理开关换成更“智能”的东西,比如我手腕上的那块智能手表。这个想法源于一个很实际的需求:我经常在书房工作时,手机调成静音,结果错过重要电话。如果手表靠近电脑时,能有一个明显的提示就好了。这就是今天要分享的“基于ESP32的BLE智能手表检测器”项目的由来。它本质上是一个基于蓝牙低功耗信号强度的接近检测器,核心逻辑是:当ESP32扫描到你的智能手表的BLE广播信号,并且信号强度(RSSI)达到预设的“足够近”的阈值时,就触发一个蜂鸣器发出提示音,同时点亮板载LED。
这个项目的价值远不止一个“手表探测器”。它为你打开了一扇门,让你理解如何让微控制器“感知”另一个智能设备的到来与离去。掌握了这套方法,你可以轻松地将触发条件从“手表靠近”替换成“手机回家”、“智能钥匙扣在范围内”或“特定的蓝牙信标出现”。而执行动作也可以从蜂鸣器扩展为控制继电器打开台灯、启动电脑、甚至发送一条网络通知。对于物联网爱好者和智能家居DIY玩家来说,这是一个绝佳的入门实践,它串联了无线通信、信号处理和硬件控制这几个关键环节。无论你是想为你的工作台增加一点自动化魔法,还是想深入学习ESP32的BLE功能,这个项目都能提供扎实的、可复现的动手经验。
2. 核心硬件与软件环境搭建
2.1 硬件清单与选型解析
工欲善其事,必先利其器。我们先来清点并理解每一件硬件的作用。
ESP32开发板(核心):这是项目的大脑。我强烈推荐选择带有内置USB转串口芯片的型号,如ESP32 DevKitC V4或NodeMCU-32S。它们省去了外接下载器的麻烦,对新手极其友好。ESP32之所以是首选,是因为它原生双模蓝牙(经典和低功耗),且性能强大、价格亲民,社区支持完善。
有源蜂鸣器(执行器):注意,这里必须使用有源蜂鸣器。它与无源蜂鸣器的区别在于:有源蜂鸣器内部自带振荡电路,通电即响,频率固定;无源蜂鸣器则类似一个喇叭,需要外部输入特定频率的方波才能发声。本项目使用
EasyBuzzer库,它主要通过控制引脚高低电平的持续时间来工作,更适合驱动有源蜂鸣器。购买时,选择工作电压为3.3V或5V的均可,ESP32的IO口输出3.3V,驱动3.3V蜂鸣器更稳妥。面包板与杜邦线(连接器):用于快速搭建和测试电路,无需焊接。准备若干公对公杜邦线即可。
智能手表/手机(被检测设备):任何支持BLE广播的设备都可以作为被检测目标。智能手表、健身手环、智能手机是最常见的选择。你需要从中获取其蓝牙MAC地址。
注意:部分新款苹果设备(iPhone、Apple Watch)为了隐私保护,会使用随机MAC地址进行广播,这会导致我们无法通过固定MAC地址进行可靠过滤。本项目更适用于安卓设备、或已关闭随机MAC地址功能的苹果设备(通常在开发者选项里,且不推荐长期关闭)。
2.2 软件环境配置详解
软件环境是项目流畅进行的基础,一步错可能导致后续步步维艰。
2.2.1 Arduino IDE的安装与ESP32支持
首先,从Arduino官网下载并安装最新版Arduino IDE。安装完成后,打开IDE,进入“文件”->“首选项”。在“附加开发板管理器网址”中,填入以下网址:https://espressif.github.io/arduino-esp32/package_esp32_index.json(如果已有其他网址,用逗号隔开即可)。这一步是告诉Arduino IDE去哪里寻找ESP32的开发板支持包。
接着,打开“工具”->“开发板”->“开发板管理器”。在搜索框中输入“esp32”,找到由Espressif Systems提供的“ESP32”开发板包,点击安装。这个过程可能需要几分钟,取决于你的网络速度。
2.2.2 解决“Sketch Too Big”编译错误
这是ESP32项目开发中一个经典的坑。随着代码和库文件的增加,你可能会遇到编译错误,提示程序空间不足。这通常是因为Arduino IDE默认的“分区方案”不适合较大的项目。
解决方法:在Arduino IDE中,选择你的ESP32开发板后,在“工具”菜单下找到“Partition Scheme”(分区方案)选项。将其从默认的“Default”更改为“Huge APP (3MB No OTA/1MB SPIFFS)”。这个方案为程序代码分配了更大的空间(3MB),牺牲了OTA升级和文件系统的部分空间,对于本项目和大多数实验项目来说是完全足够的。
2.2.3 关键库的安装与配置
本项目需要两个核心库:
- ESP32 BLE Arduino:这是由Espressif官方维护的库,提供了ESP32蓝牙功能的底层API。它通常随ESP32开发板包一起安装。你可以在“项目”->“加载库”->“管理库”中搜索“ESP32 BLE Arduino”确认。
- EasyBuzzer:这是一个简化蜂鸣器控制的第三方库。我们需要手动安装它。
- 访问EasyBuzzer的GitHub仓库(通常搜索“EasyBuzzer Arduino”即可找到),下载ZIP文件。
- 在Arduino IDE中,点击“项目”->“加载库”->“添加.ZIP库…”,选择你刚下载的ZIP文件。
库文件的关键修改:根据原始资料,我们需要修改EasyBuzzer库的一个默认配置。找到你的Arduino库安装目录(Windows通常在C:\Users\[你的用户名]\Documents\Arduino\libraries\),进入EasyBuzzer库文件夹下的src子文件夹,找到Config.h文件。用文本编辑器打开它,找到这一行:#define DEFAULT_PIN 4将其修改为:#define DEFAULT_PIN 13这是因为我们计划将蜂鸣器连接在ESP32的GPIO13引脚上。这个修改是为了让库的默认引脚与我们实际硬件连接保持一致,方便测试。
2.2.4 获取目标设备的MAC地址
我们需要一个工具来“看到”周围BLE设备的广播信息,并获取其MAC地址。在安卓手机上,我强烈推荐使用nRF Connect这款应用(由Nordic Semiconductor开发,在应用商店即可下载)。它功能强大且免费。
操作流程:
- 打开手机蓝牙。
- 打开nRF Connect应用,点击右上角的“SCAN”按钮。
- 在设备列表中,找到你的智能手表或手环(通常以设备名称为标识,如“Mi Band 6”、“Galaxy Watch”)。
- 点击该设备条目,查看详细信息。其MAC地址(一个类似于
E0:A1:07:B7:0B:95的字符串)会清晰地显示出来。请完整地记录下来。
3. 电路连接与硬件原理
硬件连接非常简单,但理解其背后的原理能让你在调试时事半功倍。
3.1 物理连接示意图
请按照以下方式连接:
- 蜂鸣器正极(+)->ESP32的GPIO13引脚。
- 蜂鸣器负极(-)->ESP32的任意一个GND(接地)引脚。
- ESP32的板载LED(通常连接在GPIO2上)在代码中已定义,无需额外接线,它会根据检测状态自动亮灭。
实操心得:在给ESP32通电进行连接操作前,务必断开USB数据线。连接好所有线路后,再插上USB线。这可以避免因误接导致的短路风险,保护你的开发板。对于有源蜂鸣器,正负极接反通常不会损坏它,但会导致不发声,检查时请留意。
3.2 核心硬件工作原理浅析
- ESP32的BLE扫描机制:ESP32在代码中扮演一个“扫描者”的角色。它周期性地开启蓝牙射频接收器,监听特定无线电频段(2.4GHz ISM波段)上的广播数据包。所有BLE设备(如你的手表)都会间歇性地向外广播这些包含自身信息(如设备名、服务UUID、MAC地址、信号强度等)的小数据包。ESP32捕获到这些包后,会通过
BLEAdvertisedDeviceCallbacks回调函数通知我们的程序。 - RSSI(接收信号强度指示)的关键作用:RSSI值是一个负数,单位是dBm。它直观地反映了信号强弱。距离越近,障碍越少,RSSI值就越大(即负得越少)。例如,-40 dBm比-80 dBm的信号强得多。本项目正是利用RSSI值来判断设备是否“足够近”。代码中的
if (Device.getRSSI() > -85)就是一个阈值判断,意思是“如果信号强度大于-85dBm(即比-85dBm强),则认为设备在范围内”。 - GPIO驱动蜂鸣器:GPIO13引脚被设置为输出模式。当检测到目标设备时,代码会调用
EasyBuzzer.beep(...)函数。这个函数内部会以我们设定的频率和间隔,循环地将GPIO13引脚置为高电平(3.3V)和低电平(0V)。对于有源蜂鸣器,高电平使其内部电路导通发声,低电平则停止。通过精确控制高、低电平的持续时间(onDuration,offDuration),我们就能制造出不同节奏的“嘀嘀”声。
4. 代码深度解析与定制化修改
原项目提供的代码是一个很好的起点,但其中有些细节和潜在问题需要我们深入理解并优化。下面我将逐段拆解,并提供增强版的代码思路。
4.1 库文件引入与全局变量定义
#include "BLEDevice.h" #include "EasyBuzzer.h" // --- 蜂鸣器参数配置 --- unsigned int frequency = 1000; // 频率 (Hz),对有源蜂鸣器无效,但需保留参数 unsigned int onDuration = 50; // 单次“嘀”声的持续时间 (ms) unsigned int offDuration = 100; // 两次“嘀”声之间的间隔时间 (ms) unsigned int beeps = 2; // 每次触发时,连续“嘀”的次数 unsigned int pauseDuration = 500; // 连续“嘀”完一组后的暂停时间 (ms) unsigned int cycles = 10; // 重复上述“组”的次数 // --- 硬件引脚定义 --- int LED = 2; // ESP32板载LED通常接在GPIO2 int BUZZER_PIN = 13; // 明确蜂鸣器引脚,增强可读性 // --- BLE相关变量 --- static BLEAddress *pServerAddress; BLEScan* pBLEScan; BLEClient* pClient; bool deviceFound = false; // --- 状态标志 --- bool LEDoff = false; // 用于记录LED状态,原代码命名易混淆,实际表示“LED该亮” // --- 核心:已知设备MAC地址列表 --- String knownAddresses[] = {"e0:a1:07:b7:0b:95"}; // 【必须修改】替换为你的设备MAC修改与解析:
- 我将蜂鸣器引脚单独定义为
BUZZER_PIN,虽然EasyBuzzer库会使用我们修改后的默认引脚13,但显式定义能让代码意图更清晰。 frequency参数对于有源蜂鸣器是无效的,因为它只能发出固定频率的声音。但这个参数必须保留,因为它是EasyBuzzer.beep()函数签名的一部分。knownAddresses是一个字符串数组。你可以在这里添加多个MAC地址,让ESP32同时检测多个设备。例如:String knownAddresses[] = {"MAC1", "MAC2", "MAC3"};。(sizeof(knownAddresses) / sizeof(knownAddresses[0]))这段代码会自动计算数组的长度,这样添加或删除地址时,无需手动修改循环次数。
4.2 回调函数:BLE扫描的核心逻辑
这是整个项目的“大脑”,决定了ESP32如何识别你的设备。
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { void onResult(BLEAdvertisedDevice advertisedDevice) { // 参数名更清晰 // 获取扫描到的设备地址 pServerAddress = new BLEAddress(advertisedDevice.getAddress()); // 调试:打印所有扫描到的设备(可选,打开后会刷屏) // Serial.print("Found: "); // Serial.println(advertisedDevice.toString().c_str()); bool isKnownDevice = false; // 遍历已知地址列表,进行匹配 for (int i = 0; i < (sizeof(knownAddresses) / sizeof(knownAddresses[0])); i++) { // 比较扫描到的地址与已知地址(转换为大写,避免大小写问题) if (strcasecmp(pServerAddress->toString().c_str(), knownAddresses[i].c_str()) == 0) { isKnownDevice = true; break; // 找到匹配项,立即跳出循环 } } if (isKnownDevice) { Serial.println("[INFO] Target device detected!"); Serial.print("[INFO] RSSI: "); Serial.println(advertisedDevice.getRSSI()); // 关键判断:根据RSSI设定触发距离 // RSSI > -60: 非常近 (约1米内) // RSSI > -70: 比较近 (约3-5米) // RSSI > -85: 中等距离 (约10米,隔墙效果会下降) int rssiThreshold = -70; // 【可调整】根据你的环境测试最佳值 if (advertisedDevice.getRSSI() > rssiThreshold) { deviceFound = true; Serial.println("[INFO] Device is WITHIN range. Triggering action."); } else { deviceFound = false; Serial.println("[INFO] Device is OUT OF range."); } // 停止本次扫描,准备执行动作或下一次扫描 advertisedDevice.getScan()->stop(); } } };重要优化与解析:
- 使用
strcasecmp替代strcmp:原代码使用strcmp进行字符串比较,这是区分大小写的。但MAC地址的字符串表示有时可能大小写不一致。strcasecmp进行不区分大小写的比较,更加健壮。 - 引入
break语句:一旦在已知列表中匹配到设备,立即用break跳出for循环,避免无意义的后续比较,提升效率。 - 可配置的RSSI阈值:我将阈值
-85定义为一个变量rssiThreshold。你必须根据实际环境测试并调整这个值。测试方法:上传代码后,打开串口监视器(波特率115200),拿着你的手表在不同距离移动,观察打印出来的RSSI值。确定一个你认为是“有效靠近”的数值(例如,走到桌子旁时RSSI约为-65,那就设-70)。 - 详细的串口输出:我增加了带标签的串口打印(
[INFO]),便于在众多日志中快速定位信息。
4.3 Setup()与Loop()函数流程
void setup() { Serial.begin(115200); Serial.println("\n[BOOT] ESP32 BLE Detector Initializing..."); // 初始化硬件引脚 pinMode(LED, OUTPUT); digitalWrite(LED, LOW); // 启动时LED熄灭 // EasyBuzzer库会自动初始化其默认引脚(我们已修改为13) // 初始化BLE BLEDevice::init(""); // 设备名称为空,因为我们只扫描不广播 pClient = BLEDevice::createClient(); pBLEScan = BLEDevice::getScan(); pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); pBLEScan->setActiveScan(true); // 主动扫描,获取更多信息但更耗电 // pBLEScan->setInterval(100); // 可调整:扫描间隔(ms) // pBLEScan->setWindow(99); // 可调整:扫描窗口(ms),应小于等于间隔 Serial.println("[BOOT] Initialization complete. Starting scan loop..."); } void performScan() { // 将扫描逻辑封装成函数,比原名`Bluetooth`更贴切 Serial.println("[SCAN] --- Starting new BLE scan ---"); deviceFound = false; // 重置发现标志 // 开始扫描,持续5秒 BLEScanResults scanResults = pBLEScan->start(5, false); // 第二个参数false表示非阻塞式扫描(实际仍是阻塞,但API如此) // 扫描结束后,根据结果执行动作 if (deviceFound) { Serial.println("[ACTION] Triggering BUZZER & LED"); digitalWrite(LED, HIGH); EasyBuzzer.beep(frequency, onDuration, offDuration, beeps, pauseDuration, cycles); // 蜂鸣器会按照预设模式鸣叫,这是一个非阻塞调用 } else { Serial.println("[ACTION] No target in range. Turning off LED."); EasyBuzzer.stopBeep(); // 确保蜂鸣器停止 digitalWrite(LED, LOW); } // 短暂延迟,避免扫描过于频繁 delay(2000); // 【可调整】扫描周期 } void loop() { performScan(); // 执行一次完整的扫描-判断-动作流程 EasyBuzzer.update(); // 必须持续调用,以驱动蜂鸣器发出声音 // 其他非阻塞任务可以放在这里 }流程详解与优化:
setup()函数负责一次性初始化。setActiveScan(true)启用主动扫描,这会向扫描到的设备发送扫描请求,以获取更多的响应数据(如设备名),功耗稍高但信息更全。如果只关心MAC和RSSI,可以设为false以省电。- 我将主要的扫描和触发逻辑封装进
performScan()函数,使loop()结构更清晰。 pBLEScan->start(5)表示每次扫描持续5秒。这个时间越长,发现设备的概率越高,但每次检测的周期也越长。你需要根据设备广播间隔和应用场景权衡。智能手表广播通常比较频繁,2-3秒也足够。EasyBuzzer.update()是库函数要求的,必须放在loop()中频繁调用,它负责在后台更新蜂鸣器的状态,实现非阻塞的鸣叫效果。如果没有它,蜂鸣器将不会响。- 扫描结束后,我添加了一个
delay(2000)。这意味着一次完整的“扫描-执行”周期大约是“5秒扫描 + 2秒延迟 = 7秒”。你可以调整这个值来控制检测的灵敏度(频率)。
5. 高级调试技巧与实战问题排查
即使代码和连接都正确,在实际环境中你仍可能遇到各种问题。下面是我在多次实践中总结的排查清单。
5.1 常见问题速查表
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 上传代码后,ESP32无任何反应 | 1. 电源问题 2. 板子型号选择错误 3. 串口驱动问题 | 1. 检查USB线是否连接牢固,尝试更换USB口或数据线。 2. 在Arduino IDE的“工具”->“开发板”中,确认选择了正确的ESP32型号(如ESP32 Dev Module)。 3. 检查设备管理器中是否有未识别的端口,安装对应的CP210x或CH340驱动。 |
| 串口监视器看不到输出 | 1. 波特率不匹配 2. 选错串口 3. 代码中 Serial.begin()被禁用 | 1. 确保串口监视器右下角的波特率设置为115200。2. 在“工具”->“端口”中,选择正确的COM口(拔插USB线观察哪个端口出现/消失)。 3. 确认代码中 Serial.begin(115200);语句存在且未被注释。 |
| 串口有输出,但始终找不到设备 | 1. MAC地址错误 2. 设备未开启蓝牙或BLE广播 3. RSSI阈值设置过于苛刻 4. 扫描时间太短 | 1.【最关键】用nRF Connect重新确认MAC地址,检查代码中地址格式是否正确(冒号分隔,字母大写)。 2. 确保手表蓝牙已开,且未处于“飞行模式”或“剧院模式”(可能关闭广播)。 3. 先将阈值 rssiThreshold调到一个非常宽松的值,如-100,看是否能发现设备。4. 将 pBLEScan->start(5)中的扫描时间增加到10秒。 |
| 能发现设备,但从不触发蜂鸣器 | 1. RSSI阈值太高 2. 蜂鸣器接线错误或损坏 3. EasyBuzzer库未正确安装或修改 | 1. 查看串口输出的RSSI值,调整rssiThreshold低于该值。例如,设备在1米处RSSI为-65,则阈值应设为-66或更低。2. 检查蜂鸣器正负极是否接反,尝试将蜂鸣器直接连接到3.3V和GND,看是否能响。 3. 确认 EasyBuzzer库的Config.h文件中的DEFAULT_PIN已修改为13,并重启Arduino IDE。 |
| 蜂鸣器一直响,或触发后不停止 | 1.deviceFound状态逻辑错误2. EasyBuzzer.update()未调用3. 扫描未正常停止 | 1. 检查if (deviceFound)的逻辑,确保在设备离开后deviceFound被重置为false。2. 确保 loop()函数中调用了EasyBuzzer.update()。3. 在回调函数中,确认调用了 advertisedDevice.getScan()->stop()。 |
| 检测延迟高,反应慢 | 1. 扫描周期(start参数)太长2. 扫描后延迟( delay)太长 | 1. 减少pBLEScan->start()的持续时间,例如从5秒改为2秒。2. 减少 performScan()函数末尾的delay()时间。注意:周期太短可能导致功耗上升和CPU占用率高。 |
5.2 串口调试信息优化
为了更高效地调试,我建议在代码中添加不同等级的日志输出,并可以通过一个开关来控制。
// 在文件开头定义调试级别 #define DEBUG_LEVEL 2 // 0:无输出, 1:仅关键信息, 2:详细信息 #if DEBUG_LEVEL >= 1 #define LOG_I(x) Serial.println(x) #else #define LOG_I(x) #endif #if DEBUG_LEVEL >= 2 #define LOG_D(x) Serial.println(x) #else #define LOG_D(x) #endif // 在回调函数中使用 class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { void onResult(BLEAdvertisedDevice advertisedDevice) { pServerAddress = new BLEAddress(advertisedDevice.getAddress()); LOG_D("[DEBUG] Scanned: " + String(advertisedDevice.toString().c_str())); bool isKnownDevice = false; for (int i = 0; i < (sizeof(knownAddresses) / sizeof(knownAddresses[0])); i++) { if (strcasecmp(pServerAddress->toString().c_str(), knownAddresses[i].c_str()) == 0) { isKnownDevice = true; LOG_I("[INFO] MAC Matched: " + String(knownAddresses[i])); break; } } // ... 后续逻辑 } };这样,在项目稳定后,你可以将DEBUG_LEVEL设为1或0,减少串口输出的干扰。
6. 项目扩展与进阶思路
这个基础项目就像一个乐高底座,你可以在此基础上搭建出各种有趣的应用。
6.1 硬件扩展:从蜂鸣器到继电器控制
将蜂鸣器替换为一个继电器模块,你就能控制交流电器。这是迈向智能家居的关键一步。
连接方式:
- ESP32的GPIO13 -> 继电器模块的
IN(或SIG)引脚。 - ESP32的5V引脚 -> 继电器模块的
VCC引脚。 - ESP32的GND引脚 -> 继电器模块的
GND引脚。 - 将你家用电器的电源线切断,一端接继电器模块的
COM(公共端),另一端接NO(常开端)。这样,当GPIO13输出高电平时,继电器吸合,电路导通,电器通电。
代码修改: 只需将触发动作部分的代码从控制蜂鸣器改为控制继电器引脚。
#define RELAY_PIN 13 // 假设继电器接在13脚 void setup() { pinMode(RELAY_PIN, OUTPUT); digitalWrite(RELAY_PIN, LOW); // 初始状态为断开 // ... 其他初始化 } void performScan() { // ... 扫描逻辑 if (deviceFound) { LOG_I("[ACTION] Turning ON Relay"); digitalWrite(RELAY_PIN, HIGH); // 吸合继电器 digitalWrite(LED, HIGH); } else { LOG_I("[ACTION] Turning OFF Relay"); digitalWrite(RELAY_PIN, LOW); // 断开继电器 digitalWrite(LED, LOW); } // ... 后续逻辑 }安全警告:操作220V交流电有生命危险!务必确保在完全断电的情况下进行接线,所有裸露的导线部分必须用绝缘胶带包裹好。如果你对强电不熟悉,建议先使用低压直流电器(如LED灯带、小风扇)进行练习。
6.2 软件优化:引入状态机与防抖机制
当前代码在设备处于临界距离时,可能会因为RSSI值在阈值上下波动,导致蜂鸣器频繁开关,形成“抖动”。引入一个简单的状态机和时间防抖可以解决这个问题。
// 新增全局变量 enum DetectorState { STATE_AWAY, STATE_NEAR }; DetectorState currentState = STATE_AWAY; unsigned long lastTriggerTime = 0; const unsigned long DEBOUNCE_DELAY = 3000; // 防抖时间,3秒内状态不变化 void performScan() { // ... 扫描逻辑,最终得到 deviceFound 布尔值 unsigned long currentTime = millis(); if (deviceFound && currentState == STATE_AWAY) { // 从未在范围内变为在范围内 if (currentTime - lastTriggerTime > DEBOUNCE_DELAY) { LOG_I("[STATE] Transition: AWAY -> NEAR"); currentState = STATE_NEAR; lastTriggerTime = currentTime; // 执行触发动作 digitalWrite(LED, HIGH); EasyBuzzer.beep(...); } } else if (!deviceFound && currentState == STATE_NEAR) { // 从在范围内变为不在范围内 if (currentTime - lastTriggerTime > DEBOUNCE_DELAY) { LOG_I("[STATE] Transition: NEAR -> AWAY"); currentState = STATE_AWAY; lastTriggerTime = currentTime; // 执行关闭动作 digitalWrite(LED, LOW); EasyBuzzer.stopBeep(); } } // 如果状态未发生变化,则什么也不做 }这个机制确保了只有当设备稳定地进入或离开范围超过3秒后,才会触发状态切换和执行相应动作,有效避免了抖动。
6.3 网络集成:添加Wi-Fi与远程通知
ESP32具备Wi-Fi功能,可以轻松将检测事件发送到互联网。
思路:
- 连接本地Wi-Fi:在
setup()中加入Wi-Fi连接代码。 - 触发网络请求:当检测到设备时,除了本地蜂鸣,还可以使用HTTP客户端或MQTT客户端向一个网络服务器发送请求。
- 实现效果:你可以收到手机推送通知(通过IFTTT、Bark、Server酱等服务),或者在家庭自动化平台(如Home Assistant)中创建一个传感器实体,从而触发更复杂的自动化流程。
例如,使用HTTP GET请求发送到IFTTT的Webhooks:
#include <WiFi.h> #include <HTTPClient.h> const char* ssid = "你的Wi-Fi名称"; const char* password = "你的Wi-Fi密码"; const char* iftttURL = "https://maker.ifttt.com/trigger/watch_detected/json/with/key/YOUR_KEY"; void connectToWiFi() { WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("WiFi Connected!"); } void sendNotification() { if (WiFi.status() == WL_CONNECTED) { HTTPClient http; http.begin(iftttURL); int httpCode = http.GET(); if (httpCode > 0) { Serial.printf("[HTTP] Notification sent, code: %d\n", httpCode); } http.end(); } } // 然后在 deviceFound 为真时调用 sendNotification();这个小小的改动,瞬间将你的本地探测器接入了广阔的物联网世界。
从我自己的使用体验来看,这个项目的稳定性很大程度上取决于RSSI阈值的校准和环境的蓝牙干扰程度。在办公室这种蓝牙设备密集的环境,阈值可能需要设得更高(如-60)来避免误触发。而在家里,-70左右通常就能很好地工作。另外,将ESP32的天线部分(板载PCB天线)朝向预计设备来的方向,也能稍微改善信号接收。最后,别忘了给它配一个好看的壳子,毕竟一个裸露着电路板和跳线的“探测器”,可算不上是合格的智能家居产品。
