charging-cabinet/README.md

371 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 充电柜矩阵系统 (Power Matrix System / PMS)
产品名:安知充(anzhizhichong)
## 项目简介
36仓体直流电瓶车充电柜,仓数不固定:1柜控板+N仓控板,每仓控板管6仓,最小6仓。
## 技术栈
- **后端**:Rust + Axum
- **前端**:React + Arco Design Pro(管理端)
- **H5用户端**:uni-app + Vue 3(跨平台,支持 H5 / 微信小程序)
- **数据库**:MySQL(阿里云RDS)
- **缓存**:Redis(阿里云Redis)
- **设备通讯**:TCP长连接(柜控板4G模块,Air780E Cat.1)
## 项目结构
```
charging-cabinet/
├── tasks/ # 任务文件(opencode执行)
├── docs/ # 开发文档、协议文档
├── software/
│ ├── api-server/ # Rust API服务
│ ├── device-server/ # Rust TCP设备服务
│ ├── web/ # React管理端前端
│ └── h5-uniapp/ # H5用户端(uni-app + Vue 3)
├── hardware/ # 硬件资料(原理图/PCB等)
├── deploy/ # 部署配置
└── test/ # 测试用例/报告
```
## 部署架构
| 环境 | 域名 | 说明 |
|------|------|------|
| 正式环境 | app.anzhizhichong.com | 后台管理 + API服务 |
| 测试环境 | test.anzhizhichong.com | 测试环境 |
**服务器**:CentOS Stream 9
**内部服务**:
- Gitea: https://app.anzhizhichong.com/doc/
- 文档Wiki: https://app.anzhizhichong.com/doc/anzhizhichong/charging-cabinet/wiki/
## 服务架构
```
┌─────────────────────────────────────────────────────────────┐
│ API服务 (api-server) — 主服务 │
│ - HTTP API(后台管理 + H5)端口: 3000 │
│ - 前端轮询刷新(每5秒) │
│ - 业务逻辑处理(验证/存DB/告警) │
│ - 节点管理(设备服务注册/心跳) │
│ - 后台协程处理Redis队列 │
└─────────────────────────────────────────────────────────────┘
↑ Redis LIST ↑ Redis LIST
│ device:report:{imei} │ device:cmd:{imei}
│ (设备上报) │ (平台指令)
│ │
┌─────────────────────────────────────────────────────────────┐
│ 设备服务 (device-server) — 轻量化 │
│ - TCP监听: 3002(设备长连接) │
│ - 只处理通信和指令解析 │
│ - 不存DB、不验证签名、不处理业务 │
│ - 注册到API服务(启动/心跳/注销) │
│ - Redis连接注册: device:{imei} → {node_id, ip, port} │
└─────────────────────────────────────────────────────────────┘
```
**核心设计原则:**
1. **TCP服务轻量化** — 只处理TCP通信和指令解析,不处理业务逻辑
2. **Redis做缓冲** — 服务间通信用Redis LIST,不用HTTP直接调用
3. **全异步处理** — 所有指令异步处理,msg_id匹配响应
4. **协程处理任务** — API服务用tokio::spawn处理Redis队列消息
**通信流程:**
- **设备上报**:设备 → TCP → 设备服务 → Redis LIST → API服务协程处理
- **平台指令**:API服务 → Redis LIST → 设备服务 → TCP → 设备
- **指令响应**:设备 → TCP → 设备服务 → Redis LIST → API服务匹配msg_id
**节点管理:**
- 设备服务启动时注册到API服务
- 每60秒心跳,180秒无心跳视为离线
- 支持多节点扩展(当前单节点)
## TCP通讯协议
### 通信规则
- TCP长连接,无需PING包
- 空闲1分钟上报,充电15秒上报
- 超时5000ms
- JSON去空格回车省流量,LF处理粘包
- `dev_id`:IMEI(10进制),`sub_device_id`:485 ID
- `msg_id`:自增会话ID
- 全局通道号:`dev_id-sub_device_id-通道号`(如`123456789012345-01-6`)
### 签名机制
- 设备首次连接调 `auth_str` 接口获取8位安全码(仅一次)
- `sign = SHA256(dev_id + auth_str + timestamp).substring(56, 63)`
- 时间戳秒级,平台校验±60秒
### 指令清单
| 动作 | 方向 | id格式 | 说明 |
|------|------|--------|------|
| `login` | 设备→平台 | 无 | 登录(含sign+timestamp) |
| `auth_str` | 设备→平台 | 无 | 获取安全码(仅首次) |
| `status_post` | 设备→平台 | 无 | 定时上报(rssi+status字典) |
| `pow_fail` | 设备→平台 | 无 | 电源掉电上报(含info区分交直流) |
| `bat_in` | 设备→平台 | `IMEI-仓控板-通道` | 电池插入(含BMS数据,字段待定) |
| `bat_out` | 设备→平台 | `IMEI-仓控板-通道` | 电池拔出 |
| `on` | **双向** | `IMEI-仓控板-通道` | 开始充电(平台下发/设备上报) |
| `off` | **双向** | `IMEI-仓控板-通道` | 停止供电(平台手动/设备自动) |
| `open` | 平台→设备 | `IMEI` | 开门 |
| `pow_on` | 平台→设备 | `IMEI` | 接触器合闸(恢复380V供电) |
| `pow_off` | 平台→设备 | `IMEI` | 接触器分闸(切断380V供电) |
| `reset` | 平台→设备 | `IMEI` 或 `IMEI-仓控板` | 重启整柜或仓控板 |
### status_post格式
```json
{
"act": "status_post",
"msg_id": 42,
"dev_id": "123456789012345",
"rssi": 85,
"status": {
"123456789012345-01": "000100020003000400050006",
"123456789012345-02": "000100020003000400050006"
}
}
```
- key: `IMEI-仓控板ID`
- value: 6个通道状态拼接(每通道2字节=4个HEX字符)
- 平台从key解析仓控板数量
### 指令详情
#### login(设备→平台)
设备登录,验证签名。
```json
// 请求
{"act":"login","msg_id":1,"dev_id":"123456789012345","sign":"abc12345","timestamp":1719800000,"h_ver":"1.0.0","s_ver":"1.0.0"}
// 响应
{"suc":1,"msg_id":1,"cell":6}
```
**字段说明:**
- `sign` — 签名(SHA256(dev_id+auth_str+timestamp)后8位)
- `timestamp` — 秒级时间戳(平台校验±60秒)
- `h_ver` — 硬件版本
- `s_ver` — 软件版本
- `cell` — 仓控板数量
---
#### auth_str(设备→平台)
获取8位安全码,仅首次连接调用。
```json
// 请求
{"act":"auth_str","msg_id":2,"dev_id":"123456789012345","ccid":"89860000000000000000"}
// 响应
{"suc":1,"msg_id":2,"data":{"auth_str":"abcd1234"}}
```
**字段说明:**
- `ccid` — SIM卡ICCID号
- `auth_str` — 8位随机安全码(仅返回一次)
---
#### status_post(设备→平台)
定时上报,空闲60秒/充电15秒。
```json
// 请求
{"act":"status_post","msg_id":10,"dev_id":"123456789012345","rssi":85,"status":{"123456789012345-01":"000100020003000400050006","123456789012345-02":"000100020003000400050006"}}
// 响应
{"suc":1,"msg_id":10}
```
**status字段说明:**
- key: `IMEI-仓控板ID`
- value: 6个通道状态拼接(每通道2字节=4个HEX字符)
- 平台从key解析仓控板数量
---
#### pow_fail(设备→平台)
电源掉电上报。
```json
// 请求
{"act":"pow_fail","msg_id":15,"dev_id":"123456789012345","info":"0"}
// 响应
{"suc":1,"msg_id":15}
```
**字段说明:**
- `info` — 停电类型:`0`=直流停电(12V掉电),`1`=交流停电(380V掉电)
---
#### pow_on(平台→设备)
接触器合闸,恢复380V充电电源供电。
```json
// 请求
{"act":"pow_on","msg_id":16,"dev_id":"123456789012345"}
// 响应
{"suc":1,"msg_id":16}
```
---
#### pow_off(平台→设备)
接触器分闸,切断380V充电电源供电。
```json
// 请求
{"act":"pow_off","msg_id":16,"dev_id":"123456789012345"}
// 响应
{"suc":1,"msg_id":16}
```
---
#### bat_in(设备→平台)
电池插入事件,立即上报。
```json
// 请求
{"act":"bat_in","msg_id":20,"id":"123456789012345-01-6","bms":{"soc":45,"voltage":52.3}}
// 响应
{"suc":1,"msg_id":20}
```
**平台处理:**
1. 记录电池信息
2. 验证电池合规性
3. 自动下发 `on` 指令
**BMS数据字段待定。**
---
#### bat_out(设备→平台)
电池拔出事件,立即上报。
```json
// 请求
{"act":"bat_out","msg_id":21,"id":"123456789012345-01-6"}
// 响应
{"suc":1,"msg_id":21}
```
---
#### on(双向)
**平台→设备:** 开始充电
```json
// 请求
{"act":"on","msg_id":30,"id":"123456789012345-01-6"}
// 响应
{"suc":1,"msg_id":30}
```
**设备→平台:** 充电开始确认(自动充电模式)
```json
// 上报
{"act":"on","msg_id":30,"id":"123456789012345-01-6"}
```
---
#### off(双向)
**平台→设备:** 手动停止充电
```json
// 请求
{"act":"off","msg_id":31,"id":"123456789012345-01-6"}
// 响应
{"suc":1,"msg_id":31}
```
**设备→平台:** 充满自动停止
```json
// 上报
{"act":"off","msg_id":31,"id":"123456789012345-01-6"}
```
---
#### open(平台→设备)
开门,只需IMEI。
```json
// 请求
{"act":"open","msg_id":40,"id":"123456789012345"}
// 响应
{"suc":1,"msg_id":40}
```
**错误码63 = 门锁故障。**
---
#### reset(平台→设备)
重启整柜或仓控板。
```json
// 重启整柜
{"act":"reset","msg_id":60,"id":"123456789012345"}
// 重启仓控板
{"act":"reset","msg_id":61,"id":"123456789012345-01"}
// 响应
{"suc":1,"msg_id":60}
```
### 充电结束原因(平台判断)
| 平台收到 | 判断原因 |
|---------|---------|
| `off` (设备→平台) | `normal` — 正常充满 |
| `off` (平台→设备) | `user_stop` — 用户手动停止 |
| `bat_out` | `normal` — 电池拔出 |
| `bat_in` (通道已有电池) | `forced` — 新电池插入,旧电池强制结束 |
| 超时未响应 | `timeout` — 通信超时 |
## 开发规范
- 任务需求写到 `tasks/` 目录的md文件
- 通过Agent子代理包裹opencode执行,异步通知
- 质量约束模板固定追加到每个任务文件
- 完成代码后执行对应栈静态校验(Rust→cargo check,TS→tsc --noEmit),零报错零警告