Files
lingniu-vehicle-ingest/go/vehicle-gateway/internal/envelope/realtime.go

112 lines
2.9 KiB
Go

package envelope
import "strings"
func IsRealtimeTelemetryFrame(env FrameEnvelope) bool {
if env.ParseStatus == ParseBadFrame {
return false
}
switch env.Protocol {
case ProtocolGB32960:
command := strings.TrimSpace(env.MessageID)
if command == "" && env.Parsed != nil {
if header, ok := env.Parsed["header"].(map[string]any); ok {
command = strings.TrimSpace(stringAny(header["command"]))
}
}
if command != "" && !strings.EqualFold(command, "0x02") && !strings.EqualFold(command, "0x03") {
return false
}
_, hasDataUnits := env.Parsed["data_units"]
return hasDataUnits || hasGB32960ParsedTelemetryField(env) || hasRealtimeField(env)
case ProtocolJT808:
messageID := strings.TrimSpace(env.MessageID)
if messageID != "" && !strings.EqualFold(messageID, "0x0200") {
return false
}
if _, ok := env.Parsed["location"]; ok {
return true
}
return hasParsedFieldPrefix(env, "jt808.location.") || hasRealtimeField(env)
case ProtocolYutongMQTT:
data, ok := env.Parsed["data"].(map[string]any)
if ok && len(data) > 0 {
return true
}
return hasParsedFieldPrefix(env, "yutong_mqtt.data.") ||
hasParsedFieldPrefix(env, "yutong_mqtt.root.data.")
default:
return false
}
}
func hasGB32960ParsedTelemetryField(env FrameEnvelope) bool {
for field := range env.ParsedFields {
if !strings.HasPrefix(field, "gb32960.") {
continue
}
if strings.HasPrefix(field, "gb32960.header.") ||
strings.HasPrefix(field, "gb32960.platform.") ||
strings.HasPrefix(field, "gb32960.identity.") ||
strings.HasPrefix(field, "gb32960.device_time.") {
continue
}
return true
}
return false
}
// RequiresVehicleIdentity keeps platform/control frames out of vehicle identity
// quality metrics while preserving JT808's phone-centric registration/auth flow.
func RequiresVehicleIdentity(env FrameEnvelope) bool {
if env.ParseStatus == ParseBadFrame {
return false
}
switch env.Protocol {
case ProtocolGB32960:
return IsRealtimeTelemetryFrame(env)
case ProtocolJT808:
return true
case ProtocolYutongMQTT:
return IsRealtimeTelemetryFrame(env)
default:
return false
}
}
func hasRealtimeField(env FrameEnvelope) bool {
if env.Fields[FieldLatitude] != nil ||
env.Fields[FieldLongitude] != nil ||
env.Fields[FieldTotalMileageKM] != nil ||
env.Fields[FieldSpeedKMH] != nil ||
env.Fields[FieldSOCPercent] != nil {
return true
}
for field := range env.ParsedFields {
if strings.HasSuffix(field, ".latitude") ||
strings.HasSuffix(field, ".longitude") ||
strings.HasSuffix(field, ".total_mileage_km") ||
strings.HasSuffix(field, ".speed_kmh") ||
strings.HasSuffix(field, ".soc_percent") {
return true
}
}
return false
}
func hasParsedFieldPrefix(env FrameEnvelope, prefix string) bool {
for field := range env.ParsedFields {
if strings.HasPrefix(field, prefix) {
return true
}
}
return false
}
func stringAny(value any) string {
if text, ok := value.(string); ok {
return text
}
return ""
}