Raspberry Pi传感器数据采集与可视化系统

Raspberry Pi传感器数据采集与可视化系统

Raspberry Pi传感器数据采集与可视化系统

内容简介

本文将详细介绍如何利用Raspberry Pi(树莓派)搭建一套完整的环境监测系统。我们将集成DHT22温湿度传感器与BMP280气压温度传感器,深入解析其通信协议与驱动编写。在软件层面,我们将使用Python的Pandas库构建高效的数据存储管道,并利用Matplotlib进行本地数据分析,最终结合Plotly与Dash框架打造一个实时的Web可视化仪表盘,实现数据的远程监控与交互。


第一章:项目背景与系统架构设计

1.1 物联网时代的边缘计算

随着物联网技术的飞速发展,边缘计算设备在数据采集领域的地位日益重要。Raspberry Pi作为一款信用卡大小的单板计算机,凭借其强大的计算能力、丰富的GPIO接口以及庞大的社区支持,成为了物联网项目的首选核心平台。在实际应用中,环境数据的采集(如温度、湿度、气压)是智能家居、农业自动化以及工业监控的基础。

1.2 项目目标

本项目的核心目标是构建一个闭环的监测系统,具体包括:

  1. 感知层:通过I2C和单总线协议驱动传感器硬件。
  2. 数据处理层:使用Python进行数据清洗、格式化,并利用Pandas进行结构化存储。
  3. 应用层:提供两种可视化方案,一是基于Matplotlib的静态分析报表,二是基于Plotly的实时Web监控界面。

1.3 系统整体架构

系统采用分层架构设计,确保各模块解耦,便于维护与扩展。

  • 硬件层
    • 主控:Raspberry Pi 4B (或3B+/Zero W)。
    • 传感器组:DHT22(温湿度)、BMP280(气压/温度)。
    • 连接:面包板、杜邦线、上拉电阻。
  • 驱动层
    • 使用Python标准库 ctypes 或成熟的第三方库(如Adafruit CircuitPython)与硬件通信。
  • 数据层
    • 内存缓存:使用List或Queue暂存实时数据。
    • 持久化:CSV文件存储(轻量级),Pandas DataFrame作为中间处理介质。
  • 表现层
    • 本地脚本:Matplotlib生成历史趋势图。
    • Web服务:Flask/Dash框架提供HTTP服务,前端使用Plotly.js渲染动态图表。

第二章:硬件准备与底层原理深度解析

在编写代码之前,深入理解硬件特性与通信协议是确保数据采集稳定性的关键。

2.1 核心控制器:Raspberry Pi GPIO

树莓派的GPIO(通用输入输出)引脚是连接物理世界的桥梁。本项目中,我们将主要使用以下引脚:

  • 3.3V Power (Pin 1/17):为传感器供电。注意BMP280和DHT22通常工作在3.3V,切勿接5V以免烧毁。
  • Ground (Pin 6/9/14...):公共地。
  • GPIO 4 (Pin 7):用于连接DHT22数据引脚(可自定义)。
  • GPIO 2 (SDA) / GPIO 3 (SCL):I2C总线的数据线与时钟线,用于连接BMP280。

2.2 温湿度传感器:DHT22 (AM2302)

DHT22是一款含有已校准数字信号输出的温湿度复合传感器。

技术规格
  • 湿度测量范围:0-100% RH(精度±2%RH)。
  • 温度测量范围:-40~80℃(精度±0.5℃)。
  • 通信协议:单总线。
通信时序详解

DHT22使用的是专有的单总线协议,对时序要求极为严格。

  1. 主机发起起始信号:GPIO配置为输出模式,拉低电平至少1ms(通常建议18ms),然后拉高20-40微秒。
  2. 等待响应:GPIO配置为输入模式。DHT22会拉低电平80微秒,再拉高80微秒作为响应信号。
  3. 数据传输 :数据共40位(16位湿度+16位温度+8位校验和)。
    • '0'信号:低电平50us + 高电平26-28us。
    • '1'信号:低电平50us + 高电平70us。

由于Linux内核并非实时操作系统(非RTOS),直接使用Python的time.sleep()控制微秒级延时往往不够精准,容易导致读取失败。因此,通常推荐使用C语言编写底层驱动或使用pigpio库的波(Wave)功能来确保时序的准确性。

2.3 气压温度传感器:BMP280

