From d41976ff24bded52c4ffcde8086799c8c1c85d65 Mon Sep 17 00:00:00 2001 From: Patrick Demers Date: Mon, 28 Oct 2024 15:36:51 -0700 Subject: [PATCH] fix floats reported in scientific notation --- telemetry/record.go | 18 ++++++++++++++++++ telemetry/record_test.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/telemetry/record.go b/telemetry/record.go index 10dd1c7e..4916c5af 100644 --- a/telemetry/record.go +++ b/telemetry/record.go @@ -2,6 +2,8 @@ package telemetry import ( "fmt" + "regexp" + "strconv" "strings" "time" @@ -36,6 +38,7 @@ var ( return &protos.Payload{} }, } + scientificNotationFloatRegex = regexp.MustCompile("^[+-]?(\\d*\\.\\d+|\\d+\\.\\d*)([eE][+-]?\\d+)$") ) // Record is a structs that represents the telemetry records vehicles send to the backend @@ -170,6 +173,7 @@ func (record *Record) applyProtoRecordTransforms() error { } message.Vin = record.Vin transformLocation(message) + transformScientificNotation(message) record.PayloadBytes, err = proto.Marshal(message) return err default: @@ -226,6 +230,20 @@ func transformLocation(message *protos.Payload) { } } +// transformScientificNotation fixes floating point values which are represented in scientific notation +// example: 1e-3 => 0.001 +func transformScientificNotation(message *protos.Payload) { + for _, datum := range message.Data { + if strVal := datum.GetValue().GetStringValue(); strVal != "" { + if scientificNotationFloatRegex.MatchString(strVal) { + if floatVal, err := strconv.ParseFloat(strVal, 32); err == nil { + datum.Value = &protos.Value{Value: &protos.Value_StringValue{StringValue: fmt.Sprintf("%.5f", floatVal)}} + } + } + } + } +} + // ParseLocation parses a location string (such as "(37.412374 N, 122.145867 W)") into a *proto.Location type. func ParseLocation(s string) (*protos.LocationValue, error) { var lat, lon float64 diff --git a/telemetry/record_test.go b/telemetry/record_test.go index ff1ee5b2..1b75c8c3 100644 --- a/telemetry/record_test.go +++ b/telemetry/record_test.go @@ -152,6 +152,42 @@ var _ = Describe("Socket handler test", func() { Expect(second.Key).To(Equal(protos.Field_VehicleName)) }) + DescribeTable("number formatting fixes", + func(in string, expected string) { + brakePedalPos := stringDatum(protos.Field_BrakePedalPos, in) + + message := messages.StreamMessage{TXID: []byte("1234"), SenderID: []byte("vehicle_device.42"), MessageTopic: []byte("V"), Payload: generatePayload("cybertruck", "42", nil, brakePedalPos)} + recordMsg, err := message.ToBytes() + Expect(err).NotTo(HaveOccurred()) + + record, err := telemetry.NewRecord(serializer, recordMsg, "1", false) + Expect(err).NotTo(HaveOccurred()) + Expect(record).NotTo(BeNil()) + + data := &protos.Payload{} + err = proto.Unmarshal(record.Payload(), data) + Expect(err).NotTo(HaveOccurred()) + Expect(data.Data).To(HaveLen(2)) + + // Give some predictability to the test + sort.Slice(data.Data, func(i, j int) bool { + return data.Data[i].Key < data.Data[j].Key + }) + + first := data.Data[0] + Expect(first.Key).To(Equal(protos.Field_VehicleName)) + + second := data.Data[1] + Expect(second.Key).To(Equal(protos.Field_BrakePedalPos)) + Expect(second.Value.GetStringValue()).To(Equal(expected)) + }, + Entry("scientific notation is reported as regular float", "1.1920928955078125e-05", "0.00001"), + Entry("scientific notation close to zero turns to zero", "1.23e-9", "0.00000"), + Entry("long floats are not modified", "0.00000012", "0.00000012"), + Entry("regular floats are not modified", "0.03", "0.03"), + Entry("integers are not modified", "3", "3"), + ) + DescribeTable("handleAlerts", func(payloadTimestamp *timestamppb.Timestamp, expectedTimestamp *timestamppb.Timestamp, isActive bool) { alert := &protos.VehicleAlert{