Files
lingniu-vehicle-ingest/go/vehicle-gateway/internal/telemetry/mileage.go

90 lines
2.2 KiB
Go

package telemetry
import (
"encoding/json"
"strconv"
"strings"
"lingniu-vehicle-ingest/go/vehicle-gateway/internal/envelope"
)
type MileageFieldMapping struct {
Key string
Scale float64
}
// MileageFieldMappings is the single protocol-to-unit contract used by every
// projection that exposes or calculates total mileage.
func MileageFieldMappings(protocol envelope.Protocol) []MileageFieldMapping {
switch protocol {
case envelope.ProtocolGB32960:
return []MileageFieldMapping{{Key: "gb32960.vehicle.total_mileage_km", Scale: 1}}
case envelope.ProtocolJT808:
return []MileageFieldMapping{{Key: "jt808.location.total_mileage_km", Scale: 1}}
case envelope.ProtocolYutongMQTT:
return []MileageFieldMapping{
{Key: "yutong_mqtt.data.total_mileage_km", Scale: 1},
{Key: "yutong_mqtt.root.data.total_mileage_km", Scale: 1},
{Key: "yutong_mqtt.data.total_mileage", Scale: 0.001},
{Key: "yutong_mqtt.root.data.total_mileage", Scale: 0.001},
}
default:
return nil
}
}
func TotalMileageKM(protocol envelope.Protocol, fields map[string]any) (float64, bool) {
for _, mapping := range MileageFieldMappings(protocol) {
value, ok := Number(fields, mapping.Key)
if !ok {
continue
}
return value * mapping.Scale, true
}
return 0, false
}
func Number(fields map[string]any, key string) (float64, bool) {
if len(fields) == 0 {
return 0, false
}
value, ok := fields[key]
if !ok || value == nil {
return 0, false
}
switch typed := value.(type) {
case float64:
return typed, true
case float32:
return float64(typed), true
case int:
return float64(typed), true
case int8:
return float64(typed), true
case int16:
return float64(typed), true
case int32:
return float64(typed), true
case int64:
return float64(typed), true
case uint:
return float64(typed), true
case uint8:
return float64(typed), true
case uint16:
return float64(typed), true
case uint32:
return float64(typed), true
case uint64:
return float64(typed), true
case json.Number:
parsed, err := typed.Float64()
return parsed, err == nil
case string:
parsed, err := strconv.ParseFloat(strings.TrimSpace(typed), 64)
return parsed, err == nil
default:
return 0, false
}
}