Documentation
¶
Overview ¶
Package tripmultiday orchestrates a multi-day trip plan over the trip planner (Rivian's planTripWithMultiStopV2, or the replay planners on installs with no Rivian access). The planner is single-day: it computes one route through up to ten waypoints with charging stops, but has no concept of "sleep here, depart tomorrow."
The orchestrator chains one planner call per day, daisied on departure SoC and departure time. Each day is a start, optional vias, and an end; day k+1 starts where day k ended. Between days an overnight model projects how much the truck charges while parked (see overnight).
Index ¶
Constants ¶
const ( MaxDays = 10 MaxDayWaypoints = 10 // the planner's limit per call, origin and destination included DefaultACMaxKW = 11.5 // onboard AC charger ceiling when the model is unknown DefaultL2KW = 7.0 // a typical hotel or home L2 when none is given DefaultReservePct = 10.0 // a day's arrival reserve when none was asked for MaxPlanTargetPct = 90.0 // a raised reserve never asks for more than this DefaultCapPct = 80.0 // overnight charge stops here unless asked otherwise )
Limits. A day is one planner call, so it takes at most the planner's waypoint count; the day count keeps one request inside its time budget.
Variables ¶
This section is empty.
Functions ¶
func OvernightSoC ¶ added in v0.37.0
OvernightSoC projects the state of charge after parking for hours at an L2 of l2kw (nil: the default; 0: none), from arrSoC, with the same model the planner chains days with. The AC ceiling is the default one and the charge stops at capPct (0: DefaultCapPct).
Types ¶
type Day ¶
type Day struct {
Index int `json:"index"` // 1-based
Plan *rivian.TripPlan `json:"plan"`
DepartAt time.Time `json:"depart_at"`
ArriveAt time.Time `json:"arrive_at"`
Start Waypoint `json:"start"`
Vias []Waypoint `json:"vias,omitempty"`
End Waypoint `json:"end"`
DepartureSoC float64 `json:"departure_soc"` // SoC at day start
ArrivalSoC float64 `json:"arrival_soc"` // SoC at day end (route 0)
// ChainArrivalSoC is the arrival SoC the overnight and the next day were
// worked from: the lower of the plan's and the corrected one. Set only
// when a correction applied.
ChainArrivalSoC float64 `json:"chain_arrival_soc,omitempty"`
DestinationReached bool `json:"destination_reached"`
SoCBelowLimit bool `json:"soc_below_limit"`
Overnight *OvernightResult `json:"overnight,omitempty"`
// Problem is plain text for the user when the day cannot be driven as
// planned: it does not reach its end, or ends below the reserve with no stop
// that fixes it. Empty for a day that works.
Problem string `json:"problem,omitempty"`
}
Day is one day's plan plus the overnight that ends it.
type DayInput ¶ added in v0.37.0
type DayInput struct {
Vias []Waypoint
End Waypoint
// DepartAt overrides when this day leaves (day 1: the request's StartAt).
DepartAt *time.Time
// TargetArrivalSoCPct is this day's reserve; nil takes the request's.
TargetArrivalSoCPct *float64
// Overnight ends the day; ignored on the last day.
Overnight *Overnight
}
DayInput is one day of the trip.
type Overnight ¶ added in v0.37.0
type Overnight struct {
// L2KW is the available AC power. nil means "not given" and takes
// DefaultL2KW; an explicit 0 means no charging at this stop.
L2KW *float64
// Hookup is the connector an own stop was entered with ("nema_14_50", ...);
// it is echoed in the result. L2KWGiven is whether the caller sent L2KW: when
// it did not, the power is a default for the hookup and the result says so.
Hookup string
L2KWGiven bool
// Until is the local time ("15:04") the truck is wanted the next morning.
// The next day departs at the next such time after arrival.
Until string
// ParkedHours, when positive, fixes the stay: the next day departs that
// long after arrival (the older request shape).
ParkedHours float64
// MaxSoCPct caps the post-charge SoC; 0 takes the request's default.
MaxSoCPct float64
Name string
}
Overnight describes the stop at the end of a day.
type OvernightResult ¶
type OvernightResult struct {
Name string `json:"name,omitempty"`
ParkedHours float64 `json:"parked_hours"`
L2KW float64 `json:"l2_kw"`
// Hookup echoes an own stop's connector; L2KWAssumed is true when the power
// is the default for it rather than a value the user gave.
Hookup string `json:"hookup,omitempty"`
L2KWAssumed bool `json:"l2_kw_assumed,omitempty"`
// PlannedKW is the power the plan charged at when the truck cannot draw all of
// L2KW (it is limited to the truck's AC maximum); omitted when L2KW is what
// was used. Show PlannedKW when present, else L2KW, as "planned at X kW".
PlannedKW float64 `json:"planned_kw,omitempty"`
// AddedKWh is the energy that went into the battery.
AddedKWh float64 `json:"added_kwh"`
PostChargeSoCPct float64 `json:"post_charge_soc_pct"`
// Capped reports the cap stopped the charge short of what the stay allowed.
Capped bool `json:"capped"`
}
OvernightResult is the post-charge state at the end of a day. Always nil on the final day.
type Planner ¶
type Planner = rivian.TripPlanner
Planner is what the orchestrator needs; tests plug a fake.
type Request ¶
type Request struct {
// Account-level inputs (forwarded to every day's planner call).
VehicleID string
HasAdapter *bool
DriveMode string
TrailerProfile string
// PackKWh is the usable pack, in kWh. Required for the overnight model.
PackKWh float64
// StartingSoC is the SoC at the start of day 1.
StartingSoC float64
// StartAt is when day 1 leaves; the zero value means Now.
StartAt time.Time
// Loc is the zone "until" times are read in; nil is UTC.
Loc *time.Location
// Now is the clock for an unset StartAt; nil is time.Now.
Now func() time.Time
Origin Waypoint
Days []DayInput
// MaxOvernightSoCPct is the default overnight cap (0: DefaultCapPct).
MaxOvernightSoCPct float64
// ACMaxKW is the truck's AC ceiling (0: DefaultACMaxKW).
ACMaxKW float64
// TargetArrivalSoCPct is every day's reserve unless the day sets one.
TargetArrivalSoCPct *float64
NetworkPreferences []rivian.NetworkPreference
// AdjustArrival, when set, is asked for each planned day (day is 1-based,
// startSoC and target as the day was planned) for the arrival SoC after the
// caller's corrections (weather, vehicle profile). The overnight and the
// next day then start from the lower of that and the plan's own arrival, so
// the chain is as conservative as what the user is shown. ok=false leaves
// the plan's arrival in use.
AdjustArrival func(ctx context.Context, day int, plan *rivian.TripPlan, startSoC float64, target *float64) (arrival float64, ok bool)
// RoutePreferences applies to every day.
RoutePreferences *rivian.RoutePreferences
}
Request is the orchestrator's input.
type RequestError ¶ added in v0.37.0
RequestError is a request the orchestrator refuses; Day is the 1-based day at fault, or 0 for the request as a whole. The handler answers it with 400.
func (*RequestError) Error ¶ added in v0.37.0
func (e *RequestError) Error() string
type Response ¶
type Response struct {
Days []Day `json:"days"`
Total Totals `json:"total"`
// Simulated is true when any day's plan was not the gateway's.
Simulated bool `json:"simulated,omitempty"`
// FailedDay is the day that could not be planned (1-based); the days
// before it are intact and chaining stopped there, because the days after
// cannot know their starting SoC. Error says why.
FailedDay int `json:"failed_day,omitempty"`
Error string `json:"error,omitempty"`
// FailedErr is Error as an error, for the caller to classify. Not sent.
FailedErr error `json:"-"`
// PlannerFailure is true when FailedErr came from the planner rather than
// from the orchestrator's own checks; its text is for the logs, not for
// the user (the caller words the message).
PlannerFailure bool `json:"-"`
}
Response is the aggregated multi-day plan.
type Totals ¶
type Totals struct {
DistanceMeters float64 `json:"distance_meters"`
DriveDurationSec int `json:"drive_duration_sec"`
ChargingDurationSec int `json:"charging_duration_sec"`
}
Totals summarises the chained-day plan so the SPA can show one "Trip total: X mi, Y h drive, Z stops" line above the day cards.
type Waypoint ¶
type Waypoint struct {
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
EntityID string `json:"entity_id,omitempty"`
Label string `json:"label,omitempty"`
}
Waypoint is a place on the trip. Label is cosmetic: never sent to the planner, echoed back so the SPA can name the stop.