BMP280是博世推出的绝对气压传感器,专为移动应用设计,通过I2C或SPI接口通信。

技术规格
  • 气压测量范围:300~1100 hPa。
  • 温度测量范围:-40~85℃。
  • 接口:I2C(地址0x76或0x77)。
I2C通信原理

I2C(Inter-Integrated Circuit)是一种两线式串行总线。

  • SDA (Serial Data):双向数据线。
  • SCL (Serial Clock) :时钟线。
    树莓派内部集成了I2C控制器,通过开启内核模块(dtparam=i2c_arm=on),我们可以直接在Linux文件系统中访问I2C设备。BMP280内部有寄存器映射表,我们需要读取其校准参数,然后读取原始的气压和温度数据,最后根据数据手册提供的公式进行补偿计算。

第三章:开发环境搭建与系统配置

3.1 操作系统初始化

假设我们使用Raspberry Pi OS (64-bit)。

  1. 启用接口 :使用 sudo raspi-config 进入配置界面,在 "Interface Options" 中启用 I2C 和 SSH。

  2. 更新系统

    bash 复制代码
    sudo apt-get update
    sudo apt-get upgrade -y

3.2 Python环境与依赖库安装

为了保持环境整洁,建议使用Python虚拟环境。

bash 复制代码
# 安装系统级依赖(用于构建Python扩展库)
sudo apt-get install python3-dev python3-pip libatlas-base-dev

# 创建项目目录
mkdir ~/sensor_system
cd ~/sensor_system

# 创建并激活虚拟环境
python3 -m venv venv
source venv/bin/activate

# 安装核心库
pip install pandas matplotlib plotly dash adafruit-circuitpython-dht adafruit-circuitpython-bmp280 board
  • Pandas:数据分析神器,用于处理时间序列数据。
  • Matplotlib:Python绘图库的基石。
  • Plotly/Dash:用于构建交互式Web应用。
  • Adafruit CircuitPython:Adafruit提供的硬件驱动库,极大地简化了底层操作,比直接操作寄存器更稳定且跨平台。

3.3 验证硬件连接

在编写主程序前,需确认I2C设备已被识别。

bash 复制代码
sudo i2cdetect -y 1

如果BMP280接线正确,输出矩阵中应显示 7677 的字样。DHT22由于是单总线,无法通过此命令检测,需通过代码测试。


第四章:传感器驱动编写与数据采集模块

我们将采用面向对象的设计模式,封装传感器类,提高代码的复用性。

4.1 DHT22驱动封装

虽然可以直接操作GPIO,但为了稳定性,我们使用Adafruit库。该库底层使用了pigpio的守护进程,能极大降低读取错误率。

python 复制代码
import time
import board
import adafruit_dht

class DHT22Sensor:
    def __init__(self, pin=board.D4):
        """
        初始化DHT22传感器
        :param pin: GPIO引脚,默认为D4 (物理引脚7)
        """
        self.sensor = adafruit_dht.DHT22(pin)
        self.last_measurement = None

    def read_data(self):
        """
        读取温湿度数据
        :return: (temperature, humidity) 或
        """
        try:
            temperature = self.sensor.temperature
            humidity = self.sensor.humidity

            # 简单的数据有效性检查
            if humidity is not None and temperature is not None:
                self.last_measurement = (temperature, humidity)
                return temperature, humidity
            else:
                return None, None

        except RuntimeError as error:
            # DHT传感器读取失败很常见,通常是因为时序问题
            print(f"读取DHT22出错: {error.args[0]}")
            # 返回上一次的有效数据或None
            if self.last_measurement:
                return self.last_measurement
            return None, None
        except Exception as error:
            print(f"DHT22严重错误: {error}")
            raise error

# 测试代码
if __name__ == "__main__":
    dht = DHT22Sensor()
    for i in range(5):
        t, h = dht.read_data()
        print(f"DHT22 - 温度: {t:.1f}C, 湿度: {h:.1f}%")
        time.sleep(2)

4.2 BMP280驱动封装

BMP280通过I2C通信,我们需要读取其校准系数并进行浮点运算。

python 复制代码
import board
import busio
import adafruit_bmp280

