# 香橙派车控项目交接文档

> 项目：飞驰人生设备端（Car + OTA + HTTP Server）  
> 工程目录：`/home/orangepi/car/master`  
> 设备地址：`192.168.0.104`（当前局域网地址，可能随 DHCP 变化）  
> 编制日期：2026-07-31  
> 文档状态：可执行交接稿（基于源码、设备环境、Git 与运行状态实机核验）

---

## 1. 文档目的与使用边界

本文用于帮助接手人员在较短时间内完成以下工作：

- 理解项目的业务目标、代码分层、启动链路和常驻线程；
- 能够在当前 Orange Pi 3B 上编译、部署、启动、停止和回滚；
- 能部署和维护 OTAdevice、设备号 HTTP Server 及三项 systemd 服务；
- 能定位设备识别、GPIO/串口控制、MQTT、配网、音频及视频推流问题；
- 清楚当前设备的真实运行状态、已知风险和优先整改项；
- 避免把设备号、JWT、MQTT 配置、Tailscale AuthKey 等敏感信息带入公开日志或版本库。

本文记录的是 2026-07-31 对 `192.168.0.104` 的核验快照。后端地址、MQTT 节点、设备 IP、硬件编号和分支状态均可能变化，操作前应重新确认。

## 2. 一页式交接摘要

### 2.1 项目是什么

完整设备端由三个常驻组件组成：`car` 主程序负责车型控制、MQTT、配网、音视频与硬件；Go 编写的 `OTAdevice` 负责轮询版本、备份、下载、校验、替换及重启 `carstart.service`；Python `httpserver.py` 提供局域网设备号查看/录入页面。三者分别由 `carstart.service`、`gostart.service`、`httpstart.service` 管理。

### 2.2 当前实机快照

| 项目 | 核验结果 |
|---|---|
| 主机 | Orange Pi 3B，aarch64 |
| 系统 | Orange Pi 1.0.8 / Ubuntu 22.04.5 LTS |
| 内核 | 5.10.160-rockchip-rk356x |
| 当前网络 | `wlan0` 为 `192.168.0.104/24`；`eth0` 为 DOWN |
| 工程目录 | `/home/orangepi/car/master` |
| Git 分支 | `feature/add_aboard_tts` |
| 工程版本 | CMake `project(car VERSION 1.3.11)` |
| 最新提交 | `c4f0ffb2`（2026-07-28，修改喇叭和麦并优化） |
| 当前设备号 | `CN010200000000`，型号编码 `0102` |
| 当前推流编译开关 | `WEBRTCPUSH_USE_MPP=0`，即 Chromium 路径 |
| Car 构建产物 | `build/main`，约 3.3 MB，ARM64 ELF |
| Car 生产路径 | `/home/orangepi/car/master/main`，由人工发布或 OTA 更新 |
| OTA 仓库 | `http://git.yd-ss.com/leimingyu/OTAdevice.git`，默认分支 `master` |
| systemd unit | 三份均位于 `/etc/systemd/system/` |
| 服务状态 | `carstart`、`httpstart`、`gostart` 均为 disabled、inactive |
| 当前缺失文件 | `master/main`、`goproject/OTAdevice`、`version.conf`、`backup/` |
| 当前可用文件 | `build/main`、`httpserver.py` |
| 本次检查时主程序 | 未发现 Car、OTA 或 HTTP Server 进程 |
| 仍在运行的相关进程 | 存在 Chromium 进程，不能据此认定主程序健康 |
| 资源 | 根分区约 29 GB，已用 61%；内存约 3.8 GiB |

### 2.3 接手后的首要动作

1. 按 OTA 目录约定补齐 `master/main`、`goproject/OTAdevice`、`version.conf` 和 `backup/`。
2. 校验三份 unit 后执行 `daemon-reload`，明确是否 `enable --now`，完成重启恢复验收。
3. 在架空车辆状态下验证 OTA 停服、备份、替换、重启、回滚和整机重启全链路。
4. 限制 HTTP Server 只在可信局域网使用，并尽快增加鉴权和输入校验。
5. 轮换历史日志中可能暴露过的 JWT/Tailscale 凭据，并改造日志脱敏。
6. 确认生产推流路径是 Chromium、Go 还是 C/libdatachannel。

## 3. 系统架构与数据流

### 3.1 分层结构

```text
上层 App / 后端 / OTA 平台
  ├─ HTTPS：拉取设备配置、语言、推流模式、音量等
  ├─ MQTT：控制、心跳、验证、状态上报
  ├─ WebRTC/信令：视频、麦克风、喊话、DataChannel
  └─ UDP 18888：局域网发现、WiFi 配置、推流调试
                    │
                    ▼
systemd 服务管理层
  ├─ carstart.service  → /home/orangepi/car/master/main
  ├─ gostart.service   → /home/orangepi/car/master/goproject/OTAdevice
  └─ httpstart.service → python3 /home/orangepi/car/master/httpserver.py
                    │
          ┌─────────┼─────────┐
          ▼         ▼         ▼
       Car 主程序  OTA 更新器  HTTP Server :8080
          │
          ▼
app/ 业务启动与设备身份
  ├─ main：分阶段初始化、拉起常驻线程
  ├─ device_identity：设备号 → 型号
  └─ device_change：WiFi/设备配置变更
                    │
                    ▼
modules/ 公共服务
  ├─ HTTP / MQTT / logger / IPC
  ├─ runtime_deps / go_deploy / tailscale_deploy
  ├─ wifi_config / device_debug
  └─ webrtcpush / browser
                    │
                    ▼
drivers/ 硬件与车型控制
  ├─ gpio / softPWM / I2C
  ├─ devicecontrol：car、tank、ship、ptz、robot、gps
  ├─ sensors：音频、温度、角度、红外等
  └─ selfcontrol：自控逻辑
                    │
                    ▼
GPIO、串口、摄像头、麦克风、喇叭、传感器、电机
```

