打造智能家居:用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 实现设备状态的实时更新。项目架构清晰,功能完备,为用户提供了良好的体验。

相关推荐
虾球xz3 分钟前
游戏引擎学习第20天
前端·学习·游戏引擎
Estar.Lee5 分钟前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
我爱李星璇8 分钟前
HTML常用表格与标签
前端·html
疯狂的沙粒12 分钟前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员27 分钟前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐29 分钟前
前端图像处理(一)
前端
程序猿阿伟37 分钟前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
疯狂的沙粒38 分钟前
对 TypeScript 中函数如何更好的理解及使用?与 JavaScript 函数有哪些区别?
前端·javascript·typescript
wenchm1 小时前
细说STM32单片机DMA中断收发RTC实时时间并改善其鲁棒性的另一种方法
stm32·单片机·嵌入式硬件
瑞雨溪1 小时前
AJAX的基本使用
前端·javascript·ajax