如何从HTML执行Node.js原型函数?运动传感器调用报错问题
解决前端HTML调用Node.js GPIO传感器代码的问题
看起来你踩了前后端环境隔离的坑——你的传感器代码是运行在Node.js后端环境里的,而HTML是在浏览器前端环境中执行的,两者完全独立,前端根本没法直接访问后端的sensor变量,这就是为什么开发者工具提示它"未定义"。
要实现从HTML控制传感器监听,你需要搭建一个简单的Web服务器,让前后端通过HTTP请求或者WebSocket通信。下面是完整的解决方案:
步骤1:搭建后端服务(用Express)
首先安装所需依赖:
npm install express onoff sleep cors
然后创建server.js文件,把你的传感器逻辑封装成后端接口:
var sleep = require('sleep'); var Gpio = require('onoff').Gpio; var express = require('express'); var cors = require('cors'); var app = express(); // 解决跨域问题,让前端能访问后端接口 app.use(cors()); app.use(express.json()); // 托管静态HTML文件,我们会把前端页面放在public文件夹里 app.use(express.static('public')); // 初始化硬件 var LED = new Gpio(18, 'out'); var sensor = new Gpio(17, 'in', 'both'); var isSensorWatching = false; // 封装传感器监听逻辑 function startSensorMonitoring() { if (isSensorWatching) return; // 避免重复启动监听 isSensorWatching = true; sensor.watch(function(err, value){ if (err){ console.error('传感器出错:', err); cleanUp(); return; } if(value == 1) { console.log('检测到运动'); LED.writeSync(value); sleep.sleep(3); } else if(value == 0) { console.log('无运动'); LED.writeSync(value); sleep.sleep(3); } }); } // 停止传感器监听 function stopSensorMonitoring() { if (!isSensorWatching) return; sensor.unwatchAll(); isSensorWatching = false; } // 硬件资源清理函数 function cleanUp() { LED.unexport(); sensor.unexport(); process.exit(); } // 前端调用的接口:启动传感器 app.post('/start-sensor', (req, res) => { startSensorMonitoring(); res.json({ status: 'success', message: '传感器已启动监听' }); }); // 前端调用的接口:停止传感器 app.post('/stop-sensor', (req, res) => { stopSensorMonitoring(); res.json({ status: 'success', message: '传感器已停止监听' }); }); // 启动服务器,监听3000端口 app.listen(3000, () => { console.log('服务器运行在 http://localhost:3000'); }); // 程序退出时清理硬件资源 process.on('SIGINT', cleanUp);
步骤2:创建前端HTML页面
新建public文件夹,在里面创建index.html:
<!DOCTYPE html> <html> <head> <title>运动传感器控制</title> </head> <body> <h1>运动传感器控制器</h1> <button id="startBtn">启动传感器监听</button> <button id="stopBtn">停止传感器监听</button> <div id="statusMsg" style="margin-top: 20px;"></div> <script> const startBtn = document.getElementById('startBtn'); const stopBtn = document.getElementById('stopBtn'); const statusMsg = document.getElementById('statusMsg'); // 点击启动按钮,调用后端接口 startBtn.addEventListener('click', async () => { try { const response = await fetch('http://localhost:3000/start-sensor', { method: 'POST', headers: { 'Content-Type': 'application/json' } }); const data = await response.json(); statusMsg.textContent = data.message; } catch (err) { statusMsg.textContent = '请求失败,请检查服务器是否运行'; } }); // 点击停止按钮,调用后端接口 stopBtn.addEventListener('click', async () => { try { const response = await fetch('http://localhost:3000/stop-sensor', { method: 'POST', headers: { 'Content-Type': 'application/json' } }); const data = await response.json(); statusMsg.textContent = data.message; } catch (err) { statusMsg.textContent = '请求失败,请检查服务器是否运行'; } }); </script> </body> </html>
步骤3:运行程序
在终端执行:
sudo node server.js # 需要sudo权限操作GPIO
然后打开浏览器访问http://localhost:3000,点击按钮就能控制传感器监听了。
额外提示
- 注意:
sleep.sleep(3)会阻塞Node.js的事件循环,导致服务器在这3秒内无法处理其他请求,建议换成非阻塞的setTimeout来替代,比如:setTimeout(() => { LED.writeSync(0); }, 3000); - 确保你的设备支持GPIO操作(比如树莓派),并且Node.js有足够的权限访问硬件。
内容的提问来源于stack exchange,提问作者Marvin
相关产品推荐
相关产品推荐