### 3.2 主数据流

- **设备识别**：读取 `Deviceld.txt` → 提取第 3～6 位型号编码 → 映射到 `DEVICE_*` → 初始化对应硬件。
- **控制链路**：MQTT 消息 → 消息类型分发 → `device_walk_control()` 等车型接口 → `device_gpio_control()` / 串口输出。
- **配置链路**：HTTPS `device/getConfig?deviceNo=...` → MQTT 节点、视频 URL、语言、`webrtcMode` 等运行参数。
- **视频链路**：当前编译为 Chromium；代码同时保留 Go 与 C/libdatachannel 分支。
- **局域网配置**：UDP `0.0.0.0:18888` 处理设备发现、WiFi 配置和推流调试命令。
- **本地 IPC**：Unix Socket `/tmp/device_msg.sock`。
- **OTA 链路**：`OTAdevice` 读取设备号和 `version.conf` → 请求 OTA API → 停止 Car → 备份旧 `main` → 下载 `main.tmp` → MD5 校验 → 替换 `main` → 重启 Car → 重启系统。
- **设备号录入链路**：浏览器访问 HTTP Server `:8080` → GET `/` 查看设备号 → POST `/submit` 覆盖写入 `Deviceld.txt`。

## 4. 代码目录与职责

| 路径 | 职责 | 接手时重点 |
|---|---|---|
| `CMakeLists.txt` | 顶层构建、版本、编译类型、依赖链接 | Release/Debug、静态库、链接项 |
| `app/main/` | `main()`、初始化顺序、常驻线程 | 首个阅读入口 |
| `app/device_identity/` | 设备号读取、型号映射、MQTT topic | 新增型号必查 |
| `app/device_change/` | 设备号/WiFi 变更及管理 | 配网与持久化 |
| `drivers/gpio/` | wiringPi、GPIO、softPWM、I2C | 引脚冲突和板型差异 |
| `drivers/devicecontrol/` | 各车/坦克/船/云台/机器人控制 | 速度、方向、急停 |
| `drivers/sensors/` | 音频、TTS、温度、角度、红外等 | 声卡竞争与资源文件 |
| `drivers/selfcontrol/` | 自控状态及线程 | 与人工遥控互斥 |
| `modules/mqtt/` | 连接、订阅、发布、验证、消息分发 | 多 Broker 与重连 |
| `modules/http/` | 后端配置获取 | 超时、回退默认值 |
| `modules/browser/` | Chromium 推流入口与重启 | DISPLAY/PulseAudio |
| `modules/webrtcpush/` | C 原生 WebRTC、GStreamer、MPP、音频 | 复杂度最高模块 |
| `modules/wifi_config/` | UDP 发现和 WiFi 配置 | 端口 18888 |
| `modules/device_debug/` | 推流模式/URL 调试接口 | 仅受控网络使用 |
| `modules/runtime_deps/` | 运行时检查/安装依赖 | 启动时可能执行 apt |
| `modules/go_deploy/` | 拉取/校验/运行 Go 视频程序 | TLS 校验风险 |
| `modules/logger/` | zlog 封装、日志保留 | 必须做敏感信息脱敏 |
| `third_party/` | mosquitto、libdatachannel、cJSON、zlog | 供应链和许可证 |
| `build/` | CMake 构建输出 | 不作为源码维护 |
| `main` | Car 生产二进制，`carstart.service` 与 OTA 的共同目标 | 不等同于 `build/main` |
| `goproject/OTAdevice` | Go OTA 常驻程序 | 由 `gostart.service` 启动 |
| `goproject/main.go` | OTA 源码 | 版本轮询、备份、校验、替换 |
| `httpserver.py` | 设备号录入 HTTP Server | TCP 8080、无第三方 Python 依赖 |
| `version.conf` | OTA 当前版本号 | 首次部署需创建，可为空 |
| `backup/` | OTA Car 二进制备份目录 | OTA 可自动创建 |
| `log/` | 运行日志 | 可能含敏感数据 |
| `交接文档/` | 本交接材料 | DOCX 与 Markdown |

## 5. 启动流程

`app/main/main.c` 使用阶段化初始化表。带 fatal 标记的步骤失败会直接返回错误码；非 fatal 步骤只记录警告并继续。

### 5.1 初始化顺序

1. **core**
   - 初始化日志。
2. **platform_driver**
   - 初始化 wiringPi；
   - 初始化音频配置和音频运行环境。
3. **app**
   - 读取设备号；
   - 生成 MQTT topic；
   - 检查并自动配置 WiFi。
4. **device_driver**
   - 初始化硬件 I2C；
   - 初始化射击冷却（不支持的设备允许跳过）。
5. **module_service**
   - 检查/安装运行时依赖；
   - 请求基础数据与 MQTT/视频配置；
   - 检查/部署 Go 视频程序；
   - 启动 `/tmp/device_msg.sock`；
   - 启动 WiFi 配置 UDP 服务。
6. **runtime**
   - 拉起 8 个工作线程；
   - 播放连接成功提示音；
   - 主线程进入常驻 sleep。

### 5.2 工作线程

