Ver Fonte

fix27 v44: comprehensive bug fixes (19 bugs found in code review)

P0 fixes:
- gmtime() -> gmtime_r() for thread safety (main.cpp)
- Null pointer protection for capture pointer deletes (main.cpp)

P1 fixes:
- localtime() -> localtime_r() for thread safety (log_manager.cpp, 5 places)
- cJSON type checks for ROI API (web_server.cpp)

P2 fixes:
- Version string updated
- DEBUG_LOG conditional logging
- SSH API cJSON safe parsing

Documentation:
- TECH_DOC.md: Complete technical configuration document (1005 lines)
- INSTALL_RPI5.md: Raspberry Pi 5 Ubuntu 24.04 installation guide (1655 lines)
- Q&A archive: Technical Q&A document (Q-001 to Q-006)
steven_roc há 10 horas atrás
pai
commit
276deacd29
5 ficheiros alterados com 2681 adições e 15 exclusões
  1. 1655 0
      INSTALL_RPI5.md
  2. 1005 0
      TECH_DOC.md
  3. 8 4
      src/log_manager.cpp
  4. 6 5
      src/main.cpp
  5. 7 6
      src/web_server.cpp

+ 1655 - 0
INSTALL_RPI5.md

@@ -0,0 +1,1655 @@
+# PlateRecApp 树莓派5安装编译运行完整指南
+
+> **适用平台**: 树莓派 5 8G (BCM2712, Cortex-A76, aarch64)  
+> **操作系统**: Ubuntu 24.04 LTS Server (aarch64)  
+> **项目版本**: fix27 v44 | 2026-08-30  
+> **C++标准**: C++17 | **编译器**: GCC 13+  
+> **本文档持续更新**
+
+---
+
+## 目录
+
+1. [系统准备](#1-系统准备)
+2. [安装所有依赖](#2-安装所有依赖)
+3. [编译安装 MNN](#3-编译安装-mnn)
+4. [安装 HyperLPR3 SDK](#4-安装-hyperlpr3-sdk)
+5. [编译 PlateRecApp](#5-编译-plateRecApp)
+6. [部署运行](#6-部署运行)
+7. [常见问题排查](#7-常见问题排查)
+8. [性能优化建议](#8-性能优化建议)
+
+---
+
+## 1. 系统准备
+
+### 1.1 安装 Ubuntu 24.04
+
+#### 1.1.1 下载 Raspberry Pi Imager
+
+从官方下载最新版本的 Raspberry Pi Imager:
+
+| 平台 | 下载地址 |
+|------|---------|
+| Windows | https://downloads.raspberrypi.org/imager/imager_latest.exe |
+| macOS | https://downloads.raspberrypi.org/imager/imager_latest.dmg |
+| Linux (AppImage) | https://downloads.raspberrypi.org/imager/imager_latest.appimage |
+| Ubuntu (snap) | `sudo snap install rpi-imager` |
+
+#### 1.1.2 烧录 Ubuntu 24.04 Server
+
+1. 插入 microSD 卡(建议 64GB 以上,A2 等级,推荐 SanDisk Extreme)
+2. 打开 Raspberry Pi Imager
+3. 点击 **CHOOSE DEVICE** → 选择 **Raspberry Pi 5**
+4. 点击 **CHOOSE OS** → **Other general-purpose OS** → **Ubuntu** → **Ubuntu Server 24.04 LTS (64-bit)**
+5. 点击 **CHOOSE STORAGE** → 选择你的 microSD 卡
+
+#### 1.1.3 配置高级选项(重要)
+
+点击右下角齿轮图标(或按 `Ctrl+Shift+X`)进入高级选项:
+
+```yaml
+# 主机名
+hostname: plate-rec
+
+# 启用 SSH(必须!)
+Enable SSH: ✅ Use password authentication
+
+# 设置用户名和密码
+Username: pi
+Password: <your-password>
+
+# WiFi 配置(如果需要无线连接)
+Configure wireless LAN:
+  SSID: YourWiFiName
+  Password: YourWiFiPassword
+  Wireless LAN country: CN
+
+# 区域设置
+Set locale settings:
+  Time zone: Asia/Shanghai
+  Keyboard layout: cn
+```
+
+#### 1.1.4 首次启动配置
+
+烧录完成后插入树莓派,接通电源启动。等待 1-2 分钟后通过 SSH 连接:
+
+```bash
+# 连接方式1: 通过主机名
+ssh pi@plate-rec.local
+
+# 连接方式2: 通过 IP 地址(在路由器管理页面查看)
+ssh pi@192.168.x.x
+
+# 首次登录,更新系统
+sudo apt update && sudo apt upgrade -y
+sudo reboot
+```
+
+> **⚠️ 注意**: 树莓派5 的 Wi-Fi 支持 Wi-Fi 6 (802.11ac/ax),但强烈建议使用有线以太网连接以获得稳定的视频流传输。
+
+#### 1.1.5 扩展文件系统(如果使用较小容量的卡)
+
+```bash
+# Ubuntu 24.04 通常会自动扩展,如果没有:
+sudo raspi-config
+# 选择 Advanced Options → Expand Filesystem → 重启
+```
+
+### 1.2 系统更新与基础工具
+
+```bash
+# 更新系统到最新
+sudo apt update && sudo apt upgrade -y
+
+# 安装基础编译工具链
+sudo apt install -y \
+    build-essential \
+    cmake \
+    git \
+    wget \
+    curl \
+    pkg-config \
+    unzip \
+    tree \
+    htop \
+    nano \
+    net-tools \
+    lsb-release
+
+# 验证系统信息
+uname -a
+# 预期输出: Linux plate-rec 6.x.x xxx aarch64 GNU/Linux
+
+cat /etc/os-release
+# 预期输出: Ubuntu 24.04.x LTS (Noble Numbat)
+
+gcc --version
+# 预期输出: gcc (Ubuntu 13.x.x) 13.x.x
+
+cmake --version
+# 预期输出: cmake version 3.28.x
+
+# 验证内存
+free -h
+# 预期输出: 约 7.8GB 可用
+
+# 查看 CPU 信息
+lscpu
+# 预期: ARMv8 Processor rev 0 (v8l), 4 cores
+```
+
+### 1.3 配置静态IP(可选)
+
+#### 1.3.1 使用 Netplan 配置静态IP
+
+Ubuntu 24.04 使用 Netplan 管理网络配置。
+
+```bash
+# 查看当前网络接口
+ip link show
+# 通常有线网卡为 eth0 或 end0
+
+# 查看当前 Netplan 配置
+cat /etc/netplan/50-cloud-init.yaml
+# 或
+ls /etc/netplan/
+```
+
+创建或编辑配置文件:
+
+```bash
+sudo nano /etc/netplan/01-static.yaml
+```
+
+写入以下内容(根据实际网卡名修改):
+
+```yaml
+# /etc/netplan/01-static.yaml
+network:
+  version: 2
+  renderer: networkd
+  ethernets:
+    end0:  # 树莓派5有线网卡名通常是 end0,用 ip link show 确认
+      dhcp4: no
+      addresses:
+        - 192.168.1.100/24    # 修改为你需要的静态IP
+      routes:
+        - to: default
+          via: 192.168.1.1    # 网关地址
+      nameservers:
+        addresses:
+          - 223.5.5.5         # 阿里DNS
+          - 8.8.8.8           # Google DNS
+```
+
+应用配置:
+
+```bash
+# 验证配置语法
+sudo netplan try
+
+# 确认无误后应用
+sudo netplan apply
+
+# 验证IP
+ip addr show end0
+```
+
+#### 1.3.2 配置 mDNS(可选)
+
+如果需要通过 `plate-rec.local` 访问:
+
+```bash
+sudo apt install -y avahi-daemon
+sudo systemctl enable avahi-daemon
+sudo systemctl start avahi-daemon
+```
+
+---
+
+## 2. 安装所有依赖
+
+按以下顺序安装所有编译和运行依赖。所有命令均为精确的 `apt` 命令。
+
+### 2.1 一键安装全部依赖(推荐)
+
+```bash
+sudo apt install -y \
+    libopencv-dev \
+    libavformat-dev \
+    libavcodec-dev \
+    libavutil-dev \
+    libswscale-dev \
+    libsqlite3-dev \
+    libcurl4-openssl-dev \
+    libssl-dev \
+    libfreetype-dev \
+    libcjson-dev \
+    libmosquitto-dev \
+    libmosquittopp-dev \
+    libprotobuf-dev \
+    protobuf-compiler \
+    libcrypt-dev
+```
+
+### 2.2 分步安装(便于排查问题)
+
+#### 2.2.1 OpenCV 4.x(计算机视觉库)
+
+```bash
+sudo apt install -y libopencv-dev
+
+# 验证
+pkg-config --modversion opencv4
+# 预期输出: 4.x.x(Ubuntu 24.04 默认提供 OpenCV 4.x)
+
+# 检查头文件
+pkg-config --cflags opencv4
+# 应包含 -I/usr/include/opencv4
+
+# 检查库
+pkg-config --libs opencv4
+```
+
+> **说明**: OpenCV 用于图像处理、ROI 裁剪、格式转换等。系统包约占用 200-300MB 磁盘空间。
+
+#### 2.2.2 FFmpeg(视频解码库,v43+ 核心依赖)
+
+```bash
+sudo apt install -y \
+    libavformat-dev \
+    libavcodec-dev \
+    libavutil-dev \
+    libswscale-dev
+
+# 验证
+pkg-config --modversion libavformat
+pkg-config --modversion libavcodec
+pkg-config --modversion libavutil
+pkg-config --modversion libswscale
+
+# 可选:安装 ffmpeg 命令行工具用于测试 RTSP 流
+sudo apt install -y ffmpeg
+```
+
+> **说明**: FFmpeg 用于 RTSP 视频流解码,支持 HEVC DRM 硬件解码和 H.264 软解。这是 v43 版本的核心新增依赖。
+
+#### 2.2.3 SQLite3(轻量级数据库)
+
+```bash
+sudo apt install -y libsqlite3-dev
+
+# 验证
+pkg-config --modversion sqlite3
+# 预期输出: 3.x.x
+
+# 可选:安装命令行工具
+sudo apt install -y sqlite3
+```
+
+#### 2.2.4 cURL + OpenSSL(网络/加密库)
+
+```bash
+sudo apt install -y libcurl4-openssl-dev libssl-dev
+
+# 验证
+pkg-config --modversion libcurl
+pkg-config --modversion openssl
+
+# 检查 cURL 支持 HTTPS
+curl --version | grep -i https
+```
+
+#### 2.2.5 FreeType2(字体渲染库)
+
+```bash
+sudo apt install -y libfreetype-dev
+
+# 验证
+pkg-config --modversion freetype2
+# 预期输出: 2x.x.x
+```
+
+> **说明**: FreeType2 用于在图像上绘制中文字符(通过 cvxFont 模块)。
+
+#### 2.2.6 cJSON(JSON 解析库)
+
+```bash
+sudo apt install -y libcjson-dev
+
+# 验证
+pkg-config --modversion cjson
+# 预期输出: 1.7.x
+
+# 检查头文件位置
+dpkg -L libcjson-dev | grep cJSON.h
+# 通常在 /usr/include/cjson/cJSON.h
+```
+
+#### 2.2.7 MQTT(消息队列库)
+
+```bash
+sudo apt install -y libmosquitto-dev libmosquittopp-dev
+
+# 验证
+ls /usr/lib/aarch64-linux-gnu/libmosquitto*
+ls /usr/lib/aarch64-linux-gnu/libmosquittopp*
+
+# 检查头文件
+ls /usr/include/mosquitto.h
+ls /usr/include/mosquittopp.h
+```
+
+> **说明**: mosquitto 是 C 库,mosquittopp 是 C++ 封装库。两者都需要安装。
+
+#### 2.2.8 Protobuf(协议缓冲区)
+
+```bash
+sudo apt install -y libprotobuf-dev protobuf-compiler
+
+# 验证
+protoc --version
+# 预期输出: libprotoc 3.x.x
+
+pkg-config --modversion protobuf
+```
+
+#### 2.2.9 libcrypt(密码哈希库,fix24 认证系统)
+
+```bash
+sudo apt install -y libcrypt-dev
+
+# 验证
+ls /usr/lib/aarch64-linux-gnu/libcrypt.so
+ls /usr/include/crypt.h
+```
+
+> **说明**: libcrypt 提供 `crypt_r()` 函数用于 bcrypt 密码哈希。这是 fix24 认证系统的必要依赖。
+
+### 2.3 验证所有依赖安装完成
+
+```bash
+# 一键验证脚本
+echo "=== 依赖验证 ==="
+pkg-config --modversion opencv4 && echo "✅ OpenCV" || echo "❌ OpenCV"
+pkg-config --modversion libavformat && echo "✅ FFmpeg-libavformat" || echo "❌ FFmpeg-libavformat"
+pkg-config --modversion libavcodec && echo "✅ FFmpeg-libavcodec" || echo "❌ FFmpeg-libavcodec"
+pkg-config --modversion libavutil && echo "✅ FFmpeg-libavutil" || echo "❌ FFmpeg-libavutil"
+pkg-config --modversion libswscale && echo "✅ FFmpeg-libswscale" || echo "❌ FFmpeg-libswscale"
+pkg-config --modversion sqlite3 && echo "✅ SQLite3" || echo "❌ SQLite3"
+pkg-config --modversion libcurl && echo "✅ cURL" || echo "❌ cURL"
+pkg-config --modversion openssl && echo "✅ OpenSSL" || echo "❌ OpenSSL"
+pkg-config --modversion freetype2 && echo "✅ FreeType2" || echo "❌ FreeType2"
+pkg-config --modversion cjson && echo "✅ cJSON" || echo "❌ cJSON"
+ls /usr/lib/aarch64-linux-gnu/libmosquitto.so && echo "✅ Mosquitto" || echo "❌ Mosquitto"
+ls /usr/lib/aarch64-linux-gnu/libmosquittopp.so && echo "✅ Mosquittopp" || echo "❌ Mosquittopp"
+protoc --version && echo "✅ Protobuf" || echo "❌ Protobuf"
+ls /usr/lib/aarch64-linux-gnu/libcrypt.so && echo "✅ libcrypt" || echo "❌ libcrypt"
+echo "=== 验证完成 ==="
+```
+
+---
+
+## 3. 编译安装 MNN
+
+MNN(Mobile Neural Network)是阿里巴巴开源的轻量级深度学习推理引擎,HyperLPR3 依赖 MNN 进行车牌检测与识别模型的推理。
+
+### 3.1 克隆源码
+
+```bash
+cd ~
+git clone https://github.com/alibaba/MNN.git
+cd MNN
+
+# 切换到稳定版本(推荐使用 2.9.x 或更高)
+git checkout 2.9.6
+# 或使用 master 分支
+# git checkout master
+```
+
+### 3.2 编译(aarch64 专用参数)
+
+```bash
+cd ~/MNN
+mkdir -p build && cd build
+```
+
+#### 完整 CMake 配置命令及参数说明
+
+```bash
+cmake .. \
+    -DCMAKE_BUILD_TYPE=Release \
+    -DMNN_BUILD_SHARED_LIBS=ON \
+    -DMNN_BUILD_CONVERTER=OFF \
+    -DMNN_BUILD_DEMO=OFF \
+    -DMNN_BUILD_TOOLS=OFF \
+    -DMNN_BUILD_TRAIN=OFF \
+    -DMNN_BUILD_QUANTOOLS=OFF \
+    -DMNN_BUILD_MINIMAL=OFF \
+    -DMNN_ARM82=ON \
+    -DMNN_FP16=ON \
+    -DMNN_OPENCL=OFF \
+    -DMNN_VULKAN=OFF \
+    -DMNN_METAL=OFF \
+    -DMNN_USE_THREAD_POOL=ON \
+    -DMNN_NUM_THREADS=4 \
+    -DCMAKE_INSTALL_PREFIX=/usr/local
+```
+
+**参数详细说明**:
+
+| 参数 | 值 | 说明 |
+|------|-----|------|
+| `CMAKE_BUILD_TYPE` | Release | 发布模式,启用 -O3 优化 |
+| `MNN_BUILD_SHARED_LIBS` | ON | 编译为动态库 (.so),减小程序体积 |
+| `MNN_BUILD_CONVERTER` | OFF | 不编译模型转换工具(节省编译时间和空间) |
+| `MNN_BUILD_DEMO` | OFF | 不编译示例程序 |
+| `MNN_BUILD_TOOLS` | OFF | 不编译额外工具 |
+| `MNN_BUILD_TRAIN` | OFF | 不编译训练模块 |
+| `MNN_BUILD_QUANTOOLS` | OFF | 不编译量化工具 |
+| `MNN_BUILD_MINIMAL` | OFF | 不启用最小化构建 |
+| **`MNN_ARM82`** | **ON** | **关键参数!启用 ARMv8.2 fp16 指令集加速,树莓派5 Cortex-A76 支持** |
+| **`MNN_FP16`** | **ON** | **启用半精度浮点运算,配合 ARM82 大幅提升推理速度** |
+| `MNN_OPENCL` | OFF | 不使用 OpenCL GPU 加速(树莓派5 支持有限) |
+| `MNN_VULKAN` | OFF | 不使用 Vulkan GPU 加速 |
+| `MNN_METAL` | OFF | Apple Metal 专用,Linux 不需要 |
+| `MNN_USE_THREAD_POOL` | ON | 启用线程池,提升多核利用率 |
+| `MNN_NUM_THREADS` | 4 | 线程数设为 4,匹配树莓派5的4个核心 |
+| `CMAKE_INSTALL_PREFIX` | /usr/local | 安装到 /usr/local 目录 |
+
+#### 开始编译
+
+```bash
+# 使用 4 核并行编译(树莓派5 有 4 个核心)
+make -j4
+
+# 编译过程约需 5-15 分钟,取决于 microSD 卡速度
+# 使用 SSD/USB 会更快
+
+# 安装
+sudo make install
+
+# 更新动态链接库缓存
+sudo ldconfig
+```
+
+### 3.3 验证安装
+
+```bash
+# 检查头文件
+ls /usr/local/include/MNN/
+# 应包含: Interpreter.hpp, MNNDefine.h, MNNForwardType.h 等
+
+# 检查库文件
+ls /usr/local/lib/libMNN*
+# 应包含: libMNN.so, libMNN*.so 等
+
+# 使用 pkg-config 验证(如果 MNN 提供了 .pc 文件)
+pkg-config --libs MNN 2>/dev/null || echo "MNN 无 pkg-config 文件,使用手动路径"
+
+# 验证库是否可加载
+ldconfig -p | grep MNN
+```
+
+---
+
+## 4. 安装 HyperLPR3 SDK
+
+HyperLPR3 是开源车牌识别库,提供车牌检测、字符识别的预训练模型和推理接口。
+
+### 4.1 预编译 SDK 安装(推荐)
+
+#### 4.1.1 下载 SDK
+
+```bash
+cd /root/PlateRecApp
+mkdir -p hyperlpr3
+cd hyperlpr3
+
+# 下载预编译的 aarch64 Linux SDK
+# 方式1: 从 GitHub Releases 下载
+wget https://github.com/nicklasxyz/hyperlpr3/releases/download/v0.1.0/hyperlpr3-linux-aarch64.tar.gz
+
+# 方式2: 如果上述链接不可用,从 HyperLPR 官方获取
+# https://github.com/nicklasxyz/HyperLPR3
+# 注意:需要根据实际发布版本调整 URL
+
+# 方式3: 从自有服务器下载(如果有预编译版本)
+# wget http://your-server/hyperlpr3-linux-aarch64.tar.gz
+```
+
+#### 4.1.2 解压并安装
+
+```bash
+cd /root/PlateRecApp/hyperlpr3
+
+# 解压
+tar -xzf hyperlpr3-linux-aarch64.tar.gz
+
+# 预期目录结构
+tree /root/PlateRecApp/hyperlpr3/
+```
+
+**标准目录结构**:
+
+```
+hyperlpr3/
+├── include/                 # 头文件目录
+│   ├── hyperlpr3.h          # C API 头文件
+│   └── hyper_lpr_sdk.h     # SDK 接口头文件
+├── lib/                     # 库文件目录
+│   ├── libhyperlpr3.so      # 主库(动态链接)
+│   └── libMNN.so            # MNN 运行时库(如果未单独安装 MNN)
+├── models/                  # 模型文件目录
+│   ├── det/                 # 车牌检测模型
+│   │   └── det.mnn         # MNN 格式检测模型
+│   ├── rec/                 # 字符识别模型
+│   │   └── rec.mnn         # MNN 格式识别模型
+│   └── seg/                 # 分割模型(如果有)
+│       └── seg.mnn
+└── README.md
+```
+
+#### 4.1.3 运行时库路径配置
+
+```bash
+# 添加 HyperLPR3 库路径到系统动态链接器
+echo "/root/PlateRecApp/hyperlpr3/lib" | sudo tee /etc/ld.so.conf.d/hyperlpr3.conf
+
+# 更新动态链接库缓存
+sudo ldconfig
+
+# 验证库是否被识别
+ldconfig -p | grep hyperlpr3
+```
+
+### 4.2 源码编译安装(备选)
+
+如果预编译 SDK 不可用,可自行编译:
+
+```bash
+cd ~
+git clone https://github.com/nicklasxyz/HyperLPR3.git
+cd HyperLPR3
+
+# 编译(需要已安装 MNN)
+mkdir build && cd build
+cmake .. \
+    -DCMAKE_BUILD_TYPE=Release \
+    -DMNN_DIR=/usr/local \
+    -DCMAKE_INSTALL_PREFIX=/root/PlateRecApp/hyperlpr3
+
+make -j4
+make install
+```
+
+> **⚠️ 注意**: 源码编译需要确保 MNN 已正确安装,且需要下载模型文件放到 models/ 目录。
+
+---
+
+## 5. 编译 PlateRecApp
+
+### 5.1 克隆代码
+
+```bash
+cd /root
+git clone https://git.zhonjin.com:40717/steven_roc/PlateRecApp.git
+cd PlateRecApp
+
+# 如果使用已有代码,直接进入目录
+# cd /root/PlateRecApp
+
+# 查看当前版本
+head -5 README.md
+```
+
+### 5.2 检查项目结构
+
+确认以下文件和目录存在:
+
+```bash
+# 检查源码目录
+ls src/
+# 应包含: main.cpp, config.cpp, plate_recognizer.cpp, web_server.cpp 等
+
+# 检查第三方依赖
+ls third_party/
+# 应包含: cvxFont.cpp, cvxFont.h, httplib.h, ini.c, ini.h, md5ex1.c, md5ex1.h
+
+# 检查 HyperLPR3 SDK
+ls hyperlpr3/include/ hyperlpr3/lib/
+# 应包含头文件和库文件
+
+# 检查 CMakeLists.txt
+ls CMakeLists.txt
+```
+
+### 5.3 CMake 配置
+
+```bash
+cd /root/PlateRecApp
+mkdir -p build && cd build
+
+cmake .. \
+    -DCMAKE_BUILD_TYPE=Release \
+    -DUSE_STATIC_LIBS=OFF \
+    -DCMAKE_CXX_FLAGS="-march=armv8.2-a+fp16" \
+    -DCMAKE_C_FLAGS="-march=armv8.2-a+fp16"
+```
+
+**CMake 参数说明**:
+
+| 参数 | 值 | 说明 |
+|------|-----|------|
+| `CMAKE_BUILD_TYPE` | Release | 发布模式,启用 -O3 优化 + strip |
+| `USE_STATIC_LIBS` | OFF | 使用动态链接,减小程序体积 |
+| `CMAKE_CXX_FLAGS` | `-march=armv8.2-a+fp16` | 启用 ARMv8.2 fp16 指令集 |
+| `CMAKE_C_FLAGS` | `-march=armv8.2-a+fp16` | 同上,用于 C 文件 |
+
+> **注意**: CMake 配置阶段会检查所有依赖。如果某个依赖缺失,会报 `FATAL_ERROR`。请根据错误提示安装缺失的库。
+
+**CMake 预期输出**(关键信息):
+
+```
+-- ========================================
+-- 项目配置信息:
+--   项目名称: HyperLPR3-LinuxAPP
+--   项目版本: 1.0.0
+--   C++ 标准: C++17
+--   构建类型: Release
+--   使用静态库: OFF
+-- ----------------------------------------
+-- 库路径信息:
+--   OpenCV: /usr/include/opencv4
+--   HyperLPR3: /root/PlateRecApp/hyperlpr3/include
+--   cJSON 库: /usr/lib/aarch64-linux-gnu/libcjson.so
+--   libcrypt: /usr/lib/aarch64-linux-gnu/libcrypt.so
+-- ========================================
+```
+
+### 5.4 编译
+
+```bash
+cd /root/PlateRecApp/build
+
+# 使用 4 核并行编译
+make -j4
+
+# 编译过程约需 3-10 分钟
+# Release 模式下会自动 strip 符号表
+
+# 如果编译出错,可查看详细错误
+make VERBOSE=1
+```
+
+### 5.5 验证编译产物
+
+```bash
+# 检查可执行文件
+ls -lh /root/PlateRecApp/build/PlateRecApp
+# 应为一个可执行文件
+
+# 查看文件信息
+file /root/PlateRecApp/build/PlateRecApp
+# 预期: ELF 64-bit LSB executable, ARM aarch64
+
+# 查看动态链接依赖
+ldd /root/PlateRecApp/build/PlateRecApp
+# 检查所有依赖库都能找到(无 "not found")
+
+# 快速测试运行(会因缺少 config.ini 报错,但不应报库缺失)
+./PlateRecApp --help 2>&1 || true
+```
+
+**关键验证**: `ldd` 输出中不应出现 `not found`,否则需要安装缺失的库。
+
+---
+
+## 6. 部署运行
+
+### 6.1 目录结构
+
+生产环境推荐以下目录结构:
+
+```
+/root/PlateRecApp/              # 项目根目录
+├── PlateRecApp                 # 编译产物(可执行文件)或 build/PlateRecApp
+├── config.ini                  # 主配置文件
+├── hyperlpr3/                  # HyperLPR3 SDK
+│   ├── include/
+│   ├── lib/
+│   └── models/
+├── data/                       # 运行时数据目录
+│   ├── plate_rec.db            # SQLite 数据库
+│   └── auth.db                 # 认证数据库
+├── fonts/                      # 字体文件目录
+│   └── font.ttf               # 中文字体文件
+├── html/                       # Web 前端文件(如果有)
+├── logs/                       # 日志目录
+│   └── plate_rec.log
+├── scripts/                    # 脚本目录
+└── src/                        # 源码目录
+```
+
+创建必要目录:
+
+```bash
+cd /root/PlateRecApp
+mkdir -p data fonts html logs scripts
+
+# 复制编译产物到项目根目录(可选)
+cp build/PlateRecApp ./PlateRecApp
+chmod +x ./PlateRecApp
+```
+
+### 6.2 config.ini 配置
+
+创建配置文件:
+
+```bash
+cat > /root/PlateRecApp/config.ini << 'EOF'
+[system]
+# 设备名称
+device_name=plate-rec-01
+# 日志级别: DEBUG, INFO, WARN, ERROR
+log_level=INFO
+# 日志文件路径
+log_path=/root/PlateRecApp/logs/plate_rec.log
+# 日志最大大小(MB)
+log_max_size=50
+# 日志保留份数
+log_backup_count=3
+
+[rtsp]
+# RTSP 视频流地址(支持最多4路)
+# 格式: rtsp://username:password@ip:port/stream
+url1=rtsp://admin:password@192.168.1.100:554/Streaming/Channels/101
+url2=
+url3=
+url4=
+# 每路流的 ROI 区域 (x,y,w,h) 逗号分隔
+roi1=0,0,1920,1080
+roi2=0,0,1920,1080
+roi3=0,0,1920,1080
+roi4=0,0,1920,1080
+# 解码模式: auto, drm(HEVC硬解), cpu(H264软解)
+decode_mode=auto
+# 帧跳过间隔(每N帧处理1帧)
+frame_skip=3
+
+[plate_recognition]
+# 置信度阈值 (0.0-1.0)
+confidence_threshold=0.5
+# 模型路径
+model_dir=/root/PlateRecApp/hyperlpr3/models
+
+[database]
+# SQLite 数据库路径
+db_path=/root/PlateRecApp/data/plate_rec.db
+
+[web_server]
+# Web 管理后台端口
+port=8080
+# 静态文件目录
+html_dir=/root/PlateRecApp/html
+# 超级管理员账号(首次启动会自动创建)
+admin_user=admin
+admin_password=zhonjin188A
+
+[feishu]
+# 飞书推送开关
+enabled=false
+# 飞书 Webhook URL
+webhook_url=https://open.feishu.cn/open-apis/bot/v2/hook/your-hook-id
+# 推送消息模板
+entry_msg=🟢 进站 | 车牌: {plate} | 时间: {time}
+exit_msg=🔴 出站 | 车牌: {plate} | 时间: {time}
+
+[mqtt]
+# MQTT 上报开关
+enabled=false
+# Broker 地址
+broker=tcp://192.168.1.200:1883
+# 客户端 ID
+client_id=plate_rec_01
+# 主题
+topic=plate_recognition/result
+# 用户名密码(如果有)
+username=
+password=
+
+[station_lock]
+# 站点锁定超时(秒)
+lock_timeout=120
+
+[frpc]
+# frpc 可执行文件路径
+frpc_path=/usr/local/bin/frpc
+# frpc 配置文件路径
+frpc_config_path=/root/PlateRecApp/frpc.toml
+# frpc admin API 端口(仅允许 127.0.0.1 访问)
+admin_port=7400
+EOF
+```
+
+> **⚠️ 重要**: 请根据实际环境修改 RTSP 地址、飞书 Webhook、MQTT Broker 等配置。
+
+### 6.3 systemd service 配置
+
+创建系统服务文件:
+
+```bash
+sudo tee /etc/systemd/system/plate-rec.service << 'EOF'
+[Unit]
+Description=PlateRecApp - License Plate Recognition Service
+After=network-online.target
+Wants=network-online.target
+
+[Service]
+Type=simple
+User=root
+Group=root
+WorkingDirectory=/root/PlateRecApp
+ExecStart=/root/PlateRecApp/PlateRecApp
+Restart=always
+RestartSec=5
+StartLimitIntervalSec=60
+StartLimitBurst=3
+
+# 环境变量
+Environment=LD_LIBRARY_PATH=/root/PlateRecApp/hyperlpr3/lib:/usr/local/lib
+Environment=MNN_NUM_THREADS=4
+
+# 资源限制
+LimitNOFILE=65536
+LimitNPROC=4096
+MemoryMax=2G
+CPUQuota=300%
+
+# 安全加固
+NoNewPrivileges=yes
+ProtectSystem=strict
+ReadWritePaths=/root/PlateRecApp
+ProtectKernelTunables=yes
+ProtectKernelModules=yes
+ProtectControlGroups=yes
+
+# 日志
+StandardOutput=journal
+StandardError=journal
+SyslogIdentifier=plate-rec
+
+[Install]
+WantedBy=multi-user.target
+EOF
+```
+
+**服务文件关键配置说明**:
+
+| 配置项 | 值 | 说明 |
+|--------|-----|------|
+| `LD_LIBRARY_PATH` | hyperlpr3/lib + /usr/local/lib | 确保能找到 MNN 和 HyperLPR3 动态库 |
+| `MNN_NUM_THREADS` | 4 | MNN 推理线程数,匹配树莓派5核心数 |
+| `LimitNOFILE` | 65536 | 最大打开文件数(4路 RTSP 流需要较多 fd) |
+| `MemoryMax` | 2G | 内存上限,防止 OOM |
+| `CPUQuota` | 300% | CPU 使用上限(4 核 = 400%,留 1 核给系统) |
+| `RestartSec` | 5 | 崩溃后 5 秒重启 |
+| `StartLimitBurst` | 3 | 60秒内最多重启 3 次,防止频繁崩溃 |
+
+### 6.4 启动和验证
+
+```bash
+# 重新加载 systemd 配置
+sudo systemctl daemon-reload
+
+# 启用开机自启
+sudo systemctl enable plate-rec
+
+# 启动服务
+sudo systemctl start plate-rec
+
+# 检查服务状态
+sudo systemctl status plate-rec
+
+# 预期输出:
+# ● plate-rec.service - PlateRecApp - License Plate Recognition Service
+#      Loaded: loaded (/etc/systemd/system/plate-rec.service; enabled)
+#      Active: active (running) since ...
+```
+
+**验证运行**:
+
+```bash
+# 检查进程
+ps aux | grep PlateRecApp
+
+# 检查端口监听
+ss -tlnp | grep 8080
+# 或
+netstat -tlnp | grep 8080
+
+# 检查数据库文件是否创建
+ls -la /root/PlateRecApp/data/
+
+# 测试 Web 管理后台
+curl -s http://localhost:8080/ | head -20
+
+# 检查日志输出
+sudo journalctl -u plate-rec -f --no-pager -n 50
+```
+
+### 6.5 日志查看
+
+```bash
+# 实时查看服务日志
+sudo journalctl -u plate-rec -f
+
+# 查看最近 100 行日志
+sudo journalctl -u plate-rec -n 100 --no-pager
+
+# 查看今天的日志
+sudo journalctl -u plate-rec --since today --no-pager
+
+# 查看应用自身日志文件
+tail -f /root/PlateRecApp/logs/plate_rec.log
+
+# 查看应用日志(带颜色)
+tail -f /root/PlateRecApp/logs/plate_rec.log | grep -E "ERROR|WARN" --color=always
+
+# 配置 logrotate 自动清理日志(如果应用未自带)
+sudo tee /etc/logrotate.d/plate-rec << 'LOGEOF'
+/root/PlateRecApp/logs/*.log {
+    daily
+    rotate 7
+    compress
+    delaycompress
+    missingok
+    notifempty
+    create 0644 root root
+    postrotate
+        systemctl reload plate-rec 2>/dev/null || true
+    endscript
+}
+LOGEOF
+```
+
+**常用运维命令**:
+
+```bash
+# 重启服务
+sudo systemctl restart plate-rec
+
+# 停止服务
+sudo systemctl stop plate-rec
+
+# 禁用开机自启
+sudo systemctl disable plate-rec
+
+# 查看服务资源使用
+systemctl status plate-rec
+systemd-cgtop
+
+# 查看 crash 日志
+sudo journalctl -u plate-rec --since "1 hour ago" -p err --no-pager
+```
+
+---
+
+## 7. 常见问题排查
+
+### 编译类问题
+
+#### Q1: CMake 报错 "Could NOT find OpenCV"
+
+**原因**: OpenCV 开发包未安装。
+
+**解决**:
+```bash
+sudo apt install -y libopencv-dev
+# 如果仍有问题,检查 pkg-config
+pkg-config --modversion opencv4
+```
+
+#### Q2: CMake 报错 "Could NOT find CURL" 或 "Failed to find curl.h"
+
+**原因**: cURL 开发包未安装。
+
+**解决**:
+```bash
+sudo apt install -y libcurl4-openssl-dev
+```
+
+#### Q3: 编译报错 "hyper_lpr_sdk.h: No such file or directory"
+
+**原因**: HyperLPR3 SDK 未正确安装到 hyperlpr3/ 目录。
+
+**解决**:
+```bash
+ls /root/PlateRecApp/hyperlpr3/include/hyper_lpr_sdk.h
+# 如果不存在,重新安装 HyperLPR3 SDK(参见第4节)
+```
+
+#### Q4: 链接报错 "undefined reference to `MNN::Interpreter::createFromFile'"
+
+**原因**: MNN 未安装或链接器找不到 MNN 库。
+
+**解决**:
+```bash
+# 检查 MNN 是否安装
+ls /usr/local/lib/libMNN.so
+
+# 如果不存在,重新编译安装 MNN(参见第3节)
+# 如果存在但找不到,更新 ldconfig
+echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/mnn.conf
+sudo ldconfig
+```
+
+#### Q5: 链接报错 "cannot find -lmosquittopp" 或 "cannot find -lcjson"
+
+**原因**: 对应的开发包未安装。
+
+**解决**:
+```bash
+sudo apt install -y libmosquittopp-dev libcjson-dev
+```
+
+#### Q6: 编译报错 "'crypt_r' was not declared in this scope"
+
+**原因**: libcrypt-dev 未安装。
+
+**解决**:
+```bash
+sudo apt install -y libcrypt-dev
+```
+
+#### Q7: 编译报错 "libavformat/libavcodec 相关头文件找不到"
+
+**原因**: FFmpeg 开发包未安装。
+
+**解决**:
+```bash
+sudo apt install -y libavformat-dev libavcodec-dev libavutil-dev libswscale-dev
+pkg-config --modversion libavformat
+```
+
+#### Q8: 链接阶段 OOM (Out of Memory)
+
+**原因**: 树莓派5 8G 内存在链接大型项目时可能不够(特别是 Debug 模式)。
+
+**解决**:
+```bash
+# 方法1: 增加 swap
+sudo fallocate -l 2G /swapfile
+sudo chmod 600 /swapfile
+sudo mkswap /swapfile
+sudo swapon /swapfile
+echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
+
+# 方法2: 使用单线程编译
+make -j1
+
+# 方法3: 使用 Release 模式(体积更小,内存占用更少)
+cmake -DCMAKE_BUILD_TYPE=Release ..
+```
+
+### 运行时问题
+
+#### Q9: 启动报错 "error while loading shared libraries: libMNN.so: cannot open shared object file"
+
+**原因**: 动态链接器找不到 MNN 库。
+
+**解决**:
+```bash
+# 确认库存在
+ls /usr/local/lib/libMNN.so
+
+# 添加路径
+echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/mnn.conf
+sudo ldconfig
+
+# 验证
+ldconfig -p | grep MNN
+```
+
+#### Q10: 启动报错 "error while loading shared libraries: libhyperlpr3.so"
+
+**原因**: HyperLPR3 库路径未配置。
+
+**解决**:
+```bash
+echo "/root/PlateRecApp/hyperlpr3/lib" | sudo tee /etc/ld.so.conf.d/hyperlpr3.conf
+sudo ldconfig
+ldconfig -p | grep hyperlpr3
+```
+
+#### Q11: RTSP 流无法连接,日志报 "Failed to open RTSP stream"
+
+**原因**: 网络不通、RTSP 地址错误或摄像头未开启。
+
+**解决**:
+```bash
+# 测试网络连通性
+ping 192.168.1.100
+
+# 使用 ffmpeg 测试 RTSP 流
+ffmpeg -rtsp_transport tcp -i "rtsp://admin:password@192.168.1.100:554/Streaming/Channels/101" -frames:v 1 test.jpg
+
+# 检查 config.ini 中 RTSP 地址是否正确
+grep "url1=" /root/PlateRecApp/config.ini
+```
+
+#### Q12: Web 管理后台无法访问(浏览器打不开 8080 端口)
+
+**原因**: 服务未启动、端口被占用或防火墙阻止。
+
+**解决**:
+```bash
+# 检查服务状态
+sudo systemctl status plate-rec
+
+# 检查端口
+ss -tlnp | grep 8080
+
+# 检查防火墙
+sudo ufw status
+sudo ufw allow 8080/tcp
+
+# 检查是否有端口冲突
+sudo lsof -i :8080
+```
+
+#### Q13: 飞书推送不工作
+
+**原因**: 配置错误或网络问题。
+
+**解决**:
+```bash
+# 检查配置
+grep -A5 "\[feishu\]" /root/PlateRecApp/config.ini
+
+# 手动测试 Webhook
+curl -X POST "https://open.feishu.cn/open-apis/bot/v2/hook/your-hook-id" \
+  -H "Content-Type: application/json" \
+  -d '{"msg_type":"text","content":{"text":"test"}}'
+
+# 查看日志中飞书相关错误
+journalctl -u plate-rec | grep -i feishu
+```
+
+#### Q14: MQTT 连接失败
+
+**原因**: Broker 地址错误、网络不通或认证失败。
+
+**解决**:
+```bash
+# 检查 Broker 连通性
+mosquitto_sub -h 192.168.1.200 -p 1883 -t "test" -d
+
+# 检查配置
+grep -A10 "\[mqtt\]" /root/PlateRecApp/config.ini
+
+# 查看 MQTT 相关日志
+journalctl -u plate-rec | grep -i mqtt
+```
+
+#### Q15: 程序运行一段时间后崩溃 (Segmentation fault)
+
+**原因**: 可能是内存泄漏、RTSP 断流重连问题或模型加载异常。
+
+**解决**:
+```bash
+# 查看崩溃前的日志
+journalctl -u plate-rec -p err --since "10 min ago"
+
+# 启用 core dump
+sudo sysctl -w kernel.core_pattern=/root/PlateRecApp/logs/core.%e.%p
+
+# 使用 Debug 模式编译以获取更多信息
+cd /root/PlateRecApp/build
+cmake -DCMAKE_BUILD_TYPE=Debug ..
+make -j4
+
+# 检查内存使用
+htop
+free -h
+
+# systemd 会自动重启服务(Restart=always)
+```
+
+#### Q16: 车牌识别率低
+
+**原因**: 摄像头角度、光线、ROI 设置或置信度阈值问题。
+
+**解决**:
+```bash
+# 调整 ROI 区域(通过 Web 管理后台或修改 config.ini)
+# roi1=x,y,width,height
+
+# 降低置信度阈值(可能增加误识别)
+# confidence_threshold=0.3
+
+# 检查摄像头画面质量
+ffmpeg -rtsp_transport tcp -i "rtsp://..." -frames:v 1 snapshot.jpg
+
+# 检查模型文件是否完整
+ls -la /root/PlateRecApp/hyperlpr3/models/
+```
+
+#### Q17: 数据库文件权限问题
+
+**原因**: 服务以 root 用户运行时创建的数据库文件,其他用户无法访问。
+
+**解决**:
+```bash
+# 确保 data 目录权限正确
+ls -la /root/PlateRecApp/data/
+
+# 修复权限
+chmod 644 /root/PlateRecApp/data/*.db
+chown root:root /root/PlateRecApp/data/*.db
+```
+
+#### Q18: config.ini 解析失败
+
+**原因**: 配置文件格式错误(如包含多余空格、编码问题)。
+
+**解决**:
+```bash
+# 检查配置文件编码
+file /root/PlateRecApp/config.ini
+# 应为: ASCII text 或 UTF-8 text
+
+# 检查语法(简单验证)
+cat /root/PlateRecApp/config.ini | grep -v "^#" | grep -v "^$"
+
+# 重新创建配置文件(参考 6.2 节)
+```
+
+#### Q19: frpc 管理功能报错 "Connection refused"
+
+**原因**: frpc 未安装或 admin API 端口未开放。
+
+**解决**:
+```bash
+# 检查 frpc 是否安装
+which frpc
+ls -la /usr/local/bin/frpc
+
+# 检查 frpc 配置文件
+cat /root/PlateRecApp/frpc.toml
+
+# 测试 admin API(仅允许 127.0.0.1)
+curl http://127.0.0.1:7400/api/status
+
+# 安全提示: frpc admin API 禁止通过 frp 隧道暴露到公网!
+```
+
+#### Q20: 登录认证系统无法登录
+
+**原因**: 认证数据库未初始化或密码错误。
+
+**解决**:
+```bash
+# 检查认证数据库
+ls -la /root/PlateRecApp/data/auth.db
+
+# 删除认证数据库让系统重新创建(会丢失用户数据)
+# rm /root/PlateRecApp/data/auth.db
+# sudo systemctl restart plate-rec
+
+# 默认超级管理员账号
+# 用户名: admin
+# 密码: zhonjin188A(在 config.ini 中配置)
+```
+
+#### Q21: 温度过高导致降频
+
+**原因**: 树莓派5 在高负载下温度可达 80°C+,触发降频保护。
+
+**解决**:
+```bash
+# 查看当前温度
+vcgencmd measure_temp
+# 或
+cat /sys/class/thermal/thermal_zone0/temp
+
+# 查看是否降频
+vcgencmd get_throttled
+# 0x0: 正常, 非0: 有降频/ throttling
+
+# 安装散热片/风扇
+# 推荐使用主动散热(风扇)方案
+```
+
+#### Q22: systemd 服务启动失败 "Exit code: 127"
+
+**原因**: 可执行文件路径错误或动态库找不到。
+
+**解决**:
+```bash
+# 检查可执行文件路径
+ls -la /root/PlateRecApp/PlateRecApp
+
+# 手动运行查看错误
+cd /root/PlateRecApp && ./PlateRecApp
+
+# 检查 LD_LIBRARY_PATH 配置
+grep LD_LIBRARY_PATH /etc/systemd/system/plate-rec.service
+
+# 确认所有动态库都能找到
+ldd /root/PlateRecApp/PlateRecApp | grep "not found"
+```
+
+#### Q23: 系统时间不准确
+
+**原因**: NTP 同步未配置或网络不通。
+
+**解决**:
+```bash
+# 检查时间同步状态
+timedatectl status
+
+# 启用 NTP
+sudo timedatectl set-ntp true
+
+# 设置时区
+sudo timedatectl set-timezone Asia/Shanghai
+
+# 手动同步时间
+sudo apt install -y ntpdate
+sudo ntpdate pool.ntp.org
+```
+
+---
+
+## 8. 性能优化建议
+
+### 8.1 CPU 调频优化
+
+树莓派5 的 Cortex-A76 核心最高可达 2.4GHz,默认使用 ondemand 调频策略。对于实时车牌识别场景,建议设置为 performance 模式。
+
+```bash
+# 查看当前 CPU 调频策略
+cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
+
+# 设置为 performance 模式(全速运行)
+echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
+
+# 设置为 powersave 模式(省电)
+echo powersave | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
+
+# 持久化配置(每次启动自动设置)
+sudo apt install -y cpufrequtils
+sudo tee /etc/default/cpufrequtils << 'EOF'
+GOVERNOR=performance
+EOF
+sudo systemctl enable cpufrequtils
+```
+
+> **注意**: performance 模式会持续运行在最高频率,功耗和温度会增加。建议配合主动散热使用。
+
+### 8.2 内存管理优化
+
+```bash
+# 查看内存使用
+free -h
+
+# 设置 swappiness(降低 swap 使用倾向,优先使用物理内存)
+echo "vm.swappiness=10" | sudo tee -a /etc/sysctl.conf
+sudo sysctl -p
+
+# 预分配大页内存(可选,MNN 推理可能受益)
+# echo "vm.nr_hugepages=16" | sudo tee -a /etc/sysctl.conf
+
+# 禁用不必要的 systemd 服务释放内存
+sudo systemctl disable bluetooth.service 2>/dev/null
+sudo systemctl disable cups.service 2>/dev/null
+sudo systemctl disable ModemManager.service 2>/dev/null
+```
+
+### 8.3 DRM 硬解优化
+
+对于 HEVC (H.265) 编码的 RTSP 流,树莓派5 支持 DRM 硬件解码,可大幅降低 CPU 占用。
+
+```bash
+# 检查 DRM 设备
+ls /dev/dri/
+
+# 检查 V4L2 硬件解码支持
+v4l2-ctl --list-devices
+
+# 在 config.ini 中启用 DRM 硬解
+# decode_mode=drm
+
+# 测试 DRM 硬解
+ffmpeg -hwaccel drm -hwaccel_output_format drm_prime \
+  -rtsp_transport tcp -i "rtsp://..." \
+  -frames:v 10 -f null -
+```
+
+**DRM 硬解 vs 软解对比**:
+
+| 模式 | CPU 占用 | 延迟 | 兼容性 | 推荐场景 |
+|------|---------|------|--------|---------|
+| `auto` | 中 | 低 | 广 | 默认推荐 |
+| `drm` | 极低 (~5%) | 最低 | HEVC 流 | 4路 HEVC 摄像头 |
+| `cpu` | 高 (~60%每路) | 中 | 最广 | H.264 流或兼容性要求 |
+
+### 8.4 RTSP 流优化
+
+```bash
+# 优化网络缓冲区(提高 RTSP 流稳定性)
+sudo sysctl -w net.core.rmem_max=16777216
+sudo sysctl -w net.core.wmem_max=16777216
+
+# 持久化
+cat >> /etc/sysctl.conf << 'EOF'
+net.core.rmem_max=16777216
+net.core.wmem_max=16777216
+net.ipv4.tcp_rmem=4096 87380 16777216
+net.ipv4.tcp_wmem=4096 65536 16777216
+EOF
+sudo sysctl -p
+```
+
+### 8.5 文件系统优化
+
+```bash
+# 使用 tmpfs 存放临时文件(减少 SD 卡写入)
+sudo tee -a /etc/fstab << 'EOF'
+tmpfs /tmp tmpfs defaults,noatime,size=256M 0 0
+tmpfs /var/log tmpfs defaults,noatime,size=128M 0 0
+EOF
+
+# SD 卡优化:禁用 atime 减少写入
+# 在 /etc/fstab 的挂载选项中添加 noatime
+# 例如: /dev/mmcblk0p2 / ext4 defaults,noatime 0 1
+
+# 强烈建议使用 SSD/USB 3.0 存储替代 microSD 卡
+# 通过 USB 3.0 接口连接 SSD,性能提升 5-10 倍
+```
+
+### 8.6 MNN 推理优化
+
+```bash
+# 在 config.ini 或环境变量中配置 MNN 推理参数
+# MNN_NUM_THREADS=4     # 推理线程数,匹配核心数
+# MNN_ARM82=1           # 启用 fp16 加速(编译时已启用)
+
+# 监控推理耗时
+# 查看日志中的推理耗时统计
+journalctl -u plate-rec | grep "inference" | tail -20
+```
+
+### 8.7 散热方案
+
+| 方案 | 散热能力 | 噪音 | 推荐度 |
+|------|---------|------|--------|
+| 被动散热片(铝制) | 中 | 无 | ⭐⭐⭐ |
+| 主动风扇(30mm) | 高 | 低 | ⭐⭐⭐⭐ |
+| 冰塔散热器 | 极高 | 无 | ⭐⭐⭐⭐⭐ |
+| 金属外壳散热 | 高 | 无 | ⭐⭐⭐⭐ |
+
+> **建议**: 4路 RTSP 流 + 车牌识别场景下,强烈推荐使用主动散热方案,确保 CPU 温度低于 70°C。
+
+### 8.8 系统监控
+
+```bash
+# 安装监控工具
+sudo apt install -y htop iotop iftop
+
+# 实时监控
+htop
+
+# 查看温度
+watch -n 1 "cat /sys/class/thermal/thermal_zone0/temp | awk '{print \$1/1000}'"
+
+# 查看 CPU 频率
+watch -n 1 "cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq | awk '{print \$1/1000 \" MHz\"}'"
+
+# 查看磁盘 IO
+iotop -o
+
+# 查看网络流量
+iftop -i end0
+```
+
+---
+
+## 附录 A: 完整安装脚本(一键执行)
+
+将以下步骤合并为单个脚本,适合全新安装:
+
+```bash
+#!/bin/bash
+# PlateRecApp 一键安装脚本 (树莓派5 + Ubuntu 24.04)
+# 使用方法: chmod +x install.sh && sudo ./install.sh
+
+set -e
+
+echo "========================================="
+echo " PlateRecApp 安装脚本"
+echo " 平台: 树莓派5 8G + Ubuntu 24.04"
+echo "========================================="
+
+# 1. 系统更新
+echo "[1/6] 更新系统..."
+apt update && apt upgrade -y
+
+# 2. 安装依赖
+echo "[2/6] 安装编译依赖..."
+apt install -y \
+    build-essential cmake git wget curl pkg-config unzip \
+    libopencv-dev \
+    libavformat-dev libavcodec-dev libavutil-dev libswscale-dev \
+    libsqlite3-dev \
+    libcurl4-openssl-dev libssl-dev \
+    libfreetype-dev \
+    libcjson-dev \
+    libmosquitto-dev libmosquittopp-dev \
+    libprotobuf-dev protobuf-compiler \
+    libcrypt-dev
+
+# 3. 编译安装 MNN
+echo "[3/6] 编译安装 MNN..."
+if [ ! -d "/usr/local/include/MNN" ]; then
+    cd /root
+    git clone --depth 1 --branch 2.9.6 https://github.com/alibaba/MNN.git
+    cd MNN && mkdir build && cd build
+    cmake .. \
+        -DCMAKE_BUILD_TYPE=Release \
+        -DMNN_BUILD_SHARED_LIBS=ON \
+        -DMNN_BUILD_CONVERTER=OFF \
+        -DMNN_BUILD_DEMO=OFF \
+        -DMNN_BUILD_TOOLS=OFF \
+        -DMNN_BUILD_TRAIN=OFF \
+        -DMNN_ARM82=ON \
+        -DMNN_FP16=ON \
+        -DMNN_USE_THREAD_POOL=ON \
+        -DMNN_NUM_THREADS=4 \
+        -DCMAKE_INSTALL_PREFIX=/usr/local
+    make -j4
+    make install
+    ldconfig
+    echo "✅ MNN 安装完成"
+else
+    echo "✅ MNN 已存在,跳过"
+fi
+
+# 4. 安装 HyperLPR3 SDK
+echo "[4/6] 安装 HyperLPR3 SDK..."
+if [ ! -d "/root/PlateRecApp/hyperlpr3/include" ]; then
+    echo "⚠️ 请手动安装 HyperLPR3 SDK 到 /root/PlateRecApp/hyperlpr3/"
+    echo "   参考本文档第4节"
+else
+    echo "/root/PlateRecApp/hyperlpr3/lib" > /etc/ld.so.conf.d/hyperlpr3.conf
+    ldconfig
+    echo "✅ HyperLPR3 SDK 配置完成"
+fi
+
+# 5. 编译 PlateRecApp
+echo "[5/6] 编译 PlateRecApp..."
+cd /root/PlateRecApp
+mkdir -p build && cd build
+cmake .. -DCMAKE_BUILD_TYPE=Release
+make -j4
+echo "✅ 编译完成: $(ls -lh PlateRecApp)"
+
+# 6. 配置 systemd 服务
+echo "[6/6] 配置系统服务..."
+mkdir -p /root/PlateRecApp/{data,fonts,html,logs}
+
+# 性能优化
+echo "performance" > /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor 2>/dev/null || true
+
+echo ""
+echo "========================================="
+echo " ✅ 安装完成!"
+echo ""
+echo " 后续步骤:"
+echo " 1. 编辑 /root/PlateRecApp/config.ini"
+echo " 2. 安装 HyperLPR3 SDK 模型文件"
+echo " 3. sudo systemctl daemon-reload"
+echo " 4. sudo systemctl enable --now plate-rec"
+echo "========================================="
+```
+
+---
+
+## 附录 B: 系统信息收集(用于问题反馈)
+
+遇到问题时,运行以下命令收集系统信息:
+
+```bash
+echo "=== 系统信息 ==="
+uname -a
+cat /etc/os-release | head -3
+echo "=== CPU ==="
+lscpu | grep -E "Model name|Architecture|CPU\(s\)|Thread"
+echo "=== 内存 ==="
+free -h
+echo "=== 温度 ==="
+cat /sys/class/thermal/thermal_zone0/temp | awk '{print $1/1000 "°C"}'
+echo "=== 磁盘 ==="
+df -h / /root
+echo "=== 依赖版本 ==="
+pkg-config --modversion opencv4 2>/dev/null && echo "OpenCV: ✅" || echo "OpenCV: ❌"
+pkg-config --modversion libavformat 2>/dev/null && echo "FFmpeg: ✅" || echo "FFmpeg: ❌"
+pkg-config --modversion sqlite3 2>/dev/null && echo "SQLite3: ✅" || echo "SQLite3: ❌"
+echo "=== MNN ==="
+ls /usr/local/lib/libMNN.so 2>/dev/null && echo "MNN: ✅" || echo "MNN: ❌"
+echo "=== HyperLPR3 ==="
+ls /root/PlateRecApp/hyperlpr3/lib/libhyperlpr3.so 2>/dev/null && echo "HyperLPR3: ✅" || echo "HyperLPR3: ❌"
+echo "=== PlateRecApp ==="
+file /root/PlateRecApp/PlateRecApp 2>/dev/null || echo "未编译"
+echo "=== 动态库检查 ==="
+ldd /root/PlateRecApp/PlateRecApp 2>/dev/null | grep "not found" || echo "所有库已找到 ✅"
+```
+
+---
+
+> **📝 本文档持续更新**  
+> 最后更新: 2026-08-30 | 版本: fix27 v44  
+> 如有问题或建议,请联系项目维护者。

+ 1005 - 0
TECH_DOC.md

@@ -0,0 +1,1005 @@
+# PlateRecApp 技术方案文档
+
+> **版本**: v43.2 fix24  
+> **作者**: steven_roc  
+> **仓库**: https://git.zhonjin.com:40717/steven_roc/PlateRecApp  
+> **最后更新**: 2026-07-06  
+
+---
+
+## 1. 项目概述
+
+### 1.1 项目名称
+**PlateRecApp**(HyperLPR3-LinuxAPP)
+
+### 1.2 系统定位
+面向渣土车/工程车辆管理的**车牌识别+称重+联单上传**一体化边缘计算系统。部署在工地出入口的树莓派5上,通过4路RTSP摄像头实时捕获车牌,结合称重仪表数据,自动完成:
+
+- 车牌识别(HyperLPR3 + MNN推理引擎)
+- 进站/出站交替锁定管理
+- 照片水印叠加与平台上传
+- 飞书实时通知推送
+- MQTT消息发布
+- 耀华称重仪表数据采集与上报
+- Web管理后台(监控/视频/配置/锁定管理)
+- frpc内网穿透管理
+- SSH密钥管理
+- 系统资源监控
+
+### 1.3 目标场景
+工地/码头/回填点出入口,单点双向(进站+出站),支持4个摄像头(前低位×2 + 侧高位×2),支持共享摄像头模式。
+
+---
+
+## 2. 软件环境
+
+### 2.1 目标硬件
+| 参数 | 规格 |
+|------|------|
+| 主板 | 树莓派5 8GB |
+| CPU | BCM2712, Quad-core Arm Cortex-A76 |
+| GPU | VideoCore VII |
+| 内存 | 8GB LPDDR4X |
+
+### 2.2 操作系统
+| 参数 | 值 |
+|------|-----|
+| OS | Ubuntu 24.04 LTS |
+| 架构 | aarch64 (ARM64) |
+| 内核 | Linux 6.x |
+
+### 2.3 编译器与构建工具
+| 工具 | 版本/标准 |
+|------|-----------|
+| GCC | 11+ (aarch64-linux-gnu) |
+| C++ 标准 | C++17 (CMAKE_CXX_STANDARD 17) |
+| CMake | 3.25.1+ |
+| 构建类型 | Release (默认) / Debug / MinSizeRel / RelWithDebInfo |
+
+### 2.4 依赖库清单
+
+| 库名 | 用途 | 查找方式 |
+|------|------|----------|
+| OpenCV | 图像处理、JPEG编解码、水印渲染 | `find_package(OpenCV REQUIRED)` |
+| HyperLPR3 SDK | 车牌检测+识别(MNN推理) | 头文件 `hyper_lpr_sdk.h`,库 `libhyperlpr3` |
+| SQLite3 | 本地数据库(记录存储、认证、监控) | `pkg_check_modules(SQLITE3 REQUIRED sqlite3)` |
+| cURL | HTTP客户端(API上传、飞书消息) | `find_package(CURL REQUIRED)` |
+| OpenSSL | HTTPS/SSL、MD5计算 | `find_package(OpenSSL REQUIRED)` |
+| FreeType2 | 中文字体渲染(水印文字) | `pkg_check_modules(FREETYPE REQUIRED freetype2)` |
+| FFmpeg (libavformat/libavcodec/libavutil/libswscale) | RTSP流解码、DRM硬件加速 | `pkg_check_modules` |
+| cJSON | JSON解析与生成 | 手动查找 + pkg-config 回退 |
+| mosquitto / mosquittopp | MQTT客户端通信 | 直接链接 |
+| libcrypt | bcrypt密码哈希(`crypt_r`) | `find_library(CRYPT_LIBRARY crypt)` |
+| inih | INI配置文件解析 | 第三方头文件 `ini.h` |
+| httplib (cpp-httplib) | 轻量级HTTP/HTTPS服务器 | 第三方头文件 `httplib.h` |
+| cvxFont | OpenCV中文字体绘制 | 第三方库 `cvxFont.h` |
+
+---
+
+## 3. 系统架构
+
+### 3.1 模块划分图
+
+```
+┌─────────────────────────────────────────────────────────────────────┐
+│                         main.cpp (主调度)                            │
+│   配置加载 → 数据库初始化 → HyperLPR初始化 → 摄像头启动 → 主循环       │
+└──────┬──────────┬──────────┬──────────┬──────────┬─────────────────┘
+       │          │          │          │          │
+  ┌────▼───┐ ┌───▼────┐ ┌──▼───┐ ┌───▼────┐ ┌───▼──────┐
+  │ config │ │database│ │web   │ │feishu  │ │ MQTT +   │
+  │  .cpp  │ │  .cpp  │ │server│ │client  │ │ Weight   │
+  └────────┘ └────────┘ └──────┘ └────────┘ │ Scale    │
+                                             └──────────┘
+  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐
+  │  RTSP    │ │  Plate   │ │ Station  │ │   Network    │
+  │ Capture  │ │Recognize │ │  Lock    │ │   Client     │
+  │  (×4)    │ │   r.cpp  │ │  .cpp    │ │   .cpp       │
+  └──────────┘ └──────────┘ └──────────┘ └──────────────┘
+  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐
+  │  Auth    │ │  frpc    │ │  SSH     │ │  System      │
+  │ System   │ │ Manager  │ │ Manager  │ │  Monitor     │
+  │(*.cpp)   │ │  .cpp    │ │  .cpp    │ │  .cpp        │
+  └──────────┘ └──────────┘ └──────────┘ └──────────────┘
+  ┌──────────┐ ┌──────────────────────────────────────────┐
+  │   Log    │ │     common.h (全局类型/结构体/指标)       │
+  │ Manager  │ │     MonitorMetrics / ROIConfig / ...     │
+  └──────────┘ └──────────────────────────────────────────┘
+```
+
+### 3.2 模块间依赖关系
+
+```
+common.h ← 所有模块(全局类型定义)
+config.cpp ← main.cpp(配置加载)
+rtsp_capture.cpp ← plate_recognizer.cpp(帧采集)
+plate_recognizer.cpp ← main.cpp(识别主逻辑)
+station_lock.cpp ← plate_recognizer.cpp(交替锁定)
+database.cpp ← plate_recognizer.cpp, web_server.cpp(数据持久化)
+network_client.cpp ← plate_recognizer.cpp, weight_scale.cpp(HTTP API)
+feishu_client.cpp ← plate_recognizer.cpp(飞书通知)
+mqtt_client.cpp ← weight_scale.cpp(MQTT发布)
+weight_scale.cpp ← main.cpp(称重数据采集)
+web_server.cpp ← main.cpp(Web服务线程)
+auth_*.cpp ← web_server.cpp(认证中间件)
+frpc_manager.cpp ← web_server.cpp(frpc管理API)
+ssh_manager.cpp ← web_server.cpp(SSH密钥管理)
+log_manager.cpp ← main.cpp(日志缓冲)
+system_monitor.cpp ← web_server.cpp(系统监控)
+```
+
+### 3.3 数据流图
+
+```
+RTSP摄像头(×4)
+    │
+    ▼ FFmpeg解码(软解/DRM硬解)
+帧队列(deque<cv::Mat>, 最大10帧)
+    │
+    ▼ getFrame() 取出最新帧
+ROI裁剪(可选, 按配置区域)
+    │
+    ▼ HyperLPR3推理(HLPR_UpdateImage)
+车牌检测结果(车牌号+置信度+类型)
+    │
+    ▼ 帧级去重(2秒内同车牌跳过)
+    │
+    ├─── 置信度 ≥ LOG_THRESHOLD? ──→ 保存照片(加水印) → 插入SQLite
+    │
+    ▼ 置信度 ≥ CONFIDENCE_THRESHOLD?
+    │
+    ├─── 交替锁定检查(try_lock_in/out_station)
+    │       │ BLOCKED → 跳过
+    │       ▼ ALLOWED
+    │
+    ├─── 创建联单(lib_curl_create_bill_request) → 获取tb_num
+    │
+    ├─── 上传照片(低位+高位×2组) → 平台API
+    │
+    ├─── 飞书通知(send_feishu_msg) → 飞书开放API
+    │
+    └─── 称重+MQTT(weight_scale → mqtt_publish) → MQTT Broker
+```
+
+---
+
+## 4. 核心模块技术方案
+
+### 4.1 车牌识别引擎(HyperLPR3 + MNN)
+
+#### 4.1.1 初始化流程
+```cpp
+// hyperlpr_lib_init() — plate_recognizer.cpp
+HLPR_ContextConfiguration configuration = { 0 };
+configuration.models_path = (char*)model.c_str();  // hyperlpr3/resource/models/r2_mobile
+configuration.max_num = 2;                    // 每帧最多检测2个车牌
+configuration.det_level = DETECT_LEVEL_HIGH;  // 高精度检测模式
+configuration.use_half = false;               // 不使用FP16半精度
+configuration.nms_threshold = 0.5f;           // NMS非极大值抑制阈值
+configuration.rec_confidence_threshold = 0.6f; // 识别置信度阈值
+configuration.box_conf_threshold = 0.30f;     // 检测框置信度阈值
+configuration.threads = 1;                    // 推理线程数
+plate_rec_app.hlpr_ctx = HLPR_CreateContext(&configuration);
+```
+
+#### 4.1.2 推理流程
+1. `capture_do_work_thread()` 主循环每500ms执行一次
+2. 从4路RTSPCapture获取最新帧
+3. ROI裁剪(如启用)→ `HLPR_CreateDataBuffer` → `HLPR_UpdateImage`
+4. 遍历检测结果,按置信度更新 `CarPlateInfo`
+5. 置信度 ≥ `PLATE_LOG_THRESHOLD` → 保存照片到磁盘
+6. 置信度 ≥ `PLATE_CONFIDENCE_THRESHOLD` → 触发上传流程
+
+#### 4.1.3 ROI裁剪策略
+```cpp
+struct ROIConfig {
+    int x, y, width, height;  // 裁剪区域
+    bool enabled;              // 是否启用
+    cv::Rect getRect(int img_w, int img_h);  // 安全边界裁剪
+};
+// 进站ROI: g_roi_in, 出站ROI: g_roi_out
+// 支持通过Web界面手动绘制调整,写回config.ini
+```
+
+#### 4.1.4 车牌类型映射
+```cpp
+static const std::vector<std::string> TYPES = {
+    "蓝牌", "黄牌", "白牌单层", "绿牌", "黑牌港澳", "香港单层",
+    "香港双层", "澳门单层", "澳门双层", "黄牌双层"
+};
+```
+
+#### 4.1.5 关键结构体
+```cpp
+struct CarPlateInfo {
+    std::string code;          // 车牌号
+    float confidence;          // 识别置信度
+    std::string type;          // 车牌类型(蓝牌/黄牌等)
+    cv::Mat image_front;       // 前向照片
+    cv::Mat image_side;        // 侧向照片
+    int db_id;                 // 数据库记录ID
+    bool is_inbound/outbound;  // 进站/出站标记
+    time_t db_capture_time;    // 照片保存时固定的capture_time
+    std::atomic<bool> upload_in_progress{false};  // P0: 上传竞态保护
+};
+```
+
+### 4.2 RTSP视频采集
+
+#### 4.2.1 类设计
+```cpp
+class RTSPCapture {
+    std::string rtspUrl_;
+    DecodeMode decodeMode_;      // AUTO / SOFT / DRM
+    std::string drmDevice_;      // 默认 /dev/dri/renderD128
+    std::string transport_;      // tcp / udp
+    AVFormatContext* fmtCtx_;
+    AVCodecContext* codecCtx_;
+    AVBufferRef* hwDeviceCtx_;   // DRM硬件设备上下文
+    SwsContext* swsCtx_;         // 像素格式转换上下文
+    std::deque<cv::Mat> frameQueue_;  // 帧队列(最大10帧)
+    std::thread captureThread_;
+};
+```
+
+#### 4.2.2 FFmpeg解码流程
+1. `avformat_open_input()` — 打开RTSP流
+2. `avformat_find_stream_info()` — 获取流信息
+3. `av_find_best_stream()` — 查找视频流
+4. 根据codec判断:HEVC → 尝试DRM硬解,否则软解
+5. `avcodec_open2()` — 打开解码器(thread_count=4)
+6. `captureLoop()` 循环读取帧 → `decodeFrameToBGR()` → 入队
+
+#### 4.2.3 DRM硬件加速配置
+```cpp
+bool initDRMHwAccel() {
+    AVHWDeviceType type = av_hwdevice_find_type_by_name("drm");
+    av_hwdevice_ctx_create(&hwDeviceCtx_, type, "/dev/dri/renderD128", nullptr, 0);
+    codecCtx_->hw_device_ctx = av_buffer_ref(hwDeviceCtx_);
+}
+// 解码后检测 AV_PIX_FMT_DRM_PRIME 格式 → av_hwframe_transfer_data 转CPU
+```
+
+#### 4.2.4 帧队列管理
+- 队列容量:最大10帧,超出时丢弃最旧帧
+- `getFrame()` — 取出并移除最新帧(供识别线程使用)
+- `peekFrame()` — 只读取不移除(供MJPEG视频流使用,避免与识别线程竞争)
+- 解码线程与消费线程通过 `std::mutex + condition_variable` 同步
+
+#### 4.2.5 重连策略
+- 读取失败(`av_read_frame` 返回错误)→ `cleanupFFmpeg()` → 等待3秒 → 重新 `initFFmpeg()`
+- 连接超时:5秒(`timeout=5000000`微秒)
+- RTSP传输:默认TCP(可配置UDP)
+- 低延迟优化:`fflags=nobuffer+genpts`, `flags=low_delay`
+
+#### 4.2.6 FFmpeg选项
+```cpp
+av_dict_set(&opts, "rtsp_transport", "tcp", 0);
+av_dict_set(&opts, "timeout", "5000000", 0);      // 5秒超时
+av_dict_set(&opts, "fflags", "nobuffer+genpts", 0);
+av_dict_set(&opts, "flags", "low_delay", 0);
+av_dict_set(&opts, "avoid_negative_ts", "make_zero", 0);
+av_dict_set(&opts, "err_detect", "ignore_err", 0);
+```
+
+### 4.3 交替锁定机制
+
+#### 4.3.1 核心规则(fix17版)
+| 状态转换 | 等待时间 | 超时行为 |
+|----------|----------|----------|
+| 进站完成 → 允许出站 | `in_out_interval` (默认300秒) | 等待≤2小时,超时清零 |
+| 出站完成 → 允许进站 | `in_out_interval + TIME_WINDOW` (默认600秒) | 等待≤2小时,超时清零 |
+| 出站无进站记录 | 永远拦截 | 必须先进站才能出站 |
+| 同方向连续操作 | 永远拦截 | 必须先完成对端操作 |
+
+#### 4.3.2 状态机
+```
+INBOUND_ALLOWED  → 上次出站完成,等待 in_out_interval+TIME_WINDOW 后允许进站
+OUTBOUND_ALLOWED → 上次进站完成,等待 in_out_interval 后允许出站
+无记录出站       → 永远拦截(必须先进站)
+锁定超2小时     → 自动清零释放(视为车辆已离开)
+```
+
+#### 4.3.3 关键函数
+```cpp
+bool try_lock_in_station(const std::string& plate);   // 原子锁定进站
+bool try_lock_out_station(const std::string&plate);   // 原子锁定出站
+void lock_in_station(const std::string& plate);        // 确认进站锁定
+void lock_out_station(const std::string& plate);       // 确认出站锁定
+void unlock_rollback_station(const std::string& plate, bool is_in);  // 失败回滚
+void cleanup_station_cache();                          // 2小时超时清理
+void load_station_cache_from_db();                     // 重启恢复
+```
+
+#### 4.3.4 持久化
+- 数据库表:`station_lock_cache`
+- 字段:`plate_number`, `last_in_time`, `last_out_time`, `current_mode`
+- 重启后自动从数据库恢复锁定状态,超时记录直接删除
+
+### 4.4 称重调度器
+
+#### 4.4.1 耀华仪表通信协议
+```
+帧格式: 0x02 + sign(1字节) + digits(8字节) + status(1字节) + 0x03
+帧长度: 12字节
+数据解析: weight_kg = digits_value / 100.0  (单位: 分→公斤)
+有效状态: 排除 status='G'/'H' 的帧
+重量范围: g_weight_min_kg ~ g_weight_max_kg
+```
+
+#### 4.4.2 TCP连接管理
+- 连接超时:`tcp_connect_timeout`(可配置)
+- 读取间隔:200ms
+- 断线重连:5秒延迟自动重连
+- 接收缓冲区:1024字节
+
+#### 4.4.3 稳定读数检测
+```cpp
+// 稳定性判定:连续 g_weight_stable_samples 个样本波动 ≤ g_weight_stable_threshold
+g_stability_samples.push_back(weight_kg);
+if (size > g_weight_stable_samples) g_stability_samples.erase(begin);
+// 候选数据:收集 g_weight_candidate_count 个有效读数
+```
+
+#### 4.4.4 称重+MQTT异步任务队列
+```cpp
+struct WeightMqttTask {
+    std::string plate;
+    int station_type;   // 1=进站, 2=出站
+    std::string tb_num;
+};
+// 去重机制:30秒内同车牌只发送一次MQTT消息
+static std::unordered_map<std::string, time_t> g_mqtt_dedup_map;
+static const int MQTT_DEDUP_INTERVAL_SEC = 30;
+```
+
+### 4.5 Web管理后台
+
+#### 4.5.1 框架与配置
+- **HTTP框架**: cpp-httplib(header-only)
+- **SSL支持**: OpenSSL,通过 `httplib::SSLServer` 创建HTTPS服务器
+- **默认端口**: 8080(从config.ini `[server] ip` 字段解析)
+- **HTTP重定向**: 可选HTTP→HTTPS自动跳转(fix24-v19)
+
+#### 4.5.2 SSL性能优化
+```cpp
+// SSL会话缓存:10分钟有效期
+SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_SERVER);
+SSL_CTX_set_timeout(ssl_ctx, 600);
+// 优先使用ECDHE+AESGCM/ChaCha20密码套件
+SSL_CTX_set_cipher_list(ssl_ctx,
+    "ECDHE-ECDSA-AES128-GCM-SHA256:"
+    "ECDHE-RSA-AES128-GCM-SHA256:"
+    "ECDHE-ECDSA-CHACHA20-POLY1305:...");
+SSL_CTX_set_ecdh_auto(ssl_ctx, 1);  // 优先X25519
+```
+
+#### 4.5.3 路由表
+
+| 路径 | 方法 | 功能 | 认证要求 |
+|------|------|------|----------|
+| `/` | GET | 监控首页 | 公开/基础 |
+| `/video` | GET | 4路视频预览 | 公开/基础 |
+| `/login` | GET | 登录页面 | 公开 |
+| `/config` | GET | 系统配置 | 管理员 |
+| `/locks` | GET | 锁定管理 | 公开/基础 |
+| `/system` | GET | 系统监控 | 公开/基础 |
+| `/api/monitor` | GET | 监控指标JSON | 公开 |
+| `/api/messages` | GET | 记录列表JSON | 公开 |
+| `/api/system/status` | GET | 系统资源状态 | 公开 |
+| `/api/frpc/status` | GET | frpc隧道状态 | 管理员 |
+| `/api/frpc/config` | GET/POST | frpc配置读写 | 超级管理员 |
+| `/api/auth/login` | POST | 登录认证 | 公开 |
+| `/api/auth/logout` | POST | 登出 | 已登录 |
+| `/api/auth/status` | GET | 会话状态 | 公开 |
+| `/api/station_locks` | GET | 锁定记录列表 | 公开 |
+| `/api/clear_lock` | POST | 清除锁定 | 管理员 |
+| `/api/video/{stream}` | GET | MJPEG视频流 | 公开 |
+| `/api/photo/{path}` | GET | 照片访问 | 公开 |
+
+#### 4.5.4 认证系统
+
+**架构**: bcrypt密码哈希 + 内存+SQLite双层Session + CSRF Token + IP速率限制
+
+```cpp
+// auth_db.h — 数据库层
+struct User {
+    int id; std::string username; std::string password_hash;
+    int role;       // 0=user, 1=admin, 2=superadmin
+    int enabled;
+    int failed_attempts; time_t locked_until;
+};
+struct Session {
+    std::string session_id;  // 64字符hex
+    std::string csrf_token;  // 64字符hex
+    int user_id; std::string username;
+    time_t created_at, last_active, expires_at;
+    int remember;   // 1=延长会话(7天)
+    int user_role;
+};
+
+// 数据库表: users, sessions, audit_log
+// WAL模式 + busy_timeout=5000ms
+```
+
+**Session管理**:
+- 空闲超时: 30分钟 (1800秒)
+- 绝对超时: 8小时 (28800秒)
+- "记住我": 7天 (604800秒)
+- 内存缓存 + SQLite持久化双层架构
+
+**速率限制**:
+- 滑动窗口: 5分钟 (300秒)
+- 最大尝试: 5次/IP
+- 超限返回 HTTP 429
+
+**CSRF保护**:
+- 每个Session生成64字符hex CSRF Token
+- 状态变更请求(POST/PUT/DELETE)必须携带 `X-CSRF-Token` 头
+
+**安全响应头**:
+- `X-Content-Type-Options: nosniff`
+- `X-Frame-Options: DENY`
+- `X-XSS-Protection: 1; mode=block`
+- `Content-Security-Policy: default-src 'self'`
+
+### 4.6 飞书/MQTT推送
+
+#### 4.6.1 飞书消息
+
+**API**: `POST https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id`
+
+**消息格式**:
+```json
+{
+    "receive_id": "{chat_id}",
+    "msg_type": "text",
+    "content": "{\"text\":\"工程名: xxx\\n车牌号: xxx\\n时间: xxx\\n...\"}"
+}
+```
+
+**重试策略**:
+- 最大重试: 4次(初始请求 + 3次重试)
+- 退让策略: 指数退让 2^n 秒 (2s, 4s, 8s)
+- 网络超时/连接失败 → 重试;业务错误 → 直接终止
+
+**Token管理**:
+- `g_tenant_token`: 飞书租户访问令牌
+- 过期时间: `g_token_expire_time`
+- 刷新缓冲: 300秒 (`TOKEN_REFRESH_BUFFER_SECONDS`)
+
+#### 4.6.2 MQTT客户端
+
+**架构**: 基于 `mosquittopp` 类,继承回调机制
+
+```cpp
+class MqttClient : public mosqpp::mosquittopp {
+    std::atomic<bool> connected{false};
+    std::atomic<MqttState> current_state{DISCONNECTED};
+    static const int MAX_RECONNECT_ATTEMPTS = 30;
+};
+```
+
+**连接管理**:
+- 异步连接: `connect_async(host, port, keepalive=60)`
+- 状态机: DISCONNECTED → CONNECTING → CONNECTED → STABLE (5秒后)
+- 最大重连: 30次
+- ClientID格式: `{client_id}_{pid}_{timestamp}`
+
+**消息发布**:
+- QoS: 1 (至少一次)
+- 发布后等待ACK确认 (`acked` 原子变量)
+- 连接断开后自动重连
+
+**消息内容**: 车牌号 + 车牌颜色 + 车型 + 联单编号 + 进出站类型
+
+### 4.7 数据库操作
+
+#### 4.7.1 SQLite表结构
+
+**主表: `upload_records`**
+```sql
+CREATE TABLE upload_records (
+    id INTEGER PRIMARY KEY AUTOINCREMENT,
+    create_time DATETIME DEFAULT (datetime('now', 'localtime')),
+    capture_time INTEGER,           -- fix24-v13: 抓拍时刻Unix时间戳
+    plate_number TEXT NOT NULL,
+    tb_num TEXT NOT NULL,
+    station_type INTEGER,           -- 1=进站, 2=出站
+    lo_photo_path TEXT,
+    hi_photo_path TEXT,
+    lo_upload_status INTEGER DEFAULT 0,
+    hi_upload_status INTEGER DEFAULT 0,
+    feishu_status INTEGER DEFAULT 0,
+    retry_count INTEGER DEFAULT 0
+);
+-- 索引
+CREATE INDEX idx_plate_number ON upload_records(plate_number);
+CREATE INDEX idx_tb_num ON upload_records(tb_num);
+CREATE INDEX idx_create_time ON upload_records(create_time);
+CREATE INDEX idx_plate_station_time_status ON upload_records(
+    plate_number, station_type, create_time, lo_upload_status, hi_upload_status);
+```
+
+**交替锁定表: `station_lock_cache`**
+```sql
+CREATE TABLE station_lock_cache (
+    plate_number TEXT PRIMARY KEY,
+    last_in_time INTEGER,
+    last_out_time INTEGER,
+    current_mode INTEGER    -- 0=INBOUND_ALLOWED, 1=OUTBOUND_ALLOWED
+);
+```
+
+**TIME_WINDOW缓存表: `time_window_cache`**
+```sql
+-- 存储进站/出站工单配额缓存
+CREATE TABLE time_window_cache (...);
+```
+
+**认证数据库表** (独立SQLite文件):
+```sql
+CREATE TABLE users (
+    id INTEGER PRIMARY KEY AUTOINCREMENT,
+    username TEXT UNIQUE NOT NULL,
+    password_hash TEXT NOT NULL,     -- bcrypt hash
+    role INTEGER DEFAULT 0,
+    enabled INTEGER DEFAULT 1,
+    failed_attempts INTEGER DEFAULT 0,
+    locked_until INTEGER DEFAULT 0,
+    created_at INTEGER NOT NULL,
+    updated_at INTEGER NOT NULL
+);
+CREATE TABLE sessions (...);
+CREATE TABLE audit_log (...);
+```
+
+**系统监控数据库** (独立SQLite文件):
+- 路径: `data/system_metrics.db`
+- 用途: CPU/内存/温度/磁盘历史数据
+
+#### 4.7.2 数据库配置
+```cpp
+sqlite3_busy_timeout(g_db, 100);       // busy超时100ms
+SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX
+// WAL模式(认证数据库)
+// 认证数据库: busy_timeout=5000ms
+```
+
+#### 4.7.3 缓存策略
+- TIME_WINDOW缓存: 内存 + SQLite 双层
+- 交替锁定缓存: 内存(`g_plate_station_cache`) + SQLite 双层
+- 联单缓存: `g_in_bill_cache` / `g_out_bill_cache` (内存)
+- 数据库自动清理: 每日23:10执行 `db_cleanup_old_records` + `db_vacuum`
+- 数据库健康检查: 每60秒 `SELECT 1` 探活,失败自动重连
+- DB容量阈值: 500MB触发清理 (`DB_CLEANUP_THRESHOLD_MB`)
+
+### 4.8 日志管理
+
+#### 4.8.1 内存日志缓冲架构(fix24-v36)
+```
+stdout/stderr → pipe() → 读取线程 → 内存buffer(vector<string>)
+                                         │
+                                         ├── Web API读取(零磁盘I/O)
+                                         └── 定时刷盘(默认23:20) → 磁盘文件
+```
+
+#### 4.8.2 关键配置
+| 参数 | 默认值 | 说明 |
+|------|--------|------|
+| `enabled` | true | 1=内存缓冲模式, 0=直写文件 |
+| `buffer_size_mb` | 20MB | 内存缓冲区上限 |
+| `flush_time` | 23:20 | 每日刷盘时间 |
+| `retention_days` | 30天 | 日志保留天数 |
+| `redirect_stdout` | true | 是否重定向stdout/stderr |
+| `auto_flush_on_exit` | true | 程序退出时自动刷盘 |
+
+#### 4.8.3 刷盘策略
+- 定时刷盘: 到达 `flush_time` 时将内存buffer全量写入磁盘
+- 退出刷盘: 程序优雅退出时执行最后一次刷盘
+- 容量控制: 超过 `buffer_size_mb` 时丢弃最旧日志
+- 文件清理: 凌晨2:00按 `retention_days` 清理过期日志文件
+
+### 4.9 frpc内网穿透管理
+
+#### 4.9.1 状态获取
+通过 frpc admin HTTP API 获取隧道状态:
+```cpp
+std::string call_admin_api(const std::string &endpoint) {
+    // URL: http://{admin_addr}:{admin_port}/api/serverinfo
+    // Basic Auth: g_frpc_admin_user : g_frpc_admin_password
+    // 超时: connect=1s, total=2s
+}
+```
+
+#### 4.9.2 进程检测(三重验证)
+1. `systemctl is-active frpc` — systemd状态
+2. `pgrep -x frpc` — 进程存在性
+3. frpc admin API可达性
+
+#### 4.9.3 配置热更新
+- 读取: 直接读取 `frpc.toml` 文件内容
+- 保存: 自动备份旧文件到 `backup_path` → 写入新配置
+- 重启: `systemctl restart frpc` → 等待 `restart_check_timeout` 秒
+- 自动回滚: 重启后检测进程存活,失败则恢复备份配置
+
+#### 4.9.4 安全限制
+- **admin API仅允许本机127.0.0.1调用**
+- 禁止通过frp隧道暴露到公网
+- 受保护隧道列表: `g_frpc_protected_tunnels`(不可删除)
+
+### 4.10 SSH密钥管理
+
+#### 4.10.1 功能
+- 读取/添加/删除 `authorized_keys` 文件中的SSH公钥
+- 支持密钥类型验证: ssh-rsa, ssh-dss, ssh-ed25519, ecdsa-sha2-*
+
+#### 4.10.2 密钥格式验证
+```cpp
+bool validate_key_format(const std::string &key_line) {
+    // 格式: type base64_data [comment]
+    // type必须是已知SSH密钥类型
+    // base64数据至少20字符
+}
+```
+
+#### 4.10.3 配置
+- 密钥文件路径: `g_ssh_keys_path` (默认 `~/.ssh/authorized_keys`)
+- 通过Web管理界面操作
+
+---
+
+## 5. 配置文件详解
+
+### 5.1 config.ini 完整配置段
+
+#### [config] — 核心业务配置
+| 参数 | 默认值 | 说明 |
+|------|--------|------|
+| `project_name` | (必填) | 工程名 |
+| `point_number` | (必填) | 点位编号 |
+| `throughway` | (必填) | 出入口编号 |
+| `rtsp_url_front_in` | (必填) | 进站前向摄像头RTSP URL |
+| `rtsp_url_front_out` | (必填) | 出站前向摄像头RTSP URL |
+| `rtsp_url_side_in` | (必填) | 进站侧向摄像头RTSP URL |
+| `rtsp_url_side_out` | (必填) | 出站侧向摄像头RTSP URL |
+| `app_api` | (必填) | 平台API地址 |
+| `app_key` | (必填) | 平台API Key |
+| `app_secret` | (必填) | 平台API Secret |
+| `DEBUG_LOG` | 0 | 调试日志(1=开启, 0=正式) |
+| `TestFlag` | 0 | 测试环境标记 |
+| `wType` | 1 | 工地类型(1=工地, 2=码头, 3=回填) |
+| `TIME_WINDOW` | 10 | 时间窗口(分钟),控制进站/出站配额 |
+| `MAX_PHOTO_GROUPS` | 2 | 每侧最大照片组数 |
+| `in_out_interval` | 5 | 进出站间隔(分钟),转换为秒: ×60 |
+| `PLATE_CONFIDENCE_THRESHOLD` | 0.8 | 上传触发置信度阈值 |
+| `PLATE_LOG_THRESHOLD` | 0.5 | 日志记录置信度阈值 |
+| `AlternatingMerge` | 0 | 交替锁定开关(1=启用) |
+| `roi_in_x/y/w/h` | 0 | 进站ROI区域坐标 |
+| `roi_in_enabled` | 0 | 进站ROI启用(1=启用) |
+| `roi_out_x/y/w/h` | 0 | 出站ROI区域坐标 |
+| `roi_out_enabled` | 0 | 出站ROI启用 |
+| `roi_debug_enabled` | 0 | ROI调试模式 |
+| `hw_decode_mode` | auto | 解码模式(auto/soft/drm) |
+| `hw_decode_device` | /dev/dri/renderD128 | DRM设备路径 |
+| `rtsp_transport` | tcp | RTSP传输协议(tcp/udp) |
+| `PhotoMaxCapacityMB` | 1024 | 照片存储容量阈值(MB) |
+| `LogRetentionDays` | 30 | 日志保留天数 |
+
+#### [server] — Web服务配置
+| 参数 | 默认值 | 说明 |
+|------|--------|------|
+| `ip` | http://0.0.0.0:8080 | 服务地址(端口从此字段解析) |
+
+#### [ssl] — HTTPS/SSL配置
+| 参数 | 默认值 | 说明 |
+|------|--------|------|
+| `enabled` | 0 | SSL启用(1=启用) |
+| `cert_path` | (空) | SSL证书文件路径 |
+| `key_path` | (空) | SSL私钥文件路径 |
+
+#### [auth] — 认证系统配置
+| 参数 | 默认值 | 说明 |
+|------|--------|------|
+| `enabled` | 0 | 认证启用(1=启用) |
+| `db_path` | data/auth.db | 认证数据库路径(相对pathComm) |
+
+#### [feishu] — 飞书通知配置
+| 参数 | 默认值 | 说明 |
+|------|--------|------|
+| `APP_ID` | (必填) | 飞书应用ID |
+| `APP_SECRET` | (必填) | 飞书应用密钥 |
+| `CHAT_ID` | (必填) | 飞书群聊ID |
+| `TIMEOUT_SECOND` | 10 | HTTP超时(秒) |
+| `WarningSigns` | 0 | 抑制紧急告警(1=抑制) |
+
+#### [weight] — 称重系统配置
+| 参数 | 默认值 | 说明 |
+|------|--------|------|
+| `flagWeight` | 0 | 称重启用(1=启用) |
+| `weight_threshold_in` | (必填) | 进站重量阈值(公斤) |
+| `weight_threshold_out` | (必填) | 出站重量阈值(公斤) |
+| `default_entry_weight` | 0 | 默认进站重量 |
+| `default_exit_weight` | 0 | 默认出站重量 |
+| `weight_detection_time` | 10 | 称重检测时间(秒) |
+| `tcp_connect_timeout` | 5 | TCP连接超时(秒) |
+| `weight_server_ip` | (必填) | 仪表IP地址 |
+| `weight_server_port` | (必填) | 仪表端口 |
+| `MAX_WEIGHT` | 100000 | 最大有效重量(公斤) |
+| `STABLE_SAMPLE_COUNT` | 5 | 稳定判定样本数 |
+| `STABLE_THRESHOLD_KG` | 50 | 稳定波动阈值(公斤) |
+| `CANDIDATE_DATA_COUNT` | 10 | 候选数据数量 |
+| `MAX_UPLOAD_RETRIES` | 3 | 最大重试次数 |
+| `RETRY_DELAY_MS` | 1000 | 重试延迟(毫秒) |
+
+#### [MQTT] — MQTT配置
+| 参数 | 默认值 | 说明 |
+|------|--------|------|
+| `MQTT_HOST` | (空) | MQTT Broker地址 |
+| `MQTT_PORT` | 1883 | MQTT端口 |
+| `MQTT_USER` | (空) | 用户名 |
+| `MQTT_PASS` | (空) | 密码 |
+| `MQTT_TOPIC` | (必填) | 发布主题 |
+| `MQTT_CLIENT_ID` | PlateRecApp | 客户端ID |
+| `PLATE_COLOR` | 黄色 | 默认车牌颜色 |
+| `VEHICLE_TYPE` | 渣土车 | 默认车型 |
+
+#### [system] — 系统监控配置
+| 参数 | 默认值 | 说明 |
+|------|--------|------|
+| `monitor_interval` | 30 | 采样间隔(秒) |
+| `temp_alert_threshold` | 80 | 温度告警阈值(°C) |
+| `cpu_alert_threshold` | 90 | CPU告警阈值(%) |
+| `db_path` | data/system_metrics.db | 监控数据库路径 |
+| `history_retention_days` | 30 | 全量数据保留天数 |
+| `aggregation_retention_days` | 365 | 聚合数据保留天数 |
+| `flush_time` | 23:20 | 每日刷盘时间 |
+
+#### [frpc] — frpc管理配置
+| 参数 | 默认值 | 说明 |
+|------|--------|------|
+| `config_path` | /etc/frp/frpc.toml | frpc配置文件路径 |
+| `backup_path` | (自动) | 备份文件路径 |
+| `protected_tunnels` | (空) | 受保护隧道列表(逗号分隔) |
+| `restart_check_timeout` | 10 | 重启后等待检测时间(秒) |
+| `auto_rollback` | 1 | 失败自动回滚(1=启用) |
+| `web_enabled` | 1 | Web管理页面开关 |
+| `admin_addr` | 127.0.0.1 | frpc admin API地址 |
+| `admin_port` | 7400 | frpc admin API端口 |
+| `admin_user` | (空) | admin用户名 |
+| `admin_password` | (空) | admin密码 |
+
+#### [terminal] — 终端/SSH配置
+| 参数 | 默认值 | 说明 |
+|------|--------|------|
+| `ttyd_port` | 7681 | ttyd Web终端端口 |
+| `ttyd_credential` | (空) | ttyd认证凭证(user:pass) |
+| `ttyd_max_clients` | 5 | 最大客户端数 |
+| `ssh_keys_path` | ~/.ssh/authorized_keys | SSH公钥文件路径 |
+
+#### [log] — 日志管理配置
+| 参数 | 默认值 | 说明 |
+|------|--------|------|
+| `enabled` | 1 | 内存日志模式(1=内存, 0=直写) |
+| `log_file` | PlateRecApp.log | 日志文件名 |
+| `buffer_size_mb` | 20 | 缓冲区大小(MB) |
+| `flush_time` | 23:20 | 刷盘时间(HH:MM) |
+| `retention_days` | 30 | 保留天数 |
+| `redirect_stdout` | 1 | 重定向stdout/stderr |
+| `auto_flush_on_exit` | 1 | 退出时自动刷盘 |
+
+---
+
+## 6. 构建系统
+
+### 6.1 CMakeLists.txt 详细解析
+
+```cmake
+cmake_minimum_required(VERSION 3.25.1)
+project(HyperLPR3-LinuxAPP VERSION 1.0.0 LANGUAGES CXX C)
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
+```
+
+**构建类型默认**: Release
+
+### 6.2 编译优化标志
+
+| 标志 | 作用 |
+|------|------|
+| `-O3` | 最高级别速度优化 |
+| `-s` | 去除符号表(strip) |
+| `--as-needed` | 只链接实际使用的符号 |
+| `--gc-sections` | 删除未使用的段 |
+| POST_BUILD strip | 编译后strip进一步减小体积 |
+
+**可选优化**(注释状态):
+- `-Os`: 体积优先优化
+- `-flto`: 链接时优化(减小10-30%体积)
+- `-fvisibility=hidden`: 隐藏符号
+
+### 6.3 依赖库查找策略
+1. **pkg-config优先**: FreeType2, SQLite3, FFmpeg各模块
+2. **CMake find_package**: OpenCV, CURL, OpenSSL
+3. **手动查找回退**: cJSON(先pkg-config,再find_library,最后硬编码路径)
+4. **动态链接优先**: `BUILD_SHARED_LIBS ON`,可通过 `-DUSE_STATIC_LIBS=ON` 切换静态
+
+### 6.4 源码文件列表
+
+```
+src/
+├── main.cpp              # 主入口 + 调度
+├── common.cpp/h          # 全局类型定义
+├── config.cpp/h          # 配置解析
+├── plate_recognizer.cpp/h # 车牌识别引擎
+├── rtsp_capture.cpp/h    # RTSP视频采集
+├── web_server.cpp/h      # Web管理后台
+├── database.cpp/h        # SQLite数据库
+├── network_client.cpp/h  # HTTP API通信
+├── feishu_client.cpp/h   # 飞书推送
+├── mqtt_client.cpp/h     # MQTT客户端
+├── weight_scale.cpp/h    # 称重系统
+├── station_lock.cpp/h    # 交替锁定
+├── log_manager.cpp/h     # 日志管理
+├── frpc_manager.cpp/h    # frpc管理
+├── ssh_manager.cpp/h     # SSH管理
+├── system_monitor.cpp/h  # 系统监控
+├── system_metrics_manager.cpp/h # 监控历史数据
+├── monitor.cpp/h         # 指标打印
+├── utils.cpp/h           # 工具函数
+├── auth_api.cpp/h        # 认证API
+├── auth_crypto.cpp/h     # bcrypt + 安全随机
+├── auth_db.cpp/h         # 认证数据库
+├── auth_session.cpp/h    # 会话管理
+├── auth_middleware.cpp/h  # 认证中间件
+├── auth_rate_limiter.h   # 速率限制(header-only)
+└── bcrypt/               # bcrypt实现
+```
+
+---
+
+## 7. 部署方案
+
+### 7.1 目录结构
+```
+/opt/openAI/project/003.PlateRecAPP/   # pathComm (可执行文件所在目录)
+├── PlateRecApp                        # 可执行文件
+├── config.ini                         # 主配置文件
+├── config.txt                         # MD5校验配置
+├── simsun.ttc                         # 中文字体文件
+├── hyperlpr3/
+│   └── resource/models/r2_mobile/     # HyperLPR3模型文件
+├── assets/web/                        # Web前端HTML页面
+│   ├── login.html
+│   ├── system.html
+│   └── ...
+├── data/                              # 数据库目录
+│   ├── upload_records.db              # 主数据库
+│   ├── auth.db                        # 认证数据库
+│   └── system_metrics.db              # 监控数据库
+├── PlateJPG/                          # 照片存储目录
+├── third_party/                       # 第三方依赖
+└── sync_to_gogs.sh                    # Gogs同步脚本
+```
+
+### 7.2 systemd service 配置
+```ini
+[Unit]
+Description=PlateRecApp License Plate Recognition
+After=network.target
+
+[Service]
+Type=simple
+WorkingDirectory=/opt/openAI/project/003.PlateRecAPP
+ExecStart=/opt/openAI/project/003.PlateRecAPP/PlateRecApp config.ini
+Restart=always
+RestartSec=5
+StandardOutput=journal
+StandardError=journal
+
+[Install]
+WantedBy=multi-user.target
+```
+
+### 7.3 文件权限
+- 可执行文件: `755`
+- 配置文件: `644`(含敏感信息,不可公开)
+- 数据库目录: `755`
+- 照片目录: `755`
+
+### 7.4 启动流程
+```
+1. 解析可执行文件路径 → 确定 pathComm
+2. 读取CPU序列号 → MD5三重校验 → 验证config.txt
+3. 解析config.ini → 加载所有配置
+4. 计算时区偏移 → 初始化cURL
+5. 初始化SQLite数据库 → 加载缓存
+6. 初始化HyperLPR3模型
+7. 创建4路RTSPCapture → 启动采集线程
+8. 启动识别工作线程
+9. 初始化认证系统 → 启动Web服务器
+10. 启动称重系统 → 启动MQTT客户端
+11. 进入主循环(100ms间隔)
+```
+
+---
+
+## 8. 安全策略
+
+### 8.1 认证机制
+- **bcrypt密码哈希**: 使用系统libcrypt的`crypt_r`,成本因子自动调整
+- **Session管理**: 64字符hex随机session_id,内存+SQLite双层
+- **CSRF防护**: 每个Session独立CSRF Token,状态变更请求必须验证
+- **IP速率限制**: 滑动窗口5分钟/5次,超限返回429
+- **角色权限**: user(0) / admin(1) / superadmin(2),不同页面/API按角色控制
+- **账户锁定**: 连续失败登录自动锁定(`failed_attempts` + `locked_until`)
+- **审计日志**: 所有登录/登出/失败/超时事件记录到 `audit_log` 表
+
+### 8.2 密码存储
+- 算法: bcrypt(通过 `crypt_r` 系统调用)
+- 自动salt生成,每次哈希结果不同
+- 验证使用 `secure_compare` 时间安全比较(防时序攻击)
+
+### 8.3 HTTPS/SSL
+- 可选启用(config.ini `[ssl] enabled=1`)
+- 证书+私钥 PEM格式
+- SSL会话缓存(10分钟)
+- 优先ECDHE+AESGCM/ChaCha20密码套件
+- HTTP→HTTPS自动重定向(可选)
+
+### 8.4 frpc admin API 限制
+- **仅允许本机127.0.0.1调用**
+- 禁止通过frp隧道暴露到公网
+- Basic Auth认证保护
+- 超时严格限制(connect=1s, total=2s)
+
+### 8.5 路径安全
+- Web文件访问: `is_safe_file_path()` 防路径穿越
+- 禁止 `..` / `/` / `\` 字符
+- `realpath()` 验证绝对路径在基础目录内
+
+### 8.6 配置文件校验
+- CPU序列号 + MD5三重校验 → 防止未授权设备运行
+- config.ini 含敏感信息,.gitignore 已排除
+
+---
+
+## 9. 版本变更记录
+
+详见 [CHANGELOG.md](CHANGELOG.md)
+
+主要版本里程碑:
+- **v43**: RTSP ROI裁剪、DRM硬件解码、4路独立视频流
+- **v43.2 fix11-fix17**: 交替锁定机制完善(非对称等待、2小时超时清零)
+- **fix18**: 称重+MQTT主进程合并、日志logrotate
+- **fix19**: 文件清理重构(照片按容量、日志按天数)
+- **fix20**: 推理耗时追踪、MQTT完整迁移
+- **fix21-fix23**: P0时间对齐bug修复、抓拍时间全链路一致
+- **fix24**: 登录认证系统、Web管理功能(系统监控+frpc+SSH+日志)、HTTPS/SSL
+
+---
+
+## 10. 待改进项
+
+### 10.1 技术债务
+1. **配置热更新不完整**: ROI可热写回config.ini,但其他配置修改后需重启
+2. **认证系统JSON解析**: 使用手写简单解析而非cJSON,鲁棒性待提升
+3. **全局变量过多**: 大量 `extern` 全局变量,耦合度高,应逐步迁移到单例/依赖注入
+4. **Web前端内嵌**: HTML直接写在C++字符串中,维护困难,应迁移到独立模板
+5. **缺少单元测试**: 无自动化测试框架覆盖核心逻辑
+6. **数据库迁移**: 旧数据库需手动cp迁移,缺少自动迁移工具
+7. **日志内存缓冲**: 超过buffer_size时丢弃旧日志,可能丢失关键信息
+
+### 10.2 改进方向
+1. **gRPC替代HTTP**: 平台API通信改用gRPC提升效率
+2. **TensorRT替代MNN**: 利用NPU/GPU进一步加速推理
+3. **WebSocket替代轮询**: Web监控数据改为实时推送
+4. **Docker化部署**: 简化依赖安装和环境配置
+5. **OTA远程更新**: 结合frpc实现远程固件升级
+6. **多站点支持**: 单进程管理多个出入口点位
+
+---
+
+> **本文档持续更新**  
+> 最后更新: 2026-07-06 | 基于 PlateRecApp v43.2 fix24 源码

+ 8 - 4
src/log_manager.cpp

@@ -278,7 +278,8 @@ bool MemoryLogBuffer::flush_to_file(std::string& error) {
         std::lock_guard<std::mutex> lock(stats_mutex_);
         time_t now = time(NULL);
         char time_buf[64];
-        struct tm *tm = localtime(&now);
+        struct tm tm_buf;
+        struct tm* tm = localtime_r(&now, &tm_buf);
         strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", tm);
         last_flush_time_ = time_buf;
     }
@@ -369,7 +370,8 @@ void MemoryLogBuffer::flush_thread_func() {
 
         // 检查是否到达刷盘时间
         time_t now = time(NULL);
-        struct tm* tm_now = localtime(&now);
+        struct tm tm_now_buf;
+        struct tm* tm_now = localtime_r(&now, &tm_now_buf);
 
         if (tm_now->tm_hour == target_hour && tm_now->tm_min == target_minute) {
             std::string error;
@@ -462,7 +464,8 @@ bool MemoryLogBuffer::parse_flush_time(const std::string& time_str, int& hour, i
 
 std::string MemoryLogBuffer::generate_archive_filename() {
     time_t now = time(NULL);
-    struct tm* tm_now = localtime(&now);
+    struct tm tm_now_buf;
+    struct tm* tm_now = localtime_r(&now, &tm_now_buf);
     char buf[64];
     // 生成 PlateRecApp_20260705.log 格式
     snprintf(buf, sizeof(buf), "PlateRecApp_%04d%02d%02d.log",
@@ -472,7 +475,8 @@ std::string MemoryLogBuffer::generate_archive_filename() {
 
 std::string MemoryLogBuffer::current_timestamp() {
     time_t now = time(NULL);
-    struct tm* tm_now = localtime(&now);
+    struct tm tm_now_buf;
+    struct tm* tm_now = localtime_r(&now, &tm_now_buf);
     char buf[32];
     snprintf(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d",
              tm_now->tm_year + 1900, tm_now->tm_mon + 1, tm_now->tm_mday,

+ 6 - 5
src/main.cpp

@@ -111,7 +111,7 @@ int main(int argc, char** argv)
 	// 需要校正时区偏移才能使ORDER BY正确排序
 	{
 		time_t now_utc = time(NULL);
-		struct tm* utc_tm = gmtime(&now_utc);
+		struct tm utc_tm_buf; struct tm* utc_tm = gmtime_r(&now_utc, &utc_tm_buf);
 		time_t utc_as_local = mktime(utc_tm);  // 把UTC时刻当作本地时间解释
 		g_tz_offset_seconds = (int)difftime(now_utc, utc_as_local);
 		std::cout << "[时区] 本地时区偏移: " << g_tz_offset_seconds << " 秒 ("
@@ -791,10 +791,11 @@ int main(int argc, char** argv)
 		capture_thread.join();
 	}
 
-	delete plate_rec_app.capture_front_in;
-	delete plate_rec_app.capture_front_out;
-	delete plate_rec_app.capture_side_in;
-	delete plate_rec_app.capture_side_out;
+	// fix27: 空指针保护
+	if (plate_rec_app.capture_front_in) { delete plate_rec_app.capture_front_in; plate_rec_app.capture_front_in = nullptr; }
+	if (plate_rec_app.capture_front_out) { delete plate_rec_app.capture_front_out; plate_rec_app.capture_front_out = nullptr; }
+	if (plate_rec_app.capture_side_in) { delete plate_rec_app.capture_side_in; plate_rec_app.capture_side_in = nullptr; }
+	if (plate_rec_app.capture_side_out) { delete plate_rec_app.capture_side_out; plate_rec_app.capture_side_out = nullptr; }
 
 	hyperlpr_lib_deinit();
 	close_database();

+ 7 - 6
src/web_server.cpp

@@ -971,12 +971,13 @@ void start_web_server() {
 		cJSON* j_h = cJSON_GetObjectItem(root, "h");
 		cJSON* j_enabled = cJSON_GetObjectItem(root, "enabled");
 
-		if (j_side && j_side->valuestring) side = j_side->valuestring;
-		if (j_x) x = j_x->valueint;
-		if (j_y) y = j_y->valueint;
-		if (j_w) w = j_w->valueint;
-		if (j_h) h = j_h->valueint;
-		if (j_enabled) enabled = (j_enabled->type == cJSON_True || j_enabled->valueint == 1);
+		// fix27: 添加 cJSON 类型检查,防止类型不匹配导致崩溃
+		if (j_side && cJSON_IsString(j_side) && j_side->valuestring) side = j_side->valuestring;
+		if (j_x && cJSON_IsNumber(j_x)) x = j_x->valueint;
+		if (j_y && cJSON_IsNumber(j_y)) y = j_y->valueint;
+		if (j_w && cJSON_IsNumber(j_w)) w = j_w->valueint;
+		if (j_h && cJSON_IsNumber(j_h)) h = j_h->valueint;
+		if (j_enabled) enabled = (j_enabled->type == cJSON_True || (cJSON_IsNumber(j_enabled) && j_enabled->valueint == 1));
 
 		// 坐标校验
 		if (x < 0 || y < 0 || w < 0 || h < 0) {