1. 项目缘起:一个被忽视的“智能”场景
你有没有想过,当你走进一个房间,墙上的屏幕或者某个角落的显示器,能自动播放一段为你准备的视频?不是那种需要你手动点击播放器,也不是通过复杂的语音指令,而是像感应灯一样,你来了,它就亮起,内容就开始流动。这个想法听起来有点“未来感”,但其实用我们手边最常见的几样东西——一个支持Wi-Fi的旧手机或平板、一个几十块钱的人体感应模块,再加上一点简单的脚本,就能轻松实现。
我最初想做这个,是因为家里的玄关处一直空着一块墙。我想,如果每次家人回家,一开门就能看到一段温馨的家庭视频集锦,或者显示当天的天气和重要提醒,那该多好。市面上当然有成熟的智能家居方案,但要么价格不菲,要么功能臃肿,无法完全自定义我想要的效果。于是,我决定自己动手,用最“土”但最有效的方法,实现一个“基于Wi-Fi的人体感应视频播放”系统。
它的核心逻辑非常简单:人体感应传感器检测到有人移动,通过Wi-Fi网络发送一个信号给播放设备,设备收到信号后,自动开始播放指定的视频内容。人离开一段时间后,视频自动停止或屏幕关闭,等待下一次触发。这个方案的优势在于,硬件成本极低(你可能只需要额外购买一个传感器),软件完全开源可控,并且可以根据你的想象力,扩展到无数场景——比如店铺门口的广告屏、展厅的互动展示、甚至是一个会“打招呼”的智能镜子。
2. 核心硬件选型与连接逻辑
要实现这个系统,我们需要两类硬件:感知端和播放端。它们之间通过Wi-Fi这个“信息高速公路”进行通信。
2.1 感知端:选对传感器,事半功倍
感知端的任务是发现“有人来了”。这里首推人体红外(PIR)传感器,它通过检测人体发出的特定波长红外线变化来工作,价格便宜(10-30元)、功耗低、技术成熟。你可能会在智能家居人体感应器里看到它。
为什么是PIR,而不是摄像头或毫米波雷达?
- 隐私与成本:摄像头涉及隐私,且需要复杂的图像识别处理,成本高。PIR只感应“有温度的生物在移动”,不成像,无隐私担忧。
- 复杂度与功耗:毫米波雷达精度高,能感知静止人体,但价格昂贵(百元以上),驱动复杂。对于“触发播放”这个场景,PIR的“有人移动”检测完全够用,且电路简单,一节电池能工作数月。
- 可靠性:PIR技术非常稳定,误报率在可接受范围内,尤其适用于室内环境。
你需要一个能连接Wi-Fi的微控制器来读取PIR传感器的信号并发送出去。最经典的选择是ESP8266(如NodeMCU开发板)或它的升级版ESP32。它们自带Wi-Fi功能,价格在10-30元之间,用Arduino IDE编程非常简单。
连接示意图:
PIR传感器输出引脚 -> ESP8266的某个数字输入引脚(如D5) ESP8266通过Wi-Fi -> 连接家庭路由器当PIR传感器被触发,输出高电平信号给ESP8266,ESP8266则执行我们写好的程序,通过Wi-Fi发送一条消息。
2.2 播放端:旧设备焕发新生
播放端可以是任何带屏幕、能联网、能运行播放程序的设备。最佳选择是闲置的安卓手机或平板。原因如下:
- 零成本:充分利用旧设备。
- 功能强大:本身具备完整的视频解码能力、扬声器和屏幕。
- 易于编程:可以通过安装一个简单的后台服务App来实现功能。
当然,你也可以使用树莓派(Raspberry Pi)连接显示器,或者一台迷你PC,但这会增加成本和设置复杂度。对于绝大多数家庭和个人场景,旧安卓设备是性价比之王。
2.3 通信协议选择:让设备“说上话”
感知端和播放端都在同一个Wi-Fi网络下,它们需要一种协议来通信。这里有几个备选方案:
MQTT(推荐):这是一个轻量级的“发布-订阅”消息协议。你可以把它想象成一个“公告栏”。ESP8266作为“发布者”,检测到人后,就向一个叫“
home/pir/status”的公告栏贴一张写着“有人”的纸条。安卓设备上的App作为“订阅者”,一直盯着这个“公告栏”,一旦看到新纸条,就触发播放。你需要一个MQTT代理服务器(Broker),可以在同一网络下的另一台电脑(甚至这台安卓设备本身)上安装一个轻量级的Broker,如Mosquitto。- 优点:标准、稳定、支持一对多通信(一个传感器可触发多个播放器),易于扩展。
- 缺点:需要额外搭建Broker。
HTTP请求:ESP8266检测到人后,直接向安卓设备上运行的一个简易Web服务器发送一个HTTP GET请求,例如
http://192.168.1.100:8080/trigger。- 优点:实现简单,无需中间服务器。
- 缺点:需要知道播放端设备的固定IP地址,且播放端需要常驻一个HTTP服务。
UDP广播:ESP8266向局域网内广播一条特定的UDP消息,播放端监听该端口,收到消息即触发。
- 优点:无需知道对方IP,配置简单。
- 缺点:在复杂的Wi-Fi网络下可能不够可靠。
对于新手和追求稳定的方案,我强烈推荐MQTT。虽然多了一步搭建Broker,但它解耦了发送和接收方,系统更健壮,未来想增加其他智能设备(比如同时触发灯光)会非常容易。接下来,我将以ESP8266 + PIR传感器作为感知端,旧安卓手机作为播放端,MQTT作为通信协议,来详细拆解实现步骤。
3. 感知端(ESP8266)的固件开发与烧录
这一部分,我们将让ESP8266“学会”连接Wi-Fi、读取PIR信号,并通过MQTT发送消息。
3.1 开发环境搭建
- 安装Arduino IDE:从Arduino官网下载并安装集成开发环境。
- 添加ESP8266开发板支持:
- 打开Arduino IDE,进入“文件”->“首选项”,在“附加开发板管理器网址”中输入:
http://arduino.esp8266.com/stable/package_esp8266com_index.json - 然后进入“工具”->“开发板”->“开发板管理器”,搜索“esp8266”,安装“esp8266 by ESP8266 Community”。
- 打开Arduino IDE,进入“文件”->“首选项”,在“附加开发板管理器网址”中输入:
- 安装必要的库:在“项目”->“加载库”->“管理库”中,搜索并安装
PubSubClient库。这个库将帮助我们实现MQTT客户端功能。
3.2 编写并上传代码
以下是ESP8266端的核心代码示例。你需要修改其中的Wi-Fi名称、密码、MQTT Broker的IP地址以及PIR传感器连接的引脚。
#include <ESP8266WiFi.h> #include <PubSubClient.h> // 1. Wi-Fi 配置 const char* ssid = "你的Wi-Fi名称"; const char* password = "你的Wi-Fi密码"; // 2. MQTT 配置 const char* mqtt_server = "192.168.1.50"; // 你的MQTT Broker IP地址 const char* mqtt_topic = "home/livingroom/pir"; // MQTT主题,可自定义 const char* mqtt_client_id = "ESP8266_PIR_Sensor"; // 客户端ID // 3. PIR 传感器引脚定义 const int pirPin = D5; // 假设PIR数据线接在D5引脚 int pirState = LOW; // 默认无人状态 int lastPirState = LOW; WiFiClient espClient; PubSubClient client(espClient); void setup_wifi() { delay(10); Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("Wi-Fi连接成功"); } void reconnect_mqtt() { while (!client.connected()) { if (client.connect(mqtt_client_id)) { Serial.println("MQTT连接成功"); } else { Serial.print("MQTT连接失败,错误码: "); Serial.print(client.state()); Serial.println(" 5秒后重试..."); delay(5000); } } } void setup() { pinMode(pirPin, INPUT); setup_wifi(); client.setServer(mqtt_server, 1883); // 1883是MQTT默认端口 } void loop() { if (!client.connected()) { reconnect_mqtt(); } client.loop(); // 读取PIR传感器状态 pirState = digitalRead(pirPin); // 状态发生变化时(从无人到有人) if (pirState == HIGH && lastPirState == LOW) { Serial.println("检测到移动,发送MQTT消息: ON"); client.publish(mqtt_topic, "ON"); // 发布“ON”消息 delay(1000); // 防抖延时,避免连续触发 } // 状态发生变化时(从有人到无人)- 可选,用于发送离开信号 else if (pirState == LOW && lastPirState == HIGH) { Serial.println("移动停止,发送MQTT消息: OFF"); client.publish(mqtt_topic, "OFF"); delay(1000); } lastPirState = pirState; // 更新上一次状态 delay(50); // 主循环短暂延迟 }代码关键点解析:
setup_wifi()和reconnect_mqtt()函数确保了网络连接的稳定性,即使断线也会自动重连。client.publish(mqtt_topic, "ON")是核心,它向指定的主题(home/livingroom/pir)发布了一条内容为“ON”的消息。- 防抖处理:
delay(1000)非常重要。PIR传感器在检测到移动时,输出信号可能有不稳定的抖动,这个延时可以确保在状态变化后1秒内不再重复发送消息,避免消息风暴。
烧录步骤:
- 用USB数据线连接ESP8266开发板到电脑。
- 在Arduino IDE的“工具”菜单中,选择正确的开发板(如“NodeMCU 1.0”)和端口。
- 点击“上传”按钮,等待编译和烧录完成。
- 打开“串口监视器”(波特率设为115200),查看连接和触发日志。
4. MQTT Broker的搭建与测试
要让MQTT消息有地方可去,我们需要一个“中转站”,即Broker。这里推荐在家庭网络中一台常开的设备(如NAS、旧电脑、甚至树莓派)上安装Mosquitto。
在Linux(如树莓派Raspbian/Ubuntu)上安装:
sudo apt update sudo apt install mosquitto mosquitto-clients sudo systemctl enable mosquitto sudo systemctl start mosquitto安装后,Mosquitto服务默认就在后台运行,监听1883端口。
测试通信:
- 在运行Broker的机器上,打开一个终端,订阅我们设定的主题:
mosquitto_sub -h localhost -t "home/livingroom/pir" -v - 当ESP8266上电并触发PIR传感器时,你应该在这个终端看到输出:
home/livingroom/pir ON。 这证明感知端到Broker的通信是成功的。
注意:如果你的网络有防火墙,请确保1883端口(TCP)是开放的。对于纯粹的家庭局域网,通常无需额外配置。
5. 播放端(安卓设备)的自动化实现
这是项目的“大脑”,我们需要一个能在后台运行、监听MQTT消息、并控制视频播放的App。有两种主流实现方式:
5.1 方案一:使用Tasker + MQTT Client插件(无需编程,推荐)
Tasker是一个强大的安卓自动化工具,配合插件可以轻松实现我们的需求。
- 安装软件:在安卓设备上安装
Tasker、AutoTools(或MQTT Client插件)。 - 配置MQTT客户端:
- 在Tasker中,进入“配置”->“插件”,设置MQTT客户端,填入Broker的IP地址、端口(1883)、以及要订阅的主题(
home/livingroom/pir)。 - 设置“连接时订阅”该主题。
- 在Tasker中,进入“配置”->“插件”,设置MQTT客户端,填入Broker的IP地址、端口(1883)、以及要订阅的主题(
- 创建触发Profile:
- 在Tasker主界面,点击“+”创建新的“配置文件”。
- 选择“事件”->“插件”->“MQTT Client”,配置为“消息收到”。
- 在“过滤”中,可以指定主题或消息内容(如“ON”)。
- 关联播放任务(Task):
- 为这个Profile关联一个新任务。
- 在任务中,添加动作:“媒体”->“播放音乐”。
- 在“文件”选项中,选择你想要播放的视频文件路径。(关键:安卓系统自带的“播放音乐”动作实际上可以播放视频,但需要指定一个能处理该视频格式的播放器App,如MX Player)
- 你还可以添加其他动作,比如“屏幕”->“唤醒”,确保播放时屏幕是亮的。
- 创建停止播放的Profile(可选):
- 类似地,创建一个监听“OFF”消息的Profile。
- 关联一个任务,动作为:“媒体”->“媒体控制”,命令选择“停止”。
Tasker方案的优势是图形化操作,灵活性强,你还可以轻松扩展其他动作,比如收到消息后同时调节音量、发送通知等。
5.2 方案二:使用Kivy或Flutter编写简易App(可深度定制)
如果你有一定编程基础,希望有更美观的界面或更复杂的功能(如播放列表、随机播放、网络流媒体),可以用Python的Kivy框架或Flutter编写一个简单的App。
以Kivy(Python)为例的核心逻辑:
- 使用
paho-mqtt库连接Broker并订阅主题。 - 使用Kivy的
Video控件来加载和播放视频。 - 在MQTT消息回调函数中,当收到“ON”时,调用
video.play();收到“OFF”时,调用video.stop()。 - 将Python脚本打包成APK文件,安装到安卓设备上。
这个方案的好处是完全可控,可以设计全屏播放、淡入淡出等效果,但需要额外的学习和开发时间。
5.3 安卓端的优化与避坑指南
无论用哪种方案,在安卓端都需要注意以下几个实际问题:
- 保活与自启动:要确保监听MQTT的服务在后台不会被系统“杀掉”。在Tasker中,需要在“首选项”->“监控”中,确保“可靠性”设置里的“通知图标”和“设备启动时运行”等选项被启用。如果是自研App,需要申请必要的后台运行权限,并考虑使用前台服务(Foreground Service)。
- 播放器选择:Tasker的“播放音乐”动作可能无法直接播放所有视频格式或无法全屏。一个更稳定的方法是使用Tasker的“发送意图(Send Intent)”动作,来调用像MX Player、VLC这样的第三方播放器的特定播放功能。这需要查询对应播放器的Intent格式。
- 电源管理:为了避免播放设备电量耗尽,最好让其长期连接充电器。同时,在系统设置中,关闭该设备的屏幕自动休眠,或者通过Tasker设置为“当播放视频时,保持屏幕常亮”。
- 网络稳定性:为播放端设备设置静态IP地址,避免DHCP租约到期后IP变化导致MQTT连接失败。这可以在家庭路由器的后台进行配置。
6. 系统集成、调试与场景化拓展
当硬件、Broker、客户端都准备好后,就到了联调阶段。
6.1 系统联调步骤
- 通电测试:给ESP8266上电,观察串口日志,确认其成功连接Wi-Fi和MQTT Broker。
- Broker监控:在Broker服务器上运行
mosquitto_sub命令,订阅相关主题,用手在PIR传感器前晃动,确认能收到“ON”和“OFF”消息。 - 播放端监听:在安卓设备上,确保Tasker Profile已启用。当Broker收到消息时,观察安卓设备是否被唤醒并开始播放视频。
- 延时与灵敏度调整:
- PIR传感器:模块上通常有两个旋钮,一个是“灵敏度”(SENS),一个是“延时时间”(TIME)。调整“延时时间”可以控制触发后,输出高电平保持的时长,这会影响“ON”状态的长度。根据你视频的长度和希望播放的时长来调整。
- 代码延时:回顾ESP8266代码中的
delay(1000),这个防抖延时如果太长,可能会错过快速连续的移动;太短则可能发送重复消息。根据实际情况微调。 - 播放端响应:Tasker任务执行可能会有微小延迟,属于正常现象。
6.2 场景化拓展思路
基础功能跑通后,你可以玩出更多花样:
- 多区域联动:部署多个ESP8266+PIR传感器,分别监控门口、走廊、客厅。让它们发布到不同的MQTT主题(如
home/door/pir,home/hallway/pir)。安卓播放端可以订阅所有主题,并根据不同的主题,播放不同的欢迎视频或信息。 - 内容动态化:播放端不播放本地固定视频,而是收到触发后,通过HTTP请求从家庭服务器或云存储获取一个最新的视频URL进行播放。这样,你每天都可以远程更新要播放的内容。
- 状态反馈:让安卓播放端也作为一个MQTT发布者。当它开始播放时,发布一条“
playing”消息。你可以让ESP8266订阅这个消息,并控制一个LED灯,当视频播放时亮起,提供视觉反馈。 - 结合其他传感器:将PIR传感器换成激光对射传感器,实现更精准的“穿越”触发;或者加入温湿度传感器,在播放欢迎视频的同时,在屏幕一角叠加显示环境信息。
- 省电优化:如果播放端是电池供电,可以设计为:平时屏幕关闭,仅后台服务监听MQTT;收到“ON”消息后,唤醒屏幕并播放;收到“OFF”消息或视频播放完毕后,延迟一段时间再关闭屏幕。
这个项目的魅力在于,它用一个简单的逻辑串联起了硬件感知、无线通信和软件控制,实现了颇具仪式感和实用性的智能交互。从技术上看,它涉及了嵌入式开发、网络通信和移动端自动化,是一个非常好的全栈小项目实践。从结果上看,它创造了一个真正“无感”的、贴心的环境反馈。当你结束一天工作推开门,熟悉的画面和音乐自动亮起,那一刻的温暖感,远不是手动点击播放所能比拟的。