Files
lingniu-vehicle-ingest/vehicle-data-platform/apps/api/internal/platform/gb32960_reference.go

228 lines
15 KiB
Go
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.
package platform
import (
"encoding/json"
"fmt"
"strconv"
"strings"
)
// gb32960FieldReference is the platform copy of the authoritative Chinese
// terminology supplied for GB/T 32960 and the Guangdong fuel-cell extension.
// It enriches protocol values at read time without changing the stored RAW
// evidence or replacing the parser's stable source-field keys.
type gb32960FieldReference struct {
Label string
Unit string
Description string
ValueMappings []MetricValueMapping
}
func enumMappings(values ...string) []MetricValueMapping {
result := make([]MetricValueMapping, 0, len(values)/3)
for index := 0; index+2 < len(values); index += 3 {
result = append(result, MetricValueMapping{Value: values[index], Label: values[index+1], Description: values[index+2]})
}
return result
}
var gb32960PositionMappings = func() []MetricValueMapping {
result := make([]MetricValueMapping, 0, 8)
for value := 0; value < 8; value++ {
parts := []string{"有效定位", "北纬", "东经"}
if value&1 != 0 {
parts[0] = "无效定位"
}
if value&2 != 0 {
parts[1] = "南纬"
}
if value&4 != 0 {
parts[2] = "西经"
}
result = append(result, MetricValueMapping{
Value: strconv.Itoa(value),
Label: strings.Join(parts, " · "),
Description: "bit0 表示定位有效性bit1 表示纬度方向bit2 表示经度方向。",
})
}
return result
}()
var gb32960FieldReferences = map[string]gb32960FieldReference{
"gb32960.vehicle.vehicle_status": {Label: "车辆状态", Description: "车辆运行、停止等状态编码。", ValueMappings: enumMappings("1", "启动", "车辆处于可行驶启动状态。", "2", "熄火", "车辆处于熄火状态。", "3", "其他", "车辆处于其他状态。", "254", "异常", "协议异常值。", "255", "无效", "协议无效值。")},
"gb32960.vehicle.charge_status": {Label: "充电状态", Description: "车辆充电状态编码。", ValueMappings: enumMappings("1", "停车充电", "车辆停车充电。", "2", "行驶充电", "车辆行驶充电。", "3", "未充电", "车辆未充电。", "4", "充电完成", "车辆充电完成。", "254", "异常", "协议异常值。", "255", "无效", "协议无效值。")},
"gb32960.vehicle.running_mode": {Label: "运行模式", Description: "纯电、混合动力、燃料电池等运行模式编码。", ValueMappings: enumMappings("1", "纯电", "纯电驱动模式。", "2", "混合动力", "混合动力驱动模式。", "3", "燃料电池", "燃料电池驱动模式。", "254", "异常", "协议异常值。", "255", "无效", "协议无效值。")},
"gb32960.vehicle.speed_kmh": {Label: "车速", Unit: "km/h", Description: "车辆当前速度。"},
"gb32960.vehicle.total_mileage_km": {Label: "累计里程", Unit: "km", Description: "车辆累计行驶里程。"},
"gb32960.vehicle.total_voltage_v": {Label: "总电压", Unit: "V", Description: "动力系统总电压。"},
"gb32960.vehicle.total_current_a": {Label: "总电流", Unit: "A", Description: "动力系统总电流。"},
"gb32960.vehicle.soc_percent": {Label: "SOC", Unit: "%", Description: "动力电池荷电状态。"},
"gb32960.vehicle.dc_dc_status": {Label: "DC/DC 状态", Description: "DC/DC 工作状态编码。", ValueMappings: enumMappings("1", "工作", "DC/DC 处于工作状态。", "2", "断开", "DC/DC 处于断开状态。", "254", "异常", "协议异常值。", "255", "无效", "协议无效值。")},
"gb32960.vehicle.gear": {Label: "挡位原始值", Description: "挡位、驱动力和制动力组合原始编码。"},
"gb32960.vehicle.insulation_kohm": {Label: "绝缘电阻", Unit: "kΩ", Description: "高压系统绝缘电阻。"},
"gb32960.vehicle.accelerator_pct": {Label: "加速踏板行程", Unit: "%", Description: "2016 版字段,加速踏板开度。"},
"gb32960.vehicle.brake_pct": {Label: "制动踏板状态", Unit: "%", Description: "2016 版字段,制动踏板状态或开度。"},
"gb32960.drive_motor.serial_no": {Label: "驱动电机序号", Description: "电机编号。"},
"gb32960.drive_motor.state": {Label: "驱动电机状态", Description: "电机工作状态编码。", ValueMappings: enumMappings("1", "耗电", "驱动电机耗电。", "2", "发电", "驱动电机发电。", "3", "关闭", "驱动电机关闭。", "4", "准备", "驱动电机准备。", "254", "异常", "协议异常值。", "255", "无效", "协议无效值。")},
"gb32960.drive_motor.controller_temperature_c": {Label: "控制器温度", Unit: "℃", Description: "驱动电机控制器温度。"},
"gb32960.drive_motor.speed_rpm": {Label: "转速", Unit: "rpm", Description: "驱动电机转速。"},
"gb32960.drive_motor.torque_nm": {Label: "转矩", Unit: "N·m", Description: "驱动电机输出转矩。"},
"gb32960.drive_motor.motor_temperature_c": {Label: "电机温度", Unit: "℃", Description: "驱动电机温度。"},
"gb32960.drive_motor.controller_voltage_v": {Label: "控制器输入电压", Unit: "V", Description: "电机控制器直流母线输入电压。"},
"gb32960.drive_motor.controller_current_a": {Label: "控制器直流母线电流", Unit: "A", Description: "电机控制器直流母线电流。"},
"gb32960.fuel_cell.fuel_cell_voltage_v": {Label: "燃料电池电压", Unit: "V", Description: "燃料电池系统输出电压。"},
"gb32960.fuel_cell.fuel_cell_current_a": {Label: "燃料电池电流", Unit: "A", Description: "燃料电池系统输出电流。"},
"gb32960.fuel_cell.hydrogen_consumption_kg_per_100km": {Label: "氢耗", Unit: "kg/100km", Description: "燃料电池氢气消耗率。"},
"gb32960.fuel_cell.temperature_probe_values_c": {Label: "探针温度", Unit: "℃", Description: "燃料电池温度探针列表。"},
"gb32960.fuel_cell.max_hydrogen_temperature_c": {Label: "氢系统最高温度", Unit: "℃", Description: "氢系统最高温度。"},
"gb32960.fuel_cell.max_hydrogen_concentration_percent": {Label: "最高氢浓度", Unit: "%", Description: "氢气浓度最高值。"},
"gb32960.fuel_cell.max_hydrogen_pressure_mpa": {Label: "最高氢压力", Unit: "MPa", Description: "氢系统最高压力。"},
"gb32960.fuel_cell.dc_dc_status": {Label: "高压 DC/DC 状态", Description: "燃料电池高压 DC/DC 状态。"},
"gb32960.fuel_cell.max_hydrogen_temperature_probe_id": {Label: "最高氢温探针编号", Description: "检测到氢系统最高温度的探针编号。"},
"gb32960.fuel_cell.max_hydrogen_concentration_probe_id": {Label: "最高氢浓度探针编号", Description: "检测到最高氢浓度的探针编号。"},
"gb32960.fuel_cell.max_hydrogen_pressure_probe_id": {Label: "最高氢压探针编号", Description: "检测到最高氢压力的探针编号。"},
"gb32960.position.position_status": {Label: "定位状态标志", Description: "定位有效性及经纬度方向标志。", ValueMappings: gb32960PositionMappings},
"gb32960.position.coordinate_system": {Label: "坐标系", Description: "2025 版新增坐标系编码。", ValueMappings: enumMappings("1", "WGS84", "WGS84 坐标系。", "2", "GCJ-02", "GCJ-02 坐标系。", "3", "其他", "其他坐标系。")},
"gb32960.position.longitude": {Label: "经度", Unit: "°", Description: "车辆经度。"},
"gb32960.position.latitude": {Label: "纬度", Unit: "°", Description: "车辆纬度。"},
"gb32960.alarm.max_alarm_level": {Label: "最高报警等级", Description: "当前最高报警等级。", ValueMappings: enumMappings("0", "无故障", "当前无报警故障。", "1", "一级故障", "一级报警故障。", "2", "二级故障", "二级报警故障。", "3", "三级故障", "三级报警故障。")},
"gb32960.alarm.general_alarm_flag": {Label: "通用报警标志", Description: "通用报警位图。"},
"gb32960.alarm.battery_faults": {Label: "可充电储能装置故障码", Description: "动力电池相关故障码列表。"},
"gb32960.alarm.motor_faults": {Label: "驱动电机故障码", Description: "驱动电机相关故障码列表。"},
"gb32960.alarm.engine_faults": {Label: "发动机故障码", Description: "发动机相关故障码列表。"},
"gb32960.alarm.other_faults": {Label: "其他故障码", Description: "其他故障码列表。"},
"gb32960.gd_fc_stack.stack_count": {Label: "电堆数量", Description: "本包包含的电堆数量。"},
"gb32960.gd_fc_stack.engine_work_state": {Label: "发动机工作状态", Description: "燃料电池发动机工作状态。"},
"gb32960.gd_fc_stack.stack_water_outlet_temp_c": {Label: "电堆出水温度", Unit: "℃", Description: "电堆冷却水出口温度。"},
"gb32960.gd_fc_stack.hydrogen_inlet_pressure_kpa": {Label: "氢气入口压力", Unit: "kPa", Description: "电堆氢气入口压力。"},
"gb32960.gd_fc_stack.air_inlet_pressure_kpa": {Label: "空气入口压力", Unit: "kPa", Description: "电堆空气入口压力。"},
"gb32960.gd_fc_stack.air_inlet_temp_c": {Label: "空气入口温度", Unit: "℃", Description: "电堆空气入口温度。"},
"gb32960.gd_fc_stack.max_cell_voltage_v": {Label: "单体最高电压", Unit: "V", Description: "本电堆单体最高电压。"},
"gb32960.gd_fc_stack.min_cell_voltage_v": {Label: "单体最低电压", Unit: "V", Description: "本电堆单体最低电压。"},
"gb32960.gd_fc_stack.avg_cell_voltage_v": {Label: "单体平均电压", Unit: "V", Description: "本电堆单体平均电压。"},
"gb32960.gd_fc_stack.cell_count": {Label: "单体总数", Description: "电堆单体总数量。"},
"gb32960.gd_fc_stack.frame_cell_start": {Label: "本帧单体起始序号", Description: "当前分段电压起始单体序号。"},
"gb32960.gd_fc_stack.frame_cell_count": {Label: "本帧单体数量", Description: "当前分段包含的单体数量。"},
"gb32960.gd_fc_stack.frame_cell_voltages_v": {Label: "本帧单体电压列表", Unit: "V", Description: "当前分段的单体电压数组;未跨帧合并时不代表完整电堆快照。"},
"gb32960.gd_fc_dcdc.input_voltage_v": {Label: "输入电压", Unit: "V", Description: "DC/DC 输入电压。"},
"gb32960.gd_fc_dcdc.input_current_a": {Label: "输入电流", Unit: "A", Description: "DC/DC 输入电流。"},
"gb32960.gd_fc_dcdc.output_voltage_v": {Label: "输出电压", Unit: "V", Description: "DC/DC 输出电压。"},
"gb32960.gd_fc_dcdc.output_current_a": {Label: "输出电流", Unit: "A", Description: "DC/DC 输出电流。"},
"gb32960.gd_fc_dcdc.controller_temp_c": {Label: "控制器温度", Unit: "℃", Description: "DC/DC 控制器温度。"},
"gb32960.gd_fc_air_conditioner.status": {Label: "空调状态", Description: "空调工作状态。", ValueMappings: enumMappings("0", "关闭", "空调关闭。", "1", "启动", "空调启动。", "254", "异常", "协议异常值。", "255", "无效", "协议无效值。")},
"gb32960.gd_fc_air_conditioner.power_kw": {Label: "空调功率", Unit: "kW", Description: "空调消耗功率。"},
"gb32960.gd_fc_air_conditioner.compressor_input_voltage_v": {Label: "压缩机输入电压", Unit: "V", Description: "空调压缩机输入电压。"},
"gb32960.gd_fc_vehicle_info.collision_alarm": {Label: "碰撞报警", Description: "碰撞报警状态。", ValueMappings: enumMappings("0", "无碰撞报警", "当前无碰撞报警。", "1", "有碰撞报警", "当前有碰撞报警。", "254", "异常", "协议异常值。", "255", "无效", "协议无效值。")},
"gb32960.gd_fc_vehicle_info.ambient_temp_c": {Label: "环境温度", Unit: "℃", Description: "车辆环境温度。"},
"gb32960.gd_fc_vehicle_info.ambient_pressure_kpa": {Label: "环境压力", Unit: "kPa", Description: "车辆环境压力。"},
"gb32960.gd_fc_vehicle_info.hydrogen_mass_kg": {Label: "车载氢量", Unit: "kg", Description: "当前车载氢气质量。"},
}
func canonicalGB32960ReferenceKey(sourceField string) string {
sourceField = strings.ToLower(strings.TrimSpace(sourceField))
if !strings.HasPrefix(sourceField, "gb32960.") {
return sourceField
}
if strings.HasPrefix(sourceField, "gb32960.drive_motor.") {
return "gb32960.drive_motor." + lastSourcePart(sourceField)
}
if strings.HasPrefix(sourceField, "gb32960.gd_fc_stack.") {
return "gb32960.gd_fc_stack." + lastSourcePart(sourceField)
}
return sourceField
}
func lastSourcePart(sourceField string) string {
if index := strings.LastIndexByte(sourceField, '.'); index >= 0 && index+1 < len(sourceField) {
return sourceField[index+1:]
}
return sourceField
}
func gb32960ReferenceForSource(sourceField string) (gb32960FieldReference, bool) {
reference, ok := gb32960FieldReferences[canonicalGB32960ReferenceKey(sourceField)]
if !ok {
return gb32960FieldReference{}, false
}
reference.ValueMappings = append([]MetricValueMapping(nil), reference.ValueMappings...)
return reference, true
}
func protocolDisplayValue(sourceField string, value any) string {
reference, ok := gb32960ReferenceForSource(sourceField)
if !ok || len(reference.ValueMappings) == 0 || value == nil {
return ""
}
raw := metricMappingValue(value)
for _, mapping := range reference.ValueMappings {
if mapping.Value == raw {
return fmt.Sprintf("%s%s", mapping.Label, raw)
}
}
return fmt.Sprintf("未知状态(%s", raw)
}
func metricMappingValue(value any) string {
switch typed := value.(type) {
case json.Number:
return typed.String()
case float64:
if typed == float64(int64(typed)) {
return strconv.FormatInt(int64(typed), 10)
}
return strconv.FormatFloat(typed, 'f', -1, 64)
case float32:
return strconv.FormatFloat(float64(typed), 'f', -1, 32)
case int:
return strconv.Itoa(typed)
case int8:
return strconv.FormatInt(int64(typed), 10)
case int16:
return strconv.FormatInt(int64(typed), 10)
case int32:
return strconv.FormatInt(int64(typed), 10)
case int64:
return strconv.FormatInt(typed, 10)
case uint:
return strconv.FormatUint(uint64(typed), 10)
case uint8:
return strconv.FormatUint(uint64(typed), 10)
case uint16:
return strconv.FormatUint(uint64(typed), 10)
case uint32:
return strconv.FormatUint(uint64(typed), 10)
case uint64:
return strconv.FormatUint(typed, 10)
default:
return strings.TrimSpace(fmt.Sprint(value))
}
}
func enrichMetricDefinitions(definitions []MetricDefinition) []MetricDefinition {
result := make([]MetricDefinition, len(definitions))
copy(result, definitions)
for index := range result {
definition := &result[index]
sourceField := definition.SourceFields["GB32960"]
reference, ok := gb32960ReferenceForSource(sourceField)
if !ok {
continue
}
if len(definition.Protocols) == 1 && strings.EqualFold(definition.Protocols[0], "GB32960") {
definition.Label = reference.Label
definition.Description = reference.Description
definition.Unit = reference.Unit
}
definition.ValueMappings = reference.ValueMappings
}
return result
}