feat: expand vehicle data platform capabilities
This commit is contained in:
@@ -57,23 +57,27 @@ type rawFrameRow struct {
|
||||
}
|
||||
|
||||
type metricAgg struct {
|
||||
VIN string
|
||||
Date string
|
||||
Protocol envelope.Protocol
|
||||
FirstKM float64
|
||||
LatestKM float64
|
||||
Count int64
|
||||
SourceKey string
|
||||
Phone string
|
||||
DeviceID string
|
||||
SourceEndpoint string
|
||||
SourceCode string
|
||||
PlatformName string
|
||||
SourceKind string
|
||||
FirstEventTime time.Time
|
||||
LatestEventTime time.Time
|
||||
QualityStatus string
|
||||
QualityReason string
|
||||
VIN string
|
||||
Date string
|
||||
Protocol envelope.Protocol
|
||||
FirstKM float64
|
||||
LatestKM float64
|
||||
PureHydrogenMileageKM float64
|
||||
Count int64
|
||||
PureHydrogenSampleCount int64
|
||||
SourceKey string
|
||||
Phone string
|
||||
DeviceID string
|
||||
SourceEndpoint string
|
||||
SourceCode string
|
||||
PlatformName string
|
||||
SourceKind string
|
||||
FirstEventTime time.Time
|
||||
LatestEventTime time.Time
|
||||
LatestPureHydrogenActive bool
|
||||
LatestPureHydrogenModeKnown bool
|
||||
QualityStatus string
|
||||
QualityReason string
|
||||
}
|
||||
|
||||
type dailySourceLast struct {
|
||||
@@ -266,21 +270,24 @@ func addSamples(aggregates map[string]*metricAgg, samples []stats.MetricSample)
|
||||
agg, ok := aggregates[key]
|
||||
if !ok {
|
||||
aggregates[key] = &metricAgg{
|
||||
VIN: sample.VIN,
|
||||
Date: sample.StatDate,
|
||||
Protocol: sample.Protocol,
|
||||
FirstKM: sample.TotalMileageKM,
|
||||
LatestKM: sample.TotalMileageKM,
|
||||
Count: 1,
|
||||
SourceKey: sample.SourceKey,
|
||||
Phone: sample.Phone,
|
||||
DeviceID: sample.DeviceID,
|
||||
SourceEndpoint: sample.SourceEndpoint,
|
||||
PlatformName: sample.PlatformName,
|
||||
FirstEventTime: sample.EventTime,
|
||||
LatestEventTime: sample.EventTime,
|
||||
QualityStatus: stats.QualityOK,
|
||||
QualityReason: "current_day_first_sample",
|
||||
VIN: sample.VIN,
|
||||
Date: sample.StatDate,
|
||||
Protocol: sample.Protocol,
|
||||
FirstKM: sample.TotalMileageKM,
|
||||
LatestKM: sample.TotalMileageKM,
|
||||
Count: 1,
|
||||
PureHydrogenSampleCount: activeModeSampleCount(sample),
|
||||
SourceKey: sample.SourceKey,
|
||||
Phone: sample.Phone,
|
||||
DeviceID: sample.DeviceID,
|
||||
SourceEndpoint: sample.SourceEndpoint,
|
||||
PlatformName: sample.PlatformName,
|
||||
FirstEventTime: sample.EventTime,
|
||||
LatestEventTime: sample.EventTime,
|
||||
LatestPureHydrogenActive: sample.PureHydrogenActive,
|
||||
LatestPureHydrogenModeKnown: sample.PureHydrogenModeKnown,
|
||||
QualityStatus: stats.QualityOK,
|
||||
QualityReason: "current_day_first_sample",
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -289,8 +296,18 @@ func addSamples(aggregates map[string]*metricAgg, samples []stats.MetricSample)
|
||||
agg.FirstEventTime = sample.EventTime
|
||||
}
|
||||
if sample.EventTime.After(agg.LatestEventTime) {
|
||||
agg.PureHydrogenMileageKM += stats.PureHydrogenMileageDelta(
|
||||
agg.LatestKM,
|
||||
sample.TotalMileageKM,
|
||||
agg.LatestPureHydrogenActive,
|
||||
agg.LatestPureHydrogenModeKnown,
|
||||
sample.PureHydrogenActive,
|
||||
sample.PureHydrogenModeKnown,
|
||||
)
|
||||
agg.LatestKM = sample.TotalMileageKM
|
||||
agg.LatestEventTime = sample.EventTime
|
||||
agg.LatestPureHydrogenActive = sample.PureHydrogenActive
|
||||
agg.LatestPureHydrogenModeKnown = sample.PureHydrogenModeKnown
|
||||
agg.SourceEndpoint = sample.SourceEndpoint
|
||||
if strings.TrimSpace(sample.Phone) != "" {
|
||||
agg.Phone = sample.Phone
|
||||
@@ -303,9 +320,17 @@ func addSamples(aggregates map[string]*metricAgg, samples []stats.MetricSample)
|
||||
}
|
||||
}
|
||||
agg.Count++
|
||||
agg.PureHydrogenSampleCount += activeModeSampleCount(sample)
|
||||
}
|
||||
}
|
||||
|
||||
func activeModeSampleCount(sample stats.MetricSample) int64 {
|
||||
if sample.PureHydrogenModeKnown && sample.PureHydrogenActive {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func writeAggregates(ctx context.Context, db *sql.DB, aggregates map[string]*metricAgg, batchSize int) (int64, error) {
|
||||
if len(aggregates) == 0 {
|
||||
return 0, nil
|
||||
@@ -338,23 +363,27 @@ func writeAggregates(ctx context.Context, db *sql.DB, aggregates map[string]*met
|
||||
}
|
||||
dailyKM := stats.DailyMileageFromDayBoundary(agg.FirstKM, agg.LatestKM)
|
||||
candidate := stats.SourceMileageSample{
|
||||
VIN: agg.VIN,
|
||||
StatDate: agg.Date,
|
||||
Protocol: agg.Protocol,
|
||||
SourceKey: agg.SourceKey,
|
||||
SourceIP: identity.SourceIP,
|
||||
SourceEndpoint: agg.SourceEndpoint,
|
||||
Phone: agg.Phone,
|
||||
DeviceID: agg.DeviceID,
|
||||
PlatformName: agg.PlatformName,
|
||||
FirstTotalKM: agg.FirstKM,
|
||||
LatestTotalKM: agg.LatestKM,
|
||||
DailyKM: dailyKM,
|
||||
SampleCount: agg.Count,
|
||||
FirstEventTime: agg.FirstEventTime,
|
||||
LatestEventTime: agg.LatestEventTime,
|
||||
QualityStatus: agg.QualityStatus,
|
||||
QualityReason: agg.QualityReason,
|
||||
VIN: agg.VIN,
|
||||
StatDate: agg.Date,
|
||||
Protocol: agg.Protocol,
|
||||
SourceKey: agg.SourceKey,
|
||||
SourceIP: identity.SourceIP,
|
||||
SourceEndpoint: agg.SourceEndpoint,
|
||||
Phone: agg.Phone,
|
||||
DeviceID: agg.DeviceID,
|
||||
PlatformName: agg.PlatformName,
|
||||
FirstTotalKM: agg.FirstKM,
|
||||
LatestTotalKM: agg.LatestKM,
|
||||
DailyKM: dailyKM,
|
||||
PureHydrogenMileageKM: agg.PureHydrogenMileageKM,
|
||||
SampleCount: agg.Count,
|
||||
PureHydrogenSampleCount: agg.PureHydrogenSampleCount,
|
||||
FirstEventTime: agg.FirstEventTime,
|
||||
LatestEventTime: agg.LatestEventTime,
|
||||
LatestPureHydrogenActive: agg.LatestPureHydrogenActive,
|
||||
LatestPureHydrogenModeKnown: agg.LatestPureHydrogenModeKnown,
|
||||
QualityStatus: agg.QualityStatus,
|
||||
QualityReason: agg.QualityReason,
|
||||
}
|
||||
if candidate.QualityStatus == "" {
|
||||
candidate.QualityStatus = stats.QualityOK
|
||||
@@ -1266,9 +1295,49 @@ func fieldsForStats(protocol envelope.Protocol, vin string, text string) map[str
|
||||
}
|
||||
fields[key] = value
|
||||
}
|
||||
promoteFuelCellWorkModeForStats(protocol, fields, text)
|
||||
return fields
|
||||
}
|
||||
|
||||
func promoteFuelCellWorkModeForStats(protocol envelope.Protocol, fields map[string]any, text string) {
|
||||
if fields == nil {
|
||||
return
|
||||
}
|
||||
if _, exists := fields[envelope.FieldFuelCellWorkMode]; exists {
|
||||
return
|
||||
}
|
||||
var candidates []string
|
||||
switch protocol {
|
||||
case envelope.ProtocolGB32960:
|
||||
candidates = []string{
|
||||
"gb32960.gd_fc_stack.engine_work_state",
|
||||
"engine_work_state",
|
||||
}
|
||||
case envelope.ProtocolYutongMQTT:
|
||||
candidates = []string{
|
||||
"yutong_mqtt.data.triangle_state",
|
||||
"yutong_mqtt.root.data.triangle_state",
|
||||
"TRIANGLE_STATE",
|
||||
"triangle_state",
|
||||
"triangleState",
|
||||
}
|
||||
default:
|
||||
return
|
||||
}
|
||||
for _, key := range candidates {
|
||||
if value, exists := fields[key]; exists {
|
||||
fields[envelope.FieldFuelCellWorkMode] = value
|
||||
return
|
||||
}
|
||||
}
|
||||
for _, key := range candidates {
|
||||
if value, ok := extractJSONStringField(text, key); ok {
|
||||
fields[envelope.FieldFuelCellWorkMode] = value
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mileageKeys(protocol envelope.Protocol) []string {
|
||||
switch protocol {
|
||||
case envelope.ProtocolGB32960:
|
||||
|
||||
Reference in New Issue
Block a user