leftopen

package
v0.40.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 29, 2026 License: MIT Imports: 7 Imported by: 0

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

View Source
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
)
View Source
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

func OpenClosures(st *rivian.State) []string

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

func WalkedAway(st *rivian.State, at, now time.Time) bool

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
	// contains filtered or unexported fields
}

Job is the timer.

func (*Job) Run

func (j *Job) Run(ctx context.Context)

Run ticks every CheckEvery until ctx ends.

func (*Job) Tick

func (j *Job) Tick(ctx context.Context)

Tick checks every candidate vehicle once.

type LatestFunc

type LatestFunc func(uid uuid.UUID, rivianID string) (*rivian.State, time.Time)

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.

func NewSource

func NewSource(db *sql.DB, latest LatestFunc, skip uuid.UUID) Source

NewSource reads candidates and records markers in Postgres, and states from latest. skip is excluded (the demo user).

type Vehicle

type Vehicle struct {
	UserID    uuid.UUID
	VehicleID uuid.UUID // the database id
	RivianID  string
	Model     string
}

Vehicle is a truck whose owner has the alert on.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL