Files
MES/yawei-mes/.tasks/2025-11-15_8Multi接入.md
2026-04-02 10:39:03 +08:00

956 lines
39 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.

# 8Multi协议设备接入技术方案
## 一、项目背景
在现有8ADPRO设备接入系统的基础上新增8Multi协议设备的接入支持。需要保持原有8ADPRO协议功能完全不受影响通过扩展现有架构实现新协议的兼容。
## 二、协议对比分析
### 2.1 原8ADPRO协议格式
```
+YAV:设备号,温度,电流,计数1,计数2,模拟1,模拟2,模拟3,模拟4,模拟5,模拟6,模拟7,数字1,数字2,数字3,数字4,数字5,数字6,EEFF
```
- **字段数量**: 19个字段
- **特点**: 简单直接,所有值都是实际物理量
### 2.2 新8Multi协议格式
```
+YAV:id,电流1,电流2,质量1,质量2,温度,湿度,工作停机故障清零,频率1,计数1,频率2,计数2,供电报警软启动停止,从机数据1,从机数据2,触摸屏,EEFF
```
**C格式**: `+YAV:%d,%d,%d,%d,%d,%.1f,%.1f,%d,%d,%d,%d,%d,%d,%d,%d,0,EEFF`
- **字段数量**: 16个字段不含帧头+YAV和帧尾EEFF
- **特点**:
- 包含设备ID字段g_tDevParam.Address
- 电流1/2AI1/AI2范围0-20A需量程转换0-65535映射
- 质量1/2AI3/AI4需量程转换0-65535映射
- 温湿度保留1位小数的实际值
- 4路DI复合状态工作/停机/故障/清零)
- 2路频率+计数
- 2路继电器+2路DO复合状态供电/报警/软启动/停止)
- 485从机数据2路
- 触摸屏数据固定发送0
### 2.3 关键差异点
| 项目 | 8ADPRO | 8Multi |
|------|--------|--------|
| 设备识别 | 第1字段设备号 | 第1字段设备ID |
| 电流采集 | 1路电流实际值 | 2路电流需量程校准 |
| 质量采集 | 无 | 2路质量需量程校准 |
| 温湿度 | 仅温度 | 温度+湿度 |
| 状态位 | 6个独立数字量 | 4个复合状态字段位运算 |
| 计数器 | 2路计数 | 2路频率+计数 |
| 状态上传 | 无 | 2路继电器+2路DO状态 |
| 扩展功能 | 无 | 485从机+触摸屏 |
**说明**8Multi协议的继电器和DO字段为下位机上传的状态不涉及下发控制功能。
## 三、数据库设计方案
### 3.1 设备主表扩展 (device)
**新增字段**:
```sql
ALTER TABLE `device`
ADD COLUMN `protocol_type` ENUM('8ADPRO', '8MULTI') NOT NULL DEFAULT '8ADPRO'
COMMENT '协议类型8ADPRO=原协议8MULTI=新协议根据device_no自动判断>200为8MULTI<=200为8ADPRO' AFTER `device_code`,
ADD COLUMN `current1_range_start` DECIMAL(10,3) DEFAULT 0
COMMENT '电流1量程起点A' AFTER `protocol_type`,
ADD COLUMN `current1_range_end` DECIMAL(10,3) DEFAULT NULL
COMMENT '电流1量程终点A用于0-65535映射8Multi设备必填' AFTER `current1_range_start`,
ADD COLUMN `current2_range_start` DECIMAL(10,3) DEFAULT 0
COMMENT '电流2量程起点A' AFTER `current1_range_end`,
ADD COLUMN `current2_range_end` DECIMAL(10,3) DEFAULT NULL
COMMENT '电流2量程终点A用于0-65535映射8Multi设备必填' AFTER `current2_range_start`,
ADD COLUMN `quality1_range_start` DECIMAL(10,3) DEFAULT 0
COMMENT '质量1量程起点' AFTER `current2_range_end`,
ADD COLUMN `quality1_range_end` DECIMAL(10,3) DEFAULT NULL
COMMENT '质量1量程终点用于0-65535映射8Multi设备必填' AFTER `quality1_range_start`,
ADD COLUMN `quality1_unit` VARCHAR(10) DEFAULT NULL
COMMENT '质量1单位前端配置如kg/g' AFTER `quality1_range_end`,
ADD COLUMN `quality2_range_start` DECIMAL(10,3) DEFAULT 0
COMMENT '质量2量程起点' AFTER `quality1_unit`,
ADD COLUMN `quality2_range_end` DECIMAL(10,3) DEFAULT NULL
COMMENT '质量2量程终点用于0-65535映射8Multi设备必填' AFTER `quality2_range_start`,
ADD COLUMN `quality2_unit` VARCHAR(10) DEFAULT NULL
COMMENT '质量2单位前端配置如kg/g' AFTER `quality2_range_end`,
ADD COLUMN `current_unit` VARCHAR(10) DEFAULT 'A'
COMMENT '电流单位前端配置如A/mA' AFTER `quality2_unit`;
```
**字段说明**:
- `protocol_type`: 区分设备使用的协议类型,根据`device_no`自动判断(>200为8MULTI<=200为8ADPRO
- `current1_range_start` / `current1_range_end`: 电流1量程起点和终点8Multi设备必填
- `current2_range_start` / `current2_range_end`: 电流2量程起点和终点8Multi设备必填
- `quality1_range_start` / `quality1_range_end`: 质量1量程起点和终点8Multi设备必填
- `quality2_range_start` / `quality2_range_end`: 质量2量程起点和终点8Multi设备必填
- `quality1_unit` / `quality2_unit`: 质量单位前端配置如kg/g
- `current_unit`: 电流单位前端配置如A/mA
**协议类型判断规则**:
- `device_no > 200`: 自动设置为8MULTI协议
- `device_no <= 200`: 自动设置为8ADPRO协议
- 同一设备不能在两种协议之间切换
**量程转换公式**:
```
量程范围 = 量程终点 - 量程起点
实际值 = (原始值 / 65535.0) * 量程范围 + 量程起点
```
**设备状态判断**:
- 电流1实际值 >= 2A **且** 电流2实际值 >= 2A设备开启状态与运算
- 其他情况:设备关闭状态
### 3.2 数据表扩展 (device_data)
**新增字段**:
```sql
ALTER TABLE `device_data`
ADD COLUMN `current1_raw` INT UNSIGNED DEFAULT NULL
COMMENT '电流1原始值0-65535' AFTER `current_value`,
ADD COLUMN `current2_raw` INT UNSIGNED DEFAULT NULL
COMMENT '电流2原始值0-65535' AFTER `current1_raw`,
ADD COLUMN `current1_value` DECIMAL(10,3) DEFAULT NULL
COMMENT '电流1实际值A经量程转换' AFTER `current2_raw`,
ADD COLUMN `current2_value` DECIMAL(10,3) DEFAULT NULL
COMMENT '电流2实际值A经量程转换' AFTER `current1_value`,
ADD COLUMN `quality1_raw` INT UNSIGNED DEFAULT NULL
COMMENT '质量1原始值0-65535' AFTER `current2_value`,
ADD COLUMN `quality2_raw` INT UNSIGNED DEFAULT NULL
COMMENT '质量2原始值0-65535' AFTER `quality1_raw`,
ADD COLUMN `quality1_value` DECIMAL(10,3) DEFAULT NULL
COMMENT '质量1实际值kg经量程转换' AFTER `quality2_raw`,
ADD COLUMN `quality2_value` DECIMAL(10,3) DEFAULT NULL
COMMENT '质量2实际值kg经量程转换' AFTER `quality1_value`,
ADD COLUMN `humidity` DECIMAL(10,3) DEFAULT NULL
COMMENT '湿度值(%RH' AFTER `quality2_value`,
ADD COLUMN `status_work` TINYINT(1) DEFAULT NULL
COMMENT '工作状态0=停止1=工作)' AFTER `humidity`,
ADD COLUMN `status_stop` TINYINT(1) DEFAULT NULL
COMMENT '停机状态0=运行1=停机)' AFTER `status_work`,
ADD COLUMN `status_fault` TINYINT(1) DEFAULT NULL
COMMENT '故障状态0=正常1=故障)' AFTER `status_stop`,
ADD COLUMN `status_reset` TINYINT(1) DEFAULT NULL
COMMENT '清零状态0=正常1=清零)' AFTER `status_fault`,
ADD COLUMN `frequency1` INT DEFAULT NULL
COMMENT '频率1原始值' AFTER `status_reset`,
ADD COLUMN `frequency2` INT DEFAULT NULL
COMMENT '频率2原始值' AFTER `frequency1`,
ADD COLUMN `counter1_current` INT DEFAULT NULL
COMMENT '计数1当前累计值下位机传值' AFTER `frequency2`,
ADD COLUMN `counter1_delta` INT DEFAULT NULL
COMMENT '计数1增量值当前值-上次值)' AFTER `counter1_current`,
ADD COLUMN `counter2_current` INT DEFAULT NULL
COMMENT '计数2当前累计值下位机传值' AFTER `counter1_delta`,
ADD COLUMN `counter2_delta` INT DEFAULT NULL
COMMENT '计数2增量值当前值-上次值)' AFTER `counter2_current`,
ADD COLUMN `counter1_total_8multi` BIGINT UNSIGNED DEFAULT NULL
COMMENT '计数1累计总数8Multi专用从清零基准值开始累计' AFTER `counter2_delta`,
ADD COLUMN `counter2_total_8multi` BIGINT UNSIGNED DEFAULT NULL
COMMENT '计数2累计总数8Multi专用从清零基准值开始累计' AFTER `counter1_total_8multi`,
ADD COLUMN `relay_power` TINYINT(1) DEFAULT NULL
COMMENT '继电器-供电状态0=断开1=闭合)' AFTER `counter2_total_8multi`,
ADD COLUMN `relay_alarm` TINYINT(1) DEFAULT NULL
COMMENT '继电器-报警状态0=正常1=报警)' AFTER `relay_power`,
ADD COLUMN `do_soft_start` TINYINT(1) DEFAULT NULL
COMMENT 'DO-软启动0=关1=开)' AFTER `relay_alarm`,
ADD COLUMN `do_stop` TINYINT(1) DEFAULT NULL
COMMENT 'DO-停止0=关1=开)' AFTER `do_soft_start`,
ADD COLUMN `slave_data1` INT DEFAULT NULL
COMMENT '485从机数据1' AFTER `do_stop`,
ADD COLUMN `slave_data2` INT DEFAULT NULL
COMMENT '485从机数据2' AFTER `slave_data1`,
ADD COLUMN `touchscreen_data` INT DEFAULT NULL
COMMENT '触摸屏数据' AFTER `slave_data2`;
```
### 3.3 动态字段配置扩展 (device_field_header_config)
**修改字段枚举**:
```sql
ALTER TABLE `device_field_header_config`
MODIFY COLUMN `field_key` ENUM(
'analog1','analog2','analog3','analog4','analog5','analog6','analog7',
'digital1','digital2','digital3','digital4','digital5','digital6',
'current1','current2','quality1','quality2','humidity',
'frequency1','frequency2','slave_data1','slave_data2','touchscreen_data'
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL
COMMENT '字段标识支持8ADPRO和8Multi协议字段';
```
### 3.4 计数器字段设计(避免触发器冲突)
**问题**:现有触发器`update_counter_totals_on_insert`处理8ADPRO的`counter1_total`/`counter2_total`字段。
**解决方案**为8Multi添加独立的计数器总计字段不修改触发器
**字段对比**
| 协议 | 当前值字段 | 增量值字段 | 总计字段 | 触发器 |
|------|-----------|-----------|---------|--------|
| 8ADPRO | counter1/counter2 | - | counter1_total/counter2_total | ✅ 使用 |
| 8Multi | counter1_current/counter2_current | counter1_delta/counter2_delta | counter1_total_8multi/counter2_total_8multi | ❌ 不使用 |
**8Multi计数器逻辑**(修订版):
```java
// 1. 获取当前累计值(下位机传值)
int currentCounter1 = parseInt(parts[10]);
// 2. 获取清零基准值baseline
long baseline1 = device.getCounter1Baseline() != null ? device.getCounter1Baseline() : 0L;
// 3. 计算累计值(下位机当前值 - 清零基准值)
long total1 = (long)currentCounter1 - baseline1;
if (total1 < 0) total1 = 0L; // 负值保护
// 4. 计算增量值(当前值 - 上次值)
int delta1 = currentCounter1 - lastCounter1;
if (delta1 < 0) delta1 = 0; // 负值归零(下位机可能重置)
// 5. 存储
deviceData.setCounter1Current(currentCounter1); // 下位机当前累计值
deviceData.setCounter1Delta(delta1); // 本次增量
deviceData.setCounter1Total8multi(total1); // 累计总值(= 下位机值 - baseline
```
**关键设计说明**
- **累计值 = 下位机当前值 - baseline**(不是累加增量!)
- **第一条数据**:累计值 = 下位机当前值因为baseline默认为0
- **清零功能**设置baseline = 当前下位机值累计值重新从0开始
- **优点**:即使下位机重置归零,累计值仍能正确计算
**优点**
- ✅ 不修改现有触发器8ADPRO功能完全不受影响
- ✅ 8Multi使用独立字段逻辑清晰
- ✅ 两种协议完全隔离,互不干扰
## 四、数据解析规则
### 4.1 量程映射转换
**电流/质量原始值转换公式**:
```
实际值 = (原始值 / 65535.0) * 量程
```
**示例**:
- 电流1量程设置为100A
- 接收到原始值32768
- 实际电流1 = (32768 / 65535.0) * 100 = 50.0A
### 4.2 复合状态位解析
#### 4.2.1 DI状态字段解析工作/停机/故障/清零)
```
字段值: U16格式例如 0x004F
解析规则: 取最后一个F低4位然后取反
```
**解析代码示例**:
```java
int diValue = parseInt(parts[8]); // 例如 0x004F
int lastNibble = diValue & 0x0F; // 取最后4位 = 0xF = 15
int inverted = (~lastNibble) & 0x0F; // 取反并保留4位 = 0x0 = 0
// 解析各个DI状态
boolean work = (inverted & 0x01) != 0; // DI1: 工作
boolean stop = (inverted & 0x02) != 0; // DI2: 停机
boolean fault = (inverted & 0x04) != 0; // DI3: 故障
boolean reset = (inverted & 0x08) != 0; // DI4: 清零
```
#### 4.2.2 继电器+DO状态字段解析供电/报警/软启动/停止)
```
字段值: U16格式例如 0x004F
解析规则: 取最后一个F低4位然后取反与DI状态相同
下发格式: DO=0_10为通道号1为值
```
**解析代码示例**:
```java
int doValue = parseInt(parts[12]); // 例如 0x004F
int lastNibble = doValue & 0x0F; // 取最后4位 = 0xF = 15
int inverted = (~lastNibble) & 0x0F; // 取反并保留4位 = 0x0 = 0
// 解析各个继电器和DO状态
boolean power = (inverted & 0x01) != 0; // 继电器1: 供电
boolean alarm = (inverted & 0x02) != 0; // 继电器2: 报警
boolean softStart = (inverted & 0x04) != 0; // DO1: 软启动
boolean stopDo = (inverted & 0x08) != 0; // DO2: 停止
```
**下发控制示例**:
```
DO=0_1 // 通道0供电值为1开启
DO=1_0 // 通道1报警值为0关闭
```
### 4.3 计数器处理逻辑(修订版)
**核心设计原则**:
- 下位机传输的是累计值
- 累计值 = 下位机当前值 - 清零基准值baseline
- 增量值 = 当前值 - 上次值
**完整处理流程**:
```java
// 1. 获取下位机传来的当前累计值
int counter1Current = parseInt(parts[10]); // 计数器1
int counter2Current = parseInt(parts[12]); // 计数器2
// 2. 获取清零基准值(用于计算累计值)
Long baseline1 = device.getCounter1Baseline() != null ? device.getCounter1Baseline() : 0L;
Long baseline2 = device.getCounter2Baseline() != null ? device.getCounter2Baseline() : 0L;
// 3. 计算累计值(显示在前端卡片上的大数字)
Long total1 = (long)counter1Current - baseline1;
Long total2 = (long)counter2Current - baseline2;
if (total1 < 0) total1 = 0L; // 负值保护
if (total2 < 0) total2 = 0L;
// 4. 查询上次累计值(用于计算增量)
DeviceData lastData = selectLastByDeviceId(deviceId);
Integer lastCounter1 = lastData != null ? lastData.getCounter1Current() : 0;
Integer lastCounter2 = lastData != null ? lastData.getCounter2Current() : 0;
// 5. 计算增量值(显示在前端卡片上的小字)
int delta1 = counter1Current - lastCounter1;
int delta2 = counter2Current - lastCounter2;
if (delta1 < 0) delta1 = 0; // 负值归零(下位机可能重置)
if (delta2 < 0) delta2 = 0;
// 6. 存储到数据库
deviceData.setCounter1Current(counter1Current); // 下位机原始值
deviceData.setCounter1Delta(delta1); // 增量
deviceData.setCounter1Total8multi(total1); // 累计值
deviceData.setCounter2Current(counter2Current);
deviceData.setCounter2Delta(delta2);
deviceData.setCounter2Total8multi(total2);
```
**清零功能实现**:
- 前端提供清零按钮
- 点击清零:`UPDATE device SET counter1_baseline = 当前下位机值 WHERE id = ?`
- 清零后:累计值 = 下位机值 - baseline重新从0开始
- 下位机继续传累计值,不受影响
**数据库字段**:
```sql
ALTER TABLE `device`
ADD COLUMN `counter1_baseline` INT DEFAULT 0 COMMENT '计数1基准值清零后的基准',
ADD COLUMN `counter2_baseline` INT DEFAULT 0 COMMENT '计数2基准值清零后的基准',
ADD COLUMN `voltage1` DECIMAL(10,3) DEFAULT NULL COMMENT '电压1配置V用于功率1计算',
ADD COLUMN `voltage2` DECIMAL(10,3) DEFAULT NULL COMMENT '电压2配置V用于功率2计算';
```
**示例场景**:
```
时间线:
下位机值: 100 → 150 → 200 → [清零,baseline=200] → 250 → 300
累计值: 100 → 150 → 200 → 0 → 50 → 100
增量值: 0 → 50 → 50 → 0 → 50 → 50
```
## 五、接口设计方案
### 5.1 数据上报接口(复用现有)
**接口路径**: `POST /equipment/info/ingest/raw`
**请求示例**:
```
+YAV:1001,32768,16384,49152,8192,25.5,65.0,15,5000,100,3000,50,3,1000,2000,0,EEFF
```
**字段映射**:
1. 帧头: +YAV固定
2. id: 1001设备ID对应g_tDevParam.Address
3. 电流1原始值: 32768AI10-65535对应usSRegHoldBuf[0]
4. 电流2原始值: 16384AI20-65535对应usSRegHoldBuf[1]
5. 质量1原始值: 49152AI30-65535对应usSRegHoldBuf[2]
6. 质量2原始值: 8192AI40-65535对应usSRegHoldBuf[3]
7. 温度: 25.5°C保留1位小数
8. 湿度: 65.0%RH保留1位小数
9. DI状态复合: 15工作/停机/故障/清零对应usSRegHoldBuf[DI_REG]
10. 频率1: 5000Hz对应freq1
11. 计数1: 100对应num_count1
12. 频率2: 3000Hz对应freq2
13. 计数2: 50对应num_count2
14. 继电器+DO状态复合: 3供电/报警/软启动/停止对应usSRegHoldBuf[DO_REG]
15. 从机数据1: 1000对应usSRegHoldBuf[DATA_REG_1]
16. 从机数据2: 2000对应usSRegHoldBuf[DATA_REG_1+1]
17. 触摸屏: 0固定发送0
18. 帧尾: EEFF固定
### 5.2 设备配置接口(扩展现有)
**新增量程配置接口**: `PUT /equipment/info/device/range`
**请求参数**:
```json
{
"id": 1,
"current1_range": 100.0,
"current2_range": 50.0,
"quality1_range": 1000.0,
"quality2_range": 500.0,
"calibration_offset": 0.5,
"calibration_factor": 1.02
}
```
**响应**:
```json
{
"code": 200,
"msg": "量程配置成功"
}
```
### 5.3 设备创建接口(扩展现有)
**接口路径**: `POST /equipment/info/device`
**请求参数扩展**:
```json
{
"deviceNo": 1001,
"deviceName": "8Multi设备1",
"protocol_type": "8MULTI",
"current1_range": 100.0,
"current2_range": 50.0,
"quality1_range": 1000.0,
"quality2_range": 500.0,
"image_url": "/profile/upload/device.png",
"headers": {
"current1": "主电流",
"current2": "辅助电流",
"quality1": "主质量",
"quality2": "辅助质量",
"humidity": "环境湿度",
"frequency1": "主频率",
"frequency2": "辅助频率"
}
}
```
## 六、前端界面扩展
### 6.1 设备卡片展示
**8ADPRO设备卡片** (保持不变):
- 温度、电流、功率、状态
- 计数器1、计数器2
**8Multi设备卡片** (新增):
- 温度、湿度
- 电流1、电流2
- 质量1、质量2
- 工作/停机/故障状态指示灯
- 频率1、频率2
- 计数器1、计数器2
### 6.2 设备详情抽屉
**新增8Multi专属字段**:
- 电流1/电流2显示原始值和实际值
- 质量1/质量2显示原始值和实际值
- 湿度
- 工作状态、停机状态、故障状态、清零状态
- 频率1、频率2
- 继电器状态(供电、报警)
- DO状态软启动、停止
- 从机数据1、从机数据2
- 触摸屏数据
### 6.3 设备配置对话框
**新增配置项**:
1. **协议类型选择**: 8ADPRO / 8Multi
2. **量程配置** (仅8Multi显示):
- 电流1量程 (A)
- 电流2量程 (A)
- 质量1量程 (kg)
- 质量2量程 (kg)
3. **校准配置**:
- 校准偏移量
- 校准系数
## 七、实现步骤
### 7.1 数据库变更
1. ✅ 执行device表ALTER语句新增协议类型和量程字段
2. ✅ 执行device_data表ALTER语句新增8Multi专属字段
3. ✅ 修改device_field_header_config表枚举支持新字段
### 7.2 后端开发(已完成)
#### 7.2.1 实体类扩展
1.**MesDevice.java** - 添加17个8Multi字段
```java
// 协议类型、量程起点/终点、单位、计数器基准值、电压1/电压2
private String protocolType;
private BigDecimal current1RangeStart, current1RangeEnd;
private BigDecimal current2RangeStart, current2RangeEnd;
private BigDecimal quality1RangeStart, quality1RangeEnd;
private String quality1Unit, quality2Unit, currentUnit;
private Integer counter1Baseline, counter2Baseline;
private BigDecimal voltage1, voltage2;
// 辅助方法
public boolean is8Multi() { return "8MULTI".equals(this.protocolType); }
public boolean is8ADPRO() { return "8ADPRO".equals(this.protocolType) || this.protocolType == null; }
```
2. ✅ **DeviceData.java** - 添加29个8Multi字段
```java
// 电流/质量原始值和实际值、湿度、状态位、频率、计数器、继电器、DO、从机数据
private Integer current1Raw, current2Raw;
private BigDecimal current1Value, current2Value;
private Integer quality1Raw, quality2Raw;
private BigDecimal quality1Value, quality2Value;
private BigDecimal humidity;
private Integer statusWork, statusStop, statusFault, statusReset;
private Integer frequency1, frequency2;
private Integer counter1Current, counter1Delta, counter2Current, counter2Delta;
private Long counter1Total8multi, counter2Total8multi;
private Integer relayPower, relayAlarm, doSoftStart, doStop;
private Integer slaveData1, slaveData2, touchscreenData;
```
#### 7.2.2 Service层
3. ✅ **Multi8ProtocolService.java** - 8Multi协议解析服务
- `parse8MultiProtocol()` - 协议解析方法
- `convertRangeValue()` - 量程转换方法
- `resetCounter()` - 计数器清零方法
#### 7.2.3 Controller层
4. ✅ **Multi8Controller.java** - 8Multi设备控制器
- `POST /equipment/multi8/resetCounter` - 计数器清零
- `PUT /equipment/multi8/updateDeviceConfig` - 更新设备配置
- `GET /equipment/multi8/getDeviceDetail/{id}` - 获取设备详情
#### 7.2.4 Mapper层
5. ✅ **DeviceDataMapper.java** - 添加方法
```java
DeviceData selectLastByDeviceId(@Param("deviceId") Long deviceId);
```
6. ✅ **MesDeviceMapper.java** - 添加方法
```java
MesDevice selectByDeviceNo(@Param("deviceNo") Integer deviceNo);
```
### 7.3 前端开发(需手动实现)
**文件位置**`e:\Yavii_P3\MES\mes-ui\src\views\mes\equipment\info\index.vue`1178行
**修改原则**
⚠️ **在现有8ADPRO代码基础上扩展不删除任何8ADPRO功能**
⚠️ **通过`v-if`判断协议类型动态渲染不同UI**
⚠️ **所有8Multi字段都要做空值处理**
#### 7.3.1 设备卡片扩展
通过`v-if`判断协议类型动态渲染不同UI
```vue
<!-- 8ADPRO设备卡片保持不变 -->
<div v-if="!d.protocol_type || d.protocol_type === '8ADPRO'" class="device-info">
<!-- 原有字段 -->
</div>
<!-- 8Multi设备卡片新增 -->
<div v-else-if="d.protocol_type === '8MULTI'" class="device-info device-8multi">
<!-- 温度/湿度、电流1/电流2、质量1/质量2、功率1/功率2、状态 -->
</div>
```
#### 7.3.2 设备详情抽屉扩展
添加8Multi字段展示
- 温度、湿度
- 电流1/电流2、质量1/质量2
- 功率1/功率2计算显示
- 频率1/频率2
- 计数器1/计数器2含清零按钮
- 工作/停机/故障状态
- 继电器、DO状态
- 从机数据
#### 7.3.3 设备配置对话框扩展
根据`device_no > 200`动态显示8Multi配置项
- 电流1/电流2量程起点~终点)
- 质量1/质量2量程起点~终点+单位)
- 电流单位
- 电压1/电压2配置
#### 7.3.4 JavaScript方法扩展
```javascript
// 计算功率
calculatePower1(data) {
return data.voltage1 * data.current1_value
}
// 获取状态类型
getStatusType(data) {
if (data.status_fault) return 'danger' // 红色
if (data.status_stop) return 'warning' // 黄色
if (data.status_work) return 'success' // 绿色
}
// 计数器清零
resetCounter(counterNo) {
this.$http.post('/equipment/multi8/resetCounter', {...})
}
```
### 7.4 测试验证
1. 8ADPRO协议回归测试确保不受影响
2. 8Multi协议功能测试
3. 量程转换准确性测试
4. 校准功能测试
5. 混合设备场景测试
## 八、待确认事项
### 8.1 位运算解析规则
- [x] **DI状态字段**已确认U16格式取最后4位F然后取反DI1=工作DI2=停机DI3=故障DI4=清零
- [x] **继电器+DO字段**:已确认,直接读取不取反(下位机上传状态)
### 8.2 校准功能细节
- [x] **校准功能**:已确认不需要校准偏移量和校准系数
### 8.3 状态上传功能
- [x] **继电器+DO状态**:已确认为下位机上传的状态,不涉及下发控制功能
### 8.4 从机和触摸屏数据
- [x] **从机数据展示**已确认从机数据1/2直接展示原始值
- [x] **触摸屏数据**已确认固定发送0
### 8.5 协议格式细节
- [x] **设备ID映射关系**已确认device_no>200为8MULTI<=200为8ADPRO
- [x] **触摸屏固定值**已确认触摸屏字段固定发送0
- [x] **字段顺序确认**:已确认,协议字段顺序完全按照文档描述
### 8.6 量程和单位配置
- [x] **电流量程范围**已确认AI1/AI2电流范围为0-20A
- [x] **质量量程配置**已确认质量1/质量2AI3/AI4需要前端配置量程起点和终点
- [x] **量程转换公式**:已确认,实际值=(原始值/65535)*量程范围+量程起点
- [x] **量程必填**已确认8Multi设备创建时必须强制配置量程
- [x] **量程修改影响**:已确认,量程修改后不需要重新计算已存储的历史数据
- [x] **单位配置**:已确认,质量单位和电流单位由前端配置
### 8.7 计数器处理逻辑
- [x] **计数器数据类型**已确认下位机传的计数1和计数2是累计值
- [x] **计数器处理方式**:已确认,需要做减运算(当前值-上次值),存储累计值和增量值
- [x] **计数器清零**:已确认,前端提供清零按钮,清零后设置基准值,增量=当前值-基准值
- [x] **频率显示**已确认频率1和频率2显示原始值
### 8.8 数据上报和存储
- [x] **上报间隔**已确认8Multi设备上报频率为10秒
- [x] **数据去重**:已确认,短时间内收到相同数据全部存储
- [x] **离线缓存**:已确认,不需要关注离线缓存补发,由下位机处理
### 8.9 设备状态判断
- [x] **运行判断依据**已确认电流1实际值>=2A **且** 电流2实际值>=2A与运算
- [x] **功率计算规则**已确认需要计算功率前端配置电压1和电压2功率1=电压1*电流1功率2=电压2*电流2分别计算
- [x] **状态指示灯颜色**:已确认,工作=绿色,停机=黄色,故障=红色,报警=红色
### 8.10 前端展示规范
- [x] **原始值显示**:已确认,前端只显示实际值,不显示原始值
- [x] **历史数据图表**:已确认,先不做历史数据图表
### 8.11 数据有效性校验
- [x] **数据校验**:已确认,不需要数据有效性校验
### 8.12 权限和安全
- [x] **数据加密传输**:已确认,设备上报的数据不需要加密传输
### 8.13 兼容性和迁移
- [x] **协议切换**已确认同一设备不能在8ADPRO和8Multi之间切换协议
- [x] **数据迁移工具**:已确认,不需要提供数据迁移工具
- [x] **8ADPRO兼容性**已确认千万不要影响8ADPRO的功能
### 待确认事项汇总
**已确认事项**共34项
- ✅ 所有核心功能已确认
- ✅ 协议解析规则已明确
- ✅ 数据库设计已完成
- ✅ 量程配置规则已确定
- ✅ 计数器处理逻辑已明确
- ✅ 兼容性要求已明确
- ✅ 功率计算规则已明确(分别计算)
- ✅ 前端展示规范已明确(只显示实际值)
- ✅ 数据安全要求已明确(不需要加密)
- ✅ 离线缓存策略已明确(不需要关注)
**待确认事项**共0项
- 🎉 所有需求已确认完毕!
**核心要求**
- ⚠️ **千万不要影响8ADPRO的功能**
- ⚠️ **device_no>200为8MULTI<=200为8ADPRO**
- ⚠️ **同一设备不能在两种协议之间切换**
## 九、8ADPRO设备相关文件清单
**说明**以下仅列出与8ADPRO设备数据接收、解析、存储、展示相关的核心文件不包括其他IoT功能如点检、维修、车间设备等
### 9.1 后端文件Java
#### 9.1.1 Controller层
```
e:\Yavii_P3\MES\yjh-mes\src\main\java\cn\sourceplan\equipment\controller\
└── EquipmentInfoController.java # 设备信息控制器(核心:数据接收、动态表头、清零)
- ingestRawData() # 数据接收接口
- getDynamicHeaders() # 动态表头接口
- getDeviceDataPage() # 设备数据查询接口
- resetCounter() # 计数器清零接口
```
#### 9.1.2 Service层
```
e:\Yavii_P3\MES\yjh-mes\src\main\java\cn\sourceplan\equipment\service\
├── IEquipmentInfoService.java # 设备信息服务接口
└── impl\
└── EquipmentInfoServiceImpl.java # 设备信息服务实现(核心:协议解析、数据存储)
- ingestFrame() # 协议解析方法需扩展支持8Multi
- parseProtocolData() # 数据解析逻辑
- saveDeviceData() # 数据存储逻辑
- updateCounter() # 计数器累加逻辑
- mergeDynamicHeaders() # 动态表头合并逻辑
```
#### 9.1.3 Domain层实体类
```
e:\Yavii_P3\MES\yjh-mes\src\main\java\cn\sourceplan\equipment\domain\
├── MesDevice.java # 设备主表实体需添加8Multi协议字段
├── DeviceData.java # 设备数据实体需添加8Multi数据字段
├── DeviceLatest.java # 设备最新数据实体
├── DeviceLatestView.java # 设备最新数据视图实体
└── DeviceFieldHeaderConfig.java # 设备字段表头配置实体
```
#### 9.1.4 Mapper层
```
e:\Yavii_P3\MES\yjh-mes\src\main\java\cn\sourceplan\equipment\mapper\
├── MesDeviceMapper.java # 设备主表Mapper
├── DeviceDataMapper.java # 设备数据Mapper
├── DeviceLatestMapper.java # 设备最新数据Mapper
├── DeviceLatestViewMapper.java # 设备最新数据视图Mapper
├── DeviceLatestJoinMapper.java # 设备最新数据关联Mapper
└── DeviceFieldHeaderConfigMapper.java # 设备字段表头配置Mapper
```
#### 9.1.5 Mapper XML文件
```
e:\Yavii_P3\MES\yjh-mes\src\main\resources\mapper\equipment\
└── (对应Mapper的XML文件需要添加8Multi字段的SQL映射)
```
### 9.2 前端文件Vue
```
e:\Yavii_P3\MES\mes-ui\src\views\mes\equipment\info\
└── index.vue # 设备信息页面(核心:实时数据监控、动态表头、清零)
- 设备卡片展示需扩展8Multi设备卡片
- 设备详情抽屉需添加8Multi字段
- 设备配置对话框(需添加量程、单位、电压配置)
- 动态表头渲染
- 实时数据刷新
- 计数器清零按钮
- 功率计算显示
```
### 9.3 核心文件修改要点
**8Multi接入需要修改的5个核心文件**
1. **EquipmentInfoController.java**
- 数据接收接口保持不变
- 可能需要添加设备配置更新接口(量程、单位、电压)
2. **EquipmentInfoServiceImpl.java**
- `ingestFrame()`方法添加协议类型判断device_no>200为8Multi
- 新增8Multi协议解析分支
- 实现量程转换逻辑
- 实现计数器减运算逻辑
- 实现功率计算逻辑
3. **MesDevice.java**
- 添加17个新字段协议类型、量程起点/终点、单位、计数器基准值、电压1/电压2
4. **DeviceData.java**
- 添加29个新字段8Multi协议数据字段含counter1_total_8multi/counter2_total_8multi
5. **info/index.vue**
- 根据协议类型渲染不同的设备卡片
- 设备详情抽屉支持8Multi字段展示
- 设备配置对话框添加量程、单位、电压1/电压2配置
- 功率计算显示功率1=电压1*电流1功率2=电压2*电流2
### 9.4 数据库表
**核心表**
- `device`设备主表新增17个字段
- `device_data`设备数据表新增29个字段含8Multi专用计数器总计字段
- `device_latest`:设备最新数据表(视图或实体表)
- `device_field_header_config`:设备字段表头配置表
## 十、兼容性保证
### 10.1 数据库兼容
- 所有新增字段均为可空或有默认值
- 原有8ADPRO设备的protocol_type默认为'8ADPRO'
- 原有字段不做任何修改
### 10.2 代码兼容
- 通过protocol_type字段区分处理逻辑
- 8ADPRO协议解析逻辑完全保留
- 新增8Multi协议解析分支
### 10.3 前端兼容
- 根据设备协议类型动态渲染UI
- 8ADPRO设备展示保持不变
- 新增8Multi设备专属UI组件
## 十一、附录
### 11.1 8Multi协议字段详细对照表
| 序号 | 字段名 | 描述 | 数据类型 | 对应C变量 | 转换规则 |
|------|--------|------|---------|-----------|----------|
| 1 | +YAV: | 帧头 | String | 固定 | 固定发送+YAV: |
| 2 | id | 设备ID | int | g_tDevParam.Address | 设备唯一标识 |
| 3 | 电流1 | 模拟输入AI1 | int(0-65535) | usSRegHoldBuf[0] | 范围0-20A<br>实际值=(原始值/65535)*量程范围+量程起点<br>实际值>=2A为设备开启 |
| 4 | 电流2 | 模拟输入AI2 | int(0-65535) | usSRegHoldBuf[1] | 范围0-20A<br>实际值=(原始值/65535)*量程范围+量程起点 |
| 5 | 质量1 | 模拟输入AI3 | int(0-65535) | usSRegHoldBuf[2] | 实际值=(原始值/65535)*量程范围+量程起点<br>前端配置量程 |
| 6 | 质量2 | 模拟输入AI4 | int(0-65535) | usSRegHoldBuf[3] | 实际值=(原始值/65535)*量程范围+量程起点<br>前端配置量程 |
| 7 | 温度 | 温湿度传感器温度 | String | temp | 保留1位小数 |
| 8 | 湿度 | 温湿度传感器湿度 | String | dht | 保留1位小数 |
| 9 | DI状态 | 工作/停机/故障/清零 | int | usSRegHoldBuf[DI_REG] | U16格式取最后4位F然后取反<br>DI1=工作DI2=停机DI3=故障DI4=清零 |
| 10 | 频率1 | 测频器1 | String | freq1 | 实际值 |
| 11 | 计数1 | 计数器1 | int | num_count1 | 下位机传累计值 |
| 12 | 频率2 | 测频器2 | String | freq2 | 实际值 |
| 13 | 计数2 | 计数器2 | int | num_count2 | 下位机传累计值 |
| 14 | 继电器+DO | 供电/报警/软启动/停止 | int | usSRegHoldBuf[DO_REG] | 直接读取,不取反<br>下发格式: DO=0_10为通道号1为值 |
| 15 | 从机数据1 | 485从机数据1 | int | usSRegHoldBuf[DATA_REG_1] | 实际值 |
| 16 | 从机数据2 | 485从机数据2 | int | usSRegHoldBuf[DATA_REG_1+1] | 实际值 |
| 17 | 触摸屏 | 触摸屏数据 | int | 固定 | 固定发送0 |
| 18 | EEFF | 帧尾 | String | 固定 | 固定发送EEFF |
### 11.2 量程配置示例
| 设备类型 | 电流1量程 | 电流2量程 | 质量1量程 | 质量2量程 |
|---------|----------|----------|----------|----------|
| 小型设备 | 50A | 30A | 500kg | 200kg |
| 中型设备 | 100A | 80A | 1000kg | 500kg |
| 大型设备 | 200A | 150A | 2000kg | 1000kg |
---
**文档版本**: v2.1
**创建日期**: 2025-11-15
**创建人**: 周启威
**最后更新**: 2025-11-15
**更新内容**:
- v1.1: 补充待确认事项8.5-8.13,新增优先级分类
- v1.2: 根据协议详细表更新字段对照表明确C变量对应关系更新已确认事项
- v1.3: 重大更新
- 修改数据库设计:量程字段拆分为起点和终点(支持非零起点)
- 更新量程转换公式:实际值=(原始值/65535)*量程范围+量程起点
- 明确DI状态解析U16格式取最后4位F然后取反
- 明确继电器+DO解析直接读取不取反下发格式DO=通道号_值
- 明确设备开启判断电流1实际值>=2A
- 明确计数器类型:下位机传累计值
- 更新协议字段对照表,添加详细转换规则
- v2.0: 完整需求确认版本30项已确认
- 移除校准功能:不需要校准偏移量和校准系数
- 添加单位配置:质量单位和电流单位前端配置
- 协议判断规则device_no>200为8MULTI<=200为8ADPRO
- 设备状态判断电流1>=2A且电流2>=2A与运算
- 计数器处理:减运算+清零功能(存储累计值和增量值)
- 频率显示:显示原始值
- 从机数据:直接展示原始值
- 数据上报10秒间隔相同数据全部存储
- 权限管理:量程配置和下发控制需要权限
- 状态指示灯:工作=绿,停机=黄,故障=红,报警=红
- 兼容性不能切换协议不影响8ADPRO功能
- 新增计数器基准值字段和单位字段
- v2.1: 功能调整
- 移除下发控制功能继电器和DO字段改为下位机上传状态不涉及下发控制
- 移除权限管理相关需求
- 新增8ADPRO现有文件清单章节第九章
- 列出所有后端Java文件Controller、Service、Domain、Mapper、XML
- 列出所有前端Vue文件
- 标注核心文件和修改要点
- 新增功率计算功能前端配置电压1和电压2功率1=电压1*电流1功率2=电压2*电流2分别计算
- device表新增voltage1和voltage2字段共17个新字段
- 精简文件清单只列出8ADPRO设备相关文件不包括其他IoT功能
- 确认所有待确认事项:离线缓存、原始值显示、数据加密传输
- 🎉 所有34项需求已确认完毕可以开始开发
- v2.2: 代码实现完成
- ✅ 完成所有后端代码实体类、Service、Controller、Mapper
- ✅ 添加8Multi协议解析服务
- ✅ 添加设备控制器接口
- ✅ 扩展Mapper查询方法
- 📝 前端代码待实现(已提供详细说明)
## 十三、代码文件清单
### 后端文件
#### 1. 实体类2个已完成
- ✅ `MesDevice.java` - 添加17个8Multi字段
- ✅ `DeviceData.java` - 添加29个8Multi字段
#### 2. Service层1个新建 + 1个需集成
- ✅ `Multi8ProtocolService.java` - 8Multi协议解析服务新建
- ⚠️ `EquipmentInfoServiceImpl.java` - 需要集成8Multi协议判断
- 参考文档:`后端集成说明_EquipmentInfoServiceImpl.md`
- 修改点:
1. 注入Multi8ProtocolService
2. 在ingestFrame方法开头添加协议判断
3. deviceNo > 200 调用8Multi解析
#### 3. Controller层1个新建
- ✅ `Multi8Controller.java` - 8Multi设备控制器新建
#### 4. Mapper层2个已扩展
- ✅ `DeviceDataMapper.java` - 添加`selectLastByDeviceId()`方法
- ✅ `MesDeviceMapper.java` - 添加`selectByDeviceNo()`方法
#### 5. Mapper XML
- ✅ 不需要XML文件使用MyBatis-Plus注解方式
### 前端文件(待实现)
#### 1. 设备信息页面1个扩展
- `e:\Yavii_P3\MES\mes-ui\src\views\mes\equipment\info\index.vue`
- 扩展设备卡片(协议类型判断)
- 扩展详情抽屉8Multi字段展示
- 扩展配置对话框(量程、单位、电压配置)
- 添加JavaScript方法功率计算、状态判断、计数器清零
### 数据库文件
#### 1. SQL脚本1个
- `e:\Yavii_P3\MES\.tasks\2025-11-15_01_周启威_8Multi接入.sql`
- device表新增17个字段
- device_data表新增29个字段
- 不修改触发器(使用独立字段)
## 十四、后续工作
### 待完成
1. 前端代码实现参考第7.3节)
2. 集成测试
3. 8ADPRO回归测试
### 注意事项
⚠️ **千万不要影响8ADPRO的功能**
⚠️ **所有修改都要通过协议类型判断**
⚠️ **前端要在现有代码基础上扩展不要删除任何8ADPRO代码**