class BMP280Sensor:
    def __init__(self, address=0x76):
        """
        初始化BMP280
        :param address: I2C地址,通常为0x76或0x77
        """
        i2c = busio.I2C(board.SCL, board.SDA)
        try:
            self.sensor = adafruit_bmp280.Adafruit_BMP280_I2C(i2c, address=address)
            # 配置采样率等参数(可选)
            self.sensor.sea_level_pressure = 1013.25 # 设置海平面气压用于计算海拔
        except ValueError:
            print("未找到BMP280传感器,请检查连线或地址!")
            self.sensor = None

    def read_data(self):
        """
        读取气压和温度
        :return: (temperature, pressure, altitude)
        """
        if self.sensor is None:
            return None, None, None

        try:
            temperature = self.sensor.temperature
            pressure = self.sensor.pressure
            altitude = self.sensor.altitude
            return temperature, pressure, altitude
        except Exception as e:
            print(f"读取BMP280出错: {e}")
            return None, None, None

# 测试代码
if __name__ == "__main__":
    bmp = BMP280Sensor()
    t, p, a = bmp.read_data()
    print(f"BMP280 - 温度: {t:.1f}C, 气压: {p:.1f}hPa, 海拔: {a:.1f}m")

4.3 统一数据采集服务

现在,我们需要将两个传感器整合,并生成带有时间戳的数据记录。

python 复制代码
import time
from datetime import datetime

class SensorService:
    def __init__(self):
        self.dht = DHT22Sensor()
        self.bmp = BMP280Sensor()

    def collect_sample(self):
        """
        采集一次样本
        :return: 包含所有传感器数据的字典
        """
        # 读取DHT22
        dht_temp, dht_hum = self.dht.read_data()

        # 读取BMP280
        bmp_temp, bmp_pressure, bmp_alt = self.bmp.read_data()

        # 创建时间戳
        timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')

        # 构建数据字典
        record = {
            'timestamp': timestamp,
            'dht_temp': dht_temp,
            'dht_humidity': dht_hum,
            'bmp_temp': bmp_temp,
            'bmp_pressure': bmp_pressure,
            'bmp_altitude': bmp_alt
        }

        return record

# 模拟采集
if __name__ == "__main__":
    service = SensorService()
    while True:
        data = service.collect_sample()
        print(data)
        time.sleep(5)

第五章:基于Pandas的数据存储与管理

采集到的原始数据如果不进行管理,将毫无价值。Pandas是处理此类结构化数据的最佳工具。

5.1 数据模型设计

我们将创建一个DataFrame来存储数据。索引为时间戳,列为各个传感器读数。

5.2 数据存储管理器类

为了防止内存溢出,我们不会将所有数据一直保存在内存中,而是定期写入CSV文件。

python 复制代码
import pandas as pd
import os
from datetime import datetime

class DataManager:
    def __init__(self, file_path='sensor_data.csv'):
        self.file_path = file_path
        self.columns = ['timestamp', 'dht_temp', 'dht_humidity', 'bmp_temp', 'bmp_pressure', 'bmp_altitude']

        # 如果文件不存在,创建并写入表头
        if not os.path.exists(self.file_path):
            df_init = pd.DataFrame(columns=self.columns)
            df_init.to_csv(self.file_path, index=False)
            print(f"已创建数据文件: {self.file_path}")

    def save_record(self, record):
        """
        将单条记录追加到CSV文件
        """
        # 将字典转换为DataFrame
        df_new = pd.DataFrame([record])

        # 追加模式写入CSV
        df_new.to_csv(self.file_path, mode='a', header=False, index=False)

    def load_recent_data(self, minutes=30):
        """
        加载最近N分钟的数据用于绘图
        """
        if not os.path.exists(self.file_path):
            return pd.DataFrame(columns=self.columns)

        # 读取CSV,解析时间戳
        try:
            df = pd.read_csv(self.file_path, parse_dates=['timestamp'])
        except pd.errors.EmptyDataError:
            return pd.DataFrame(columns=self.columns)

        # 过滤最近时间的数据
        cutoff = datetime.now() - pd.Timedelta(minutes=minutes)
        recent_df = df[df['timestamp'] > cutoff]

        return recent_df

# 测试数据管理
if __name__ == "__main__":
    manager = DataManager()
    # 模拟一条数据
    fake_data = {
        'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        'dht_temp': 25.5,
        'dht_humidity': 60.2,
        'bmp_temp': 25.3,
        'bmp_pressure': 1012.5,
        'bmp_altitude': 50.0
    }
    manager.save_record(fake_data)
    print("数据已保存。")
    print(manager.load_recent_data(1))