| 线程 | 主要职责 | 关注点 |
|---|---|---|
| `thread_exit_time` | 串口接收、异常退出计时、失联停车、自控计时 | 安全关键 |
| `thread_mqtt_beat` | 心跳、验证开关轮询、状态发布 | MQTT 健康 |
| `thread_open_browser` | Go/原生 C/Chromium 三选一推流 | 互斥与自动回退 |
| `thread_mqtt_reconnect` | MQTT 初始化、重试与循环 | 多节点部分失败 |
| `thread_time_calculation` | 5 ms 周期快速检查与计数器 | CPU 占用与溢出 |
| `thread_play_mp3` | 音频播放队列 | 与喊话/麦克风竞争 |
| `thread_steering_control` | 25 ms 方向盘平滑处理 | 无匹配设备时退出 |
| `thread_wifi_offline_recovery` | 断网恢复 | 当前日志显示 40 秒检测 |

## 6. 设备识别与已注册型号

设备号当前为 14 位字符串，例如 `CN010200000000`。第 3～6 位 `0102` 是型号编码。新增设备时不能只加枚举；需同步检查身份映射、设备初始化表、控制实现、GPIO/串口资源、急停逻辑和文档。

| 类别 | 编码 | 说明 |
|---|---|---|
| 车辆 | 0101 | 莽牛大车，速度上限约 150，避免顶满 |
| 车辆 | 0102 | 小闪电/莽牛小车，最大速度 200；当前实机型号 |
| 车辆 | 0103 | 挖掘机，按电池电压调速 |
| 车辆 | 0104 | 推土机，按电池电压调速 |
| 车辆 | 0105 | 人坐超大车，串口遥控方案 |
| 车辆 | 0106 | F1 双电机大板，含起步阈值与固定转向 PWM |
| 坦克 | 0201 | 废弃占位，不建议新部署 |
| 坦克 | 0202/0203/0204 | 豹2/M1A2/99A 等，按电池电压调速 |
| 坦克 | 0206 | 可喷水坦克 |
| 坦克 | 0207 | 可发射水弹坦克 |
| 船舶 | 0301/0302 | 两套独立船舶控制 |
| 云台/定位 | 0401 | 云台炮台，有限位 |
| 云台/定位 | 0403 | GPS 定位设备，串口线程 |
| 云台/定位 | 0404 | 烟花大云台等，有限位 |
| 云台/定位 | 0405 | 云台，例如射击 pin27 配置 |
| 云台/定位 | 0406 | 水枪炮台 |
| 机器人 | 0501 | 机械狗 |
| 机器人 | 0502 | 六自由度机械臂，CH340 串口总线舵机 |

> 注意：旧资料中的 `0205` 与当前代码不一致，应以代码注册表为准。

## 7. 构建环境与依赖

### 7.1 已核验工具链

- CMake 3.22.1；
- GCC 11.4.0；
- GStreamer 1.20.3；
- GLib 2.72.4；
- aarch64 Linux。

### 7.2 主要依赖

- 系统库：wiringPi、libcurl、OpenSSL、pthread、dl、uuid、math；
- GStreamer：core、app、webrtc、sdp、video、json-glib、libsoup 2.4、libjpeg；
- 仓库内依赖：Mosquitto、libdatachannel、cJSON、zlog；
- Chromium 路径：`chromium-browser`/`chromium`、`xdotool`；
- 原生推流可用：Rockchip MPP，缺失时可回退 x264。

### 7.3 常规编译

```bash
cd /home/orangepi/car/master
cmake -S . -B build -DCAR_BUILD_TYPE=Release
cmake --build build -j2
```

调试构建：

```bash
cd /home/orangepi/car/master
cmake -S . -B build -DCAR_BUILD_TYPE=Debug
cmake --build build -j2
```

产物：

```text
/home/orangepi/car/master/build/main
```

Release 模式会定义 `LOG_PRODUCTION`，减少 debug 日志。项目虽然主体是 C，但 libdatachannel 是 C++，最终链接器被设置为 C++。

### 7.4 构建后最低检查

```bash
file build/main
ldd build/main
./build/main
```

启动测试前应先确认没有旧实例，且车辆架空/断开动力，避免误动作。首次启动可能因 `runtime_deps` 自动执行 apt 安装或摄像头 USB 重置，不应在生产高峰期盲测。

## 8. systemd 服务管理

### 8.1 三项服务与文件位置

三份 unit 均应放在 `/etc/systemd/system/`，所有者为 `root:root`、权限通常为 `0644`。它们不在 `/lib/systemd/system/`；后者通常留给软件包管理器安装的 unit。

| Unit | 管理对象 | ExecStart | WorkingDirectory |
|---|---|---|---|
| `carstart.service` | Car 主程序 | `/home/orangepi/car/master/main` | `/home/orangepi/car/master` |
| `httpstart.service` | Python 设备号 HTTP Server | `/usr/bin/python3 /home/orangepi/car/master/httpserver.py` | `/home/orangepi/car/master` |
| `gostart.service` | Go OTAdevice | `/home/orangepi/car/master/goproject/OTAdevice` | `/home/orangepi/car/master/goproject` |

当前实机三份 unit 均已加载、语法可识别，但均为 disabled、inactive；`carstart` 和 `gostart` 的 ExecStart 目标文件缺失。

### 8.2 当前 carstart.service

保存位置：`/etc/systemd/system/carstart.service`

```ini
[Unit]
Description=My Custom Service
After=network.target

[Service]
ExecStart=/home/orangepi/car/master/main
Environment=TZ=Asia/Shanghai
WorkingDirectory=/home/orangepi/car/master
Restart=always
User=root
Group=root
Environment="DISPLAY=:0"
Environment="XAUTHORITY=/home/orangepi/.Xauthority"

[Install]
WantedBy=multi-user.target
```

