• 基于物联网的水质监测系统设计与实现:React前端、Node.js后端与TCP/IP协议的云平台集成(代码示例)


    一、项目概述

    随着环境保护意识的增强,水质监测在水资源管理和污染防治中变得尤为重要。本项目旨在设计一个基于物联网的水质监测系统,能够实时监测水中的pH值、溶解氧、电导率和浊度等参数,并将数据传输至云端,以便进行分析和可视化。该系统采用低功耗设计,适合在各种环境中长期稳定工作,具有良好的扩展性和用户友好的界面。

    二、系统架构

    为了满足项目的需求,系统架构选择如下组件和技术:

    • 微控制器:采用 ESP32,具备Wi-Fi和蓝牙功能,支持多任务处理。

    • 传感器:包括pH传感器、溶解氧传感器、电导率传感器和浊度传感器,能够全面监测水质。

    • 通信技术:使用 Wi-Fi 进行数据传输到云端。

    • 数据管理与云服务:选择 AWS IoT 作为云平台,使用 DynamoDB 存储数据。

    • 前端技术:开发 React 前端应用,提供实时监控和数据可视化功能。

    • 后端技术:使用 Node.js 搭建RESTful API,以便与前端和云服务交互。

    系统架构图

    数据采集
    Wi-Fi
    数据存储
    数据分析
    数据可视化
    控制指令
    传感器
    ESP32微控制器
    AWS IoT
    DynamoDB
    数据分析与机器学习
    React前端
    移动应用

    三、环境搭建

    根据系统架构的技术栈,环境搭建的步骤如下:

    1. ESP32开发环境:
    • 安装 Arduino IDE。

    • 在Arduino IDE中添加ESP32开发板支持,依次选择 文件 -> 首选项,在“附加开发板管理器网址”中添加以下链接:

      https://dl.espressif.com/dl/package\_esp32\_index.json
      
    • 进入 工具 -> 开发板 -> 开发板管理器,搜索并安装 ESP32。

    1. AWS IoT 环境:
    • 注册AWS账号,并登录AWS管理控制台。

    • 创建一个 IoT设备,并下载设备证书和密钥。

    • 配置AWS IoT策略,允许设备发布和订阅消息。

    1. Node.js环境:
    • 在本地机器上安装 Node.js。

    • 使用npm初始化项目:

      mkdir water_quality_monitoring
      cd water_quality_monitoring
      npm init -y    
      
    • 安装所需依赖:

      npm install express aws-sdk body-parser cors
      
    1. 前端环境:
    • 使用 create-react-app 创建React项目:

      npx create-react-app water-quality-frontend
      cd water-quality-frontend
      

    四、代码实现

    在这一部分,我们将实现水质监测系统的代码,涵盖ESP32微控制器的数据采集和传输、Node.js后端API的实现以及React前端应用的基本结构。

    1. ESP32微控制器代码

    代码示例

    以下是ESP32的代码示例,用于读取传感器数据并将其发送到AWS IoT。代码中包含读取pH传感器、溶解氧传感器、电导率传感器和浊度传感器的逻辑。

    #include 
    #include 
    #include 
    
    // Wi-Fi配置
    const char* ssid = "your_SSID";  // Wi-Fi名称
    const char* password = "your_PASSWORD";  // Wi-Fi密码
    
    // AWS IoT配置
    const char* host = "your_aws_iot_endpoint";  // AWS IoT端点
    const char* thingName = "your_thing_name";  // IoT设备名称
    const char* privateKey = "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n";  // 私钥
    const char* certificate = "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n";  // 证书
    
    AWS_IOT awsIot;
    
    // 假设传感器连接在模拟引脚
    const int pHSensorPin = 34;  // pH传感器引脚
    const int doSensorPin = 35;  // 溶解氧传感器引脚
    const int ecSensorPin = 32;   // 电导率传感器引脚
    const int turbiditySensorPin = 33;  // 浊度传感器引脚
    
    void setup() {
        Serial.begin(115200);
        WiFi.begin(ssid, password);
        
        // 连接到Wi-Fi
        while (WiFi.status() != WL_CONNECTED) {
            delay(1000);
            Serial.println("Connecting to WiFi...");
        }
        Serial.println("Connected to WiFi");
    
        // 连接到AWS IoT
        awsIot.begin(host, thingName, privateKey, certificate);
    }
    
    void loop() {
        // 读取传感器数据
        float pH = readPHSensor();
        float doValue = readDOSensor();
        float ecValue = readECSensor();
        float turbidity = readTurbiditySensor();
    
        // 打印到串口
        Serial.printf("pH: %.2f, DO: %.2f mg/L, EC: %.2f µS/cm, Turbidity: %.2f NTU\n", pH, doValue, ecValue, turbidity);
    
        // 创建JSON字符串
        String payload = String("{\"pH\":") + pH + ",\"DO\":" + doValue + ",\"EC\":" + ecValue + ",\"Turbidity\":" + turbidity + "}";
    
        // 发布到AWS IoT
        awsIot.publish("water_quality_data", payload.c_str());
    
        delay(60000);  // 每60秒发送一次数据
    }
    
    // 读取pH传感器的函数
    float readPHSensor() {
        // 模拟读取传感器值,实际应用中应替换为真实读取逻辑
        return analogRead(pHSensorPin) * (5.0 / 1023.0); // 示例转换
    }
    
    // 读取溶解氧传感器的函数
    float readDOSensor() {
        // 模拟读取传感器值
        return analogRead(doSensorPin) * (5.0 / 1023.0); // 示例转换
    }
    
    // 读取电导率传感器的函数
    float readECSensor() {
        // 模拟读取传感器值
        return analogRead(ecSensorPin) * (5.0 / 1023.0); // 示例转换
    }
    
    // 读取浊度传感器的函数
    float readTurbiditySensor() {
        // 模拟读取传感器值
        return analogRead(turbiditySensorPin) * (5.0 / 1023.0); // 示例转换
    }
    
    代码说明
    1. Wi-Fi连接:
    • 使用WiFi.begin(ssid, password)连接到指定的Wi-Fi网络,使用循环检查连接状态。
    1. AWS IoT连接:
    • 使用awsIot.begin(...)初始化与AWS IoT的连接,传入设备的端点、名称、私钥和证书。
    1. 数据采集:
    • loop() 函数中,调用 readPHSensor()readDOSensor()readECSensor()readTurbiditySensor() 函数以读取各个传感器的值。这些函数将模拟读取的传感器值转换为相应的实际数值,示例中使用了一个简单的线性转换公式(实际应用中应根据传感器特性进行相应调整)。
    1. 数据格式化:
    • 使用 String payload 创建一个 JSON 字符串,包含 pH、溶解氧 (DO)、电导率 (EC) 和浊度 (Turbidity) 的数据。这个 JSON 字符串将被发送到 AWS IoT。
    1. 数据发布:
    • 使用 awsIot.publish("water_quality_data", payload.c_str()) 将格式化后的数据发布到指定的主题 "water_quality_data"。此主题可以在 AWS IoT 控制台中用于监控和分析数据。
    1. 数据发送频率:
    • 使用 delay(60000) 设置每次数据发送之间的间隔为 60 秒。根据需要,可以调整这个时间以满足项目的需求。

    2. Node.js 后端 API 实现

    为了处理来自 ESP32 的数据,我们需要在 Node.js 中创建一个简单的 RESTful API。该 API 将接收来自 AWS IoT 的数据并存储到 DynamoDB。

    代码示例

    以下是 Node.js 后端代码的示例:

    const express = require('express');
    const bodyParser = require('body-parser');
    const AWS = require('aws-sdk');
    const cors = require('cors');
    
    const app = express();
    const port = 3000;
    
    // AWS DynamoDB配置
    AWS.config.update({
        region: 'us-east-1', // 替换为您的区域
        accessKeyId: 'your_access_key_id',
        secretAccessKey: 'your_secret_access_key'
    });
    
    const dynamoDB = new AWS.DynamoDB.DocumentClient();
    const tableName = 'WaterQualityData'; // DynamoDB表名
    
    app.use(cors()); // 允许跨域请求
    app.use(bodyParser.json()); // 解析JSON请求体
    
    // 接收来自ESP32的数据
    app.post('/data', (req, res) => {
        const { pH, DO, EC, Turbidity } = req.body;
    
        const params = {
            TableName: tableName,
            Item: {
                id: Date.now(), // 使用时间戳作为唯一ID
                pH: pH,
                DO: DO,
                EC: EC,
                Turbidity: Turbidity,
                timestamp: new Date().toISOString() // 添加时间戳
            }
        };
    
        dynamoDB.put(params, (err) => {
            if (err) {
                console.error("Unable to add item. Error JSON:", JSON.stringify(err, null, 2));
                res.status(500).send("Error saving data");
            } else {
                console.log("Added item:", JSON.stringify(params.Item, null, 2));
                res.status(200).send("Data saved successfully");
            }
        });
    });
    
    app.listen(port, () => {
        console.log(`Server running at http://localhost:${port}`);
    });
    
    代码说明
    1. 依赖模块:
    • 使用 express 创建一个简单的 HTTP 服务器,使用 body-parser 解析 JSON 格式的请求体,使用 cors 处理跨域请求。
    1. AWS SDK配置:
    • 使用 AWS.config.update 设置 AWS 区域和访问密钥,使用 DynamoDB.DocumentClient 连接到 DynamoDB。
    1. POST路由:
    • 定义一个 /data POST 路由,该路由接收 ESP32 发送的水质数据。在路由中,提取请求体中的 pH、DO、EC、Turbidity 数据。
    1. 数据存储:
    • 使用 dynamoDB.put() 方法将接收到的数据存储到 DynamoDB 表中。每个数据项包含一个唯一的 ID(使用当前时间戳)和传感器读取值以及时间戳。
    1. 错误处理:
    • 如果存储数据时出现错误,返回 500 状态码并发送错误信息;如果成功,返回 200 状态码并发送成功消息。

    3. React 前端应用

    前端部分将使用 React 框架开发一个用户界面,允许用户查看水质监测数据。

    代码示例
    // src/App.js
    import React, { useEffect, useState } from 'react';
    import axios from 'axios';
    import './App.css';
    
    function App() {
        const [data, setData] = useState([]);
        const [error, setError] = useState('');
    
        useEffect(() => {
            const fetchData = async () => {
                try {
                    const response = await axios.get('http://localhost:3000/data'); // 假设有一个GET接口返回数据
                    setData(response.data);
                } catch (err) {
                    setError('Error fetching data');
                    console.error(err);
                }
            };
    
            fetchData();
            const interval = setInterval(fetchData, 60000); // 每60秒刷新一次数据
            return () => clearInterval(interval); // 清理定时器
        }, []);
    
        return (
            <div className="App">
                <h1>水质监测数据</h1>
                {error && <p>{error}</p>}
                <table>
                    <thead>
                        <tr>
                            <th>时间</th>
                            <th>pH值</th>
                            <th>溶解氧 (DO)</th>
                            <th>电导率 (EC)</th>
                            <th>浊度</th>
                        </tr>
                    </thead>
                    <tbody>
                        {data.map((item) => (
                            <tr key={item.id}>
                                <td>{item.timestamp}</td>
                                <td>{item.pH}</td>
                                <td>{item.DO}</td>
                                <td>{item.EC}</td>
                                <td>{item.Turbidity}</td>
                            </tr>
                        ))}
                    </tbody>
                </table>
            </div>
        );
    }
    
    export default App;
    
    代码说明
    1. 状态管理:
    • 使用 useState 钩子管理 dataerror 状态。data 用于存储水质监测数据,error 用于存储错误信息。
    1. 数据获取:
    • 使用 useEffect 钩子在组件挂载时和每次更新时获取数据。通过 axios 库发送 GET 请求到 /data 接口(假设后端实现了这个接口以获取存储的数据)。

    • 每60秒调用一次 fetchData 函数,以确保数据保持最新。

    1. 错误处理:
    • 如果请求失败,设置错误状态,显示错误信息。
    1. 数据展示:
    • 使用 HTML 表格展示水质监测数据,表头包括时间、pH值、溶解氧 (DO)、电导率 (EC) 和浊度。

    • 使用 map() 方法遍历 data 数组,生成表格行,显示每个数据项的详细信息。

    1. 样式:
    • src/App.css 中可以添加样式以美化界面,例如:
    .App {
        text-align: center;
        margin: 20px;
    }
    table {
        margin: 0 auto;
        border-collapse: collapse;
        width: 80%;
    }
    th, td {
        border: 1px solid #ddd;
        padding: 8px;
    }
    th {
        background-color: #f2f2f2;
    }
    

    4. 数据可视化

    为了使数据更具可读性和可视化,可以使用 Chart.js 库绘制图表。以下是如何在上述应用中添加图表的示例:

    安装依赖
    npm install chart.js react-chartjs-2
    

    更新代码示例以添加图表

    下面的代码将绘制 pH 值、溶解氧 (DO)、电导率 (EC) 和浊度的折线图,使用 Chart.js 来可视化数据。

    完整代码示例
    // src/App.js
    import React, { useEffect, useState } from 'react';
    import axios from 'axios';
    import { Line } from 'react-chartjs-2';
    import './App.css';
    
    function App() {
        const [data, setData] = useState([]);
        const [error, setError] = useState('');
    
        useEffect(() => {
            const fetchData = async () => {
                try {
                    const response = await axios.get('http://localhost:3000/data'); // 假设有一个GET接口返回数据
                    setData(response.data);
                } catch (err) {
                    setError('Error fetching data');
                    console.error(err);
                }
            };
    
            fetchData();
            const interval = setInterval(fetchData, 60000); // 每60秒刷新一次数据
            return () => clearInterval(interval); // 清理定时器
        }, []);
    
        // 准备图表数据
        const chartData = {
            labels: data.map(item => item.timestamp), // X轴为时间戳
            datasets: [
                {
                    label: 'pH值',
                    data: data.map(item => item.pH),
                    borderColor: 'rgba(75,192,192,1)',
                    backgroundColor: 'rgba(75,192,192,0.2)',
                    fill: true,
                },
                {
                    label: '溶解氧 (DO)',
                    data: data.map(item => item.DO),
                    borderColor: 'rgba(255,99,132,1)',
                    backgroundColor: 'rgba(255,99,132,0.2)',
                    fill: true,
                },
                {
                    label: '电导率 (EC)',
                    data: data.map(item => item.EC),
                    borderColor: 'rgba(54,162,235,1)',
                    backgroundColor: 'rgba(54,162,235,0.2)',
                    fill: true,
                },
                {
                    label: '浊度',
                    data: data.map(item => item.Turbidity),
                    borderColor: 'rgba(255,206,86,1)',
                    backgroundColor: 'rgba(255,206,86,0.2)',
                    fill: true,
                },
            ],
        };
    
        return (
            <div className="App">
                <h1>水质监测数据</h1>
                {error && <p>{error}</p>}
                <div>
                    <h2>水质监测趋势</h2>
                    <Line data={chartData} />
                </div>
                <table>
                    <thead>
                        <tr>
                            <th>时间</th>
                            <th>pH值</th>
                            <th>溶解氧 (DO)</th>
                            <th>电导率 (EC)</th>
                            <th>浊度</th>
                        </tr>
                    </thead>
                    <tbody>
                        {data.map((item) => (
                            <tr key={item.id}>
                                <td>{item.timestamp}</td>
                                <td>{item.pH}</td>
                                <td>{item.DO}</td>
                                <td>{item.EC}</td>
                                <td>{item.Turbidity}</td>
                            </tr>
                        ))}
                    </tbody>
                </table>
            </div>
        );
    }
    
    export default App;
    

    代码说明

    1. 引入 Chart.js:
    • 使用 import { Line } from 'react-chartjs-2' 引入折线图组件,允许在应用中绘制图表。
    1. 准备图表数据:
    • 每个数据集都有 label(图例名称)、data(数据点数组)、borderColor(线条颜色)、backgroundColor(填充颜色)和 fill(是否填充区域)属性。

    • 在组件中创建 chartData 对象,该对象包含 labelsdatasets

    • labels 使用时间戳作为 X 轴的标签。

    • datasets 是一个数组,包含不同传感器数据的配置:

    1. 渲染图表:
    • 使用 组件在应用中渲染图表,显示水质监测数据的趋势。

    五、项目总结

    本项目设计并实现了一个基于物联网的水质监测系统,旨在实时监测和分析水质参数,以帮助用户及时了解水质状况。通过使用 ESP32 微控制器、多个水质传感器、云服务以及前端可视化技术,系统具备以下几个关键特点:

    1. 实时数据监测:
    • 系统能够实时收集水中的 pH 值、溶解氧、电导率和浊度等重要水质参数。通过编写驱动程序,ESP32 能够稳定地读取传感器数据,并将其通过 Wi-Fi 发送到 AWS IoT 平台。
    1. 数据存储与分析:
    • 通过与 AWS IoT 和 DynamoDB 的结合,系统实现了数据的安全存储和高效管理。后端使用 Node.js 提供 RESTful API,使得数据的接收和存储变得更加灵活可靠。
    1. 可视化用户界面:
    • 前端使用 React 框架开发,提供用户友好的界面,允许用户查看水质数据的历史记录和实时趋势。使用 Chart.js 库进行数据可视化,使得数据更加直观,方便用户进行分析和决策。
    1. 低功耗设计:
    • 系统设计时考虑了低功耗需求,ESP32 的使用使得设备能够长期运行在电池供电或太阳能供电的情况下,适用于各种环境。
    1. 扩展性与适应性:
    • 系统架构具有良好的扩展性,可以根据实际需求添加新的传感器或功能模块。同时,设备设计考虑了防水和耐腐蚀特性,适应水质监测的实际应用场景。
    1. 安全性:
    • 在数据传输过程中实现了数据加密和身份验证,确保系统的安全性和用户隐私。

    未来工作方向

    尽管本项目已实现基本功能,但仍有若干改进和扩展的方向:

    • 增加更多传感器:可以考虑增加新的传感器,例如温度传感器、氨氮传感器等,以提供更全面的水质监测能力。

    • 数据分析与机器学习:通过对历史数据进行分析,利用机器学习算法进行异常检测和预测,帮助用户提前预警水质问题。

    • 移动应用开发:开发移动端应用,让用户可以随时随地监控水质数据并接收预警信息。

  • 相关阅读:
    jvm参数设置方法(win10)
    HR人才测评,什么是全局观念?如何测评全局观念?
    opencv dnn模块 示例(18) 目标检测 object_detection 之 pp-yolo、pp-yolov2和pp-yolo tiny
    详解Kafka 3.0 稳定版新特性
    JavaWeb项目(登录注册页面)全过程详细总结
    Java8-Java16部分重要新特性汇总
    百川的大模型KnowHow
    【前端】使用promise解决地狱回调问题
    React 基础使用
    DDR3笔记 频率配置
  • 原文地址:https://blog.csdn.net/qq_40431685/article/details/141024035