5.3 数据清洗与预处理

在实际应用中,传感器数据常包含噪声(如DHT22偶尔会返回None或异常值)。Pandas提供了强大的清洗功能:

  • 缺失值处理df.fillna(method='ffill') 使用前向填充来处理偶发的读取失败。
  • 异常值过滤:例如,如果温度读数突然跳变到85度(DHT系列传感器常见的错误码),应将其剔除。
python 复制代码
def clean_data(self, df):
    # 剔除无效温度值 (假设正常范围 -20 到 50)
    df = df[(df['dht_temp'] > -20) & (df['dht_temp'] < 50)]
    # 前向填充缺失值
    df.fillna(method='ffill', inplace=True)
    return df

第六章:数据可视化方案一------Matplotlib静态绘图

Matplotlib适合用于生成历史报表或离线分析图表。我们可以编写一个脚本,定期生成PNG图片并保存,或者通过邮件发送。

6.1 绘图逻辑

我们需要绘制双Y轴图表:左轴表示温度(℃),右轴表示湿度(%)和气压。

python 复制代码
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

class Plotter:
    def __init__(self, data_manager):
        self.manager = data_manager

    def generate_history_plot(self, output_file='history_plot.png', hours=24):
        # 加载过去24小时的数据
        minutes = hours * 60
        df = self.manager.load_recent_data(minutes)

        if df.empty:
            print("无数据可绘图")
            return

        # 设置中文字体支持(如果系统安装了中文字体)
        plt.rcParams['font.sans-serif'] = ['SimHei'] # 或者 'WenQuanYi Micro Hei' on Linux
        plt.rcParams['axes.unicode_minus'] = False

        fig, ax1 = plt.subplots(figsize=(12, 6))

        # 绘制温度曲线
        color = 'tab:red'
        ax1.set_xlabel('时间')
        ax1.set_ylabel('温度 (℃)', color=color)
        ax1.plot(df['timestamp'], df['dht_temp'], color=color, label='DHT22 Temp', marker='o', markersize=2)
        ax1.plot(df['timestamp'], df['bmp_temp'], color='tab:orange', linestyle='--', label='BMP280 Temp')
        ax1.tick_params(axis='y', labelcolor=color)
        ax1.legend(loc='upper left')

        # 创建第二个Y轴用于气压
        ax2 = ax1.twinx()  
        color = 'tab:blue'
        ax2.set_ylabel('气压', color=color)  
        ax2.plot(df['timestamp'], df['bmp_pressure'], color=color, label='Pressure', alpha=0.5)
        ax2.tick_params(axis='y', labelcolor=color)
        ax2.legend(loc='upper right')

        # 格式化X轴时间显示
        ax1.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))
        fig.autofmt_xdate() # 自动旋转日期标签

        plt.title(f'环境监测数据 - 最近{hours}小时')
        plt.tight_layout()
        plt.savefig(output_file)
        plt.close()
        print(f"图表已保存至 {output_file}")

# 使用示例
if __name__ == "__main__":
    manager = DataManager()
    plotter = Plotter(manager)
    plotter.generate_history_plot()

这段代码展示了如何利用Matplotlib的twinx功能在一张图上展示不同量纲的数据,并通过Pandas读取的时间序列数据自动适配X轴刻度。


第七章:数据可视化方案二------Plotly与Dash实时Web系统

这是本项目的核心亮点。传统的Matplotlib图表是静态的,无法满足实时监控的需求。Plotly提供了交互式图表,而Dash框架让我们可以用纯Python代码构建Web App,无需编写HTML/JavaScript。

7.1 Dash应用结构

一个Dash应用通常由两部分组成:

  1. Layout (布局):定义UI长什么样。
  2. Callbacks (回调):定义UI如何交互。

7.2 构建实时仪表盘

我们将创建一个每秒自动更新的网页,显示实时数据和历史趋势。

python 复制代码
import dash
from dash import dcc, html, Input, Output
import plotly.graph_objs as go
from datetime import datetime
import time

# 假设前面的类定义都在同一个文件中或已导入
# from sensor_module import SensorService, DataManager

# 初始化
sensor_service = SensorService()
data_manager = DataManager()

# 初始化Dash App
app = dash.Dash(__name__)