`DISPLAY` 与 `XAUTHORITY` 用于 Chromium 推流路径。`master/main` 是 OTA 的固定发布目标；`build/main` 只是 CMake 构建产物。人工首次部署需执行：

```bash
cd /home/orangepi/car/master
sudo install -o root -g root -m 0755 build/main main
```

### 8.3 当前 httpstart.service

保存位置：`/etc/systemd/system/httpstart.service`

```ini
[Unit]
Description=My Custom Service
After=network.target

[Service]
ExecStart=/usr/bin/python3 /home/orangepi/car/master/httpserver.py
Environment=TZ=Asia/Shanghai
WorkingDirectory=/home/orangepi/car/master
Restart=always
User=root
Group=root

[Install]
WantedBy=multi-user.target
```

该服务不需要 Python 第三方包，脚本仅使用标准库。启动后先等待 20 秒，再尝试获取本机 IP 并绑定 TCP 8080。

### 8.4 当前 gostart.service

保存位置：`/etc/systemd/system/gostart.service`

```ini
[Unit]
Description=My Custom Service
After=network.target

[Service]
ExecStart=/home/orangepi/car/master/goproject/OTAdevice
Environment=TZ=Asia/Shanghai
WorkingDirectory=/home/orangepi/car/master/goproject
Restart=always
User=root
Group=root

[Install]
WantedBy=multi-user.target
```

`OTAdevice` 内部会调用 `systemctl stop/restart carstart.service` 和 `reboot`，因此当前使用 root。程序中的 `sudo` 在 root 服务下属于冗余，但不影响理解其权限需求。

### 8.5 安装、检查与启停

复制或编辑 unit 后必须执行：

```bash
sudo chown root:root /etc/systemd/system/carstart.service \
  /etc/systemd/system/httpstart.service \
  /etc/systemd/system/gostart.service
sudo chmod 0644 /etc/systemd/system/carstart.service \
  /etc/systemd/system/httpstart.service \
  /etc/systemd/system/gostart.service
sudo systemd-analyze verify /etc/systemd/system/carstart.service \
  /etc/systemd/system/httpstart.service \
  /etc/systemd/system/gostart.service
sudo systemctl daemon-reload
```

启动并设置开机自启：

```bash
sudo systemctl enable --now httpstart.service
sudo systemctl enable --now carstart.service
sudo systemctl enable --now gostart.service
```

统一检查：

```bash
systemctl is-enabled carstart.service httpstart.service gostart.service
systemctl is-active carstart.service httpstart.service gostart.service
systemctl status carstart.service httpstart.service gostart.service --no-pager -l
journalctl -u carstart.service -u httpstart.service -u gostart.service -n 300 --no-pager
```

停止并取消开机自启：

```bash
sudo systemctl disable --now gostart.service
sudo systemctl disable --now httpstart.service
sudo systemctl disable --now carstart.service
```

只要修改了 unit 文件，就必须重新 `daemon-reload`；只替换二进制或 Python 脚本时不需要 reload，但需要 restart 对应服务。

### 8.6 建议的加固项

- 将 `Description` 改成明确名称；
- 网络服务使用 `Wants=network-online.target` 与 `After=network-online.target`；
- 增加 `RestartSec=5`，避免缺文件或网络故障时高频重启；
- 用 `ExecStartPre=/usr/bin/test -x ...` 或 `test -f` 提前给出清晰错误；
- Car 保留 DISPLAY/XAUTHORITY；HTTP 与 OTA 不需要图形环境；
- 生产变更前备份 `/etc/systemd/system/*.service`。

以下是 Car 的加固示例，实际启用前需在测试板验证：

```ini
[Unit]
Description=Orange Pi Car Control
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
User=root
Group=root
WorkingDirectory=/home/orangepi/car/master
Environment=TZ=Asia/Shanghai
Environment=DISPLAY=:0
Environment=XAUTHORITY=/home/orangepi/.Xauthority
ExecStartPre=/usr/bin/test -x /home/orangepi/car/master/main
ExecStart=/home/orangepi/car/master/main
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
```

## 9. OTAdevice

### 9.1 仓库与部署结构

仓库：`http://git.yd-ss.com/leimingyu/OTAdevice.git`  
默认分支：`master`  
本次读取提交：`fefd6dc`（2025-08-08）

仓库内容：

```text
OTAdevice/
├── httpserver.py
├── version.conf
└── goproject/
    ├── main.go
    ├── go.mod
    ├── go.sum
    └── OTAdevice
```

部署到板端后的目标结构：

```text
/home/orangepi/car/master/
├── main                     # Car 生产二进制，OTA 替换目标
├── Deviceld.txt             # 14 位设备号
├── version.conf             # 当前 OTA 版本
├── backup/                  # main_<版本> 备份
├── httpserver.py
└── goproject/
    └── OTAdevice            # gostart.service 启动目标
```

### 9.2 OTA 工作流程

1. 启动后循环读取 `Deviceld.txt`，文件不存在或为空时每 10 秒重试。
2. 读取 `version.conf`；文件不存在时视为空版本。
3. POST 到 `http://47.119.190.60/api/v1/ota/latestVersion`，请求体为 `{"device_id":"<设备号>"}`。
4. 比较服务端 `data.version` 与本地版本。
5. 版本不同时停止 `carstart.service`。
6. 若 `master/main` 存在，备份为 `backup/main_<旧版本>`。
7. 下载到 `master/main.tmp`。
8. 计算 MD5，与服务端 `data.md5` 比较。
9. 校验通过后将临时文件提升为 `master/main`，写入 `version.conf` 并增加执行权限。
10. 重启 `carstart.service`，等待 3 秒后执行整机 reboot。
11. 版本相同则等待 30 分钟再次检查；请求失败等异常路径通常较快重试。

