目录

打造智能家居:用React、Node.js和WebSocket构建ESP32设备控制面板(代码说明)

一、项目概述

在物联网(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 运行');
});

代码说明

前端代码说明
  1. DeviceList 组件 (DeviceList.js)
  • 用于显示设备列表。

  • props 获取设备数据,并生成设备列表的 HTML 元素。

  1. DeviceControl 组件 (DeviceControl.js)
  • 用于控制设备。

  • 包含设备 ID 和控制指令的输入框,并在表单提交时调用 onControl 函数。

  1. deviceService 模块 (deviceService.js)
  • getDevices 函数:从后端获取设备列表。

  • controlDevice 函数:向后端发送控制设备的指令。

  • subscribeToDeviceUpdates 函数:通过 WebSocket 订阅设备状态更新。

  1. App 组件 (App.js)
  • 主应用组件,管理设备列表和控制操作。

  • 使用 useEffect 钩子在组件挂载时获取设备列表,并订阅设备状态更新。

  • handleControl 函数调用 controlDevice 发送控制指令。

后端代码说明
  1. 设备模型 (Device.js)
  • 定义设备的 Mongoose 模型,包含 namestatus 属性。
  1. 服务器和路由 (server.js)
  • 监听客户端连接和消息,更新设备状态并通知所有客户端。

  • GET /devices:获取所有设备。

  • POST /control/:id:控制指定 ID 的设备,并通过 WebSocket 通知所有客户端。

  • 使用 Express 创建服务器,并连接到 MongoDB 数据库。

五、项目总结

在本项目中,我们构建了一个智能设备控制面板,用户可以通过 Web 应用控制多个 ESP32 设备。项目使用 React 构建前端,用 Node.js 和 Express 搭建后端,使用 MongoDB 存储设备数据,并通过 WebSocket 实现设备状态的实时更新。项目架构清晰,功能完备,为用户提供了良好的体验。

本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
腾讯TNTWeb前端团队6 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰10 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪10 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪10 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy11 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom11 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom11 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom11 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom11 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom12 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试