Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 42 additions & 14 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -309,103 +309,131 @@
"filename": "pkg/decoder/smartlabel/v1/decoder_test.go",
"hashed_secret": "2969e12a864a2091be4082d99c1767a6d225ef9f",
"is_verified": false,
"line_number": 170,
"line_number": 171,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/smartlabel/v1/decoder_test.go",
"hashed_secret": "18911f680f30a3d441a7314a5f4131ccdf5a291d",
"is_verified": false,
"line_number": 193,
"line_number": 194,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/smartlabel/v1/decoder_test.go",
"hashed_secret": "03799cbbbde9a26987fc61ee9d1c7607efa5b6c3",
"is_verified": false,
"line_number": 216,
"line_number": 217,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/smartlabel/v1/decoder_test.go",
"hashed_secret": "5834801389e8dc5649da5afb03daa5984c109656",
"is_verified": false,
"line_number": 241
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/smartlabel/v1/decoder_test.go",
"hashed_secret": "728a3e88a062cfba092183aca6fe9b07841fd501",
"is_verified": false,
"line_number": 256
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/smartlabel/v1/decoder_test.go",
"hashed_secret": "b5950857a05765aaec2390c6fb6e6d178fde38ec",
"is_verified": false,
"line_number": 271
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/smartlabel/v1/decoder_test.go",
"hashed_secret": "88d19da2a0e9309b61e89836d80f63274d9faeea",
"is_verified": false,
"line_number": 286
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/smartlabel/v1/decoder_test.go",
"hashed_secret": "d85e5644e91feb126f202af26abefd4aadde571e",
"is_verified": false,
"line_number": 239,
"line_number": 307,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/smartlabel/v1/decoder_test.go",
"hashed_secret": "9db4104f44fd40f26bce7072ad15bc10f1e833d6",
"is_verified": false,
"line_number": 259,
"line_number": 327,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/smartlabel/v1/decoder_test.go",
"hashed_secret": "517accb9519da7da9ae0f3ee9eac83543169ee17",
"is_verified": false,
"line_number": 269,
"line_number": 337,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/smartlabel/v1/decoder_test.go",
"hashed_secret": "32179884041e9ddc27e1c5e0e45ccc6e81637d65",
"is_verified": false,
"line_number": 279,
"line_number": 347,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/smartlabel/v1/decoder_test.go",
"hashed_secret": "07cb4aff970c7271688f1e8eaf214a516d3970e3",
"is_verified": false,
"line_number": 299,
"line_number": 367,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/smartlabel/v1/decoder_test.go",
"hashed_secret": "bc4afa2f3630480ca72a32c5c8421b39f3ce1a71",
"is_verified": false,
"line_number": 332,
"line_number": 400,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/smartlabel/v1/decoder_test.go",
"hashed_secret": "395900609a0d94e6b75d0f0cb6b647d1d554c442",
"is_verified": false,
"line_number": 343,
"line_number": 411,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/smartlabel/v1/decoder_test.go",
"hashed_secret": "81de30f2e09afabf90f74a4addd1ddbc354277d4",
"is_verified": false,
"line_number": 356,
"line_number": 424,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/smartlabel/v1/decoder_test.go",
"hashed_secret": "a158f37d59e2f1ea505e92294149581814a5ffe3",
"is_verified": false,
"line_number": 373,
"line_number": 441,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "pkg/decoder/smartlabel/v1/decoder_test.go",
"hashed_secret": "884f72cf02528dcd37a031e2af8575273d4394e2",
"is_verified": false,
"line_number": 529,
"line_number": 619,
"is_secret": false
}
],
Expand Down Expand Up @@ -2235,5 +2263,5 @@
}
]
},
"generated_at": "2026-04-28T18:24:36Z"
"generated_at": "2026-05-29T14:09:23Z"
}
45 changes: 45 additions & 0 deletions pkg/decoder/smartlabel/v1/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"reflect"
"time"