# 定义布局
app.layout = html.Div(style={'backgroundColor': '#f4f4f4', 'padding': '20px'}, children=[
    html.H1("树莓派环境监测站", style={'textAlign': 'center', 'color': '#333'}),

    # 实时数据显示卡片
    html.Div([
        html.Div([
            html.H3("当前温度 (DHT22)", style={'textAlign': 'center'}),
            html.H2(id='live-temp', style={'textAlign': 'center', 'color': 'red'}), 
        ], className='four columns', style={'width': '30%', 'display': 'inline-block', 'background': 'white', 'padding': '10px', 'borderRadius': '10px'}),

        html.Div([
            html.H3("当前湿度", style={'textAlign': 'center'}),
            html.H2(id='live-hum', style={'textAlign': 'center', 'color': 'blue'}), 
        ], className='four columns', style={'width': '30%', 'display': 'inline-block', 'background': 'white', 'padding': '10px', 'borderRadius': '10px', 'marginLeft': '5%'}),

        html.Div([
            html.H3("当前气压", style={'textAlign': 'center'}),
            html.H2(id='live-pres', style={'textAlign': 'center', 'color': 'green'}), 
        ], className='four columns', style={'width': '30%', 'display': 'inline-block', 'background': 'white', 'padding': '10px', 'borderRadius': '10px', 'marginLeft': '5%'}),
    ], style={'marginBottom': '20px'}),

    # 历史趋势图
    dcc.Graph(id='live-graph'),

    # 隐藏的Interval组件,用于定时触发回调
    dcc.Interval(
        id='interval-component',
        interval=5*1000, # 5秒更新一次
        n_intervals=0
    )
])

# 定义回调函数
@app.callback(
    [Output('live-temp', 'children'),
     Output('live-hum', 'children'),
     Output('live-pres', 'children'),
     Output('live-graph', 'figure')],
    [Input('interval-component', 'n_intervals')]
)
def update_metrics(n):
    # 1. 采集新数据
    record = sensor_service.collect_sample()

    # 2. 保存数据
    data_manager.save_record(record)

    # 3. 更新实时数值显示
    temp_str = f"{record['dht_temp']:.1f} °C" if record['dht_temp'] else "N/A"
    hum_str = f"{record['dht_humidity']:.1f} %" if record['dht_humidity'] else "N/A"
    pres_str = f"{record['bmp_pressure']:.1f} hPa" if record['bmp_pressure'] else "N/A"

    # 4. 更新历史图表
    # 获取最近1小时的数据
    df = data_manager.load_recent_data(minutes=60)

    # 创建Plotly图表
    fig = go.Figure()

    if not df.empty:
        # 温度曲线
        fig.add_trace(go.Scatter(
            x=df['timestamp'], y=df['dht_temp'],
            mode='lines+markers', name='温度 (DHT22)',
            line=dict(color='red')
        ))

        # 气压曲线 (使用次坐标轴)
        fig.add_trace(go.Scatter(
            x=df['timestamp'], y=df['bmp_pressure'],
            mode='lines+markers', name='气压',
            line=dict(color='green'),
            yaxis='y2'
        ))

        # 湿度曲线
        fig.add_trace(go.Scatter(
            x=df['timestamp'], y=df['dht_humidity'],
            mode='lines+markers', name='湿度',
            line=dict(color='blue'),
            yaxis='y3' # 这里简化处理,实际可能需要配置layout overlaying
        ))

    # 配置图表布局,包含双Y轴
    fig.update_layout(
        title='实时环境趋势 (最近1小时)',
        xaxis_title='时间',
        yaxis=dict(title='温度 (℃)', titlefont=dict(color='red'), tickfont=dict(color='red')),
        yaxis2=dict(title='气压', titlefont=dict(color='green'), tickfont=dict(color='green'), anchor='x', overlaying='y', side='right'),
        legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1),
        margin=dict(l=40, r=40, t=40, b=40)
    )

    return temp_str, hum_str, pres_str, fig

if __name__ == '__main__':
    # 注意:在开发模式下运行,生产环境建议使用gunicorn + nginx
    app.run_server(debug=True, host='0.0.0.0', port=8050)

