Documentation
¶
Overview ¶
Package leftopen sends the left-open alert: an opt-in push when a door, the frunk, the liftgate, the tailgate or the tonneau has stayed open for OpenFor after the truck was parked and left (DA's ruling, Sprint 8 item 4).
The rule is a "walked away" proxy built only from state we already receive; nothing here calls Rivian, wakes the truck or asks it anything. Unknown inputs mean no alert: a missed alert is acceptable, one sent for lack of knowledge is not. A truck that sleeps with the frunk open stops sending frames, so a timer (not the arrival of a frame) drives the check, reading the monitor's latest state.
- Closures: only what the state positively says is open (a door, the frunk, the liftgate, the tailgate, the tonneau). Windows are not part of v1.
- An episode starts when something is first seen open on a fresh state, and ends when everything is closed.
- The alert fires once per episode, after OpenFor, when the truck is in P (stated, not assumed), not charging, its power state is known, and it is asleep or standby, or awake but locked on a fresh state.
- The text is fixed (internal/push.LeftOpenPayload): the model, what is open, how long. No place.
The marker (left_open_alerts) records only that a vehicle's episode was alerted, so a restart or a second pod never repeats it. A pod that does not run the vehicle's monitor sees no state for it and does nothing.
Index ¶
Constants ¶
const ( // CheckEvery is the timer. CheckEvery = time.Minute // FreshFrame is how recent a state must be to start an episode, and to vouch for an awake, locked truck. FreshFrame = 10 * time.Minute // MaxAge: a state older than this (a sleeping truck's last frame) no longer says anything. MaxAge = 12 * time.Hour // PruneAfter is how long a marker is kept. PruneAfter = 30 * 24 * time.Hour // Cooldown: no second alert for a vehicle within this long of its last. Cooldown = 2 * time.Hour )
const OpenFor = 15 * time.Minute
OpenFor is how long something must stay open (the owner's N). One constant: changing it is a one-line change.
Variables ¶
This section is empty.
Functions ¶
func OpenClosures ¶
OpenClosures names what the state positively reports open, as the kinds internal/push.JoinClosures knows. A state with no real data (nothing has been read yet) reports nothing.
func WalkedAway ¶
WalkedAway says whether the state shows the truck parked and left: in P (stated), not charging, with a known power state that is asleep or standby, or awake but locked on a fresh state. at is when the state was last updated.
Types ¶
type Job ¶
type Job struct {
Source Source
// Deliver sends the push to the account's devices that have the alert on.
Deliver func(ctx context.Context, uid uuid.UUID, model string, kinds []string, minutes int) error
Now func() time.Time
Logger *slog.Logger
// Fence says what this pod may do for a vehicle (the group lease, lead mode). Nil, or Off, is as
// before. An alert is made only while the pod holds the vehicle's group; the claim then carries
// the epoch. A pod that does not hold it, or is still warming up, skips the tick (the owner
// alerts; this pod would only race it for the marker).
Fence func(rivianID string) (fence.Token, fence.State)
// contains filtered or unexported fields
}
Job is the timer.
type LatestFunc ¶
LatestFunc reads a vehicle's newest state from the monitor this pod runs (nil state: not this pod's).
type Source ¶
type Source interface {
// Vehicles are the trucks of accounts with the alert on for some device.
Vehicles(ctx context.Context) ([]Vehicle, error)
// Latest is the monitor's newest state for the vehicle and when it was last updated; nil when this pod does not
// run that vehicle's monitor.
Latest(uid uuid.UUID, rivianID string) (*rivian.State, time.Time)
// Claim records the episode as alerted and reports whether this call was the one (false: already alerted).
Claim(ctx context.Context, uid, vehicleID uuid.UUID, episodeStart time.Time) (bool, error)
// Prune deletes markers older than the cutoff.
Prune(ctx context.Context, before time.Time) (int64, error)
}
Source reads what the job needs.