### 9.3 构建和部署 OTA

在 Orange Pi 上从源码构建：

```bash
cd /home/orangepi/car/master/goproject
go mod download
go build -o OTAdevice .
chmod 0755 OTAdevice
```

从其他平台交叉编译 ARM64：

```bash
cd goproject
GOOS=linux GOARCH=arm64 go build -o OTAdevice .
```

首次部署应先补齐目录和文件，再启动服务：

```bash
cd /home/orangepi/car/master
mkdir -p goproject backup
touch version.conf
chmod 0644 version.conf
chmod 0755 main goproject/OTAdevice
sudo systemctl daemon-reload
sudo systemctl enable --now carstart.service gostart.service
```

### 9.4 OTA 验收与回滚

OTA 测试必须在车辆架空或断开动力的测试设备上完成。至少验证：

- 相同版本不下载；
- 新版本能停止 Car、生成备份、下载、校验、替换和启动；
- MD5 不一致会删除临时文件并恢复旧版本；
- 下载失败后 Car 能恢复；
- 重启后 `carstart` 与 `gostart` 自动恢复；
- `version.conf`、`main`、`backup/` 权限正确；
- 更新后的 Car 能通过急停、控制、MQTT、视频和音频冒烟测试。

手工回滚示例：

```bash
sudo systemctl stop gostart.service carstart.service
ls -lh /home/orangepi/car/master/backup/
sudo cp /home/orangepi/car/master/backup/main_<版本> \
  /home/orangepi/car/master/main
sudo chmod 0755 /home/orangepi/car/master/main
printf '%s' '<版本>' | sudo tee /home/orangepi/car/master/version.conf
sudo systemctl start carstart.service
sudo systemctl status carstart.service --no-pager -l
```

### 9.5 OTA 已知风险

- OTA API 使用 HTTP，下载 URL 也未在客户端强制 HTTPS；
- MD5 只能发现传输损坏，不能证明更新包来自可信发布方；
- 没有数字签名、证书固定、超时、灰度或更新后健康检查；
- `promoteTempToFinal()` 和 `chmod` 的返回值未被严格处理；
- 在确认 Car 真正健康前就写版本并准备重启；
- 回滚使用 rename，会消耗掉对应备份文件；
- OTA 可停止 Car 和重启整机，必须限制仓库、接口和服务权限。

## 10. HTTP Server

### 10.1 功能与接口

实现文件：`/home/orangepi/car/master/httpserver.py`。启动后固定等待 20 秒，通过连接 `8.8.8.8:80` 推断本机 IP，再绑定 `<本机IP>:8080`。

| 方法 | 路径 | 作用 |
|---|---|---|
| GET | `/` | 显示当前 `Deviceld.txt` 内容和设备号输入表单 |
| POST | `/submit` | 覆盖写入 `/home/orangepi/car/master/Deviceld.txt` |
| 其他 | 任意 | 返回 404 |

浏览器访问示例：

```text
http://192.168.0.104:8080/
```

修改设备号后应验证 14 位格式，并重启 Car 使设备身份、MQTT topic 和后端配置重新初始化：

```bash
cat /home/orangepi/car/master/Deviceld.txt
sudo systemctl restart carstart.service
```

### 10.2 启动与排错

```bash
sudo systemctl start httpstart.service
systemctl status httpstart.service --no-pager -l
journalctl -u httpstart.service -f
ss -lntp | grep ':8080'
curl -i http://192.168.0.104:8080/
```

如果没有监听 8080：

1. 检查脚本固定的 20 秒启动等待；
2. 检查 `get_local_ip()` 是否能通过路由选择获得本机 IP；
3. 检查 8080 是否被占用；
4. 检查服务是否因绑定失败而被 `Restart=always` 反复拉起；
5. 检查 `httpserver.py` 与 `Deviceld.txt` 权限。

### 10.3 HTTP Server 风险

- 无鉴权、无 CSRF 防护，局域网内任何可访问者都可能修改设备号；
- 绑定具体 IP 而非 `0.0.0.0`，换网后需要服务重启；
- 依赖到 `8.8.8.8` 的路由来获取本机 IP，无外网时可能直接退出；
- 只读取 1024 字节并手工解析 HTTP，不适合复杂请求；
- 未做 URL 解码和 14 位设备号格式校验；
- 修改设备号会影响设备类型、MQTT topic 和后端身份，生产网络应限制 8080 访问。

## 11. 配置、接口与端口

### 11.1 本地配置

| 项目 | 位置/值 | 说明 |
|---|---|---|
| 设备号 | `Deviceld.txt` | 文件名中是小写字母 `l`，不是 `DeviceId.txt` |
| OTA 版本 | `version.conf` | 当前部署版本，由 OTA 写入 |
| OTA 备份 | `backup/main_<版本>` | 旧 Car 二进制 |
| 日志配置 | `zlog.conf` | 运行时使用/生成 |
| 推流编译开关 | `modules/webrtcpush/webrtcpush_config.h` | 当前 `WEBRTCPUSH_USE_MPP=0` |
| WiFi 配置端口 | UDP 18888 | 监听所有地址 |
| IPC | `/tmp/device_msg.sock` | Unix Socket |

### 11.2 外部服务

