Repository navigation
Conversation
The writer used a navigation fix only while it was under a minute old by the server's clock, and ignored every GNSS fix meanwhile. That dropped navigation fixes delivered late, and GNSS fixes for up to a minute after navigation stopped. Now every navigation fix is stored at its own time, and a GNSS fix is stored unless a navigation fix is within 15 s of it. On an R1S the navigation stream ran at 5.0 s (p99 5.1 s), so 15 s keeps the feeds from interleaving while letting GNSS take over as soon as navigation stops. A late fix no longer becomes the point later moves are measured from. Legacy now counts as a track of its own while it has three distinct fixes within 30 s, instead of two short gaps followed by up to five minutes of quiet. Replayed over 33 navigated R1S drives, the old rule held navigation fixes back for 2,445 s after legacy had gone quiet; this one never does, and a wake-up burst on an R2 holds for 30 s at most. The held navigation fix is no longer deleted when legacy takes over.
The import flow and panel each kept their own copy of both. They now live in lib/format, where the rest of the app can use them too.
The secondary and danger buttons were class strings kept in settings and imported from there by shared components, and the text field's classes were copied into each form. They're now .btn-secondary, .btn-danger and .field beside .btn-primary, built from the same classes, so they look as before. In the components layer, a caller's own utilities still win. Three notification settings fields used the browser's focus style; they now take the field's grey focus border like the rest.
Tabbing through the app showed the browser's blue focus ring, which on a nav link also ringed the hidden current-page bar off its left edge. Focus is now the accent outline that buttons and pickers already used, solid, so it rings the element alone. A focused sidebar link lights like the current page, with a faint accent ring inside its edge rather than an outline crowding the links around it. The sign-in field's focus is the grey border other fields use, not blue.
A driver was looked up by inserting its profile with ON CONFLICT DO UPDATE, which takes the next id before finding the row is already there, so every active-profile report, settled name and assigned drive used one up: two drivers could sit at ids 1 and 631. The row is now updated first, and only a profile seen for the first time is inserted, with the upsert kept for two arriving at once. The last-seen time still only moves forward. This is the id oddity noted in #91; the ids already spent stay spent.
A drive that ended where navigation was headed now shows that place by the name navigation gave it, "Jumbo Rocks Campground" rather than the road it's on, wherever the vehicle parks there, ahead of the looked-up address. A saved location's name still comes first. Parked within half a kilometre of the destination counts as arriving, or two and a half where the address has no house number (a park, a campground), whose pin can sit well away from the car park. A name that's only an address is left to the looked-up one, and a charger's "Joshua Tree, CA [Rivian Adventure Network]" reads "Rivian Adventure Network · Joshua Tree".
A trip is its dates. Finished drives and charges that start within its days, counted in the time zone they were set in, join it on their own, and with no end date it takes in everything after its start. One taken out stays out, and an activity is in one trip at a time: adding one that's in another is refused unless asked to move it. Two trips can't share a day. A trip without dates holds only what's put in it. Trips read the existing records, Rivian's or TeslaMate's, and store only which records each holds. Their totals (distance, driving and charging time, energy, efficiency, and cost per currency) say how many drives or charges each figure covers. A trip's routes are thinned like History's, with each drive's elevation by distance taken from every reading, so a pass keeps its height. TeslaMate says nothing when a drive ends, so trips take in what's finished when they're read, at most every 30 seconds for each vehicle, and straight away after any change to a trip. Only activities not in a trip already are offered, so ids aren't spent on every read. Discarding a charge or replacing records with an import takes them out of their trips. Drive and session listings are built by shared helpers the trip routes use too. The demo scene makes a trip of its latest drives and charges.
A Trips page lists the vehicle's trips, any under way first with the day it's on, then those to come, then those done, each as a card with its dates as a calendar page and its figures. A trip's page has its totals, a map colored by day with numbered stops, where a road driven more than once is drawn once, and a replay of the journey, beside a timeline of its drives, stops, nights and charges. Below come highlights, the battery and elevation along the whole way, each day, where it stayed, where the time went and who drove. A trip is made or edited by its dates, picked on the calendar Drives and Charging use, tinted with what was driven each day. Pick the day it set out and the end follows the way home, or leave it running with no end; what started in its days comes ticked, to untick what wasn't part of it. A drive or charge can be added to a trip from its own page, stretching the trip's dates to take it in, or to a new trip of its day. Where one drive doesn't end where the next starts, the timeline says the driving between isn't in the trip, with a way to find it, rather than calling it a stop, and the map and charts bridge it with a dashed line. A drive or charge removed from the timeline can be put back for a few seconds. A charge counts on the day it charged, as on Charging. The Drives and Charging calendar's popover is shared with the trip's date fields, a card that's a link warms its edge on hover everywhere, map markers take their dark face from a token, and the README describes trips.
Legacy counted as a dense track when the navigation fix was within 30 s of the oldest of its last three fixes. On a feed reporting once a minute those three span two minutes, so a navigation fix stamped before the newest legacy fix read as dense and was dropped. Now only the legacy fixes at or before the navigation fix count, and three of them must fall in the 30 s up to it. The feed is judged only when a delta brings a new navigation fix. The cached one was settled when it arrived; judging it again as it aged logged a switch of source that never happened. A navigation fix refused for stepping the track back no longer claims its 15 s, so it can't mute the GNSS fix that is the only point there. The replay test now uses a new monitor, so only the stored row stops the frame being stored twice, and checks the save doesn't fail. Co-authored-by: Grant Leisz <MrSerious0@users.noreply.github.com>
An R2 reports its own fix about once a minute, so its marker on the dashboard jumped once a minute even while navigation was sending a fix every 5 s. The map now follows the rule the stored track does: the navigation fix while one is running, and the vehicle's own fix once that is more than 15 s newer. Speed and heading come with the fix shown, so they match the marker. An R1, whose own fix is already a track, is unchanged, since the server doesn't keep its navigation fixes. A delta carrying only a navigation fix now reaches the live stream too, so the map moves as each one arrives. The live trail skips a fix older than the last one drawn, so it doesn't step back when navigation's fix was taken a moment before the GPS fix already shown. The out-of-date warning judges the fix the map shows. Geofences, charging and drive detection still read only the vehicle's own fix. The 15 s window moves to state-utils so the web shares it.
A drive on the trip's timeline now opens with its battery from start to end, "82% → 78%", and its average speed while moving, where its route can tell moving from stopped. A charge opens with the range it added and its average and peak power, worked out from energy and time where no average was reported. Elevation among the trip's highlights is now lowest to highest rather than the highest point alone, with the descent beneath the total climb, and the elevation chart says how far it came down too. "Closest call" is now "Lowest battery", with where the drive that left it there ended; the weather swing is gone, as a few lookups can't vouch for it. Day by day comes before the highlights, which are smaller, in as many columns as fit. The replay button is a small pill until it plays, then widens for the drive under way and the scrubber, keeping its height.
… across Rivian Roamer is now the first source under Settings → Import. Its data copy is one .zip, read in place, and matched to your Rivian by VIN. From a Rivian Roamer copy: - Drives and charges are Roamer's own sessions; ones it flagged as corrupted are left out. - Charges keep their energy breakdown and a curve from Roamer's charging readings. A charge you already have only gets what it's missing, and undo puts it back as it was. - Vehicle history comes from the metrics Roamer kept as Rivian sent them; ones it recoded (seat heat, service mode, range thresholds) are skipped. - Each drive gets the driver profile and navigation destination Roamer recorded, and the account's saved places are added unless one is already saved there. ElectraFi drives now get their driver too: ElectraFi keeps the active profile's name in Tesla's autopark_state_v2 column. Drivers are matched by name to ones RivianMate knows. A name it doesn't know becomes a driver without a profile, which the car's profile takes over once it reports that name. Undo keeps drivers and places. The import itself: - The shared steps (drafts, planning, writing, undo) move to services/imports, with each export as a format that reads its files. - The preview counts readings left for live tracking apart from ones already recorded, and lists the places it adds. - The flow's rows hold their size as files and dates load, and its text is shorter.
The show-password toggle sat between the two fields when choosing an app password, so Tab went to it before the confirm field.
# Conflicts: # web/src/features/drives/DrivesPage.tsx
Merges main, track-fix-precedence (#95) and roamer-import (#97) into trips so all three ship in one merge to main, and one Docker Hub publish. Trips now uses the import code where Roamer moved it: isTimeZone from imports/time-zone and rangeOf from imports/plan. The import flow uses Trips' shared btn-secondary and btn-danger classes and the plural from lib/format.
This was referenced Nov 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds trips: a page per journey with its totals, a map colored by day, a replay, a timeline of its drives, stops, nights and charges, and highlights below. A trip is its dates, so drives and charges join it on their own.
Trips on the server
0021addstrips,trip_activitiesandtrip_exclusions.Trips in the web app
Also
.btn-secondary,.btn-dangerand.field.pluralandbrowserTimeZonemove tolib/format.Testing