feat: build vehicle data platform and production pipeline
This commit is contained in:
89
go/vehicle-gateway/internal/telemetry/mileage.go
Normal file
89
go/vehicle-gateway/internal/telemetry/mileage.go
Normal file
@@ -0,0 +1,89 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user