Add depot, attendant, jetfire, optimus, ota services with kustomize overlays

This commit is contained in:
Chris Rai
2026-01-31 15:35:07 -05:00
parent a0ec642ca1
commit 9a5cb2f547
404 changed files with 38817 additions and 16 deletions

View File

@@ -0,0 +1,184 @@
package controllers
import (
"github.com/fiskerinc/cloud-services/services/attendant/services"
"encoding/base64"
"encoding/json"
"errors"
"sync"
"time"
"github.com/fiskerinc/cloud-services/pkg/grpc/kafka_grpc"
"github.com/fiskerinc/cloud-services/pkg/logger"
"github.com/fiskerinc/cloud-services/pkg/can-go/pkg/descriptor"
)
type DTCEntry struct {
CreatedAt time.Time `bson:"created_at"`
VIN string `bson:"vin"`
ECU string `json:"ecu" bson:"ecu"`
DTC uint64 `json:"dtc" bson:"dtc"`
Status uint8 `json:"status" bson:"status"`
Timestamp time.Time `json:"timestamp" bson:"timestamp"`
Speed uint16 `json:"speed" bson:"speed"`
Mileage uint32 `json:"mileage" bson:"mileage"`
Voltage uint16 `json:"voltage" bson:"voltage"`
SnapshotBase64 string `json:"snapshot,omitempty" bson:"snapshot,omitempty"`
}
func GRPCToDTCEntry(payload *kafka_grpc.GRPC_AttendantPayload) []byte {
if payload.Data == nil {
return nil
}
data := payload.Data.(*kafka_grpc.GRPC_AttendantPayload_DtcEntry)
if data == nil {
return nil
}
dtc := &DTCEntry{
VIN: data.DtcEntry.Vin,
ECU: data.DtcEntry.Ecu,
CreatedAt: milliToDate(data.DtcEntry.CreatedAt),
DTC: data.DtcEntry.Dtc,
Status: uint8(data.DtcEntry.Status),
Timestamp: milliToDate(data.DtcEntry.Timestamp),
Speed: uint16(data.DtcEntry.Speed),
Mileage: data.DtcEntry.Mileage,
Voltage: uint16(data.DtcEntry.Volt),
SnapshotBase64: data.DtcEntry.SnapshotBase64,
}
bytes, _ := json.Marshal(dtc)
return bytes
}
func milliToDate(timestamp int64) time.Time {
seconds := timestamp / 1000
nanoseconds := (timestamp % 1000) * int64(time.Millisecond)
return time.Unix(seconds, nanoseconds)
}
const SNAPSHOT_LEN = 21
func (entry *DTCEntry) ParseSnapshot() error {
data, errc := base64.StdEncoding.DecodeString(entry.SnapshotBase64)
if errc != nil {
return errc
}
payloadLen := len(data) - 2
if payloadLen < SNAPSHOT_LEN {
logger.Debug().Msgf("DTC snapshot payload is too small. Required length=%d, actual=%d, ECU=%s\n", SNAPSHOT_LEN, len(data), entry.ECU)
return errors.New("Snapshot too small")
}
// Our "Basic Diagnostic" spec defines 4 mandatory DIDs that must be
// stored inside DTCStapshotRecord:
// 1. EF F6 - Timestamp (6 bytes).
// 2. EF F7 - Vehicle Speed (2 bytes).
// 3. EF F8 - Milage (idk, our spec doesn't specify exact number.
// Empirically it's 4 bytes (same as "ICC_0x531::TotMilg_ODO").
// 4. EF F9 - Battery Voltage (2 bytes).
///entry.Speed = int16(speed.ToPhysical(float64(uint16(decodedBytes[0])<<8 | uint16(decodedBytes[1]))))
//entry.Voltage = int16(voltage.ToPhysical(float64(uint16(decodedBytes[0])<<8 | uint16(decodedBytes[1]))))
for idx := 2; idx < len(data)-1; {
if data[idx] != 0xEF {
idx++
continue
}
if data[idx+1] == 0xF6 && idx+7 < len(data) {
idx += 2
entry.Timestamp, idx = consumeTimestamp(data, idx)
} else if data[idx+1] == 0xF7 && idx+3 < len(data) {
idx += 2
entry.Speed, idx = consumeSpeed(data, idx)
} else if data[idx+1] == 0xF8 && idx+5 < len(data) {
idx += 2
entry.Mileage, idx = consumeMileage(data, idx)
} else if data[idx+1] == 0xF9 && idx+3 < len(data) {
idx += 2
entry.Voltage, idx = consumeVoltage(data, idx)
} else {
idx++
}
}
return nil
}
var onceTimestamp sync.Once
var (
day *descriptor.Signal
hr *descriptor.Signal
mins *descriptor.Signal
yr *descriptor.Signal
month *descriptor.Signal
sec *descriptor.Signal
)
func consumeTimestamp(data []byte, idx int) (res time.Time, idx_ret int) {
onceTimestamp.Do(func() {
day, _ = services.GetDBC().Signal(0x62F, "TBOX_CrtTi_Day")
hr, _ = services.GetDBC().Signal(0x62F, "TBOX_CrtTi_Hr")
mins, _ = services.GetDBC().Signal(0x62F, "TBOX_CrtTi_Mins")
yr, _ = services.GetDBC().Signal(0x62F, "TBOX_CrtTi_Yr")
month, _ = services.GetDBC().Signal(0x62F, "TBOX_CrtTi_Mth")
sec, _ = services.GetDBC().Signal(0x62F, "TBOX_CrtTi_Sec")
})
res = time.Date(int(yr.ToPhysical(float64(data[idx]))),
time.Month(month.ToPhysical(float64(data[idx+1]))),
int(day.ToPhysical(float64(data[idx+2]))),
int(hr.ToPhysical(float64(data[idx+3]))),
int(mins.ToPhysical(float64(data[idx+4]))),
int(sec.ToPhysical(float64(data[idx+5]))), 0, time.UTC)
idx_ret = idx + 6
return res, idx_ret
}
var onceSpeed sync.Once
var speed *descriptor.Signal
func consumeSpeed(data []byte, idx int) (res uint16, idx_ret int) {
onceSpeed.Do(func() {
speed, _ = services.GetDBC().Signal(0x318, "ESP_VehSpd")
})
res = uint16(speed.ToPhysical(float64(uint16(data[idx])<<8 | uint16(data[idx+1]))))
idx_ret = idx + 2
return res, idx_ret
}
var onceMileage sync.Once
var mileage *descriptor.Signal
func consumeMileage(data []byte, idx int) (res uint32, idx_ret int) {
onceMileage.Do(func() {
mileage, _ = services.GetDBC().Signal(0x531, "ICC_TotMilg_ODO")
})
res = uint32(mileage.ToPhysical(
float64(
uint64(data[idx])<<24 |
uint64(data[idx+1])<<16 |
uint64(data[idx+2])<<8 | uint64(data[idx+3]))))
idx_ret = idx + 4
return res, idx_ret
}
var onceVoltage sync.Once
var voltage *descriptor.Signal
func consumeVoltage(data []byte, idx int) (res uint16, idx_ret int) {
onceVoltage.Do(func() {
voltage, _ = services.GetDBC().Signal(0x507, "VCU_BattVolt")
})
res = uint16(voltage.ToPhysical(float64(uint16(data[idx])<<8 | uint16(data[idx+1]))))
idx_ret = idx + 2
return res, idx_ret
}