资讯动态

PIR传感器+Photon 2+Node.js+AutoHotkey:打造人体感应自动打开作业页面系统

发布时间:2026/10/9 3:43:17 来源:尧图企业网站定制
1. 项目缘起与整体设计思路1.1 这个项目到底在解决什么问题先说说这个项目的由来。家里有娃的朋友大概都有体会孩子放学回家第一件事不是写作业而是摸手机、开电视、翻零食。你人在公司鞭长莫及打电话催吧一天三遍自己也烦。我就想能不能做一个东西孩子一坐到他书桌前电脑自动把作业页面弹出来省得我天天远程唠叨。于是就有了这个Motion Detected Homework Opener——直译过来就是检测到人体移动就打开作业。核心逻辑非常朴素PIR 人体红外传感器检测到有人靠近书桌Particle Photon 2 通过 Wi-Fi 把事件推送到云端本地跑的一个 Node.js 服务收到事件后调用 AutoHotkey 脚本把作业网页或文档窗口弹到最前面。整套链路从人坐下到作业页面出现实测在 2 秒以内。这个项目适合谁我认为有三类人值得动手做一遍一是家里有学龄儿童、想用技术手段做点温和提醒的家长二是刚接触物联网、想找一个从硬件到云端再到本地自动化完整闭环练手的人三是已经会写点代码、但没玩过 Particle 生态和 AutoHotkey 联动的开发者。硬件门槛不高软件部分全是免费工具总成本大概一百多块钱。1.2 为什么选这套技术栈技术选型这块我纠结过一阵最后定下来用Particle Photon 2 PIR 传感器 Node.js ngrok AutoHotkey每一个都有明确的理由。Particle Photon 2是我优先考虑的。市面上能联网的 MCU 很多ESP32 便宜、Arduino Nano 33 IoT 也行但 Particle 的优势在于它自带云平台设备上线、事件发布、Webhook 配置全在网页后台点几下就搞定不用自己搭 MQTT Broker也不用折腾证书。对于我就想快速把传感器数据送到我电脑上这种需求Particle 的Particle.publish()一行代码就能把事件推到云端省掉大量样板代码。Photon 2 还支持 Wi-Fi 6家里路由器再挤也不容易掉线。PIR 运动传感器选的是最常见的 HC-SR501。它输出的是数字高低电平检测到人体移动拉高静止一段时间后拉低Photon 2 直接读 GPIO 就行不需要额外的 ADC。灵敏度、延时、触发模式都能通过板载电位器调非常适合检测人是否坐到桌前这种场景。Node.js作为本地服务端是因为它处理 HTTP 请求和事件回调特别顺手http模块几十行就能起一个 Webhook 接收器而且 npm 生态里有大量现成库可以调用系统命令、操作窗口。热词里那一堆nodejs安装及环境配置npm 无法加载文件 npm.ps1的问题我在搭建过程中也踩过后面会专门讲。ngrok的作用是把本地 Node.js 服务暴露到公网让 Particle 云端的 Webhook 能回调进来。家里宽带没有公网 IP这是最省事的方案。热词里的ngrok内网穿透教程我看了不少但很多讲得太泛我会结合这个项目讲具体怎么配。AutoHotkey是 Windows 上做窗口自动化的老牌工具脚本简单、启动快、能精确控制窗口激活和键盘输入。相比 Python 的 pyautoguiAHK 在把某个窗口拉到最前并聚焦这件事上更稳资源占用也低。1.3 整体数据流与架构把上面几个组件串起来数据流是这样的PIR 传感器检测到人体移动输出高电平给 Photon 2 的 D2 引脚。Photon 2 固件里做去抖和冷却判断确认是有效触发后调用Particle.publish(motion-detected, desk, 60, PRIVATE)发布事件。Particle 云端收到事件根据预先配置的 Webhook向 ngrok 提供的公网地址发起 POST 请求。ngrok 把请求转发到本机localhost:3000的 Node.js 服务。Node.js 服务校验请求来源和内容确认无误后通过child_process调用 AutoHotkey 脚本。AutoHotkey 脚本激活浏览器窗口、切换到作业标签页或者直接打开作业文档。整个链路里Particle 云端到 ngrok 这一段是公网传输所以 Webhook 里我加了一个自定义的共享密钥做校验Node.js 端会检查请求头防止被人乱打接口。这一点后面会详细说。提示这套架构里没有任何数据是敏感的个人信息PIR 只输出有人/没人的布尔状态不涉及图像、声音隐私上比较放心。2. 硬件准备与 Photon 2 固件开发2.1 元器件清单与接线细节先列一下需要买的东西都是常见件某宝某东都能买到元件型号/规格数量备注主控板Particle Photon 21自带 Wi-Fi需注册 Particle 账号人体红外传感器HC-SR5011可调灵敏度与延时面包板半尺寸1免焊接方便调试杜邦线公对公若干建议多备几根USB 电源5V 2A1给 Photon 2 供电电阻10kΩ1下拉用可选接线其实很简单HC-SR501 有三个引脚VCC、GND、OUT。VCC 接 Photon 2 的 VIN或者 3V3看传感器工作电压HC-SR501 一般支持 4.5V-20V接 VIN 更稳GND 接 GNDOUT 接 D2。如果你担心信号抖动可以在 OUT 和 GND 之间加一个 10kΩ 下拉电阻不过 HC-SR501 输出本身比较干净不加也能跑。这里有个新手容易踩的坑HC-SR501 刚上电有大约 30 到 60 秒的初始化时间这段时间输出会乱跳固件里必须做启动延时否则一上电就疯狂触发。我在代码里加了delay(60000)的预热等待虽然简单粗暴但很有效。2.2 Photon 2 固件代码逐段解析固件部分我写得比较克制核心就是读引脚、去抖、冷却、发布事件。完整代码如下#include Particle.h const int PIR_PIN D2; const unsigned long COOLDOWN_MS 120000; // 两次触发最小间隔 2 分钟 const unsigned long DEBOUNCE_MS 2000; // 信号稳定确认时间 unsigned long lastTrigger 0; bool lastState LOW; void setup() { pinMode(PIR_PIN, INPUT); Serial.begin(9600); // 等待传感器预热避免上电乱触发 delay(60000); Serial.println(PIR sensor ready); } void loop() { bool currentState digitalRead(PIR_PIN); // 只在上升沿且超过冷却时间时触发 if (currentState HIGH lastState LOW) { unsigned long now millis(); if (now - lastTrigger COOLDOWN_MS) { delay(DEBOUNCE_MS); // 简单去抖确认不是瞬时干扰 if (digitalRead(PIR_PIN) HIGH) { Particle.publish(motion-detected, desk, 60, PRIVATE); Serial.println(Event published); lastTrigger now; } } } lastState currentState; delay(100); }逐段说一下设计意图。COOLDOWN_MS设成 2 分钟是因为孩子写作业时不可能一直不动如果每次小动作都触发作业页面会反复弹出来反而干扰。2 分钟是个经验值你可以根据自家情况调。DEBOUNCE_MS的 2 秒去抖是为了过滤掉传感器偶尔的误报比如窗外有只猫经过、阳光突然变化都可能让 PIR 误触发加个二次确认能挡掉大部分。Particle.publish的第三个参数60是 TTL存活时间单位秒表示这个事件在云端保留 60 秒供订阅者接收。第四个参数PRIVATE表示事件只对同一账号下的订阅者可见这是默认值但显式写出来更清楚。注意delay(60000)会阻塞整个 loop如果你后续想加别的功能比如同时读温度传感器得改成非阻塞的 millis 计时方式。这个项目里功能单一阻塞一下无所谓。2.3 烧录与设备上线烧录方式有两种用 Particle 的 Web IDEbuild.particle.io在线编译烧录或者用本地 particle-cli。我推荐新手先用 Web IDE注册账号、把 Photon 2 连上 Wi-Fi用手机 App 配网几分钟搞定然后在 Web IDE 里粘贴代码、点闪电图标就能烧录。设备上线后在 Particle Console 里能看到设备状态变成 online事件流里也能看到motion-detected事件。这时候你可以先手动在传感器前挥挥手确认事件能正常发出来再往下做云端配置。这一步一定要先验证通过不然后面 Node.js 收不到请求你会怀疑人生。3. 云端 Webhook 与 ngrok 打通3.1 Particle Webhook 配置要点Particle 云端到本地服务的桥梁就是 Webhook。在 Particle Console 里找到 Integrations新建一个 Webhook关键字段这样填Event Namemotion-detected必须和固件里 publish 的事件名完全一致。URL填 ngrok 给你的公网地址比如https://xxxx.ngrok-free.app/webhook。Request TypePOST。Request FormatJSON。JSON Body可以自定义我一般带上设备 ID 和时间戳方便排查。这里有个关键安全设计Webhook 的请求头里加一个自定义字段比如X-Auth-Token: 你的随机字符串。Node.js 端收到请求后先校验这个头不匹配直接返回 403。因为 ngrok 的公网地址理论上谁都能访问加个共享密钥能挡掉绝大部分乱扫的请求。Webhook 配置里还有个Custom Header区域可以填X-Auth-Token和对应的值。这个值你自己生成一串随机字符就行别用简单的123456。3.2 ngrok 内网穿透实操ngrok 的安装很简单官网下载对应系统的压缩包解压得到一个可执行文件。Windows 下把它放到一个固定目录比如C:\ngrok\然后在该目录打开终端执行ngrok http 3000它会输出一个公网地址类似https://abc123.ngrok-free.app这个地址转发到本机 3000 端口。把这个地址填到 Particle Webhook 的 URL 里后面加上/webhook路径。免费版 ngrok 有个限制每次重启地址都会变。这意味着你每次重启 ngrok都得去 Particle Console 改 Webhook URL很烦。解决办法有两个一是买个付费版固定域名不便宜二是用 ngrok 的配置文件固定一个子域名免费版也支持但子域名是随机的不能自定义。我的做法是写了个小脚本ngrok 启动后自动读取它的本地 APIhttp://localhost:4040/api/tunnels拿到当前地址然后调用 Particle API 自动更新 Webhook。这个脚本后面在 Node.js 部分一起讲。提示ngrok 免费版还会在浏览器访问时插一个警告页但 Webhook 是程序调用不受影响。如果你用 curl 测试发现返回 HTML 警告页加个请求头ngrok-skip-browser-warning: true就能跳过。3.3 Node.js 服务端搭建与环境配置Node.js 这块是热词里问题最多的我先讲安装和环境配置再讲代码。安装去 Node.js 官网下载 LTS 版本Windows 下双击安装一路下一步。安装完在终端执行node -v和npm -v能输出版本号就说明装好了。Mac 用户可以用brew install node更省事。那个经典的 npm.ps1 报错热词里反复出现npm : 无法加载文件 npm.ps1因为在此系统上禁止运行脚本。这是 PowerShell 的执行策略问题不是 Node.js 装错了。解决办法是以管理员身份打开 PowerShell执行Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser然后输入 Y 确认。这个命令只影响当前用户不会降低系统整体安全性。改完之后 npm 就能正常用了。如果你不想改执行策略也可以改用 CMD 而不是 PowerShellCMD 不受这个策略限制。项目初始化新建一个目录执行npm init -y生成 package.json然后安装依赖npm install express body-parserExpress 用来起 HTTP 服务body-parser 解析 JSON 请求体。虽然 Node.js 内置的 http 模块也能做但 Express 写起来更清爽。服务端核心代码const express require(express); const { exec } require(child_process); const app express(); const AUTH_TOKEN 你的随机字符串; const AHK_SCRIPT C:\\scripts\\open_homework.ahk; app.use(express.json()); app.post(/webhook, (req, res) { const token req.headers[x-auth-token]; if (token ! AUTH_TOKEN) { return res.status(403).send(Forbidden); } const event req.body; console.log(收到事件:, JSON.stringify(event)); exec(C:\\Program Files\\AutoHotkey\\AutoHotkey.exe ${AHK_SCRIPT}, (err, stdout, stderr) { if (err) { console.error(执行 AHK 失败:, err); return res.status(500).send(AHK error); } console.log(AHK 执行成功); res.status(200).send(OK); }); }); app.listen(3000, () { console.log(服务已启动监听 3000 端口); });这段代码里exec调用 AutoHotkey 可执行文件并传入脚本路径。注意路径里有空格所以用双引号包起来。AUTH_TOKEN必须和 Particle Webhook 里配的一致。注意exec是异步的但这里我们等它回调再返回响应避免 Particle 那边超时。Particle Webhook 默认超时是 5 秒AHK 脚本执行通常几百毫秒够用。4. AutoHotkey 脚本与窗口自动化4.1 AutoHotkey 版本选择与安装AutoHotkey 有两个大版本v1 和 v2语法不兼容。网上大量老教程是 v1 的但 v2 更现代、更规范。我建议直接用 v2官网下载安装包装完右键新建脚本时选 v2 版本。热词里有人问autohotkey和autoit的区别简单说AutoIt 更偏向自动化测试和 GUI 自动化语法类似 BASICAutoHotkey 更偏向键盘鼠标热键和窗口操作社区脚本更多。这个项目里我们只需要激活窗口、发送按键AHK 完全够用而且脚本更短。4.2 打开作业页面的脚本实现脚本的核心任务是找到浏览器窗口激活它切换到作业标签页或者直接打开作业 URL。我写的是打开一个固定的作业网页#Requires AutoHotkey v2.0 ; 作业页面地址 HomeworkURL : https://example.com/homework ; 如果浏览器已打开激活它否则启动浏览器 if WinExist(ahk_exe chrome.exe) { WinActivate(ahk_exe chrome.exe) Sleep 300 ; 新建标签页并打开作业地址 Send(^t) Sleep 200 Send(HomeworkURL) Send({Enter}) } else { Run(chrome.exe . HomeworkURL) }逐行解释WinExist检查 Chrome 是否在运行ahk_exe chrome.exe是按进程名匹配窗口比按标题匹配稳因为标题会随页面变化。WinActivate把窗口拉到最前。Send(^t)是 CtrlT 新建标签页^在 AHK 里代表 Ctrl。然后输入 URL 回车。如果你用的是 Edge把chrome.exe换成msedge.exe即可。如果作业是本地文档比如 Word 文件把Run那行改成Run(C:\\path\\to\\homework.docx)。一个提升体验的细节如果孩子已经在写作业页面已经开着重复触发会不断新建标签页很烦。我加了个判断先检查当前活动窗口标题里是否已包含作业页面的关键词如果包含就直接返回不重复打开if InStr(WinGetTitle(A), 作业) { ExitApp }WinGetTitle(A)获取当前活动窗口标题InStr判断是否包含关键词。这个判断放在脚本最前面能有效避免重复弹窗。4.3 让脚本更温和的几个技巧直接弹窗有时候太突兀孩子正专注做别的事会被吓一跳。我试过几个缓和方案一是加一个系统提示音先叮一声再弹窗二是用WinActivate之前先WinMinimizeAll把其他窗口最小化视觉上更干净三是设置一个时间段限制比如只在下午 4 点到晚上 9 点之间才触发其他时间忽略。时间段限制可以在 AHK 里做也可以在 Node.js 端做。我选择在 Node.js 端做因为改起来不用重新编译脚本const hour new Date().getHours(); if (hour 16 || hour 21) { console.log(非作业时段忽略); return res.status(200).send(Ignored); }这样晚上十点以后孩子再经过书桌也不会弹作业页面避免打扰休息。5. 常见问题与排查技巧实录5.1 硬件与固件层问题问题一Photon 2 上电后事件疯狂触发。这是 HC-SR501 预热期的典型表现。解决办法就是固件里加delay(60000)等传感器稳定。如果你不想阻塞可以用状态机前 60 秒忽略所有输入。问题二传感器检测距离太短或太远。HC-SR501 板上有两个电位器一个调灵敏度检测距离3-7 米可调一个调延时触发后输出高电平的持续时间0.3-200 秒可调。检测距离不够就顺时针拧灵敏度电位器误触发多就逆时针拧。延时建议调到最小因为我们在固件里自己做冷却控制。问题三Photon 2 频繁掉线。检查路由器是不是开了 AP 隔离或者 2.4G 和 5G 混用导致设备连错频段。Photon 2 只支持 2.4G如果路由器把 2.4G 和 5G 合并成一个 SSID可能会连不上。解决办法是在路由器里把 2.4G 单独分一个 SSID 出来。5.2 网络与云端层问题问题四Particle Webhook 返回 4xx 或 5xx。先在 Particle Console 的 Webhook 日志里看具体错误。常见原因ngrok 地址变了没更新、Node.js 服务没启动、AUTH_TOKEN 不匹配。排查顺序是先用 curl 直接打 ngrok 地址确认能通再看 Particle 日志。问题五ngrok 地址每次重启都变。前面提过写个自动更新脚本。核心逻辑是启动 ngrok 后请求http://localhost:4040/api/tunnels拿到公网地址然后调用 Particle API 更新 Webhook。Particle API 更新 Webhook 的接口是PUT /v1/webhooks/{id}需要 access token在 Particle Console 里能生成。问题六npm 装包时报错。除了前面说的 PowerShell 执行策略问题还可能是网络问题。国内访问 npm 官方源有时很慢可以换成国内镜像npm config set registry https://registry.npmmirror.com。换完再装速度会快很多。5.3 自动化执行层问题问题七AHK 脚本执行了但窗口没弹出来。最常见的原因是 AHK 脚本路径写错或者 AutoHotkey.exe 路径不对。在 Node.js 里exec执行时把 stdout 和 stderr 都打印出来能看到具体报错。另外如果 Node.js 是以服务方式运行的比如用 nssm 注册成 Windows 服务它可能没有桌面交互权限无法操作窗口。解决办法是让 Node.js 以普通用户进程运行或者用计划任务在用户登录时启动。问题八窗口激活了但焦点不对。WinActivate只是把窗口拉到最前但输入焦点可能还在别的控件上。加一个WinWaitActive等窗口真正激活再Send按键会稳很多。如果还是不行可以用ControlFocus直接指定控件。问题九孩子把浏览器关了脚本报错。脚本里WinExist返回 0 时会走 else 分支启动浏览器不会报错。但如果浏览器进程在但窗口被最小化到托盘WinActivate可能失败。这种情况加一个WinRestore先还原窗口。5.4 常见问题速查表现象可能原因排查方法解决事件疯狂触发传感器预热期观察上电后 1 分钟固件加延时Webhook 无响应ngrok 地址失效curl 测试 ngrok 地址更新 Webhook URLnpm 报 ps1 错误PowerShell 策略看报错全文改执行策略AHK 不执行路径或权限看 Node.js 日志修正路径/权限窗口不弹出焦点问题手动跑 AHK 脚本加 WinWaitActive重复弹窗无去重判断观察触发频率加标题判断6. 实际部署中的经验与优化建议6.1 稳定性优化让服务开机自启这套东西要长期跑不能每次重启电脑都手动开 Node.js 和 ngrok。Windows 下我推荐用任务计划程序新建两个任务一个启动 Node.js 服务一个启动 ngrok触发器都设为用户登录时。这样开机后自动跑起来不用管。Node.js 服务建议用pm2守护它能自动重启崩溃的进程还能看日志。安装npm install -g pm2然后用pm2 start server.js --name homework-opener启动pm2 save保存进程列表pm2 startup生成开机自启配置。ngrok 也可以用 pm2 守护但 ngrok 是个可执行文件不是 Node 脚本pm2 管起来别扭。我的做法是写一个批处理文件里面先启动 ngrok再跑一个 Node 脚本轮询 ngrok API 更新 Webhook然后用任务计划程序启动这个批处理。6.2 隐私与安全上的考量虽然这个项目不涉及摄像头和麦克风但家里有没有人这个信息本身也有一定敏感性。我在设计时做了几层防护一是 Particle 事件设为 PRIVATE只有自己账号能订阅二是 Webhook 加了共享密钥校验三是 ngrok 地址虽然公开但没有密钥的请求一律 403四是 Node.js 服务只监听 localhost不直接暴露到局域网。另外ngrok 免费版会把访问日志保留一段时间如果你介意可以定期在 ngrok 后台清理或者用付费版关闭日志。不过说实话PIR 事件本身没什么敏感内容不用过度紧张。6.3 后续可以扩展的方向这套架构搭好之后其实可以玩出很多花样。比如把 PIR 换成超声波传感器检测孩子是否真的坐在椅子上而不只是路过或者在 Node.js 端接一个语音合成弹窗的同时播一句该写作业啦再或者把事件记录到本地数据库统计孩子每天在书桌前待了多久生成周报。我还试过把触发事件同时推送到手机用 Bark 或者 Server 酱这样我在公司也能知道孩子什么时候坐到了书桌前。不过后来觉得推送太频繁也烦就关了。技术上是通的看个人需求。6.4 几个我踩过的坑第一个坑是HC-SR501 的触发模式。它板子上有个跳线可以选可重复触发和不可重复触发。默认是可重复意思是检测到人动就持续输出高电平人不动了延时一段时间才拉低。这个模式下孩子坐在那里写作业只要偶尔动一下输出就一直是高我的上升沿检测就永远触发不了第二次。后来我把跳线改成不可重复模式每次触发输出一个固定宽度的高脉冲然后拉低这样上升沿检测才正常工作。第二个坑是ngrok 的 HTTPS 证书。Particle Webhook 默认要求 HTTPSngrok 免费版提供的是 https 地址但证书是 ngrok 自己的。Particle 云端信任这个证书所以没问题。但如果你自己用 curl 测试可能会遇到证书警告加-k跳过即可。第三个坑是AutoHotkey v1 和 v2 的语法差异。我一开始抄了个 v1 的脚本在 v2 里跑直接报错。v2 里Send变成了函数调用Send()变量赋值用:字符串拼接用.。如果你不确定自己装的是哪个版本在脚本开头加#Requires AutoHotkey v2.0版本不对会直接提示。第四个坑是Node.js 的路径转义。Windows 路径里的反斜杠在 JavaScript 字符串里要写成双反斜杠\\或者用正斜杠/。我一开始写C:\scripts\open.ahk结果\s被当成转义字符路径全乱了。这个错误很隐蔽日志里看不出来排查了半天。6.5 成本与时间投入最后算笔账。硬件方面Photon 2 大概 100 元左右HC-SR501 几块钱面包板和线材十几块总共不到 150 元。软件全是免费的ngrok 免费版够用Node.js、AutoHotkey 都不要钱。时间投入上如果你有编程基础一个周末能搞定完全新手的话可能要花两三个晚上主要卡在环境配置和 ngrok 那一段。我个人觉得这个项目最大的价值不在于省了那几句催促的话而在于它是一条完整的物理世界事件触发数字世界动作的链路。把这套链路跑通之后你可以把 PIR 换成任何传感器把 AHK 换成任何自动化动作可能性是开放的。我家现在除了作业提醒还用类似的架构做了进门自动开灯和久坐提醒站起来活动都是同一套思路的变体。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