"github.com/truvami/decoder/pkg/common"
"github.com/truvami/decoder/pkg/decoder"
Expand Down Expand Up @@ -104,6 +105,22 @@ func (t SmartLabelv1Decoder) getConfig(port uint8, data string) (common.PayloadC
TargetType: reflect.TypeOf(Port4Payload{}),
Features: []decoder.Feature{decoder.FeatureConfig, decoder.FeatureFirmwareVersion},
}, nil
case 10:
return common.PayloadConfig{
Fields: []common.FieldConfig{
{Name: "Status", Start: 0, Length: 1},
{Name: "Latitude", Start: 1, Length: 4, Transform: latitude},
{Name: "Longitude", Start: 5, Length: 4, Transform: longitude},
{Name: "Altitude", Start: 9, Length: 2, Transform: port10Altitude},
{Name: "Timestamp", Start: 11, Length: 4, Transform: timestamp},
{Name: "Battery", Start: 15, Length: 2, Transform: gnssBattery},
{Name: "TTF", Start: 17, Length: 1, Transform: ttf},
{Name: "PDOP", Start: 18, Length: 1, Transform: pdop},
{Name: "Satellites", Start: 19, Length: 1},
},
TargetType: reflect.TypeOf(Port10Payload{}),
Features: []decoder.Feature{decoder.FeatureGNSS, decoder.FeatureTimestamp, decoder.FeatureBattery},
}, nil
case 11:
return common.PayloadConfig{
Fields: []common.FieldConfig{
Expand Down Expand Up @@ -214,3 +231,31 @@ func temperature(v any) any {
func humidity(v any) any {
return float32(common.BytesToUint8(v.([]byte))) / 2
}

func latitude(v any) any {
return float64(common.BytesToInt32(v.([]byte))) / 1000000
}

func longitude(v any) any {
return float64(common.BytesToInt32(v.([]byte))) / 1000000
}

func port10Altitude(v any) any {
return float64(common.BytesToUint16(v.([]byte))) / 100
}

func timestamp(v any) any {
return time.Unix(int64(common.BytesToUint32(v.([]byte))), 0).UTC()
}

func gnssBattery(v any) any {
return float64(common.BytesToUint16(v.([]byte))) / 1000
}

func ttf(v any) any {
return time.Duration(int64(common.BytesToUint8(v.([]byte)))) * time.Second
}

func pdop(v any) any {
return float64(common.BytesToUint8(v.([]byte))) / 2
}
95 changes: 95 additions & 0 deletions pkg/decoder/smartlabel/v1/decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"reflect"
"strings"
"testing"
"time"

"github.com/stretchr/testify/assert"
helpers "github.com/truvami/decoder/pkg/common"
Expand Down Expand Up @@ -235,6 +236,73 @@ func TestDecode(t *testing.T) {
FirmwareVersionPatch: 12,
},
},
{
// Active GNSS fix near Zurich (tracker sample)
payload: "0002d2eeb40081d77ca3706a196afd0e74000009",
port: 10,
expected: Port10Payload{
Status: 0,
Latitude: 47.3781,
Longitude: 8.509308,
Altitude: 418.4,
Timestamp: time.Date(2026, 5, 29, 10, 31, 25, 0, time.UTC),
Battery: 3.7,
TTF: helpers.DurationPtr(0),
PDOP: helpers.Float64Ptr(0),
Satellites: helpers.Uint8Ptr(9),
},
},
{
payload: "0002d308b50082457f16eb66c4a5cd0ed3000505",
port: 10,
expected: Port10Payload{
Status: 0,
Latitude: 47.384757,
Longitude: 8.537471,
Altitude: 58.67,
Timestamp: time.Date(2024, 8, 20, 14, 18, 53, 0, time.UTC),
Battery: 3.795,
TTF: helpers.DurationPtr(0),
PDOP: helpers.Float64Ptr(2.5),
Satellites: helpers.Uint8Ptr(5),
},
},
{
payload: "0002d30b070082491f11256718d9fe0ede190505",
port: 10,
expected: Port10Payload{
Status: 0,
Latitude: 47.385351,
Longitude: 8.538399,
Altitude: 43.89,
Timestamp: time.Date(2024, 10, 23, 11, 11, 58, 0, time.UTC),
Battery: 3.806,
PDOP: helpers.Float64Ptr(2.5),
Satellites: helpers.Uint8Ptr(5),
TTF: helpers.DurationPtr(25 * time.Second),
},
},
{
payload: "0002d30b070082491f11256718d9fe0e74190505",
port: 10,
expected: Port10Payload{
Status: 0,
Latitude: 47.385351,
Longitude: 8.538399,
Altitude: 43.89,
Timestamp: time.Date(2024, 10, 23, 11, 11, 58, 0, time.UTC),
Battery: 3.7,
PDOP: helpers.Float64Ptr(2.5),
Satellites: helpers.Uint8Ptr(5),
TTF: helpers.DurationPtr(25 * time.Second),
},
},
{
payload: "00deadbeef",
port: 10,
expected: nil,
expectedErr: "invalid payload length",
},
{
payload: "0ca90dbd07fa69",
port: 11,
Expand Down Expand Up @@ -445,6 +513,24 @@ func TestDecodeWithNoopSolver(t *testing.T) {
}
}

func TestPort10Features(t *testing.T) {
d := NewSmartLabelv1Decoder(context.TODO(), solver.MockSolverV1{}, zap.NewNop())
decoded, err := d.Decode(context.TODO(), "0002d30b070082491f11256718d9fe0ede190505", 10)
assert.NoError(t, err)
assert.NotNil(t, decoded)

assert.True(t, decoded.Is(decoder.FeatureGNSS))
assert.True(t, decoded.Is(decoder.FeatureTimestamp))
assert.True(t, decoded.Is(decoder.FeatureBattery))
assert.False(t, decoded.Is(decoder.FeatureMoving))
assert.False(t, decoded.Is(decoder.FeatureDutyCycle))
assert.False(t, decoded.Is(decoder.FeatureConfigChange))

payload, ok := decoded.Data.(Port10Payload)
assert.True(t, ok)
assert.Equal(t, uint8(0), payload.Status)
}

func TestInvalidPort(t *testing.T) {
logger := zap.NewExample()
defer func() {
Expand Down Expand Up @@ -518,6 +604,10 @@ func TestFeatures(t *testing.T) {
payload: "fdb7218f6c166fadb359ea3bdec77daff72faac81784ab263386a455d3a73592a063900ba262b95a6ffc86",
port: 197,
},
{
payload: "0002d30b070082491f11256718d9fe0ede190505",
port: 10,
},
}

mux := http.NewServeMux()
Expand Down Expand Up @@ -708,6 +798,11 @@ func TestMarshal(t *testing.T) {
port: 4,
expected: []string{"\"dataRate\": \"automatic-wide\"", "\"gnss\": true", "\"temperatureUpperThreshold\": 40", "\"temperatureLowerThreshold\": -20"},
},
{
payload: "0002d30b070082491f11256718d9fe0ede190505",
port: 10,
expected: []string{"\"status\": 0", "\"latitude\": 47.385351", "\"battery\": \"3.806v\"", "\"satellites\": 5"},
},
{
payload: "0f50107904da8d",
port: 11,
Expand Down
Loading
Loading