- 设备配置：`https://fcrs-api.yd-ss.com/device/getConfig?deviceNo=<设备号>`；
- 音量状态：`https://fcrs-api.yd-ss.com/api/drive/use/status/<...>`；
- 原生 WebRTC 信令主机：`signal.yd-ss.com`；
- Chromium 默认页面由后端配置或代码默认值产生；
- MQTT Broker 列表由后端配置下发，程序允许多节点部分成功。
- OTA 查询：`http://47.119.190.60/api/v1/ota/latestVersion`。

所有 URL、Broker 和证书策略都应由配置管理，避免继续散落在 C 宏和源码中。

### 11.3 当前监听与相关端口

| 端口/套接字 | 用途 | 备注 |
|---|---|---|
| UDP 18888 | WiFi 配置、设备发现、推流调试 | 局域网可达，应限制可信网段 |
| TCP 1883（本机回环） | 本机 MQTT | 当前只监听 127.0.0.1/::1 |
| TCP 22 | SSH | 运维入口 |
| TCP 8080 | 设备号 HTTP Server | `httpstart.service` 启动后监听 |
| TCP 5555 | 未在本次核验中确认归属 | 接手人需确认 |
| `/tmp/device_msg.sock` | 本地设备消息 IPC | 主程序启动后创建 |

## 12. 视频与音频

### 12.1 三条视频路径

1. **Chromium**：当前编译开关选择的路径；依赖图形会话、`DISPLAY=:0`、XAUTHORITY、摄像头与浏览器稳定性。
2. **Go `go_video`**：后端 `moreInfo.webrtcMode=go` 且 `/home/orangepi/go_video/go_video` 存在时启用。
3. **C/libdatachannel**：`WEBRTCPUSH_USE_MPP=1` 时尝试；使用 GStreamer、MPP/x264、libdatachannel，失败可回退 Chromium。

三条路径共用 `thread_open_browser`，设计上互斥。上线前必须记录该设备最终采用哪条路径。

### 12.2 当前原生推流关键参数

- H.264 24 fps，最低目标 22 fps；
- 初始码率约 1.06 Mbps，范围 0.8～3.0 Mbps；
- H.264 Baseline@L3.1；
- RTP 最大分片 1050 字节；
- 麦克风 Opus 64 kbps、48 kHz、单声道；
- 喇叭默认 `plughw:2,0`；
- 信令主机 `signal.yd-ss.com`。

### 12.3 音频注意事项

- 本地 MP3/TTS、WebRTC 麦克风采集和手机喊话可能竞争声卡/PulseAudio；
- 当前 USB 声卡位于 card 2，但枚举序号可能重启后变化，建议使用稳定的 ALSA by-id 或 udev 规则；
- 日志显示系统会将 Yundea USB 声卡的输入/输出设为默认；
- MQTT 音频 `volume` 是线性增益，代码钳位到 `[0, 2]`。

## 13. 日志、监控与健康检查

### 13.1 日志位置

```text
/home/orangepi/car/master/log/log_YYYY-MM-DD.log
```

最近一次已检查的启动日志表明：设备识别为 0102、HTTP 配置成功、UDP 18888 与 IPC 启动、8 个 MQTT 节点中 7 个连接成功、Chromium 页面已拉起；同时存在一个 MQTT DNS 解析失败和 Tailscale AuthKey 无效。

### 13.2 最小健康检查

```bash
systemctl status carstart.service httpstart.service gostart.service --no-pager -l
pgrep -af '/home/orangepi/car/.*/main|OTAdevice|httpserver.py|chromium|go_video'
ss -lntup
tail -n 200 /home/orangepi/car/master/log/log_$(date +%F).log
```

业务健康至少应同时满足：

- 主进程常驻且无重启循环；
- 正确识别设备型号；
- 至少一个/预期数量 MQTT 节点连接成功；
- 验证开关查询成功；
- UDP 配网服务和 IPC 启动；
- 操作指令、急停、视频和音频按当前设备配置工作；
- 日志中无持续增长的 ERROR。
- OTA 版本文件、生产 `main` 和最新备份一致；
- HTTP Server 仅在需要时对可信局域网开放。

### 13.3 建议补充监控

- systemd 重启次数和退出码；
- MQTT 活跃连接数；
- 最近心跳时间；
- 视频首帧、重连次数、实际码率、丢包/PLI；
- 音频设备是否存在；
- `/dev/video0` 是否为可采集设备；
- 磁盘、日志目录、内存和 CPU；
- 后端配置接口耗时与失败率。
- OTA 最近检查时间、当前版本、下载/校验/回滚结果；
- HTTP Server 8080 暴露范围与设备号修改审计。

## 14. 常见故障排查

### 14.1 服务启动失败

1. `systemctl status carstart.service -l`；
2. 检查 `ExecStart` 文件是否存在且可执行；
3. 检查工作目录、`Deviceld.txt`、`zlog.conf`；
4. Car 可先手工运行 `./main` 获取首个 fatal 初始化错误；
5. 检查 wiringPi、I2C、声卡、摄像头权限。

当前 unit 路径符合 OTA 设计，但实机尚未部署 `master/main` 和 `goproject/OTAdevice`。应先从已验证的 `build/main` 发布生产 `main`，再部署 OTA 二进制。

### 14.2 OTA 不更新或更新后 Car 不启动

