112 lines
2.9 KiB
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 ""
|
|
}
|