219 lines
5.8 KiB
Go
219 lines
5.8 KiB
Go
package digitaltwin
|
|
|
|
import (
|
|
"encoding/json"
|
|
|
|
"fiskerinc.com/modules/cache"
|
|
"fiskerinc.com/modules/common"
|
|
"fiskerinc.com/modules/db/queries"
|
|
"fiskerinc.com/modules/logger"
|
|
"fiskerinc.com/modules/redis"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
func NewSendDigitalTwin(redis redis.ClientPoolInterface, cars queries.CarsInterface) SendDigitalTwin {
|
|
return SendDigitalTwin{
|
|
redisClientPool: redis,
|
|
carsDB: cars,
|
|
}
|
|
}
|
|
|
|
type SendDigitalTwin struct {
|
|
redisClientPool redis.ClientPoolInterface
|
|
carsDB queries.CarsInterface
|
|
parser *cache.VehicleState
|
|
}
|
|
|
|
func (d *SendDigitalTwin) Close() {
|
|
d.carsDB = nil
|
|
}
|
|
|
|
func (d *SendDigitalTwin) GetDigitalTwin(vin string) (*common.JSONDigitalTwin, error) {
|
|
state, err := d.getVehicleState(vin)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return CreateDigitalTwinResponse(vin, state), nil
|
|
}
|
|
|
|
func CreateDigitalTwinResponse(vin string, state common.CarState) *common.JSONDigitalTwin {
|
|
var battery *common.JSONBattery
|
|
var windows *common.JSONWindows
|
|
var climateControl *common.JSONClimateControl
|
|
|
|
battery = consolidateBattery(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
|
|
}
|
|
|
|
func consolidateBattery(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 *SendDigitalTwin) 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")
|
|
client := d.redisClientPool.GetFromPool()
|
|
defer client.Close()
|
|
err = client.SafePublishMessage(
|
|
common.Mobile.Key(driver),
|
|
common.Message{
|
|
Handler: "digital_twin",
|
|
Data: twin,
|
|
},
|
|
)
|
|
return err
|
|
}
|
|
|
|
func (d *SendDigitalTwin) 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 *SendDigitalTwin) 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 *SendDigitalTwin) getVehicleState(vin string) (common.CarState, error) {
|
|
return d.getParser().Get(vin)
|
|
}
|
|
|
|
func (d *SendDigitalTwin) verifyCarToDriver(vin string, driver string) (bool, error) {
|
|
return cache.VerifyCarToDriver(d.redisClientPool, d.carsDB, vin, driver)
|
|
}
|
|
|
|
func (d *SendDigitalTwin) retrieveDriverIDs(vin string) ([]string, error) {
|
|
drivers := cache.NewDriversCache(d.redisClientPool, d.carsDB)
|
|
|
|
return drivers.RetrieveDriverIDs(vin)
|
|
}
|
|
|
|
func (d *SendDigitalTwin) getParser() *cache.VehicleState {
|
|
if d.parser == nil {
|
|
d.parser = cache.NewVehicleState(d.redisClientPool)
|
|
}
|
|
|
|
return d.parser
|
|
}
|