- 检查 `gostart.service` 状态与 journal；
- 检查 `Deviceld.txt`、`version.conf`、`main`、`main.tmp`、`backup/`；
- 检查 OTA API 网络、返回版本、下载 URL 和 MD5；
- 检查 `main` 是否为 ARM64、是否有执行权限、动态库是否齐全；
- 检查 OTA 是否成功停止/重启 `carstart.service`；
- 更新失败时先停止 `gostart`，避免重复覆盖，再手工回滚。

### 14.3 HTTP Server 无法访问

- 等待启动脚本固定的 20 秒；
- 检查 `httpstart.service`、8080 监听和防火墙；
- 检查板子是否有到外网的路由，以便 `get_local_ip()` 得到地址；
- 检查 IP 是否变化，变化后重启服务；
- 检查浏览器与设备是否在同一可达网段。

### 14.4 设备识别失败

- 检查 `Deviceld.txt` 是否存在、是否正好 14 位、是否有不可见字符；
- 检查第 3～6 位是否在 `device_identity.c` 注册；
- 检查型号是否在 `device_init.c` 有初始化配置；
- 不要随意修改设备号，topic、后端配置和设备动作都依赖它。

### 14.5 MQTT 不连接

- 检查 DNS、网关和系统时间；
- 检查后端配置接口返回的 Broker 列表；
- 允许单个节点失败，但需要确认活跃节点数；
- 检查 1883 出站策略和 Mosquitto 返回码；
- 禁止在日志中打印完整 JWT、密码或 token。

### 14.6 Chromium 无画面

- 检查当前模式确为 Chromium；
- 检查 `/dev/video0`、浏览器进程、`DISPLAY=:0` 与 XAUTHORITY；
- 检查页面 URL 是否带正确设备号；
- 检查是否被 `pkill chromium` 后未能重启；
- 检查 PulseAudio/摄像头权限和网页端信令。

### 14.7 C 原生推流失败

- 确认 `WEBRTCPUSH_USE_MPP=1` 后重新编译；
- 用 `gst-inspect-1.0` 检查 `webrtcbin`、`v4l2src`、`opusenc`、`mpph264enc`/`x264enc`；
- 检查信令 DNS/TLS、摄像头格式、MPP 设备和 ALSA/Pulse；
- 观察是否自动回退 Chromium；
- 不要同时手工启动多个推流实现。

### 14.8 无声音或声卡被占用

- `aplay -l`、`arecord -l`、`pactl list short sinks/sources`；
- 确认 card 2 未因重启变为其他序号；
- 检查本地播报、WebRTC 喊话、麦克风是否同时占用；
- 检查 `/home/orangepi/audio/<语言>/` 资源文件；
- 先停止车辆动作再做大音量测试。

### 14.9 WiFi 配网失败

- 检查 UDP 18888 是否监听、是否被防火墙拦截；
- 手机与设备是否在同一广播域；
- 检查配置命令的 ACK/结果返回；
- 检查设备号和显示名生成是否正常；
- 修改网络前保留 SSH 回退通道，避免失联。

## 15. 安全、可靠性与技术债

### P0：立即处理

1. **部署不完整**：unit 已安装，但 Car 生产 `main`、OTA 二进制和版本文件缺失，三项服务均未启用。
2. **日志泄露凭据**：历史日志出现完整 JWT；应立刻轮换可能受影响的凭据，删除/受控归档旧日志，并在代码中只记录摘要。
3. **硬件安全测试缺少门禁**：发布/调试前必须架空车辆或断开动力，验证急停后再落地。
4. **设备号接口无鉴权**：HTTP Server 能直接覆盖设备身份，只能部署在受控网络。

### P1：近期处理

1. `go_deploy.c` 下载时关闭 TLS 证书和主机校验，存在中间人攻击风险；
2. 运行时依赖模块可能在程序启动阶段执行 `apt-get`、重载摄像头模块或 USB reset，增加不可预测性；
3. 服务使用 root，权限过大；应评估最小能力集、设备组权限或专用用户；
4. UDP 18888 监听所有网卡，调试/配网命令需要鉴权、来源限制和重放保护；
5. Tailscale 日志显示 AuthKey 缺失或无效，应明确是否仍为生产依赖；
6. 稳定配置散落在源码宏中，修改需要重新编译。
7. OTA 使用 HTTP + MD5，缺少更新包签名和更新后健康检查。

### P2：持续改进

1. 建立版本化发布目录、可审计发布脚本和一键回滚；
2. 为设备号解析、消息分发、速度边界和急停逻辑增加单元测试；
3. 为每类硬件建立 HIL 冒烟测试；
4. 统一 Chromium、Go、C 三条推流路线的负责人和淘汰策略；
5. 增加 CI 构建、静态分析、依赖漏洞和许可证检查；
6. 补齐服务 Watchdog、健康检查和结构化指标。

## 16. 常用变更流程

### 16.1 新增设备型号

1. 分配四位型号编码并确认 14 位设备号规则；
2. 在设备身份映射中注册；
3. 在 GPIO/串口初始化表中加入资源；
4. 新增对应控制文件并接入统一控制/停止入口；
5. 校验引脚、电压、PWM 上限、方向和急停；
6. 更新 MQTT 消息适配；
7. 在架空状态完成正反转、转向、失联停车和异常恢复测试；
8. 更新设备清单和发布记录。

### 16.2 修改 MQTT 消息

1. 记录 `message_type`、请求/响应 JSON、topic 和兼容策略；
2. 对空字段、类型错误、重复消息、乱序和超时做防御；
3. 保留旧版本兼容期；
4. 日志只记录消息类型、设备号掩码和结果，不记录 token；
5. 与 App/后端联调后再合入。

### 16.3 修改推流

