基于ExpressJS与Johnny-Five实现Arduino LED闪烁间隔实时调节
嘿,你已经搭好了React客户端和集成Johnny-Five的Express服务端基础架构,要实现实时更新LED闪烁间隔的功能其实不难,咱们一步步来完善:
第一步:完善Express服务端逻辑
首先要注意Johnny-Five的Board必须处于ready状态才能操作硬件,所以相关的LED初始化和API路由都要放在board.on('ready')回调里。另外,咱们需要维护一个全局的定时器变量,用来在更新间隔时清除旧的闪烁任务,避免多个定时器冲突。
下面是补全后的服务端代码:
const express = require('express'); const bodyParser = require('body-parser'); const five = require('johnny-five'); const app = express(); const board = new five.Board(); // 处理跨域(如果React和Express不在同一端口,必须添加这个配置) app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); // 生产环境建议替换为具体域名 res.header('Access-Control-Allow-Methods', 'POST, GET'); res.header('Access-Control-Allow-Headers', 'Content-Type'); next(); }); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); // 全局变量存储LED实例和闪烁定时器 let ledInstance; let blinkTimer; board.on('ready', () => { console.log('Arduino连接成功!'); // 初始化LED,假设连接在数字引脚13(Arduino自带的LED引脚) ledInstance = new five.Led(13); // 新增API接口:接收客户端传来的间隔值,更新LED闪烁 app.post('/api/update-blink-interval', (req, res) => { const { interval } = req.body; // 验证输入合法性:必须是大于0的数字 if (!interval || typeof interval !== 'number' || interval <= 0) { return res.status(400).json({ success: false, message: '请输入有效的正整数间隔(单位:毫秒)' }); } // 清除旧的闪烁定时器,避免冲突 if (blinkTimer) { clearInterval(blinkTimer); ledInstance.stop(); // 停止当前LED的闪烁状态 } // 启动新的闪烁任务 blinkTimer = setInterval(() => { ledInstance.toggle(); }, interval); res.json({ success: true, currentInterval: interval, message: `LED闪烁间隔已更新为${interval}毫秒` }); }); // 可选:新增接口获取当前闪烁间隔 app.get('/api/current-interval', (req, res) => { res.json({ currentInterval: blinkTimer ? interval : null, isBlinking: !!blinkTimer }); }); const PORT = 3001; app.listen(PORT, () => { console.log(`服务端运行在 http://localhost:${PORT}`); }); }); // 处理Arduino连接错误 board.on('error', (err) => { console.error('Arduino连接失败,请检查设备:', err); });
第二步:React客户端发送请求逻辑
在React组件里,咱们可以做一个简单的输入框+按钮,或者监听输入框实时变化来发送请求。这里以点击按钮更新为例:
import { useState } from 'react'; const LedBlinkController = () => { const [inputInterval, setInputInterval] = useState(1000); // 默认1秒间隔 const [statusMessage, setStatusMessage] = useState(''); // 发送更新请求到服务端 const handleUpdateInterval = async () => { try { const response = await fetch('http://localhost:3001/api/update-blink-interval', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ interval: parseInt(inputInterval) }), }); const result = await response.json(); if (result.success) { setStatusMessage(result.message); } else { setStatusMessage(`错误:${result.message}`); } } catch (error) { setStatusMessage('请求失败,请检查服务端是否运行'); console.error('请求错误:', error); } }; return ( <div style={{ padding: '20px', maxWidth: '400px' }}> <h2>LED闪烁控制器</h2> <div style={{ margin: '15px 0' }}> <label>闪烁间隔(毫秒):</label> <input type="number" value={inputInterval} onChange={(e) => setInputInterval(e.target.value)} min="50" step="50" style={{ marginLeft: '10px', padding: '5px' }} /> </div> <button onClick={handleUpdateInterval} style={{ padding: '8px 16px', cursor: 'pointer' }} > 更新闪烁间隔 </button> {statusMessage && <p style={{ marginTop: '15px', color: '#333' }}>{statusMessage}</p>} </div> ); }; export default LedBlinkController;
关键注意事项
- 硬件连接时机:必须等Johnny-Five的Board触发
ready事件后再初始化LED和API,否则会出现硬件操作失败的错误。 - 跨域问题:如果React运行在默认的3000端口,Express在3001端口,一定要在服务端配置CORS头,或者在React的
package.json里添加代理配置。 - 输入验证:必须对客户端传来的间隔值做合法性检查,避免非数字、负数等非法输入导致程序崩溃。
- 定时器管理:每次更新间隔时一定要清除旧的定时器,否则多个定时器同时运行会让LED闪烁混乱。
内容的提问来源于stack exchange,提问作者Andrei Rosu
相关产品推荐
相关产品推荐

