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天线朝向预计设备来的方向也能稍微改善信号接收。最后别忘了给它配一个好看的壳子毕竟一个裸露着电路板和跳线的“探测器”可算不上是合格的智能家居产品。