package common import ( "encoding/json" "time" "github.com/pkg/errors" ) type CarState struct { Online bool `json:"online"` OnlineHMI bool `json:"online_hmi"` Battery *Battery `json:"battery,omitempty"` MaxRange *MaxRange `json:"max_range,omitempty"` Doors *Doors `json:"doors,omitempty"` Location *Location `json:"location,omitempty"` Locks *Locks `json:"door_locks,omitempty"` Windows *Windows `json:"windows,omitempty"` MiscWindows *MiscWindows `json:"misc_windows,omitempty"` Sunroof *Sunroof `json:"sunroof,omitempty"` CabinClimate *CabinClimate `json:"cabin_climate,omitempty"` RearDefrost *RearDefrost `json:"rear_defrost,omitempty"` DriverSeatHeat *DriverSeatHeat `json:"driver_seat_heat,omitempty"` PassengerSeatHeat *PassengerSeatHeat `json:"passenger_seat_heat,omitempty"` SteeringWheelHeat *SteeringWheelHeat `json:"steering_wheel_heat,omitempty"` AmbientTemperature *AmbientTemperature `json:"ambient_temperature,omitempty"` CellTemperature *CellTemperature `json:"cell_temp,omitempty"` VehicleSpeed *VehicleSpeed `json:"vehicle_speed,omitempty"` VCU0x260 *VCU0x260Descriptor `json:"vcu0x260,omitempty"` ChargingMetrics *VCUChargingMetrics `json:"charging_metrics,omitempty"` Gear *Gear `json:"gear,omitempty"` StateOfCharge *StateOfCharge `json:"state_of_charge,omitempty"` TRexVersion string `json:"trex_version,omitempty"` DBCVersion string `json:"dbc_version,omitempty"` IP string `json:"ip,omitempty"` UpdatedAt *time.Time `json:"updated,omitempty"` SafeState *SafeState `json:"safe_state,omitempty"` DriverOccupySeatState *int `json:"driver_occupy_seat_state,omitempty"` PowerMode *int `json:"power_mode,omitempty"` ChargingStatus *int `json:"charging_status,omitempty"` VehicleReadyState *VehicleReadyState `json:"vehicle_ready_state,omitempty"` Battery12V *Battery12V `json:"battery_12v,omitempty"` // maybe make it Battery12v ExpandedSignals *ExpandedSignals `json:"expanded_signals,omitempty"` } func (c *CarState) GetBattery() *Battery { if c.Battery == nil { c.Battery = &Battery{} } return c.Battery } func (c *CarState) GetMaxRange() *MaxRange { if c.MaxRange == nil { c.MaxRange = &MaxRange{} } return c.MaxRange } func (c *CarState) GetDoors() *Doors { if c.Doors == nil { c.Doors = &Doors{} } return c.Doors } func (c *CarState) UpdateLocation(value []byte) error { loc := Location{} err := loc.Unmarshal(value) if err != nil { return err } location := c.GetLocation() location.Latitude = loc.Latitude location.Longitude = loc.Longitude // Altitude could have already been set from GPS_ALTITUDE so do not overwrite unless it is a non-zero if loc.Altitude != 0 { location.Altitude = loc.Altitude } return nil } func (c *CarState) GetLocation() *Location { if c.Location == nil { c.Location = &Location{} } return c.Location } func (c *CarState) GetLocks() *Locks { if c.Locks == nil { c.Locks = &Locks{} } return c.Locks } func (c *CarState) GetWindows() *Windows { if c.Windows == nil { c.Windows = &Windows{} } return c.Windows } func (c *CarState) GetMiscWindows() *MiscWindows { if c.MiscWindows == nil { c.MiscWindows = &MiscWindows{} } return c.MiscWindows } func (c *CarState) GetSunroof() *Sunroof { if c.Sunroof == nil { c.Sunroof = &Sunroof{} } return c.Sunroof } func (c *CarState) GetCabinClimate() *CabinClimate { if c.CabinClimate == nil { c.CabinClimate = &CabinClimate{} } return c.CabinClimate } func (c *CarState) GetRearDefrost() *RearDefrost { if c.RearDefrost == nil { c.RearDefrost = &RearDefrost{} } return c.RearDefrost } func (c *CarState) GetDriverSeatHeat() *DriverSeatHeat { if c.DriverSeatHeat == nil { c.DriverSeatHeat = &DriverSeatHeat{} } return c.DriverSeatHeat } func (c *CarState) GetPassengerSeatHeat() *PassengerSeatHeat { if c.PassengerSeatHeat == nil { c.PassengerSeatHeat = &PassengerSeatHeat{} } return c.PassengerSeatHeat } func (c *CarState) GetSteeringWheelHeat() *SteeringWheelHeat { if c.SteeringWheelHeat == nil { c.SteeringWheelHeat = &SteeringWheelHeat{} } return c.SteeringWheelHeat } func (c *CarState) GetAmbientTemperature() *AmbientTemperature { if c.AmbientTemperature == nil { c.AmbientTemperature = &AmbientTemperature{} } return c.AmbientTemperature } func (c *CarState) GetCellTemperature() *CellTemperature { if c.CellTemperature == nil { c.CellTemperature = &CellTemperature{} } return c.CellTemperature } func (c *CarState) GetVCU0x260() *VCU0x260Descriptor { if c.VCU0x260 == nil { c.VCU0x260 = &VCU0x260Descriptor{} } return c.VCU0x260 } func (c *CarState) GetChargingMetrics() *VCUChargingMetrics { if c.ChargingMetrics == nil { c.ChargingMetrics = &VCUChargingMetrics{} } return c.ChargingMetrics } func (c *CarState) GetGear() *Gear { if c.Gear == nil { c.Gear = &Gear{} } return c.Gear } func (c *CarState) GetStateOfCharge() *StateOfCharge { if c.StateOfCharge == nil { c.StateOfCharge = &StateOfCharge{} } return c.StateOfCharge } func (c *CarState) GetVehicleSpeed() *VehicleSpeed { if c.VehicleSpeed == nil { c.VehicleSpeed = &VehicleSpeed{} } return c.VehicleSpeed } // Battery represents the battery state of the car type Battery struct { Percent int `json:"percent" redis:"percent"` TotalMileageOdometer int `json:"total_mileage_odometer"` BatteryVoltage float64 `json:"battery_voltage"` // The fact that this is called battery voltage is really dumb. Its the 12 volt battery, not the high voltage one } func (b *Battery) Marshal() ([]byte, error) { data, err := json.Marshal(*b) return data, errors.WithStack(err) } func (b *Battery) Unmarshal(data []byte) error { err := json.Unmarshal(data, b) return errors.WithStack(err) } // StateOfCharge represents the battery state of charge type StateOfCharge struct { Usable int `json:"usable"` Health int `json:"health"` } type SafeState struct { VehicleSafeState bool `json:"vehicle_safe_state" redis:"vehicle_safe_state"` VCUSafeState bool `json:"vcu_safe_state" redis:"vcu_safe_state"` MCUFrontSafeState bool `json:"mcu_front_safe_state" redis:"mcu_front_safe_state"` MCURearSafeState bool `json:"mcu_rear_safe_state" redis:"mcu_rear_safe_state"` MCURearDecoupState bool `json:"mcu_rear_decoup_state" redis:"mcu_rear_decoup_state"` MCUFrontInverterError bool `json:"mcu_front_inverter_error" redis:"mcu_front_inverter_error"` MCURearInverterError bool `json:"mcu_rear_inverter_error" redis:"mcu_rear_inverter_error"` } func (s *SafeState) Marshal() ([]byte, error) { data, err := json.Marshal(*s) return data, errors.WithStack(err) } func (s *SafeState) Unmarshal(data []byte) error { err := json.Unmarshal(data, s) return errors.WithStack(err) } func (c *CarState) GetSafeState() *SafeState { if c.SafeState == nil { c.SafeState = &SafeState{} } return c.SafeState } // MaxRange represents the predicted max range of the car type MaxRange struct { MaxMiles int `json:"max_miles" redis:"max_miles"` } type VehicleReadyState struct { IsVehicleReady bool `json:"is_vehicle_ready" redis:"is_vehicle_ready"` } func (c *CarState) GetVehicleReadyState() *VehicleReadyState { if c.VehicleReadyState == nil { c.VehicleReadyState = &VehicleReadyState{} } return c.VehicleReadyState } func (b *MaxRange) Marshal() ([]byte, error) { data, err := json.Marshal(*b) return data, errors.WithStack(err) } func (b *MaxRange) Unmarshal(data []byte) error { err := json.Unmarshal(data, b) return errors.WithStack(err) } // Doors represents the doors state of the car // false means closed, true means open type Doors struct { Hood bool `json:"hood" redis:"hood"` LeftFront bool `json:"left_front" redis:"left_front"` LeftRear bool `json:"left_rear" redis:"left_rear"` RightFront bool `json:"right_front" redis:"right_front"` RightRear bool `json:"right_rear" redis:"right_rear"` Trunk bool `json:"trunk" redis:"trunk"` } func (d *Doors) Marshal() ([]byte, error) { data, err := json.Marshal(*d) return data, errors.WithStack(err) } func (d *Doors) Unmarshal(data []byte) error { err := json.Unmarshal(data, d) return errors.WithStack(err) } // Locks represents the lock state of the car type Locks struct { Driver bool `json:"driver" redis:"driver"` All bool `json:"all" redis:"all"` } func (l *Locks) Marshal() ([]byte, error) { data, err := json.Marshal(*l) return data, errors.WithStack(err) } func (l *Locks) Unmarshal(data []byte) error { err := json.Unmarshal(data, l) return errors.WithStack(err) } // Windows represents the windows state of the car // // value is a percentage 0-100 in increments of 0.5 type Windows struct { LeftFront int `json:"left_front" redis:"left_front"` LeftRear int `json:"left_rear" redis:"left_rear"` RightFront int `json:"right_front" redis:"right_front"` RightRear int `json:"right_rear" redis:"right_rear"` } func (w *Windows) Marshal() ([]byte, error) { data, err := json.Marshal(*w) return data, errors.WithStack(err) } func (w *Windows) Unmarshal(data []byte) error { err := json.Unmarshal(data, w) return errors.WithStack(err) } // MiscWindows represents the windows state of the car for misc windows (left / right rear quarter and rear windshield) // value is a percentage 0-100 in increments of 0.5 type MiscWindows struct { LeftRearQuarter int `json:"left_rear_quarter" redis:"left_rear_quarter"` RightRearQuarter int `json:"right_rear_quarter" redis:"right_rear_quarter"` RearWindshield int `json:"rear_windshield" redis:"rear_windshield"` } func (w *MiscWindows) Marshal() ([]byte, error) { data, err := json.Marshal(*w) return data, errors.WithStack(err) } func (w *MiscWindows) Unmarshal(data []byte) error { err := json.Unmarshal(data, w) return errors.WithStack(err) } type Sunroof struct { Sunroof int `json:"sunroof" redis:"sunroof"` } func (s *Sunroof) Marshal() ([]byte, error) { data, err := json.Marshal(*s) return data, errors.WithStack(err) } func (s *Sunroof) Unmarshal(data []byte) error { err := json.Unmarshal(data, s) return errors.WithStack(err) } type CabinClimate struct { CabinTemperature int `json:"cabin_temperature" redis:"cabin_temperature"` InternalTemperature int `json:"internal_temperature" redis:"internal_temperature"` } func (w *CabinClimate) Marshal() ([]byte, error) { data, err := json.Marshal(*w) return data, errors.WithStack(err) } func (w *CabinClimate) Unmarshal(data []byte) error { err := json.Unmarshal(data, w) return errors.WithStack(err) } type RearDefrost struct { On bool `json:"on" redis:"on"` } func (w *RearDefrost) Marshal() ([]byte, error) { data, err := json.Marshal(*w) return data, errors.WithStack(err) } func (w *RearDefrost) Unmarshal(data []byte) error { err := json.Unmarshal(data, w) return errors.WithStack(err) } type DriverSeatHeat struct { Level int `json:"level" redis:"level"` } func (w *DriverSeatHeat) Marshal() ([]byte, error) { data, err := json.Marshal(*w) return data, errors.WithStack(err) } func (w *DriverSeatHeat) Unmarshal(data []byte) error { err := json.Unmarshal(data, w) return errors.WithStack(err) } type PassengerSeatHeat struct { Level int `json:"level" redis:"level"` } func (w *PassengerSeatHeat) Marshal() ([]byte, error) { data, err := json.Marshal(*w) return data, errors.WithStack(err) } func (w *PassengerSeatHeat) Unmarshal(data []byte) error { err := json.Unmarshal(data, w) return errors.WithStack(err) } type SteeringWheelHeat struct { On bool `json:"on" redis:"on"` } func (w *SteeringWheelHeat) Marshal() ([]byte, error) { data, err := json.Marshal(*w) return data, errors.WithStack(err) } func (w *SteeringWheelHeat) Unmarshal(data []byte) error { err := json.Unmarshal(data, w) return errors.WithStack(err) } type AmbientTemperature struct { Temperature int `json:"temperature" redis:"temperature"` } func (w *AmbientTemperature) Marshal() ([]byte, error) { data, err := json.Marshal(*w) return data, errors.WithStack(err) } func (w *AmbientTemperature) Unmarshal(data []byte) error { err := json.Unmarshal(data, w) return errors.WithStack(err) } type VehicleSpeed struct { Speed float64 `json:"speed" redis:"speed"` } func (w *VehicleSpeed) Marshal() ([]byte, error) { data, err := json.Marshal(*w) return data, errors.WithStack(err) } func (w *VehicleSpeed) Unmarshal(data []byte) error { err := json.Unmarshal(data, w) return errors.WithStack(err) } type CellTemperature struct { AvgBatteryTemp int `json:"avg_battery_temp"` } type VCU0x260Descriptor struct { ChargeType string `json:"charge_type"` } type VCUChargingMetrics struct { RemainingChargingTime int `json:"remaining_charging_time"` RemainingChargingTimeFull int `json:"remaining_charging_time_full"` } type Gear struct { InPark bool `json:"in_park"` Immobilizer string `json:"immobilizer,omitempty"` } type Battery12V struct { IBS_BatteryVoltage *float64 `json:"voltage,omitempty"` // 12 Volt battery voltage IBS_StateOfCharge *float64 `json:"percent_charge,omitempty"` // Percentages of the voltage out of about 15.5 Volts IBS_StateOfHealth *int `json:"health,omitempty"` // estimated health of the 12v battery } func (c *CarState) GetBattery12V() *Battery12V { if c.Battery12V == nil { c.Battery12V = &Battery12V{} } return c.Battery12V } type ExpandedSignals struct { // IBS_SOCUpperTolerance *float64 //unconfirmed // IBS_SOCLowerTolerance *float64 //unconfirmed IBS_NominalCapacity *int `json:",omitempty"` IBS_AvailableCapacity *int `json:",omitempty"` BCM_TotMilg_ODO *float64 `json:",omitempty"` BMS_SwVersS *int `json:",omitempty"` BMS_SwVersM *int `json:",omitempty"` BMS_SwVers *int `json:",omitempty"` BMS_AccueDchaTotAh *int `json:",omitempty"` BMS_AccueChrgTotAh *int `json:",omitempty"` } func (c *CarState) GetExpandedSignals() *ExpandedSignals { if c.ExpandedSignals == nil { c.ExpandedSignals = &ExpandedSignals{} } return c.ExpandedSignals } // I am quite certain there is no reason to have these custom marshalers, but want to keep with the current form incase of unexpected side effects func (w *ExpandedSignals) Marshal() ([]byte, error) { data, err := json.Marshal(*w) return data, errors.WithStack(err) } func (w *ExpandedSignals) Unmarshal(data []byte) error { err := json.Unmarshal(data, w) return errors.WithStack(err) }