一、项目概述
在物联网(IoT)时代,智能设备的远程控制变得越来越重要。本文介绍了一个构建智能设备控制面板的项目,允许用户通过 Web 应用来控制多个 ESP32 设备。用户可以通过该面板查看设备列表,实时了解设备状态,并对设备进行操作(例如开关、调节亮度等)。
二、系统架构
为了满足项目需求,我们设计了一套系统架构,包括前端、后端、数据库和通信协议,如下图所示:
用户 前端 后端 数据库 ESP32 设备
1. 单片机和设备
-
单片机:ESP32
-
设备:智能灯光、智能插座等
2. 通信协议
-
WebSocket:用于实时通信,保证设备状态的实时更新
-
RESTful API:用于设备的管理操作
3. 技术栈
-
前端:React、Vue.js 或 Angular(本文选择 React)
-
后端:Node.js、Flask 或 Django(本文选择 Node.js)
-
数据库:MongoDB 或 Firebase(本文选择 MongoDB)
三、环境搭建
1. 前端环境
安装 React 开发环境:
bash
npx create-react-app smart-device-control-panel
cd smart-device-control-panel
npm start
2. 后端环境
安装 Node.js 和 Express:
bash
mkdir backend
cd backend
npm init -y
npm install express mongoose body-parser ws
3. 数据库环境
安装 MongoDB:
bash
# 对于 macOS 用户
brew tap mongodb/brew
brew install mongodb-community@5.0
# 启动 MongoDB
brew services start mongodb/brew/mongodb-community
四、代码实现
1. 前端代码
在 src
目录下创建组件和服务,主要包括设备列表管理、设备控制和实时状态更新。
设备列表组件
DeviceList
组件用于显示所有设备的列表。
js
// src/components/DeviceList.js
import React from 'react';
function DeviceList({ devices }) {
return (
<div>
<h2>设备列表</h2>
<ul>
{devices.map((device) => (
<li key={device.id}>
{device.name} - {device.status}
</li>
))}
</ul>
</div>
);
}
export default DeviceList;
设备控制组件
DeviceControl
组件用于控制设备的状态。
js
// src/components/DeviceControl.js
import React, { useState } from 'react';
function DeviceControl({ onControl }) {
const [deviceId, setDeviceId] = useState('');
const [command, setCommand] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
if (deviceId && command) {
onControl(deviceId, command);
}
};
return (
<div>
<h2>设备控制</h2>
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="deviceId">设备 ID:</label>
<input
type="text"
id="deviceId"
value={deviceId}
onChange={(e) => setDeviceId(e.target.value)}
/>
</div>
<div>
<label htmlFor="command">指令:</label>
<input
type="text"
id="command"
value={command}
onChange={(e) => setCommand(e.target.value)}
/>
</div>
<button type="submit">发送</button>
</form>
</div>
);
}
export default DeviceControl;
服务模块
deviceService
模块用于与后端进行通信。
js
// src/services/deviceService.js
const API_URL = 'http://localhost:3000';
export async function getDevices() {
const response = await fetch(`${API_URL}/devices`);
return response.json();
}
export async function controlDevice(id, command) {
await fetch(`${API_URL}/control/${id}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ command }),
});
}
export function subscribeToDeviceUpdates(callback) {
const ws = new WebSocket('ws://localhost:8080');
ws.onmessage = (event) => {
const device = JSON.parse(event.data);
callback(device);
};
}
主应用组件
App
组件是主应用组件,负责管理设备列表和控制操作。
js
// src/App.js
import React, { useState, useEffect } from 'react';
import DeviceList from './components/DeviceList';
import DeviceControl from './components/DeviceControl';
import { getDevices, controlDevice, subscribeToDeviceUpdates } from './services/deviceService';
function App() {
const [devices, setDevices] = useState([]);
useEffect(() => {
getDevices().then(setDevices);
subscribeToDeviceUpdates((updatedDevice) => {
setDevices((prevDevices) =>
prevDevices.map((device) => (device.id === updatedDevice.id ? updatedDevice : device))
);
});
}, []);
const handleControl = (id, command) => {
controlDevice(id, command);
};
return (
<div className="App">
<DeviceList devices={devices} />
<DeviceControl onControl={handleControl} />
</div>
);
}
export default App;
2. 后端代码
在 backend
目录下创建服务器和路由,处理设备管理和控制请求。
设备模型
Device
模型定义设备的结构。
js
// backend/models/Device.js
const mongoose = require('mongoose');
const deviceSchema = new mongoose.Schema({
name: String,
status: String,
});
module.exports = mongoose.model('Device', deviceSchema);
服务器和路由
server.js
文件设置服务器,处理设备列表和控制请求,并通过 WebSocket 实现实时状态更新。
js
// backend/server.js
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const WebSocket = require('ws');
const Device = require('./models/Device');
const app = express();
const wss = new WebSocket.Server({ port: 8080 });
app.use(bodyParser.json());
// RESTful API
app.get('/devices', async (req, res) => {
const devices = await Device.find();
res.json(devices);
});
app.post('/control/:id', async (req, res) => {
const { id } = req.params;
const { command } = req.body;
// 发送控制命令给设备
// 这里可以通过与 ESP32 设备通信的特定实现来发送命令
const device = await Device.findById(id);
if (device) {
// 更新设备状态逻辑
device.status = command.status; // 假设 command 包含 status 属性
await device.save();
// 通知所有 WebSocket 客户端
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(device));
}
});
res.sendStatus(200);
} else {
res.sendStatus(404);
}
});
// WebSocket
wss.on('connection', (ws) => {
ws.on('message', (message) => {
const { id, status } = JSON.parse(message);
Device.findByIdAndUpdate(id, { status }, { new: true }, (err, device) => {
if (err) return;
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(device));
}
});
});
});
});
app.listen(3000, () => {
console.log('后端服务器在 http://localhost:3000 运行');
});
代码说明
前端代码说明
- DeviceList 组件 (
DeviceList.js
)
-
用于显示设备列表。
-
从
props
获取设备数据,并生成设备列表的 HTML 元素。
- DeviceControl 组件 (
DeviceControl.js
)
-
用于控制设备。
-
包含设备 ID 和控制指令的输入框,并在表单提交时调用
onControl
函数。
- deviceService 模块 (
deviceService.js
)
-
getDevices
函数:从后端获取设备列表。 -
controlDevice
函数:向后端发送控制设备的指令。 -
subscribeToDeviceUpdates
函数:通过 WebSocket 订阅设备状态更新。
- App 组件 (
App.js
)
-
主应用组件,管理设备列表和控制操作。
-
使用
useEffect
钩子在组件挂载时获取设备列表,并订阅设备状态更新。 -
handleControl
函数调用controlDevice
发送控制指令。
后端代码说明
- 设备模型 (
Device.js
)
- 定义设备的 Mongoose 模型,包含
name
和status
属性。
- 服务器和路由 (
server.js
)
-
监听客户端连接和消息,更新设备状态并通知所有客户端。
-
GET /devices
:获取所有设备。 -
POST /control/:id
:控制指定 ID 的设备,并通过 WebSocket 通知所有客户端。 -
使用 Express 创建服务器,并连接到 MongoDB 数据库。
五、项目总结
在本项目中,我们构建了一个智能设备控制面板,用户可以通过 Web 应用控制多个 ESP32 设备。项目使用 React 构建前端,用 Node.js 和 Express 搭建后端,使用 MongoDB 存储设备数据,并通过 WebSocket 实现设备状态的实时更新。项目架构清晰,功能完备,为用户提供了良好的体验。