You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:46:20