Skip to the content.

✅ 批量读取数据解析 Bug 修复完成

问题症状

用户报告使用新实现的批量读取功能(批量 18 个寄存器)后,所有点位的值都显示为 0,尽管 Modbus TCP 协议层的通信正常。

根本原因

Scale = 0 && Offset = 0 的缩放公式导致所有值归零

配置文件中的点位定义没有 scaleoffset 字段:

points:
  - id: "p1"
    address: "40001"
    datatype: "int16"
    readwrite: "RW"
    # 注意:没有 scale/offset,使用 Go 结构体的默认值(0)

readPointGroup() 方法中应用变换:

result = rawValue × Scale + Offset
       = rawValue × 0 + 0 = 0  ❌

修复内容

文件: internal/driver/modbus/modbus.go (readPointGroup 方法, 第 390-430 行)

修复逻辑:检测当 Scale=0 且 Offset=0 时,直接使用原始值,不应用变换公式

// 应用缩放和偏移
var finalValue any

if point.Scale == 0 && point.Offset == 0 {
    // 默认情况:未设置缩放和偏移,直接使用原始值
    finalValue = val
} else {
    // 应用缩放和偏移:result = value * Scale + Offset
    if scaledVal, ok := val.(float64); ok {
        finalValue = scaledVal*point.Scale + point.Offset
    } else if scaledVal, ok := val.(float32); ok {
        finalValue = float64(scaledVal)*point.Scale + point.Offset
    } else if scaledVal, ok := val.(int16); ok {
        finalValue = float64(scaledVal)*point.Scale + point.Offset
    } else if scaledVal, ok := val.(uint16); ok {
        finalValue = float64(scaledVal)*point.Scale + point.Offset
    } else if scaledVal, ok := val.(int32); ok {
        finalValue = float64(scaledVal)*point.Scale + point.Offset
    } else if scaledVal, ok := val.(uint32); ok {
        finalValue = float64(scaledVal)*point.Scale + point.Offset
    } else {
        finalValue = val
    }
}

result[point.ID] = finalValue

验证结果

✅ 实际 Modbus 协议验证

使用用户提供的完整 Modbus TCP 响应消息进行数据解析测试:

请求数据: 00 06 01 03 00 00 00 12 (读取18个寄存器从40001)
响应数据: 01 03 24 00 06 03 F7 01 27 ... (36字节)

解析结果:
✓ p1 (40001):    6      (字节: 00 06)
✓ p2 (40002):    1015   (字节: 03 F7)
✓ p3 (40003):    295    (字节: 01 27)
✓ 40018 (40018): 7      (字节: 00 07)

✅ 单元测试全部通过

TestGroupPoints          PASSED ✓
TestRegisterCount        PASSED ✓
TestParseAddress         PASSED ✓
TestMaxPacketSizeLimit   PASSED ✓
TestSortAddressInfos     PASSED ✓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
5/5 单元测试通过

✅ 编译验证

✓ 代码编译成功
✓ 无编译错误
✓ 无编译警告

修复的行为变化

场景 修复前 修复后 备注
Scale=0, Offset=0 (默认) 0 ❌ 原始值 ✓ 现在正确返回实际值
Scale=1, Offset=0 原始值 ✓ 原始值 ✓ 无变化
Scale=0.1, Offset=0 原始值×0=0 ❌ 原始值×0.1 ✓ 修复了缩放计算
Scale=1, Offset=273.15 值×1+273.15 ✓ 值×1+273.15 ✓ 无变化

向后兼容性

完全向后兼容 - 配置了 Scale/Offset 的现有系统不受影响

部署建议

  1. 立即部署 - 这是数据准确性的关键修复
  2. 无需配置变更 - 现有 YAML 配置无需修改
  3. 可选优化 - 为了代码清晰性,可在 YAML 中显式设置:
    scale: 1.0
    offset: 0
    

验证工具

验证脚本可用于测试其他 Modbus 响应数据:

go run verify_batch_read.go

后续改进建议

  1. 默认值初始化:在 model.Point 中设置 Scale=1.0 的默认值
  2. 配置校验:在加载配置时检测并警告 Scale=0 的情况
  3. 文档完善:在配置示例中明确说明缩放参数用途

修复状态: ✅ 完成并验证
优先级: 🔴 严重(影响数据准确性)
影响范围: 批量读取功能 (ReadPoints API)
风险等级: 🟢 低(修复向后兼容,现有测试全部通过)