7.3 代码深度解析

  1. dcc.Interval:这是Dash实现实时更新的核心组件。它每隔设定的毫秒数触发一次回调函数,无需手动编写多线程循环。
  2. 回调逻辑update_metrics函数既是数据的消费者(绘图),也是数据的生产者(采集并保存)。这种设计在低频采集(如每5秒一次)中是可行的。如果采集频率极高(如100Hz),则应将采集过程放在独立的后台线程中,通过全局变量或Redis共享数据,避免阻塞Web响应。
  3. Plotly双Y轴 :通过yaxis='y2'overlaying='y'配置,我们成功在一张图表上展示了量级差异巨大的温度和气压数据,且互不干扰。

第八章:系统部署与自动化运维

让脚本在终端前台运行是不够的,我们需要它开机自启并在崩溃后自动重启。

8.1 使用Systemd管理服务

在Linux系统中,Systemd是标准的进程管理工具。

  1. 创建服务文件
    sudo nano /etc/systemd/system/sensor_web.service

    内容如下:

    ini 复制代码
    [Unit]
    Description=Sensor Data Visualization Web App
    After=network.target
    
    [Service]
    # 替换为你的实际路径
    WorkingDirectory=/home/pi/sensor_system
    # 指定虚拟环境的Python解释器
    ExecStart=/home/pi/sensor_system/venv/bin/python app.py
    # 自动重启策略
    Restart=on-failure
    RestartSec=10
    User=pi
    Environment=PYTHONUNBUFFERED=1
    
    [Install]
    WantedBy=multi-user.target
  2. 启用并启动服务

    bash 复制代码
    sudo systemctl daemon-reload
    sudo systemctl enable sensor_web.service
    sudo systemctl start sensor_web.service
  3. 查看状态
    sudo systemctl status sensor_web.service

8.2 日志管理

Systemd会自动捕获标准输出。使用 journalctl -u sensor_web.service -f 可以实时查看系统日志,这对于调试传感器读数异常非常有帮助。

8.3 性能优化与注意事项

  • SD卡寿命:频繁写入CSV可能会损耗树莓派的SD卡。虽然对于本项目频率(每5秒一次)影响不大,但在高频工业场景下,建议将数据写入内存盘或外接USB硬盘/SSD。
  • 传感器漂移:DHT22在长时间运行后可能会出现读数漂移。建议在代码中加入定期校准逻辑,或者对比两个温度传感器(DHT22和BMP280)的读数,若差异过大则发出警报。
  • 网络访问:通过配置路由器的端口转发,可以在公网访问树莓派的8050端口,实现远程监控。但务必添加Nginx反向代理并开启HTTPS加密,甚至添加Dash的Basic Auth认证,防止数据泄露。

第九章:总结与展望

9.1 项目总结

本文详细构建了一个基于Raspberry Pi的完整物联网系统。从底层的GPIO时序分析,到中间层的数据清洗与Pandas存储,再到顶层的Web可视化,我们覆盖了全栈开发的各个环节。

  • 硬件方面:掌握了I2C与单总线通信的原理与接线。
  • 软件方面:熟练运用了Python的面向对象编程、Pandas的时间序列处理能力以及Dash框架的交互式开发模式。
相关推荐
代码探秘者1 分钟前
【Java集合】ArrayList :底层原理、数组互转与扩容计算
java·开发语言·jvm·数据库·后端·python·算法
格鸰爱童话34 分钟前
向AI学习项目技能(二)
java·人工智能·python·学习
Sagittarius_A*38 分钟前
傅里叶变换:从空域到频域的图像分析【计算机视觉】
图像处理·人工智能·python·opencv·计算机视觉·傅里叶变换·频域滤波
Pyeako1 小时前
深度学习--循环神经网络原理&局限&与LSTM解决方案
人工智能·python·rnn·深度学习·lstm·循环神经网络·遗忘门
搜佛说1 小时前
第2章-EdgeX-Foundry架构深度解析
数据库·物联网·架构·边缘计算·iot
困死,根本不会1 小时前
蓝桥杯python备赛笔记之(八)动态规划(DP)
笔记·python·学习·算法·蓝桥杯·动态规划
weixin199701080161 小时前
货铺头商品详情页前端性能优化实战
java·前端·python
深蓝电商API1 小时前
爬虫监控告警:结合企业微信或钉钉,打造 7×24 小时实时预警系统
爬虫·python·钉钉·企业微信
懷淰メ1 小时前
python3GUI--socket+PyQt5开发局域网微信(含功能、详细介绍、分享)
python·学习·gui·大学生·pyqt5·微信界面
risc1234561 小时前
channel.read(dest, channelPosition) 的读取大小限制
开发语言·python