Files
cloud-services/pkg/digitaltwin/sendv2.go

213 lines
5.7 KiB
Go

package digitaltwin
import (
"encoding/json"
cache "fiskerinc.com/modules/cachev2"
"fiskerinc.com/modules/common"
"fiskerinc.com/modules/db/queries"
"fiskerinc.com/modules/logger"
redis "fiskerinc.com/modules/redisv2"
"github.com/pkg/errors"
)
func NewSendDigitalTwinV2(redisClient redis.ClientInterface, cars queries.CarsInterface) SendDigitalTwinV2 {
return SendDigitalTwinV2{
redisClient: redisClient,
carsDB: cars,
}
}
type SendDigitalTwinV2 struct {
redisClient redis.ClientInterface
carsDB queries.CarsInterface
parser *cache.VehicleState
}
func (d *SendDigitalTwinV2) Close() {
d.carsDB = nil
}
func (d *SendDigitalTwinV2) GetDigitalTwin(vin string) (*common.JSONDigitalTwin, error) {
state, err := d.getVehicleState(vin)
if err != nil {
return nil, err
}
var battery *common.JSONBattery
var windows *common.JSONWindows
var climateControl *common.JSONClimateControl
battery = consolidateBatteryV2(state)
// Consolidate windows
if state.Windows != nil && state.MiscWindows != nil && state.Sunroof != nil {
windows = &common.JSONWindows{}
// Main windows
windows.LeftFront = state.Windows.LeftFront
windows.LeftRear = state.Windows.LeftRear
windows.RightFront = state.Windows.RightFront
windows.RightRear = state.Windows.RightRear
// Miscellaneous windows
windows.LeftRearQuarter = state.MiscWindows.LeftRearQuarter
windows.RightRearQuarter = state.MiscWindows.RightRearQuarter
windows.RearWindshield = state.MiscWindows.RearWindshield
// Sunroof
windows.Sunroof = state.Sunroof.Sunroof
}
// Consolidate climate control
if state.CabinClimate != nil && state.RearDefrost != nil && state.DriverSeatHeat != nil &&
state.PassengerSeatHeat != nil && state.SteeringWheelHeat != nil && state.AmbientTemperature != nil {
climateControl = &common.JSONClimateControl{}
climateControl.CabinTemperature = state.CabinClimate.CabinTemperature
climateControl.RearDefrost = state.RearDefrost.On
climateControl.DriverSeatHeat = state.DriverSeatHeat.Level
climateControl.PassengerSeatHeat = state.PassengerSeatHeat.Level
climateControl.SteeringWheelHeat = state.SteeringWheelHeat.On
climateControl.AmbientTemperature = state.AmbientTemperature.Temperature
climateControl.InternalTemperature = state.CabinClimate.InternalTemperature
}
twinForDrivers := &common.JSONDigitalTwin{
VIN: vin,
Online: state.Online,
OnlineHMI: state.OnlineHMI,
VehicleSpeed: state.VehicleSpeed,
Gear: state.Gear,
Battery: battery,
Doors: state.Doors,
Location: state.Location,
Locks: state.Locks,
Windows: windows,
ClimateControl: climateControl,
TRexVersion: state.TRexVersion,
IP: state.IP,
VehicleReadyState: state.VehicleReadyState,
ExpandedSignals: state.ExpandedSignals,
UpdatedAt: state.UpdatedAt,
}
return twinForDrivers, nil
}
func consolidateBatteryV2(state common.CarState) *common.JSONBattery {
battery := common.JSONBattery{}
if state.StateOfCharge != nil {
battery.StateOfCharge = &state.StateOfCharge.Usable
}
if state.Battery != nil {
battery.Percent = &state.Battery.Percent
battery.TotalMileageOdometer = &state.Battery.TotalMileageOdometer
}
if state.MaxRange != nil {
battery.MaxMiles = &state.MaxRange.MaxMiles
}
if state.VCU0x260 != nil {
battery.ChargeType = &state.VCU0x260.ChargeType
}
if state.ChargingMetrics != nil {
battery.RemainingChargingTime = &state.ChargingMetrics.RemainingChargingTime
}
if state.ChargingMetrics != nil {
battery.RemainingChargingTimeFull = &state.ChargingMetrics.RemainingChargingTimeFull
}
if state.CellTemperature != nil {
battery.AvgCellTemperature = &state.CellTemperature.AvgBatteryTemp
}
if battery == (common.JSONBattery{}) {
return nil
}
return &battery
}
func (d *SendDigitalTwinV2) sendToDriver(twin *common.JSONDigitalTwin, driver string) error {
dt, err := json.Marshal(twin)
if err != nil {
logger.Error().Err(errors.WithStack(err)).Send()
}
sdt := string(dt)
logger.Debug().Msg(sdt)
logger.Info().Interface("digital twin", twin).Msg("send to driver add to redis")
err = d.redisClient.SafePublishMessage(
common.Mobile.Key(driver),
common.Message{
Handler: "digital_twin",
Data: twin,
},
)
return err
}
func (d *SendDigitalTwinV2) SendToDriver(vin string, driver string) error {
ok, err := d.verifyCarToDriver(vin, driver)
if err != nil {
return err
} else if !ok {
return cache.ErrInvalidCarToDriverAssociation(vin, driver)
}
twin, err := d.GetDigitalTwin(vin)
if err != nil {
return err
}
return d.sendToDriver(twin, driver)
}
func (d *SendDigitalTwinV2) Send(vin string) error {
// Get the digital twin
redisDigitalTwin, err := d.GetDigitalTwin(vin)
if err != nil {
return err
}
drivers, err := d.retrieveDriverIDs(vin)
if err != nil {
return err
}
if len(drivers) == 0 {
return nil
}
if redisDigitalTwin != nil {
for _, driver := range drivers {
err = d.sendToDriver(redisDigitalTwin, driver)
if err != nil {
logger.Error().Err(err)
}
}
}
return nil
}
func (d *SendDigitalTwinV2) getVehicleState(vin string) (common.CarState, error) {
return d.getParser().Get(vin)
}
func (d *SendDigitalTwinV2) verifyCarToDriver(vin string, driver string) (bool, error) {
return cache.VerifyCarToDriver(d.redisClient, d.carsDB, vin, driver)
}
func (d *SendDigitalTwinV2) retrieveDriverIDs(vin string) ([]string, error) {
drivers := cache.NewDriversCache(d.redisClient, d.carsDB)
return drivers.RetrieveDriverIDs(vin)
}
func (d *SendDigitalTwinV2) getParser() *cache.VehicleState {
if d.parser == nil {
d.parser = cache.NewVehicleState(d.redisClient)
}
return d.parser
}