1. 明确目标路径；
2. 固化摄像头、编码、信令、音频输入输出基线；
3. 测试首帧、10 分钟稳定性、弱网、切网、换手机、音视频同时运行；
4. 检查资源释放和回退路径；
5. 记录关键参数与实测结果，禁止只凭“有画面”上线。

### 16.4 发布 Car 与 OTA

1. Car 在 `build/main` 完成编译和冒烟测试；
2. 记录 SHA-256 后复制为 `master/main`；
3. OTA 在测试板验证 API、下载、MD5、备份、替换和回滚；
4. 补齐 `version.conf`、`backup/` 和文件权限；
5. 校验三份 unit，执行 `daemon-reload`；
6. 先启动 HTTP/Car，再启动 OTA；
7. 验证服务自启、整机重启和更新后业务健康。

## 17. 接手验收清单

### 17.1 账号与资料

- [ ] 已获得代码仓库、后端测试环境、MQTT、设备管理和日志访问权限；
- [ ] 已确认敏感凭据交付渠道，不在本文或 Git 中保存；
- [ ] 已明确生产/测试设备号和硬件负责人；
- [ ] 已确认三个 Git remote 的用途与主仓库。
- [ ] 已获得 OTAdevice 仓库与 OTA 后端接口权限。

### 17.2 开发与构建

- [ ] 能从干净工作区完成 Release/Debug 编译；
- [ ] 能说明可执行文件、配置、日志和音频资源位置；
- [ ] 能定位设备识别、控制、MQTT、配网和推流代码；
- [ ] 已保存已知可用版本的提交号和二进制哈希。
- [ ] 能构建/部署 `goproject/OTAdevice` 并说明 `version.conf`、`backup/` 的作用。

### 17.3 部署与运行

- [ ] 三项 ExecStart 目标文件均存在且权限正确；
- [ ] 三份 unit 位于 `/etc/systemd/system/`，已通过 verify；
- [ ] 已决定是否启用开机自启；
- [ ] 重启后设备可自动恢复；
- [ ] 能查看服务日志并判断健康状态；
- [ ] 能在 10 分钟内完成回滚。
- [ ] 已完成一次 OTA 全流程测试和一次失败回滚测试。

### 17.4 功能与安全

- [ ] 型号识别正确；
- [ ] 前进、后退、转向与急停正确；
- [ ] 失联后按预期停车；
- [ ] MQTT 心跳、验证和控制正常；
- [ ] 视频、麦克风、喇叭与本地播报正常；
- [ ] WiFi 配网和断网恢复正常；
- [ ] 日志不再输出完整 JWT、密码或 AuthKey。
- [ ] TCP 8080 仅允许可信网络访问，设备号输入经过人工复核。

## 18. 建议阅读顺序

1. `app/main/main.c`：掌握初始化阶段；
2. `app/main/pthread_open.c`：掌握常驻线程；
3. `app/device_identity/device_identity.c`：掌握型号识别；
4. `drivers/gpio/device_init.c`：掌握资源初始化；
5. `drivers/devicecontrol/devcontrol_common.c` 和当前车型实现；
6. `modules/mqtt/`：掌握控制和状态链路；
7. `modules/http/http_config_mqtt.c`：掌握后端配置；
8. `modules/wifi_config/` 与 `modules/device_debug/`；
9. `modules/browser/`、`modules/go_deploy/`、`modules/webrtcpush/`。
10. OTA 仓库 `goproject/main.go`：掌握版本、备份、下载和回滚。
11. OTA 仓库 `httpserver.py`：掌握设备号录入服务。
12. `/etc/systemd/system/{carstart,httpstart,gostart}.service`。

## 19. 附录：实用命令

### 环境快照

```bash
uname -a
cat /etc/os-release
ip -brief address
df -h /
free -h
```

### Git 快照

```bash
cd /home/orangepi/car/master
git branch --show-current
git status --short
git log -8 --date=short --pretty=format:'%h %ad %s'
```

### 构建

```bash
cmake -S . -B build -DCAR_BUILD_TYPE=Release
cmake --build build -j2
file build/main
sha256sum build/main
sudo install -o root -g root -m 0755 build/main main
```

### 服务与日志

```bash
systemctl cat carstart.service httpstart.service gostart.service
systemctl status carstart.service httpstart.service gostart.service --no-pager -l
systemctl is-enabled carstart.service httpstart.service gostart.service
journalctl -u carstart.service -u httpstart.service -u gostart.service -n 300 --no-pager
tail -n 200 log/log_$(date +%F).log
```

### 设备与媒体

```bash
ls -l /dev/video*
v4l2-ctl --list-devices
aplay -l
arecord -l
pactl list short sinks
pactl list short sources
```

### 网络与进程

```bash
ss -lntup
pgrep -af 'main|OTAdevice|httpserver.py|chromium|go_video'
getent hosts fcrs-api.yd-ss.com
getent hosts signal.yd-ss.com
```

---

## 20. 交接结论

项目由 Car、OTAdevice 和设备号 HTTP Server 三部分共同组成。`carstart.service` 指向 `master/main` 与 OTA 的下载目标一致，是有意的发布约定；`build/main` 仅是编译产物。三份 systemd 配置已存在于正确目录，但当前板端仍缺生产 Car/OTA 文件且未启用服务。接手人应先按本文补齐部署结构并验证三服务自启，再在安全条件下完成 OTA 成功、失败和回滚测试，同时治理 HTTP 设备号入口及凭据日志风险。

本文不包含任何密码、私钥、MQTT 凭据、JWT 或 Tailscale AuthKey。相关秘密应通过独立的安全渠道交接。
